1. 音视频解封装流程分析
音视频解封装是指将音频流和视频流从多媒体文件(如MP4、MKV、FLV等)中提取出来的过程。在FFmpeg中,我们通过以下步骤来完成解封装:
- 初始化:首先我们需要使用
avformat_open_input()函数打开媒体文件。这个函数会根据输入的文件名和文件格式,打开相应的文件并为其分配一个AVFormatContext结构。 - 获取流信息:使用
avformat_find_stream_info()函数获取媒体文件中的流信息。这个函数会填充AVFormatContext结构中的各个字段,如流的数量、每个流的类型(音频流、视频流或字幕流)等。 - 查找解码器:每个流都与一个解码器相关联,我们需要找到并打开这个解码器。我们可以通过
AVCodecParameters结构中的codec_id字段来获取解码器的ID,然后使用avcodec_find_decoder()函数查找解码器。找到解码器后,我们需要使用avcodec_open2()函数打开解码器。 - 读取和解码数据包:使用
av_read_frame()函数从AVFormatContext中读取数据包。这个函数会返回一个AVPacket结构,该结构包含了数据包的所有信息,如数据包所在的流、数据包的大小、数据包的时间戳等。然后我们需要使用avcodec_send_packet()和avcodec_receive_frame()函数将数据包发送到解码器并获取解码后的帧。 - 关闭和清理:解封装和解码完成后,我们需要关闭解码器和输入文件,并释放所有分配的内存。我们可以使用
avcodec_close()函数关闭解码器,使用avformat_close_input()函数关闭输入文件。
2. ACC ADTS分析
AAC ADTS(Audio Data Transport Stream)是一种用于在无损或有损压缩音频数据中,传输 AAC(Advanced Audio Coding)编码音频数据的格式。下面是一个 ADTS 数据帧的头格式:
ADTS Fixed header (28 bits):
- Syncword (12 bits): always 0xFFF
- MPEG Version (1 bit): 0 for MPEG-4, 1 for MPEG-2
- Layer (2 bits): always 0
- Protection absent (1 bit)
- Profile (2 bits)
- Sampling frequency index (4 bits)
- Private bit (1 bit)
- Channel configuration (3 bits)
- Originality (1 bit)
- Home (1 bit)
- Copyright identifier bit (1 bit)
- Copyright identifier start (1 bit)
ADTS Variable header (28 bits):
- Frame length (13 bits)
- Buffer fullness (11 bits)
- Number of AAC frames (RDBs) in ADTS frame (2 bits)
ADTS Error check (16 bits, optional): CRC
以下是各个字段的详细解释:
- Syncword: 0xFFF,固定的同步字,标志着 ADTS 帧的开始。
- MPEG Version: 用于标识 AAC 的版本,0 代表 MPEG-4,1 代表 MPEG-2。
- Layer: 在 ADTS 中,这个字段总是为 0。
- Protection absent: 如果设置为 1,则表示没有 CRC 校验,否则有 CRC 校验。
- Profile: 标志着 AAC 的编码级别。
- Sampling frequency index: 对应到采样率,例如 44.1 KHz、48 KHz 等。
- Private bit: 私有位,一般总是为 0。
- Channel configuration: 声道配置,例如立体声、5.1 声道等。
- Originality, Home, Copyright identifier bit, Copyright identifier start: 这些字段在大多数情况下都被设置为 0。
- Frame length: 该字段包含整个 ADTS 帧的长度,包括头部和数据。
- Buffer fullness: 编码器的缓冲区充满程度。
- Number of AAC frames (RDBs) in ADTS frame: 表示每个 ADTS 帧中包含的 AAC 帧数量。
下面是一个例子:为一个 AAC 数据帧创建 ADTS 头部。这个例子使用 MPEG-4、采样率为 44.1 KHz、2 声道的配置,展示如何在 C 语言中生成一个 ADTS 头部:
#include <stdio.h>
#include <stdint.h>
// 创建 ADTS 头
void createAdtsHeader(uint8_t* header, int dataLength) {
// 变量定义
int sampling_frequency_index = 4; // 44.1KHz
int channel_config = 2; // 声道
// ADTS 固定头部
header[0] = 0xFF; // 同步字: 0xFFF, 所有位都必须是 1
header[1] = 0xF1; // MPEG-4, 层: 0, 无 CRC
header[2] = ((1<<6) + (sampling_frequency_index<<2) + (channel_config>>2));
header[3] = ((channel_config&3)<<6) + ((dataLength+7)>>11);
header[4] = ((dataLength+7) & 0x7FF) >> 3;
header[5] = (((dataLength+7) & 7) << 5) + 0x1F;
header[6] = 0xFC;
}
// 主函数
int main() {
uint8_t adts_header[7];
int dataLength = 1024; // 假设一个 AAC 帧的长度是 1024 字节
createAdtsHeader(adts_header, dataLength);
for (int i = 0; i < 7; i++) {
printf("%02x ", adts_header[i]);
}
printf("\n");
return 0;
}
在这段代码中,我们首先定义了我们要使用的音频配置:MPEG-4、44.1 KHz 的采样率和立体声声道。然后我们定义了一个函数 createAdtsHeader,它接受一个字节数组和数据长度作为输入,并填充字节数组以创建 ADTS 头部。ADTS 头部总是 7 个字节。
在主函数中,我们创建一个字节数组,指定一个假设的 AAC 帧长度(在实际应用中,这应该是封装的 AAC 数据帧的真实长度),然后调用 createAdtsHeader 函数。最后打印出 ADTS 头部的内容,每个字节以十六进制格式显示。
运行这段代码会得到一个 7 字节的 ADTS 头部,它可以直接前置到 AAC 数据帧前,形成一个完整的 ADTS 帧。
3. H264 NALU分析
H.264,也被称为AVC(Advanced Video Coding,高级视频编码),是一种视频压缩标准,其目标是提供良好的视频质量,同时降低数据率(即文件大小)。 H.264编码原理:
- 预测编码:H.264使用两种预测技术,即空间预测和时间预测。空间预测用于I帧(内部帧),而时间预测用于P帧(预测帧)和B帧(双向预测帧)。
- 变换和量化:预测误差通过离散余弦变换(DCT)变换为频域,然后通过量化步骤简化。
- 熵编码:H.264编码器使用CAVLC(上下文自适应变长编码)或CABAC(上下文自适应二进制算术编码)进行熵编码。这两种方法都能进一步压缩数据,不过CABAC更复杂,但能提供更好的压缩性能。
H.264编码结构解析:
-
NAL单元:H.264的编码结构被称为网络抽象层(Network Abstraction Layer,简称NAL)。NAL单元(NALU)是H.264编码的最小数据单元。每个NALU都有一个头部和有效载荷。头部包含NALU的类型,有效载荷包含编码的视频数据。
-
编码类型:H.264编码中有多种不同类型的帧,包括I帧、P帧和B帧。I帧是完全自我编码的帧。P帧是基于之前的I帧或P帧预测的帧。B帧则是基于之前和之后的帧进行预测的帧。
-
SPS和PPS:序列参数集(Sequence Parameter Sets,简称SPS)和图像参数集(Picture Parameter Sets,简称PPS)是H.264视频的重要组成部分。SPS包含视频序列的参数,而PPS包含特定图像的参数。视频解码器需要这两种参数集才能正确解码视频。
H.264 的数据编码结构被称为网络抽象层(Network Abstraction Layer,简称 NAL)。NAL 单元(NALU)是 H.264 编码的最小数据单元。NALU 主要由两部分组成:NALU 头部和载荷(Payload)。
-
NALU 头部:头部包含一个字节,主要包括两个字段:forbidden_zero_bit、NAL reference idc和 NAL unit type。
- forbidden_zero_bit:始终为 0。如果为 1,表示此 NALU 存在错误,需要立即丢弃。
- NAL reference idc:表示该 NALU 的重要性,例如是否关键帧等信息。
- NAL unit type:NALU 类型,表示 NALU 是序列参数集、图像参数集、切片等类型。
-
载荷(Payload) :Payload 通常包含原始的 H.264 视频数据。
H.264 视频流就是由一个个 NALU 串接起来的。在 H.264 的实际应用中,为了能够区分两个 NALU 之间的边界,会在每个 NALU 前面加上一个开始码(Start Code),它通常是 0x000001 或者 0x00000001。
对于 NAL unit type,常见的类型包括:
- 类型为 5:IDR(即时刷新)图像的 NAL 单元。在这个 NALU 之后,所有图像都独立于以前的图像。通常情况下,编码器会周期性地插入 IDR 图像。IDR 图像之间的图像序列称为一个“GOP”。
- 类型为 7:序列参数集(SPS)的 NAL 单元。它包含关于视频序列的一些参数。
- 类型为 8:图像参数集(PPS)的 NAL 单元。它包含关于图像的一些参数。
4. FLV解封装格式
FLV(Flash Video)是Adobe开发的一种流媒体格式,主要用于网络视频播放。FLV文件主要包括头部信息(Header)、FLV标签(FLV Tags,包括音频、视频以及脚本标签)以及其他数据。
1. FLV头部信息(Header)
FLV文件的头部包括了9个或更多字节,分为3个部分:Signature、Version和Flags,以及Header Size。
Signature:占3个字节,一般为"FLV",表示文件类型。Version:占1个字节,表示FLV的版本,目前为1。Flags:占1个字节,表示文件体中存在的类型,例如音频或视频。Header Size:占4个字节,表示头部的长度,一般为9。
2. FLV标签(FLV Tags)
每个FLV标签都对应一块数据(音频、视频或者脚本)。标签的开始总是由Previous Tag Size字段标记的。
Previous Tag Size:占4个字节,表示前一个Tag的长度。Tag Type:占1个字节,表示Tag的类型,音频(8)、视频(9)或脚本(18)。Data Size:占3个字节,表示数据区的大小。Timestamp:占3个字节,表示该Tag在流中的时间基准,单位是毫秒。Timestamp Extended:占1个字节,扩展时间戳,当24位时间戳不够用时使用。StreamID:占3个字节,总是0。
之后就是Tag Data,长度由Data Size字段给出,存储具体的音频数据、视频数据或者元数据。
3. 音频数据和视频数据
音频和视频数据位于FLV标签中,音频或视频数据的格式取决于其编码方式。例如,音频数据可以被编码为AAC,MP3等,视频数据可以被编码为H.264,VP6等。
4. 元数据(Script Data)
元数据主要包含了与整个FLV文件有关的信息,例如duration(时长)、width、height(视频的宽和高)、videodatarate(视频数据率)等。
元数据是以脚本标签的形式存在,可以在文件的任何位置,但通常在文件开始部分,方便快速获取视频的基本信息。
具体的FLV标签数据的解析,需要根据FLV规范,和具体的音视频编码格式去解析。
5. MP4封装格式剖析
MP4(MPEG-4 Part 14)是一种常见的多媒体容器格式,用于封装音频、视频、字幕和元数据等多种媒体数据。下面是对MP4封装格式的详细剖析,包括其各个组成部分和它们之间的关系:
-
头部(Header):
- MP4文件以一个头部开始,包含了一些关键信息,如文件类型和版本信息。
- 头部通常有12个字节,包括一个固定的8字节签名("ftyp")和一个4字节的版本信息。
-
元数据(Metadata):
- MP4格式支持多种元数据格式,如ID3标签、iTunes元数据、Exif数据等。
- 这些元数据可以包含有关媒体文件的信息,如标题、艺术家、发行日期等。
-
音频轨道(Audio Track):
- MP4可以容纳一个或多个音频轨道,每个轨道都包括音频编解码器类型、采样率、通道数和音频数据。
- 音频数据通常以AAC(Advanced Audio Coding)或MP3等格式进行编码。
-
视频轨道(Video Track):
- MP4可以容纳一个或多个视频轨道,每个轨道都包括视频编解码器类型、帧率、分辨率和视频数据。
- 视频数据通常以H.264、H.265(HEVC)或VP9等编码格式进行编码。
-
时间轴(Timecode):
- MP4文件包括一个时间轴,用于记录每个媒体样本(音频或视频帧)的时间戳信息,以确保正确的播放顺序和同步。
-
同步轨道(Synchronization Track):
- 同步轨道用于指示媒体文件中音频和视频轨道之间的同步关系,以确保它们在播放时能够正确地配合。
-
字幕和章节轨道(Subtitles and Chapters Track):
- MP4还支持包含字幕和章节信息的轨道,这些信息可以用于添加字幕、章节导航和其他交互式功能。
-
样本表(Sample Table):
- 样本表是MP4文件中最重要的部分之一,它记录了媒体文件中每个样本的位置、大小和时间戳信息。
- 样本表包括时间戳表(Time-to-Sample)、同步采样表(Sync Sample)、块表(Chunk Offset)、样本描述表(Sample Description)等。
-
媒体数据(Media Data):
- 媒体数据部分包含了实际的音频和视频样本数据,这些数据通常是压缩过的。
- 样本表中的信息帮助解析器定位和解码媒体数据。
-
索引表(Index Table):
- 索引表用于加速访问媒体数据,它包含了样本的索引信息,以便快速跳转到特定的媒体位置。
MP4文件的结构允许将多种类型的媒体数据有序封装在一起,以便于播放和传输。不同类型的轨道和元数据一起构成了完整的媒体体验。解码器和播放器使用MP4文件中的头部信息、样本表和索引表来解析和播放媒体文件,确保音频和视频的同步和正确顺序。这种封装格式的灵活性和通用性使得MP4成为流行的多媒体容器格式之一。