加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

解密H264、AAC硬件解码的关键扩展数据处理

发布时间:2020-12-14 02:38:50 所属栏目:大数据 来源:网络整理
导读:??? 通过上一篇文章,我们用 ffmpeg 分离出一个多媒体容器中的音视频数据,但是很可能这些数据是不能被正确解码的。为什么呢?因为在解码这些数据之前,需要对解码器做一些配置,典型的就是目前流行的高清编码“黄金搭档”组合 H264 + AAC 的搭配。本文将讲

??? 通过上一篇文章,我们用ffmpeg分离出一个多媒体容器中的音视频数据,但是很可能这些数据是不能被正确解码的。为什么呢?因为在解码这些数据之前,需要对解码器做一些配置,典型的就是目前流行的高清编码“黄金搭档”组合H264 + AAC的搭配。本文将讲述H264AAC的关键解码配置参数的解析,如果没有这些配置信息,数据帧往往不完整,导致了解码器不能解码。

  • H264的配置信息解析

    前面我们知道,ffmpegavformat_find_stream_info函数可以取得音视频媒体多种,比如播放持续时间、音视频压缩格式、音轨信息、字幕信息、帧率、采样率等。在信息结果中有一项扩展数据描述(avcodec.h文件中):

????????? AVCodecContext定义如下:

????如果视频流是H264,这个extradate里面就包含了H264的配置信息,这个扩展数据有如下定义:

??? 详细解释可以参考ISO-14496-15 AVC file format文档。里面最重要的就是NAL长度和SPSPPS数据和对应的长度信息。对该数据的解析在ffmpeg里面有现成的函数:ff_h264_decode_extradata,在我的项目里面是自己写的扩展数据解析。

  • AAC的配置信息解析及设置

    如果音频数据是AAC流,在解码时需要ADTS(Audio Data Transport Stream)头部,不管是容器封装还是流媒体,没有这个,一般都是不能播放的。很多朋友在做AAC流播放时遇到播不出声音,很可能就是这个原因导致。

    ADTS所需的数据仍然是放在上面的扩展数据extradata中,我们需要先解码这个扩展数据,然后再从解码后的数据信息里面重新封装成头信息,加到每一帧数据之前再送解码器,这样就可以正常解码了。

    extradate数据定义如下:

    ?

    ??? 详细信息及说明请参考“ISO-IEC-14496-3 (Audio)”的AudioSpecificConfig部分。里面最重要的部分有采样频率、通道配置和音频对象类型,这几个一般都是AAC解码器需要的配置参数。

    ??? 这个数据在ffmpeg中也有相应的解码函数:avpriv_aac_parse_header。在我的项目中,我没有使用这个函数,而是自己实现的

typedef?struct??

{

???? ?int?write_adts;??

??????int?objecttype;??

??????int?sample_rate_index;??

??????int?channel_conf;??

}ADTSContext;??

typedef?struct
{
??????int?write_adts;
??????int?objecttype;
??????int?sample_rate_index;
??????int?channel_conf;
}ADTSContext;

??????? int?aac_decode_extradata(ADTSContext?*adts,?unsigned?char?*pbuf,?int?bufsize)??


{??

??????int?aot,?aotext,?samfreindex;??

??????int?i,?channelconfig;??

??????unsigned?char?*p?=?pbuf;??

???

??????if?(!adts?||?!pbuf?||?bufsize<2)??

??????{??

????????????return?-1;??

??????}??

??????aot?=?(p[0]>>3)&0x1f;??

??????if?(aot?==?31)??

??????{??

????????????aotext?=?(p[0]<<3?|?(p[1]>>5))?&?0x3f;??

????????????aot?=?32?+?aotext;??

????????????samfreindex?=?(p[1]>>1)?&?0x0f;??

?????????????

????????????if?(samfreindex?==?0x0f)??

????????????{??

??????????????????channelconfig?=?((p[4]<<3)?|?(p[5]>>5))?&?0x0f;??

????????????}??

????????????else??

????????????{??

??????????????????channelconfig?=?((p[1]<<3)|(p[2]>>5))?&?0x0f;??

????????????}??

??????}??

??????else??

??????{??

????????????samfreindex?=?((p[0]<<1)|p[1]>>7)?&?0x0f;??

????????????if?(samfreindex?==?0x0f)??

????????????{??

??????????????????channelconfig?=?(p[4]>>3)?&?0x0f;??

????????????}??

????????????else??

????????????{??

??????????????????channelconfig?=?(p[1]>>3)?&?0x0f;??

????????????}??

??????}??

???

#ifdef?AOT_PROFILE_CTRL??

??????if?(aot?<?2)?aot?=?2;??

#endif??

??????adts->objecttype?=?aot-1;??

??????adts->sample_rate_index?=?samfreindex;??

??????adts->channel_conf?=?channelconfig;??

??????adts->write_adts?=?1;??

???

??????return?0;??

}??

int?aac_decode_extradata(ADTSContext?*adts,?unsigned?char?*pbuf,?int?bufsize)
{
??????int?aot,?samfreindex;
??????int?i,?channelconfig;
??????unsigned?char?*p?=?pbuf;
?
??????if?(!adts?||?!pbuf?||?bufsize<2)
??????{
????????????return?-1;
??????}
??????aot?=?(p[0]>>3)&0x1f;
??????if?(aot?==?31)
??????{
????????????aotext?=?(p[0]<<3?|?(p[1]>>5))?&?0x3f;
????????????aot?=?32?+?aotext;
????????????samfreindex?=?(p[1]>>1)?&?0x0f;
???????????
????????????if?(samfreindex?==?0x0f)
????????????{
??????????????????channelconfig?=?((p[4]<<3)?|?(p[5]>>5))?&?0x0f;
????????????}
????????????else
????????????{
??????????????????channelconfig?=?((p[1]<<3)|(p[2]>>5))?&?0x0f;
????????????}
??????}
??????else
??????{
????????????samfreindex?=?((p[0]<<1)|p[1]>>7)?&?0x0f;
????????????if?(samfreindex?==?0x0f)
????????????{
??????????????????channelconfig?=?(p[4]>>3)?&?0x0f;
????????????}
????????????else
????????????{
??????????????????channelconfig?=?(p[1]>>3)?&?0x0f;
????????????}
??????}
?
#ifdef?AOT_PROFILE_CTRL
??????if?(aot?<?2)?aot?=?2;
#endif
??????adts->objecttype?=?aot-1;
??????adts->sample_rate_index?=?samfreindex;
??????adts->channel_conf?=?channelconfig;
??????adts->write_adts?=?1;
?
??????return?0;
}

?????????? 上面的pbuf就是extradata

??? 接下来,再用ADTSContext数据编码为ADTS头信息插入每一个AAC帧前面:

?????? ?int?aac_set_adts_head(ADTSContext?*acfg,0);">char?*buf,0);">int?size)??


{?????????

??????unsigned?char?byte;??

???

??????if?(size?<?ADTS_HEADER_SIZE)??

??????{??

????????????return?-1;??

??????}??

???????

??????buf[0]?=?0xff;??

??????buf[1]?=?0xf1;??

??????byte?=?0;??

??????byte?|=?(acfg->objecttype?&?0x03)?<<?6;??

??????byte?|=?(acfg->sample_rate_index?&?0x0f)?<<?2;??

??????byte?|=?(acfg->channel_conf?&?0x07)?>>?2;??

??????buf[2]?=?byte;??

??????byte?=?0;??

??????byte?|=?(acfg->channel_conf?&?0x07)?<<?6;??

??????byte?|=?(ADTS_HEADER_SIZE?+?size)?>>?11;??

??????buf[3]?=?byte;??

??????byte?=?0;??

??????byte?|=?(ADTS_HEADER_SIZE?+?size)?>>?3;??

??????buf[4]?=?byte;??

??????byte?=?0;??

??????byte?|=?((ADTS_HEADER_SIZE?+?size)?&?0x7)?<<?5;??

??????byte?|=?(0x7ff?>>?6)?&?0x1f;??

??????buf[5]?=?byte;??

??????byte?=?0;??

??????byte?|=?(0x7ff?&?0x3f)?<<?2;??

??????buf[6]?=?byte;??

???

??????return?0;??

}??

int?aac_set_adts_head(ADTSContext?*acfg,?unsigned?char?*buf,?int?size)
{???????
??????unsigned?char?byte;
?
??????if?(size?<?ADTS_HEADER_SIZE)
??????{
????????????return?-1;
??????}
?????
??????buf[0]?=?0xff;
??????buf[1]?=?0xf1;
??????byte?=?0;
??????byte?|=?(acfg->objecttype?&?0x03)?<<?6;
??????byte?|=?(acfg->sample_rate_index?&?0x0f)?<<?2;
??????byte?|=?(acfg->channel_conf?&?0x07)?>>?2;
??????buf[2]?=?byte;
??????byte?=?0;
??????byte?|=?(acfg->channel_conf?&?0x07)?<<?6;
??????byte?|=?(ADTS_HEADER_SIZE?+?size)?>>?11;
??????buf[3]?=?byte;
??????byte?=?0;
??????byte?|=?(ADTS_HEADER_SIZE?+?size)?>>?3;
??????buf[4]?=?byte;
??????byte?=?0;
??????byte?|=?((ADTS_HEADER_SIZE?+?size)?&?0x7)?<<?5;
??????byte?|=?(0x7ff?>>?6)?&?0x1f;
??????buf[5]?=?byte;
??????byte?=?0;
??????byte?|=?(0x7ff?&?0x3f)?<<?2;
??????buf[6]?=?byte;
?
??????return?0;
}

? 这个头部是固定的7字节长度,所以可提前空出这7个字节供ADTS占用。

? 通过以上对H264AAC的扩展数据处理,播放各种“黄金搭档”的多媒体文件、流媒体、视频点播等都应该没有问题了。

?

? 想第一时间获得更多原创文章,请关注个人微信公众平台:程序员互动联盟(coder_online),扫一扫下方二维码或者搜索微信号coder_online即可关注,里面有大量AndroidChromiumLinux等相关文章等着您,我们还可以在线交流。

??????? 如需转载本文,请注明出处:谢谢合作!

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读