From 289b69859831b7a534cc785eaa23e820c6cff32b Mon Sep 17 00:00:00 2001 From: ayaya <62456287+a15355447898a@users.noreply.github.com> Date: Mon, 10 Nov 2025 06:55:12 +0800 Subject: [PATCH] Add hardware codec support for rkmpp (#6182) --- pkg/ffmpeg/codec_hardware.go | 43 ++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/pkg/ffmpeg/codec_hardware.go b/pkg/ffmpeg/codec_hardware.go index 4081f015d..bbbdbda6e 100644 --- a/pkg/ffmpeg/codec_hardware.go +++ b/pkg/ffmpeg/codec_hardware.go @@ -29,6 +29,7 @@ var ( VideoCodecIVP9 = makeVideoCodec("VP9 Intel Quick Sync Video (QSV)", "vp9_qsv") VideoCodecVVP9 = makeVideoCodec("VP9 VAAPI", "vp9_vaapi") VideoCodecVVPX = makeVideoCodec("VP8 VAAPI", "vp8_vaapi") + VideoCodecRK264 = makeVideoCodec("H264 Rockchip MPP (rkmpp)", "h264_rkmpp") ) const minHeight int = 480 @@ -45,6 +46,7 @@ func (f *FFMpeg) InitHWSupport(ctx context.Context) { VideoCodecI264C, VideoCodecV264, VideoCodecR264, + VideoCodecRK264, VideoCodecIVP9, VideoCodecVVP9, VideoCodecM264, @@ -201,6 +203,19 @@ func (f *FFMpeg) hwDeviceInit(args Args, toCodec VideoCodec, fullhw bool) Args { args = append(args, "-init_hw_device") args = append(args, "videotoolbox=vt") } + case VideoCodecRK264: + // Rockchip: always create rkmpp device and make it the filter device, so + // scale_rkrga and subsequent hwupload/hwmap operate in the right context. + args = append(args, "-init_hw_device") + args = append(args, "rkmpp=rk") + args = append(args, "-filter_hw_device") + args = append(args, "rk") + if fullhw { + args = append(args, "-hwaccel") + args = append(args, "rkmpp") + args = append(args, "-hwaccel_output_format") + args = append(args, "drm_prime") + } } return args @@ -233,6 +248,14 @@ func (f *FFMpeg) hwFilterInit(toCodec VideoCodec, fullhw bool) VideoFilter { videoFilter = videoFilter.Append("format=nv12") videoFilter = videoFilter.Append("hwupload") } + case VideoCodecRK264: + // For Rockchip full-hw, do NOT pre-map to rkrga here. scale_rkrga can + // consume DRM_PRIME frames directly when filter_hw_device is set. + // For non-fullhw, keep a sane software format. + if !fullhw { + videoFilter = videoFilter.Append("format=nv12") + videoFilter = videoFilter.Append("hwupload") + } } return videoFilter @@ -310,6 +333,9 @@ func (f *FFMpeg) hwApplyFullHWFilter(args VideoFilter, codec VideoCodec, fullhw if fullhw && f.version.Gteq(Version{major: 3, minor: 3}) { // Added in FFMpeg 3.3 args = args.Append("scale_qsv=format=nv12") } + case VideoCodecRK264: + // For Rockchip, no extra mapping here. If there is no scale filter, + // leave frames in DRM_PRIME for the encoder. } return args @@ -337,6 +363,14 @@ func (f *FFMpeg) hwApplyScaleTemplate(sargs string, codec VideoCodec, match []in } case VideoCodecM264: template = "scale_vt=$value" + case VideoCodecRK264: + // The original filter chain is a fallback for maximum compatibility: + // "scale_rkrga=$value:format=nv12,hwdownload,format=nv12,hwupload" + // It avoids hwmap(rkrga→rkmpp) failures (-38/-12) seen on some builds + // by downloading the scaled frame to system RAM and re-uploading it. + // The filter chain below uses a zero-copy approach, passing the hardware-scaled + // frame directly to the encoder. This is more efficient but may be less stable. + template = "scale_rkrga=$value" default: return VideoFilter(sargs) } @@ -345,12 +379,15 @@ func (f *FFMpeg) hwApplyScaleTemplate(sargs string, codec VideoCodec, match []in isIntel := codec == VideoCodecI264 || codec == VideoCodecI264C || codec == VideoCodecIVP9 // BUG: scale_vt doesn't call ff_scale_adjust_dimensions, thus cant accept negative size values isApple := codec == VideoCodecM264 + // Rockchip's scale_rkrga supports -1/-2; don't apply minus-one hack here. return VideoFilter(templateReplaceScale(sargs, template, match, vf, isIntel || isApple)) } // Returns the max resolution for a given codec, or a default func (f *FFMpeg) hwCodecMaxRes(codec VideoCodec) (int, int) { switch codec { + case VideoCodecRK264: + return 8192, 8192 case VideoCodecN264, VideoCodecN264H, VideoCodecI264, @@ -382,7 +419,8 @@ func (f *FFMpeg) hwCodecHLSCompatible() *VideoCodec { VideoCodecI264C, VideoCodecV264, VideoCodecR264, - VideoCodecM264: // Note that the Apple encoder sucks at startup, thus HLS quality is crap + VideoCodecM264, // Note that the Apple encoder sucks at startup, thus HLS quality is crap + VideoCodecRK264: return &element } } @@ -397,7 +435,8 @@ func (f *FFMpeg) hwCodecMP4Compatible() *VideoCodec { VideoCodecN264H, VideoCodecI264, VideoCodecI264C, - VideoCodecM264: + VideoCodecM264, + VideoCodecRK264: return &element } }