@@ -235,7 +235,15 @@ static int vaapi_encode_issue(AVCodecContext *avctx,
if (err < 0)
goto fail;
}
-
+#if VA_CHECK_VERSION(1, 3, 0)
+ if (ctx->max_frame_size) {
+ err = vaapi_encode_make_param_buffer(avctx, pic, VAEncMiscParameterBufferType,
+ (char*) &ctx->mfs_params.misc,
+ sizeof(ctx->mfs_params));
+ if (err < 0)
+ goto fail;
+ }
+#endif
if (pic->type == PICTURE_TYPE_IDR) {
if (ctx->va_packed_headers & VA_ENC_PACKED_HEADER_SEQUENCE &&
ctx->codec->write_sequence_header) {
@@ -1630,6 +1638,43 @@ rc_mode_found:
return 0;
}
+static av_cold int vaapi_encode_init_max_frame_size(AVCodecContext *avctx)
+{
+ VAAPIEncodeContext *ctx = avctx->priv_data;
+
+ uint32_t max_frame_size = ctx->max_frame_size;
+ uint8_t num_passes = ctx->pass_num;
+ int err = 0;
+ int i = 0;
+
+ ctx->delta_qp_array = av_mallocz_array(num_passes, sizeof(uint8_t));
+ if (!ctx->delta_qp_array) {
+ err = AVERROR(ENOMEM);
+ return err;
+ }
+ for (i = 0; i <num_passes; i++){
+ ctx->delta_qp_array[i] = ctx->delta_qp;
+ }
+
+
+#if VA_CHECK_VERSION(1, 3, 0)
+ ctx->mfs_params.misc.type = VAEncMiscParameterTypeMultiPassFrameSize;
+ ctx->mfs_params.mfs.type = VAEncMiscParameterTypeMultiPassFrameSize;
+ ctx->mfs_params.mfs.max_frame_size = max_frame_size;
+ ctx->mfs_params.mfs.num_passes = num_passes;
+ ctx->mfs_params.mfs.delta_qp = ctx->delta_qp_array;
+
+ av_log(avctx, AV_LOG_VERBOSE, "Max Frame Size: %d bytes, "
+ "num_passes: %d, delta_qp = %d.\n",
+ ctx->max_frame_size, num_passes, ctx->delta_qp);
+#else
+ av_log(avctx, AV_LOG_WARNING, "Max Frame Size is "
+ "not supported with this VA version.\n");
+#endif
+
+ return 0;
+}
+
static av_cold int vaapi_encode_init_gop_structure(AVCodecContext *avctx)
{
VAAPIEncodeContext *ctx = avctx->priv_data;
@@ -2095,6 +2140,12 @@ av_cold int ff_vaapi_encode_init(AVCodecContext *avctx)
goto fail;
}
+ if (ctx->max_frame_size) {
+ err = vaapi_encode_init_max_frame_size(avctx);
+ if (err < 0)
+ goto fail;
+ }
+
vas = vaCreateConfig(ctx->hwctx->display,
ctx->va_profile, ctx->va_entrypoint,
ctx->config_attributes, ctx->nb_config_attributes,
@@ -2219,6 +2270,9 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx)
ctx->va_config = VA_INVALID_ID;
}
+ if (ctx->delta_qp_array)
+ av_freep(&ctx->delta_qp_array);
+
av_freep(&ctx->codec_sequence_params);
av_freep(&ctx->codec_picture_params);
@@ -176,6 +176,15 @@ typedef struct VAAPIEncodeContext {
// Desired B frame reference depth.
int desired_b_depth;
+ // Max Frame Size
+ int max_frame_size;
+ // Number Of Passes
+ int pass_num;
+ // Delta_qp For Each Pass
+ int delta_qp;
+ // Array of delta_qp
+ uint8_t *delta_qp_array;
+
// Explicitly set RC mode (otherwise attempt to pick from
// available modes).
int explicit_rc_mode;
@@ -267,7 +276,12 @@ typedef struct VAAPIEncodeContext {
VAEncMiscParameterBufferQualityLevel quality;
} quality_params;
#endif
-
+#if VA_CHECK_VERSION(1, 3, 0)
+ struct {
+ VAEncMiscParameterBuffer misc;
+ VAEncMiscParameterBufferMultiPassFrameSize mfs;
+ } __attribute__((packed)) mfs_params;
+#endif
// Per-sequence parameter structure (VAEncSequenceParameterBuffer*).
void *codec_sequence_params;
@@ -72,6 +72,9 @@ typedef struct VAAPIEncodeH264Context {
int sei;
int profile;
int level;
+ int max_frame_size;
+ int pass_num;
+ int delta_qp;
// Derived settings.
int mb_width;
@@ -1233,6 +1236,12 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx)
if (priv->qp > 0)
ctx->explicit_qp = priv->qp;
+ if (priv->max_frame_size > 0) {
+ ctx->max_frame_size = priv->max_frame_size;
+ ctx->pass_num = priv->pass_num;
+ ctx->delta_qp = priv->delta_qp;
+ }
+
return ff_vaapi_encode_init(avctx);
}
@@ -1266,6 +1275,12 @@ static const AVOption vaapi_encode_h264_options[] = {
{ "aud", "Include AUD",
OFFSET(aud), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS },
+ { "max_frame_size", "Maximum frame size (in bytes)",
+ OFFSET(max_frame_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS },
+ { "pass_num", "number of passes, every pass can have different QP, currently can support up to 4 passes",
+ OFFSET(pass_num), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, 4, FLAGS },
+ { "delta_qp", "delta QP for every pass",
+ OFFSET(delta_qp), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 51, FLAGS },
{ "sei", "Set SEI to include",
OFFSET(sei), AV_OPT_TYPE_FLAGS,
Add support for max frame size: - max_frame_size (bytes) to indicate the allowed max frame size, set with default 4 passes and delata_qp = 1 per pass; Customized pass_num and delta_qp per pass is also available: - pass_num to indicate number of passes. - delta_qp to indicate qp value added to base_qp for each pass. Currently only AVC encoder can support this settings in multiple pass case. If the frame size exceeds the limitation, encoder will adjust the QP value set by bit rate control methods, add delta_qp for each pass to control the frame size. new_qp = base_qp + delta_qp[0]; new_qp = base_qp + delta_qp[0] + delta_qp[1] + ... Set max frame size with default params: ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -f rawvideo \ -v verbose -s:v 352x288 -i ./input.yuv -vf format=nv12,hwupload \ -c:v h264_vaapi -profile:v main -g 30 -bf 3 -max_frame_size 40000 \ -vframes 100 -y ./max_frame_size.h264 Set max frame size with expected params: ffmpeg -hwaccel vaapi -vaapi_device /dev/dri/renderD128 -f rawvideo \ -v verbose -s:v 352x288 -i ./input.yuv -vf format=nv12,hwupload \ -c:v h264_vaapi -profile:v main -g 30 -bf 3 -max_frame_size 40000 \ -pass_num 2 -delta_qp 2 -vframes 100 -y ./max_frame_size.h264 Signed-off-by: Linjie Fu <linjie.fu@intel.com> --- libavcodec/vaapi_encode.c | 56 +++++++++++++++++++++++++++++++++- libavcodec/vaapi_encode.h | 16 +++++++++- libavcodec/vaapi_encode_h264.c | 15 +++++++++ 3 files changed, 85 insertions(+), 2 deletions(-)