前言
最近使用 RK3588 在做音视频项目开发,过程中使用了该芯片提供的硬件编解码和 2D 图形加速能力,发现相比软编解码,硬编解码无论是处理速度、系统负载还是稳定性,都比软编解码强太多了。本文将分享如何使用 RK 提供的 FFmpeg + MPP + RGA,实现一个硬件编解码+2D图形加速的功能,全部使用命令行来完成。后面也会出一篇使用开发库实现的源码版。
本文不仅适用于 RK3588,也还适用于其他 RK 系列的芯片,具体的细节出入请参考官方文档。
本文首先简要介绍下 MPP 和 RGA,之后介绍如何编译项目,最后介绍如何使用命令来调动它们。关于命令的代码版,将会在之后的文章中介绍,敬请期待~
什么是 MPP
MPP(Media Process Platform)全称为媒体处理平台,它是 RK 提供的一个用于进行视频硬编解码的库。通过 MPP,我们就可以使用 RK 芯片的 VPU(Video Process Unit,视频处理单元)对我们的视频进行硬件编解码,从而减少 CPU 的负担,加快编解码速度。它的架构如下:
+---------------------------------------+
| |
| ffmpeg / OpenMax / gstreamer / libva |
| |
+---------------------------------------+
+-------------------- MPP ----------------------+
| |
| +-------------------------+ +--------+ |
| | | | | |
| | MPI / MPP | | | |
| | buffer queue manage | | | |
| | | | | |
| +-------------------------+ | | |
| | | |
| +-------------------------+ | | |
| | | | | |
| | codec | | OSAL | |
| | decoder / encoder | | | |
| | | | | |
| +-------------------------+ | | |
| | | |
| +-----------+ +-----------+ | | |
| | | | | | | |
| | parser | | HAL | | | |
| | recoder | | reg_gen | | | |
| | | | | | | |
| +-----------+ +-----------+ +--------| |
| |
+-------------------- MPP ----------------------+
+---------------------------------------+
| |
| kernel |
| RK vcodec_service / v4l2 |
| |
+---------------------------------------+
MPP 分别 4 个模块,分别是:
- MPP : 媒体处理平台
- MPI : 媒体处理接口
- HAL : 硬件抽象层
- OSAL : 操作系统抽象层
关于如何编译 MPP,会在下面进行介绍。
什么是 RGA
RGA(Raster Graphic Acceleration Unit)是一个独立的 2D 硬件加速器,可用于加速点/线绘制,执行图像缩放、旋转、bitBlt、alpha混合等常见的2D图形操作。
有时候我们在进行视频帧处理过程中,可能会对它进行缩放,比如摄像头捕获的是 2160P 的画面,我们想缩小到 1080P,传统的方式是使用 CPU 处理,但这会造成 CPU 的处理负担,而 RGA 提供了这个功能,可以把图形的缩放、旋转等方式放到这个硬件加速器中,加速处理。
关于如何查看 RGA 或 VPU 是否正在运行以及负载状态,可以参考我这篇文章:《瑞芯微 RK 系列 RK3588 CPU、GPU、NPU、VPU、RGA、DDR 状态查看与操作》
什么是 ffmpeg-rockchip
FFmpeg 是一个支持解码、编码、转码和流式传输多种媒体格式的多媒体框架。而 ffmpeg-rockchip 是在 FFmpeg 的基础上,封装了 MPP 编解码和 RGA 2D 图形加速功能,使得我们可以使用 FFmpeg 的 api 就能实现 MPP 和 RGA 的功能,大大降低开发成本。
下图展示了 ffmpeg-rockchip 源码库的 libavcodec 目录下的部分文件,libavcodec 目录主要是包含各种编解码器的实现,比如 h264、h265、aac 等等,而 ffmpeg-rockchip 在此基础上实现了 RK 的编解码器,比如 h264_rkmpp、hevc_rkmpp 的硬件编解码格式。
ffmpeg-rockchip 封装了如下格式:
解码器
V..... av1_rkmpp Rockchip MPP (Media Process Platform) AV1 decoder (codec av1)
V..... h263_rkmpp Rockchip MPP (Media Process Platform) H263 decoder (codec h263)
V..... h264_rkmpp Rockchip MPP (Media Process Platform) H264 decoder (codec h264)
V..... hevc_rkmpp Rockchip MPP (Media Process Platform) HEVC decoder (codec hevc)
V..... mpeg1_rkmpp Rockchip MPP (Media Process Platform) MPEG1VIDEO decoder (codec mpeg1video)
V..... mpeg2_rkmpp Rockchip MPP (Media Process Platform) MPEG2VIDEO decoder (codec mpeg2video)
V..... mpeg4_rkmpp Rockchip MPP (Media Process Platform) MPEG4 decoder (codec mpeg4)
V..... vp8_rkmpp Rockchip MPP (Media Process Platform) VP8 decoder (codec vp8)
V..... vp9_rkmpp Rockchip MPP (Media Process Platform) VP9 decoder (codec vp9)
编码器
V..... h264_rkmpp Rockchip MPP (Media Process Platform) H264 encoder (codec h264)
V..... hevc_rkmpp Rockchip MPP (Media Process Platform) HEVC encoder (codec hevc)
V..... mjpeg_rkmpp Rockchip MPP (Media Process Platform) MJPEG encoder (codec mjpeg)
过滤器
... overlay_rkrga VV->V Rockchip RGA (2D Raster Graphic Acceleration) video compositor
... scale_rkrga V->V Rockchip RGA (2D Raster Graphic Acceleration) video resizer and format converter
... vpp_rkrga V->V Rockchip RGA (2D Raster Graphic Acceleration) video post-process (scale/crop/transpose)
编译项目
一共要编译 3 个项目,因为 ffmpeg-rockchip 依赖于 MPP 和 RGA,先编译 MPP 和 RGA,最后编译 ffmpeg-rockchip,具体如下:
# 在ARM/ARM64主机上进行本地编译
# 编译 MPP
mkdir -p ~/dev && cd ~/dev
git clone -b jellyfin-mpp --depth=1 https://github.com/nyanmisaka/mpp.git rkmpp
pushd rkmpp
mkdir rkmpp_build
pushd rkmpp_build
cmake \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_SHARED_LIBS=ON \
-DBUILD_TEST=OFF \
..
make -j $(nproc)
make install
# 编译 RGA
sudo apt install meson ninja-build
mkdir -p ~/dev && cd ~/dev
git clone -b jellyfin-rga --depth=1 https://github.com/nyanmisaka/rk-mirrors.git rkrga
meson setup rkrga rkrga_build \
--prefix=/usr \
--libdir=lib \
--buildtype=release \
--default-library=shared \
-Dcpp_args=-fpermissive \
-Dlibdrm=false \
-Dlibrga_demo=false
meson configure rkrga_build
ninja -C rkrga_build install
# 构建FFmpeg(可自定义配置及安装路径)
mkdir -p ~/dev && cd ~/dev
git clone --depth=1 https://github.com/nyanmisaka/ffmpeg-rockchip.git ffmpeg
cd ffmpeg
./configure --prefix=/usr --enable-gpl --enable-version3 --enable-libdrm --enable-rkmpp --enable-rkrga
make -j $(nproc)
# 将FFmpeg安装到指定前缀路径
make install
注:如果看完上面教程还是不会编译项目的小伙伴,可以在评论区回复,我可以提供已经编译好的 arrch64 架构的库文件和头文件,你直接放到开发板即可使用。
// 下载地址,评论区一直发不出来,放这里
pan.baidu.com
/s/1MRv2SR6Fl-zscWLJSHNlfQ?pwd=54kh
是否有相应的编解码器和 rga
ffmpeg -decoders | grep rkmpp # 查看是否有 rk 的解码器
ffmpeg -encoders | grep rkmpp # 查看是否有 rk 的编码器
ffmpeg -filters | grep rkrga # 查看是否有 rk 的 rga
打印如下:
V..... av1_rkmpp Rockchip MPP (Media Process Platform) AV1 decoder (codec av1)
V..... h263_rkmpp Rockchip MPP (Media Process Platform) H263 decoder (codec h263)
V..... h264_rkmpp Rockchip MPP (Media Process Platform) H264 decoder (codec h264)
V..... hevc_rkmpp Rockchip MPP (Media Process Platform) HEVC decoder (codec hevc)
V..... mpeg1_rkmpp Rockchip MPP (Media Process Platform) MPEG1VIDEO decoder (codec mpeg1video)
V..... mpeg2_rkmpp Rockchip MPP (Media Process Platform) MPEG2VIDEO decoder (codec mpeg2video)
V..... mpeg4_rkmpp Rockchip MPP (Media Process Platform) MPEG4 decoder (codec mpeg4)
V..... vp8_rkmpp Rockchip MPP (Media Process Platform) VP8 decoder (codec vp8)
V..... vp9_rkmpp Rockchip MPP (Media Process Platform) VP9 decoder (codec vp9)
V..... h264_rkmpp Rockchip MPP (Media Process Platform) H264 encoder (codec h264)
V..... hevc_rkmpp Rockchip MPP (Media Process Platform) HEVC encoder (codec hevc)
V..... mjpeg_rkmpp Rockchip MPP (Media Process Platform) MJPEG encoder (codec mjpeg)
... overlay_rkrga VV->V Rockchip RGA (2D Raster Graphic Acceleration) video compositor
... scale_rkrga V->V Rockchip RGA (2D Raster Graphic Acceleration) video resizer and format converter
... vpp_rkrga V->V Rockchip RGA (2D Raster Graphic Acceleration) video post-process (scale/crop/transpose)
命令
编译好之后,我们就可以执行各种命令来测试我们想要的操作了。
查看编码器的选项
打印编码器的选项,可以让我们知道在使用编码器时应该传入什么选项,例如:
ffmpeg -hide_banner -h encoder=h264_rkmpp
输出如下:
Encoder h264_rkmpp [Rockchip MPP (Media Process Platform) H264 encoder]:
General capabilities: delay hardware
Threading capabilities: none
Supported hardware devices: rkmpp rkmpp drm
Supported pixel formats: gray yuv420p yuv422p yuv444p nv12 nv21 nv16 nv24 yuyv422 yvyu422 uyvy422 rgb24 bgr24 rgba rgb0 bgra bgr0 argb 0rgb abgr 0bgr drm_prime
h264_rkmpp_encoder AVOptions:
-rc_mode <int> E..V....... Set the encoding rate control mode (from 0 to 5) (default 5)
VBR 0 E..V.......
CBR 1 E..V.......
CQP 2 E..V.......
AVBR 3 E..V.......
-qp_init <int> E..V....... Set the initial QP value (from -1 to 51) (default -1)
-qp_max <int> E..V....... Set the max QP value for P and B frame (from -1 to 51) (default -1)
-qp_min <int> E..V....... Set the min QP value for P and B frame (from -1 to 51) (default -1)
-qp_max_i <int> E..V....... Set the max QP value for I frame (from -1 to 51) (default -1)
-qp_min_i <int> E..V....... Set the min QP value for I frame (from -1 to 51) (default -1)
-profile <int> E..V....... Set the encoding profile restriction (from -1 to 100) (default high)
baseline 66 E..V.......
main 77 E..V.......
high 100 E..V.......
-level <int> E..V....... Set the encoding level restriction (from -99 to 62) (default 0)
1 10 E..V.......
1.1 11 E..V.......
1.2 12 E..V.......
1.3 13 E..V.......
2 20 E..V.......
2.1 21 E..V.......
2.2 22 E..V.......
3 30 E..V.......
3.1 31 E..V.......
3.2 32 E..V.......
4 40 E..V.......
4.1 41 E..V.......
4.2 42 E..V.......
5 50 E..V.......
5.1 51 E..V.......
5.2 52 E..V.......
6 60 E..V.......
6.1 61 E..V.......
6.2 62 E..V.......
-coder <int> E..V....... Set the entropy coder type (from 0 to 1) (default cabac) (from 0 to 1) (default cabac)
cavlc 0 E..V.......
cabac 1 E..V.......
-8x8dct <boolean> E..V....... Set the high profile 8x8 transform (default true)
编码
下面的命令作用是:使用虚拟设备 lavfi 生成一个测试视频流,使用 hevc_rkmpp 编码器,CQP 速率控制,复用 mp4 容器文件
ffmpeg -f lavfi -i testsrc2=s=1920x1080,format=nv12 -c:v hevc_rkmpp -qp_init 26 -profile:v main -level 4.1 -g:v 100 -vframes 5000 -y /tmp/tmp.mp4
命令参数解释:
-f lavfi
:-f
选项指定输入格式,lavfi
是 FFmpeg 中的一个虚拟设备,用于生成来自 FFmpeg 内部的滤镜或测试源的数据流。-i testsrc2=s=1920x1080,format=nv12
:-i
选项指定输入文件或输入流。这里使用的是lavfi
生成的测试源(testsrc2
),它会产生一个测试图像作为视频流。生成的视频分辨率为 1920x1080,格式为 nv12。-c:v hevc_rkmpp
:指定使用 rockchip 的硬件加速编码器。-qp_init 26
:设置视频编码的初始量化参数(QP, Quantization Parameter),数值越小,视频质量越高,但文件越大;数值越大,视频质量降低但文件较小。-profile:v main
:设置视频编码的配置文件,这里是根据编码器提供的选项来设置的,通过上面的那个命令就可以知道编码器的参数选项有哪些。-level 4.1
:设置编码的级别。-g:v 100
:设置 GOP(Group of Pictures)的大小,也就是 I 帧间的间隔。-g:v 100
意味着每 100 帧插入一个 I 帧。-vframes 5000
:指定输出视频的帧数。-y
:表示在输出文件已存在时自动覆盖输出文件,而不进行提示。
解码
下面的命令作用是:解码 /path/to/any-h264-video.mp4
文件,一共解码 5000 帧
ffmpeg -stream_loop -1 -hwaccel rkmpp -hwaccel_output_format drm_prime -i /path/to/any-h264-video.mp4 -an -sn -vframes 5000 -f null -
命令参数解释:
-stream_loop -1
:表示视频输入流将会无限循环。-1
表示循环次数为无限,直到手动停止该命令。-hwaccel rkmpp
:启用硬件加速-hwaccel_output_format drm_prime
:指定硬件加速后的输出格式为drm_prime
。drm_prime
是一种 DRM(Direct Rendering Manager)接口的输出格式,通常用于 Linux 系统中进行高效的视频渲染,特别是在使用硬件加速的场景下。-i /path/to/any-h264-video.mp4
:指定输入文件路径。-an
:禁用音频流,忽略输入视频中的音频部分,不会进行解码或输出音频数据。-sn
:禁用字幕流,忽略视频中的字幕部分。-vframes 5000
:表示只处理视频中的前 5000 帧。即使视频文件有更长的时长,ffmpeg
也会停止处理,处理完 5000 帧之后退出。-f null
:指定输出格式为null
,意味着输出不会保存到文件。null
是一个虚拟格式,用于丢弃所有输出数据。通常用于测试或者性能分析。-
:表示ffmpeg
将输出到标准输出(即终端/控制台)。在这里,由于输出格式是null
,实际上没有任何文件会被生成。
使用 RGA 缩小分辨率
读取 V4L2 摄像头(我的摄像头是 IM415),将 2160P 缩小到 1080P,使用 h264_rkmpp 格式编码器,并推送到 rtsp 服务器:
ffmpeg -init_hw_device rkmpp=hw -filter_hw_device hw -vsync 2 -f v4l2 -i /dev/video11 -vf hwupload,scale_rkrga=w=1920:h=1080:format=nv12 -c:v h264_rkmpp -g:v 100 -qp_init 26 -f rtsp rtsp://192.168.31.253:8554/live/stream
命令参数解释:
-init_hw_device rkmpp=hw
:初始化一个名为hw
的硬件加速设备,使用rkmpp
作为 Rockchip 平台的硬件加速库(MultiMedia Processing Platform)。-filter_hw_device hw
:将上一步初始化的硬件设备(hw
)用于硬件滤镜。意味着后续的硬件处理将通过这个设备来完成。-vsync 2
:控制视频帧同步。设置为2
表示使用时间戳来调整视频帧的同步,确保输出的帧率正确并避免掉帧或重复帧。-f v4l2
:指定输入格式为v4l2
(Video4Linux2)。-i /dev/video11
:指定输入设备为/dev/video11
,即从该设备获取视频流。-vf hwupload,scale_rkrga=w=1920:h=1080:format=nv12
:将视频帧从 CPU 内存上传到硬件设备的内存中,以便硬件加速处理。使用rkrga
硬件加速库对视频进行缩放,调整视频的分辨率到 1920x1080,并且设置像素格式为nv12
。-c:v h264_rkmpp
:指定视频编码器为h264_rkmpp
。-g:v 100
:设置视频的 GOP(Group of Pictures)大小为 100。GOP 控制的是关键帧(I 帧)之间的间隔,100 帧的 GOP 大小表示每 100 帧中会有一个关键帧。-qp_init 26
:设置视频编码器的初始量化参数(QP)为 26。量化参数控制视频的压缩率和质量,数值越低,图像质量越好,但压缩率较低;数值越高,图像质量下降,压缩率增大。26 是一个中等质量的设置。-f rtsp
:指定输出格式为 RTSP(实时流协议)。
视频解码再转码
下面这个例子展示了同时使用了编码和解码来加速转码:
ffmpeg -hwaccel rkmpp -hwaccel_output_format drm_prime -afbc rga -i /path/to/any_4k_10bit_hevc.mkv -c:a copy -strict -2 \
-vf scale_rkrga=w=1920:h=1080:format=nv12:afbc=1 -c:v h264_rkmpp -rc_mode VBR -b:v 6M -maxrate 6M \
-bufsize 12M -profile:v high -g:v 120 -y /path/to/1080p_h264_6M.mkv
命令参数解释:
-hwaccel rkmpp
:启用硬件加速解码。-hwaccel_output_format drm_prime
:设置硬件加速后的输出格式为drm_prime
。-afbc rga
:启用 Rockchip 的 RGA(Raster Graphics Accelerator)硬件加速库。afbc
(Arm Framebuffer Compression)是一种压缩格式,旨在减少内存带宽的占用,提高视频处理效率。-i /path/to/any_4k_10bit_hevc.mkv
:指定输入文件路径。-c:a copy
:音频编解码器设置为copy
,即直接复制输入视频文件中的音频流而不做任何编码或转换。-strict -2
:启用实验性功能或允许使用一些非标准的选项。这个选项主要是用于启用ffmpeg
中一些不符合标准的功能或编解码器选项。-vf scale_rkrga=w=1920:h=1080:format=nv12:afbc=1
:使用 Rockchip 的硬件加速rkrga
进行视频缩放操作。将视频缩放到 1920x1080 分辨率(即 1080p)。设置输出像素格式为nv12
。启用 ARM Framebuffer Compression(AFBC),这有助于减少内存带宽的使用,提升性能。-c:v h264_rkmpp
:视频编码器设置为h264_rkmpp
-rc_mode VBR
:设置视频的比特率控制模式为VBR
(Variable Bit Rate,可变比特率)。这意味着ffmpeg
会根据视频内容的复杂度动态调整比特率,从而优化视频质量和压缩效率。-b:v 6M
:设置视频的目标比特率为 6 Mbps(兆比特每秒)。这是输出视频的平均比特率,表示视频每秒传输的比特数。-maxrate 6M
:设置视频编码时允许的最大比特率为 6 Mbps。这个限制确保视频流的比特率不会超过此值,有助于在带宽有限的情况下控制输出质量。-bufsize 12M
:设置码流缓冲区的大小为 12 Mbps。此参数用于控制编码器的码率控制,确保编码器能够平稳地处理比特率波动,避免过度波动导致质量问题。-profile:v high
:设置视频编码的 H.264 配置文件为high
。high
配置文件提供了更好的视频质量和更多的特性,适合于高质量的编码和兼容性要求较高的场景。-g:v 120
:设置视频的 GOP(Group of Pictures)大小为 120。这表示视频编码中关键帧(I 帧)之间的间隔为 120 帧。较大的 GOP 会减少视频文件的大小,但可能导致随机访问性能差一些。-y
:表示自动覆盖输出文件(如果该文件已经存在)。
结语
在下一篇文章,我将介绍如何使用 ffmpeg 的用户空间库实现同样的功能,因为在日常开发过程中,大部分都是使用开发库进行开发的,这样可以支持更多的功能自定义,以满足不同的业务需求。
如果觉得本文不错,请麻烦帮忙点赞、转发、收藏,谢谢~