| 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