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")
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
}
}