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

  • H264的配置信息解析

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

AVCodecContext定义如下:

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

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

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

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

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

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

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

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

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

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

解密H264、AAC硬件解码的关键扩展数据处理的更多相关文章

  1. (转) 解密H264、AAC硬件解码的关键扩展数据处理

    出自:http://blog.itpub.net/30168498/viewspace-1576794/       通过上一篇文章,我们用ffmpeg分离出一个多媒体容器中的音视频数据,但是很可能这 ...

  2. Android平台对H264视频硬解码

    本文讲述如何使用Android标准的API (MediaCodec)实现H264的硬件解码. 原本我们是用JNI调用平台提供的硬件解码接口得到YUV帧,再放入opengl脚本里处理渲染的.可是换了新平 ...

  3. 使用C#+FFmpeg+DirectX+dxva2硬件解码播放h264流

    本文门槛较高,因此行文看起来会乱一些,如果你看到某处能会心一笑请马上联系我开始摆龙门阵 如果你跟随这篇文章实现了播放器,那你会得到一个高效率,低cpu占用(单路720p视频解码播放占用1%左右cpu) ...

  4. iOS8系统H264视频硬件编解码说明

    公司项目原因,接触了一下视频流H264的编解码知识,之前项目使用的是FFMpeg多媒体库,利用CPU做视频的编码和解码,俗称为软编软解.该方法比较通用,但是占用CPU资源,编解码效率不高.一般系统都会 ...

  5. android Mediaplayer硬件解码浅探

    在讨论stagefright如何调用硬件解码之前,我们要先清楚几个问题. 我不展开这几个结论是如何得来的,因为这部分属于进程间通信binder的理解,和多媒体本身无关. 一.问题空间 这个有点像方法学 ...

  6. Android中使用MediaCodec硬件解码,高效率得到YUV格式帧,快速保存JPEG图片(不使用OpenGL)(附Demo)

    MediaCodec的使用demo: https://github.com/vecio/MediaCodecDemo https://github.com/taehwandev/MediaCodecE ...

  7. Android的音频解码原来是直接调用的本地C方法直接通过硬件解码

    Android就是披着JAVA外衣的C啊~音频解码原来是直接调用的本地C方法直接通过硬件解码的,JAVA和C的字节数组存放模式不同(java是大端,C根据不同平台不同),不同格式需要转化以后才能用. ...

  8. send/receive h264/aac file/data by rtp/rtsp over udp/tcp

    一.安装一些必要的调试工具 1.vlc安装sudo apt-get install vlcsudo apt-get install vlc-nox 2.ffmpeg安装,带ffplay,ffplay依 ...

  9. 转载:AAC编解码概述

    转自:http://www.cnblogs.com/gaozehua/archive/2012/05/03/2479960.html 编码概述 其整体AAC 编解码系统,如图所示,其编码流程概述如下: ...

随机推荐

  1. JS验证图片格式和大小并预览

    用于上传图片的js验证: <%@ page language="java" contentType="text/html; charset=UTF-8"p ...

  2. Devexpress RaisePropertyChanged

    所有的重载设置字段作为参数传递到指定的值,而属性提高INotifyPropertyChanged.PropertyChanged事件. 如果一个字段已经成功地改变,setProperty方法中返回真. ...

  3. 纯css3艺术文字样式效果代码

    效果:http://hovertree.com/texiao/css3/1/ 本效果主要使用text-shadow实现.参考:http://hovertree.com/h/bjaf/css3_text ...

  4. C#模拟Http请求时出现 基础连接已经关闭 未能为 SSLTLS 安全通道建立信任关系

    //解决方法: //引入命名空间: using System.Security.Cryptography.X509Certificates; using System.Net.Security; // ...

  5. Overload 和Override 的区别

    Overload 是重载的意思,Override 是覆盖的意思,也就是重写.重载 Overload 表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同).重写 ...

  6. socket编程-java

    一,网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可 ...

  7. 【来自媳妇的需求】PHP实现随机数和方程求解

    话说2015.11.06 ,北京下了第一场雪.16年的今天没下雪,但是雾霾还是不小的,帮媳妇整理她工作时,出现了下面的需求,便想到使用PHP来写程序来进行求解. [需求] 1. 给出一个平均值X,反过 ...

  8. Eclipse中的checkstyle插件

    一.Checkstyle工具 Checkstyle是一款检查Java程序源代码样式的工具,它可以有效的帮助我们检视代码以便更好的遵循代码编写标准. 官方地址:http://checkstyle.sou ...

  9. CSS3与页面布局学习笔记(七)——前端预处理技术(Less、Sass、CoffeeScript、TypeScript)

    CSS不像其它高级语言一样支持算术运算.变量.流程控制与面向对象特性,所以CSS样式较多时会引起一些问题,如修改复杂,冗余,某些别的语言很简单的功能实现不了等.而javascript则是一种半面向对象 ...

  10. Webstorm常用的快捷键

    WS的常用操作: 常用快捷键(Keymap/Eclipse): 复制当前行: Ctrl+Alt+↓ 向上/下移动当前行: Alt+↑/↓ 删除当前行: Ctrl+D 注释/取消当前行: Ctrl+/ ...