【RK3588】mpp解码v4l2采集的h264码流

前言

  所需要的东西均放在Gitee:https://gitee.com/x_du/rk3588-mpp-h264-v4l2

H264码流类型

  首先,NALU是网络提取层NAL(Network Abstraction Layer) 的组成单元。如图1所示。
在这里插入图片描述

图1 NALU单元

  我们今天要分析的h264码流类型位于 NAL unit header中。NAL unit header仅占1个字节,由如下三部分组成。
在这里插入图片描述

图2 NALU的头部

字段介绍

forbidden_zero_bit

  在网络传输中发生错误时,会被置为 1,告诉接收方丢掉该单元;否则为 0。

nal_ref_idc

  用于表示当前NALU的重要性,值越大,越重要。解码器在解码处理不过来的时候,可以丢掉重要性为 0 的 NALU。

nal_unit_type

  表示 NALU 数据的类型,有以下几种:
在这里插入图片描述

图3 264帧类型

   ● 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开头的
在这里插入图片描述

图4 前八字节二进制数据

  从上述码流中可以看出我的 【startcode】0x 00 00 00 01 四字节组成的,接下来的一个字节就是我们上边提到的NAL unit header部分,例如68、06。0x68 = 0 11 01000 ,从左到右解释 0 11 010000代表传输正确,11代表当前NALU是最重要的,01000 代表PPS帧,0x06代表的就是SEI帧。
  使用方法
  解压 二进制码流查看工具中的压缩包->双击HxD.exe
在这里插入图片描述

图5 二进制码流查看工具HxD

整帧数据分析

  在网上阅读文章的时候,我发现,一帧数据中可能是有多个NALU的,也就是说,一帧数据中有可能有SPS、PPS和I帧等。为了验证这个发现是正确的,我将每帧二进制码流数据都保存起来,然后我又在网上搜索可以分析264码流的工具,最终找到了H264BSAnalyzer工具(放在gittee,链接在文章底部)。
  使用方法
  解压H264码流分析工具的压缩包->双击release

在这里插入图片描述

图6 H264码流分析工具1
  双击其中的exe可执行文件

在这里插入图片描述

图7 H264码流分析工具2

  点击File
在这里插入图片描述

图8 H264码流分析工具3

  选择demo_data文件夹中的数据,发现没有数据,是因为下边只过滤后缀是.h264和.h265的
在这里插入图片描述

图9 H264码流分析工具4

  而我提供的数据是以bin结尾的,如下图所示。
在这里插入图片描述

图10 H264码流分析工具5

  ● frame_data_all.bin代表的每帧的完整数据
  ● frame_info_all-data.txt 统计的是第几帧及其对应的字节数
  ● frame_headers_8.bin代表的是每帧的前八个字节

  这个自己也可以手动修改.bin为.h264,或者按照我下边的办法来
将这里选成All Files就行,这样所有文件都会显示出来
在这里插入图片描述

图10 H264码流分析工具6

  打开后的结果是这样子的
在这里插入图片描述
  画面如下,我把镜头放反了哈哈哈
在这里插入图片描述

  在这里我验证了一帧数据中可能有多个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/

### RK3588多媒体处理管道(MPP)架构 RK3588芯片集成了强大的多媒体处理能力,其多媒体处理管道(Media Processing Pipeline, MPP)设计用于高效处理视频编解码、图像处理和其他多媒体任务。该架构支持多种硬件加速模块,旨在提供高性能的同时降低功耗。 #### 架构概述 MPP由多个核心组件构成: - **VPU (Video Processing Unit)**:负责视频编解码操作,支持主的视频标准如H.264/H.265等。 - **ISP (Image Signal Processor)**:专注于摄像头输入信号的预处理工作,包括降噪、色彩校正等功能。 - **GPU**:图形渲染单元可以辅助进行复杂的视觉效果计算以及部分AI推理运算。 - **NPU (Neural Processing Unit)**:神经网络处理器专门针对机器学习模型执行优化过的算法实现快速推断过程[^2]。 这些部件通过内部总线紧密相连,在操作系统层面提供了统一的应用编程接口(API),使得开发者能够方便地调用底层资源来构建丰富的多媒体应用。 #### 使用教程 为了充分利用RK3588上的MPP特性,建议按照如下指南开发应用程序: ##### 初始化环境配置 安装必要的软件包并设置好交叉编译工具链以便于后续的操作系统移植与驱动程序编写。对于Linux平台而言,则需准备内核源树及其补丁文件以适应特定板级需求。 ```bash sudo apt-get update && sudo apt-get install build-essential git-core gcc-aarch64-linux-gnu git clone https://github.com/rockchip-linux/kernel.git -b rk3588 cd kernel/ patch -p1 < /path/to/rk3588_patches/*.patch ``` ##### 编写测试代 创建简单的C/C++项目结构,并利用Rockchip官方提供的API库来进行基本的功能验证实验。下面是一个展示如何打开摄像机并将帧数据传递给ISP做初步处理的例子: ```c #include <fcntl.h> #include <linux/videodev2.h> // ...其他头文件... int main() { int fd = open("/dev/video0", O_RDWR); struct v4l2_format fmt; memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; ioctl(fd, VIDIOC_G_FMT, &fmt); // 获取当前格式 // 设置新的像素格式... fmt.fmt.pix.width = 1920; fmt.fmt.pix.height = 1080; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; ioctl(fd, VIDIOC_S_FMT, &fmt); // 启动捕获程... } ``` 此段代片段展示了访问视频设备节点的方式之一,实际应用场景下还需要考虑更多细节比如缓冲区管理、同步机制等问题。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱叨叨的小嘟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值