diff mbox series

[FFmpeg-devel,04/10] libavcodec/qsvdec.c: extract frame packing arrangement data

Message ID 20210126023213.146185-4-wenbin.chen@intel.com
State New
Headers show
Series [FFmpeg-devel,01/10] libavcodec/qsvenc.c: add max_frame_size support for hevc_qsv | expand

Checks

Context Check Description
andriy/x86_make success Make finished
andriy/x86_make_fate success Make fate finished
andriy/PPC64_make success Make finished
andriy/PPC64_make_fate success Make fate finished

Commit Message

Wenbin Chen Jan. 26, 2021, 2:32 a.m. UTC
From: Wenbinc-Bin <wenbin.chen@intel.com>

Use h264_sei to parse SEI data got from MediaSDK. Extract frame
packing arrangement information from SEI data and config AVStereo3D
side data for decoded frame.

Sigend-off-by: Wenbin Chen <wenbin.chen@intel.com>
---
 libavcodec/qsv_internal.h |   2 +
 libavcodec/qsvdec.c       | 149 ++++++++++++++++++++++++++++++++++++++
 libavcodec/qsvdec.h       |   6 ++
 3 files changed, 157 insertions(+)
diff mbox series

Patch

diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h
index 6b2fbbe252..aa3da97c99 100644
--- a/libavcodec/qsv_internal.h
+++ b/libavcodec/qsv_internal.h
@@ -52,6 +52,8 @@ 
 
 #define QSV_MAX_ENC_PAYLOAD 2       // # of mfxEncodeCtrl payloads supported
 
+#define QSV_PAYLOAD_SIZE 1024
+
 #define QSV_VERSION_ATLEAST(MAJOR, MINOR)   \
     (MFX_VERSION_MAJOR > (MAJOR) ||         \
      MFX_VERSION_MAJOR == (MAJOR) && MFX_VERSION_MINOR >= (MINOR))
diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c
index d10f90a0db..5cb49cfb4a 100644
--- a/libavcodec/qsvdec.c
+++ b/libavcodec/qsvdec.c
@@ -36,10 +36,12 @@ 
 #include "libavutil/pixfmt.h"
 #include "libavutil/time.h"
 #include "libavutil/imgutils.h"
+#include "libavutil/stereo3d.h"
 
 #include "avcodec.h"
 #include "internal.h"
 #include "decode.h"
+#include "get_bits.h"
 #include "qsv.h"
 #include "qsv_internal.h"
 #include "qsvdec.h"
@@ -398,6 +400,147 @@  static QSVFrame *find_frame(QSVContext *q, mfxFrameSurface1 *surf)
     return NULL;
 }
 
+static int h264_decode_fpa(H264SEIFramePacking *fpa, AVFrame *frame)
+{
+    if (!fpa || !frame) {
+        return AVERROR(EINVAL);
+    }
+
+    if (!fpa->arrangement_cancel_flag &&
+        fpa->arrangement_type <= 6 &&
+        fpa->content_interpretation_type > 0 &&
+        fpa->content_interpretation_type < 3) {
+        AVStereo3D *stereo = av_stereo3d_create_side_data(frame);
+        if (stereo) {
+            switch (fpa->arrangement_type) {
+            case 0:
+                stereo->type = AV_STEREO3D_CHECKERBOARD;
+                break;
+            case 1:
+                stereo->type = AV_STEREO3D_COLUMNS;
+                break;
+            case 2:
+                stereo->type = AV_STEREO3D_LINES;
+                break;
+            case 3:
+                if (fpa->quincunx_sampling_flag)
+                    stereo->type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX;
+                else
+                    stereo->type = AV_STEREO3D_SIDEBYSIDE;
+                break;
+            case 4:
+                stereo->type = AV_STEREO3D_TOPBOTTOM;
+                break;
+            case 5:
+                stereo->type = AV_STEREO3D_FRAMESEQUENCE;
+                if (fpa->current_frame_is_frame0_flag)
+                    stereo->view = AV_STEREO3D_VIEW_LEFT;
+                else
+                    stereo->view = AV_STEREO3D_VIEW_RIGHT;
+                break;
+            case 6:
+                stereo->type = AV_STEREO3D_2D;
+                break;
+            }
+
+            if (fpa->content_interpretation_type == 2)
+                stereo->flags = AV_STEREO3D_FLAG_INVERT;
+        }
+    }
+    return 0;
+}
+
+static int h264_parse_side_data(AVCodecContext *avctx, QSVContext *q, AVFrame *frame)
+{
+    GetBitContext gb_payload;
+    uint8_t *sei_buffer;
+    int sei_buffer_index;
+    int ret;
+
+    /* remove emulation prevention bytes */
+    sei_buffer = (uint8_t *)av_mallocz(q->payload.NumBit / 8);
+    if (!sei_buffer) {
+        av_freep(&sei_buffer);
+        return AVERROR(ENOMEM);
+    }
+    sei_buffer_index = 0;
+    for (int i = 0; i < q->payload.NumBit / 8; i++) {
+        if (q->payload.Data[i] == 3)
+            i++;
+        sei_buffer[sei_buffer_index] = q->payload.Data[i];
+        sei_buffer_index += 1;
+    }
+
+    ret = init_get_bits8(&gb_payload, sei_buffer, sei_buffer_index+1);
+    if (ret < 0) {
+        av_freep(&sei_buffer);
+        return ret;
+    }
+
+    ret = ff_h264_sei_decode(&q->sei, &gb_payload, &q->ps, avctx);
+    if (ret < 0) {
+        av_freep(&sei_buffer);
+        return ret;
+    }
+
+    switch (q->payload.Type) {
+    case SEI_TYPE_FRAME_PACKING_ARRANGEMENT:
+        ret = h264_decode_fpa(&q->sei.frame_packing, frame);
+        break;
+    default:
+        break;
+    }
+
+    av_freep(&sei_buffer);
+    return ret;
+}
+
+static int extract_frame_side_data(AVCodecContext *avctx, QSVContext *q, AVFrame *frame)
+{
+    mfxU64 ts;
+    mfxStatus sts;
+    int ret;
+
+    if (q->payload.BufSize == 0) {
+        q->payload.Data = av_mallocz(QSV_PAYLOAD_SIZE);
+        if (!q->payload.Data) {
+            av_freep(&q->payload.Data);
+            return AVERROR(ENOMEM);
+        }
+        q->payload.BufSize = QSV_PAYLOAD_SIZE;
+    }
+
+    sts = MFX_ERR_NONE;
+    while (sts == MFX_ERR_NONE) {
+
+        sts = MFXVideoDECODE_GetPayload(q->session, &ts, &q->payload);
+
+        if (sts == MFX_ERR_NOT_ENOUGH_BUFFER) {
+            av_log(avctx, AV_LOG_WARNING, "Space for SEI is not enough. One SEI will be skipped\n");
+            continue;
+        } else if (sts != MFX_ERR_NONE || q->payload.NumBit == 0) {
+            break;
+        }
+
+        if (q->payload.Type != SEI_TYPE_FRAME_PACKING_ARRANGEMENT)
+            continue;
+
+        switch (avctx->codec_id) {
+        case AV_CODEC_ID_H264:
+            ret = h264_parse_side_data(avctx, q, frame);
+            break;
+        default:
+            break;
+        }
+
+        if (ret < 0) {
+            av_log(avctx, AV_LOG_WARNING, "parse side data failed\n");
+            break;
+        }
+    }
+    return ret;
+}
+
 static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
                       AVFrame *frame, int *got_frame,
                       AVPacket *avpkt)
@@ -501,6 +644,10 @@  static int qsv_decode(AVCodecContext *avctx, QSVContext *q,
 
         outsurf = &out_frame->surface;
 
+        ret = extract_frame_side_data(avctx, q, frame);
+        if (ret < 0)
+            av_log(avctx, AV_LOG_WARNING, "Extracting side from packet failed\n");
+
 #if FF_API_PKT_PTS
 FF_DISABLE_DEPRECATION_WARNINGS
         frame->pkt_pts = outsurf->Data.TimeStamp;
@@ -564,6 +711,8 @@  int ff_qsv_decode_close(QSVContext *q)
     av_buffer_unref(&q->frames_ctx.mids_buf);
     av_buffer_pool_uninit(&q->pool);
 
+    av_freep(&q->payload.Data);
+
     return 0;
 }
 
diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h
index f3b7344cba..282943b00c 100644
--- a/libavcodec/qsvdec.h
+++ b/libavcodec/qsvdec.h
@@ -34,6 +34,7 @@ 
 
 #include "avcodec.h"
 #include "hwconfig.h"
+#include "h264_sei.h"
 #include "qsv_internal.h"
 
 typedef struct QSVContext {
@@ -70,8 +71,13 @@  typedef struct QSVContext {
 
     char *load_plugins;
 
+    mfxPayload payload;
+
     mfxExtBuffer **ext_buffers;
     int         nb_ext_buffers;
+
+    H264SEIContext sei;
+    H264ParamSets ps;
 } QSVContext;
 
 extern const AVCodecHWConfigInternal *const ff_qsv_hw_configs[];