完善对高规格aac的支持

This commit is contained in:
xiongziliang 2020-06-11 19:21:46 +08:00
parent b9006a90d4
commit efa92752c7
6 changed files with 107 additions and 66 deletions

View File

@ -9,6 +9,9 @@
*/ */
#include "AAC.h" #include "AAC.h"
#ifdef ENABLE_MP4
#include "mpeg4-aac.h"
#endif
namespace mediakit{ namespace mediakit{
@ -89,7 +92,8 @@ static void parseAacConfig(const string &config, AdtsHeader &adts) {
adts.no_raw_data_blocks_in_frame = 0; 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)) { if (!(hex[0] == 0xFF && (hex[1] & 0xF0) == 0xF0)) {
return ""; return "";
} }
@ -112,20 +116,58 @@ string makeAacConfig(const uint8_t *hex){
audioSpecificConfig[0] = (audioObjectType << 3) | (sampling_frequency_index >> 1); audioSpecificConfig[0] = (audioObjectType << 3) | (sampling_frequency_index >> 1);
audioSpecificConfig[1] = (sampling_frequency_index << 7) | (channel_configuration << 3); audioSpecificConfig[1] = (sampling_frequency_index << 7) | (channel_configuration << 3);
return string((char *)audioSpecificConfig,2); 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; AdtsHeader header;
parseAacConfig(config, header); parseAacConfig(config, header);
header.aac_frame_length = length; header.aac_frame_length = length;
dumpAdtsHeader(header, out); 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; AdtsHeader header;
parseAacConfig(config, header); parseAacConfig(config, header);
samplerate = samplingFrequencyTable[header.sf_index]; samplerate = samplingFrequencyTable[header.sf_index];
channels = header.channel_configuration; 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() { Sdp::Ptr AACTrack::getSdp() {

View File

@ -17,9 +17,9 @@
namespace mediakit{ namespace mediakit{
string makeAacConfig(const uint8_t *hex); string makeAacConfig(const uint8_t *hex, int length);
void dumpAacConfig(const string &config, int length, uint8_t *out); int dumpAacConfig(const string &config, int length, uint8_t *out, int out_size);
void parseAacConfig(const string &config, int &samplerate, int &channels); bool parseAacConfig(const string &config, int &samplerate, int &channels);
/** /**
* aac帧adts头 * aac帧adts头
@ -137,9 +137,9 @@ public:
void inputFrame(const Frame::Ptr &frame) override{ void inputFrame(const Frame::Ptr &frame) override{
if (_cfg.empty()) { if (_cfg.empty()) {
//未获取到aac_cfg信息 //未获取到aac_cfg信息
if (frame->prefixSize() >= ADTS_HEADER_LEN) { if (frame->prefixSize()) {
//7个字节的adts头 //7个字节的adts头
_cfg = makeAacConfig((uint8_t *) (frame->data())); _cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize());
onReady(); onReady();
} else { } else {
WarnL << "无法获取adts头!"; WarnL << "无法获取adts头!";

View File

@ -13,20 +13,6 @@
namespace mediakit{ 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) { static string getAacCfg(const RtmpPacket &thiz) {
string ret; string ret;
if (thiz.getMediaType() != FLV_CODEC_AAC) { if (thiz.getMediaType() != FLV_CODEC_AAC) {
@ -46,12 +32,6 @@ static string getAacCfg(const RtmpPacket &thiz) {
bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) { bool AACRtmpDecoder::inputRtmp(const RtmpPacket::Ptr &pkt, bool) {
if (pkt->isCfgFrame()) { if (pkt->isCfgFrame()) {
_aac_cfg = getAacCfg(*pkt); _aac_cfg = getAacCfg(*pkt);
if (_track) {
//设置aac config
_track->setAacCfg(_aac_cfg);
//不再强引用
_track = nullptr;
}
return false; return false;
} }
if (!_aac_cfg.empty()) { 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) { void AACRtmpDecoder::onGetAAC(const char* data, int len, uint32_t stamp) {
_frame->_dts = stamp; auto frame = ResourcePoolHelper<AACFrame>::obtainObj();
//先追加数据
_frame->_buffer.append(data, len); //生成adts头
//覆盖adts头 char adts_header[32] = {0};
dumpAacConfig(_aac_cfg, _frame->size(), (uint8_t *) _frame->data()); 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); RtmpCodec::inputFrame(frame);
_frame = obtainFrame();
} }
///////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////
AACRtmpEncoder::AACRtmpEncoder(const Track::Ptr &track): AACRtmpDecoder(track) { AACRtmpEncoder::AACRtmpEncoder(const Track::Ptr &track) {
_track = dynamic_pointer_cast<AACTrack>(track); _track = dynamic_pointer_cast<AACTrack>(track);
} }
@ -91,9 +81,9 @@ void AACRtmpEncoder::makeConfigPacket() {
void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) { void AACRtmpEncoder::inputFrame(const Frame::Ptr &frame) {
if (_aac_cfg.empty()) { if (_aac_cfg.empty()) {
if (frame->prefixSize() >= 7) { if (frame->prefixSize()) {
//包含adts头,从adts头获取aac配置信息 //包含adts头,从adts头获取aac配置信息
_aac_cfg = makeAacConfig((uint8_t *) (frame->data())); _aac_cfg = makeAacConfig((uint8_t *) (frame->data()), frame->prefixSize());
} }
makeConfigPacket(); makeConfigPacket();
} }

View File

@ -23,7 +23,7 @@ class AACRtmpDecoder : public RtmpCodec , public ResourcePoolHelper<AACFrame> {
public: public:
typedef std::shared_ptr<AACRtmpDecoder> Ptr; typedef std::shared_ptr<AACRtmpDecoder> Ptr;
AACRtmpDecoder(const Track::Ptr &track); AACRtmpDecoder() {}
~AACRtmpDecoder() {} ~AACRtmpDecoder() {}
/** /**
@ -37,13 +37,10 @@ public:
return CodecAAC; return CodecAAC;
} }
protected: private:
void onGetAAC(const char *data, int len, uint32_t stamp); void onGetAAC(const char *data, int len, uint32_t stamp);
AACFrame::Ptr obtainFrame();
protected: private:
AACFrame::Ptr _frame;
AACTrack::Ptr _track;
string _aac_cfg; string _aac_cfg;
}; };
@ -80,6 +77,8 @@ private:
private: private:
uint8_t _audio_flv_flags; uint8_t _audio_flv_flags;
AACTrack::Ptr _track;
string _aac_cfg;
}; };
}//namespace mediakit }//namespace mediakit

View File

@ -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) { 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); auto aacTrack = dynamic_pointer_cast<AACTrack>(track);
if(!aacTrack || !aacTrack->ready()){ if (!aacTrack || !aacTrack->ready()) {
WarnL << "该aac track无效!"; WarnL << "该aac track无效!";
}else{ } else {
_aac_cfg = aacTrack->getAacCfg(); _aac_cfg = aacTrack->getAacCfg();
} }
_adts = obtainFrame(); _frame = obtainFrame();
} }
AACRtpDecoder::AACRtpDecoder() { AACRtpDecoder::AACRtpDecoder() {
_adts = obtainFrame(); _frame = obtainFrame();
} }
AACFrame::Ptr AACRtpDecoder::obtainFrame() { AACFrame::Ptr AACRtpDecoder::obtainFrame() {
//从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象 //从缓存池重新申请对象,防止覆盖已经写入环形缓存的对象
auto frame = ResourcePoolHelper<AACFrame>::obtainObj(); auto frame = ResourcePoolHelper<AACFrame>::obtainObj();
frame->_prefix_size = ADTS_HEADER_LEN; frame->_prefix_size = 0;
//预留7个字节的空位以便后续覆盖 frame->_buffer.clear();
frame->_buffer.assign(ADTS_HEADER_LEN,(char)0);
return frame; return frame;
} }
@ -94,19 +94,18 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) {
//忽略Au-Header区 //忽略Au-Header区
ptr += 2 + au_header_count * 2; ptr += 2 + au_header_count * 2;
static const uint32_t max_size = AAC_MAX_FRAME_SIZE - ADTS_HEADER_LEN;
while (ptr < end) { while (ptr < end) {
auto size = (uint32_t) (end - ptr); auto size = (uint32_t) (end - ptr);
if(size > max_size){ if (size > AAC_MAX_FRAME_SIZE) {
size = max_size; size = AAC_MAX_FRAME_SIZE;
} }
if (_adts->size() + size > AAC_MAX_FRAME_SIZE) { if (_frame->size() + size > AAC_MAX_FRAME_SIZE) {
//数据太多了,先清空 //数据太多了,先清空
flushData(); flushData();
} }
//追加aac数据 //追加aac数据
_adts->_buffer.append((char *)ptr, size); _frame->_buffer.append((char *) ptr, size);
_adts->_dts = rtppack->timeStamp; _frame->_dts = rtppack->timeStamp;
ptr += size; ptr += size;
} }
@ -118,15 +117,21 @@ bool AACRtpDecoder::inputRtp(const RtpPacket::Ptr &rtppack, bool key_pos) {
} }
void AACRtpDecoder::flushData() { void AACRtpDecoder::flushData() {
if (_adts->size() == ADTS_HEADER_LEN) { if (_frame->_buffer.empty()) {
//没有有效数据 //没有有效数据
return; return;
} }
//覆盖adts头 //插入adts头
dumpAacConfig(_aac_cfg, _adts->size(), (uint8_t *) _adts->data()); char adts_header[32] = {0};
RtpCodec::inputFrame(_adts); auto size = dumpAacConfig(_aac_cfg, _frame->_buffer.size(), (uint8_t *) adts_header, sizeof(adts_header));
_adts = obtainFrame(); if (size > 0) {
//插入adts头
_frame->_buffer.insert(0, adts_header, size);
_frame->_prefix_size = size;
}
RtpCodec::inputFrame(_frame);
_frame = obtainFrame();
} }

View File

@ -31,16 +31,19 @@ public:
*/ */
bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override; bool inputRtp(const RtpPacket::Ptr &rtp, bool key_pos = false) override;
CodecId getCodecId() const override{ CodecId getCodecId() const override {
return CodecAAC; return CodecAAC;
} }
protected: protected:
AACRtpDecoder(); AACRtpDecoder();
private: private:
AACFrame::Ptr obtainFrame(); AACFrame::Ptr obtainFrame();
void flushData(); void flushData();
private: private:
AACFrame::Ptr _adts; AACFrame::Ptr _frame;
string _aac_cfg; string _aac_cfg;
}; };
@ -71,8 +74,10 @@ public:
* @param frame dats头的aac数据 * @param frame dats头的aac数据
*/ */
void inputFrame(const Frame::Ptr &frame) override; void inputFrame(const Frame::Ptr &frame) override;
private: private:
void makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp); void makeAACRtp(const void *pData, unsigned int uiLen, bool bMark, uint32_t uiStamp);
private: private:
unsigned char _aucSectionBuf[1600]; unsigned char _aucSectionBuf[1600];
}; };