Rockchip你官方sdk被dcma是hyw啊
如何在Rockchip上安装支持rkmpp加速的ffmpeg。
armbian不管是debian还是ubuntu系统均无法使用rkmpp硬件编码器。我翻看源码发现源码里有相关代码,并且内核日志里这个硬件被正确初始化了,但是就是不能用。
简而言之就是当下你目前必须使用开发版提供的固件(我用的orangepi5)
需要存在以下设备才证明当前编码器可用:
ls /dev/mpp_service理论上那几个/dev/vide*的设备上M2M的编码器,你可以使用以下命令查看功能:
v4l2-ctl -d /dev/videoX --list-formats在我这里这个设备无法被使用,说不定以后armbian更新会修复。
最简单的方案是在你的apt源里添加jellyfin的源.
deb [signed-by=/etc/apt/keyrings/jellyfin.gpg] https://repo.jellyfin.org/ubuntu jammy main
apt update && apt install jellyfin-ffmpeg7你可以通过以下命令来确保ffmpeg正确的支持了硬件加速:
ffmpeg -encoders | grep mpp正确输出类似于:
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)
但是如果你需要使用libav库进行开发,一切都会变得复杂
(我折腾了很久也没有成功的交叉编译ffmpeg,因此这里提供的思路是在开发版上编译ffmpeg,并将sysroot挂载到上位机。在上位机开发应用程序,在上位机通过远程挂载的sysroot交叉编译程序。ffmpeg本身不需要频繁的重新编译因此大体上可以接收)
sudo apt update
sudo apt install -y \
git build-essential pkg-config cmake meson ninja-build \
libdrm-devmkdir -p ~/dev && cd ~/dev
git clone -b jellyfin-mpp --depth=1 https://gitee.com/nyanmisaka/mpp.git rkmpp
# 官方git仓库:
# git clone -b jellyfin-mpp --depth=1 https://github.com/rockchip-linux/mpp 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)"
sudo make install
popd
popd确认安装成功:
pkg-config --modversion rockchip_mpp 2>/dev/null || echo "pkg-config里没找到rockchip_mpp(不一定致命,但要留意)"
ldconfig -p | grep -i mpp || truemkdir -p ~/dev && cd ~/dev
git clone -b jellyfin-rga --depth=1 https://gitee.com/nyanmisaka/rga.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
sudo ninja -C rkrga_build install确认安装成功:
ldconfig -p | grep -i rga || truemkdir -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 --enable-shared --disable-static
make -j"$(nproc)"
sudo make install验证:
ffmpeg -decoders | grep rkmpp
ffmpeg -encoders | grep rkmpp
ffmpeg -filters | grep rkrgasshfs orangepi@orangepi5:/ /mnt/rk3588-sysroot -o ro,reconnect,ServerAliveInterval=15我不怎么想写C/C++,所以我的demo是zig写的,如果你想用C来写也差不多,把build.zig的内容放到CMakeLists.txt里就行了。
// main.zig
const std = @import("std");
const c = @cImport({
@cInclude("libavcodec/avcodec.h");
@cInclude("libavutil/avutil.h");
});
const HW_TAGS = [_][]const u8{
"nvenc",
"qsv",
"vaapi",
"amf",
"videotoolbox",
"v4l2m2m",
"omx",
"rkmpp",
"mediacodec",
"mmal",
};
fn isHwEncoder(name: []const u8) bool {
var buf: [256]u8 = undefined;
// std.ascii.lowerString 会 assert(output.len >= input.len),先防一下
const lower: []const u8 = if (name.len <= buf.len)
std.ascii.lowerString(&buf, name)
else
name; // 超长就退化为原串(一般 codec 名都很短)
for (HW_TAGS) |tag| {
if (std.mem.indexOf(u8, lower, tag) != null) return true;
}
return false;
}
const Item = struct {
name: []u8,
long_name: ?[]u8,
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const alloc = gpa.allocator();
var iter: ?*anyopaque = null;
// Zig 0.15+: ArrayList 用 .empty,所有操作显式传 allocator
var found: std.ArrayList(Item) = .empty;
defer {
for (found.items) |it| {
alloc.free(it.name);
if (it.long_name) |ln| alloc.free(ln);
}
found.deinit(alloc);
}
while (true) {
const codec: ?*const c.AVCodec = c.av_codec_iterate(&iter);
if (codec == null) break;
if (c.av_codec_is_encoder(codec) == 0) continue;
if (codec.?.type != c.AVMEDIA_TYPE_VIDEO) continue;
const cname = std.mem.span(codec.?.name);
if (!isHwEncoder(cname)) continue;
const name_copy = try alloc.dupe(u8, cname);
var long_copy: ?[]u8 = null;
if (codec.?.long_name != null) {
const clong = std.mem.span(codec.?.long_name);
long_copy = try alloc.dupe(u8, clong);
}
try found.append(alloc, .{ .name = name_copy, .long_name = long_copy });
}
// Zig 0.15.1+ 新 stdout 写法:提供 buffer + flush
var stdout_buffer: [4096]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const out = &stdout_writer.interface;
if (found.items.len == 0) {
try out.print("没有检测到硬件视频编码器(来自已链接的 libavcodec)。\n", .{});
try out.flush();
return;
}
try out.print("当前可用的硬件视频编码器(来自 libavcodec):\n", .{});
for (found.items) |it| {
if (it.long_name) |ln| {
try out.print("- {s}: {s}\n", .{ it.name, ln });
} else {
try out.print("- {s}\n", .{it.name});
}
}
try out.flush();
}const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const sysroot_opt = b.option([]const u8, "sysroot", "Sysroot path (e.g. /mnt/rk3588)");
const mod = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const exe = b.addExecutable(.{
.name = "hwenc_list",
.root_module = mod,
});
// 你项目里有 @cImport + @cInclude,需要 libc
exe.linkLibC(); // 官方文档/示例做法 :contentReference[oaicite:1]{index=1}
// 如果提供了 sysroot,就把头文件/库路径加进去
if (sysroot_opt) |sysroot| {
// ---- headers: IMPORTANT (multiarch first) ----
mod.addIncludePath(.{ .cwd_relative = b.fmt("{s}/usr/include/aarch64-linux-gnu", .{sysroot}) });
mod.addIncludePath(.{ .cwd_relative = b.fmt("{s}/usr/include", .{sysroot}) });
mod.addIncludePath(.{ .cwd_relative = b.fmt("{s}/include", .{sysroot}) });
// ---- libraries: put multiarch first ----
exe.addLibraryPath(.{ .cwd_relative = b.fmt("{s}/usr/lib/aarch64-linux-gnu", .{sysroot}) });
exe.addLibraryPath(.{ .cwd_relative = b.fmt("{s}/lib/aarch64-linux-gnu", .{sysroot}) });
exe.addLibraryPath(.{ .cwd_relative = b.fmt("{s}/usr/lib", .{sysroot}) });
exe.addLibraryPath(.{ .cwd_relative = b.fmt("{s}/lib", .{sysroot}) });
}
// 链接 FFmpeg / libav(官方“Linking to System Libraries”示例就是 exe.linkSystemLibrary) :contentReference[oaicite:2]{index=2}
exe.linkSystemLibrary("avcodec");
exe.linkSystemLibrary("avutil");
// 常见依赖(缺啥报错再补)
exe.linkSystemLibrary("z");
exe.linkSystemLibrary("m");
exe.linkSystemLibrary("pthread");
exe.linkSystemLibrary("dl");
b.installArtifact(exe);
// 可选:zig build run
const run_cmd = b.addRunArtifact(exe);
if (b.args) |args| run_cmd.addArgs(args);
b.step("run", "Run the app").dependOn(&run_cmd.step);
}编译程序:
zig build -Dtarget=aarch64-linux-gnu -Dsysroot=/mnt/rk3588-sysroot连接上开发版的ssh并运行:
./hwenc_list输出:
当前可用的硬件视频编码器(来自 libavcodec):
- h263_v4l2m2m: V4L2 mem2mem H.263 encoder wrapper
- h264_v4l2m2m: V4L2 mem2mem H.264 encoder wrapper
- h264_rkmpp: Rockchip MPP (Media Process Platform) H264 encoder
- hevc_v4l2m2m: V4L2 mem2mem HEVC encoder wrapper
- hevc_rkmpp: Rockchip MPP (Media Process Platform) HEVC encoder
- mjpeg_rkmpp: Rockchip MPP (Media Process Platform) MJPEG encoder
- mpeg4_v4l2m2m: V4L2 mem2mem MPEG4 encoder wrapper
- vp8_v4l2m2m: V4L2 mem2mem VP8 encoder wrapper