Merge commit '4ab61cd983b539749bd621ea271624ddb5196a8e'
authorMark Thompson <sw@jkqxz.net>
Thu, 30 Mar 2017 21:07:57 +0000 (22:07 +0100)
committerMark Thompson <sw@jkqxz.net>
Thu, 30 Mar 2017 21:07:57 +0000 (22:07 +0100)
* commit '4ab61cd983b539749bd621ea271624ddb5196a8e':
  qsv{enc,dec}: extend the internal frame allocator

Merged-by: Mark Thompson <sw@jkqxz.net>
1  2 
libavcodec/qsv.c
libavcodec/qsv_internal.h
libavcodec/qsvdec.c
libavcodec/qsvenc.c

diff --combined libavcodec/qsv.c
@@@ -1,20 -1,20 +1,20 @@@
  /*
   * Intel MediaSDK QSV encoder/decoder shared code
   *
 - * 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
   */
  
@@@ -29,6 -29,7 +29,7 @@@
  #include "libavutil/error.h"
  #include "libavutil/hwcontext.h"
  #include "libavutil/hwcontext_qsv.h"
+ #include "libavutil/imgutils.h"
  
  #include "avcodec.h"
  #include "qsv_internal.h"
@@@ -54,22 -55,6 +55,22 @@@ int ff_qsv_codec_id_to_mfx(enum AVCodec
      return AVERROR(ENOSYS);
  }
  
 +int ff_qsv_profile_to_mfx(enum AVCodecID codec_id, int profile)
 +{
 +    if (profile == FF_PROFILE_UNKNOWN)
 +        return MFX_PROFILE_UNKNOWN;
 +    switch (codec_id) {
 +    case AV_CODEC_ID_H264:
 +    case AV_CODEC_ID_HEVC:
 +        return profile;
 +    case AV_CODEC_ID_VC1:
 +        return 4 * profile + 1;
 +    case AV_CODEC_ID_MPEG2VIDEO:
 +        return 0x10 * profile;
 +    }
 +    return MFX_PROFILE_UNKNOWN;
 +}
 +
  static const struct {
      mfxStatus   mfxerr;
      int         averr;
@@@ -143,6 -128,16 +144,16 @@@ int ff_qsv_print_warning(void *log_ctx
      return ret;
  }
  
+ static enum AVPixelFormat qsv_map_fourcc(uint32_t fourcc)
+ {
+     switch (fourcc) {
+     case MFX_FOURCC_NV12: return AV_PIX_FMT_NV12;
+     case MFX_FOURCC_P010: return AV_PIX_FMT_P010;
+     case MFX_FOURCC_P8:   return AV_PIX_FMT_PAL8;
+     }
+     return AV_PIX_FMT_NONE;
+ }
  int ff_qsv_map_pixfmt(enum AVPixelFormat format, uint32_t *fourcc)
  {
      switch (format) {
@@@ -265,53 -260,251 +276,251 @@@ int ff_qsv_init_internal_session(AVCode
      return 0;
  }
  
+ static void mids_buf_free(void *opaque, uint8_t *data)
+ {
+     AVBufferRef *hw_frames_ref = opaque;
+     av_buffer_unref(&hw_frames_ref);
+     av_freep(&data);
+ }
+ static AVBufferRef *qsv_create_mids(AVBufferRef *hw_frames_ref)
+ {
+     AVHWFramesContext    *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data;
+     AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
+     int                  nb_surfaces = frames_hwctx->nb_surfaces;
+     AVBufferRef *mids_buf, *hw_frames_ref1;
+     QSVMid *mids;
+     int i;
+     hw_frames_ref1 = av_buffer_ref(hw_frames_ref);
+     if (!hw_frames_ref1)
+         return NULL;
+     mids = av_mallocz_array(nb_surfaces, sizeof(*mids));
+     if (!mids) {
+         av_buffer_unref(&hw_frames_ref1);
+         return NULL;
+     }
+     mids_buf = av_buffer_create((uint8_t*)mids, nb_surfaces * sizeof(*mids),
+                                 mids_buf_free, hw_frames_ref1, 0);
+     if (!mids_buf) {
+         av_buffer_unref(&hw_frames_ref1);
+         av_freep(&mids);
+         return NULL;
+     }
+     for (i = 0; i < nb_surfaces; i++) {
+         QSVMid *mid = &mids[i];
+         mid->handle        = frames_hwctx->surfaces[i].Data.MemId;
+         mid->hw_frames_ref = hw_frames_ref1;
+     }
+     return mids_buf;
+ }
+ static int qsv_setup_mids(mfxFrameAllocResponse *resp, AVBufferRef *hw_frames_ref,
+                           AVBufferRef *mids_buf)
+ {
+     AVHWFramesContext    *frames_ctx = (AVHWFramesContext*)hw_frames_ref->data;
+     AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
+     QSVMid                     *mids = (QSVMid*)mids_buf->data;
+     int                  nb_surfaces = frames_hwctx->nb_surfaces;
+     int i;
+     // the allocated size of the array is two larger than the number of
+     // surfaces, we store the references to the frames context and the
+     // QSVMid array there
+     resp->mids = av_mallocz_array(nb_surfaces + 2, sizeof(*resp->mids));
+     if (!resp->mids)
+         return AVERROR(ENOMEM);
+     for (i = 0; i < nb_surfaces; i++)
+         resp->mids[i] = &mids[i];
+     resp->NumFrameActual = nb_surfaces;
+     resp->mids[resp->NumFrameActual] = (mfxMemId)av_buffer_ref(hw_frames_ref);
+     if (!resp->mids[resp->NumFrameActual]) {
+         av_freep(&resp->mids);
+         return AVERROR(ENOMEM);
+     }
+     resp->mids[resp->NumFrameActual + 1] = av_buffer_ref(mids_buf);
+     if (!resp->mids[resp->NumFrameActual + 1]) {
+         av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]);
+         av_freep(&resp->mids);
+         return AVERROR(ENOMEM);
+     }
+     return 0;
+ }
  static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req,
                                   mfxFrameAllocResponse *resp)
  {
      QSVFramesContext *ctx = pthis;
-     mfxFrameInfo      *i  = &req->Info;
-     mfxFrameInfo      *i1 = &ctx->info;
-     int j;
+     int ret;
  
-     if (!(req->Type & MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET) ||
-         !(req->Type & (MFX_MEMTYPE_FROM_DECODE | MFX_MEMTYPE_FROM_ENCODE)) ||
-         !(req->Type & MFX_MEMTYPE_EXTERNAL_FRAME))
-         return MFX_ERR_UNSUPPORTED;
-     if (i->Width  != i1->Width || i->Height != i1->Height ||
-         i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) {
-         av_log(ctx, AV_LOG_ERROR, "Mismatching surface properties in an "
-                "allocation request: %dx%d %d %d vs %dx%d %d %d\n",
-                i->Width,  i->Height,  i->FourCC,  i->ChromaFormat,
-                i1->Width, i1->Height, i1->FourCC, i1->ChromaFormat);
+     /* this should only be called from an encoder or decoder and
+      * only allocates video memory frames */
+     if (!(req->Type & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET |
+                        MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET))         ||
+         !(req->Type & (MFX_MEMTYPE_FROM_DECODE | MFX_MEMTYPE_FROM_ENCODE)))
          return MFX_ERR_UNSUPPORTED;
-     }
  
-     resp->mids = av_mallocz_array(ctx->nb_mids, sizeof(*resp->mids));
-     if (!resp->mids)
-         return MFX_ERR_MEMORY_ALLOC;
+     if (req->Type & MFX_MEMTYPE_EXTERNAL_FRAME) {
+         /* external frames -- fill from the caller-supplied frames context */
+         AVHWFramesContext *frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data;
+         AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
+         mfxFrameInfo      *i  = &req->Info;
+         mfxFrameInfo      *i1 = &frames_hwctx->surfaces[0].Info;
+         if (i->Width  != i1->Width  || i->Height != i1->Height ||
+             i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) {
+             av_log(ctx->logctx, AV_LOG_ERROR, "Mismatching surface properties in an "
+                    "allocation request: %dx%d %d %d vs %dx%d %d %d\n",
+                    i->Width,  i->Height,  i->FourCC,  i->ChromaFormat,
+                    i1->Width, i1->Height, i1->FourCC, i1->ChromaFormat);
+             return MFX_ERR_UNSUPPORTED;
+         }
+         ret = qsv_setup_mids(resp, ctx->hw_frames_ctx, ctx->mids_buf);
+         if (ret < 0) {
+             av_log(ctx->logctx, AV_LOG_ERROR,
+                    "Error filling an external frame allocation request\n");
+             return MFX_ERR_MEMORY_ALLOC;
+         }
+     } else if (req->Type & MFX_MEMTYPE_INTERNAL_FRAME) {
+         /* internal frames -- allocate a new hw frames context */
+         AVHWFramesContext *ext_frames_ctx = (AVHWFramesContext*)ctx->hw_frames_ctx->data;
+         mfxFrameInfo      *i  = &req->Info;
+         AVBufferRef *frames_ref, *mids_buf;
+         AVHWFramesContext *frames_ctx;
+         AVQSVFramesContext *frames_hwctx;
+         frames_ref = av_hwframe_ctx_alloc(ext_frames_ctx->device_ref);
+         if (!frames_ref)
+             return MFX_ERR_MEMORY_ALLOC;
+         frames_ctx   = (AVHWFramesContext*)frames_ref->data;
+         frames_hwctx = frames_ctx->hwctx;
+         frames_ctx->format            = AV_PIX_FMT_QSV;
+         frames_ctx->sw_format         = qsv_map_fourcc(i->FourCC);
+         frames_ctx->width             = i->Width;
+         frames_ctx->height            = i->Height;
+         frames_ctx->initial_pool_size = req->NumFrameSuggested;
+         frames_hwctx->frame_type      = req->Type;
+         ret = av_hwframe_ctx_init(frames_ref);
+         if (ret < 0) {
+             av_log(ctx->logctx, AV_LOG_ERROR,
+                    "Error initializing a frames context for an internal frame "
+                    "allocation request\n");
+             av_buffer_unref(&frames_ref);
+             return MFX_ERR_MEMORY_ALLOC;
+         }
  
-     for (j = 0; j < ctx->nb_mids; j++)
-         resp->mids[j] = &ctx->mids[j];
+         mids_buf = qsv_create_mids(frames_ref);
+         if (!mids_buf) {
+             av_buffer_unref(&frames_ref);
+             return MFX_ERR_MEMORY_ALLOC;
+         }
  
-     resp->NumFrameActual = ctx->nb_mids;
+         ret = qsv_setup_mids(resp, frames_ref, mids_buf);
+         av_buffer_unref(&mids_buf);
+         av_buffer_unref(&frames_ref);
+         if (ret < 0) {
+             av_log(ctx->logctx, AV_LOG_ERROR,
+                    "Error filling an internal frame allocation request\n");
+             return MFX_ERR_MEMORY_ALLOC;
+         }
+     } else {
+         return MFX_ERR_UNSUPPORTED;
+     }
  
      return MFX_ERR_NONE;
  }
  
  static mfxStatus qsv_frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp)
  {
+     av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual]);
+     av_buffer_unref((AVBufferRef**)&resp->mids[resp->NumFrameActual + 1]);
      av_freep(&resp->mids);
      return MFX_ERR_NONE;
  }
  
  static mfxStatus qsv_frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
  {
-     return MFX_ERR_UNSUPPORTED;
+     QSVMid *qsv_mid = mid;
+     AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)qsv_mid->hw_frames_ref->data;
+     AVQSVFramesContext *hw_frames_hwctx = hw_frames_ctx->hwctx;
+     int size;
+     int ret;
+     mfxStatus err;
+     if (qsv_mid->locked_frame)
+         return MFX_ERR_UNDEFINED_BEHAVIOR;
+     /* Allocate a system memory frame that will hold the mapped data. */
+     qsv_mid->locked_frame = av_frame_alloc();
+     if (!qsv_mid->locked_frame)
+         return MFX_ERR_MEMORY_ALLOC;
+     qsv_mid->locked_frame->format  = hw_frames_ctx->sw_format;
+     /* wrap the provided handle in a hwaccel AVFrame */
+     qsv_mid->hw_frame = av_frame_alloc();
+     if (!qsv_mid->hw_frame)
+         goto fail;
+     qsv_mid->hw_frame->data[3] = (uint8_t*)&qsv_mid->surf;
+     qsv_mid->hw_frame->format  = AV_PIX_FMT_QSV;
+     // doesn't really matter what buffer is used here
+     qsv_mid->hw_frame->buf[0]  = av_buffer_alloc(1);
+     if (!qsv_mid->hw_frame->buf[0])
+         goto fail;
+     qsv_mid->hw_frame->width   = hw_frames_ctx->width;
+     qsv_mid->hw_frame->height  = hw_frames_ctx->height;
+     qsv_mid->hw_frame->hw_frames_ctx = av_buffer_ref(qsv_mid->hw_frames_ref);
+     if (!qsv_mid->hw_frame->hw_frames_ctx)
+         goto fail;
+     qsv_mid->surf.Info = hw_frames_hwctx->surfaces[0].Info;
+     qsv_mid->surf.Data.MemId = qsv_mid->handle;
+     /* map the data to the system memory */
+     ret = av_hwframe_map(qsv_mid->locked_frame, qsv_mid->hw_frame,
+                          AV_HWFRAME_MAP_DIRECT);
+     if (ret < 0)
+         goto fail;
+     ptr->Pitch = qsv_mid->locked_frame->linesize[0];
+     ptr->Y     = qsv_mid->locked_frame->data[0];
+     ptr->U     = qsv_mid->locked_frame->data[1];
+     ptr->V     = qsv_mid->locked_frame->data[1] + 1;
+     return MFX_ERR_NONE;
+ fail:
+     av_frame_free(&qsv_mid->hw_frame);
+     av_frame_free(&qsv_mid->locked_frame);
+     return MFX_ERR_MEMORY_ALLOC;
  }
  
  static mfxStatus qsv_frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr)
  {
-     return MFX_ERR_UNSUPPORTED;
+     QSVMid *qsv_mid = mid;
+     int ret;
+     av_frame_free(&qsv_mid->locked_frame);
+     av_frame_free(&qsv_mid->hw_frame);
+     return MFX_ERR_NONE;
  }
  
  static mfxStatus qsv_frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl)
@@@ -392,16 -585,15 +601,15 @@@ int ff_qsv_init_session_hwcontext(AVCod
      }
  
      if (!opaque) {
-         av_freep(&qsv_frames_ctx->mids);
-         qsv_frames_ctx->mids = av_mallocz_array(frames_hwctx->nb_surfaces,
-                                                 sizeof(*qsv_frames_ctx->mids));
-         if (!qsv_frames_ctx->mids)
-             return AVERROR(ENOMEM);
+         qsv_frames_ctx->logctx = avctx;
  
-         qsv_frames_ctx->info    = frames_hwctx->surfaces[0].Info;
+         /* allocate the memory ids for the external frames */
+         av_buffer_unref(&qsv_frames_ctx->mids_buf);
+         qsv_frames_ctx->mids_buf = qsv_create_mids(qsv_frames_ctx->hw_frames_ctx);
+         if (!qsv_frames_ctx->mids_buf)
+             return AVERROR(ENOMEM);
+         qsv_frames_ctx->mids    = (QSVMid*)qsv_frames_ctx->mids_buf->data;
          qsv_frames_ctx->nb_mids = frames_hwctx->nb_surfaces;
-         for (i = 0; i < frames_hwctx->nb_surfaces; i++)
-             qsv_frames_ctx->mids[i].handle = frames_hwctx->surfaces[i].Data.MemId;
  
          err = MFXVideoCORE_SetFrameAllocator(session, &frame_allocator);
          if (err != MFX_ERR_NONE)
@@@ -1,20 -1,20 +1,20 @@@
  /*
   * Intel MediaSDK QSV encoder/decoder shared code
   *
 - * 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
   */
  
  
  #define ASYNC_DEPTH_DEFAULT 4       // internal parallelism
  
 +#define QSV_MAX_ENC_PAYLOAD 2       // # of mfxEncodeCtrl payloads supported
 +
  #define QSV_VERSION_ATLEAST(MAJOR, MINOR)   \
      (MFX_VERSION_MAJOR > (MAJOR) ||         \
       MFX_VERSION_MAJOR == (MAJOR) && MFX_VERSION_MINOR >= (MINOR))
  
  typedef struct QSVMid {
+     AVBufferRef *hw_frames_ref;
      mfxHDL handle;
+     AVFrame *locked_frame;
+     AVFrame *hw_frame;
+     mfxFrameSurface1 surf;
  } QSVMid;
  
  typedef struct QSVFrame {
      AVFrame *frame;
      mfxFrameSurface1 surface;
 +    mfxEncodeCtrl enc_ctrl;
  
      int queued;
      int used;
  
  typedef struct QSVFramesContext {
      AVBufferRef *hw_frames_ctx;
-     mfxFrameInfo info;
+     void *logctx;
+     /* The memory ids for the external frames.
+      * Refcounted, since we need one reference owned by the QSVFramesContext
+      * (i.e. by the encoder/decoder) and another one given to the MFX session
+      * from the frame allocator. */
+     AVBufferRef *mids_buf;
      QSVMid *mids;
      int  nb_mids;
  } QSVFramesContext;
  
  /**
 - * Convert a libmfx error code into a libav error code.
 + * Convert a libmfx error code into an ffmpeg error code.
   */
  int ff_qsv_map_error(mfxStatus mfx_err, const char **desc);
  
@@@ -72,7 -80,6 +83,7 @@@ int ff_qsv_print_warning(void *log_ctx
                           const char *warning_string);
  
  int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id);
 +int ff_qsv_profile_to_mfx(enum AVCodecID codec_id, int profile);
  
  int ff_qsv_map_pixfmt(enum AVPixelFormat format, uint32_t *fourcc);
  
diff --combined libavcodec/qsvdec.c
@@@ -4,20 -4,20 +4,20 @@@
   * copyright (c) 2013 Luca Barbato
   * copyright (c) 2015 Anton Khirnov <anton@khirnov.net>
   *
 - * 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
   */
  
@@@ -144,8 -144,8 +144,8 @@@ static int qsv_decode_init(AVCodecConte
          return ret;
  
      param.mfx.CodecId      = ret;
 -    param.mfx.CodecProfile = avctx->profile;
 -    param.mfx.CodecLevel   = avctx->level;
 +    param.mfx.CodecProfile = ff_qsv_profile_to_mfx(avctx->codec_id, avctx->profile);
 +    param.mfx.CodecLevel   = avctx->level == FF_LEVEL_UNKNOWN ? MFX_LEVEL_UNKNOWN : avctx->level;
  
      param.mfx.FrameInfo.BitDepthLuma   = desc->comp[0].depth;
      param.mfx.FrameInfo.BitDepthChroma = desc->comp[0].depth;
      param.mfx.FrameInfo.Height         = frame_height;
      param.mfx.FrameInfo.ChromaFormat   = MFX_CHROMAFORMAT_YUV420;
  
 +    switch (avctx->field_order) {
 +    case AV_FIELD_PROGRESSIVE:
 +        param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
 +        break;
 +    case AV_FIELD_TT:
 +        param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_FIELD_TFF;
 +        break;
 +    case AV_FIELD_BB:
 +        param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_FIELD_BFF;
 +        break;
 +    default:
 +        param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_UNKNOWN;
 +        break;
 +    }
 +
      param.IOPattern   = q->iopattern;
      param.AsyncDepth  = q->async_depth;
      param.ExtParam    = q->ext_buffers;
@@@ -306,15 -291,13 +306,15 @@@ static int qsv_decode(AVCodecContext *a
  
      do {
          ret = get_surface(avctx, q, &insurf);
 -        if (ret < 0)
 +        if (ret < 0) {
 +            av_freep(&sync);
              return ret;
 +        }
  
          ret = MFXVideoDECODE_DecodeFrameAsync(q->session, avpkt->size ? &bs : NULL,
                                                insurf, &outsurf, sync);
          if (ret == MFX_WRN_DEVICE_BUSY)
 -            av_usleep(1);
 +            av_usleep(500);
  
      } while (ret == MFX_WRN_DEVICE_BUSY || ret == MFX_ERR_MORE_SURFACE);
  
@@@ -433,8 -416,7 +433,7 @@@ int ff_qsv_decode_close(QSVContext *q
          MFXClose(q->internal_session);
  
      av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
-     av_freep(&q->frames_ctx.mids);
-     q->frames_ctx.nb_mids = 0;
+     av_buffer_unref(&q->frames_ctx.mids_buf);
  
      return 0;
  }
@@@ -451,6 -433,16 +450,6 @@@ int ff_qsv_process_data(AVCodecContext 
          if (!q->avctx_internal)
              return AVERROR(ENOMEM);
  
 -        if (avctx->extradata) {
 -            q->avctx_internal->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
 -            if (!q->avctx_internal->extradata)
 -                return AVERROR(ENOMEM);
 -
 -            memcpy(q->avctx_internal->extradata, avctx->extradata,
 -                   avctx->extradata_size);
 -            q->avctx_internal->extradata_size = avctx->extradata_size;
 -        }
 -
          q->parser = av_parser_init(avctx->codec_id);
          if (!q->parser)
              return AVERROR(ENOMEM);
          avctx->height       = q->parser->height;
          avctx->coded_width  = q->parser->coded_width;
          avctx->coded_height = q->parser->coded_height;
 +        avctx->field_order  = q->parser->field_order;
          avctx->level        = q->avctx_internal->level;
          avctx->profile      = q->avctx_internal->profile;
  
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"
@@@ -134,6 -133,9 +134,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);
@@@ -265,7 -273,7 +265,7 @@@ static int select_rc_mode(AVCodecContex
      const char *rc_desc;
      mfxU16      rc_mode;
  
 -    int want_la     = q->la_depth >= 0;
 +    int want_la     = q->look_ahead;
      int want_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE);
      int want_vcm    = q->vcm;
  
@@@ -440,11 -448,11 +440,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;
@@@ -466,9 -474,6 +466,9 @@@ FF_ENABLE_DEPRECATION_WARNING
          q->extco.CAVLC = q->cavlc ? MFX_CODINGOPTION_ON
                                    : MFX_CODINGOPTION_UNKNOWN;
  
 +        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;
  
@@@ -532,10 -537,6 +532,10 @@@ FF_ENABLE_DEPRECATION_WARNING
  #endif
  
              q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco2;
 +
 +#if QSV_HAVE_LA_DS
 +            q->extco2.LookAheadDS           = q->look_ahead_downsampling;
 +#endif
          }
  #endif
      }
@@@ -574,12 -575,21 +574,12 @@@ 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,
          (mfxExtBuffer*)&co,
  #if QSV_HAVE_CO2
          (mfxExtBuffer*)&co2,
 -#endif
 -#if QSV_HAVE_CO3
 -        (mfxExtBuffer*)&co3,
  #endif
      };
  
@@@ -799,23 -809,11 +799,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;
          }
@@@ -850,11 -848,6 +850,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;
  }
@@@ -955,21 -948,15 +955,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)
@@@ -1110,14 -1093,12 +1110,13 @@@ int ff_qsv_enc_close(AVCodecContext *av
      q->internal_session = NULL;
  
      av_buffer_unref(&q->frames_ctx.hw_frames_ctx);
-     av_freep(&q->frames_ctx.mids);
-     q->frames_ctx.nb_mids = 0;
+     av_buffer_unref(&q->frames_ctx.mids_buf);
  
      cur = q->work_frames;
      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;
      }