[FFmpeg-devel] Fixed problems with QuickSync (QSV) interlaced video encoding

Submitted by Aaron Levinson on April 14, 2017, 6:36 a.m.

Details

Message ID 332b9d84-a63a-e0b5-f911-74fcca201103@aracnet.com
State New
Headers show

Commit Message

Aaron Levinson April 14, 2017, 6:36 a.m.
From da3899b24ad89b4788a3b8191d53b26f5eec328e Mon Sep 17 00:00:00 2001
From: Aaron Levinson <alevinsn@aracnet.com>
Date: Thu, 13 Apr 2017 23:12:30 -0700
Subject: [PATCH] Fixed problems with QuickSync (QSV) interlaced video
 encoding

Purpose: Fixed problems with QuickSync (QSV) interlaced video encoding
that were introduced in revision 1f26a23 on Oct. 31, 2016 (qsv: Merge
libav implementation, at
https://github.com/FFmpeg/FFmpeg/commit/1f26a231bb065276cd80ce02957c759f3197edfa#diff-7d84a34d58597bb7aa4b8239dca1f9f8).
As a result of the qsv libav merge, when attempting to encode
interlaced video, it doesn't work and instead results in a bunch of
incompatible video parameter errors.

Comments:

-- qsvenc.c / .h:
a) Added code back in to set PicStruct appropriately based on whether
   or not interlaced or progressive video is being encoded.  Also
   reintroduced the related code to set the height alignment.  The
   height alignment code was also enhanced slightly (compared to the
   version in 3.2.4) to properly handle progressive video when the
   HEVC encoder is used.  The elimination of this code is the main
   reason why interlaced video encoding stopped working.
b) Reintroduced code to call MFXVideoENCODE_Query() after calling
   init_video_param().  This isn't strictly required to fix the
   interlaced video encoding issue, but it represents a generally good
   practice to make sure that one is working with the right parameter
   values.
---
 libavcodec/qsvenc.c | 33 +++++++++++++++++++++++++++++----
 libavcodec/qsvenc.h |  1 +
 2 files changed, 30 insertions(+), 4 deletions(-)

Comments

Aaron Levinson May 7, 2017, 5:37 p.m.
Please disregard this patch--I'm submitting two new patches that have 
already been reviewed and applied to libav.

Aaron Levinson

On 4/13/2017 11:36 PM, Aaron Levinson wrote:
> From da3899b24ad89b4788a3b8191d53b26f5eec328e Mon Sep 17 00:00:00 2001
> From: Aaron Levinson <alevinsn@aracnet.com>
> Date: Thu, 13 Apr 2017 23:12:30 -0700
> Subject: [PATCH] Fixed problems with QuickSync (QSV) interlaced video
>  encoding
>
> Purpose: Fixed problems with QuickSync (QSV) interlaced video encoding
> that were introduced in revision 1f26a23 on Oct. 31, 2016 (qsv: Merge
> libav implementation, at
> https://github.com/FFmpeg/FFmpeg/commit/1f26a231bb065276cd80ce02957c759f3197edfa#diff-7d84a34d58597bb7aa4b8239dca1f9f8).
> As a result of the qsv libav merge, when attempting to encode
> interlaced video, it doesn't work and instead results in a bunch of
> incompatible video parameter errors.
>
> Comments:
>
> -- qsvenc.c / .h:
> a) Added code back in to set PicStruct appropriately based on whether
>    or not interlaced or progressive video is being encoded.  Also
>    reintroduced the related code to set the height alignment.  The
>    height alignment code was also enhanced slightly (compared to the
>    version in 3.2.4) to properly handle progressive video when the
>    HEVC encoder is used.  The elimination of this code is the main
>    reason why interlaced video encoding stopped working.
> b) Reintroduced code to call MFXVideoENCODE_Query() after calling
>    init_video_param().  This isn't strictly required to fix the
>    interlaced video encoding issue, but it represents a generally good
>    practice to make sure that one is working with the right parameter
>    values.
> ---
>  libavcodec/qsvenc.c | 33 +++++++++++++++++++++++++++++----
>  libavcodec/qsvenc.h |  1 +
>  2 files changed, 30 insertions(+), 4 deletions(-)
>
> diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
> index 9c385a7..24ac390 100644
> --- a/libavcodec/qsvenc.c
> +++ b/libavcodec/qsvenc.c
> @@ -358,6 +358,9 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q)
>          return AVERROR_BUG;
>      q->param.mfx.CodecId = ret;
>
> +    // TODO:  detect version of MFX--if the minor version is greater than
> +    // or equal to 19, then can use the same alignment settings as H.264
> +    // for HEVC
>      q->width_align = avctx->codec_id == AV_CODEC_ID_HEVC ? 32 : 16;
>
>      if (avctx->level > 0)
> @@ -381,20 +384,34 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q)
>
>      ff_qsv_map_pixfmt(sw_format, &q->param.mfx.FrameInfo.FourCC);
>
> -    q->param.mfx.FrameInfo.Width          = FFALIGN(avctx->width, q->width_align);
> -    q->param.mfx.FrameInfo.Height         = FFALIGN(avctx->height, 32);
>      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.PicStruct      = MFX_PICSTRUCT_PROGRESSIVE;
>      q->param.mfx.FrameInfo.ChromaFormat   = MFX_CHROMAFORMAT_YUV420;
>      q->param.mfx.FrameInfo.BitDepthLuma   = desc->comp[0].depth;
>      q->param.mfx.FrameInfo.BitDepthChroma = desc->comp[0].depth;
>      q->param.mfx.FrameInfo.Shift          = desc->comp[0].depth > 8;
>
> +    q->param.mfx.FrameInfo.Width          = FFALIGN(avctx->width, q->width_align);
> +    if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) {
> +        // it is important that PicStruct be setup correctly from the
> +        // start--otherwise, encoding doesn't work and results in a bunch
> +        // of incompatible video parameter errors
> +        q->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_FIELD_TFF;
> +        // height alignment always must be 32 for interlaced video
> +        q->height_align = 32;
> +    } else {
> +        q->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
> +        // for progressive video, the height should be aligned to 16 for
> +        // H.264.  For HEVC, depending on the version of MFX, it should be
> +        // either 32 or 16.  The lower number is better if possible.
> +        q->height_align = avctx->codec_id == AV_CODEC_ID_HEVC ? 32 : 16;
> +    }
> +    q->param.mfx.FrameInfo.Height = FFALIGN(avctx->height, q->height_align);
> +
>      if (avctx->hw_frames_ctx) {
>          AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
>          AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
> @@ -740,10 +757,18 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
>      if (ret < 0)
>          return ret;
>
> +    ret = MFXVideoENCODE_Query(q->session, &q->param, &q->param);
> +    if (ret == MFX_WRN_PARTIAL_ACCELERATION) {
> +        av_log(avctx, AV_LOG_WARNING, "Encoder will work with partial HW acceleration\n");
> +    } else if (ret < 0) {
> +        return ff_qsv_print_error(avctx, ret,
> +                                  "Error querying encoder params");
> +    }
> +
>      ret = MFXVideoENCODE_QueryIOSurf(q->session, &q->param, &q->req);
>      if (ret < 0)
>          return ff_qsv_print_error(avctx, ret,
> -                                  "Error querying the encoding parameters");
> +                                  "Error querying (IOSurf) the encoding parameters");
>
>      if (opaque_alloc) {
>          ret = qsv_init_opaque_alloc(avctx, q);
> diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
> index 361d933..12e3444 100644
> --- a/libavcodec/qsvenc.h
> +++ b/libavcodec/qsvenc.h
> @@ -84,6 +84,7 @@ typedef struct QSVEncContext {
>
>      int packet_size;
>      int width_align;
> +    int height_align;
>
>      mfxVideoParam param;
>      mfxFrameAllocRequest req;
>

Patch hide | download patch | download mbox

diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 9c385a7..24ac390 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -358,6 +358,9 @@  static int init_video_param(AVCodecContext *avctx, QSVEncContext *q)
         return AVERROR_BUG;
     q->param.mfx.CodecId = ret;
 
+    // TODO:  detect version of MFX--if the minor version is greater than
+    // or equal to 19, then can use the same alignment settings as H.264
+    // for HEVC
     q->width_align = avctx->codec_id == AV_CODEC_ID_HEVC ? 32 : 16;
 
     if (avctx->level > 0)
@@ -381,20 +384,34 @@  static int init_video_param(AVCodecContext *avctx, QSVEncContext *q)
 
     ff_qsv_map_pixfmt(sw_format, &q->param.mfx.FrameInfo.FourCC);
 
-    q->param.mfx.FrameInfo.Width          = FFALIGN(avctx->width, q->width_align);
-    q->param.mfx.FrameInfo.Height         = FFALIGN(avctx->height, 32);
     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.PicStruct      = MFX_PICSTRUCT_PROGRESSIVE;
     q->param.mfx.FrameInfo.ChromaFormat   = MFX_CHROMAFORMAT_YUV420;
     q->param.mfx.FrameInfo.BitDepthLuma   = desc->comp[0].depth;
     q->param.mfx.FrameInfo.BitDepthChroma = desc->comp[0].depth;
     q->param.mfx.FrameInfo.Shift          = desc->comp[0].depth > 8;
 
+    q->param.mfx.FrameInfo.Width          = FFALIGN(avctx->width, q->width_align);
+    if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT) {
+        // it is important that PicStruct be setup correctly from the
+        // start--otherwise, encoding doesn't work and results in a bunch
+        // of incompatible video parameter errors
+        q->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_FIELD_TFF;
+        // height alignment always must be 32 for interlaced video
+        q->height_align = 32;
+    } else {
+        q->param.mfx.FrameInfo.PicStruct = MFX_PICSTRUCT_PROGRESSIVE;
+        // for progressive video, the height should be aligned to 16 for
+        // H.264.  For HEVC, depending on the version of MFX, it should be
+        // either 32 or 16.  The lower number is better if possible.
+        q->height_align = avctx->codec_id == AV_CODEC_ID_HEVC ? 32 : 16;
+    }
+    q->param.mfx.FrameInfo.Height = FFALIGN(avctx->height, q->height_align);
+
     if (avctx->hw_frames_ctx) {
         AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data;
         AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx;
@@ -740,10 +757,18 @@  int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
     if (ret < 0)
         return ret;
 
+    ret = MFXVideoENCODE_Query(q->session, &q->param, &q->param);
+    if (ret == MFX_WRN_PARTIAL_ACCELERATION) {
+        av_log(avctx, AV_LOG_WARNING, "Encoder will work with partial HW acceleration\n");
+    } else if (ret < 0) {
+        return ff_qsv_print_error(avctx, ret,
+                                  "Error querying encoder params");
+    }
+
     ret = MFXVideoENCODE_QueryIOSurf(q->session, &q->param, &q->req);
     if (ret < 0)
         return ff_qsv_print_error(avctx, ret,
-                                  "Error querying the encoding parameters");
+                                  "Error querying (IOSurf) the encoding parameters");
 
     if (opaque_alloc) {
         ret = qsv_init_opaque_alloc(avctx, q);
diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
index 361d933..12e3444 100644
--- a/libavcodec/qsvenc.h
+++ b/libavcodec/qsvenc.h
@@ -84,6 +84,7 @@  typedef struct QSVEncContext {
 
     int packet_size;
     int width_align;
+    int height_align;
 
     mfxVideoParam param;
     mfxFrameAllocRequest req;