mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-25 20:27:34 +08:00
完善对高规格aac的支持
This commit is contained in:
parent
b9006a90d4
commit
efa92752c7
@ -9,6 +9,9 @@
|
||||
*/
|
||||
|
||||
#include "AAC.h"
|
||||
#ifdef ENABLE_MP4
|
||||
#include "mpeg4-aac.h"
|
||||
#endif
|
||||
|
||||
namespace mediakit{
|
||||
|
||||
@ -89,7 +92,8 @@ static void parseAacConfig(const string &config, AdtsHeader &adts) {
|
||||
adts.no_raw_data_blocks_in_frame = 0;
|
||||
}
|
||||
|
||||
string makeAacConfig(const uint8_t *hex){
|
||||
string makeAacConfig(const uint8_t *hex, int length){
|
||||
#ifndef ENABLE_MP4
|
||||
if (!(hex[0] == 0xFF && (hex[1] & 0xF0) == 0xF0)) {
|
||||
return "";
|
||||
}
|
||||
@ -112,20 +116,58 @@ string makeAacConfig(const uint8_t *hex){
|
||||
audioSpecificConfig[0] = (audioObjectType << 3) | (sampling_frequency_index >> 1);
|
||||
audioSpecificConfig[1] = (sampling_frequency_index << 7) | (channel_configuration << 3);
|
||||
return string((char *)audioSpecificConfig,2);
|
||||
#else
|
||||
struct mpeg4_aac_t aac = {0};
|
||||
if (mpeg4_aac_adts_load(hex, length, &aac) > 0) {
|
||||
char buf[32] = {0};
|
||||
int len = mpeg4_aac_audio_specific_config_save(&aac, (uint8_t *) buf, sizeof(buf));
|
||||
if (len > 0) {
|
||||
return string(buf, len);
|
||||
}
|
||||
}
|
||||
WarnL << "生成aac config失败, adts header:" << hexdump(hex, length);
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
void dumpAacConfig(const string &config, int length, uint8_t *out){
|
||||
int dumpAacConfig(const string &config, int length, uint8_t *out, int out_size) {
|
||||
#ifndef ENABLE_MP4
|
||||
AdtsHeader header;
|
||||
parseAacConfig(config, header);
|
||||
header.aac_frame_length = length;
|
||||
dumpAdtsHeader(header, out);
|
||||
return ADTS_HEADER_LEN;
|
||||
#else
|
||||
struct mpeg4_aac_t aac = {0};
|
||||
int ret = mpeg4_aac_audio_specific_config_load((uint8_t *) config.data(), config.size(), &aac);
|
||||
if (ret > 0) {
|
||||
ret = mpeg4_aac_adts_save(&aac, length, out, out_size);
|
||||
}
|
||||
if (ret < 0) {
|
||||
WarnL << "生成adts头失败:" << ret << ", aac config:" << hexdump(config.data(), config.size());
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
void parseAacConfig(const string &config, int &samplerate, int &channels){
|
||||
bool parseAacConfig(const string &config, int &samplerate, int &channels){
|
||||
#ifndef ENABLE_MP4
|
||||
AdtsHeader header;
|
||||
parseAacConfig(config, header);
|
||||
samplerate = samplingFrequencyTable[header.sf_index];
|
||||
channels = header.channel_configuration;
|
||||
return true;
|
||||
#else
|
||||
struct mpeg4_aac_t aac = {0};
|
||||
int ret = mpeg4_aac_audio_specific_config_load((uint8_t *) config.data(), config.size(), &aac);
|
||||
if (ret > 0) {
|
||||
samplerate = aac.sampling_frequency;
|
||||
channels = aac.channels;
|
||||
return true;
|
||||
}
|
||||
WarnL << "获取aac采样率、声道数失败:" << hexdump(config.data(), config.size());
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
Sdp::Ptr AACTrack::getSdp() {
|
||||
|
@ -17,9 +17,9 @@
|
||||
|
||||
namespace mediakit{
|
||||
|
||||
string makeAacConfig(const uint8_t *hex);
|
||||
void dumpAacConfig(const string &config, int length, uint8_t *out);
|
||||
void parseAacConfig(const string &config, int &samplerate, int &channels);
|
||||
string makeAacConfig(const uint8_t *hex, int length);
|
||||
int dumpAacConfig(const string &config, int length, uint8_t *out, int out_size);
|
||||
bool parseAacConfig(const string &config, int &samplerate, int &channels);
|
||||
|
||||
/**
|
||||
* aac帧,包含adts头
|
||||
@ -137,9 +137,9 @@ public:
|
||||
void inputFrame(const Frame::Ptr &frame) override{
|
||||
if (_cfg.empty()) {
|
||||
//未获取到aac_cfg信息
|
||||
if (frame->prefixSize() >= ADTS_HEADER_LEN) {
|
||||
if (frame->prefixSize()) {
|
||||
//7个字节的adts头
|
||||
_cfg = makeAacConfig((uint8_t *) (frame->data()));
|
||||
_cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize());
|
||||
onReady();
|
||||
} else {
|
||||
WarnL << "无法获取adts头!";
|
||||
|
@ -13,20 +13,6 @@
|
||||
|
||||
namespace mediakit{
|
||||
|
||||
AACRtmpDecoder::AACRtmpDecoder(const Track::Ptr &track) {
|
||||
_frame = obtainFrame();
|
||||
_track = dynamic_pointer_cast<AACTrack>(track);
|
||||
}
|
||||
|
||||
AACFrame::Ptr AACRtmpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
auto frame = ResourcePoolHelper<AACFrame>::obtainObj();
|
||||
frame->_prefix_size = ADTS_HEADER_LEN;
|
||||
//预留7个字节的空位以便后续覆盖
|
||||
frame->_buffer.assign(ADTS_HEADER_LEN,(char)0);
|
||||
return frame;
|
||||
}
|
||||
|
||||
static string getAacCfg(const RtmpPacket &thiz) {
|
||||
string ret;
|
||||
if (thiz.getMediaType() != FLV_CODEC_AAC) {
|
||||
@ -46,12 +32,6 @@ static string getAacCfg(const RtmpPacket &thiz) {
|
||||
bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) {
|
||||
if (pkt->isCfgFrame()) {
|
||||
_aac_cfg = getAacCfg(*pkt);
|
||||
if (_track) {
|
||||
//设置aac config
|
||||
_track->setAacCfg(_aac_cfg);
|
||||
//不再强引用
|
||||
_track = nullptr;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!_aac_cfg.empty()) {
|
||||
@ -61,20 +41,30 @@ bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) {
|
||||
}
|
||||
|
||||
void AACRtmpDecoder::onGetAAC(const char* data, int len, uint32_t stamp) {
|
||||
_frame->_dts = stamp;
|
||||
//先追加数据
|
||||
_frame->_buffer.append(data, len);
|
||||
//覆盖adts头
|
||||
dumpAacConfig(_aac_cfg, _frame->size(), (uint8_t *) _frame->data());
|
||||
auto frame = ResourcePoolHelper<AACFrame>::obtainObj();
|
||||
|
||||
//生成adts头
|
||||
char adts_header[32] = {0};
|
||||
auto size = dumpAacConfig(_aac_cfg, len, (uint8_t *) adts_header, sizeof(adts_header));
|
||||
if (size > 0) {
|
||||
frame->_buffer.assign(adts_header, size);
|
||||
frame->_prefix_size = size;
|
||||
} else {
|
||||
frame->_buffer.clear();
|
||||
frame->_prefix_size = 0;
|
||||
}
|
||||
|
||||
//追加负载数据
|
||||
frame->_buffer.append(data, len);
|
||||
frame->_dts = stamp;
|
||||
|
||||
//写入环形缓存
|
||||
RtmpCodec::inputFrame(_frame);
|
||||
_frame = obtainFrame();
|
||||
RtmpCodec::inputFrame(frame);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AACRtmpEncoder::AACRtmpEncoder(const Track::Ptr &track): AACRtmpDecoder(track) {
|
||||
AACRtmpEncoder::AACRtmpEncoder(const Track::Ptr &track) {
|
||||
_track = dynamic_pointer_cast<AACTrack>(track);
|
||||
}
|
||||
|
||||
@ -91,9 +81,9 @@ void AACRtmpEncoder::makeConfigPacket() {
|
||||
|
||||
void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
if (_aac_cfg.empty()) {
|
||||
if (frame->prefixSize() >= 7) {
|
||||
if (frame->prefixSize()) {
|
||||
//包含adts头,从adts头获取aac配置信息
|
||||
_aac_cfg = makeAacConfig((uint8_t *) (frame->data()));
|
||||
_aac_cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize());
|
||||
}
|
||||
makeConfigPacket();
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ class AACRtmpDecoder : public RtmpCodec , public ResourcePoolHelper<AACFrame> {
|
||||
public:
|
||||
typedef std::shared_ptr<AACRtmpDecoder> Ptr;
|
||||
|
||||
AACRtmpDecoder(const Track::Ptr &track);
|
||||
AACRtmpDecoder() {}
|
||||
~AACRtmpDecoder() {}
|
||||
|
||||
/**
|
||||
@ -37,13 +37,10 @@ public:
|
||||
return CodecAAC;
|
||||
}
|
||||
|
||||
protected:
|
||||
private:
|
||||
void onGetAAC(const char *data, int len, uint32_t stamp);
|
||||
AACFrame::Ptr obtainFrame();
|
||||
|
||||
protected:
|
||||
AACFrame::Ptr _frame;
|
||||
AACTrack::Ptr _track;
|
||||
private:
|
||||
string _aac_cfg;
|
||||
};
|
||||
|
||||
@ -80,6 +77,8 @@ private:
|
||||
|
||||
private:
|
||||
uint8_t _audio_flv_flags;
|
||||
AACTrack::Ptr _track;
|
||||
string _aac_cfg;
|
||||
};
|
||||
|
||||
}//namespace mediakit
|
||||
|
@ -56,30 +56,30 @@ void AACRtpEncoder::inputFrame(const Frame::Ptr &frame) {
|
||||
}
|
||||
|
||||
void AACRtpEncoder::makeAACRtp(const void *data, unsigned int len, bool mark, uint32_t uiStamp) {
|
||||
RtpCodec::inputRtp(makeRtp(getTrackType(),data,len,mark,uiStamp), false);
|
||||
RtpCodec::inputRtp(makeRtp(getTrackType(), data, len, mark, uiStamp), false);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AACRtpDecoder::AACRtpDecoder(const Track::Ptr &track){
|
||||
AACRtpDecoder::AACRtpDecoder(const Track::Ptr &track) {
|
||||
auto aacTrack = dynamic_pointer_cast<AACTrack>(track);
|
||||
if(!aacTrack || !aacTrack->ready()){
|
||||
if (!aacTrack || !aacTrack->ready()) {
|
||||
WarnL << "该aac track无效!";
|
||||
}else{
|
||||
} else {
|
||||
_aac_cfg = aacTrack->getAacCfg();
|
||||
}
|
||||
_adts = obtainFrame();
|
||||
_frame = obtainFrame();
|
||||
}
|
||||
|
||||
AACRtpDecoder::AACRtpDecoder() {
|
||||
_adts = obtainFrame();
|
||||
_frame = obtainFrame();
|
||||
}
|
||||
|
||||
AACFrame::Ptr AACRtpDecoder::obtainFrame() {
|
||||
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
|
||||
auto frame = ResourcePoolHelper<AACFrame>::obtainObj();
|
||||
frame->_prefix_size = ADTS_HEADER_LEN;
|
||||
//预留7个字节的空位以便后续覆盖
|
||||
frame->_buffer.assign(ADTS_HEADER_LEN,(char)0);
|
||||
frame->_prefix_size = 0;
|
||||
frame->_buffer.clear();
|
||||
return frame;
|
||||
}
|
||||
|
||||
@ -94,19 +94,18 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) {
|
||||
//忽略Au-Header区
|
||||
ptr += 2 + au_header_count * 2;
|
||||
|
||||
static const uint32_t max_size = AAC_MAX_FRAME_SIZE - ADTS_HEADER_LEN;
|
||||
while (ptr < end) {
|
||||
auto size = (uint32_t) (end - ptr);
|
||||
if(size > max_size){
|
||||
size = max_size;
|
||||
if (size > AAC_MAX_FRAME_SIZE) {
|
||||
size = AAC_MAX_FRAME_SIZE;
|
||||
}
|
||||
if (_adts->size() + size > AAC_MAX_FRAME_SIZE) {
|
||||
if (_frame->size() + size > AAC_MAX_FRAME_SIZE) {
|
||||
//数据太多了,先清空
|
||||
flushData();
|
||||
}
|
||||
//追加aac数据
|
||||
_adts->_buffer.append((char *)ptr, size);
|
||||
_adts->_dts = rtppack->timeStamp;
|
||||
_frame->_buffer.append((char *) ptr, size);
|
||||
_frame->_dts = rtppack->timeStamp;
|
||||
ptr += size;
|
||||
}
|
||||
|
||||
@ -118,15 +117,21 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) {
|
||||
}
|
||||
|
||||
void AACRtpDecoder::flushData() {
|
||||
if (_adts->size() == ADTS_HEADER_LEN) {
|
||||
if (_frame->_buffer.empty()) {
|
||||
//没有有效数据
|
||||
return;
|
||||
}
|
||||
|
||||
//覆盖adts头
|
||||
dumpAacConfig(_aac_cfg, _adts->size(), (uint8_t *) _adts->data());
|
||||
RtpCodec::inputFrame(_adts);
|
||||
_adts = obtainFrame();
|
||||
//插入adts头
|
||||
char adts_header[32] = {0};
|
||||
auto size = dumpAacConfig(_aac_cfg, _frame->_buffer.size(), (uint8_t *) adts_header, sizeof(adts_header));
|
||||
if (size > 0) {
|
||||
//插入adts头
|
||||
_frame->_buffer.insert(0, adts_header, size);
|
||||
_frame->_prefix_size = size;
|
||||
}
|
||||
RtpCodec::inputFrame(_frame);
|
||||
_frame = obtainFrame();
|
||||
}
|
||||
|
||||
|
||||
|
@ -31,16 +31,19 @@ public:
|
||||
*/
|
||||
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
|
||||
|
||||
CodecId getCodecId() const override{
|
||||
CodecId getCodecId() const override {
|
||||
return CodecAAC;
|
||||
}
|
||||
|
||||
protected:
|
||||
AACRtpDecoder();
|
||||
|
||||
private:
|
||||
AACFrame::Ptr obtainFrame();
|
||||
void flushData();
|
||||
|
||||
private:
|
||||
AACFrame::Ptr _adts;
|
||||
AACFrame::Ptr _frame;
|
||||
string _aac_cfg;
|
||||
};
|
||||
|
||||
@ -71,8 +74,10 @@ public:
|
||||
* @param frame 带dats头的aac数据
|
||||
*/
|
||||
void inputFrame(const Frame::Ptr &frame) override;
|
||||
|
||||
private:
|
||||
void makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp);
|
||||
|
||||
private:
|
||||
unsigned char _aucSectionBuf[1600];
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user