]> git.sesse.net Git - ffmpeg/blob - libavcodec/libzvbi-teletextdec.c
avcodec: Constify AVCodecs
[ffmpeg] / libavcodec / libzvbi-teletextdec.c
1 /*
2  * Teletext decoding for ffmpeg
3  * Copyright (c) 2005-2010, 2012 Wolfram Gloger
4  * Copyright (c) 2013 Marton Balint
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20
21 #include "avcodec.h"
22 #include "libavcodec/ass.h"
23 #include "libavcodec/dvbtxt.h"
24 #include "libavutil/opt.h"
25 #include "libavutil/bprint.h"
26 #include "libavutil/internal.h"
27 #include "libavutil/intreadwrite.h"
28 #include "libavutil/log.h"
29 #include "libavutil/common.h"
30
31 #include <libzvbi.h>
32
33 #define TEXT_MAXSZ    (25 * (56 + 1) * 4 + 2)
34 #define VBI_NB_COLORS 40
35 #define VBI_TRANSPARENT_BLACK 8
36 #define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
37 #define VBI_R(rgba)   (((rgba) >> 0) & 0xFF)
38 #define VBI_G(rgba)   (((rgba) >> 8) & 0xFF)
39 #define VBI_B(rgba)   (((rgba) >> 16) & 0xFF)
40 #define VBI_A(rgba)   (((rgba) >> 24) & 0xFF)
41 #define MAX_BUFFERED_PAGES 25
42 #define BITMAP_CHAR_WIDTH  12
43 #define BITMAP_CHAR_HEIGHT 10
44 #define MAX_SLICES 64
45
46 typedef struct TeletextPage
47 {
48     AVSubtitleRect *sub_rect;
49     int pgno;
50     int subno;
51     int64_t pts;
52 } TeletextPage;
53
54 typedef struct TeletextContext
55 {
56     AVClass        *class;
57     char           *pgno;
58     int             default_region;
59     int             x_offset;
60     int             y_offset;
61     int             format_id; /* 0 = bitmap, 1 = text/ass, 2 = ass */
62     int             chop_top;
63     int             sub_duration; /* in msec */
64     int             transparent_bg;
65     int             opacity;
66     int             chop_spaces;
67
68     int             lines_processed;
69     TeletextPage    *pages;
70     int             nb_pages;
71     int64_t         pts;
72     int             handler_ret;
73
74     vbi_decoder *   vbi;
75     vbi_sliced      sliced[MAX_SLICES];
76
77     int             readorder;
78     uint8_t         subtitle_map[2048];
79     int             last_pgno;
80     int             last_p5;
81     int             last_ass_alignment;
82 } TeletextContext;
83
84 static int my_ass_subtitle_header(AVCodecContext *avctx)
85 {
86     int ret = ff_ass_subtitle_header_default(avctx);
87     char *new_header;
88     uint8_t *event_pos;
89
90     if (ret < 0)
91         return ret;
92
93     event_pos = strstr(avctx->subtitle_header, "\r\n[Events]\r\n");
94     if (!event_pos)
95         return AVERROR_BUG;
96
97     new_header = av_asprintf("%.*s%s%s",
98         (int)(event_pos - avctx->subtitle_header), avctx->subtitle_header,
99         "Style: "
100         "Teletext,"            /* Name */
101         "Monospace,11,"        /* Font{name,size} */
102         "&Hffffff,&Hffffff,&H0,&H0," /* {Primary,Secondary,Outline,Back}Colour */
103         "0,0,0,0,"             /* Bold, Italic, Underline, StrikeOut */
104         "160,100,"             /* Scale{X,Y} */
105         "0,0,"                 /* Spacing, Angle */
106         "3,0.1,0,"             /* BorderStyle, Outline, Shadow */
107         "5,1,1,1,"             /* Alignment, Margin[LRV] */
108         "0\r\n"                /* Encoding */
109         "Style: "
110         "Subtitle,"            /* Name */
111         "Monospace,16,"        /* Font{name,size} */
112         "&Hffffff,&Hffffff,&H0,&H0," /* {Primary,Secondary,Outline,Back}Colour */
113         "0,0,0,0,"             /* Bold, Italic, Underline, StrikeOut */
114         "100,100,"             /* Scale{X,Y} */
115         "0,0,"                 /* Spacing, Angle */
116         "1,1,1,"               /* BorderStyle, Outline, Shadow */
117         "8,48,48,20,"          /* Alignment, Margin[LRV] */
118         "0\r\n"                /* Encoding */
119         , event_pos);
120
121     if (!new_header)
122         return AVERROR(ENOMEM);
123
124     av_free(avctx->subtitle_header);
125     avctx->subtitle_header = new_header;
126     avctx->subtitle_header_size = strlen(new_header);
127     return 0;
128 }
129
130 static int chop_spaces_utf8(const unsigned char* t, int len)
131 {
132     t += len;
133     while (len > 0) {
134         if (*--t != ' ' || (len-1 > 0 && *(t-1) & 0x80))
135             break;
136         --len;
137     }
138     return len;
139 }
140
141 static void subtitle_rect_free(AVSubtitleRect **sub_rect)
142 {
143     av_freep(&(*sub_rect)->data[0]);
144     av_freep(&(*sub_rect)->data[1]);
145     av_freep(&(*sub_rect)->ass);
146     av_freep(sub_rect);
147 }
148
149 static char *create_ass_text(TeletextContext *ctx, const char *text)
150 {
151     char *dialog;
152     AVBPrint buf;
153
154     av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
155     ff_ass_bprint_text_event(&buf, text, strlen(text), "", 0);
156     if (!av_bprint_is_complete(&buf)) {
157         av_bprint_finalize(&buf, NULL);
158         return NULL;
159     }
160     dialog = ff_ass_get_dialog(ctx->readorder++, 0, NULL, NULL, buf.str);
161     av_bprint_finalize(&buf, NULL);
162     return dialog;
163 }
164
165 /* Draw a page as text */
166 static int gen_sub_text(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top)
167 {
168     const char *in;
169     AVBPrint buf;
170     char *vbi_text = av_malloc(TEXT_MAXSZ);
171     int sz;
172
173     if (!vbi_text)
174         return AVERROR(ENOMEM);
175
176     sz = vbi_print_page_region(page, vbi_text, TEXT_MAXSZ-1, "UTF-8",
177                                    /*table mode*/ TRUE, FALSE,
178                                    0,             chop_top,
179                                    page->columns, page->rows-chop_top);
180     if (sz <= 0) {
181         av_log(ctx, AV_LOG_ERROR, "vbi_print error\n");
182         av_free(vbi_text);
183         return AVERROR_EXTERNAL;
184     }
185     vbi_text[sz] = '\0';
186     in  = vbi_text;
187     av_bprint_init(&buf, 0, TEXT_MAXSZ);
188
189     if (ctx->chop_spaces) {
190         for (;;) {
191             int nl, sz;
192
193             // skip leading spaces and newlines
194             in += strspn(in, " \n");
195             // compute end of row
196             for (nl = 0; in[nl]; ++nl)
197                 if (in[nl] == '\n' && (nl==0 || !(in[nl-1] & 0x80)))
198                     break;
199             if (!in[nl])
200                 break;
201             // skip trailing spaces
202             sz = chop_spaces_utf8(in, nl);
203             av_bprint_append_data(&buf, in, sz);
204             av_bprintf(&buf, "\n");
205             in += nl;
206         }
207     } else {
208         av_bprintf(&buf, "%s\n", vbi_text);
209     }
210     av_free(vbi_text);
211
212     if (!av_bprint_is_complete(&buf)) {
213         av_bprint_finalize(&buf, NULL);
214         return AVERROR(ENOMEM);
215     }
216
217     if (buf.len) {
218         sub_rect->type = SUBTITLE_ASS;
219         sub_rect->ass = create_ass_text(ctx, buf.str);
220
221         if (!sub_rect->ass) {
222             av_bprint_finalize(&buf, NULL);
223             return AVERROR(ENOMEM);
224         }
225         av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", sub_rect->ass);
226     } else {
227         sub_rect->type = SUBTITLE_NONE;
228     }
229     av_bprint_finalize(&buf, NULL);
230     return 0;
231 }
232
233 static void bprint_color(const char *type, AVBPrint *buf, vbi_page *page, unsigned ci)
234 {
235     int r = VBI_R(page->color_map[ci]);
236     int g = VBI_G(page->color_map[ci]);
237     int b = VBI_B(page->color_map[ci]);
238     av_bprintf(buf, "{\\%s&H%02X%02X%02X&}", type, b, g, r);
239 }
240
241 #define IS_TXT_SPACE(ch) ((ch).unicode < 0x0020 || (ch).unicode >= 0xe000 || (ch).unicode == 0x00a0 ||\
242                           (ch).size > VBI_DOUBLE_SIZE || (ch).opacity == VBI_TRANSPARENT_SPACE)
243
244 static void get_trim_info(vbi_page *page, vbi_char *row, int *leading, int *trailing, int *olen)
245 {
246     int i, len = 0;
247     int char_seen = 0;
248
249     *leading = 0;
250
251     for (i = 0; i < page->columns; i++) {
252         uint16_t out = IS_TXT_SPACE(row[i]) ? 32 : row[i].unicode;
253
254         if (out == 32 && !char_seen)
255             (*leading)++;
256         else if (out != 32)
257             char_seen = 1, len = i - (*leading) + 1;
258     }
259
260     *olen = len;
261     *trailing = len > 0 ? page->columns - *leading - len : page->columns;
262 }
263
264 static void decode_string(vbi_page *page, vbi_char *row, AVBPrint *buf,
265                           int start, int end, vbi_color *cur_color, vbi_color *cur_back_color)
266 {
267     int i;
268
269     for (i = start; i < end; i++) {
270         uint16_t out = IS_TXT_SPACE(row[i]) ? 32 : row[i].unicode;
271
272         if (*cur_color != row[i].foreground) {
273             bprint_color("c", buf, page, row[i].foreground);
274             *cur_color = row[i].foreground;
275         }
276         if (*cur_back_color != row[i].background) {
277             bprint_color("3c", buf, page, row[i].background);
278             *cur_back_color = row[i].background;
279         }
280
281         if (out == 32) {
282             av_bprintf(buf, "\\h");
283         } else if (out == '\\' || out == '{' || out == '}') {
284             av_bprintf(buf, "\\%c", (char)out);
285         } else {
286             char tmp;
287             /* convert to utf-8 */
288             PUT_UTF8(out, tmp, av_bprint_chars(buf, tmp, 1););
289         }
290     }
291 }
292
293 /* Draw a page as ass formatted text */
294 static int gen_sub_ass(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top)
295 {
296     int i;
297     int leading, trailing, len;
298     int last_trailing = -1, last_leading = -1;
299     int min_trailing = page->columns, min_leading = page->columns;
300     int alignment = 2;
301     int vertical_align = -1;
302     int can_align_left = 1, can_align_right = 1, can_align_center = 1;
303     int is_subtitle_page = ctx->subtitle_map[page->pgno & 0x7ff];
304     int empty_lines = 0;
305     vbi_color cur_color = VBI_WHITE;
306     vbi_color cur_back_color = VBI_BLACK;
307     AVBPrint buf;
308
309     av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
310
311     for (i = chop_top; i < page->rows; i++) {
312         vbi_char *row = page->text + i * page->columns;
313
314         get_trim_info(page, row, &leading, &trailing, &len);
315
316         if (len) {
317             if (last_leading != -1 && last_leading != leading || leading > 5)
318                 can_align_left = 0;
319             if (last_trailing != -1 && last_trailing != trailing || trailing > 2)
320                 can_align_right = 0;
321             if (last_trailing != -1 && (FFABS((trailing - leading) - (last_trailing - last_leading)) > 1) || trailing - leading > 4)
322                 can_align_center = 0;
323             last_leading = leading;
324             last_trailing = trailing;
325             min_leading = FFMIN(leading, min_leading);
326             min_trailing = FFMIN(trailing, min_trailing);
327         }
328     }
329
330     if (!can_align_right && can_align_left && !can_align_center) {
331         ctx->last_ass_alignment = alignment = 1;
332     } else if (!can_align_right && !can_align_left && can_align_center) {
333         ctx->last_ass_alignment = alignment = 2;
334     } else if (can_align_right && !can_align_left && !can_align_center) {
335         ctx->last_ass_alignment = alignment = 3;
336     } else {
337         if (ctx->last_ass_alignment == 1 && can_align_left ||
338             ctx->last_ass_alignment == 2 && can_align_center ||
339             ctx->last_ass_alignment == 3 && can_align_right)
340             alignment = ctx->last_ass_alignment;
341     }
342
343     for (i = chop_top; i < page->rows; i++) {
344         int j;
345         vbi_char *row = page->text + i * page->columns;
346         int is_transparent_line;
347
348         for (j = 0; j < page->columns; j++)
349             if (row[j].opacity != VBI_TRANSPARENT_SPACE)
350                 break;
351         is_transparent_line = (j == page->columns);
352
353         len = is_transparent_line ? 0 : page->columns;
354         leading = trailing = is_transparent_line ? page->columns : 0;
355
356         if (is_subtitle_page) {
357             if (!is_transparent_line)
358                 get_trim_info(page, row, &leading, &trailing, &len);
359
360             if (vertical_align == -1 && len) {
361                 vertical_align = (2 - (av_clip(i + 1, 0, 23) / 8));
362                 av_bprintf(&buf, "{\\an%d}", alignment + vertical_align * 3);
363                 if (vertical_align != 2)
364                     empty_lines = 0;
365             }
366
367             if (len && empty_lines > 1)
368                 for (empty_lines /= 2; empty_lines > 0; empty_lines--)
369                     av_bprintf(&buf, " \\N");
370
371             if (alignment == 1 || alignment == 2 && !can_align_center)
372                 leading = min_leading;
373             if (alignment == 3 || alignment == 2 && !can_align_center)
374                 trailing = min_trailing;
375         }
376
377         if (len || !is_subtitle_page) {
378             decode_string(page, row, &buf, leading, page->columns - trailing, &cur_color, &cur_back_color);
379             av_bprintf(&buf, " \\N");
380             empty_lines = 0;
381         } else {
382             empty_lines++;
383         }
384     }
385
386     if (vertical_align == 0)
387         for (empty_lines = (empty_lines - 1) / 2; empty_lines > 0; empty_lines--)
388             av_bprintf(&buf, " \\N");
389
390     if (!av_bprint_is_complete(&buf)) {
391         av_bprint_finalize(&buf, NULL);
392         return AVERROR(ENOMEM);
393     }
394
395     if (buf.len) {
396         sub_rect->type = SUBTITLE_ASS;
397         sub_rect->ass = ff_ass_get_dialog(ctx->readorder++, 0, is_subtitle_page ? "Subtitle" : "Teletext", NULL, buf.str);
398
399         if (!sub_rect->ass) {
400             av_bprint_finalize(&buf, NULL);
401             return AVERROR(ENOMEM);
402         }
403         av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", sub_rect->ass);
404     } else {
405         sub_rect->type = SUBTITLE_NONE;
406     }
407     av_bprint_finalize(&buf, NULL);
408     return 0;
409 }
410
411 static void fix_transparency(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page,
412                              int chop_top, int resx, int resy)
413 {
414     int iy;
415
416     // Hack for transparency, inspired by VLC code...
417     for (iy = 0; iy < resy; iy++) {
418         uint8_t *pixel = sub_rect->data[0] + iy * sub_rect->linesize[0];
419         vbi_char *vc = page->text + (iy / BITMAP_CHAR_HEIGHT + chop_top) * page->columns;
420         vbi_char *vcnext = vc + page->columns;
421         for (; vc < vcnext; vc++) {
422             uint8_t *pixelnext = pixel + BITMAP_CHAR_WIDTH;
423             switch (vc->opacity) {
424                 case VBI_TRANSPARENT_SPACE:
425                     memset(pixel, VBI_TRANSPARENT_BLACK, BITMAP_CHAR_WIDTH);
426                     break;
427                 case VBI_OPAQUE:
428                     if (!ctx->transparent_bg)
429                         break;
430                 case VBI_SEMI_TRANSPARENT:
431                     if (ctx->opacity > 0) {
432                         if (ctx->opacity < 255)
433                             for(; pixel < pixelnext; pixel++)
434                                 if (*pixel == vc->background)
435                                     *pixel += VBI_NB_COLORS;
436                         break;
437                     }
438                 case VBI_TRANSPARENT_FULL:
439                     for(; pixel < pixelnext; pixel++)
440                         if (*pixel == vc->background)
441                             *pixel = VBI_TRANSPARENT_BLACK;
442                     break;
443             }
444             pixel = pixelnext;
445         }
446     }
447 }
448
449 /* Draw a page as bitmap */
450 static int gen_sub_bitmap(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top)
451 {
452     int resx = page->columns * BITMAP_CHAR_WIDTH;
453     int resy = (page->rows - chop_top) * BITMAP_CHAR_HEIGHT;
454     uint8_t ci;
455     vbi_char *vc = page->text + (chop_top * page->columns);
456     vbi_char *vcend = page->text + (page->rows * page->columns);
457
458     for (; vc < vcend; vc++) {
459         if (vc->opacity != VBI_TRANSPARENT_SPACE)
460             break;
461     }
462
463     if (vc >= vcend) {
464         av_log(ctx, AV_LOG_DEBUG, "dropping empty page %3x\n", page->pgno);
465         sub_rect->type = SUBTITLE_NONE;
466         return 0;
467     }
468
469     sub_rect->data[0] = av_mallocz(resx * resy);
470     sub_rect->linesize[0] = resx;
471     if (!sub_rect->data[0])
472         return AVERROR(ENOMEM);
473
474     vbi_draw_vt_page_region(page, VBI_PIXFMT_PAL8,
475                             sub_rect->data[0], sub_rect->linesize[0],
476                             0, chop_top, page->columns, page->rows - chop_top,
477                             /*reveal*/ 1, /*flash*/ 1);
478
479     fix_transparency(ctx, sub_rect, page, chop_top, resx, resy);
480     sub_rect->x = ctx->x_offset;
481     sub_rect->y = ctx->y_offset + chop_top * BITMAP_CHAR_HEIGHT;
482     sub_rect->w = resx;
483     sub_rect->h = resy;
484     sub_rect->nb_colors = ctx->opacity > 0 && ctx->opacity < 255 ? 2 * VBI_NB_COLORS : VBI_NB_COLORS;
485     sub_rect->data[1] = av_mallocz(AVPALETTE_SIZE);
486     if (!sub_rect->data[1]) {
487         av_freep(&sub_rect->data[0]);
488         return AVERROR(ENOMEM);
489     }
490     for (ci = 0; ci < VBI_NB_COLORS; ci++) {
491         int r, g, b, a;
492
493         r = VBI_R(page->color_map[ci]);
494         g = VBI_G(page->color_map[ci]);
495         b = VBI_B(page->color_map[ci]);
496         a = VBI_A(page->color_map[ci]);
497         ((uint32_t *)sub_rect->data[1])[ci] = RGBA(r, g, b, a);
498         ((uint32_t *)sub_rect->data[1])[ci + VBI_NB_COLORS] = RGBA(r, g, b, ctx->opacity);
499         ff_dlog(ctx, "palette %0x\n", ((uint32_t *)sub_rect->data[1])[ci]);
500     }
501     ((uint32_t *)sub_rect->data[1])[VBI_TRANSPARENT_BLACK] = RGBA(0, 0, 0, 0);
502     ((uint32_t *)sub_rect->data[1])[VBI_TRANSPARENT_BLACK + VBI_NB_COLORS] = RGBA(0, 0, 0, 0);
503     sub_rect->type = SUBTITLE_BITMAP;
504     return 0;
505 }
506
507 static void handler(vbi_event *ev, void *user_data)
508 {
509     TeletextContext *ctx = user_data;
510     TeletextPage *new_pages;
511     vbi_page page;
512     int res;
513     char pgno_str[12];
514     int chop_top;
515     int is_subtitle_page = ctx->subtitle_map[ev->ev.ttx_page.pgno & 0x7ff];
516
517     snprintf(pgno_str, sizeof pgno_str, "%03x", ev->ev.ttx_page.pgno);
518     av_log(ctx, AV_LOG_DEBUG, "decoded page %s.%02x\n",
519            pgno_str, ev->ev.ttx_page.subno & 0xFF);
520
521     if (strcmp(ctx->pgno, "*") && (strcmp(ctx->pgno, "subtitle") || !is_subtitle_page) && !strstr(ctx->pgno, pgno_str))
522         return;
523     if (ctx->handler_ret < 0)
524         return;
525
526     res = vbi_fetch_vt_page(ctx->vbi, &page,
527                             ev->ev.ttx_page.pgno,
528                             ev->ev.ttx_page.subno,
529                             VBI_WST_LEVEL_3p5, 25, TRUE);
530
531     if (!res)
532         return;
533
534     chop_top = ctx->chop_top || ((page.rows > 1) && is_subtitle_page);
535
536     av_log(ctx, AV_LOG_DEBUG, "%d x %d page chop:%d\n",
537            page.columns, page.rows, chop_top);
538
539     if (ctx->nb_pages < MAX_BUFFERED_PAGES) {
540         if ((new_pages = av_realloc_array(ctx->pages, ctx->nb_pages + 1, sizeof(TeletextPage)))) {
541             TeletextPage *cur_page = new_pages + ctx->nb_pages;
542             ctx->pages = new_pages;
543             cur_page->sub_rect = av_mallocz(sizeof(*cur_page->sub_rect));
544             cur_page->pts = ctx->pts;
545             cur_page->pgno = ev->ev.ttx_page.pgno;
546             cur_page->subno = ev->ev.ttx_page.subno;
547             if (cur_page->sub_rect) {
548                 switch (ctx->format_id) {
549                     case 0:
550                         res = gen_sub_bitmap(ctx, cur_page->sub_rect, &page, chop_top);
551                         break;
552                     case 1:
553                         res = gen_sub_text(ctx, cur_page->sub_rect, &page, chop_top);
554                         break;
555                     case 2:
556                         res = gen_sub_ass(ctx, cur_page->sub_rect, &page, chop_top);
557                         break;
558                     default:
559                         res = AVERROR_BUG;
560                         break;
561                 }
562                 if (res < 0) {
563                     av_freep(&cur_page->sub_rect);
564                     ctx->handler_ret = res;
565                 } else {
566                     ctx->pages[ctx->nb_pages++] = *cur_page;
567                 }
568             } else {
569                 ctx->handler_ret = AVERROR(ENOMEM);
570             }
571         } else {
572             ctx->handler_ret = AVERROR(ENOMEM);
573         }
574     } else {
575         //TODO: If multiple packets contain more than one page, pages may got queued up, and this may happen...
576         av_log(ctx, AV_LOG_ERROR, "Buffered too many pages, dropping page %s.\n", pgno_str);
577         ctx->handler_ret = AVERROR(ENOSYS);
578     }
579
580     vbi_unref_page(&page);
581 }
582
583 static int slice_to_vbi_lines(TeletextContext *ctx, uint8_t* buf, int size)
584 {
585     int lines = 0;
586     while (size >= 2 && lines < MAX_SLICES) {
587         int data_unit_id     = buf[0];
588         int data_unit_length = buf[1];
589         if (data_unit_length + 2 > size)
590             return AVERROR_INVALIDDATA;
591         if (ff_data_unit_id_is_teletext(data_unit_id)) {
592             if (data_unit_length != 0x2c)
593                 return AVERROR_INVALIDDATA;
594             else {
595                 int line_offset  = buf[2] & 0x1f;
596                 int field_parity = buf[2] & 0x20;
597                 uint8_t *p = ctx->sliced[lines].data;
598                 int i, pmag;
599                 ctx->sliced[lines].id = VBI_SLICED_TELETEXT_B;
600                 ctx->sliced[lines].line = (line_offset > 0 ? (line_offset + (field_parity ? 0 : 313)) : 0);
601                 for (i = 0; i < 42; i++)
602                     p[i] = vbi_rev8(buf[4 + i]);
603                 /* Unfortunately libzvbi does not expose page flags, and
604                  * vbi_classify_page only checks MIP, so we have to manually
605                  * decode the page flags and store the results. */
606                 pmag = vbi_unham16p(p);
607                 if (pmag >= 0 && pmag >> 3 == 0) {   // We found a row 0 header
608                     int page = vbi_unham16p(p + 2);
609                     int flags1 = vbi_unham16p(p + 6);
610                     int flags2 = vbi_unham16p(p + 8);
611                     if (page >= 0 && flags1 >= 0 && flags2 >= 0) {
612                         int pgno = ((pmag & 7) << 8) + page;
613                         // Check for disabled NEWSFLASH flag and enabled SUBTITLE and SUPRESS_HEADER flags
614                         ctx->subtitle_map[pgno] = (!(flags1 & 0x40) && flags1 & 0x80 && flags2 & 0x01);
615                         // Propagate ERASE_PAGE flag for repeated page headers to work around a libzvbi bug
616                         if (ctx->subtitle_map[pgno] && pgno == ctx->last_pgno) {
617                             int last_byte9 = vbi_unham8(ctx->last_p5);
618                             if (last_byte9 >= 0 && last_byte9 & 0x8) {
619                                 int byte9 = vbi_unham8(p[5]);
620                                 if (byte9 >= 0)
621                                     p[5] = vbi_ham8(byte9 | 0x8);
622                             }
623                         }
624                         ctx->last_pgno = pgno;
625                         ctx->last_p5 = p[5];
626                     }
627                 }
628                 lines++;
629             }
630         }
631         size -= data_unit_length + 2;
632         buf += data_unit_length + 2;
633     }
634     if (size)
635         av_log(ctx, AV_LOG_WARNING, "%d bytes remained after slicing data\n", size);
636     return lines;
637 }
638
639 static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *got_sub_ptr, AVPacket *pkt)
640 {
641     TeletextContext *ctx = avctx->priv_data;
642     AVSubtitle      *sub = data;
643     int             ret = 0;
644
645     if (!ctx->vbi) {
646         if (!(ctx->vbi = vbi_decoder_new()))
647             return AVERROR(ENOMEM);
648         if (ctx->default_region != -1) {
649             av_log(avctx, AV_LOG_INFO, "Setting default zvbi region to %i\n", ctx->default_region);
650             vbi_teletext_set_default_region(ctx->vbi, ctx->default_region);
651         }
652         if (!vbi_event_handler_register(ctx->vbi, VBI_EVENT_TTX_PAGE, handler, ctx)) {
653             vbi_decoder_delete(ctx->vbi);
654             ctx->vbi = NULL;
655             return AVERROR(ENOMEM);
656         }
657     }
658
659     if (avctx->pkt_timebase.num && pkt->pts != AV_NOPTS_VALUE)
660         ctx->pts = av_rescale_q(pkt->pts, avctx->pkt_timebase, AV_TIME_BASE_Q);
661
662     if (pkt->size) {
663         int lines;
664         const int full_pes_size = pkt->size + 45; /* PES header is 45 bytes */
665
666         // We allow unreasonably big packets, even if the standard only allows a max size of 1472
667         if (full_pes_size < 184 || full_pes_size > 65504 || full_pes_size % 184 != 0)
668             return AVERROR_INVALIDDATA;
669
670         ctx->handler_ret = pkt->size;
671
672         if (ff_data_identifier_is_teletext(*pkt->data)) {
673             if ((lines = slice_to_vbi_lines(ctx, pkt->data + 1, pkt->size - 1)) < 0)
674                 return lines;
675             ff_dlog(avctx, "ctx=%p buf_size=%d lines=%u pkt_pts=%7.3f\n",
676                     ctx, pkt->size, lines, (double)pkt->pts/90000.0);
677             if (lines > 0) {
678                 vbi_decode(ctx->vbi, ctx->sliced, lines, 0.0);
679                 ctx->lines_processed += lines;
680             }
681         }
682         ctx->pts = AV_NOPTS_VALUE;
683         ret = ctx->handler_ret;
684     }
685
686     if (ret < 0)
687         return ret;
688
689     // is there a subtitle to pass?
690     if (ctx->nb_pages) {
691         int i;
692         sub->format = !!ctx->format_id;
693         sub->start_display_time = 0;
694         sub->end_display_time = ctx->sub_duration;
695         sub->num_rects = 0;
696         sub->pts = ctx->pages->pts;
697
698         if (ctx->pages->sub_rect->type != SUBTITLE_NONE) {
699             sub->rects = av_malloc(sizeof(*sub->rects));
700             if (sub->rects) {
701                 sub->num_rects = 1;
702                 sub->rects[0] = ctx->pages->sub_rect;
703             } else {
704                 ret = AVERROR(ENOMEM);
705             }
706         } else {
707             av_log(avctx, AV_LOG_DEBUG, "sending empty sub\n");
708             sub->rects = NULL;
709         }
710         if (!sub->rects) // no rect was passed
711             subtitle_rect_free(&ctx->pages->sub_rect);
712
713         for (i = 0; i < ctx->nb_pages - 1; i++)
714             ctx->pages[i] = ctx->pages[i + 1];
715         ctx->nb_pages--;
716
717         if (ret >= 0)
718             *got_sub_ptr = 1;
719     } else
720         *got_sub_ptr = 0;
721
722     return ret;
723 }
724
725 static int teletext_init_decoder(AVCodecContext *avctx)
726 {
727     TeletextContext *ctx = avctx->priv_data;
728     unsigned int maj, min, rev;
729
730     vbi_version(&maj, &min, &rev);
731     if (!(maj > 0 || min > 2 || min == 2 && rev >= 26)) {
732         av_log(avctx, AV_LOG_ERROR, "decoder needs zvbi version >= 0.2.26.\n");
733         return AVERROR_EXTERNAL;
734     }
735
736     if (ctx->format_id == 0) {
737         avctx->width  = 41 * BITMAP_CHAR_WIDTH;
738         avctx->height = 25 * BITMAP_CHAR_HEIGHT;
739     }
740
741     ctx->vbi = NULL;
742     ctx->pts = AV_NOPTS_VALUE;
743     ctx->last_pgno = -1;
744     ctx->last_ass_alignment = 2;
745
746     if (ctx->opacity == -1)
747         ctx->opacity = ctx->transparent_bg ? 0 : 255;
748
749     av_log(avctx, AV_LOG_VERBOSE, "page filter: %s\n", ctx->pgno);
750
751     switch (ctx->format_id) {
752         case 0:
753             return 0;
754         case 1:
755             return ff_ass_subtitle_header_default(avctx);
756         case 2:
757             return my_ass_subtitle_header(avctx);
758     }
759     return AVERROR_BUG;
760 }
761
762 static int teletext_close_decoder(AVCodecContext *avctx)
763 {
764     TeletextContext *ctx = avctx->priv_data;
765
766     ff_dlog(avctx, "lines_total=%u\n", ctx->lines_processed);
767     while (ctx->nb_pages)
768         subtitle_rect_free(&ctx->pages[--ctx->nb_pages].sub_rect);
769     av_freep(&ctx->pages);
770
771     vbi_decoder_delete(ctx->vbi);
772     ctx->vbi = NULL;
773     ctx->pts = AV_NOPTS_VALUE;
774     ctx->last_pgno = -1;
775     ctx->last_ass_alignment = 2;
776     memset(ctx->subtitle_map, 0, sizeof(ctx->subtitle_map));
777     if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP))
778         ctx->readorder = 0;
779     return 0;
780 }
781
782 static void teletext_flush(AVCodecContext *avctx)
783 {
784     teletext_close_decoder(avctx);
785 }
786
787 #define OFFSET(x) offsetof(TeletextContext, x)
788 #define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
789 static const AVOption options[] = {
790     {"txt_page",        "page numbers to decode, subtitle for subtitles, * for all", OFFSET(pgno),   AV_OPT_TYPE_STRING, {.str = "*"},      0, 0,        SD},
791     {"txt_default_region", "default G0 character set used for decoding",     OFFSET(default_region), AV_OPT_TYPE_INT,    {.i64 = -1},      -1, 87,       SD},
792     {"txt_chop_top",    "discards the top teletext line",                    OFFSET(chop_top),       AV_OPT_TYPE_INT,    {.i64 = 1},        0, 1,        SD},
793     {"txt_format",      "format of the subtitles (bitmap or text or ass)",   OFFSET(format_id),      AV_OPT_TYPE_INT,    {.i64 = 0},        0, 2,        SD,  "txt_format"},
794     {"bitmap",          NULL,                                                0,                      AV_OPT_TYPE_CONST,  {.i64 = 0},        0, 0,        SD,  "txt_format"},
795     {"text",            NULL,                                                0,                      AV_OPT_TYPE_CONST,  {.i64 = 1},        0, 0,        SD,  "txt_format"},
796     {"ass",             NULL,                                                0,                      AV_OPT_TYPE_CONST,  {.i64 = 2},        0, 0,        SD,  "txt_format"},
797     {"txt_left",        "x offset of generated bitmaps",                     OFFSET(x_offset),       AV_OPT_TYPE_INT,    {.i64 = 0},        0, 65535,    SD},
798     {"txt_top",         "y offset of generated bitmaps",                     OFFSET(y_offset),       AV_OPT_TYPE_INT,    {.i64 = 0},        0, 65535,    SD},
799     {"txt_chop_spaces", "chops leading and trailing spaces from text",       OFFSET(chop_spaces),    AV_OPT_TYPE_INT,    {.i64 = 1},        0, 1,        SD},
800     {"txt_duration",    "display duration of teletext pages in msecs",       OFFSET(sub_duration),   AV_OPT_TYPE_INT,    {.i64 = -1},      -1, 86400000, SD},
801     {"txt_transparent", "force transparent background of the teletext",      OFFSET(transparent_bg), AV_OPT_TYPE_INT,    {.i64 = 0},        0, 1,        SD},
802     {"txt_opacity",     "set opacity of the transparent background",         OFFSET(opacity),        AV_OPT_TYPE_INT,    {.i64 = -1},      -1, 255,      SD},
803     { NULL },
804 };
805
806 static const AVClass teletext_class = {
807     .class_name = "libzvbi_teletextdec",
808     .item_name  = av_default_item_name,
809     .option     = options,
810     .version    = LIBAVUTIL_VERSION_INT,
811 };
812
813 const AVCodec ff_libzvbi_teletext_decoder = {
814     .name      = "libzvbi_teletextdec",
815     .long_name = NULL_IF_CONFIG_SMALL("Libzvbi DVB teletext decoder"),
816     .type      = AVMEDIA_TYPE_SUBTITLE,
817     .id        = AV_CODEC_ID_DVB_TELETEXT,
818     .priv_data_size = sizeof(TeletextContext),
819     .init      = teletext_init_decoder,
820     .close     = teletext_close_decoder,
821     .decode    = teletext_decode_frame,
822     .capabilities = AV_CODEC_CAP_DELAY,
823     .flush     = teletext_flush,
824     .priv_class= &teletext_class,
825     .wrapper_name = "libzvbi",
826 };