libavcodec/qsvenc.c
72b7441a
 /*
  * Intel MediaSDK QSV encoder utility functions
  *
  * copyright (c) 2013 Yukinori Yamazoe
  * copyright (c) 2015 Anton Khirnov
  *
0a731e45
  * This file is part of FFmpeg.
72b7441a
  *
0a731e45
  * FFmpeg is free software; you can redistribute it and/or
72b7441a
  * 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.
  *
0a731e45
  * FFmpeg is distributed in the hope that it will be useful,
72b7441a
  * 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
0a731e45
  * License along with FFmpeg; if not, write to the Free Software
72b7441a
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
 #include <string.h>
 #include <sys/types.h>
 #include <mfx/mfxvideo.h>
 
 #include "libavutil/common.h"
 #include "libavutil/mem.h"
 #include "libavutil/log.h"
 #include "libavutil/time.h"
 #include "libavutil/imgutils.h"
0eac93da
 #include "libavcodec/bytestream.h"
72b7441a
 
 #include "avcodec.h"
 #include "internal.h"
 #include "qsv.h"
 #include "qsv_internal.h"
 #include "qsvenc.h"
 
4d8f536b
 static const struct {
     mfxU16 profile;
     const char *name;
 } profile_names[] = {
     { MFX_PROFILE_AVC_BASELINE,                 "baseline"              },
     { MFX_PROFILE_AVC_MAIN,                     "main"                  },
     { MFX_PROFILE_AVC_EXTENDED,                 "extended"              },
     { MFX_PROFILE_AVC_HIGH,                     "high"                  },
 #if QSV_VERSION_ATLEAST(1, 15)
     { MFX_PROFILE_AVC_HIGH_422,                 "high 422"              },
 #endif
 #if QSV_VERSION_ATLEAST(1, 4)
     { MFX_PROFILE_AVC_CONSTRAINED_BASELINE,     "constrained baseline"  },
     { MFX_PROFILE_AVC_CONSTRAINED_HIGH,         "constrained high"      },
     { MFX_PROFILE_AVC_PROGRESSIVE_HIGH,         "progressive high"      },
 #endif
     { MFX_PROFILE_MPEG2_SIMPLE,                 "simple"                },
     { MFX_PROFILE_MPEG2_MAIN,                   "main"                  },
     { MFX_PROFILE_MPEG2_HIGH,                   "high"                  },
     { MFX_PROFILE_VC1_SIMPLE,                   "simple"                },
     { MFX_PROFILE_VC1_MAIN,                     "main"                  },
     { MFX_PROFILE_VC1_ADVANCED,                 "advanced"              },
 #if QSV_VERSION_ATLEAST(1, 8)
     { MFX_PROFILE_HEVC_MAIN,                    "main"                  },
     { MFX_PROFILE_HEVC_MAIN10,                  "main10"                },
     { MFX_PROFILE_HEVC_MAINSP,                  "mainsp"                },
 #endif
 };
 
 static const char *print_profile(mfxU16 profile)
 {
     int i;
     for (i = 0; i < FF_ARRAY_ELEMS(profile_names); i++)
         if (profile == profile_names[i].profile)
             return profile_names[i].name;
     return "unknown";
 }
 
 static const struct {
     mfxU16      rc_mode;
     const char *name;
 } rc_names[] = {
     { MFX_RATECONTROL_CBR,     "CBR" },
     { MFX_RATECONTROL_VBR,     "VBR" },
     { MFX_RATECONTROL_CQP,     "CQP" },
     { MFX_RATECONTROL_AVBR,    "AVBR" },
 #if QSV_HAVE_LA
     { MFX_RATECONTROL_LA,      "LA" },
 #endif
 #if QSV_HAVE_ICQ
     { MFX_RATECONTROL_ICQ,     "ICQ" },
     { MFX_RATECONTROL_LA_ICQ,  "LA_ICQ" },
 #endif
 #if QSV_HAVE_VCM
     { MFX_RATECONTROL_VCM,     "VCM" },
 #endif
 #if QSV_VERSION_ATLEAST(1, 10)
     { MFX_RATECONTROL_LA_EXT,  "LA_EXT" },
 #endif
 #if QSV_HAVE_LA_HRD
     { MFX_RATECONTROL_LA_HRD,  "LA_HRD" },
 #endif
 #if QSV_HAVE_QVBR
     { MFX_RATECONTROL_QVBR,    "QVBR" },
 #endif
 };
 
 static const char *print_ratecontrol(mfxU16 rc_mode)
 {
     int i;
     for (i = 0; i < FF_ARRAY_ELEMS(rc_names); i++)
         if (rc_mode == rc_names[i].rc_mode)
             return rc_names[i].name;
     return "unknown";
 }
 
 static const char *print_threestate(mfxU16 val)
 {
     if (val == MFX_CODINGOPTION_ON)
         return "ON";
     else if (val == MFX_CODINGOPTION_OFF)
         return "OFF";
     return "unknown";
 }
 
 static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q,
                              mfxExtBuffer **coding_opts)
 {
     mfxInfoMFX *info = &q->param.mfx;
 
     mfxExtCodingOption   *co = (mfxExtCodingOption*)coding_opts[0];
 #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);
 
     av_log(avctx, AV_LOG_VERBOSE, "GopPicSize: %"PRIu16"; GopRefDist: %"PRIu16"; GopOptFlag: ",
            info->GopPicSize, info->GopRefDist);
     if (info->GopOptFlag & MFX_GOP_CLOSED)
         av_log(avctx, AV_LOG_VERBOSE, "closed ");
     if (info->GopOptFlag & MFX_GOP_STRICT)
         av_log(avctx, AV_LOG_VERBOSE, "strict ");
     av_log(avctx, AV_LOG_VERBOSE, "; IdrInterval: %"PRIu16"\n", info->IdrInterval);
 
     av_log(avctx, AV_LOG_VERBOSE, "TargetUsage: %"PRIu16"; RateControlMethod: %s\n",
            info->TargetUsage, print_ratecontrol(info->RateControlMethod));
 
     if (info->RateControlMethod == MFX_RATECONTROL_CBR ||
         info->RateControlMethod == MFX_RATECONTROL_VBR
 #if QSV_HAVE_VCM
         || info->RateControlMethod == MFX_RATECONTROL_VCM
 #endif
         ) {
         av_log(avctx, AV_LOG_VERBOSE,
                "InitialDelayInKB: %"PRIu16"; TargetKbps: %"PRIu16"; MaxKbps: %"PRIu16"\n",
                info->InitialDelayInKB, info->TargetKbps, info->MaxKbps);
     } else if (info->RateControlMethod == MFX_RATECONTROL_CQP) {
         av_log(avctx, AV_LOG_VERBOSE, "QPI: %"PRIu16"; QPP: %"PRIu16"; QPB: %"PRIu16"\n",
                info->QPI, info->QPP, info->QPB);
     } else if (info->RateControlMethod == MFX_RATECONTROL_AVBR) {
         av_log(avctx, AV_LOG_VERBOSE,
                "TargetKbps: %"PRIu16"; Accuracy: %"PRIu16"; Convergence: %"PRIu16"\n",
                info->TargetKbps, info->Accuracy, info->Convergence);
     }
 #if QSV_HAVE_LA
     else if (info->RateControlMethod == MFX_RATECONTROL_LA
 #if QSV_HAVE_LA_HRD
              || info->RateControlMethod == MFX_RATECONTROL_LA_HRD
 #endif
              ) {
         av_log(avctx, AV_LOG_VERBOSE,
                "TargetKbps: %"PRIu16"; LookAheadDepth: %"PRIu16"\n",
                info->TargetKbps, co2->LookAheadDepth);
     }
 #endif
 #if QSV_HAVE_ICQ
     else if (info->RateControlMethod == MFX_RATECONTROL_ICQ) {
         av_log(avctx, AV_LOG_VERBOSE, "ICQQuality: %"PRIu16"\n", info->ICQQuality);
     } else if (info->RateControlMethod == MFX_RATECONTROL_LA_ICQ) {
         av_log(avctx, AV_LOG_VERBOSE, "ICQQuality: %"PRIu16"; LookAheadDepth: %"PRIu16"\n",
                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);
     av_log(avctx, AV_LOG_VERBOSE, "RateDistortionOpt: %s\n",
            print_threestate(co->RateDistortionOpt));
 
 #if QSV_HAVE_CO2
     av_log(avctx, AV_LOG_VERBOSE,
            "RecoveryPointSEI: %s IntRefType: %"PRIu16"; IntRefCycleSize: %"PRIu16"; IntRefQPDelta: %"PRId16"\n",
            print_threestate(co->RecoveryPointSEI), co2->IntRefType, co2->IntRefCycleSize, co2->IntRefQPDelta);
 
     av_log(avctx, AV_LOG_VERBOSE, "MaxFrameSize: %"PRIu16"; ", co2->MaxFrameSize);
fc4c27c4
 #if QSV_HAVE_MAX_SLICE_SIZE
4d8f536b
     av_log(avctx, AV_LOG_VERBOSE, "MaxSliceSize: %"PRIu16"; ", co2->MaxSliceSize);
 #endif
     av_log(avctx, AV_LOG_VERBOSE, "\n");
 
     av_log(avctx, AV_LOG_VERBOSE,
            "BitrateLimit: %s; MBBRC: %s; ExtBRC: %s\n",
            print_threestate(co2->BitrateLimit), print_threestate(co2->MBBRC),
            print_threestate(co2->ExtBRC));
 
 #if QSV_HAVE_TRELLIS
     av_log(avctx, AV_LOG_VERBOSE, "Trellis: ");
     if (co2->Trellis & MFX_TRELLIS_OFF) {
         av_log(avctx, AV_LOG_VERBOSE, "off");
     } else if (!co2->Trellis) {
         av_log(avctx, AV_LOG_VERBOSE, "auto");
     } else {
         if (co2->Trellis & MFX_TRELLIS_I) av_log(avctx, AV_LOG_VERBOSE, "I");
         if (co2->Trellis & MFX_TRELLIS_P) av_log(avctx, AV_LOG_VERBOSE, "P");
         if (co2->Trellis & MFX_TRELLIS_B) av_log(avctx, AV_LOG_VERBOSE, "B");
     }
     av_log(avctx, AV_LOG_VERBOSE, "\n");
 #endif
 
 #if QSV_VERSION_ATLEAST(1, 8)
     av_log(avctx, AV_LOG_VERBOSE,
            "RepeatPPS: %s; NumMbPerSlice: %"PRIu16"; LookAheadDS: ",
            print_threestate(co2->RepeatPPS), co2->NumMbPerSlice);
     switch (co2->LookAheadDS) {
     case MFX_LOOKAHEAD_DS_OFF: av_log(avctx, AV_LOG_VERBOSE, "off");     break;
     case MFX_LOOKAHEAD_DS_2x:  av_log(avctx, AV_LOG_VERBOSE, "2x");      break;
     case MFX_LOOKAHEAD_DS_4x:  av_log(avctx, AV_LOG_VERBOSE, "4x");      break;
     default:                   av_log(avctx, AV_LOG_VERBOSE, "unknown"); break;
     }
     av_log(avctx, AV_LOG_VERBOSE, "\n");
 
     av_log(avctx, AV_LOG_VERBOSE, "AdaptiveI: %s; AdaptiveB: %s; BRefType: ",
            print_threestate(co2->AdaptiveI), print_threestate(co2->AdaptiveB));
     switch (co2->BRefType) {
     case MFX_B_REF_OFF:     av_log(avctx, AV_LOG_VERBOSE, "off");       break;
     case MFX_B_REF_PYRAMID: av_log(avctx, AV_LOG_VERBOSE, "pyramid");   break;
     default:                av_log(avctx, AV_LOG_VERBOSE, "auto");      break;
     }
     av_log(avctx, AV_LOG_VERBOSE, "\n");
 #endif
 
 #if QSV_VERSION_ATLEAST(1, 9)
     av_log(avctx, AV_LOG_VERBOSE,
            "MinQPI: %"PRIu8"; MaxQPI: %"PRIu8"; MinQPP: %"PRIu8"; MaxQPP: %"PRIu8"; MinQPB: %"PRIu8"; MaxQPB: %"PRIu8"\n",
            co2->MinQPI, co2->MaxQPI, co2->MinQPP, co2->MaxQPP, co2->MinQPB, co2->MaxQPB);
 #endif
 #endif
 
     if (avctx->codec_id == AV_CODEC_ID_H264) {
         av_log(avctx, AV_LOG_VERBOSE, "Entropy coding: %s; MaxDecFrameBuffering: %"PRIu16"\n",
                co->CAVLC == MFX_CODINGOPTION_ON ? "CAVLC" : "CABAC", co->MaxDecFrameBuffering);
         av_log(avctx, AV_LOG_VERBOSE,
                "NalHrdConformance: %s; SingleSeiNalUnit: %s; VuiVclHrdParameters: %s VuiNalHrdParameters: %s\n",
                print_threestate(co->NalHrdConformance), print_threestate(co->SingleSeiNalUnit),
                print_threestate(co->VuiVclHrdParameters), print_threestate(co->VuiNalHrdParameters));
     }
 }
 
e7d7cf86
 static int select_rc_mode(AVCodecContext *avctx, QSVEncContext *q)
72b7441a
 {
e7d7cf86
     const char *rc_desc;
     mfxU16      rc_mode;
 
24563c20
     int want_la     = q->look_ahead;
e7d7cf86
     int want_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE);
     int want_vcm    = q->vcm;
 
     if (want_la && !QSV_HAVE_LA) {
         av_log(avctx, AV_LOG_ERROR,
                "Lookahead ratecontrol mode requested, but is not supported by this SDK version\n");
         return AVERROR(ENOSYS);
     }
     if (want_vcm && !QSV_HAVE_VCM) {
         av_log(avctx, AV_LOG_ERROR,
                "VCM ratecontrol mode requested, but is not supported by this SDK version\n");
         return AVERROR(ENOSYS);
     }
 
     if (want_la + want_qscale + want_vcm > 1) {
         av_log(avctx, AV_LOG_ERROR,
                "More than one of: { constant qscale, lookahead, VCM } requested, "
                "only one of them can be used at a time.\n");
         return AVERROR(EINVAL);
     }
72b7441a
 
e7d7cf86
     if (want_qscale) {
         rc_mode = MFX_RATECONTROL_CQP;
         rc_desc = "constant quantization parameter (CQP)";
     }
 #if QSV_HAVE_VCM
     else if (want_vcm) {
         rc_mode = MFX_RATECONTROL_VCM;
         rc_desc = "video conferencing mode (VCM)";
     }
 #endif
 #if QSV_HAVE_LA
     else if (want_la) {
         rc_mode = MFX_RATECONTROL_LA;
         rc_desc = "VBR with lookahead (LA)";
72b7441a
 
e7d7cf86
 #if QSV_HAVE_ICQ
         if (avctx->global_quality > 0) {
             rc_mode = MFX_RATECONTROL_LA_ICQ;
             rc_desc = "intelligent constant quality with lookahead (LA_ICQ)";
         }
 #endif
     }
 #endif
 #if QSV_HAVE_ICQ
     else if (avctx->global_quality > 0) {
         rc_mode = MFX_RATECONTROL_ICQ;
         rc_desc = "intelligent constant quality (ICQ)";
     }
 #endif
     else if (avctx->rc_max_rate == avctx->bit_rate) {
         rc_mode = MFX_RATECONTROL_CBR;
         rc_desc = "constant bitrate (CBR)";
     } else if (!avctx->rc_max_rate) {
         rc_mode = MFX_RATECONTROL_AVBR;
         rc_desc = "average variable bitrate (AVBR)";
     } else {
         rc_mode = MFX_RATECONTROL_VBR;
         rc_desc = "variable bitrate (VBR)";
     }
 
     q->param.mfx.RateControlMethod = rc_mode;
     av_log(avctx, AV_LOG_VERBOSE, "Using the %s ratecontrol method\n", rc_desc);
 
     return 0;
 }
 
 static int rc_supported(QSVEncContext *q)
 {
     mfxVideoParam param_out = { .mfx.CodecId = q->param.mfx.CodecId };
     mfxStatus ret;
 
     ret = MFXVideoENCODE_Query(q->session, &q->param, &param_out);
     if (ret < 0 ||
         param_out.mfx.RateControlMethod != q->param.mfx.RateControlMethod)
         return 0;
     return 1;
 }
 
 static int init_video_param(AVCodecContext *avctx, QSVEncContext *q)
 {
72b7441a
     float quant;
     int ret;
 
     ret = ff_qsv_codec_id_to_mfx(avctx->codec_id);
     if (ret < 0)
         return AVERROR_BUG;
     q->param.mfx.CodecId = ret;
 
66acb76b
     q->width_align = avctx->codec_id == AV_CODEC_ID_HEVC ? 32 : 16;
 
72b7441a
     if (avctx->level > 0)
         q->param.mfx.CodecLevel = avctx->level;
 
     q->param.mfx.CodecProfile       = q->profile;
     q->param.mfx.TargetUsage        = q->preset;
     q->param.mfx.GopPicSize         = FFMAX(0, avctx->gop_size);
     q->param.mfx.GopRefDist         = FFMAX(-1, avctx->max_b_frames) + 1;
7c6eb0a1
     q->param.mfx.GopOptFlag         = avctx->flags & AV_CODEC_FLAG_CLOSED_GOP ?
72b7441a
                                       MFX_GOP_CLOSED : 0;
     q->param.mfx.IdrInterval        = q->idr_interval;
     q->param.mfx.NumSlice           = avctx->slices;
     q->param.mfx.NumRefFrame        = FFMAX(0, avctx->refs);
     q->param.mfx.EncodedOrder       = 0;
     q->param.mfx.BufferSizeInKB     = 0;
 
     q->param.mfx.FrameInfo.FourCC         = MFX_FOURCC_NV12;
     q->param.mfx.FrameInfo.CropX          = 0;
     q->param.mfx.FrameInfo.CropY          = 0;
     q->param.mfx.FrameInfo.CropW          = avctx->width;
     q->param.mfx.FrameInfo.CropH          = avctx->height;
     q->param.mfx.FrameInfo.AspectRatioW   = avctx->sample_aspect_ratio.num;
     q->param.mfx.FrameInfo.AspectRatioH   = avctx->sample_aspect_ratio.den;
     q->param.mfx.FrameInfo.ChromaFormat   = MFX_CHROMAFORMAT_YUV420;
     q->param.mfx.FrameInfo.BitDepthLuma   = 8;
     q->param.mfx.FrameInfo.BitDepthChroma = 8;
7871eb43
     q->param.mfx.FrameInfo.Width          = FFALIGN(avctx->width, q->width_align);
38402754
 
94d68a41
     if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) {
38402754
        /* A true field layout (TFF or BFF) is not important here,
           it will specified later during frame encoding. But it is important
           to specify is frame progressive or not because allowed heigh alignment
           does depend by this.
         */
         q->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_FIELD_TFF;
dbf8352a
         q->height_align = 32;
38402754
     } else {
         q->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
dbf8352a
         q->height_align = 16;
38402754
     }
dbf8352a
    q->param.mfx.FrameInfo.Height    = FFALIGN(avctx->height, q->height_align);
72b7441a
 
     if (avctx->framerate.den > 0 && avctx->framerate.num > 0) {
         q->param.mfx.FrameInfo.FrameRateExtN = avctx->framerate.num;
         q->param.mfx.FrameInfo.FrameRateExtD = avctx->framerate.den;
     } else {
         q->param.mfx.FrameInfo.FrameRateExtN  = avctx->time_base.den;
         q->param.mfx.FrameInfo.FrameRateExtD  = avctx->time_base.num;
     }
 
e7d7cf86
     ret = select_rc_mode(avctx, q);
     if (ret < 0)
         return ret;
72b7441a
 
     switch (q->param.mfx.RateControlMethod) {
     case MFX_RATECONTROL_CBR:
     case MFX_RATECONTROL_VBR:
e7d7cf86
 #if QSV_HAVE_VCM
     case MFX_RATECONTROL_VCM:
 #endif
72b7441a
         q->param.mfx.InitialDelayInKB = avctx->rc_initial_buffer_occupancy / 1000;
         q->param.mfx.TargetKbps       = avctx->bit_rate / 1000;
f3fbe790
         q->param.mfx.MaxKbps          = avctx->rc_max_rate / 1000;
72b7441a
         break;
     case MFX_RATECONTROL_CQP:
         quant = avctx->global_quality / FF_QP2LAMBDA;
 
         q->param.mfx.QPI = av_clip(quant * fabs(avctx->i_quant_factor) + avctx->i_quant_offset, 0, 51);
         q->param.mfx.QPP = av_clip(quant, 0, 51);
         q->param.mfx.QPB = av_clip(quant * fabs(avctx->b_quant_factor) + avctx->b_quant_offset, 0, 51);
 
         break;
     case MFX_RATECONTROL_AVBR:
         q->param.mfx.TargetKbps  = avctx->bit_rate / 1000;
         q->param.mfx.Convergence = q->avbr_convergence;
         q->param.mfx.Accuracy    = q->avbr_accuracy;
         break;
e7d7cf86
 #if QSV_HAVE_LA
     case MFX_RATECONTROL_LA:
         q->param.mfx.TargetKbps  = avctx->bit_rate / 1000;
24563c20
         q->extco2.LookAheadDepth = q->look_ahead_depth;
e7d7cf86
         break;
 #if QSV_HAVE_ICQ
     case MFX_RATECONTROL_LA_ICQ:
24563c20
         q->extco2.LookAheadDepth = q->look_ahead_depth;
e7d7cf86
     case MFX_RATECONTROL_ICQ:
         q->param.mfx.ICQQuality  = avctx->global_quality;
         break;
 #endif
 #endif
72b7441a
     }
 
66acb76b
     // the HEVC encoder plugin currently fails if coding options
     // are provided
     if (avctx->codec_id != AV_CODEC_ID_HEVC) {
         q->extco.Header.BufferId      = MFX_EXTBUFF_CODING_OPTION;
         q->extco.Header.BufferSz      = sizeof(q->extco);
9cac1b4b
 #if FF_API_CODER_TYPE
 FF_DISABLE_DEPRECATION_WARNINGS
         if (avctx->coder_type != 0)
             q->cavlc = avctx->coder_type == FF_CODER_TYPE_VLC;
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
         q->extco.CAVLC = q->cavlc ? MFX_CODINGOPTION_ON
                                   : MFX_CODINGOPTION_UNKNOWN;
72b7441a
 
6eecb91f
         q->extco.PicTimingSEI         = q->pic_timing_sei ?
                                         MFX_CODINGOPTION_ON : MFX_CODINGOPTION_UNKNOWN;
 
fc4c27c4
         if (q->rdo >= 0)
             q->extco.RateDistortionOpt = q->rdo > 0 ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
 
         if (avctx->codec_id == AV_CODEC_ID_H264) {
             if (avctx->strict_std_compliance != FF_COMPLIANCE_NORMAL)
                 q->extco.NalHrdConformance = avctx->strict_std_compliance > FF_COMPLIANCE_NORMAL ?
                                              MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
 
             if (q->single_sei_nal_unit >= 0)
                 q->extco.SingleSeiNalUnit = q->single_sei_nal_unit ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
             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;
         }
 
dc923bc2
         q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco;
72b7441a
 
e7d7cf86
 #if QSV_HAVE_CO2
         if (avctx->codec_id == AV_CODEC_ID_H264) {
             q->extco2.Header.BufferId     = MFX_EXTBUFF_CODING_OPTION2;
             q->extco2.Header.BufferSz     = sizeof(q->extco2);
fc4c27c4
 
             if (q->int_ref_type >= 0)
                 q->extco2.IntRefType = q->int_ref_type;
             if (q->int_ref_cycle_size >= 0)
                 q->extco2.IntRefCycleSize = q->int_ref_cycle_size;
             if (q->int_ref_qp_delta != INT16_MIN)
                 q->extco2.IntRefQPDelta = q->int_ref_qp_delta;
 
             if (q->bitrate_limit >= 0)
                 q->extco2.BitrateLimit = q->bitrate_limit ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
             if (q->mbbrc >= 0)
                 q->extco2.MBBRC = q->mbbrc ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
             if (q->extbrc >= 0)
                 q->extco2.ExtBRC = q->extbrc ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
 
             if (q->max_frame_size >= 0)
                 q->extco2.MaxFrameSize = q->max_frame_size;
 #if QSV_HAVE_MAX_SLICE_SIZE
             if (q->max_slice_size >= 0)
                 q->extco2.MaxSliceSize = q->max_slice_size;
 #endif
 
 #if QSV_HAVE_TRELLIS
             q->extco2.Trellis = q->trellis;
 #endif
 
 #if QSV_HAVE_BREF_TYPE
0e6c8532
 #if FF_API_PRIVATE_OPT
 FF_DISABLE_DEPRECATION_WARNINGS
fc4c27c4
             if (avctx->b_frame_strategy >= 0)
0e6c8532
                 q->b_strategy = avctx->b_frame_strategy;
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
02bd02da
             if (q->b_strategy >= 0)
0e6c8532
                 q->extco2.BRefType = q->b_strategy ? MFX_B_REF_PYRAMID : MFX_B_REF_OFF;
fc4c27c4
             if (q->adaptive_i >= 0)
                 q->extco2.AdaptiveI = q->adaptive_i ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
             if (q->adaptive_b >= 0)
                 q->extco2.AdaptiveB = q->adaptive_b ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF;
 #endif
 
e7d7cf86
             q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco2;
67e87f80
 
 #if QSV_VERSION_ATLEAST(1,8)
24563c20
             q->extco2.LookAheadDS           = q->look_ahead_downsampling;
67e87f80
 #endif
e7d7cf86
         }
67e87f80
 #endif
66acb76b
     }
72b7441a
 
e7d7cf86
     if (!rc_supported(q)) {
         av_log(avctx, AV_LOG_ERROR,
                "Selected ratecontrol mode is not supported by the QSV "
                "runtime. Choose a different mode.\n");
         return AVERROR(ENOSYS);
66acb76b
     }
72b7441a
 
     return 0;
 }
 
 static int qsv_retrieve_enc_params(AVCodecContext *avctx, QSVEncContext *q)
 {
82590024
     AVCPBProperties *cpb_props;
 
72b7441a
     uint8_t sps_buf[128];
     uint8_t pps_buf[128];
 
     mfxExtCodingOptionSPSPPS extradata = {
         .Header.BufferId = MFX_EXTBUFF_CODING_OPTION_SPSPPS,
         .Header.BufferSz = sizeof(extradata),
         .SPSBuffer = sps_buf, .SPSBufSize = sizeof(sps_buf),
         .PPSBuffer = pps_buf, .PPSBufSize = sizeof(pps_buf)
     };
 
4d8f536b
     mfxExtCodingOption co = {
         .Header.BufferId = MFX_EXTBUFF_CODING_OPTION,
         .Header.BufferSz = sizeof(co),
     };
 #if QSV_HAVE_CO2
     mfxExtCodingOption2 co2 = {
         .Header.BufferId = MFX_EXTBUFF_CODING_OPTION2,
         .Header.BufferSz = sizeof(co2),
     };
 #endif
 #if QSV_HAVE_CO3
     mfxExtCodingOption3 co3 = {
         .Header.BufferId = MFX_EXTBUFF_CODING_OPTION3,
         .Header.BufferSz = sizeof(co3),
     };
 #endif
 
72b7441a
     mfxExtBuffer *ext_buffers[] = {
         (mfxExtBuffer*)&extradata,
4d8f536b
         (mfxExtBuffer*)&co,
 #if QSV_HAVE_CO2
         (mfxExtBuffer*)&co2,
 #endif
 #if QSV_HAVE_CO3
         (mfxExtBuffer*)&co3,
 #endif
72b7441a
     };
 
3a85397e
     int need_pps = avctx->codec_id != AV_CODEC_ID_MPEG2VIDEO;
72b7441a
     int ret;
 
     q->param.ExtParam    = ext_buffers;
     q->param.NumExtParam = FF_ARRAY_ELEMS(ext_buffers);
 
     ret = MFXVideoENCODE_GetVideoParam(q->session, &q->param);
     if (ret < 0)
         return ff_qsv_error(ret);
 
     q->packet_size = q->param.mfx.BufferSizeInKB * 1000;
 
3a85397e
     if (!extradata.SPSBufSize || (need_pps && !extradata.PPSBufSize)) {
72b7441a
         av_log(avctx, AV_LOG_ERROR, "No extradata returned from libmfx.\n");
         return AVERROR_UNKNOWN;
     }
 
3a85397e
     avctx->extradata = av_malloc(extradata.SPSBufSize + need_pps * extradata.PPSBufSize +
059a9348
                                  AV_INPUT_BUFFER_PADDING_SIZE);
72b7441a
     if (!avctx->extradata)
         return AVERROR(ENOMEM);
 
     memcpy(avctx->extradata,                        sps_buf, extradata.SPSBufSize);
3a85397e
     if (need_pps)
         memcpy(avctx->extradata + extradata.SPSBufSize, pps_buf, extradata.PPSBufSize);
     avctx->extradata_size = extradata.SPSBufSize + need_pps * extradata.PPSBufSize;
059a9348
     memset(avctx->extradata + avctx->extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
72b7441a
 
82590024
     cpb_props = ff_add_cpb_side_data(avctx);
     if (!cpb_props)
         return AVERROR(ENOMEM);
     cpb_props->max_bitrate = avctx->rc_max_rate;
     cpb_props->min_bitrate = avctx->rc_min_rate;
     cpb_props->avg_bitrate = avctx->bit_rate;
     cpb_props->buffer_size = avctx->rc_buffer_size;
 
4d8f536b
     dump_video_param(avctx, q, ext_buffers + 1);
 
72b7441a
     return 0;
 }
 
dc923bc2
 static int qsv_init_opaque_alloc(AVCodecContext *avctx, QSVEncContext *q)
 {
     AVQSVContext *qsv = avctx->hwaccel_context;
     mfxFrameSurface1 *surfaces;
     int nb_surfaces, i;
 
     nb_surfaces = qsv->nb_opaque_surfaces + q->req.NumFrameSuggested + q->async_depth;
 
     q->opaque_alloc_buf = av_buffer_allocz(sizeof(*surfaces) * nb_surfaces);
     if (!q->opaque_alloc_buf)
         return AVERROR(ENOMEM);
 
     q->opaque_surfaces = av_malloc_array(nb_surfaces, sizeof(*q->opaque_surfaces));
     if (!q->opaque_surfaces)
         return AVERROR(ENOMEM);
 
     surfaces = (mfxFrameSurface1*)q->opaque_alloc_buf->data;
     for (i = 0; i < nb_surfaces; i++) {
         surfaces[i].Info      = q->req.Info;
         q->opaque_surfaces[i] = surfaces + i;
     }
 
     q->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION;
     q->opaque_alloc.Header.BufferSz = sizeof(q->opaque_alloc);
     q->opaque_alloc.In.Surfaces     = q->opaque_surfaces;
     q->opaque_alloc.In.NumSurface   = nb_surfaces;
     q->opaque_alloc.In.Type         = q->req.Type;
 
     q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->opaque_alloc;
 
     qsv->nb_opaque_surfaces = nb_surfaces;
     qsv->opaque_surfaces    = q->opaque_alloc_buf;
     qsv->opaque_alloc_type  = q->req.Type;
 
     return 0;
 }
 
72b7441a
 int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
 {
dc923bc2
     int opaque_alloc = 0;
72b7441a
     int ret;
 
     q->param.IOPattern  = MFX_IOPATTERN_IN_SYSTEM_MEMORY;
     q->param.AsyncDepth = q->async_depth;
 
69b92f1b
     q->async_fifo = av_fifo_alloc((1 + q->async_depth) *
a1335149
                                   (sizeof(AVPacket) + sizeof(mfxSyncPoint*) + sizeof(mfxBitstream*)));
69b92f1b
     if (!q->async_fifo)
         return AVERROR(ENOMEM);
 
72b7441a
     if (avctx->hwaccel_context) {
         AVQSVContext *qsv = avctx->hwaccel_context;
 
         q->session         = qsv->session;
         q->param.IOPattern = qsv->iopattern;
dc923bc2
 
         opaque_alloc = qsv->opaque_alloc;
72b7441a
     }
 
     if (!q->session) {
ce91bab7
         ret = ff_qsv_init_internal_session(avctx, &q->internal_qs,
66acb76b
                                            q->load_plugins);
72b7441a
         if (ret < 0)
             return ret;
 
ce91bab7
         q->session = q->internal_qs.session;
72b7441a
     }
 
     ret = init_video_param(avctx, q);
     if (ret < 0)
         return ret;
 
5d4a3563
     ret = MFXVideoENCODE_Query(q->session, &q->param,&q->param);
     if (MFX_WRN_PARTIAL_ACCELERATION==ret) {
         av_log(avctx, AV_LOG_WARNING, "Encoder will work with partial HW acceleration\n");
     } else if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "Error %d querying encoder params\n", ret);
         return ff_qsv_error(ret);
     }
 
72b7441a
     ret = MFXVideoENCODE_QueryIOSurf(q->session, &q->param, &q->req);
     if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "Error querying the encoding parameters\n");
         return ff_qsv_error(ret);
     }
 
dc923bc2
     if (opaque_alloc) {
         ret = qsv_init_opaque_alloc(avctx, q);
         if (ret < 0)
             return ret;
     }
 
772c87c5
     if (avctx->hwaccel_context) {
         AVQSVContext *qsv = avctx->hwaccel_context;
         int i, j;
 
dc923bc2
         q->extparam = av_mallocz_array(qsv->nb_ext_buffers + q->nb_extparam_internal,
772c87c5
                                        sizeof(*q->extparam));
         if (!q->extparam)
             return AVERROR(ENOMEM);
 
         q->param.ExtParam = q->extparam;
         for (i = 0; i < qsv->nb_ext_buffers; i++)
             q->param.ExtParam[i] = qsv->ext_buffers[i];
         q->param.NumExtParam = qsv->nb_ext_buffers;
 
dc923bc2
         for (i = 0; i < q->nb_extparam_internal; i++) {
772c87c5
             for (j = 0; j < qsv->nb_ext_buffers; j++) {
                 if (qsv->ext_buffers[j]->BufferId == q->extparam_internal[i]->BufferId)
                     break;
             }
             if (j < qsv->nb_ext_buffers)
                 continue;
 
             q->param.ExtParam[q->param.NumExtParam++] = q->extparam_internal[i];
         }
     } else {
         q->param.ExtParam    = q->extparam_internal;
dc923bc2
         q->param.NumExtParam = q->nb_extparam_internal;
772c87c5
     }
 
72b7441a
     ret = MFXVideoENCODE_Init(q->session, &q->param);
115c14c3
     if (MFX_WRN_PARTIAL_ACCELERATION==ret) {
         av_log(avctx, AV_LOG_WARNING, "Encoder will work with partial HW acceleration\n");
     } else if (ret < 0) {
72b7441a
         av_log(avctx, AV_LOG_ERROR, "Error initializing the encoder\n");
         return ff_qsv_error(ret);
     }
 
     ret = qsv_retrieve_enc_params(avctx, q);
     if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "Error retrieving encoding parameters.\n");
         return ret;
     }
 
     q->avctx = avctx;
 
     return 0;
 }
 
0eac93da
 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++) {
63adb360
             av_free(enc_ctrl->Payload[i]);
0eac93da
         }
         enc_ctrl->NumPayload = 0;
     }
 }
 
72b7441a
 static void clear_unused_frames(QSVEncContext *q)
 {
     QSVFrame *cur = q->work_frames;
     while (cur) {
         if (cur->surface && !cur->surface->Data.Locked) {
             cur->surface = NULL;
0eac93da
             free_encoder_ctrl_payloads(&cur->enc_ctrl);
72b7441a
             av_frame_unref(cur->frame);
         }
         cur = cur->next;
     }
 }
 
 static int get_free_frame(QSVEncContext *q, QSVFrame **f)
 {
     QSVFrame *frame, **last;
 
     clear_unused_frames(q);
 
     frame = q->work_frames;
     last  = &q->work_frames;
     while (frame) {
         if (!frame->surface) {
             *f = frame;
             return 0;
         }
 
         last  = &frame->next;
         frame = frame->next;
     }
 
     frame = av_mallocz(sizeof(*frame));
     if (!frame)
         return AVERROR(ENOMEM);
     frame->frame = av_frame_alloc();
     if (!frame->frame) {
         av_freep(&frame);
         return AVERROR(ENOMEM);
     }
0eac93da
     frame->enc_ctrl.Payload = av_mallocz(sizeof(mfxPayload*) * QSV_MAX_ENC_PAYLOAD);
     if (!frame->enc_ctrl.Payload) {
         av_freep(&frame);
         return AVERROR(ENOMEM);
     }
72b7441a
     *last = frame;
 
     *f = frame;
 
     return 0;
 }
 
 static int submit_frame(QSVEncContext *q, const AVFrame *frame,
0eac93da
                         QSVFrame **new_frame)
72b7441a
 {
     QSVFrame *qf;
     int ret;
 
     ret = get_free_frame(q, &qf);
     if (ret < 0)
         return ret;
 
     if (frame->format == AV_PIX_FMT_QSV) {
         ret = av_frame_ref(qf->frame, frame);
         if (ret < 0)
             return ret;
 
         qf->surface = (mfxFrameSurface1*)qf->frame->data[3];
f6f32fc9
     } else {
2ec96b6b
         /* make a copy if the input is not padded as libmfx requires */
a440886a
         if (     frame->height & (q->height_align - 1) ||
             frame->linesize[0] & (q->width_align - 1)) {
             qf->frame->height = FFALIGN(frame->height, q->height_align);
2ec96b6b
             qf->frame->width  = FFALIGN(frame->width, q->width_align);
 
             ret = ff_get_buffer(q->avctx, qf->frame, AV_GET_BUFFER_FLAG_REF);
             if (ret < 0)
                 return ret;
 
             qf->frame->height = frame->height;
             qf->frame->width  = frame->width;
             ret = av_frame_copy(qf->frame, frame);
             if (ret < 0) {
                 av_frame_unref(qf->frame);
                 return ret;
             }
         } else {
             ret = av_frame_ref(qf->frame, frame);
             if (ret < 0)
                 return ret;
72b7441a
         }
 
2ec96b6b
         qf->surface_internal.Info = q->param.mfx.FrameInfo;
72b7441a
 
2ec96b6b
         qf->surface_internal.Info.PicStruct =
             !frame->interlaced_frame ? MFX_PICSTRUCT_PROGRESSIVE :
             frame->top_field_first   ? MFX_PICSTRUCT_FIELD_TFF :
                                        MFX_PICSTRUCT_FIELD_BFF;
         if (frame->repeat_pict == 1)
             qf->surface_internal.Info.PicStruct |= MFX_PICSTRUCT_FIELD_REPEATED;
         else if (frame->repeat_pict == 2)
             qf->surface_internal.Info.PicStruct |= MFX_PICSTRUCT_FRAME_DOUBLING;
         else if (frame->repeat_pict == 4)
             qf->surface_internal.Info.PicStruct |= MFX_PICSTRUCT_FRAME_TRIPLING;
72b7441a
 
2ec96b6b
         qf->surface_internal.Data.PitchLow  = qf->frame->linesize[0];
         qf->surface_internal.Data.Y         = qf->frame->data[0];
         qf->surface_internal.Data.UV        = qf->frame->data[1];
72b7441a
 
2ec96b6b
         qf->surface = &qf->surface_internal;
f6f32fc9
     }
 
     qf->surface->Data.TimeStamp = av_rescale_q(frame->pts, q->avctx->time_base, (AVRational){1, 90000});
72b7441a
 
0eac93da
     *new_frame = qf;
72b7441a
 
     return 0;
 }
 
 static void print_interlace_msg(AVCodecContext *avctx, QSVEncContext *q)
 {
     if (q->param.mfx.CodecId == MFX_CODEC_AVC) {
         if (q->param.mfx.CodecProfile == MFX_PROFILE_AVC_BASELINE ||
             q->param.mfx.CodecLevel < MFX_LEVEL_AVC_21 ||
             q->param.mfx.CodecLevel > MFX_LEVEL_AVC_41)
             av_log(avctx, AV_LOG_WARNING,
                    "Interlaced coding is supported"
                    " at Main/High Profile Level 2.1-4.1\n");
     }
 }
 
d1cd20e4
 static int encode_frame(AVCodecContext *avctx, QSVEncContext *q,
                         const AVFrame *frame)
72b7441a
 {
69b92f1b
     AVPacket new_pkt = { 0 };
     mfxBitstream *bs;
72b7441a
 
     mfxFrameSurface1 *surf = NULL;
acc155ac
     mfxSyncPoint *sync      = NULL;
0eac93da
     QSVFrame *qsv_frame = NULL;
     mfxEncodeCtrl* enc_ctrl = NULL;
72b7441a
     int ret;
 
     if (frame) {
0eac93da
         ret = submit_frame(q, frame, &qsv_frame);
72b7441a
         if (ret < 0) {
             av_log(avctx, AV_LOG_ERROR, "Error submitting the frame for encoding.\n");
             return ret;
         }
     }
0eac93da
     if (qsv_frame) {
         surf = qsv_frame->surface;
         enc_ctrl = &qsv_frame->enc_ctrl;
     }
72b7441a
 
69b92f1b
     ret = av_new_packet(&new_pkt, q->packet_size);
72b7441a
     if (ret < 0) {
         av_log(avctx, AV_LOG_ERROR, "Error allocating the output packet\n");
         return ret;
     }
69b92f1b
 
     bs = av_mallocz(sizeof(*bs));
     if (!bs) {
         av_packet_unref(&new_pkt);
         return AVERROR(ENOMEM);
     }
     bs->Data      = new_pkt.data;
     bs->MaxLength = new_pkt.size;
72b7441a
 
0eac93da
     if (q->set_encode_ctrl_cb) {
         q->set_encode_ctrl_cb(avctx, frame, &qsv_frame->enc_ctrl);
     }
 
a1335149
     sync = av_mallocz(sizeof(*sync));
     if (!sync) {
         av_freep(&bs);
         av_packet_unref(&new_pkt);
         return AVERROR(ENOMEM);
     }
 
72b7441a
     do {
acc155ac
         ret = MFXVideoENCODE_EncodeFrameAsync(q->session, enc_ctrl, surf, bs, sync);
b409748b
         if (ret == MFX_WRN_DEVICE_BUSY) {
947c2aa4
             av_usleep(500);
b409748b
             continue;
         }
         break;
     } while ( 1 );
72b7441a
 
5985316f
     if (ret < 0) {
69b92f1b
         av_packet_unref(&new_pkt);
         av_freep(&bs);
5985316f
         if (ret == MFX_ERR_MORE_DATA)
             return 0;
         av_log(avctx, AV_LOG_ERROR, "EncodeFrameAsync returned %d\n", ret);
         return ff_qsv_error(ret);
     }
72b7441a
 
5985316f
     if (ret == MFX_WRN_INCOMPATIBLE_VIDEO_PARAM) {
         if (frame->interlaced_frame)
             print_interlace_msg(avctx, q);
         else
             av_log(avctx, AV_LOG_WARNING,
                    "EncodeFrameAsync returned 'incompatible param' code\n");
     }
72b7441a
     if (sync) {
69b92f1b
         av_fifo_generic_write(q->async_fifo, &new_pkt, sizeof(new_pkt), NULL);
         av_fifo_generic_write(q->async_fifo, &sync,    sizeof(sync),    NULL);
         av_fifo_generic_write(q->async_fifo, &bs,      sizeof(bs),    NULL);
     } else {
a1335149
         av_freep(&sync);
69b92f1b
         av_packet_unref(&new_pkt);
         av_freep(&bs);
     }
 
d1cd20e4
     return 0;
 }
 
 int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q,
                   AVPacket *pkt, const AVFrame *frame, int *got_packet)
 {
     int ret;
 
     ret = encode_frame(avctx, q, frame);
     if (ret < 0)
         return ret;
 
69b92f1b
     if (!av_fifo_space(q->async_fifo) ||
         (!frame && av_fifo_size(q->async_fifo))) {
d1cd20e4
         AVPacket new_pkt;
         mfxBitstream *bs;
a1335149
         mfxSyncPoint *sync;
d1cd20e4
 
69b92f1b
         av_fifo_generic_read(q->async_fifo, &new_pkt, sizeof(new_pkt), NULL);
         av_fifo_generic_read(q->async_fifo, &sync,    sizeof(sync),    NULL);
         av_fifo_generic_read(q->async_fifo, &bs,      sizeof(bs),      NULL);
 
a6259a6e
         do {
a1335149
             ret = MFXVideoCORE_SyncOperation(q->session, *sync, 1000);
a6259a6e
         } while (ret == MFX_WRN_IN_EXECUTION);
72b7441a
 
69b92f1b
         new_pkt.dts  = av_rescale_q(bs->DecodeTimeStamp, (AVRational){1, 90000}, avctx->time_base);
         new_pkt.pts  = av_rescale_q(bs->TimeStamp,       (AVRational){1, 90000}, avctx->time_base);
         new_pkt.size = bs->DataLength;
 
         if (bs->FrameType & MFX_FRAMETYPE_IDR ||
             bs->FrameType & MFX_FRAMETYPE_xIDR)
             new_pkt.flags |= AV_PKT_FLAG_KEY;
 
40cf1bba
 #if FF_API_CODED_FRAME
 FF_DISABLE_DEPRECATION_WARNINGS
69b92f1b
         if (bs->FrameType & MFX_FRAMETYPE_I || bs->FrameType & MFX_FRAMETYPE_xI)
72b7441a
             avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
69b92f1b
         else if (bs->FrameType & MFX_FRAMETYPE_P || bs->FrameType & MFX_FRAMETYPE_xP)
72b7441a
             avctx->coded_frame->pict_type = AV_PICTURE_TYPE_P;
69b92f1b
         else if (bs->FrameType & MFX_FRAMETYPE_B || bs->FrameType & MFX_FRAMETYPE_xB)
72b7441a
             avctx->coded_frame->pict_type = AV_PICTURE_TYPE_B;
40cf1bba
 FF_ENABLE_DEPRECATION_WARNINGS
 #endif
72b7441a
 
69b92f1b
         av_freep(&bs);
a1335149
         av_freep(&sync);
69b92f1b
 
         if (pkt->data) {
             if (pkt->size < new_pkt.size) {
                 av_log(avctx, AV_LOG_ERROR, "Submitted buffer not large enough: %d < %d\n",
                        pkt->size, new_pkt.size);
                 av_packet_unref(&new_pkt);
                 return AVERROR(EINVAL);
             }
72b7441a
 
69b92f1b
             memcpy(pkt->data, new_pkt.data, new_pkt.size);
             pkt->size = new_pkt.size;
72b7441a
 
69b92f1b
             ret = av_packet_copy_props(pkt, &new_pkt);
             av_packet_unref(&new_pkt);
             if (ret < 0)
                 return ret;
         } else
             *pkt = new_pkt;
72b7441a
 
         *got_packet = 1;
     }
 
     return 0;
 }
 
 int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q)
 {
     QSVFrame *cur;
 
83847cc8
     if (q->session)
         MFXVideoENCODE_Close(q->session);
ce91bab7
     q->session = NULL;
 
     ff_qsv_close_internal_session(&q->internal_qs);
72b7441a
 
     cur = q->work_frames;
     while (cur) {
         q->work_frames = cur->next;
         av_frame_free(&cur->frame);
0eac93da
         av_free(cur->enc_ctrl.Payload);
72b7441a
         av_freep(&cur);
         cur = q->work_frames;
     }
 
69b92f1b
     while (q->async_fifo && av_fifo_size(q->async_fifo)) {
         AVPacket pkt;
a1335149
         mfxSyncPoint *sync;
69b92f1b
         mfxBitstream *bs;
 
         av_fifo_generic_read(q->async_fifo, &pkt,  sizeof(pkt),  NULL);
         av_fifo_generic_read(q->async_fifo, &sync, sizeof(sync), NULL);
         av_fifo_generic_read(q->async_fifo, &bs,   sizeof(bs),   NULL);
 
a1335149
         av_freep(&sync);
69b92f1b
         av_freep(&bs);
         av_packet_unref(&pkt);
     }
     av_fifo_free(q->async_fifo);
     q->async_fifo = NULL;
 
dc923bc2
     av_freep(&q->opaque_surfaces);
     av_buffer_unref(&q->opaque_alloc_buf);
 
772c87c5
     av_freep(&q->extparam);
 
72b7441a
     return 0;
 }