24 changes: 11 additions & 13 deletions libavcodec/ccaption_dec.c
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ typedef struct CCaptionSubContext {
char prev_cmd[2];
/* buffer to store pkt data */
AVBufferRef *pktbuf;
int readorder;
} CCaptionSubContext;


Expand Down Expand Up @@ -306,6 +307,7 @@ static void flush_decoder(AVCodecContext *avctx)
ctx->last_real_time = 0;
ctx->screen_touched = 0;
ctx->buffer_changed = 0;
ctx->readorder = 0;
av_bprint_clear(&ctx->buffer);
}

Expand Down Expand Up @@ -752,18 +754,16 @@ static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avp

if (*ctx->buffer.str || ctx->real_time)
{
int64_t sub_pts = ctx->real_time ? avpkt->pts : ctx->start_time;
int start_time = av_rescale_q(sub_pts, avctx->time_base, ass_tb);
int duration = -1;
if (!ctx->real_time) {
int end_time = av_rescale_q(ctx->end_time, avctx->time_base, ass_tb);
duration = end_time - start_time;
}
ff_dlog(ctx, "cdp writing data (%s)\n",ctx->buffer.str);
ret = ff_ass_add_rect_bprint(sub, &ctx->buffer, start_time, duration);
ret = ff_ass_add_rect(sub, ctx->buffer.str, ctx->readorder++, 0, NULL, NULL);
if (ret < 0)
return ret;
sub->pts = av_rescale_q(sub_pts, avctx->time_base, AV_TIME_BASE_Q);
sub->pts = av_rescale_q(ctx->start_time, avctx->time_base, AV_TIME_BASE_Q);
if (!ctx->real_time)
sub->end_display_time = av_rescale_q(ctx->end_time - ctx->start_time,
avctx->time_base, av_make_q(1, 1000));
else
sub->end_display_time = -1;
ctx->buffer_changed = 0;
ctx->last_real_time = avpkt->pts;
ctx->screen_touched = 0;
Expand All @@ -772,18 +772,16 @@ static int decode(AVCodecContext *avctx, void *data, int *got_sub, AVPacket *avp

if (ctx->real_time && ctx->screen_touched &&
avpkt->pts > ctx->last_real_time + av_rescale_q(20, ass_tb, avctx->time_base)) {
int start_time;
ctx->last_real_time = avpkt->pts;
ctx->screen_touched = 0;

capture_screen(ctx);
ctx->buffer_changed = 0;

start_time = av_rescale_q(avpkt->pts, avctx->time_base, ass_tb);
ret = ff_ass_add_rect_bprint(sub, &ctx->buffer, start_time, -1);
ret = ff_ass_add_rect(sub, ctx->buffer.str, ctx->readorder++, 0, NULL, NULL);
if (ret < 0)
return ret;
sub->pts = av_rescale_q(avpkt->pts, avctx->time_base, AV_TIME_BASE_Q);
sub->end_display_time = -1;
}

*got_sub = sub->num_rects > 0;
Expand Down
5 changes: 4 additions & 1 deletion libavcodec/jacosubdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ static int jacosub_decode_frame(AVCodecContext *avctx,
int ret;
AVSubtitle *sub = data;
const char *ptr = avpkt->data;
FFASSDecoderContext *s = avctx->priv_data;

if (avpkt->size <= 0)
goto end;
Expand All @@ -181,7 +182,7 @@ static int jacosub_decode_frame(AVCodecContext *avctx,

av_bprint_init(&buffer, JSS_MAX_LINESIZE, JSS_MAX_LINESIZE);
jacosub_to_ass(avctx, &buffer, ptr);
ret = ff_ass_add_rect_bprint(sub, &buffer, avpkt->pts, avpkt->duration);
ret = ff_ass_add_rect(sub, buffer.str, s->readorder++, 0, NULL, NULL);
av_bprint_finalize(&buffer, NULL);
if (ret < 0)
return ret;
Expand All @@ -199,4 +200,6 @@ AVCodec ff_jacosub_decoder = {
.id = AV_CODEC_ID_JACOSUB,
.init = ff_ass_subtitle_header_default,
.decode = jacosub_decode_frame,
.flush = ff_ass_decoder_flush,
.priv_data_size = sizeof(FFASSDecoderContext),
};
38 changes: 13 additions & 25 deletions libavcodec/libzvbi-teletextdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ typedef struct TeletextContext
vbi_export * ex;
#endif
vbi_sliced sliced[MAX_SLICES];

int readorder;
} TeletextContext;

static int chop_spaces_utf8(const unsigned char* t, int len)
Expand All @@ -95,37 +97,21 @@ static void subtitle_rect_free(AVSubtitleRect **sub_rect)
av_freep(sub_rect);
}

static int create_ass_text(TeletextContext *ctx, const char *text, char **ass)
static char *create_ass_text(TeletextContext *ctx, const char *text)
{
int ret;
AVBPrint buf, buf2;
const int ts_start = av_rescale_q(ctx->pts, AV_TIME_BASE_Q, (AVRational){1, 100});
const int ts_duration = av_rescale_q(ctx->sub_duration, (AVRational){1, 1000}, (AVRational){1, 100});
char *dialog;
AVBPrint buf;

/* First we escape the plain text into buf. */
av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
ff_ass_bprint_text_event(&buf, text, strlen(text), "", 0);
av_bprintf(&buf, "\r\n");

if (!av_bprint_is_complete(&buf)) {
av_bprint_finalize(&buf, NULL);
return AVERROR(ENOMEM);
return NULL;
}

/* Then we create the ass dialog line in buf2 from the escaped text in buf. */
av_bprint_init(&buf2, 0, AV_BPRINT_SIZE_UNLIMITED);
ff_ass_bprint_dialog(&buf2, buf.str, ts_start, ts_duration, 0);
dialog = ff_ass_get_dialog(ctx->readorder++, 0, NULL, NULL, buf.str);
av_bprint_finalize(&buf, NULL);

if (!av_bprint_is_complete(&buf2)) {
av_bprint_finalize(&buf2, NULL);
return AVERROR(ENOMEM);
}

if ((ret = av_bprint_finalize(&buf2, ass)) < 0)
return ret;

return 0;
return dialog;
}

/* Draw a page as text */
Expand Down Expand Up @@ -181,11 +167,12 @@ static int gen_sub_text(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page
}

if (buf.len) {
int ret;
sub_rect->type = SUBTITLE_ASS;
if ((ret = create_ass_text(ctx, buf.str, &sub_rect->ass)) < 0) {
sub_rect->ass = create_ass_text(ctx, buf.str);

if (!sub_rect->ass) {
av_bprint_finalize(&buf, NULL);
return ret;
return AVERROR(ENOMEM);
}
av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", sub_rect->ass);
} else {
Expand Down Expand Up @@ -541,6 +528,7 @@ static int teletext_close_decoder(AVCodecContext *avctx)
vbi_decoder_delete(ctx->vbi);
ctx->vbi = NULL;
ctx->pts = AV_NOPTS_VALUE;
ctx->readorder = 0;
return 0;
}

Expand Down
12 changes: 4 additions & 8 deletions libavcodec/microdvddec.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ static int microdvd_decode_frame(AVCodecContext *avctx,
AVBPrint new_line;
char *line = avpkt->data;
char *end = avpkt->data + avpkt->size;
FFASSDecoderContext *s = avctx->priv_data;
struct microdvd_tag tags[sizeof(MICRODVD_TAGS) - 1] = {{0}};

if (avpkt->size <= 0)
Expand Down Expand Up @@ -308,14 +309,7 @@ static int microdvd_decode_frame(AVCodecContext *avctx,
}
}
if (new_line.len) {
int ret;
int64_t start = avpkt->pts;
int64_t duration = avpkt->duration;
int ts_start = av_rescale_q(start, avctx->time_base, (AVRational){1,100});
int ts_duration = duration != -1 ?
av_rescale_q(duration, avctx->time_base, (AVRational){1,100}) : -1;

ret = ff_ass_add_rect_bprint(sub, &new_line, ts_start, ts_duration);
int ret = ff_ass_add_rect(sub, new_line.str, s->readorder++, 0, NULL, NULL);
av_bprint_finalize(&new_line, NULL);
if (ret < 0)
return ret;
Expand Down Expand Up @@ -381,4 +375,6 @@ AVCodec ff_microdvd_decoder = {
.id = AV_CODEC_ID_MICRODVD,
.init = microdvd_init,
.decode = microdvd_decode_frame,
.flush = ff_ass_decoder_flush,
.priv_data_size = sizeof(FFASSDecoderContext),
};
19 changes: 10 additions & 9 deletions libavcodec/movtextdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ typedef struct {
uint64_t tracksize;
int size_var;
int count_s, count_f;
int readorder;
} MovTextContext;

typedef struct {
Expand Down Expand Up @@ -424,7 +425,7 @@ static int mov_text_decode_frame(AVCodecContext *avctx,
{
AVSubtitle *sub = data;
MovTextContext *m = avctx->priv_data;
int ret, ts_start, ts_end;
int ret;
AVBPrint buf;
char *ptr = avpkt->data;
char *end;
Expand Down Expand Up @@ -454,13 +455,6 @@ static int mov_text_decode_frame(AVCodecContext *avctx,
end = ptr + FFMIN(2 + text_length, avpkt->size);
ptr += 2;

ts_start = av_rescale_q(avpkt->pts,
avctx->time_base,
(AVRational){1,100});
ts_end = av_rescale_q(avpkt->pts + avpkt->duration,
avctx->time_base,
(AVRational){1,100});

tsmb_size = 0;
m->tracksize = 2 + text_length;
m->style_entries = 0;
Expand Down Expand Up @@ -506,7 +500,7 @@ static int mov_text_decode_frame(AVCodecContext *avctx,
} else
text_to_ass(&buf, ptr, end, m);

ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_end - ts_start);
ret = ff_ass_add_rect(sub, buf.str, m->readorder++, 0, NULL, NULL);
av_bprint_finalize(&buf, NULL);
if (ret < 0)
return ret;
Expand All @@ -521,6 +515,12 @@ static int mov_text_decode_close(AVCodecContext *avctx)
return 0;
}

static void mov_text_flush(AVCodecContext *avctx)
{
MovTextContext *m = avctx->priv_data;
m->readorder = 0;
}

AVCodec ff_movtext_decoder = {
.name = "mov_text",
.long_name = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
Expand All @@ -530,4 +530,5 @@ AVCodec ff_movtext_decoder = {
.init = mov_text_init,
.decode = mov_text_decode_frame,
.close = mov_text_decode_close,
.flush = mov_text_flush,
};
12 changes: 11 additions & 1 deletion libavcodec/movtextenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,16 +332,26 @@ static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
s->box_flags = 0;
s->style_entries = 0;
for (i = 0; i < sub->num_rects; i++) {
const char *ass = sub->rects[i]->ass;

if (sub->rects[i]->type != SUBTITLE_ASS) {
av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
return AVERROR(ENOSYS);
}

dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
if (!strncmp(ass, "Dialogue: ", 10)) {
dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
// TODO reindent
for (; dialog && num--; dialog++) {
ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
}
} else {
dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
if (!dialog)
return AVERROR(ENOMEM);
ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
ff_ass_free_dialog(&dialog);
}

for (j = 0; j < box_count; j++) {
box_types[j].encode(s, box_types[j].type);
Expand Down
8 changes: 4 additions & 4 deletions libavcodec/mpl2dec.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,11 @@ static int mpl2_decode_frame(AVCodecContext *avctx, void *data,
AVBPrint buf;
AVSubtitle *sub = data;
const char *ptr = avpkt->data;
const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
const int ts_duration = avpkt->duration != -1 ?
av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
FFASSDecoderContext *s = avctx->priv_data;

av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
if (ptr && avpkt->size > 0 && *ptr && !mpl2_event_to_ass(&buf, ptr))
ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_duration);
ret = ff_ass_add_rect(sub, buf.str, s->readorder++, 0, NULL, NULL);
av_bprint_finalize(&buf, NULL);
if (ret < 0)
return ret;
Expand All @@ -90,4 +88,6 @@ AVCodec ff_mpl2_decoder = {
.id = AV_CODEC_ID_MPL2,
.decode = mpl2_decode_frame,
.init = ff_ass_subtitle_header_default,
.flush = ff_ass_decoder_flush,
.priv_data_size = sizeof(FFASSDecoderContext),
};
3 changes: 3 additions & 0 deletions libavcodec/options_table.h
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,9 @@ static const AVOption avcodec_options[] = {
{"do_nothing", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_DO_NOTHING}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"},
{"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_AUTOMATIC}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"},
{"pre_decoder", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_PRE_DECODER}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"},
{"sub_text_format", "set decoded text subtitle format", OFFSET(sub_text_format), AV_OPT_TYPE_INT, {.i64 = FF_SUB_TEXT_FMT_ASS_WITH_TIMINGS}, 0, 1, S|D, "sub_text_format"},
{"ass", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_TEXT_FMT_ASS}, INT_MIN, INT_MAX, S|D, "sub_text_format"},
{"ass_with_timings", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_TEXT_FMT_ASS_WITH_TIMINGS}, INT_MIN, INT_MAX, S|D, "sub_text_format"},
{"refcounted_frames", NULL, OFFSET(refcounted_frames), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, A|V|D },
#if FF_API_SIDEDATA_ONLY_PKT
{"side_data_only_packets", NULL, OFFSET(side_data_only_packets), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, A|V|E },
Expand Down
7 changes: 4 additions & 3 deletions libavcodec/realtextdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,12 @@ static int realtext_decode_frame(AVCodecContext *avctx,
int ret = 0;
AVSubtitle *sub = data;
const char *ptr = avpkt->data;
FFASSDecoderContext *s = avctx->priv_data;
AVBPrint buf;

av_bprint_init(&buf, 0, 4096);
// note: no need to rescale pts & duration since they are in the same
// timebase as ASS (1/100)
if (ptr && avpkt->size > 0 && !rt_event_to_ass(&buf, ptr))
ret = ff_ass_add_rect_bprint(sub, &buf, avpkt->pts, avpkt->duration);
ret = ff_ass_add_rect(sub, buf.str, s->readorder++, 0, NULL, NULL);
av_bprint_finalize(&buf, NULL);
if (ret < 0)
return ret;
Expand All @@ -82,4 +81,6 @@ AVCodec ff_realtext_decoder = {
.id = AV_CODEC_ID_REALTEXT,
.decode = realtext_decode_frame,
.init = ff_ass_subtitle_header_default,
.flush = ff_ass_decoder_flush,
.priv_data_size = sizeof(FFASSDecoderContext),
};
14 changes: 10 additions & 4 deletions libavcodec/samidec.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ typedef struct {
AVBPrint encoded_source;
AVBPrint encoded_content;
AVBPrint full;
int readorder;
} SAMIContext;

static int sami_paragraph_to_ass(AVCodecContext *avctx, const char *src)
Expand Down Expand Up @@ -131,10 +132,8 @@ static int sami_decode_frame(AVCodecContext *avctx,
SAMIContext *sami = avctx->priv_data;

if (ptr && avpkt->size > 0 && !sami_paragraph_to_ass(avctx, ptr)) {
int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
int ts_duration = avpkt->duration != -1 ?
av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
int ret = ff_ass_add_rect_bprint(sub, &sami->full, ts_start, ts_duration);
// TODO: pass escaped sami->encoded_source.str as source
int ret = ff_ass_add_rect(sub, sami->full.str, sami->readorder++, 0, NULL, NULL);
if (ret < 0)
return ret;
}
Expand Down Expand Up @@ -164,6 +163,12 @@ static av_cold int sami_close(AVCodecContext *avctx)
return 0;
}

static void sami_flush(AVCodecContext *avctx)
{
SAMIContext *sami = avctx->priv_data;
sami->readorder = 0;
}

AVCodec ff_sami_decoder = {
.name = "sami",
.long_name = NULL_IF_CONFIG_SMALL("SAMI subtitle"),
Expand All @@ -173,4 +178,5 @@ AVCodec ff_sami_decoder = {
.init = sami_init,
.close = sami_close,
.decode = sami_decode_frame,
.flush = sami_flush,
};
17 changes: 7 additions & 10 deletions libavcodec/srtdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,10 @@ static int srt_decode_frame(AVCodecContext *avctx,
{
AVSubtitle *sub = data;
AVBPrint buffer;
int ts_start, ts_end, x1 = -1, y1 = -1, x2 = -1, y2 = -1;
int x1 = -1, y1 = -1, x2 = -1, y2 = -1;
int size, ret;
const uint8_t *p = av_packet_get_side_data(avpkt, AV_PKT_DATA_SUBTITLE_POSITION, &size);
FFASSDecoderContext *s = avctx->priv_data;

if (p && size == 16) {
x1 = AV_RL32(p );
Expand All @@ -73,16 +74,8 @@ static int srt_decode_frame(AVCodecContext *avctx,

av_bprint_init(&buffer, 0, AV_BPRINT_SIZE_UNLIMITED);

// Do final divide-by-10 outside rescale to force rounding down.
ts_start = av_rescale_q(avpkt->pts,
avctx->time_base,
(AVRational){1,100});
ts_end = av_rescale_q(avpkt->pts + avpkt->duration,
avctx->time_base,
(AVRational){1,100});

srt_to_ass(avctx, &buffer, avpkt->data, x1, y1, x2, y2);
ret = ff_ass_add_rect_bprint(sub, &buffer, ts_start, ts_end-ts_start);
ret = ff_ass_add_rect(sub, buffer.str, s->readorder++, 0, NULL, NULL);
av_bprint_finalize(&buffer, NULL);
if (ret < 0)
return ret;
Expand All @@ -100,6 +93,8 @@ AVCodec ff_srt_decoder = {
.id = AV_CODEC_ID_SUBRIP,
.init = ff_ass_subtitle_header_default,
.decode = srt_decode_frame,
.flush = ff_ass_decoder_flush,
.priv_data_size = sizeof(FFASSDecoderContext),
};
#endif

Expand All @@ -111,5 +106,7 @@ AVCodec ff_subrip_decoder = {
.id = AV_CODEC_ID_SUBRIP,
.init = ff_ass_subtitle_header_default,
.decode = srt_decode_frame,
.flush = ff_ass_decoder_flush,
.priv_data_size = sizeof(FFASSDecoderContext),
};
#endif
14 changes: 13 additions & 1 deletion libavcodec/srtenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,18 +237,30 @@ static int encode_frame(AVCodecContext *avctx,
av_bprint_clear(&s->buffer);

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

if (sub->rects[i]->type != SUBTITLE_ASS) {
av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
return AVERROR(ENOSYS);
}

dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
if (!strncmp(ass, "Dialogue: ", 10)) {
dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
// TODO reindent
for (; dialog && num--; dialog++) {
s->alignment_applied = 0;
srt_style_apply(s, dialog->style);
ff_ass_split_override_codes(cb, s, dialog->text);
}
} else {
dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
if (!dialog)
return AVERROR(ENOMEM);
s->alignment_applied = 0;
srt_style_apply(s, dialog->style);
ff_ass_split_override_codes(cb, s, dialog->text);
ff_ass_free_dialog(&dialog);
}
}

if (!av_bprint_is_complete(&s->buffer))
Expand Down
7 changes: 4 additions & 3 deletions libavcodec/subviewerdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,12 @@ static int subviewer_decode_frame(AVCodecContext *avctx,
int ret = 0;
AVSubtitle *sub = data;
const char *ptr = avpkt->data;
FFASSDecoderContext *s = avctx->priv_data;
AVBPrint buf;

av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
// note: no need to rescale pts & duration since they are in the same
// timebase as ASS (1/100)
if (ptr && avpkt->size > 0 && !subviewer_event_to_ass(&buf, ptr))
ret = ff_ass_add_rect_bprint(sub, &buf, avpkt->pts, avpkt->duration);
ret = ff_ass_add_rect(sub, buf.str, s->readorder++, 0, NULL, NULL);
av_bprint_finalize(&buf, NULL);
if (ret < 0)
return ret;
Expand All @@ -73,4 +72,6 @@ AVCodec ff_subviewer_decoder = {
.id = AV_CODEC_ID_SUBVIEWER,
.decode = subviewer_decode_frame,
.init = ff_ass_subtitle_header_default,
.flush = ff_ass_decoder_flush,
.priv_data_size = sizeof(FFASSDecoderContext),
};
19 changes: 14 additions & 5 deletions libavcodec/textdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ typedef struct {
AVClass *class;
const char *linebreaks;
int keep_ass_markup;
int readorder;
} TextContext;

#define OFFSET(x) offsetof(TextContext, x)
Expand All @@ -48,15 +49,12 @@ static int text_decode_frame(AVCodecContext *avctx, void *data,
AVBPrint buf;
AVSubtitle *sub = data;
const char *ptr = avpkt->data;
const TextContext *text = avctx->priv_data;
const int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
const int ts_duration = avpkt->duration != -1 ?
av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
TextContext *text = avctx->priv_data;

av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
if (ptr && avpkt->size > 0 && *ptr) {
ff_ass_bprint_text_event(&buf, ptr, avpkt->size, text->linebreaks, text->keep_ass_markup);
ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_duration);
ret = ff_ass_add_rect(sub, buf.str, text->readorder++, 0, NULL, NULL);
}
av_bprint_finalize(&buf, NULL);
if (ret < 0)
Expand All @@ -65,6 +63,12 @@ static int text_decode_frame(AVCodecContext *avctx, void *data,
return avpkt->size;
}

static void text_flush(AVCodecContext *avctx)
{
TextContext *text = avctx->priv_data;
text->readorder = 0;
}

#define DECLARE_CLASS(decname) static const AVClass decname ## _decoder_class = { \
.class_name = #decname " decoder", \
.item_name = av_default_item_name, \
Expand All @@ -85,6 +89,7 @@ AVCodec ff_text_decoder = {
.decode = text_decode_frame,
.init = ff_ass_subtitle_header_default,
.priv_class = &text_decoder_class,
.flush = text_flush,
};
#endif

Expand All @@ -110,6 +115,7 @@ AVCodec ff_vplayer_decoder = {
.decode = text_decode_frame,
.init = linebreak_init,
.priv_class = &vplayer_decoder_class,
.flush = text_flush,
};
#endif

Expand All @@ -126,6 +132,7 @@ AVCodec ff_stl_decoder = {
.decode = text_decode_frame,
.init = linebreak_init,
.priv_class = &stl_decoder_class,
.flush = text_flush,
};
#endif

Expand All @@ -142,6 +149,7 @@ AVCodec ff_pjs_decoder = {
.decode = text_decode_frame,
.init = linebreak_init,
.priv_class = &pjs_decoder_class,
.flush = text_flush,
};
#endif

Expand All @@ -158,6 +166,7 @@ AVCodec ff_subviewer1_decoder = {
.decode = text_decode_frame,
.init = linebreak_init,
.priv_class = &subviewer1_decoder_class,
.flush = text_flush,
};
#endif

Expand Down
74 changes: 74 additions & 0 deletions libavcodec/utils.c
Original file line number Diff line number Diff line change
Expand Up @@ -2426,6 +2426,76 @@ static int utf8_check(const uint8_t *str)
return 1;
}

static void insert_ts(AVBPrint *buf, int ts)
{
if (ts == -1) {
av_bprintf(buf, "9:59:59.99,");
} else {
int h, m, s;

h = ts/360000; ts -= 360000*h;
m = ts/ 6000; ts -= 6000*m;
s = ts/ 100; ts -= 100*s;
av_bprintf(buf, "%d:%02d:%02d.%02d,", h, m, s, ts);
}
}

static int convert_sub_to_old_ass_form(AVSubtitle *sub, const AVPacket *pkt, AVRational tb)
{
int i;
AVBPrint buf;

av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);

for (i = 0; i < sub->num_rects; i++) {
char *final_dialog;
const char *dialog;
AVSubtitleRect *rect = sub->rects[i];
int ts_start, ts_duration = -1;
long int layer;

if (rect->type != SUBTITLE_ASS || !strncmp(rect->ass, "Dialogue ", 10))
continue;

av_bprint_clear(&buf);

/* skip ReadOrder */
dialog = strchr(rect->ass, ',');
if (!dialog)
continue;
dialog++;

/* extract Layer or Marked */
layer = strtol(dialog, (char**)&dialog, 10);
if (*dialog != ',')
continue;
dialog++;

/* rescale timing to ASS time base (ms) */
ts_start = av_rescale_q(pkt->pts, tb, av_make_q(1, 100));
if (pkt->duration != -1)
ts_duration = av_rescale_q(pkt->duration, tb, av_make_q(1, 100));
sub->end_display_time = FFMAX(sub->end_display_time, 10 * ts_duration);

/* construct ASS (standalone file form with timestamps) string */
av_bprintf(&buf, "Dialogue: %ld,", layer);
insert_ts(&buf, ts_start);
insert_ts(&buf, ts_duration == -1 ? -1 : ts_start + ts_duration);
av_bprintf(&buf, "%s\r\n", dialog);

final_dialog = av_strdup(buf.str);
if (!av_bprint_is_complete(&buf) || !final_dialog) {
av_bprint_finalize(&buf, NULL);
return AVERROR(ENOMEM);
}
av_freep(&rect->ass);
rect->ass = final_dialog;
}

av_bprint_finalize(&buf, NULL);
return 0;
}

int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
int *got_sub_ptr,
AVPacket *avpkt)
Expand Down Expand Up @@ -2476,6 +2546,10 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub,
av_assert1((ret >= 0) >= !!*got_sub_ptr &&
!!*got_sub_ptr >= !!sub->num_rects);

if (avctx->sub_text_format == FF_SUB_TEXT_FMT_ASS_WITH_TIMINGS
&& *got_sub_ptr && sub->num_rects)
ret = convert_sub_to_old_ass_form(sub, avpkt, avctx->time_base);

if (sub->num_rects && !sub->end_display_time && avpkt->duration &&
avctx->pkt_timebase.num) {
AVRational ms = { 1, 1000 };
Expand Down
4 changes: 2 additions & 2 deletions libavcodec/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
#include "libavutil/version.h"

#define LIBAVCODEC_VERSION_MAJOR 57
#define LIBAVCODEC_VERSION_MINOR 25
#define LIBAVCODEC_VERSION_MICRO 101
#define LIBAVCODEC_VERSION_MINOR 26
#define LIBAVCODEC_VERSION_MICRO 100

#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
Expand Down
11 changes: 5 additions & 6 deletions libavcodec/webvttdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,15 +85,12 @@ static int webvtt_decode_frame(AVCodecContext *avctx,
int ret = 0;
AVSubtitle *sub = data;
const char *ptr = avpkt->data;
FFASSDecoderContext *s = avctx->priv_data;
AVBPrint buf;

av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
if (ptr && avpkt->size > 0 && !webvtt_event_to_ass(&buf, ptr)) {
int ts_start = av_rescale_q(avpkt->pts, avctx->time_base, (AVRational){1,100});
int ts_duration = avpkt->duration != -1 ?
av_rescale_q(avpkt->duration, avctx->time_base, (AVRational){1,100}) : -1;
ret = ff_ass_add_rect_bprint(sub, &buf, ts_start, ts_duration);
}
if (ptr && avpkt->size > 0 && !webvtt_event_to_ass(&buf, ptr))
ret = ff_ass_add_rect(sub, buf.str, s->readorder++, 0, NULL, NULL);
av_bprint_finalize(&buf, NULL);
if (ret < 0)
return ret;
Expand All @@ -108,4 +105,6 @@ AVCodec ff_webvtt_decoder = {
.id = AV_CODEC_ID_WEBVTT,
.decode = webvtt_decode_frame,
.init = ff_ass_subtitle_header_default,
.flush = ff_ass_decoder_flush,
.priv_data_size = sizeof(FFASSDecoderContext),
};
14 changes: 13 additions & 1 deletion libavcodec/webvttenc.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,16 +164,28 @@ static int webvtt_encode_frame(AVCodecContext *avctx,
av_bprint_clear(&s->buffer);

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

if (sub->rects[i]->type != SUBTITLE_ASS) {
av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
return AVERROR(ENOSYS);
}

dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
if (!strncmp(ass, "Dialogue: ", 10)) {
dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
// TODO reindent
for (; dialog && num--; dialog++) {
webvtt_style_apply(s, dialog->style);
ff_ass_split_override_codes(&webvtt_callbacks, s, dialog->text);
}
} else {
dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
if (!dialog)
return AVERROR(ENOMEM);
webvtt_style_apply(s, dialog->style);
ff_ass_split_override_codes(&webvtt_callbacks, s, dialog->text);
ff_ass_free_dialog(&dialog);
}
}

if (!av_bprint_is_complete(&s->buffer))
Expand Down
2 changes: 2 additions & 0 deletions tests/ref/fate/api-mjpeg-codec-param
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ stream=0, decode=0
pkt_timebase=1/25
sub_charenc=
sub_charenc_mode=0x00000000
sub_text_format=1
refcounted_frames=false
side_data_only_packets=true
skip_alpha=false
Expand Down Expand Up @@ -300,6 +301,7 @@ stream=0, decode=1
pkt_timebase=1/25
sub_charenc=
sub_charenc_mode=0x00000000
sub_text_format=1
refcounted_frames=false
side_data_only_packets=true
skip_alpha=false
Expand Down
2 changes: 2 additions & 0 deletions tests/ref/fate/api-png-codec-param
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ stream=0, decode=0
pkt_timebase=1/25
sub_charenc=
sub_charenc_mode=0x00000000
sub_text_format=1
refcounted_frames=false
side_data_only_packets=true
skip_alpha=false
Expand Down Expand Up @@ -300,6 +301,7 @@ stream=0, decode=1
pkt_timebase=1/25
sub_charenc=
sub_charenc_mode=0x00000000
sub_text_format=1
refcounted_frames=false
side_data_only_packets=true
skip_alpha=false
Expand Down