]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/vaapi_encode_mpeg2.c
avcodec: Constify AVCodecs
[ffmpeg] / libavcodec / vaapi_encode_mpeg2.c
index 5577fa9e048abffb82d38aea46afb8fd35b32e1f..af3a63dab735e20e8fdfce26f563d257101e8f10 100644 (file)
 typedef struct VAAPIEncodeMPEG2Context {
     VAAPIEncodeContext common;
 
-    // Derived settings.
-    int mb_width;
-    int mb_height;
+    // User options.
+    int profile;
+    int level;
 
+    // Derived settings.
     int quant_i;
     int quant_p;
     int quant_b;
@@ -92,10 +93,9 @@ static int vaapi_encode_mpeg2_add_header(AVCodecContext *avctx,
                                          CodedBitstreamFragment *frag,
                                          int type, void *header)
 {
-    VAAPIEncodeMPEG2Context *priv = avctx->priv_data;
     int err;
 
-    err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, type, header, NULL);
+    err = ff_cbs_insert_unit_content(frag, -1, type, header, NULL);
     if (err < 0) {
         av_log(avctx, AV_LOG_ERROR, "Failed to add header: "
                "type = %d.\n", type);
@@ -134,7 +134,7 @@ static int vaapi_encode_mpeg2_write_sequence_header(AVCodecContext *avctx,
 
     err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag);
 fail:
-    ff_cbs_fragment_uninit(priv->cbc, frag);
+    ff_cbs_fragment_reset(frag);
     return 0;
 }
 
@@ -158,7 +158,7 @@ static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx,
 
     err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag);
 fail:
-    ff_cbs_fragment_uninit(priv->cbc, frag);
+    ff_cbs_fragment_reset(frag);
     return 0;
 }
 
@@ -184,8 +184,8 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx)
     memset(pce,  0, sizeof(*pce));
 
 
-    if (avctx->bit_rate > 0) {
-        priv->bit_rate = (avctx->bit_rate + 399) / 400;
+    if (ctx->va_bit_rate > 0) {
+        priv->bit_rate = (ctx->va_bit_rate + 399) / 400;
     } else {
         // Unknown (not a bitrate-targetting mode), so just use the
         // highest value.
@@ -292,17 +292,16 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx)
     priv->sequence_display_extension.extension_start_code_identifier =
         MPEG2_EXTENSION_SEQUENCE_DISPLAY;
 
+    // Unspecified video format, from table 6-6.
     sde->video_format = 5;
-    if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
+
+    sde->colour_primaries         = avctx->color_primaries;
+    sde->transfer_characteristics = avctx->color_trc;
+    sde->matrix_coefficients      = avctx->colorspace;
+    sde->colour_description       =
+        avctx->color_primaries != AVCOL_PRI_UNSPECIFIED ||
         avctx->color_trc       != AVCOL_TRC_UNSPECIFIED ||
-        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED) {
-        sde->colour_description       = 1;
-        sde->colour_primaries         = avctx->color_primaries;
-        sde->transfer_characteristics = avctx->color_trc;
-        sde->matrix_coefficients      = avctx->colorspace;
-    } else {
-        sde->colour_description = 0;
-    }
+        avctx->colorspace      != AVCOL_SPC_UNSPECIFIED;
 
     sde->display_horizontal_size = avctx->width;
     sde->display_vertical_size   = avctx->height;
@@ -312,7 +311,8 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx)
 
     goph->group_start_code = MPEG2_START_GROUP;
 
-    goph->time_code   = 0;
+    // Marker bit in the middle of time_code.
+    goph->time_code   = 1 << 12;
     goph->closed_gop  = 1;
     goph->broken_link = 0;
 
@@ -351,13 +351,13 @@ static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx)
 
 
     *vseq = (VAEncSequenceParameterBufferMPEG2) {
-        .intra_period = avctx->gop_size,
+        .intra_period = ctx->gop_size,
         .ip_period    = ctx->b_per_p + 1,
 
         .picture_width  = avctx->width,
         .picture_height = avctx->height,
 
-        .bits_per_second          = avctx->bit_rate,
+        .bits_per_second          = ctx->va_bit_rate,
         .frame_rate               = av_q2d(priv->frame_rate),
         .aspect_ratio_information = sh->aspect_ratio_information,
         .vbv_buffer_size          = priv->vbv_buffer_size,
@@ -473,8 +473,6 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx,
     vpic->f_code[1][0]       = pce->f_code[1][0];
     vpic->f_code[1][1]       = pce->f_code[1][1];
 
-    pic->nb_slices = priv->mb_height;
-
     return 0;
 }
 
@@ -486,8 +484,8 @@ static int vaapi_encode_mpeg2_init_slice_params(AVCodecContext *avctx,
     VAEncSliceParameterBufferMPEG2   *vslice = slice->codec_slice_params;
     int qp;
 
-    vslice->macroblock_address = priv->mb_width * slice->index;
-    vslice->num_macroblocks    = priv->mb_width;
+    vslice->macroblock_address = slice->block_start;
+    vslice->num_macroblocks    = slice->block_size;
 
     switch (pic->type) {
     case PICTURE_TYPE_IDR:
@@ -521,23 +519,18 @@ static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx)
     if (err < 0)
         return err;
 
-    priv->mb_width  = FFALIGN(avctx->width,  16) / 16;
-    priv->mb_height = FFALIGN(avctx->height, 16) / 16;
-
     if (ctx->va_rc_mode == VA_RC_CQP) {
-        priv->quant_p = av_clip(avctx->global_quality, 1, 31);
+        priv->quant_p = av_clip(ctx->rc_quality, 1, 31);
         if (avctx->i_quant_factor > 0.0)
-            priv->quant_i = av_clip((avctx->global_quality *
-                                     avctx->i_quant_factor +
-                                     avctx->i_quant_offset) + 0.5,
-                                    1, 31);
+            priv->quant_i =
+                av_clip((avctx->i_quant_factor * priv->quant_p +
+                         avctx->i_quant_offset) + 0.5, 1, 31);
         else
             priv->quant_i = priv->quant_p;
         if (avctx->b_quant_factor > 0.0)
-            priv->quant_b = av_clip((avctx->global_quality *
-                                     avctx->b_quant_factor +
-                                     avctx->b_quant_offset) + 0.5,
-                                    1, 31);
+            priv->quant_b =
+                av_clip((avctx->b_quant_factor * priv->quant_p +
+                         avctx->b_quant_offset) + 0.5, 1, 31);
         else
             priv->quant_b = priv->quant_p;
 
@@ -546,15 +539,37 @@ static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx)
                priv->quant_i, priv->quant_p, priv->quant_b);
 
     } else {
-        av_assert0(0 && "Invalid RC mode.");
+        priv->quant_i = 16;
+        priv->quant_p = 16;
+        priv->quant_b = 16;
     }
 
+    ctx->slice_block_rows = FFALIGN(avctx->height, 16) / 16;
+    ctx->slice_block_cols = FFALIGN(avctx->width,  16) / 16;
+
+    ctx->nb_slices  = ctx->slice_block_rows;
+    ctx->slice_size = 1;
+
+    ctx->roi_quant_range = 31;
+
     return 0;
 }
 
+static const VAAPIEncodeProfile vaapi_encode_mpeg2_profiles[] = {
+    { FF_PROFILE_MPEG2_MAIN,   8, 3, 1, 1, VAProfileMPEG2Main   },
+    { FF_PROFILE_MPEG2_SIMPLE, 8, 3, 1, 1, VAProfileMPEG2Simple },
+    { FF_PROFILE_UNKNOWN }
+};
+
 static const VAAPIEncodeType vaapi_encode_type_mpeg2 = {
+    .profiles              = vaapi_encode_mpeg2_profiles,
+
+    .flags                 = FLAG_B_PICTURES,
+
     .configure             = &vaapi_encode_mpeg2_configure,
 
+    .default_quality       = 10,
+
     .sequence_params_size  = sizeof(VAEncSequenceParameterBufferMPEG2),
     .init_sequence_params  = &vaapi_encode_mpeg2_init_sequence_params,
 
@@ -573,35 +588,18 @@ static const VAAPIEncodeType vaapi_encode_type_mpeg2 = {
 
 static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx)
 {
-    VAAPIEncodeContext *ctx = avctx->priv_data;
+    VAAPIEncodeContext       *ctx = avctx->priv_data;
+    VAAPIEncodeMPEG2Context *priv = avctx->priv_data;
 
     ctx->codec = &vaapi_encode_type_mpeg2;
 
-    switch (avctx->profile) {
-    case FF_PROFILE_MPEG2_SIMPLE:
-        ctx->va_profile = VAProfileMPEG2Simple;
-        break;
-    case FF_PROFILE_MPEG2_MAIN:
-        ctx->va_profile = VAProfileMPEG2Main;
-        break;
-    case FF_PROFILE_MPEG2_422:
-        av_log(avctx, AV_LOG_ERROR, "MPEG-2 4:2:2 profile "
-               "is not supported.\n");
-        return AVERROR_PATCHWELCOME;
-    case FF_PROFILE_MPEG2_HIGH:
-        av_log(avctx, AV_LOG_ERROR, "MPEG-2 high profile "
-               "is not supported.\n");
-        return AVERROR_PATCHWELCOME;
-    case FF_PROFILE_MPEG2_SS:
-    case FF_PROFILE_MPEG2_SNR_SCALABLE:
-        av_log(avctx, AV_LOG_ERROR, "MPEG-2 scalable profiles "
-               "are not supported.\n");
-        return AVERROR_PATCHWELCOME;
-    default:
-        av_log(avctx, AV_LOG_ERROR, "Unknown MPEG-2 profile %d.\n",
-               avctx->profile);
-        return AVERROR(EINVAL);
-    }
+    if (avctx->profile == FF_PROFILE_UNKNOWN)
+        avctx->profile = priv->profile;
+    if (avctx->level == FF_LEVEL_UNKNOWN)
+        avctx->level = priv->level;
+
+    // Reject unknown levels (these are required to set f_code for
+    // motion vector encoding).
     switch (avctx->level) {
     case 4: // High
     case 6: // High 1440
@@ -620,12 +618,8 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx)
         return AVERROR(EINVAL);
     }
 
-    ctx->va_entrypoint = VAEntrypointEncSlice;
-    ctx->va_rt_format  = VA_RT_FORMAT_YUV420;
-    ctx->va_rc_mode    = VA_RC_CQP;
-
-    ctx->va_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE |
-                             VA_ENC_PACKED_HEADER_PICTURE;
+    ctx->desired_packed_headers = VA_ENC_PACKED_HEADER_SEQUENCE |
+                                  VA_ENC_PACKED_HEADER_PICTURE;
 
     ctx->surface_width  = FFALIGN(avctx->width,  16);
     ctx->surface_height = FFALIGN(avctx->height, 16);
@@ -637,38 +631,81 @@ static av_cold int vaapi_encode_mpeg2_close(AVCodecContext *avctx)
 {
     VAAPIEncodeMPEG2Context *priv = avctx->priv_data;
 
+    ff_cbs_fragment_free(&priv->current_fragment);
     ff_cbs_close(&priv->cbc);
 
     return ff_vaapi_encode_close(avctx);
 }
 
+#define OFFSET(x) offsetof(VAAPIEncodeMPEG2Context, x)
+#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
+static const AVOption vaapi_encode_mpeg2_options[] = {
+    VAAPI_ENCODE_COMMON_OPTIONS,
+    VAAPI_ENCODE_RC_OPTIONS,
+
+    { "profile", "Set profile (in profile_and_level_indication)",
+      OFFSET(profile), AV_OPT_TYPE_INT,
+      { .i64 = FF_PROFILE_UNKNOWN }, FF_PROFILE_UNKNOWN, 7, FLAGS, "profile" },
+
+#define PROFILE(name, value)  name, NULL, 0, AV_OPT_TYPE_CONST, \
+      { .i64 = value }, 0, 0, FLAGS, "profile"
+    { PROFILE("simple", FF_PROFILE_MPEG2_SIMPLE) },
+    { PROFILE("main",   FF_PROFILE_MPEG2_MAIN)   },
+#undef PROFILE
+
+    { "level", "Set level (in profile_and_level_indication)",
+      OFFSET(level), AV_OPT_TYPE_INT,
+      { .i64 = 4 }, 0, 15, FLAGS, "level" },
+
+#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \
+      { .i64 = value }, 0, 0, FLAGS, "level"
+    { LEVEL("low",       10) },
+    { LEVEL("main",       8) },
+    { LEVEL("high_1440",  6) },
+    { LEVEL("high",       4) },
+#undef LEVEL
+
+    { NULL },
+};
+
 static const AVCodecDefault vaapi_encode_mpeg2_defaults[] = {
-    { "profile",        "4"   },
-    { "level",          "4"   },
+    { "b",              "0"   },
     { "bf",             "1"   },
     { "g",              "120" },
     { "i_qfactor",      "1"   },
     { "i_qoffset",      "0"   },
     { "b_qfactor",      "6/5" },
     { "b_qoffset",      "0"   },
-    { "global_quality", "10"  },
+    { "qmin",           "-1"  },
+    { "qmax",           "-1"  },
     { NULL },
 };
 
-AVCodec ff_mpeg2_vaapi_encoder = {
+static const AVClass vaapi_encode_mpeg2_class = {
+    .class_name = "mpeg2_vaapi",
+    .item_name  = av_default_item_name,
+    .option     = vaapi_encode_mpeg2_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
+const AVCodec ff_mpeg2_vaapi_encoder = {
     .name           = "mpeg2_vaapi",
     .long_name      = NULL_IF_CONFIG_SMALL("MPEG-2 (VAAPI)"),
     .type           = AVMEDIA_TYPE_VIDEO,
     .id             = AV_CODEC_ID_MPEG2VIDEO,
     .priv_data_size = sizeof(VAAPIEncodeMPEG2Context),
     .init           = &vaapi_encode_mpeg2_init,
-    .encode2        = &ff_vaapi_encode2,
+    .receive_packet = &ff_vaapi_encode_receive_packet,
     .close          = &vaapi_encode_mpeg2_close,
-    .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE,
+    .priv_class     = &vaapi_encode_mpeg2_class,
+    .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE |
+                      AV_CODEC_CAP_DR1,
+    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
     .defaults       = vaapi_encode_mpeg2_defaults,
     .pix_fmts = (const enum AVPixelFormat[]) {
         AV_PIX_FMT_VAAPI,
         AV_PIX_FMT_NONE,
     },
+    .hw_configs     = ff_vaapi_encode_hw_configs,
     .wrapper_name   = "vaapi",
 };