Skip to content

Instantly share code, notes, and snippets.

@tea
Created June 3, 2016 18:00
Show Gist options
  • Save tea/f4f241056dcc7bd57c907d2a75c2bd3f to your computer and use it in GitHub Desktop.
Save tea/f4f241056dcc7bd57c907d2a75c2bd3f to your computer and use it in GitHub Desktop.
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/mpeg12dec.c b/libavcodec/mpeg12dec.c
index b861358..09be22b 100644
--- a/libavcodec/mpeg12dec.c
+++ b/libavcodec/mpeg12dec.c
@@ -1656,6 +1656,7 @@ static int mpeg_field_start(MpegEncContext *s, const uint8_t *buf, int buf_size)
memcpy(sd->data, s1->a53_caption, s1->a53_caption_size);
av_freep(&s1->a53_caption);
avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS;
+ av_log(s->avctx, AV_LOG_ERROR, "A53 dec\n");
}
if (s1->has_stereo3d) {
diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c
index 4be0405..2f6f33b 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;
}
}
@@ -1577,6 +1586,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;
@@ -1618,12 +1629,25 @@ int ff_nvenc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
pic_params.inputTimeStamp = frame->pts;
pic_params.inputDuration = av_frame_get_pkt_duration(frame);
- 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;
+}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment