Skip to content

Commit

Permalink
avcodec/subtitles: Migrate subtitle encoders to frame-based API
Browse files Browse the repository at this point in the history
and provide a compatibility shim for the legacy api

Signed-off-by: softworkz <softworkz@hotmail.com>
  • Loading branch information
softworkz committed Oct 2, 2022
1 parent ce0c57a commit 2f815dc
Show file tree
Hide file tree
Showing 13 changed files with 689 additions and 280 deletions.
189 changes: 157 additions & 32 deletions libavcodec/assenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,67 +25,192 @@

#include "avcodec.h"
#include "codec_internal.h"
#include "encode.h"
#include "libavutil/ass_internal.h"
#include "libavutil/avstring.h"
#include "libavutil/internal.h"
#include "libavutil/mem.h"

typedef struct {
AVCodecContext *avctx;
AVFrame* current_frame;
int have_frame;
int current_area;
} AssEncContext;

static void check_write_header(AVCodecContext* avctx, const AVFrame* frame)
{
if (avctx->extradata_size)
return;

if (frame->subtitle_header && frame->subtitle_header->size > 0) {
const char* subtitle_header = (char*)frame->subtitle_header->data;
avctx->extradata_size = strlen(subtitle_header);
avctx->extradata = av_mallocz(frame->subtitle_header->size + 1);
memcpy(avctx->extradata, subtitle_header, avctx->extradata_size);
avctx->extradata[avctx->extradata_size] = 0;
}

if (!avctx->extradata_size) {
const char* subtitle_header = avpriv_ass_get_subtitle_header_default(0);
if (!subtitle_header)
return;

avctx->extradata_size = strlen(subtitle_header);
avctx->extradata = av_mallocz(avctx->extradata_size + 1);
memcpy(avctx->extradata, subtitle_header, avctx->extradata_size);
avctx->extradata[avctx->extradata_size] = 0;
av_freep(&subtitle_header);
}
}

static av_cold int ass_encode_init(AVCodecContext *avctx)
{
avctx->extradata = av_malloc(avctx->subtitle_header_size + 1);
if (!avctx->extradata)
return AVERROR(ENOMEM);
memcpy(avctx->extradata, avctx->subtitle_header, avctx->subtitle_header_size);
avctx->extradata_size = avctx->subtitle_header_size;
avctx->extradata[avctx->extradata_size] = 0;
AssEncContext *s = avctx->priv_data;

if (avctx->subtitle_header_size) {
avctx->extradata = av_malloc(avctx->subtitle_header_size + 1);
if (!avctx->extradata)
return AVERROR(ENOMEM);
memcpy(avctx->extradata, avctx->subtitle_header, avctx->subtitle_header_size);
avctx->extradata_size = avctx->subtitle_header_size;
avctx->extradata[avctx->extradata_size] = 0;
}

s->current_frame = av_frame_alloc();
return 0;
}

static av_cold int ass_encode_close(AVCodecContext *avctx)
{
AssEncContext *s = avctx->priv_data;
av_frame_free(&s->current_frame);
return 0;
}

static int ass_encode_frame(AVCodecContext *avctx,
unsigned char *buf, int bufsize,
const AVSubtitle *sub)
////static int ass_encode_frame(AVCodecContext* avctx, AVPacket* avpkt,
//// const AVFrame* frame, int* got_packet)
////{
//// int ret;
//// size_t req_len = 0, total_len = 0;
////
//// check_write_header(avctx, frame);
////
//// for (unsigned i = 0; i < frame->num_subtitle_areas; i++) {
//// const char *ass = frame->subtitle_areas[i]->ass;
////
//// if (frame->subtitle_areas[i]->type != AV_SUBTITLE_FMT_ASS) {
//// av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n");
//// return AVERROR(EINVAL);
//// }
////
//// if (ass)
//// req_len += strlen(ass);
//// }
////
//// ret = ff_get_encode_buffer(avctx, avpkt, req_len + 1, 0);
//// if (ret < 0) {
//// av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
//// return ret;
//// }
////
//// for (unsigned i = 0; i < frame->num_subtitle_areas; i++) {
//// const char *ass = frame->subtitle_areas[i]->ass;
////
//// if (ass) {
//// size_t len = av_strlcpy((char *)avpkt->data + total_len, ass, avpkt->size - total_len);
//// total_len += len;
//// }
//// }
////
//// avpkt->size = total_len;
//// *got_packet = total_len > 0;
////
//// return 0;
////}

static int ass_receive_packet(AVCodecContext *avctx, AVPacket *avpkt)
{
int i, len, total_len = 0;
AssEncContext *s = avctx->priv_data;
int ret;

if (!s->have_frame) {
s->current_area = 0;
ret = ff_encode_get_frame(avctx, s->current_frame);

if (ret < 0) {
av_frame_unref(s->current_frame);
return ret;
}

s->have_frame = 1;
}

for (i=0; i<sub->num_rects; i++) {
const char *ass = sub->rects[i]->ass;
check_write_header(avctx, s->current_frame);

if (sub->rects[i]->type != SUBTITLE_ASS) {
av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
if (s->current_frame->repeat_sub) {
av_frame_unref(s->current_frame);
s->have_frame = 0;
return AVERROR(EAGAIN);
}

if (s->current_area < s->current_frame->num_subtitle_areas) {
const AVSubtitleArea *area = s->current_frame->subtitle_areas[s->current_area];
const char *ass = area->ass;

if (area->type != AV_SUBTITLE_FMT_ASS) {
av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n");
return AVERROR(EINVAL);
}

len = av_strlcpy(buf+total_len, ass, bufsize-total_len);
if (ass) {
size_t len = strlen(ass);

ret = ff_get_encode_buffer(avctx, avpkt, len + 1, 0);
if (ret < 0) {
av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
return ret;
}

len = av_strlcpy((char *)avpkt->data, ass, avpkt->size);

if (len > bufsize-total_len-1) {
av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
return AVERROR_BUFFER_TOO_SMALL;
avpkt->size = len;
}

total_len += len;
s->current_area++;
}

return total_len;
if (s->current_area < s->current_frame->num_subtitle_areas)
return 0;

av_frame_unref(s->current_frame);
s->have_frame = 0;

return 0;
}

#if CONFIG_SSA_ENCODER
const FFCodec ff_ssa_encoder = {
.p.name = "ssa",
CODEC_LONG_NAME("ASS (Advanced SubStation Alpha) subtitle"),
.p.type = AVMEDIA_TYPE_SUBTITLE,
.p.id = AV_CODEC_ID_ASS,
.init = ass_encode_init,
FF_CODEC_ENCODE_SUB_CB(ass_encode_frame),
.p.name = "ssa",
.p.long_name = NULL_IF_CONFIG_SMALL("ASS (Advanced SubStation Alpha) subtitle"),
.p.type = AVMEDIA_TYPE_SUBTITLE,
.p.id = AV_CODEC_ID_ASS,
.priv_data_size = sizeof(AssEncContext),
.init = ass_encode_init,
.close = ass_encode_close,
FF_CODEC_RECEIVE_PACKET_CB(ass_receive_packet),
};
#endif

#if CONFIG_ASS_ENCODER
const FFCodec ff_ass_encoder = {
.p.name = "ass",
CODEC_LONG_NAME("ASS (Advanced SubStation Alpha) subtitle"),
.p.type = AVMEDIA_TYPE_SUBTITLE,
.p.id = AV_CODEC_ID_ASS,
.init = ass_encode_init,
FF_CODEC_ENCODE_SUB_CB(ass_encode_frame),
.p.name = "ass",
.p.long_name = NULL_IF_CONFIG_SMALL("ASS (Advanced SubStation Alpha) subtitle"),
.p.type = AVMEDIA_TYPE_SUBTITLE,
.priv_data_size = sizeof(AssEncContext),
.p.id = AV_CODEC_ID_ASS,
.init = ass_encode_init,
.close = ass_encode_close,
FF_CODEC_RECEIVE_PACKET_CB(ass_receive_packet),
};
#endif
5 changes: 4 additions & 1 deletion libavcodec/avcodec.h
Original file line number Diff line number Diff line change
Expand Up @@ -3024,10 +3024,13 @@ void av_parser_close(AVCodecParserContext *s);
* @{
*/

/**
* @deprecated Use @ref avcodec_encode_subtitle2() instead.
*/
attribute_deprecated
int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size,
const AVSubtitle *sub);


/**
* @}
*/
Expand Down
12 changes: 0 additions & 12 deletions libavcodec/codec_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,6 @@ enum FFCodecType {
/* The codec is an encoder using the encode callback;
* audio and video codecs only. */
FF_CODEC_CB_TYPE_ENCODE,
/* The codec is an encoder using the encode_sub callback;
* subtitle codecs only. */
FF_CODEC_CB_TYPE_ENCODE_SUB,
/* The codec is an encoder using the receive_packet callback;
* audio and video codecs only. */
FF_CODEC_CB_TYPE_RECEIVE_PACKET,
Expand Down Expand Up @@ -213,12 +210,6 @@ typedef struct FFCodec {
*/
int (*encode)(struct AVCodecContext *avctx, struct AVPacket *avpkt,
const struct AVFrame *frame, int *got_packet_ptr);
/**
* Encode subtitles to a raw buffer.
* cb is in this state if cb_type is FF_CODEC_CB_TYPE_ENCODE_SUB.
*/
int (*encode_sub)(struct AVCodecContext *avctx, uint8_t *buf,
int buf_size, const struct AVSubtitle *sub);
/**
* Encode API with decoupled frame/packet dataflow.
* cb is in this state if cb_type is FF_CODEC_CB_TYPE_RECEIVE_PACKET.
Expand Down Expand Up @@ -307,9 +298,6 @@ typedef struct FFCodec {
#define FF_CODEC_ENCODE_CB(func) \
.cb_type = FF_CODEC_CB_TYPE_ENCODE, \
.cb.encode = (func)
#define FF_CODEC_ENCODE_SUB_CB(func) \
.cb_type = FF_CODEC_CB_TYPE_ENCODE_SUB, \
.cb.encode_sub = (func)
#define FF_CODEC_RECEIVE_PACKET_CB(func) \
.cb_type = FF_CODEC_CB_TYPE_RECEIVE_PACKET, \
.cb.receive_packet = (func)
Expand Down
Loading

0 comments on commit 2f815dc

Please sign in to comment.