05_解封装和解码

1. 基本概念

容器就是一种文件格式,比如flv、mkv、mp4等。包含下面5种流以及文件头信息。
是一种视频数据信息的传输方式,5种流:音频,视频,字幕,附件,数据。
在ffmpeg中代表已经编码好的一个单位的音频或者视频。
在ffmpeg中帧代表一幅静止的图像(yuv数据)或一些数量的音频采样。
编解码器是对视频进行压缩或者解压缩,CODEC =ENCode (编码) +DECode(解码)
复用/解复用(mux/demux)

  • 把不同的流按照某种容器的规则放入容器,这种行为叫做复用(mux)

  • 把不同的流从某种容器中解析出来,这种行为叫做解复用(demux)

下面ffmpeg将h264+aac编码的flv文件转码为 h265+mp3编码的mp4文件的处理流程:

flv文件
解复用器
音频包aac
视频包h264
aac音频解码器
原始音频采样pcm
mp3音频编码器
音频包mp3
h264视频解码器
原始视频数据yuv
h265视频编码器
视频包h265
mp4复用器
mp4文件

2. 解封装操作

2.1 封装相关API

◼ AVFormatContext* avformat_alloc_context();负责申请一个AVFormatContext结构的内存,并进行简单初始化
◼ avformat_free_context();释放该结构里的所有东西以及该结构本身
◼ avformat_close_input();关闭解复用器。关闭后就不再需要使用avformat_free_context 进行释放。
◼ avformat_open_input();打开输入视频文件
◼ avformat_find_stream_info():获取视频文件信息
◼ av_read_frame(); 读取音视频包
◼ avformat_seek_file(); 定位文件
◼ av_seek_frame():定位文件

2.2 解封装流程

  1. 创建avformat上下文(可选)

    AVFormatContext* avformat_alloc_context();
    

    因为调用avformat_open_input函数时会创建, 所以不是必须调用,结束时必须使用avformat_free_context()销毁AVFormatContext指针

  2. 打开输入文件

    // ps	指向AVFormatContext的指针,可以用avformat_alloc_context()提前申请,当然也可直接用  
    //      avformat_open_input函数生成,不论哪种方式,都必须使用avformat_free_context()销毁该指针
    //url	要打开的媒体流地址(或文件路径)
    //fmt	输入类型,如果此参数不为空,则强制设置输入媒体的类型(如flv、mp4等)
    //options 可选的选项,此处参考ffmpeg命令行操作里的一些输入参数,如reorder_queue_size、
    //        stimeout、scan_all_pmts 等等。使用av_dict_set()函数设置,使用av_dict_free()释放。
    int avformat_open_input(AVFormatContext **ps, const char *url, ff_const59 AVInputFormat *fmt, AVDictionary **options);
    

    该函数作用是打开一个输入流(或者文件)并且读取媒体头信息(如音视频编码类型等等)。
    任务结束时使用函数 avformat_close_input()关闭。

  3. 获取码流信息

    区分不同的码流

    ◼ AVMEDIA_TYPE_VIDEO视频流
    video_index = av_find_best_stream(ic, AVMEDIA_TYPE_VIDEO,-1,-1, NULL, 0)
    ◼ AVMEDIA_TYPE_AUDIO音频流
    audio_index = av_find_best_stream(ic, AVMEDIA_TYPE_AUDIO,-1,-1, NULL, 0)
    AVPacket 里面也有一个index的字段
    

    由于需要读取数据包,avformat_find_stream_info接口会带来很大的延迟。

    //读取媒体文件的数据包以获取流信息。 这个对于没有header的文件格式(例如MPEG)很有用。
    // 总之使用该函数可以将输入流(文件)中的媒体信息(包括编码信息)解析出来。
    // 通过ic->streams[i]访问,streams的个数由ic->nb_streams获取。
    int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)
    
  4. 读取音视频包

    //将输入文件或输入URL的流内容读取到AVPacket中
    int av_read_frame(AVFormatContext *s, AVPacket *pkt);
    

2.3 解复用代码示例

代码地址,打印信息如下
在这里插入图片描述

3. AAC ADTS格式分析

AAC⾳频格式:Advanced Audio Coding(⾼级⾳频解码),是⼀种由MPEG-4标准定义的有损⾳频压缩格式,由Fraunhofer发展,Dolby, Sony和AT&T是主要的贡献者。

  • ADIF:Audio Data Interchange Format ⾳频数据交换格式。这种格式的特征是可以确定的找到这个⾳频数据的开始,不需进⾏在⾳频数据流中间开始的解码,即它的解码必须在明确定义的开始处进⾏。故这种格式常⽤在磁盘⽂件中。

  • ADTS的全称是Audio Data Transport Stream。是AAC⾳频的传输流格式。AAC⾳频格式在MPEG-2(ISO-13318-7 2003)中有定义。AAC后来⼜被采⽤到MPEG-4标准中。这种格式的特征是它是⼀个有同步字的⽐特流,解码可以在这个流中任何位置开始。它的特征类似于mp3数据流格式。

简单说,ADTS可以在任意帧解码,也就是说它每⼀帧都有头信息。ADIF只有⼀个统⼀的头,所以必须得到所有的数据后解码。

且这两种的header的格式也是不同的,⽬前⼀般编码后的和抽取出的都是ADTS格式的⾳频流。两者具体的组织结构如下所示:

有的时候当你编码AAC裸流的时候,会遇到写出来的AAC⽂件并不能在PC和⼿机上播放,很⼤的可能就是AAC⽂件的每⼀帧⾥缺少了ADTS头信息⽂件的包装拼接, 比如MP4和FLV中的aac音频。解决方法:只需要加⼊头⽂件ADTS即可。⼀个AAC原始数据块⻓度是可变的,对原始帧加 上ADTS头进⾏ADTS的封装,就形成了ADTS帧。

AAC音频文件中的每一帧是由ADTS Header 和 AAC Audio Data组成,结构图如下:

每⼀帧的ADTS的头⽂件都包含了⾳频的采样率,声道,帧⻓度等信息,这样解码器才能解析读取。
⼀般情况下ADTS的头信息都是7个字节,分为2部分:

  • adts_fixed_header();
  • adts_variable_header();

adts_fixed_header为固定头信息,adts_variable_header是可变头信息。固定头信息中的数据每⼀帧都相同,⽽可变头信息则在帧与帧之间可变。

3.1 adts_fixed_header

  • syncword:同步头 总是0xFFF, all bits must be 1,代表着⼀个ADTS帧的开始

  • ID:MPEG标识符,0标识MPEG-4,1标识MPEG-2

  • Layer:always: ‘00’

  • protection_absent:表示是否误码校验。Warning, set to 1 if there is no CRC and 0 if there is CRC

  • profile:表示使⽤哪个级别的AAC,如01 Low Complexity(LC)— AAC LC。有些芯⽚只⽀持AAC LC;MPEG-2 AAC中定义了3种:

并且profile的值等于 Audio Object Type的值减1 profile = MPEG-4 Audio Object Type - 1
在这里插入图片描述
在ffmpeg源码中我们可以找到AAC级别被设成的值,就不用上面的那个公式来计算了:

   /**
     * profile
     * - encoding: Set by user.
     * - decoding: Set by libavcodec.
     */
     int profile;
	#define FF_PROFILE_UNKNOWN -99
	#define FF_PROFILE_RESERVED -100
 
	#define FF_PROFILE_AAC_MAIN 0
	#define FF_PROFILE_AAC_LOW  1
	#define FF_PROFILE_AAC_SSR  2
	#define FF_PROFILE_AAC_LTP  3
	#define FF_PROFILE_AAC_HE   4
	#define FF_PROFILE_AAC_HE_V2 28
	#define FF_PROFILE_AAC_LD   22
	#define FF_PROFILE_AAC_ELD  38
	#define FF_PROFILE_MPEG2_AAC_LOW 128
	#define FF_PROFILE_MPEG2_AAC_HE  131
  • sampling_frequency_index:表示使⽤的采样率下标,通过这个下标在 Sampling Frequencies[ ]数组中查找得知采样率的值。

  • channel_configuration: 表示声道数,⽐如2表示⽴体声双声道

3.2 adts_variable_header

在这里插入图片描述

  • frame_length : ⼀个ADTS帧的⻓度包括ADTS头和AAC原始流. frame length, this value must include 7 or 9 bytes of header length: aac_frame_length = (protection_absent == 1 ? 7 : 9) + size(AACFrame)

    protection_absent=0时, header length=9bytes
    protection_absent=1时, header length=7bytes

  • adts_buffer_fullness:0x7FF 说明是码率可变的码流。number_of_raw_data_blocks_in_frame:表示ADTS帧中有 number_of_raw_data_blocks_in_frame + 1个AAC原始帧。所以说number_of_raw_data_blocks_i

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值