[FFmpeg-devel] [PATCH] qsvenc: write a53 caption data to SEI

Will Kelleher wkelleher at gogoair.com
Sat Nov 7 15:29:15 CET 2015


---
 libavcodec/qsvenc.c      | 114 +++++++++++++++++++++++++++++++++++++++++++++--
 libavcodec/qsvenc.h      |   2 +-
 libavcodec/qsvenc_h264.c |   2 +-
 3 files changed, 113 insertions(+), 5 deletions(-)

diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c
index df1f777..0ee45f9 100644
--- a/libavcodec/qsvenc.c
+++ b/libavcodec/qsvenc.c
@@ -30,6 +30,7 @@
 #include "libavutil/log.h"
 #include "libavutil/time.h"
 #include "libavutil/imgutils.h"
+#include "libavcodec/bytestream.h"
 
 #include "avcodec.h"
 #include "internal.h"
@@ -276,7 +277,7 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q)
     q->param.AsyncDepth = q->async_depth;
 
     q->async_fifo = av_fifo_alloc((1 + q->async_depth) *
-                                  (sizeof(AVPacket) + sizeof(mfxSyncPoint) + sizeof(mfxBitstream*)));
+                                  (sizeof(AVPacket) + sizeof(mfxSyncPoint) + sizeof(mfxBitstream*) + sizeof(mfxEncodeCtrl*)));
     if (!q->async_fifo)
         return AVERROR(ENOMEM);
 
@@ -494,6 +495,27 @@ static void print_interlace_msg(AVCodecContext *avctx, QSVEncContext *q)
     }
 }
 
+static void freep_encoder_ctrl(mfxEncodeCtrl** enc_ptr)
+{
+    mfxEncodeCtrl* enc_ctrl;
+
+    if (!enc_ptr)
+        return;
+
+    enc_ctrl = *enc_ptr;
+
+    if (enc_ctrl) {
+        int i;
+        for (i = 0; i < enc_ctrl->NumPayload; i++) {
+            av_free(enc_ctrl->Payload[i]->Data);
+            av_freep(&enc_ctrl->Payload[i]);
+        }
+        av_free(enc_ctrl->Payload);
+        av_freep(&enc_ctrl);
+    }
+    *enc_ptr = NULL;
+}
+
 int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q,
                   AVPacket *pkt, const AVFrame *frame, int *got_packet)
 {
@@ -504,6 +526,10 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q,
     mfxSyncPoint sync      = NULL;
     int ret;
 
+    // for A53 CC data
+    mfxEncodeCtrl* enc_ctrl = NULL;
+    AVFrameSideData *side_data = NULL;
+
     if (frame) {
         ret = submit_frame(q, frame, &surf);
         if (ret < 0) {
@@ -526,8 +552,83 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q,
     bs->Data      = new_pkt.data;
     bs->MaxLength = new_pkt.size;
 
+    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;
+            mfxPayload** payloads = 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");
+                goto skip_a53cc;
+            }
+
+            // 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);
+                goto skip_a53cc;
+            }
+            payload->BufSize = side_data->size + 13;
+            payload->NumBit = payload->BufSize * 8;
+            payload->Type = 4;
+            payload->Data = sei_data;
+
+            payloads = av_mallocz(sizeof(mfxPayload*));
+            if (!payloads) {
+                av_log(avctx, AV_LOG_ERROR, "No memory, skipping captions\n");
+                av_freep(&sei_data);
+                av_freep(&payload);
+                goto skip_a53cc;
+            }
+
+            payloads[0] = payload;
+
+            enc_ctrl = av_mallocz(sizeof(mfxEncodeCtrl));
+            if (!enc_ctrl)
+            {
+                av_log(avctx, AV_LOG_VERBOSE, "No memory for mfxEncodeCtrl\n");
+                av_freep(&sei_data);
+                av_freep(&payload);
+                av_freep(&payloads);
+                goto skip_a53cc;
+            }
+            enc_ctrl->NumExtParam = 0;
+            enc_ctrl->NumPayload = 0;
+            enc_ctrl->Payload = payloads;
+       }
+    }
+skip_a53cc:
     do {
-        ret = MFXVideoENCODE_EncodeFrameAsync(q->session, NULL, surf, bs, &sync);
+        ret = MFXVideoENCODE_EncodeFrameAsync(q->session, enc_ctrl, surf, bs, &sync);
         if (ret == MFX_WRN_DEVICE_BUSY) {
             av_usleep(500);
             continue;
@@ -554,10 +655,12 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q,
     if (sync) {
         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);
+        av_fifo_generic_write(q->async_fifo, &bs,      sizeof(bs),      NULL);
+        av_fifo_generic_write(q->async_fifo, &enc_ctrl,sizeof(mfxEncodeCtrl*),NULL);
     } else {
         av_packet_unref(&new_pkt);
         av_freep(&bs);
+        freep_encoder_ctrl(&enc_ctrl);
     }
 
     if (!av_fifo_space(q->async_fifo) ||
@@ -565,6 +668,7 @@ int ff_qsv_encode(AVCodecContext *avctx, QSVEncContext *q,
         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);
+        av_fifo_generic_read(q->async_fifo, &enc_ctrl,sizeof(mfxEncodeCtrl*),NULL);
 
         MFXVideoCORE_SyncOperation(q->session, sync, 60000);
 
@@ -588,6 +692,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
 #endif
 
         av_freep(&bs);
+        freep_encoder_ctrl(&enc_ctrl);
 
         if (pkt->data) {
             if (pkt->size < new_pkt.size) {
@@ -635,13 +740,16 @@ int ff_qsv_enc_close(AVCodecContext *avctx, QSVEncContext *q)
         AVPacket pkt;
         mfxSyncPoint sync;
         mfxBitstream *bs;
+        mfxEncodeCtrl* enc_ctrl;
 
         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);
+        av_fifo_generic_read(q->async_fifo, &enc_ctrl, sizeof(mfxEncodeCtrl*), NULL);
 
         av_freep(&bs);
         av_packet_unref(&pkt);
+        freep_encoder_ctrl(&enc_ctrl);
     }
     av_fifo_free(q->async_fifo);
     q->async_fifo = NULL;
diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h
index 3dd7afe..d2fa6b4 100644
--- a/libavcodec/qsvenc.h
+++ b/libavcodec/qsvenc.h
@@ -76,7 +76,7 @@ typedef struct QSVEncContext {
     int look_ahead;
     int look_ahead_depth;
     int look_ahead_downsampling;
-
+    int a53_cc;
     char *load_plugins;
 } QSVEncContext;
 
diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c
index 0e5a26c..5bdb5f4 100644
--- a/libavcodec/qsvenc_h264.c
+++ b/libavcodec/qsvenc_h264.c
@@ -97,7 +97,7 @@ static const AVOption options[] = {
     { "slow",        NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_3  },            INT_MIN, INT_MAX, VE, "preset" },
     { "slower",      NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_2  },            INT_MIN, INT_MAX, VE, "preset" },
     { "veryslow",    NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_TARGETUSAGE_BEST_QUALITY  }, INT_MIN, INT_MAX, VE, "preset" },
-
+    {"a53cc",          "Use A53 Closed Captions (if available)",          OFFSET(qsv.a53_cc),        AV_OPT_TYPE_BOOL,   {.i64 = 0}, 0, 1, VE},
     { NULL },
 };
 
-- 
2.6.2



More information about the ffmpeg-devel mailing list