|
|
|
@ -19,6 +19,7 @@ |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include "avcodec.h" |
|
|
|
|
#include "libavcodec/ass.h" |
|
|
|
|
#include "libavutil/opt.h" |
|
|
|
|
#include "libavutil/bprint.h" |
|
|
|
|
#include "libavutil/intreadwrite.h" |
|
|
|
@ -49,7 +50,7 @@ typedef struct TeletextContext |
|
|
|
|
char *pgno; |
|
|
|
|
int x_offset; |
|
|
|
|
int y_offset; |
|
|
|
|
int format_id; /* 0 = bitmap, 1 = text */ |
|
|
|
|
int format_id; /* 0 = bitmap, 1 = text/ass */ |
|
|
|
|
int chop_top; |
|
|
|
|
int sub_duration; /* in msec */ |
|
|
|
|
int transparent_bg; |
|
|
|
@ -88,10 +89,43 @@ subtitle_rect_free(AVSubtitleRect **sub_rect) |
|
|
|
|
{ |
|
|
|
|
av_freep(&(*sub_rect)->pict.data[0]); |
|
|
|
|
av_freep(&(*sub_rect)->pict.data[1]); |
|
|
|
|
av_freep(&(*sub_rect)->text); |
|
|
|
|
av_freep(&(*sub_rect)->ass); |
|
|
|
|
av_freep(sub_rect); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int |
|
|
|
|
create_ass_text(TeletextContext *ctx, const char *text, char **ass) |
|
|
|
|
{ |
|
|
|
|
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}); |
|
|
|
|
|
|
|
|
|
/* 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); |
|
|
|
|
|
|
|
|
|
if (!av_bprint_is_complete(&buf)) { |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* 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); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// draw a page as text
|
|
|
|
|
static int |
|
|
|
|
gen_sub_text(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top) |
|
|
|
@ -147,14 +181,16 @@ gen_sub_text(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int |
|
|
|
|
|
|
|
|
|
if (buf.len) { |
|
|
|
|
int ret; |
|
|
|
|
sub_rect->type = SUBTITLE_TEXT; |
|
|
|
|
if ((ret = av_bprint_finalize(&buf, &sub_rect->text)) < 0) |
|
|
|
|
sub_rect->type = SUBTITLE_ASS; |
|
|
|
|
if ((ret = create_ass_text(ctx, buf.str, &sub_rect->ass)) < 0) { |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
return ret; |
|
|
|
|
av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", sub_rect->text); |
|
|
|
|
} |
|
|
|
|
av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", sub_rect->ass); |
|
|
|
|
} else { |
|
|
|
|
sub_rect->type = SUBTITLE_NONE; |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
} |
|
|
|
|
av_bprint_finalize(&buf, NULL); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -393,7 +429,7 @@ teletext_decode_frame(AVCodecContext *avctx, |
|
|
|
|
// is there a subtitle to pass?
|
|
|
|
|
if (ctx->nb_pages) { |
|
|
|
|
int i; |
|
|
|
|
sub->format = (ctx->pages->sub_rect->type == SUBTITLE_TEXT ? 1: 0); |
|
|
|
|
sub->format = ctx->format_id; |
|
|
|
|
sub->start_display_time = 0; |
|
|
|
|
sub->end_display_time = ctx->sub_duration; |
|
|
|
|
sub->num_rects = 0; |
|
|
|
@ -445,7 +481,7 @@ static int teletext_init_decoder(AVCodecContext *avctx) |
|
|
|
|
} |
|
|
|
|
#endif |
|
|
|
|
av_log(avctx, AV_LOG_VERBOSE, "page filter: %s\n", ctx->pgno); |
|
|
|
|
return 0; |
|
|
|
|
return (ctx->format_id == 1) ? ff_ass_subtitle_header_default(avctx) : 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int teletext_close_decoder(AVCodecContext *avctx) |
|
|
|
|