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

发布时间:2020-07-29 19:49:00 作者:yanggq
来源:网络 阅读:645

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

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

          AVCodecContext定义如下:

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

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

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

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

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, 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;
}

           上面的pbuf就是extradata

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

        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;  

}  

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等相关文章等着您,我们还可以在线交流。

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

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


推荐阅读:
  1. Android中获取手机支持的硬件解码器类型以及对应的解码器名称
  2. AAC ADTS头详解

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

多媒体 ffmpeg h264

上一篇:Go语言的包管理

下一篇:运维思考 | 你知道CMDB与监控是什么关系吗?

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》