It mimics same options in libx264 and qsv_h264 encoders
---
 libavcodec/internal.h    | 15 +++++++++
 libavcodec/libx264.c     | 49 ++++++++++-------------------
 libavcodec/nvenc.c       | 28 +++++++++++++++--
 libavcodec/nvenc.h       |  1 +
 libavcodec/nvenc_h264.c  |  1 +
 libavcodec/nvenc_hevc.c  |  1 +
 libavcodec/qsvenc.c      |  4 +--
 libavcodec/qsvenc_h264.c | 82 +++++++++++++++---------------------------------
 libavcodec/utils.c       | 44 ++++++++++++++++++++++++++
 9 files changed, 131 insertions(+), 94 deletions(-)

diff --git a/libavcodec/internal.h b/libavcodec/internal.h
index be54471..000fe26 100644
--- a/libavcodec/internal.h
+++ b/libavcodec/internal.h
@@ -345,4 +345,19 @@ AVCPBProperties *ff_add_cpb_side_data(AVCodecContext *avctx);
 
 int ff_side_data_set_encoder_stats(AVPacket *pkt, int quality, int64_t *error, int error_count, int pict_type);
 
+/**
+ * Check AVFrame for A53 side data and allocate and fill SEI message with A53 info
+ *
+ * @param frame      Raw frame to get A53 side data from
+ * @param prefix_len Number of bytes to allocate before SEI message
+ * @param data       Pointer to a variable to store allocated memory
+ *                   Upon return the variable will hold NULL on error or if frame has no A53 info.
+ *                   Otherwise it will point to prefix_len uninitialized bytes followed by
+ *                   *sei_size SEI message
+ * @param sei_size   Pointer to a variable to store generated SEI message length
+ * @return           Zero on success, negative error code on failure
+ */
+int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len,
+                     void **data, size_t *sei_size);
+
 #endif /* AVCODEC_INTERNAL_H */
diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c
index 449d76d..0063ae0 100644
--- a/libavcodec/libx264.c
+++ b/libavcodec/libx264.c
@@ -310,46 +310,29 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame,
         reconfig_encoder(ctx, frame);
 
         if (x4->a53_cc) {
-            side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_A53_CC);
-            if (side_data) {
+            void *sei_data;
+            size_t sei_size;
+
+            ret = ff_alloc_a53_sei(frame, 0, &sei_data, &sei_size);
+            if (ret < 0) {
+                av_log(ctx, AV_LOG_ERROR, "Not enough memory for closed captions, skipping\n");
+            } else if (sei_data) {
                 x4->pic.extra_sei.payloads = av_mallocz(sizeof(x4->pic.extra_sei.payloads[0]));
                 if (x4->pic.extra_sei.payloads == NULL) {
                     av_log(ctx, AV_LOG_ERROR, "Not enough memory for closed captions, skipping\n");
-                    goto skip_a53cc;
+                    av_free(sei_data);
+                } else {
+                    x4->pic.extra_sei.sei_free = av_free;
+
+                    x4->pic.extra_sei.payloads[0].payload_size = sei_size;
+                    x4->pic.extra_sei.payloads[0].payload = sei_data;
+                    x4->pic.extra_sei.num_payloads = 1;
+                    x4->pic.extra_sei.payloads[0].payload_type = 4;
                 }
-                x4->pic.extra_sei.sei_free = av_free;
-
-                x4->pic.extra_sei.payloads[0].payload_size = side_data->size + 11;
-                x4->pic.extra_sei.payloads[0].payload = av_mallocz(x4->pic.extra_sei.payloads[0].payload_size);
-                if (x4->pic.extra_sei.payloads[0].payload == NULL) {
-                    av_log(ctx, AV_LOG_ERROR, "Not enough memory for closed captions, skipping\n");
-                    av_freep(&x4->pic.extra_sei.payloads);
-                    goto skip_a53cc;
-                }
-                x4->pic.extra_sei.num_payloads = 1;
-                x4->pic.extra_sei.payloads[0].payload_type = 4;
-                memcpy(x4->pic.extra_sei.payloads[0].payload + 10, side_data->data, side_data->size);
-                x4->pic.extra_sei.payloads[0].payload[0] = 181;
-                x4->pic.extra_sei.payloads[0].payload[1] = 0;
-                x4->pic.extra_sei.payloads[0].payload[2] = 49;
-
-                /**
-                 * 'GA94' is standard in North America for ATSC, but hard coding
-                 * this style may not be the right thing to do -- other formats
-                 * do exist. This information is not available in the side_data
-                 * so we are going with this right now.
-                 */
-                AV_WL32(x4->pic.extra_sei.payloads[0].payload + 3,
-                    MKTAG('G', 'A', '9', '4'));
-                x4->pic.extra_sei.payloads[0].payload[7] = 3;
-                x4->pic.extra_sei.payloads[0].payload[8] =
-                    ((side_data->size/3) & 0x1f) | 0x40;
-                x4->pic.extra_sei.payloads[0].payload[9] = 0;
-                x4->pic.extra_sei.payloads[0].payload[side_data->size+10] = 255;
             }
         }
     }
-skip_a53cc:
+
     do {
         if (x264_encoder_encode(x4->enc, &nal, &nnal, frame? &x4->pic: NULL, &pic_out) < 0)
             return AVERROR_EXTERNAL;
diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index d3115f4..010819a 100644
--- a/libavcodec/nvenc.c
+++ b/libavcodec/nvenc.c
@@ -1374,7 +1374,8 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame,
 }
 
 static void nvenc_codec_specific_pic_params(AVCodecContext *avctx,
-                                            NV_ENC_PIC_PARAMS *params)
+                                            NV_ENC_PIC_PARAMS *params,
+                                            NV_ENC_SEI_PAYLOAD *sei_data)
 {
     NvencContext *ctx = avctx->priv_data;
 
@@ -1384,12 +1385,20 @@ static void nvenc_codec_specific_pic_params(AVCodecContext *avctx,
             ctx->encode_config.encodeCodecConfig.h264Config.sliceMode;
         params->codecPicParams.h264PicParams.sliceModeData =
             ctx->encode_config.encodeCodecConfig.h264Config.sliceModeData;
+        if (sei_data) {
+             params->codecPicParams.h264PicParams.seiPayloadArray = sei_data;
+             params->codecPicParams.h264PicParams.seiPayloadArrayCnt = 1;
+        }
       break;
     case AV_CODEC_ID_HEVC:
         params->codecPicParams.hevcPicParams.sliceMode =
             ctx->encode_config.encodeCodecConfig.hevcConfig.sliceMode;
         params->codecPicParams.hevcPicParams.sliceModeData =
             ctx->encode_config.encodeCodecConfig.hevcConfig.sliceModeData;
+        if (sei_data) {
+             params->codecPicParams.hevcPicParams.seiPayloadArray = sei_data;
+             params->codecPicParams.hevcPicParams.seiPayloadArrayCnt = 1;
+        }
         break;
     }
 }
@@ -1576,6 +1585,8 @@ int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 {
     NVENCSTATUS nv_status;
     NvencSurface *tmpoutsurf, *inSurf;
+    NV_ENC_SEI_PAYLOAD *sei_data = NULL;
+    size_t sei_size;
     int res;
 
     NvencContext *ctx = avctx->priv_data;
@@ -1616,12 +1627,25 @@ int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
         pic_params.encodePicFlags = 0;
         pic_params.inputTimeStamp = frame->pts;
 
-        nvenc_codec_specific_pic_params(avctx, &pic_params);
+        if (ctx->a53_cc) {
+            if (ff_alloc_a53_sei(frame, sizeof(NV_ENC_SEI_PAYLOAD), (void**)&sei_data, &sei_size) < 0) {
+                    av_log(ctx, AV_LOG_ERROR, "Not enough memory for closed captions, skipping\n");
+            }
+
+            if (sei_data) {
+                sei_data->payloadSize = (uint32_t)sei_size;
+                sei_data->payloadType = 4;
+                sei_data->payload = (uint8_t*)(sei_data + 1);
+            }
+        }
+
+        nvenc_codec_specific_pic_params(avctx, &pic_params, sei_data);
     } else {
         pic_params.encodePicFlags = NV_ENC_PIC_FLAG_EOS;
     }
 
     nv_status = p_nvenc->nvEncEncodePicture(ctx->nvencoder, &pic_params);
+    av_free(sei_data);
     if (nv_status != NV_ENC_SUCCESS &&
         nv_status != NV_ENC_ERR_NEED_MORE_INPUT)
         return nvenc_print_error(avctx, nv_status, "EncodePicture failed!");
diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h
index 961cbc7..71f538a 100644
--- a/libavcodec/nvenc.h
+++ b/libavcodec/nvenc.h
@@ -174,6 +174,7 @@ typedef struct NvencContext
     int device;
     int flags;
     int async_depth;
+    int a53_cc;
 } NvencContext;
 
 int ff_nvenc_encode_init(AVCodecContext *avctx);
diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c
index cdb80f2..eb9cb31 100644
--- a/libavcodec/nvenc_h264.c
+++ b/libavcodec/nvenc_h264.c
@@ -83,6 +83,7 @@ static const AVOption options[] = {
     { "any",      "Pick the first device available",      0,                   AV_OPT_TYPE_CONST,  { .i64 = ANY_DEVICE },           0, 0, VE, "gpu" },
     { "list",     "List the available devices",           0,                   AV_OPT_TYPE_CONST,  { .i64 = LIST_DEVICES },         0, 0, VE, "gpu" },
     { "delay",    "Delay frame output by the given amount of frames", OFFSET(async_depth), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 0, INT_MAX, VE },
+    { "a53cc",    "Use A53 Closed Captions (if available)", OFFSET(a53_cc),    AV_OPT_TYPE_BOOL,   { .i64 = 1 },                    0, 1, VE},
     { NULL }
 };
 
diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c
index cef19f7..5458eef 100644
--- a/libavcodec/nvenc_hevc.c
+++ b/libavcodec/nvenc_hevc.c
@@ -80,6 +80,7 @@ static const AVOption options[] = {
     { "any",      "Pick the first device available",      0,                   AV_OPT_TYPE_CONST,  { .i64 = ANY_DEVICE },           0, 0, VE, "device" },
     { "list",     "List the available devices",           0,                   AV_OPT_TYPE_CONST,  { .i64 = LIST_DEVICES },         0, 0, VE, "device" },
     { "delay",    "Delay frame output by the given amount of frames", OFFSET(async_depth), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 0, INT_MAX, VE },
+    { "a53cc",    "Use A53 Closed Captions (if available)", OFFSET(a53_cc),    AV_OPT_TYPE_BOOL,   { .i64 = 1 },                    0, 1, VE},
     { NULL }
 };
 
diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index 132cf47..f56cb61 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -781,9 +781,7 @@ 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++) {
-            mfxPayload* pay = enc_ctrl->Payload[i];
-            av_free(enc_ctrl->Payload[i]->Data);
-            av_free(pay);
+            av_free(enc_ctrl->Payload[i]);
         }
         enc_ctrl->NumPayload = 0;
     }
diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c
index 66e5ee8..cd08d86 100644
--- a/libavcodec/qsvenc_h264.c
+++ b/libavcodec/qsvenc_h264.c
@@ -43,63 +43,33 @@ typedef struct QSVH264EncContext {
 static int qsv_h264_set_encode_ctrl(AVCodecContext *avctx,
                                     const AVFrame *frame, mfxEncodeCtrl* enc_ctrl)
 {
-    AVFrameSideData *side_data = NULL;
-    QSVH264EncContext *qh264 = avctx->priv_data;
-    QSVEncContext *q = &qh264->qsv;
-
     if (q->a53_cc && frame) {
-        side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_A53_CC);
-        if (side_data) {
-
-            int sei_payload_size = 0;
-            mfxU8* sei_data = NULL;
-            mfxPayload* payload = NULL;
-
-            sei_payload_size = side_data->size + 13;
-
-            sei_data = av_mallocz(sei_payload_size);
-            if (!sei_data) {
-                av_log(avctx, AV_LOG_ERROR, "No memory for CC, skipping...\n");
-                return AVERROR(ENOMEM);
-            }
-
-            // SEI header
-            sei_data[0] = 4;
-            sei_data[1] = sei_payload_size - 2; // size of SEI data
-
-            // country code
-            sei_data[2] = 181;
-            sei_data[3] = 0;
-            sei_data[4] = 49;
-
-            // ATSC_identifier - using 'GA94' only
-            AV_WL32(sei_data + 5,
-                MKTAG('G', 'A', '9', '4'));
-            sei_data[9] = 3;
-            sei_data[10] =
-                ((side_data->size/3) & 0x1f) | 0xC0;
-
-            sei_data[11] = 0xFF; // reserved
-
-            memcpy(sei_data + 12, side_data->data, side_data->size);
-
-            sei_data[side_data->size+12] = 255;
-
-            payload = av_mallocz(sizeof(mfxPayload));
-            if (!payload) {
-                av_log(avctx, AV_LOG_ERROR, "No memory, skipping captions\n");
-                av_freep(&sei_data);
-                return AVERROR(ENOMEM);
-            }
-            payload->BufSize = side_data->size + 13;
-            payload->NumBit = payload->BufSize * 8;
-            payload->Type = 4;
-            payload->Data = sei_data;
-
-            enc_ctrl->NumExtParam = 0;
-            enc_ctrl->NumPayload = 1;
-            enc_ctrl->Payload[0] = payload;
-        }
+        AVFrameSideData *side_data = NULL;
+        QSVH264EncContext *qh264 = avctx->priv_data;
+        QSVEncContext *q = &qh264->qsv;
+        mfxPayload* payload;
+        mfxU8* sei_data;
+        size_t sei_size;
+        int res;
+
+        res = ff_alloc_a53_sei(frame, sizeof(mfxPayload) + 2, (void**)&payload, &sei_size);
+        if (res < 0)
+            return res;
+
+        sei_data = (mfxU8*)(payload + 1);
+        // SEI header
+        sei_data[0] = 4;
+        sei_data[1] = (mfxU8)sei_size; // size of SEI data
+        // SEI data filled in by ff_alloc_a53_sei
+
+        payload->BufSize = sei_size + 2;
+        payload->NumBit = payload->BufSize * 8;
+        payload->Type = 4;
+        payload->Data = sei_data;
+
+        enc_ctrl->NumExtParam = 0;
+        enc_ctrl->NumPayload = 1;
+        enc_ctrl->Payload[0] = payload;
     }
     return 0;
 }
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
index 7b99526..0367e20 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -4177,3 +4177,47 @@ int avcodec_parameters_to_context(AVCodecContext *codec,
 
     return 0;
 }
+
+int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len,
+                     void **data, size_t *sei_size)
+{
+    AVFrameSideData *side_data = NULL;
+    uint8_t *sei_data;
+
+    if (frame)
+        side_data = av_frame_get_side_data(frame, AV_FRAME_DATA_A53_CC);
+
+    if (!side_data)
+    {
+        *data = NULL;
+        return 0;
+    }
+
+    *sei_size = side_data->size + 11;
+    *data = av_mallocz(*sei_size + prefix_len);
+    if (!*data)
+        return AVERROR(ENOMEM);
+    sei_data = (uint8_t*)*data + prefix_len;
+
+    // country code
+    sei_data[0] = 181;
+    sei_data[1] = 0;
+    sei_data[2] = 49;
+
+    /**
+     * 'GA94' is standard in North America for ATSC, but hard coding
+     * this style may not be the right thing to do -- other formats
+     * do exist. This information is not available in the side_data
+     * so we are going with this right now.
+     */
+    AV_WL32(sei_data + 3, MKTAG('G', 'A', '9', '4'));
+    sei_data[7] = 3;
+    sei_data[8] = ((side_data->size/3) & 0x1f) | 0x40;
+    sei_data[9] = 0;
+
+    memcpy(sei_data + 10, side_data->data, side_data->size);
+
+    sei_data[side_data->size+10] = 255;
+
+    return 0;
+}
_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel

Reply via email to