【RK3588】mpp解码v4l2采集的h264码流
前言
所需要的东西均放在Gitee:https://gitee.com/x_du/rk3588-mpp-h264-v4l2
H264码流类型
首先,NALU是网络提取层NAL(Network Abstraction Layer) 的组成单元。如图1所示。
我们今天要分析的h264码流类型位于 NAL unit header中。NAL unit header仅占1个字节,由如下三部分组成。

字段介绍
forbidden_zero_bit
在网络传输中发生错误时,会被置为 1,告诉接收方丢掉该单元;否则为 0。
nal_ref_idc
用于表示当前NALU的重要性,值越大,越重要。解码器在解码处理不过来的时候,可以丢掉重要性为 0 的 NALU。
nal_unit_type
表示 NALU 数据的类型,有以下几种:
● 1-4:I/P/B帧,如果 nal_ref_idc 为 0,则表示 I 帧,不为 0 则为 P/B 帧。
● 5:IDR帧,I 帧的一种,告诉解码器,之前依赖的解码参数集合(接下来要出现的 SPS\PPS 等)可以被刷新了。
● 6:SEI,英文全称 Supplemental Enhancement Information,翻译为“补充增强信息”,提供了向视频码流中加入额外信息的方法。
● 7:SPS,全称 Sequence Paramater Set,翻译为“序列参数集”。SPS 中保存了一组编码视频序列(Coded Video Sequence)的全局参数。因此该类型保存的是和编码序列相关的参数。
● 8: PPS,全称 Picture Paramater Set,翻译为“图像参数集”。该类型保存了整体图像相关的参数。
● 9:AU 分隔符,AU 全称 Access Unit,它是一个或者多个 NALU 的集合,代表了一个完整的帧,有时候用于解码中的帧边界识别。
特殊的 NALU 类型:SPS和PPS
SPS 和 PPS 存储了编解码需要的图像参数。SPS,PPS 需要在 I 帧前出现,不然解码器没法解码。而 SPS,PPS 出现的频率也跟不同应用场景有关,对于一个本地 h264 流,可能只要在第一个 I 帧前面出现一次就可以,但对于直播流,每个 I 帧前面都应该插入 sps 或 pps,因为直播时客户端进入的时间是不确定的。
遇到的问题
场景:使用v4l2采集264编码的摄像头视频,然后把采集到的一帧帧数据送入mpp解码器中完成解码。
在mpp解码的过程中,遇到前40-50帧的数据从结果上看解码成功,但是解码的数据是无效的,具体表现在变量rgbImage的宽高不符合预期:
MppFrameFormat format = mpp_frame_get_fmt(frame);
char *data_vir =(char *) mpp_buffer_get_ptr(mpp_frame_get_buffer(frame));
int fd = mpp_buffer_get_fd(mpp_frame_get_buffer(frame));
int y_size = hor_stride * ver_height;
int uv_offset = y_size + (ver_stride - ver_height) * hor_stride;
memmove(data_vir + y_size, data_vir + uv_offset, hor_stride * ver_stride / 2);
cv::Mat yuvImage(ver_stride + ver_stride / 2, hor_stride, CV_8UC1, (uint8_t*)data_vir);
cv::cvtColor(yuvImage, rgbImage, cv::COLOR_YUV420sp2RGB);
mpp默认解码的数据是YUV420SP格式的。我采用opencv的转换方式将YUV420SP转成RGB,之后存放在rgbImage中。
if(rgbImage.cols <=0 || rgbImage.rows <=0)
continue;
当我用这个进行判断的时候,rgbImage的宽高是<=0的,也就是说解码的数据是不可用的。
解决思路
针对上述现象,首先我猜想可能是代码逻辑有问题,之后我经过认真的分析与思考,最终排除该问题。然后我就坐在哪儿上不停地想,突然我产生了个想法,要不对捕获的二进制码流进行分析?
前8字节分析
说干就干。刚开始,我只是将每帧数据的前8字节保存(注:介绍264码流的文章中提到h264有个起始码 【startcode】, 为四字节,接下来的四字节应该紧接着存的是帧类型和数据)。
[start code]–[NALU]–[start code]–[NALU]…
于是我找了一个可以打开二进制码流的工具-HXD(位于二进制码流查看工具文件夹中),想看下我的码流是否有 【startcode】,结果如下图所示。会看到是以00 00 00 01开头的
从上述码流中可以看出我的 【startcode】 是 0x 00 00 00 01 四字节组成的,接下来的一个字节就是我们上边提到的NAL unit header部分,例如68、06。0x68 = 0 11 01000 ,从左到右解释 0 11 01000 , 0代表传输正确,11代表当前NALU是最重要的,01000 代表PPS帧,0x06代表的就是SEI帧。
使用方法
解压 二进制码流查看工具中的压缩包->双击HxD.exe
整帧数据分析
在网上阅读文章的时候,我发现,一帧数据中可能是有多个NALU的,也就是说,一帧数据中有可能有SPS、PPS和I帧等。为了验证这个发现是正确的,我将每帧二进制码流数据都保存起来,然后我又在网上搜索可以分析264码流的工具,最终找到了H264BSAnalyzer工具(放在gittee,链接在文章底部)。
使用方法
解压H264码流分析工具的压缩包->双击release
点击File
选择demo_data文件夹中的数据,发现没有数据,是因为下边只过滤后缀是.h264和.h265的
而我提供的数据是以bin结尾的,如下图所示。
● frame_data_all.bin代表的每帧的完整数据
● frame_info_all-data.txt 统计的是第几帧及其对应的字节数
● frame_headers_8.bin代表的是每帧的前八个字节
这个自己也可以手动修改.bin为.h264,或者按照我下边的办法来
将这里选成All Files就行,这样所有文件都会显示出来
打开后的结果是这样子的
画面如下,我把镜头放反了哈哈哈
在这里我验证了一帧数据中可能有多个NALU,比如 Frame0里边就有SPS、PPS、SEI和I帧
23+8+1052+454016=455099
这个数据的前边是我过滤的无效帧,因为我发现当没有SPS帧时,数据是无法解码成功的,这个也就解释了上述提到的这个问题----遇到前40-50帧的数据虽然解码是成功的,但是解码的数据是无效的。
结尾
- 在自己能力范围内将事情做到最好
- 有时间有需要记录的我都会写
- 对阅读者来说要是有价值的article
参考文章
二进制码流查看工具的安装教程:https://blog.csdn.net/Java_ZZZZZ/article/details/136039206
【H264】码流结构详解:https://www.cnblogs.com/linuxAndMcu/p/14533228.html
H.264——H.264的profile 和 level:https://blog.csdn.net/qq_28258885/article/details/118890413
H264参数SPS(序列参数集)和PPS(图像参数集)说明:https://blog.csdn.net/xiaozhiit/article/details/107095351
H264 NALU语法结构:https://zhuanlan.zhihu.com/p/760103792
h264检测是I帧还是P帧:https://blog.csdn.net/zgyulongfei/article/details/7558031
数据压缩实验–H.264码流分析:https://blog.csdn.net/m0_54222259/article/details/125492571?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522b4c223be2fe0c21481ddc6e51449b6d4%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=b4c223be2fe0c21481ddc6e51449b6d4&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-1-125492571-null-null.142%5ev102%5econtrol&utm_term=h264%E7%A0%81%E6%B5%81%E5%B7%A5%E5%85%B7&spm=1018.2226.3001.4187
h264 I帧的判断:https://blog.csdn.net/dxpqxb/article/details/13289205?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ECtr-1-13289205-blog-7558031.235%5Ev43%5Epc_blog_bottom_relevance_base8&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ECtr-1-13289205-blog-7558031.235%5Ev43%5Epc_blog_bottom_relevance_base8&utm_relevant_index=2
工具出处
软件可能有些bug,检测的帧数目有些问题,但是不影响分析
H264码流分析工具:https://github.com/latelee/H264BSAnalyzer
二进制码流查看工具:https://mh-nexus.de/en/hxd/