Add hardware codec support for rkmpp (#6182)

This commit is contained in:
ayaya 2025-11-10 06:55:12 +08:00 committed by GitHub
parent b4d148bdb0
commit 289b698598
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -29,6 +29,7 @@ var (
VideoCodecIVP9 = makeVideoCodec("VP9 Intel Quick Sync Video (QSV)", "vp9_qsv") VideoCodecIVP9 = makeVideoCodec("VP9 Intel Quick Sync Video (QSV)", "vp9_qsv")
VideoCodecVVP9 = makeVideoCodec("VP9 VAAPI", "vp9_vaapi") VideoCodecVVP9 = makeVideoCodec("VP9 VAAPI", "vp9_vaapi")
VideoCodecVVPX = makeVideoCodec("VP8 VAAPI", "vp8_vaapi") VideoCodecVVPX = makeVideoCodec("VP8 VAAPI", "vp8_vaapi")
VideoCodecRK264 = makeVideoCodec("H264 Rockchip MPP (rkmpp)", "h264_rkmpp")
) )
const minHeight int = 480 const minHeight int = 480
@ -45,6 +46,7 @@ func (f *FFMpeg) InitHWSupport(ctx context.Context) {
VideoCodecI264C, VideoCodecI264C,
VideoCodecV264, VideoCodecV264,
VideoCodecR264, VideoCodecR264,
VideoCodecRK264,
VideoCodecIVP9, VideoCodecIVP9,
VideoCodecVVP9, VideoCodecVVP9,
VideoCodecM264, 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, "-init_hw_device")
args = append(args, "videotoolbox=vt") 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 return args
@ -233,6 +248,14 @@ func (f *FFMpeg) hwFilterInit(toCodec VideoCodec, fullhw bool) VideoFilter {
videoFilter = videoFilter.Append("format=nv12") videoFilter = videoFilter.Append("format=nv12")
videoFilter = videoFilter.Append("hwupload") 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 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 if fullhw && f.version.Gteq(Version{major: 3, minor: 3}) { // Added in FFMpeg 3.3
args = args.Append("scale_qsv=format=nv12") 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 return args
@ -337,6 +363,14 @@ func (f *FFMpeg) hwApplyScaleTemplate(sargs string, codec VideoCodec, match []in
} }
case VideoCodecM264: case VideoCodecM264:
template = "scale_vt=$value" 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: default:
return VideoFilter(sargs) return VideoFilter(sargs)
} }
@ -345,12 +379,15 @@ func (f *FFMpeg) hwApplyScaleTemplate(sargs string, codec VideoCodec, match []in
isIntel := codec == VideoCodecI264 || codec == VideoCodecI264C || codec == VideoCodecIVP9 isIntel := codec == VideoCodecI264 || codec == VideoCodecI264C || codec == VideoCodecIVP9
// BUG: scale_vt doesn't call ff_scale_adjust_dimensions, thus cant accept negative size values // BUG: scale_vt doesn't call ff_scale_adjust_dimensions, thus cant accept negative size values
isApple := codec == VideoCodecM264 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)) return VideoFilter(templateReplaceScale(sargs, template, match, vf, isIntel || isApple))
} }
// Returns the max resolution for a given codec, or a default // Returns the max resolution for a given codec, or a default
func (f *FFMpeg) hwCodecMaxRes(codec VideoCodec) (int, int) { func (f *FFMpeg) hwCodecMaxRes(codec VideoCodec) (int, int) {
switch codec { switch codec {
case VideoCodecRK264:
return 8192, 8192
case VideoCodecN264, case VideoCodecN264,
VideoCodecN264H, VideoCodecN264H,
VideoCodecI264, VideoCodecI264,
@ -382,7 +419,8 @@ func (f *FFMpeg) hwCodecHLSCompatible() *VideoCodec {
VideoCodecI264C, VideoCodecI264C,
VideoCodecV264, VideoCodecV264,
VideoCodecR264, 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 return &element
} }
} }
@ -397,7 +435,8 @@ func (f *FFMpeg) hwCodecMP4Compatible() *VideoCodec {
VideoCodecN264H, VideoCodecN264H,
VideoCodecI264, VideoCodecI264,
VideoCodecI264C, VideoCodecI264C,
VideoCodecM264: VideoCodecM264,
VideoCodecRK264:
return &element return &element
} }
} }