1
0
mirror of https://github.com/FFmpeg/FFmpeg.git synced 2024-11-26 19:01:44 +02:00

libx265: support ATSC A/53 captions

added a new option 'a53cc' (on by default, as in libx264) for rendering
AV_FRAME_DATA_A53_CC as hevc sei payloads.
the code is a blend of the libx265.c code for writing
AV_FRAME_DATA_SEI_UNREGISTERED with the libx264.c code for writing atsc
a/53 payloads.
This commit is contained in:
erankor 2022-11-08 17:14:07 +02:00 committed by Timo Rothenpieler
parent 939273d3b4
commit 6043352bd9
3 changed files with 58 additions and 8 deletions

1
configure vendored
View File

@ -3399,6 +3399,7 @@ libx264_encoder_select="atsc_a53"
libx264rgb_encoder_deps="libx264" libx264rgb_encoder_deps="libx264"
libx264rgb_encoder_select="libx264_encoder" libx264rgb_encoder_select="libx264_encoder"
libx265_encoder_deps="libx265" libx265_encoder_deps="libx265"
libx265_encoder_select="atsc_a53"
libxavs_encoder_deps="libxavs" libxavs_encoder_deps="libxavs"
libxavs2_encoder_deps="libxavs2" libxavs2_encoder_deps="libxavs2"
libxvid_encoder_deps="libxvid" libxvid_encoder_deps="libxvid"

View File

@ -36,6 +36,7 @@
#include "encode.h" #include "encode.h"
#include "internal.h" #include "internal.h"
#include "packet_internal.h" #include "packet_internal.h"
#include "atsc_a53.h"
#include "sei.h" #include "sei.h"
typedef struct libx265Context { typedef struct libx265Context {
@ -56,6 +57,7 @@ typedef struct libx265Context {
void *sei_data; void *sei_data;
int sei_data_size; int sei_data_size;
int udu_sei; int udu_sei;
int a53_cc;
/** /**
* If the encoder does not support ROI then warn the first time we * If the encoder does not support ROI then warn the first time we
@ -499,6 +501,16 @@ static av_cold int libx265_encode_set_roi(libx265Context *ctx, const AVFrame *fr
return 0; return 0;
} }
static void free_picture(x265_picture *pic)
{
x265_sei *sei = &pic->userSEI;
for (int i = 0; i < sei->numPayloads; i++)
av_free(sei->payloads[i].payload);
av_freep(&pic->userData);
av_freep(&pic->quantOffsets);
sei->numPayloads = 0;
}
static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
const AVFrame *pic, int *got_packet) const AVFrame *pic, int *got_packet)
{ {
@ -506,6 +518,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
x265_picture x265pic; x265_picture x265pic;
x265_picture x265pic_out = { 0 }; x265_picture x265pic_out = { 0 };
x265_nal *nal; x265_nal *nal;
x265_sei *sei;
uint8_t *dst; uint8_t *dst;
int pict_type; int pict_type;
int payload = 0; int payload = 0;
@ -515,9 +528,10 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
ctx->api->picture_init(ctx->params, &x265pic); ctx->api->picture_init(ctx->params, &x265pic);
sei = &x265pic.userSEI;
sei->numPayloads = 0;
if (pic) { if (pic) {
x265_sei *sei = &x265pic.userSEI;
sei->numPayloads = 0;
for (i = 0; i < 3; i++) { for (i = 0; i < 3; i++) {
x265pic.planes[i] = pic->data[i]; x265pic.planes[i] = pic->data[i];
x265pic.stride[i] = pic->linesize[i]; x265pic.stride[i] = pic->linesize[i];
@ -539,13 +553,42 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
if (pic->reordered_opaque) { if (pic->reordered_opaque) {
x265pic.userData = av_malloc(sizeof(pic->reordered_opaque)); x265pic.userData = av_malloc(sizeof(pic->reordered_opaque));
if (!x265pic.userData) { if (!x265pic.userData) {
av_freep(&x265pic.quantOffsets); free_picture(&x265pic);
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
memcpy(x265pic.userData, &pic->reordered_opaque, sizeof(pic->reordered_opaque)); memcpy(x265pic.userData, &pic->reordered_opaque, sizeof(pic->reordered_opaque));
} }
if (ctx->a53_cc) {
void *sei_data;
size_t sei_size;
ret = ff_alloc_a53_sei(pic, 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) {
void *tmp;
x265_sei_payload *sei_payload;
tmp = av_fast_realloc(ctx->sei_data,
&ctx->sei_data_size,
(sei->numPayloads + 1) * sizeof(*sei_payload));
if (!tmp) {
av_free(sei_data);
free_picture(&x265pic);
return AVERROR(ENOMEM);
}
ctx->sei_data = tmp;
sei->payloads = ctx->sei_data;
sei_payload = &sei->payloads[sei->numPayloads];
sei_payload->payload = sei_data;
sei_payload->payloadSize = sei_size;
sei_payload->payloadType = SEI_TYPE_USER_DATA_REGISTERED_ITU_T_T35;
sei->numPayloads++;
}
}
if (ctx->udu_sei) { if (ctx->udu_sei) {
for (i = 0; i < pic->nb_side_data; i++) { for (i = 0; i < pic->nb_side_data; i++) {
AVFrameSideData *side_data = pic->side_data[i]; AVFrameSideData *side_data = pic->side_data[i];
@ -559,14 +602,17 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
&ctx->sei_data_size, &ctx->sei_data_size,
(sei->numPayloads + 1) * sizeof(*sei_payload)); (sei->numPayloads + 1) * sizeof(*sei_payload));
if (!tmp) { if (!tmp) {
av_freep(&x265pic.userData); free_picture(&x265pic);
av_freep(&x265pic.quantOffsets);
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
} }
ctx->sei_data = tmp; ctx->sei_data = tmp;
sei->payloads = ctx->sei_data; sei->payloads = ctx->sei_data;
sei_payload = &sei->payloads[sei->numPayloads]; sei_payload = &sei->payloads[sei->numPayloads];
sei_payload->payload = side_data->data; sei_payload->payload = av_memdup(side_data->data, side_data->size);
if (!sei_payload->payload) {
free_picture(&x265pic);
return AVERROR(ENOMEM);
}
sei_payload->payloadSize = side_data->size; sei_payload->payloadSize = side_data->size;
/* Equal to libx265 USER_DATA_UNREGISTERED */ /* Equal to libx265 USER_DATA_UNREGISTERED */
sei_payload->payloadType = SEI_TYPE_USER_DATA_UNREGISTERED; sei_payload->payloadType = SEI_TYPE_USER_DATA_UNREGISTERED;
@ -578,6 +624,8 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal, ret = ctx->api->encoder_encode(ctx->encoder, &nal, &nnal,
pic ? &x265pic : NULL, &x265pic_out); pic ? &x265pic : NULL, &x265pic_out);
for (i = 0; i < sei->numPayloads; i++)
av_free(sei->payloads[i].payload);
av_freep(&x265pic.quantOffsets); av_freep(&x265pic.quantOffsets);
if (ret < 0) if (ret < 0)
@ -713,7 +761,8 @@ static const AVOption options[] = {
{ "preset", "set the x265 preset", OFFSET(preset), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { "preset", "set the x265 preset", OFFSET(preset), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
{ "tune", "set the x265 tune parameter", OFFSET(tune), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { "tune", "set the x265 tune parameter", OFFSET(tune), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
{ "profile", "set the x265 profile", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { "profile", "set the x265 profile", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE },
{ "udu_sei", "Use user data unregistered SEI if available", OFFSET(udu_sei), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "udu_sei", "Use user data unregistered SEI if available", OFFSET(udu_sei), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE },
{ "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE },
{ "x265-params", "set the x265 configuration using a :-separated list of key=value parameters", OFFSET(x265_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE }, { "x265-params", "set the x265 configuration using a :-separated list of key=value parameters", OFFSET(x265_opts), AV_OPT_TYPE_DICT, { 0 }, 0, 0, VE },
{ NULL } { NULL }
}; };

View File

@ -30,7 +30,7 @@
#include "version_major.h" #include "version_major.h"
#define LIBAVCODEC_VERSION_MINOR 52 #define LIBAVCODEC_VERSION_MINOR 52
#define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_MICRO 101
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \ LIBAVCODEC_VERSION_MINOR, \