Merge commit 'deefca02c275ce4bc5ccbee690463ffef81a18b8'
authorJames Almer <jamrial@gmail.com>
Thu, 29 Mar 2018 23:34:43 +0000 (20:34 -0300)
committerJames Almer <jamrial@gmail.com>
Thu, 29 Mar 2018 23:34:43 +0000 (20:34 -0300)
* commit 'deefca02c275ce4bc5ccbee690463ffef81a18b8':
  qsvenc: add the Access Unit Delimiter NAL Unit support

Merged-by: James Almer <jamrial@gmail.com>
1  2 
libavcodec/qsvenc.c
libavcodec/qsvenc.h
libavcodec/qsvenc_h264.c

diff --combined libavcodec/qsvenc.c
@@@ -4,20 -4,20 +4,20 @@@
   * copyright (c) 2013 Yukinori Yamazoe
   * copyright (c) 2015 Anton Khirnov
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
@@@ -32,7 -32,6 +32,7 @@@
  #include "libavutil/log.h"
  #include "libavutil/time.h"
  #include "libavutil/imgutils.h"
 +#include "libavcodec/bytestream.h"
  
  #include "avcodec.h"
  #include "internal.h"
@@@ -136,6 -135,9 +136,6 @@@ static void dump_video_param(AVCodecCon
  #if QSV_HAVE_CO2
      mfxExtCodingOption2 *co2 = (mfxExtCodingOption2*)coding_opts[1];
  #endif
 -#if QSV_HAVE_CO3
 -    mfxExtCodingOption3 *co3 = (mfxExtCodingOption3*)coding_opts[2];
 -#endif
  
      av_log(avctx, AV_LOG_VERBOSE, "profile: %s; level: %"PRIu16"\n",
             print_profile(info->CodecProfile), info->CodecLevel);
                 info->ICQQuality, co2->LookAheadDepth);
      }
  #endif
 -#if QSV_HAVE_QVBR
 -    else if (info->RateControlMethod == MFX_RATECONTROL_QVBR) {
 -        av_log(avctx, AV_LOG_VERBOSE, "QVBRQuality: %"PRIu16"\n",
 -               co3->QVBRQuality);
 -    }
 -#endif
  
      av_log(avctx, AV_LOG_VERBOSE, "NumSlice: %"PRIu16"; NumRefFrame: %"PRIu16"\n",
             info->NumSlice, info->NumRefFrame);
@@@ -270,7 -278,7 +270,7 @@@ static int select_rc_mode(AVCodecContex
      const char *rc_desc;
      mfxU16      rc_mode;
  
 -    int want_la     = q->la_depth >= 10;
 +    int want_la     = q->look_ahead;
      int want_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE);
      int want_vcm    = q->vcm;
  
@@@ -552,11 -560,11 +552,11 @@@ static int init_video_param(AVCodecCont
  #if QSV_HAVE_LA
      case MFX_RATECONTROL_LA:
          q->param.mfx.TargetKbps  = avctx->bit_rate / 1000;
 -        q->extco2.LookAheadDepth = q->la_depth;
 +        q->extco2.LookAheadDepth = q->look_ahead_depth;
          break;
  #if QSV_HAVE_ICQ
      case MFX_RATECONTROL_LA_ICQ:
 -        q->extco2.LookAheadDepth = q->la_depth;
 +        q->extco2.LookAheadDepth = q->look_ahead_depth;
      case MFX_RATECONTROL_ICQ:
          q->param.mfx.ICQQuality  = avctx->global_quality;
          break;
          q->extco.Header.BufferId      = MFX_EXTBUFF_CODING_OPTION;
          q->extco.Header.BufferSz      = sizeof(q->extco);
  
 +        q->extco.PicTimingSEI         = q->pic_timing_sei ?
 +                                        MFX_CODINGOPTION_ON : MFX_CODINGOPTION_UNKNOWN;
 +
          if (q->rdo >= 0)
              q->extco.RateDistortionOpt = q->rdo > 0 ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
  
@@@ -595,6 -600,7 +595,7 @@@ FF_ENABLE_DEPRECATION_WARNING
              if (q->recovery_point_sei >= 0)
                  q->extco.RecoveryPointSEI = q->recovery_point_sei ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
              q->extco.MaxDecFrameBuffering = q->max_dec_frame_buffering;
+             q->extco.AUDelimiter          = q->aud ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
          }
  
          q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco;
  #endif
  
  #if QSV_HAVE_LA_DS
 -            q->extco2.LookAheadDS = q->la_ds;
 +            q->extco2.LookAheadDS = q->look_ahead_downsampling;
  #endif
  
  #if QSV_HAVE_BREF_TYPE
@@@ -705,6 -711,12 +706,6 @@@ static int qsv_retrieve_enc_params(AVCo
          .Header.BufferSz = sizeof(co2),
      };
  #endif
 -#if QSV_HAVE_CO3
 -    mfxExtCodingOption3 co3 = {
 -        .Header.BufferId = MFX_EXTBUFF_CODING_OPTION3,
 -        .Header.BufferSz = sizeof(co3),
 -    };
 -#endif
  
      mfxExtBuffer *ext_buffers[] = {
          (mfxExtBuffer*)&extradata,
  #if QSV_HAVE_CO2
          (mfxExtBuffer*)&co2,
  #endif
 -#if QSV_HAVE_CO3
 -        (mfxExtBuffer*)&co3,
 -#endif
      };
  
      int need_pps = avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO;
@@@ -960,23 -975,11 +961,23 @@@ int ff_qsv_enc_init(AVCodecContext *avc
      return 0;
  }
  
 +static void free_encoder_ctrl_payloads(mfxEncodeCtrl* enc_ctrl)
 +{
 +    if (enc_ctrl) {
 +        int i;
 +        for (i = 0; i < enc_ctrl->NumPayload && i < QSV_MAX_ENC_PAYLOAD; i++) {
 +            av_free(enc_ctrl->Payload[i]);
 +        }
 +        enc_ctrl->NumPayload = 0;
 +    }
 +}
 +
  static void clear_unused_frames(QSVEncContext *q)
  {
      QSVFrame *cur = q->work_frames;
      while (cur) {
          if (cur->used && !cur->surface.Data.Locked) {
 +            free_encoder_ctrl_payloads(&cur->enc_ctrl);
              av_frame_unref(cur->frame);
              cur->used = 0;
          }
@@@ -1011,11 -1014,6 +1012,11 @@@ static int get_free_frame(QSVEncContex
          av_freep(&frame);
          return AVERROR(ENOMEM);
      }
 +    frame->enc_ctrl.Payload = av_mallocz(sizeof(mfxPayload*) * QSV_MAX_ENC_PAYLOAD);
 +    if (!frame->enc_ctrl.Payload) {
 +        av_freep(&frame);
 +        return AVERROR(ENOMEM);
 +    }
      *last = frame;
  
      *f = frame;
  }
  
  static int submit_frame(QSVEncContext *q, const AVFrame *frame,
 -                        mfxFrameSurface1 **surface)
 +                        QSVFrame **new_frame)
  {
      QSVFrame *qf;
      int ret;
  
      qf->surface.Data.TimeStamp = av_rescale_q(frame->pts, q->avctx->time_base, (AVRational){1, 90000});
  
 -    *surface = &qf->surface;
 +    *new_frame = qf;
  
      return 0;
  }
@@@ -1116,21 -1114,15 +1117,21 @@@ static int encode_frame(AVCodecContext 
  
      mfxFrameSurface1 *surf = NULL;
      mfxSyncPoint *sync     = NULL;
 +    QSVFrame *qsv_frame = NULL;
 +    mfxEncodeCtrl* enc_ctrl = NULL;
      int ret;
  
      if (frame) {
 -        ret = submit_frame(q, frame, &surf);
 +        ret = submit_frame(q, frame, &qsv_frame);
          if (ret < 0) {
              av_log(avctx, AV_LOG_ERROR, "Error submitting the frame for encoding.\n");
              return ret;
          }
      }
 +    if (qsv_frame) {
 +        surf = &qsv_frame->surface;
 +        enc_ctrl = &qsv_frame->enc_ctrl;
 +    }
  
      ret = av_new_packet(&new_pkt, q->packet_size);
      if (ret < 0) {
      bs->Data      = new_pkt.data;
      bs->MaxLength = new_pkt.size;
  
 +    if (q->set_encode_ctrl_cb) {
 +        q->set_encode_ctrl_cb(avctx, frame, &qsv_frame->enc_ctrl);
 +    }
 +
      sync = av_mallocz(sizeof(*sync));
      if (!sync) {
          av_freep(&bs);
      }
  
      do {
 -        ret = MFXVideoENCODE_EncodeFrameAsync(q->session, NULL, surf, bs, sync);
 +        ret = MFXVideoENCODE_EncodeFrameAsync(q->session, enc_ctrl, surf, bs, sync);
          if (ret == MFX_WRN_DEVICE_BUSY)
 -            av_usleep(1);
 +            av_usleep(500);
      } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_WRN_IN_EXECUTION);
  
      if (ret > 0)
@@@ -1277,7 -1265,6 +1278,7 @@@ int ff_qsv_enc_close(AVCodecContext *av
      while (cur) {
          q->work_frames = cur->next;
          av_frame_free(&cur->frame);
 +        av_free(cur->enc_ctrl.Payload);
          av_freep(&cur);
          cur = q->work_frames;
      }
diff --combined libavcodec/qsvenc.h
@@@ -3,20 -3,20 +3,20 @@@
   *
   * copyright (c) 2013 Yukinori Yamazoe
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
  #endif
  
  #if !QSV_HAVE_LA_DS
 +#define MFX_LOOKAHEAD_DS_UNKNOWN 0
  #define MFX_LOOKAHEAD_DS_OFF 0
  #define MFX_LOOKAHEAD_DS_2x 0
  #define MFX_LOOKAHEAD_DS_4x 0
  #endif
  
  #define QSV_COMMON_OPTS \
 -{ "async_depth", "Maximum processing parallelism", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VE },  \
 -{ "avbr_accuracy",    "Accuracy of the AVBR ratecontrol",    OFFSET(qsv.avbr_accuracy),    AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },     \
 -{ "avbr_convergence", "Convergence of the AVBR ratecontrol", OFFSET(qsv.avbr_convergence), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },     \
 -{ "preset", NULL, OFFSET(qsv.preset), AV_OPT_TYPE_INT, { .i64 = MFX_TARGETUSAGE_BALANCED }, 0, 7,   VE, "preset" },                             \
 -{ "fast",   NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BEST_SPEED  },   INT_MIN, INT_MAX, VE, "preset" },                             \
 -{ "medium", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BALANCED  },     INT_MIN, INT_MAX, VE, "preset" },                             \
 -{ "slow",   NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BEST_QUALITY  }, INT_MIN, INT_MAX, VE, "preset" },                             \
 -{ "la_depth", "Number of frames to analyze before encoding.", OFFSET(qsv.la_depth), AV_OPT_TYPE_INT, { .i64 = 9 },   9, 100, VE, "la_depth" },  \
 -{ "unset", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 9 }, INT_MIN, INT_MAX,                                                       VE, "la_depth" },  \
 -{ "la_ds", "Downscaling factor for the frames saved for the lookahead analysis", OFFSET(qsv.la_ds), AV_OPT_TYPE_INT,                            \
 -                    { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, MFX_LOOKAHEAD_DS_UNKNOWN, MFX_LOOKAHEAD_DS_4x, VE, "la_ds" },                          \
 -{ "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, INT_MIN, INT_MAX,                                     VE, "la_ds" }, \
 -{ "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_OFF }, INT_MIN, INT_MAX,                                          VE, "la_ds" }, \
 -{ "2x", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_2x }, INT_MIN, INT_MAX,                                            VE, "la_ds" }, \
 -{ "4x", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_4x }, INT_MIN, INT_MAX,                                            VE, "la_ds" }, \
 -{ "vcm",      "Use the video conferencing mode ratecontrol",  OFFSET(qsv.vcm),      AV_OPT_TYPE_INT, { .i64 = 0  },  0, 1,         VE },        \
 -{ "rdo",            "Enable rate distortion optimization",    OFFSET(qsv.rdo),            AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE }, \
 -{ "max_frame_size", "Maximum encoded frame size in bytes",    OFFSET(qsv.max_frame_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE }, \
 -{ "max_slice_size", "Maximum encoded slice size in bytes",    OFFSET(qsv.max_slice_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE }, \
 -{ "bitrate_limit",  "Toggle bitrate limitations",             OFFSET(qsv.bitrate_limit),  AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE }, \
 -{ "mbbrc",          "MB level bitrate control",               OFFSET(qsv.mbbrc),          AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE }, \
 -{ "extbrc",         "Extended bitrate control",               OFFSET(qsv.extbrc),         AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE }, \
 -{ "adaptive_i",     "Adaptive I-frame placement",             OFFSET(qsv.adaptive_i),     AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE }, \
 -{ "adaptive_b",     "Adaptive B-frame placement",             OFFSET(qsv.adaptive_b),     AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE }, \
 -{ "b_strategy",     "Strategy to choose between I/P/B-frames", OFFSET(qsv.b_strategy),    AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE },
 -
 +{ "async_depth", "Maximum processing parallelism", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VE },                          \
 +{ "avbr_accuracy",    "Accuracy of the AVBR ratecontrol",    OFFSET(qsv.avbr_accuracy),    AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },                             \
 +{ "avbr_convergence", "Convergence of the AVBR ratecontrol", OFFSET(qsv.avbr_convergence), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },                             \
 +{ "preset", NULL, OFFSET(qsv.preset), AV_OPT_TYPE_INT, { .i64 = MFX_TARGETUSAGE_BALANCED }, MFX_TARGETUSAGE_BEST_QUALITY, MFX_TARGETUSAGE_BEST_SPEED,   VE, "preset" }, \
 +{ "veryfast",    NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BEST_SPEED  },   INT_MIN, INT_MAX, VE, "preset" },                                                \
 +{ "faster",      NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_6  },            INT_MIN, INT_MAX, VE, "preset" },                                                \
 +{ "fast",        NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_5  },            INT_MIN, INT_MAX, VE, "preset" },                                                \
 +{ "medium",      NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BALANCED  },     INT_MIN, INT_MAX, VE, "preset" },                                                \
 +{ "slow",        NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_3  },            INT_MIN, INT_MAX, VE, "preset" },                                                \
 +{ "slower",      NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_2  },            INT_MIN, INT_MAX, VE, "preset" },                                                \
 +{ "veryslow",    NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BEST_QUALITY  }, INT_MIN, INT_MAX, VE, "preset" },                                                \
 +{ "vcm",      "Use the video conferencing mode ratecontrol",  OFFSET(qsv.vcm),      AV_OPT_TYPE_INT, { .i64 = 0  },  0, 1,         VE },                                \
 +{ "rdo",            "Enable rate distortion optimization",    OFFSET(qsv.rdo),            AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE },                         \
 +{ "max_frame_size", "Maximum encoded frame size in bytes",    OFFSET(qsv.max_frame_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE },                         \
 +{ "max_slice_size", "Maximum encoded slice size in bytes",    OFFSET(qsv.max_slice_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE },                         \
 +{ "bitrate_limit",  "Toggle bitrate limitations",             OFFSET(qsv.bitrate_limit),  AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE },                         \
 +{ "mbbrc",          "MB level bitrate control",               OFFSET(qsv.mbbrc),          AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE },                         \
 +{ "extbrc",         "Extended bitrate control",               OFFSET(qsv.extbrc),         AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE },                         \
 +{ "adaptive_i",     "Adaptive I-frame placement",             OFFSET(qsv.adaptive_i),     AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE },                         \
 +{ "adaptive_b",     "Adaptive B-frame placement",             OFFSET(qsv.adaptive_b),     AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE },                         \
 +{ "b_strategy",     "Strategy to choose between I/P/B-frames", OFFSET(qsv.b_strategy),    AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE },                         \
 +
 +typedef int SetEncodeCtrlCB (AVCodecContext *avctx,
 +                             const AVFrame *frame, mfxEncodeCtrl* enc_ctrl);
  typedef struct QSVEncContext {
      AVCodecContext *avctx;
  
      int preset;
      int avbr_accuracy;
      int avbr_convergence;
 -    int la_depth;
 -    int la_ds;
 +    int pic_timing_sei;
 +    int look_ahead;
 +    int look_ahead_depth;
 +    int look_ahead_downsampling;
      int vcm;
      int rdo;
      int max_frame_size;
      int max_slice_size;
  
+     int aud;
      int single_sei_nal_unit;
      int max_dec_frame_buffering;
      int trellis;
      int int_ref_qp_delta;
      int recovery_point_sei;
  
 +    int a53_cc;
      char *load_plugins;
 +    SetEncodeCtrlCB *set_encode_ctrl_cb;
  } QSVEncContext;
  
  int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q);
diff --combined libavcodec/qsvenc_h264.c
@@@ -3,20 -3,20 +3,20 @@@
   *
   * copyright (c) 2013 Yukinori Yamazoe
   *
 - * This file is part of Libav.
 + * This file is part of FFmpeg.
   *
 - * Libav is free software; you can redistribute it and/or
 + * FFmpeg is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
 - * Libav is distributed in the hope that it will be useful,
 + * FFmpeg is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public
 - * License along with Libav; if not, write to the Free Software
 + * License along with FFmpeg; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   */
  
@@@ -40,45 -40,10 +40,45 @@@ typedef struct QSVH264EncContext 
      QSVEncContext qsv;
  } QSVH264EncContext;
  
 +static int qsv_h264_set_encode_ctrl(AVCodecContext *avctx,
 +                                    const AVFrame *frame, mfxEncodeCtrl* enc_ctrl)
 +{
 +    QSVH264EncContext *qh264 = avctx->priv_data;
 +    QSVEncContext *q = &qh264->qsv;
 +
 +    if (q->a53_cc && frame) {
 +        mfxPayload* payload;
 +        mfxU8* sei_data;
 +        size_t sei_size;
 +        int res;
 +
 +        res = ff_alloc_a53_sei(frame, sizeof(mfxPayload) + 2, (void**)&payload, &sei_size);
 +        if (res < 0 || !payload)
 +            return res;
 +
 +        sei_data = (mfxU8*)(payload + 1);
 +        // SEI header
 +        sei_data[0] = 4;
 +        sei_data[1] = (mfxU8)sei_size; // size of SEI data
 +        // SEI data filled in by ff_alloc_a53_sei
 +
 +        payload->BufSize = sei_size + 2;
 +        payload->NumBit = payload->BufSize * 8;
 +        payload->Type = 4;
 +        payload->Data = sei_data;
 +
 +        enc_ctrl->NumExtParam = 0;
 +        enc_ctrl->NumPayload = 1;
 +        enc_ctrl->Payload[0] = payload;
 +    }
 +    return 0;
 +}
 +
  static av_cold int qsv_enc_init(AVCodecContext *avctx)
  {
      QSVH264EncContext *q = avctx->priv_data;
  
 +    q->qsv.set_encode_ctrl_cb = qsv_h264_set_encode_ctrl;
      return ff_qsv_enc_init(avctx, &q->qsv);
  }
  
@@@ -104,24 -69,9 +104,24 @@@ static const AVOption options[] = 
  
      { "cavlc",          "Enable CAVLC",                           OFFSET(qsv.cavlc),          AV_OPT_TYPE_INT, { .i64 = 0 },   0,          1, VE },
      { "idr_interval", "Distance (in I-frames) between IDR frames", OFFSET(qsv.idr_interval), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE },
 +    { "pic_timing_sei",    "Insert picture timing SEI with pic_struct_syntax element", OFFSET(qsv.pic_timing_sei), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE },
      { "single_sei_nal_unit",    "Put all the SEI messages into one NALU",        OFFSET(qsv.single_sei_nal_unit),     AV_OPT_TYPE_INT, { .i64 = -1 }, -1,          1, VE },
      { "max_dec_frame_buffering", "Maximum number of frames buffered in the DPB", OFFSET(qsv.max_dec_frame_buffering), AV_OPT_TYPE_INT, { .i64 = 0 },   0, UINT16_MAX, VE },
  
 +#if QSV_HAVE_LA
 +    { "look_ahead",       "Use VBR algorithm with look ahead",    OFFSET(qsv.look_ahead),       AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE },
 +    { "look_ahead_depth", "Depth of look ahead in number frames", OFFSET(qsv.look_ahead_depth), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, VE },
 +#endif
 +#if QSV_HAVE_LA_DS
 +    { "look_ahead_downsampling", "Downscaling factor for the frames saved for the lookahead analysis", OFFSET(qsv.look_ahead_downsampling),
 +                                          AV_OPT_TYPE_INT,   { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, MFX_LOOKAHEAD_DS_UNKNOWN, MFX_LOOKAHEAD_DS_2x, VE, "look_ahead_downsampling" },
 +    { "unknown"                , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, INT_MIN, INT_MAX,     VE, "look_ahead_downsampling" },
 +    { "auto"                   , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, INT_MIN, INT_MAX,     VE, "look_ahead_downsampling" },
 +    { "off"                    , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_OFF     }, INT_MIN, INT_MAX,     VE, "look_ahead_downsampling" },
 +    { "2x"                     , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_2x      }, INT_MIN, INT_MAX,     VE, "look_ahead_downsampling" },
 +    { "4x"                     , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_4x      }, INT_MIN, INT_MAX,     VE, "look_ahead_downsampling" },
 +#endif
 +
      { "int_ref_type", "Intra refresh type",                                      OFFSET(qsv.int_ref_type),            AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE, "int_ref_type" },
          { "none",     NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, .flags = VE, "int_ref_type" },
          { "vertical", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .flags = VE, "int_ref_type" },
      { "main"    , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_AVC_MAIN     }, INT_MIN, INT_MAX,     VE, "profile" },
      { "high"    , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_AVC_HIGH     }, INT_MIN, INT_MAX,     VE, "profile" },
  
 +    { "a53cc" , "Use A53 Closed Captions (if available)", OFFSET(qsv.a53_cc), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, VE},
++
+     { "aud", "Insert the Access Unit Delimiter NAL", OFFSET(qsv.aud), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE},
      { NULL },
  };