diff options
author | Will Kelleher <wkelleher@gogoair.com> | 2015-10-27 12:08:45 -0500 |
---|---|---|
committer | Michael Niedermayer <michael@niedermayer.cc> | 2015-11-30 23:31:12 +0100 |
commit | 0eac93da0fd5baa400ee0a4a6dd8334202e8ada9 (patch) | |
tree | 39184a006a0a6de98e122b63fd44b7277448c76f /libavcodec/qsvenc_h264.c | |
parent | a00cc2e40d40c06e867ab4a07afbbbb3df565b02 (diff) |
qsvenc: write a53 caption data to SEI
Signed-off-by: Will Kelleher <wkelleher@gogoair.com>
Previous version reviewed-by: Ivan Uskov <ivan.uskov@nablet.com>
Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Diffstat (limited to 'libavcodec/qsvenc_h264.c')
-rw-r--r-- | libavcodec/qsvenc_h264.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c index 043f4d3fd1..4600831f20 100644 --- a/libavcodec/qsvenc_h264.c +++ b/libavcodec/qsvenc_h264.c @@ -40,10 +40,75 @@ typedef struct QSVH264EncContext { QSVEncContext qsv; } 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; + } + } + return 0; +} + static av_cold int qsv_enc_init(AVCodecContext *avctx) { QSVH264EncContext *q = avctx->priv_data; + q->qsv.set_encode_ctrl_cb = qsv_h264_set_encode_ctrl; return ff_qsv_enc_init(avctx, &q->qsv); } @@ -103,6 +168,7 @@ static const AVOption options[] = { { "main" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_AVC_MAIN }, INT_MIN, INT_MAX, VE, "profile" }, { "high" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_AVC_HIGH }, INT_MIN, INT_MAX, VE, "profile" }, + { "a53cc" , "Use A53 Closed Captions (if available)", OFFSET(qsv.a53_cc), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, VE}, { NULL }, }; |