[FFmpeg-devel] [PATCH 2/2] lavc/qsvenc_{h264, hevc}: import user data unregistered SEIs if available

Xiang, Haihao haihao.xiang at intel.com
Wed Feb 8 08:26:19 EET 2023


From: Haihao Xiang <haihao.xiang at intel.com>

option udu_sei is added, user should set udu_sei to true|on|1 if user
data unregistered SEI is expected.

Verify user data unregistered SEI with commands below:
$ ffmpeg -y -f lavfi -i testsrc -vf "format=nv12" -c:v libx264 -frames:v 1
a.h264
$ ffmpeg -y -init_hw_device qsv -i a.h264 -c:v hevc_qsv -udu_sei 1 b.h265
$ ffmpeg -y -init_hw_device qsv -i a.h264 -c:v hevc_qsv -udu_sei 0 c.h265

$ ffmpeg -i b.h265 -vf showinfo -f null -
$ ffmpeg -i c.h265 -vf showinfo -f null -

Signed-off-by: Haihao Xiang <haihao.xiang at intel.com>
---
 doc/encoders.texi        |  6 +++++
 libavcodec/qsvenc.c      | 47 ++++++++++++++++++++++++++++++++++++++++
 libavcodec/qsvenc.h      |  1 +
 libavcodec/qsvenc_h264.c |  1 +
 libavcodec/qsvenc_hevc.c |  1 +
 5 files changed, 56 insertions(+)

diff --git a/doc/encoders.texi b/doc/encoders.texi
index 727f12a59d..a9972d8b9c 100644
--- a/doc/encoders.texi
+++ b/doc/encoders.texi
@@ -3582,6 +3582,9 @@ skip_frame metadata indicates the number of missed frames before the current
 frame.
 @end table
 
+ at item udu_sei @var{boolean}
+Import user data unregistered SEI if available into output. Default is 0 (off).
+
 @end table
 
 @subsection HEVC Options
@@ -3787,6 +3790,9 @@ skip_frame metadata indicates the number of missed frames before the current
 frame.
 @end table
 
+ at item udu_sei @var{boolean}
+Import user data unregistered SEI if available into output. Default is 0 (off).
+
 @end table
 
 @subsection MPEG2 Options
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 2f0e94a914..c0c40e706f 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -2046,6 +2046,49 @@ static void set_skip_frame_encode_ctrl(AVCodecContext *avctx, const AVFrame *fra
     return;
 }
 
+static int set_udu_encode_ctrl(AVCodecContext *avctx,  QSVEncContext *q,
+                               const AVFrame *frame, mfxEncodeCtrl *enc_ctrl)
+{
+    if (!frame || !q->udu_sei)
+        return 0;
+
+    for (int i = 0; i < frame->nb_side_data && enc_ctrl->NumPayload < QSV_MAX_ENC_PAYLOAD; i++) {
+        AVFrameSideData *sd = NULL;
+        mfxPayload *payload = NULL;
+        mfxU8* sei_data;
+        int j;
+
+        sd = frame->side_data[i];
+        if (sd->type != AV_FRAME_DATA_SEI_UNREGISTERED)
+            continue;
+
+        /* SEI type: 1 byte, SEI size: sd->size / 255 + 1 bytes, SEI data: sd->size bytes */
+        payload = av_malloc(sizeof(*payload) + sd->size / 255 + 2 + sd->size);
+        if (!payload)
+            return AVERROR(ENOMEM);
+
+        memset(payload, 0, sizeof(*payload));
+        sei_data = (mfxU8 *)(payload + 1);
+        // SEI header
+        sei_data[0] = 5;
+        for (j = 0; j < sd->size / 255; j++)
+            sei_data[j + 1] = 0xff;
+        sei_data[j + 1] = sd->size % 255;
+        // SEI data
+        memcpy(&sei_data[sd->size / 255 + 2], sd->data, sd->size);
+
+        payload->BufSize = sd->size + sd->size / 255 + 2;
+        payload->NumBit = payload->BufSize * 8;
+        payload->Type = 5;
+        payload->Data = sei_data;
+
+        enc_ctrl->Payload[enc_ctrl->NumPayload] = payload;
+        enc_ctrl->NumPayload++;
+    }
+
+    return 0;
+}
+
 static int update_qp(AVCodecContext *avctx, QSVEncContext *q)
 {
     int updated = 0, new_qp = 0;
@@ -2416,6 +2459,10 @@ static int encode_frame(AVCodecContext *avctx, QSVEncContext *q,
         ret = set_roi_encode_ctrl(avctx, frame, enc_ctrl);
         if (ret < 0)
             goto free;
+
+        ret = set_udu_encode_ctrl(avctx, q, frame, enc_ctrl);
+        if (ret < 0)
+            goto free;
     }
     if ((avctx->codec_id == AV_CODEC_ID_H264 ||
          avctx->codec_id == AV_CODEC_ID_H265) &&
diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
index 4a6fa2caed..5b66d31053 100644
--- a/libavcodec/qsvenc.h
+++ b/libavcodec/qsvenc.h
@@ -255,6 +255,7 @@ typedef struct QSVEncContext {
     int transform_skip;
 
     int a53_cc;
+    int udu_sei;
 
 #if QSV_HAVE_MF
     int mfmode;
diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c
index 071a9a79e9..31de8d7073 100644
--- a/libavcodec/qsvenc_h264.c
+++ b/libavcodec/qsvenc_h264.c
@@ -166,6 +166,7 @@ static const AVOption options[] = {
 #endif
 
     { "repeat_pps", "repeat pps for every frame", OFFSET(qsv.repeat_pps), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
+    { "udu_sei",    "Use user data unregistered SEI if available", OFFSET(qsv.udu_sei), AV_OPT_TYPE_BOOL,   { .i64 = 0 }, 0, 1, VE },
 
     { NULL },
 };
diff --git a/libavcodec/qsvenc_hevc.c b/libavcodec/qsvenc_hevc.c
index 5e23ca9647..5941c332cf 100644
--- a/libavcodec/qsvenc_hevc.c
+++ b/libavcodec/qsvenc_hevc.c
@@ -362,6 +362,7 @@ static const AVOption options[] = {
     { "int_ref_cycle_size", "Number of frames in the intra refresh cycle",       OFFSET(qsv.int_ref_cycle_size),      AV_OPT_TYPE_INT, { .i64 = -1 },               -1, UINT16_MAX, VE },
     { "int_ref_qp_delta",   "QP difference for the refresh MBs",                 OFFSET(qsv.int_ref_qp_delta),        AV_OPT_TYPE_INT, { .i64 = INT16_MIN }, INT16_MIN,  INT16_MAX, VE },
     { "int_ref_cycle_dist",   "Distance between the beginnings of the intra-refresh cycles in frames",  OFFSET(qsv.int_ref_cycle_dist),      AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT16_MAX, VE },
+    { "udu_sei",    "Use user data unregistered SEI if available", OFFSET(qsv.udu_sei), AV_OPT_TYPE_BOOL,   { .i64 = 0 }, 0, 1, VE },
 
     { NULL },
 };
-- 
2.17.1



More information about the ffmpeg-devel mailing list