mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-29 14:45:55 +08:00
完善对高规格aac的支持
This commit is contained in:
parent
b9006a90d4
commit
efa92752c7
@ -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() {
|
||||||
|
@ -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头!";
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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];
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user