全志H616 通过Cedrus和v4l2_request API实现硬件编解码加速(香橙派zero2)

本文主要是介绍全志H616 通过Cedrus和v4l2_request API实现硬件编解码加速(香橙派zero2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

编译安装或加载cedrus驱动模块,加载v4l2-mem2mem

Sunxi-Cedrus 致力于为全志 SoC 提供硬件加速的视频解码和编码支持,并将其引入主线 Linux 内核。此外,还为典型的基于 GNU/Linux 的系统提供了与内核驱动程序接口的其他用户空间组件。

Sunxi-Cedrus - linux-sunxi.org

如果你的kernel中不包含sunxi-cedrus驱动、v4l2-mem2mem,可能要从源码开始编译该模块。

对于香橙派zero2,sunxi-cedrus视频编解码驱动存在于 Linux 内核源码drivers/staging/media/sunxi/cedrus目录,而v4l2相关支持在drivers/media/v4l2-core/中,通过编译orangepi提供的源码我们可以知道,sunxi-cedrus已被编译为模块但并未加载,需要我们手动加载。

sudo modprobe sunxi-cedrus
sudo modprobe v4l2_mem2memlsmod | grep cedrus
dmesg | grep cedrus
lsmod | grep v4l2_mem2memecho "sunxi-cedrus" | sudo tee -a /etc/modules #系统在启动时自动加载 sunxi-cedrus 模块

我们可以观察到,cedrus已在系统中成功注册,并注册为/dev/video0,并提醒驱动来自于 Linux 内核的“staging”目录,这意味着该模块可能还不完全稳定或经过充分测试。

请添加图片描述

对 Sunxi-Cedrus 的支持是通过内核空间或用户空间中的各种组件实现的:

  • Cedrus V4L2 M2M 内核驱动程序
  • v4l2 请求 VAAPI 后端

此外,还提供了其他用户空间组件,用于开发目的:

  • v4l2-request-test 工具,允许测试 -Cedrus VPU 驱动程序
  • libdrm-sun4i,支持以 VPU 使用的 MB32 平铺 NV12 格式分配缓冲区**(已弃用)**
  • libva-dump VAAPI,允许从视频中转储元数据和切片

支持 libVA 的视频播放器应与 v4l2-request libVA 后端兼容。但是,实现中的某些细节可能会导致与某些播放器不兼容。

下表显示了 v4l2-request libVA 后端中特定编解码器的支持状态:

请添加图片描述

下表显示了对 V4L2 M2M 内核驱动程序中特定 SoC 的支持:

请添加图片描述

以下播放器使用 v4l2-request libVA 后端进行了测试:

请添加图片描述

采用Gstreamer工具进行硬件编解码的测试

安装Gstreamer和相关插件,加载必要模块

sudo apt update
sudo apt install gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav
sudo apt install v4l-utils
gst-launch-1.0 --versionsudo modprobe videobuf2-core
sudo modprobe videobuf2-memops
sudo modprobe videobuf2-vmalloc
sudo modprobe videobuf2-v4l2
sudo modprobe v4l2-mem2mem
sudo modprobe sunxi-cedrus

查看H.264相关的编解码支持

gst-inspect-1.0 | grep 264root@orangepizero2:~# gst-inspect-1.0 | grep 264
libav:  avdec_h264: libav H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 decoder
libav:  avenc_h264_omx: libav OpenMAX IL H.264 video encoder encoder
libav:  avmux_ipod: libav iPod H.264 MP4 (MPEG-4 Part 14) muxer
openh264:  openh264dec: OpenH264 video decoder
openh264:  openh264enc: OpenH264 video encoder
rtp:  rtph264depay: RTP H264 depayloader
rtp:  rtph264pay: RTP H264 payloader
typefindfunctions: video/x-h264: h264, x264, 264
uvch264:  uvch264deviceprovider (GstDeviceProviderFactory)
uvch264:  uvch264mjpgdemux: UVC H264 MJPG Demuxer
uvch264:  uvch264src: UVC H264 Source
v4l2codecs:  v4l2slh264dec: V4L2 Stateless H.264 Video Decoder  
# v4l2slh264dec这是一个 V4L2 Stateless H.264 Video Decoder,用于硬件加速解码。
videoparsersbad:  h264parse: H.264 parser
x264:  x264enc: x264 H.264 Encoder

那么,可以先用本地mp4视频测试硬件解码,并将解码数据直接保存保存为原始 YUV 格式文件(例如 NV12 或 I420),我们可以看到v4l2-ctl显示了香橙派的/dev/video0设备支持的视频捕获格式

root@orangepizero2:~# v4l2-ctl --list-formats-ext -d /dev/video0
ioctl: VIDIOC_ENUM_FMTType: Video Capture[0]: 'ST12' (Y/UV 4:2:0 (32x32 Linear))[1]: 'NV12' (Y/UV 4:2:0)

利用Gstreamer解码本地命令

gst-launch-1.0 -v filesrc location=input.mp4 ! qtdemux ! h264parse ! v4l2slh264dec ! videoconvert ! video/x-raw,format=I420 ! filesink location=output.yuv

出现报错,从dmesg日志中可以看出,cedrus 视频编解码器在尝试分配 DMA 内存时失败了。这通常表示系统内存不足或者 DMA 分配失败。解码 H.264/H.265 视频可能需要大量的 CMA 内存,因此建议设置一个大型 CMA 池,例如使用内核命令行参数。例如,256 MiB 应该足以解码 1080p H.264 视频。

/boot/orangepiEnv.txt中添加或修改如下行:

extraargs=cma=256M

接下来,我们尝试编码推流,但是我们发现Gstreamer工具中v4l2并没有适用硬件加速编码的支持。

先尝试软件编码推流,安装RTSP服务

sudo apt-get install gir1.2-gst-rtsp-server-1.0 libgstrtspserver-1.0-0 libgstrtspserver-1.0-dev

编写服务器推流代码,命名为 rtsp-server.c

#include <gst/gst.h>
#include <gst/rtsp-server/rtsp-server.h>int main(int argc, char *argv[]) {gst_init(&argc, &argv);GstRTSPServer *server = gst_rtsp_server_new();gst_rtsp_server_set_service(server, "8554");GstRTSPMountPoints *mounts = gst_rtsp_server_get_mount_points(server);GstRTSPMediaFactory *factory = gst_rtsp_media_factory_new();// 使用v4l2src从摄像头采集视频,并使用x264enc进行编码gst_rtsp_media_factory_set_launch(factory,"( v4l2src device=/dev/video1 ! video/x-raw,width=640,height=480 ! videoconvert ! video/x-raw,format=I420 ! x264enc tune=zerolatency profile=main ! rtph264pay name=pay0 pt=96 )");gst_rtsp_mount_points_add_factory(mounts, "/test", factory);g_object_unref(mounts);gst_rtsp_server_attach(server, NULL);g_print("stream ready at rtsp://192.168.137.189:8554/test\n");GMainLoop *loop = g_main_loop_new(NULL, FALSE);g_main_loop_run(loop);gst_object_unref(server);g_main_loop_unref(loop);return 0;
}

使用GCC编译器编译代码,链接GStreamer库。

gcc rtsp-server.c -o rtsp-server `pkg-config --cflags --libs gstreamer-1.0 gstreamer-rtsp-server-1.0`
./rtsp-server

这样就会启动RTSP服务器,并开始推流。你可以使用VLC或其他支持RTSP的媒体播放器来访问和观看流媒体。例如,在VLC中打开网络串流,输入RTSP流地址(比如 rtsp://192.168.137.189:8554/test),就可以观看视频流了。延时大概2秒左右,cpu占用率80%。

尝试ffmpeg工具进行硬件编解码的测试

  1. 安装 Cedrus 支持的第一步是构建一个具有驱动程序最新补丁系列的 Linux 内核。这一步香橙派已经替我们完成了。
  2. 支持 Cedrus VPU 驱动程序的主要用户空间组件是 libva-v4l2-request VAAPI 后端
git clone https://github.com/bootlin/libva-v4l2-request -b release-2019.03
cd libva-v4l2-request
./autogen.sh && make && sudo make install

在这里插入图片描述

系统中缺少对应的定义,这可能是因为我的 V4L2 (Video4Linux) 头文件版本不支持 HEVC (High Efficiency Video Coding) 的相关功能。

config.c

/*found = v4l2_find_format(driver_data->video_fd,V4L2_BUF_TYPE_VIDEO_OUTPUT,V4L2_PIX_FMT_HEVC_SLICE);if (found && index < (V4L2_REQUEST_MAX_CONFIG_ATTRIBUTES - 1))profiles[index++] = VAProfileHEVCMain;
*/

context.c

	case VAProfileHEVCMain://pixelformat = V4L2_PIX_FMT_HEVC_SLICE;pixelformat = V4L2_PIX_FMT_H264_SLICE;break;

在这里插入图片描述

h264-ctrls.h

/*注释掉重复的结构体定义
struct v4l2_ctrl_h264_pps {__u8 pic_parameter_set_id;__u8 seq_parameter_set_id;__u8 num_slice_groups_minus1;__u8 num_ref_idx_l0_default_active_minus1;__u8 num_ref_idx_l1_default_active_minus1;__u8 weighted_bipred_idc;__s8 pic_init_qp_minus26;__s8 pic_init_qs_minus26;__s8 chroma_qp_index_offset;__s8 second_chroma_qp_index_offset;__u16 flags;
};struct v4l2_ctrl_h264_scaling_matrix {__u8 scaling_list_4x4[6][16];__u8 scaling_list_8x8[6][64];
};struct v4l2_h264_weight_factors {__s8 luma_weight[32];__s8 luma_offset[32];__s8 chroma_weight[32][2];__s8 chroma_offset[32][2];
};
*/
//修改v4l2_h264_dpb_entry
struct v4l2_h264_dpb_re_entry {__u64 timestamp;__u16 frame_num;__u16 pic_num;/* Note that field is indicated by v4l2_buffer.field */__s32 top_field_order_cnt;__s32 bottom_field_order_cnt;__u32 flags; /* V4L2_H264_DPB_ENTRY_FLAG_* */
};struct v4l2_ctrl_h264_decode_param {__u32 num_slices;__u16 idr_pic_flag;__u16 nal_ref_idc;__u8 ref_pic_list_p0[32];__u8 ref_pic_list_b0[32];__u8 ref_pic_list_b1[32];__s32 top_field_order_cnt;__s32 bottom_field_order_cnt;struct v4l2_h264_dpb_re_entry dpb[16];
};

h264.c

static void h264_fill_dpb(struct request_data *data,struct object_context *context,struct v4l2_ctrl_h264_decode_param *decode)
{int i;for (i = 0; i < H264_DPB_SIZE; i++) {struct v4l2_h264_dpb_re_entry *dpb = &decode->dpb[i];struct h264_dpb_entry *entry = &context->dpb.entries[i];struct object_surface *surface =SURFACE(data, entry->pic.picture_id);uint64_t timestamp;if (!entry->valid)continue;if (surface) {timestamp = v4l2_timeval_to_ns(&surface->timestamp);dpb->timestamp = timestamp;}dpb->frame_num = entry->pic.frame_idx;dpb->top_field_order_cnt = entry->pic.TopFieldOrderCnt;dpb->bottom_field_order_cnt = entry->pic.BottomFieldOrderCnt;dpb->flags = V4L2_H264_DPB_RE_ENTRY_FLAG_VALID;if (entry->used)dpb->flags |= V4L2_H264_DPB_RE_ENTRY_FLAG_ACTIVE;if (entry->pic.flags & VA_PICTURE_H264_LONG_TERM_REFERENCE)dpb->flags |= V4L2_H264_DPB_RE_ENTRY_FLAG_LONG_TERM;}
}

在这里插入图片描述

编译器在链接过程中找不到 tiled_to_planar 函数的定义,我们尝试手动编译和链接

sudo apt-get install --reinstall libtool-bin
root@orangepizero2:~/libva-v4l2-request# libtool --mode=compile gcc -c src/tiled_yuv.S -o src/tiled_yuv.lolibtool: compile:  gcc -c src/tiled_yuv.S  -fPIC -DPIC -o src/.libs/tiled_yuv.o
libtool: compile:  gcc -c src/tiled_yuv.S -o src/tiled_yuv.o >/dev/null 2>&1
root@orangepizero2:~/libva-v4l2-request#

make编译依然失败,查看tiled_yuv.S汇编源文件,发现是针对 ARMv7 架构的汇编代码,需要改为适合 aarch64 架构的汇编代码。

这篇关于全志H616 通过Cedrus和v4l2_request API实现硬件编解码加速(香橙派zero2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/1025005

相关文章

SpringBoot实现微信小程序支付功能

《SpringBoot实现微信小程序支付功能》小程序支付功能已成为众多应用的核心需求之一,本文主要介绍了SpringBoot实现微信小程序支付功能,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录一、引言二、准备工作(一)微信支付商户平台配置(二)Spring Boot项目搭建(三)配置文件

基于Python实现高效PPT转图片工具

《基于Python实现高效PPT转图片工具》在日常工作中,PPT是我们常用的演示工具,但有时候我们需要将PPT的内容提取为图片格式以便于展示或保存,所以本文将用Python实现PPT转PNG工具,希望... 目录1. 概述2. 功能使用2.1 安装依赖2.2 使用步骤2.3 代码实现2.4 GUI界面3.效

MySQL更新某个字段拼接固定字符串的实现

《MySQL更新某个字段拼接固定字符串的实现》在MySQL中,我们经常需要对数据库中的某个字段进行更新操作,本文就来介绍一下MySQL更新某个字段拼接固定字符串的实现,感兴趣的可以了解一下... 目录1. 查看字段当前值2. 更新字段拼接固定字符串3. 验证更新结果mysql更新某个字段拼接固定字符串 -

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

Java Optional避免空指针异常的实现

《JavaOptional避免空指针异常的实现》空指针异常一直是困扰开发者的常见问题之一,本文主要介绍了JavaOptional避免空指针异常的实现,帮助开发者编写更健壮、可读性更高的代码,减少因... 目录一、Optional 概述二、Optional 的创建三、Optional 的常用方法四、Optio

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

Spring Boot项目中结合MyBatis实现MySQL的自动主从切换功能

《SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能》:本文主要介绍SpringBoot项目中结合MyBatis实现MySQL的自动主从切换功能,本文分步骤给大家介绍的... 目录原理解析1. mysql主从复制(Master-Slave Replication)2. 读写分离3.

Redis实现延迟任务的三种方法详解

《Redis实现延迟任务的三种方法详解》延迟任务(DelayedTask)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下... 目录1.前言2.Redis如何实现延迟任务3.代码实现3.1. 过期键通知事件实现3.2. 使用ZSet实现延迟任务3.3

基于Python和MoviePy实现照片管理和视频合成工具

《基于Python和MoviePy实现照片管理和视频合成工具》在这篇博客中,我们将详细剖析一个基于Python的图形界面应用程序,该程序使用wxPython构建用户界面,并结合MoviePy、Pill... 目录引言项目概述代码结构分析1. 导入和依赖2. 主类:PhotoManager初始化方法:__in

springboot filter实现请求响应全链路拦截

《springbootfilter实现请求响应全链路拦截》这篇文章主要为大家详细介绍了SpringBoot如何结合Filter同时拦截请求和响应,从而实现​​日志采集自动化,感兴趣的小伙伴可以跟随小... 目录一、为什么你需要这个过滤器?​​​二、核心实现:一个Filter搞定双向数据流​​​​三、完整代码