[FFmpeg-devel] [PATCH 02/11] libzvbi-teletextdec: support multiple teletext pages in a single packet
Marton Balint
cus at passwd.hu
Thu Oct 31 21:28:48 CET 2013
After this patch, if a packet contains multiple teletext pages, the teletext
decoder can return the fist page and store the remaining pages in memory, and
return them to the user on the next calls to avcodec_decode_subtitle2.
Signed-off-by: Marton Balint <cus at passwd.hu>
---
libavcodec/libzvbi-teletextdec.c | 101 ++++++++++++++++++++++++++++-----------
1 file changed, 74 insertions(+), 27 deletions(-)
diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c
index 8b504b5..1ebe6ca 100644
--- a/libavcodec/libzvbi-teletextdec.c
+++ b/libavcodec/libzvbi-teletextdec.c
@@ -31,6 +31,15 @@
#define VBI_G(rgba) (((rgba) >> 8) & 0xFF)
#define VBI_B(rgba) (((rgba) >> 16) & 0xFF)
#define VBI_A(rgba) (((rgba) >> 24) & 0xFF)
+#define MAX_BUFFERED_PAGES 25
+
+typedef struct TeletextPage
+{
+ AVSubtitleRect *sub_rect;
+ int pgno;
+ int subno;
+ int64_t pts;
+} TeletextPage;
/* main data structure */
typedef struct TeletextContext
@@ -47,7 +56,9 @@ typedef struct TeletextContext
int chop_spaces;
int lines_processed;
- AVSubtitleRect *sub_rect;
+ TeletextPage *pages;
+ int nb_pages;
+ int64_t pts;
vbi_decoder * vbi;
vbi_dvb_demux * dx;
@@ -72,11 +83,19 @@ chop_spaces_utf8(const unsigned char* t, int len)
return len;
}
+static void
+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);
+}
+
// draw a page as text
static int
-gen_sub_text(TeletextContext *ctx, vbi_page *page, int chop_top)
+gen_sub_text(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top)
{
- AVSubtitleRect *sub_rect = ctx->sub_rect;
char *text;
const char *in;
char *out;
@@ -140,9 +159,8 @@ gen_sub_text(TeletextContext *ctx, vbi_page *page, int chop_top)
}
static void
-fix_transparency(TeletextContext *ctx, vbi_page *page, int chop_top, uint8_t transparent_color, int resx, int resy)
+fix_transparency(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top, uint8_t transparent_color, int resx, int resy)
{
- AVSubtitleRect *sub_rect = ctx->sub_rect;
int iy;
// Hack for transparency, inspired by VLC code...
@@ -173,9 +191,8 @@ fix_transparency(TeletextContext *ctx, vbi_page *page, int chop_top, uint8_t tra
// draw a page as bitmap
static int
-gen_sub_bitmap(TeletextContext *ctx, vbi_page *page, int chop_top)
+gen_sub_bitmap(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top)
{
- AVSubtitleRect *sub_rect = ctx->sub_rect;
int resx = page->columns * 12;
int resy = (page->rows - chop_top) * 10;
uint8_t ci, cmax = 0;
@@ -206,7 +223,7 @@ gen_sub_bitmap(TeletextContext *ctx, vbi_page *page, int chop_top)
0, chop_top, page->columns, page->rows - chop_top,
/*reveal*/ 1, /*flash*/ 1);
- fix_transparency(ctx, page, chop_top, cmax, resx, resy);
+ fix_transparency(ctx, sub_rect, page, chop_top, cmax, resx, resy);
sub_rect->x = ctx->x_offset;
sub_rect->y = ctx->y_offset;
sub_rect->w = resx;
@@ -239,6 +256,7 @@ static void
handler(vbi_event *ev, void *user_data)
{
TeletextContext *ctx = user_data;
+ TeletextPage *new_pages;
vbi_page page;
int res;
char pgno_str[12];
@@ -279,18 +297,29 @@ handler(vbi_event *ev, void *user_data)
av_log(ctx, AV_LOG_DEBUG, "%d x %d page chop:%d\n",
page.columns, page.rows, chop_top);
- if (!ctx->sub_rect) {
- ctx->sub_rect = av_mallocz(sizeof(*ctx->sub_rect));
- if (ctx->sub_rect) {
- res = (ctx->format_id == 0) ?
- gen_sub_bitmap(ctx, &page, chop_top) :
- gen_sub_text (ctx, &page, chop_top);
- if (res)
- av_freep(&ctx->sub_rect);
+ if (ctx->nb_pages < MAX_BUFFERED_PAGES) {
+ if ((new_pages = av_realloc_array(ctx->pages, ctx->nb_pages + 1, sizeof(TeletextPage)))) {
+ TeletextPage *cur_page = new_pages + ctx->nb_pages;
+ ctx->pages = new_pages;
+ cur_page->sub_rect = av_mallocz(sizeof(*cur_page->sub_rect));
+ cur_page->pts = ctx->pts;
+ cur_page->pgno = ev->ev.ttx_page.pgno;
+ cur_page->subno = ev->ev.ttx_page.subno;
+ if (cur_page->sub_rect) {
+ res = (ctx->format_id == 0) ?
+ gen_sub_bitmap(ctx, cur_page->sub_rect, &page, chop_top) :
+ gen_sub_text (ctx, cur_page->sub_rect, &page, chop_top);
+ if (res)
+ av_freep(&cur_page->sub_rect);
+ else
+ ctx->pages[ctx->nb_pages++] = *cur_page;
+ }
+ } else {
+ av_log(ctx, AV_LOG_ERROR, "Failed to allocate memory to to buffer pages\n");
}
} else {
- // FIXME: Multiple teletext pages in a single packet, some kind of buffering should be done instead of dropping the page...
- av_log(ctx, AV_LOG_WARNING, "Missed page %s.%02x.\n", pgno_str, ev->ev.ttx_page.subno & 0xFF);
+ //TODO: If multiple packets contain more than one page, pages may got queued up, and this may happen...
+ av_log(ctx, AV_LOG_ERROR, "Buffered too many pages, dropping page %s.\n", pgno_str);
}
vbi_unref_page(&page);
@@ -304,10 +333,11 @@ teletext_decode_frame(AVCodecContext *avctx,
TeletextContext *ctx = avctx->priv_data;
AVSubtitle *sub = data;
const uint8_t *buf = pkt->data;
- unsigned int left = pkt->size;
+ int left = pkt->size;
uint8_t pesheader[45] = {0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x85, 0x80, 0x24, 0x21, 0x00, 0x01, 0x00, 0x01};
int pesheader_size = sizeof(pesheader);
const uint8_t *pesheader_buf = pesheader;
+ int ret = 0;
if (!ctx->vbi) {
if (!(ctx->vbi = vbi_decoder_new()))
@@ -321,6 +351,10 @@ teletext_decode_frame(AVCodecContext *avctx,
if (!ctx->dx && (!(ctx->dx = vbi_dvb_pes_demux_new (/* callback */ NULL, NULL))))
return AVERROR(ENOMEM);
+ if (avctx->pkt_timebase.den && pkt->pts != AV_NOPTS_VALUE)
+ ctx->pts = av_rescale_q(pkt->pts, avctx->pkt_timebase, AV_TIME_BASE_Q);
+
+ if (left) {
// We allow unreasonably big packets, even if the standard only allows a max size of 1472
if ((pesheader_size + left) < 184 || (pesheader_size + left) > 65504 || (pesheader_size + left) % 184 != 0)
return AVERROR_INVALIDDATA;
@@ -352,33 +386,41 @@ teletext_decode_frame(AVCodecContext *avctx,
ctx->lines_processed += lines;
}
}
+ ctx->pts = AV_NOPTS_VALUE;
+ ret = pkt->size;
+ }
// is there a subtitle to pass?
- if (ctx->sub_rect) {
- sub->format = (ctx->sub_rect->type == SUBTITLE_TEXT ? 1: 0);
+ if (ctx->nb_pages) {
+ int i;
+ sub->format = (ctx->pages->sub_rect->type == SUBTITLE_TEXT ? 1: 0);
sub->start_display_time = 0;
sub->end_display_time = ctx->sub_duration;
sub->num_rects = 0;
+ sub->pts = ctx->pages->pts;
- if (ctx->sub_rect->type != SUBTITLE_NONE) {
+ if (ctx->pages->sub_rect->type != SUBTITLE_NONE) {
sub->rects = av_malloc(sizeof(*sub->rects) * 1);
if (sub->rects) {
sub->num_rects = 1;
- sub->rects[0] = ctx->sub_rect;
+ sub->rects[0] = ctx->pages->sub_rect;
}
} else {
av_log(avctx, AV_LOG_DEBUG, "sending empty sub\n");
sub->rects = NULL;
}
if (!sub->rects) // no rect was passed
- av_free(ctx->sub_rect);
- ctx->sub_rect = NULL;
+ subtitle_rect_free(&ctx->pages->sub_rect);
+
+ for (i = 0; i < ctx->nb_pages - 1; i++)
+ ctx->pages[i] = ctx->pages[i + 1];
+ ctx->nb_pages--;
*data_size = 1;
} else
*data_size = 0;
- return pkt->size;
+ return ret;
}
static int teletext_init_decoder(AVCodecContext *avctx)
@@ -394,7 +436,7 @@ static int teletext_init_decoder(AVCodecContext *avctx)
ctx->dx = NULL;
ctx->vbi = NULL;
- ctx->sub_rect = NULL;
+ ctx->pts = AV_NOPTS_VALUE;
if (!strcmp(ctx->format, "bitmap")) {
ctx->format_id = 0;
} else if (!strcmp(ctx->format, "text")) {
@@ -421,11 +463,15 @@ static int teletext_close_decoder(AVCodecContext *avctx)
#ifdef DEBUG
av_log(avctx, AV_LOG_DEBUG, "lines_total=%u\n", ctx->lines_processed);
#endif
+ while (ctx->nb_pages)
+ subtitle_rect_free(&ctx->pages[--ctx->nb_pages].sub_rect);
+ av_freep(&ctx->pages);
vbi_dvb_demux_delete(ctx->dx);
vbi_decoder_delete(ctx->vbi);
ctx->dx = NULL;
ctx->vbi = NULL;
+ ctx->pts = AV_NOPTS_VALUE;
return 0;
}
@@ -464,6 +510,7 @@ AVCodec ff_libzvbi_teletext_decoder = {
.init = teletext_init_decoder,
.close = teletext_close_decoder,
.decode = teletext_decode_frame,
+ .capabilities = CODEC_CAP_DELAY,
.flush = teletext_flush,
.priv_class= &teletext_class,
};
--
1.8.1.4
More information about the ffmpeg-devel
mailing list