学习内容:
本章探讨如何将h264的 avpacket的视频 数据,通过RTP协议发送到 流媒体 服务器 或者 对端接受者。
前提
我们在将 YUV数据变成avframe后,通过h264 编码变成AVPacket,例如,在安防项目中,或者直播中,需要将 avpacket发送到 流媒体服务器 或者 对端,那么如何做呢?
H264格式的回顾
音视频开发14 FFmpeg 视频 相关格式分析 -- H264 NALU格式分析-CSDN博客
这里将关键点 摘录出来:
帧内压缩: H264将图像分块为⽚、宏块和字块进⾏分⽚传输;通过这个过程实现对视频⽂件的压缩包装。
帧间压缩: H264采⽤了独特的I帧、P帧和B帧策略 来实现,连续帧之间的压缩;
H264编码结构- NALU
H.264 原始码流 ( 裸流 ) 是由⼀个接⼀个 NALU 组成。
就像下面这样:
NALU Header
F为禁⽌位,占1bit
forbidden_zero_bit: 在 H.264 规范中规定了这⼀位必须为 0。
R为重要性指示位,占2个bit
nal_ref_idc:取00~11,似乎指示这个NALU的重要性,如00的NALU解码器可以丢弃它⽽不影响图像的回放,0~3,取值越⼤,表示当前NAL越重要,需要优先受到保护。如果当前 NAL是属于参考帧的⽚,或是序列参数集,或是图像参数集这些重要的单位时,本句法元 素必需⼤于0。
T为负荷数据类型,占5bit
nal_unit_type:这个NALU单元的类型,1~12由H.264使⽤,24~31由H.264以外的应⽤
0 Unspecified non-VCL
未指定
1 Coded slice of a non-IDR picture VCL
⼀个⾮IDR图像的编码条带slice_layer_without_partitioning_rbsp()
2 Coded slice data partition A VCL
编码条带数据分割块A slice_data_partition_a_layer_rbsp()
3 Coded slice data partition B VCL
编码条带数据分割块B slice_data_partition_b_layer_rbsp( )
4 Coded slice data partition C VCL
编码条带数据分割块C slice_data_partition_c_layer_rbsp( )
5 Coded slice of an IDR picture VCL
IDR图像的编码条带(⽚) slice_layer_without_partitioning_rbsp( )
6 Supplemental enhancement information (SEI) non-VCL
辅助增强信息 (SEI)sei_rbsp( )
7 Sequence parameter set non-VCL
序列参数集 seq_parameter_set_rbsp( )
8 Picture parameter set non-VCL
图像参数集 pic_parameter_set_rbsp( )
9 Access unit delimiter non-VCL
访问单元分隔符 access_unit_delimiter_rbsp( )
10 End of sequence non-VCL
序列结尾 end_of_seq_rbsp( )
11 End of stream non-VCL
流结尾end_of_stream_rbsp( )
12 Filler data non-VCL
填充数据filler_data_rbsp( )
13 Sequence parameter set extension non-VCL
序列参数集扩展seq_parameter_set_extension_rbsp( )
14 Prefix NAL unit non-VCL
NAL 单元前缀
15 Subset sequence parameter set non-VCL
子集序列参数集
16 Depth parameter set non-VCL
深度参数集
17..18 Reserved non-VCL
保留
19 Coded slice of an auxiliary coded picture without partitioning non-VCL
未分割的辅助编码图像的编码条带slice_layer_without_partitioning_rbsp( )
20 Coded slice extension non-VCL
编码切片扩展
21 Coded slice extension for depth view components non-VCL
深度视图组件的编码切片扩展
22..23 Reserved non-VCL
保留
24..31 Unspecified non-VCL
未定义
H264对于内部连接一个一个的NALU有两种模式
AnnexB模式: ffmpeg解析出来的模式
AVCC模式: 存储在本地的mp4文件的模式
因此 存在AnnexB模式 和 AVCC模式转换的问题
解决方案:如下博客搜索 “AnnexB和 AVCC的转换"
音视频开发14 FFmpeg 视频 相关格式分析 -- H264 NALU格式分析-CSDN博客
AnnexB模式下的 一个一个NALU 的链接方式
[StartCode] [NALU Header] [NALU Payload]
每个NALU = StartCode + 由一个1字节的NALU头部 + 一个包含控制信息或编码视频数据的字节流组成。
⼀个原始的 H.264 NALU 单元
通常由 [StartCode] [NALU Header] [NALU Payload] 三部分组成。
Start Code
Start Code ⽤于标示这是⼀个NALU 单元的开始,
必须是"00 00 00 01" 或"00 00 01",
H.264标准指出,当数据流是储存在介质上时,在每个NALU 前添加起始码:0x000001 或
0x00000001,⽤来指示⼀个NALU 的起始和终⽌位置:
在这样的机制下,在码流中检测起始码,作为⼀个NALU得起始标识,当检测到下⼀个起始码时,当前NALU结束。
3字节的0x000001只有⼀种场合下使⽤,就是⼀个完整的帧被编为多个slice(⽚)的时
候,包含这些slice的NALU 使⽤3字节起始码。其余场合都是4字节0x00000001的。
AVCC 模式下的一个一个NALU的链接方式
也叫mp4 模式,⼀般 mp4 mkv 都是 mp4 模式,没有 startcode , SPS 和 PPS 以及其它信息
被封装在extradata 也叫做 container中,每⼀个 frame 前⾯ 4 个字节是这个 frame 的⻓度
回顾:将avpacket 存储为h264代码
音视频开发21 FFmpeg 视频解复用练习,将一个mp4文件,分解成一个aac文件 和 h264文件_ffmpeg解复用mp4例程-CSDN博客
核心内容如下:
当我们从mp4中读取到 video stream 的avpacket 后,如果存储到h264文件,存储的内容为 avpacket的data,存储的大小为avpacket 的size,如下的核心代码。h264_fd 为要存储到的out.h264文件的句柄。
-
fwrite(avpacket->data, 1, avpacket->size, h264_fd);
avpacket 和 NAL关系
例如对于H.264来说。1个AVPacket的data通常对应一个NAL。【注意:此处强调是“通常”,不是“所有”】
注意:在这里只是对应,而不是一模一样。他们之间有区别,区别的部分可以参考雷神的博客,核心内容是:
通过查看FFMPEG源代码我们发现,AVPacket中data的数据起始处没有分隔符(0x00000001), 也不是0x65、0x67、0x68、0x41等字节,所以可以AVPacket肯定这不是标准的nalu。其实,AVPacket前4个字表示的是nalu的长度,从第5个字节开始才是nalu的数据。所以直接将AVPacket前4个字节替换为0x00000001即可得到标准的nalu数据。
关于雷神的这个博客,猜测有可能是分析的a.mp4文件读取后的avpacket,这和AVCC模式很像,前面4个字节都是大小,那么问题是,如果是从 ffmpeg 中通过读取到数据是AnnexB 模式的,带有startcode,又如何呢?
使用FFMPEG类库分离出多媒体文件中的H.264码流_ffmpeg 抽码流-CSDN博客