~ubuntu-branches/ubuntu/vivid/ffmpeg/vivid

« back to all changes in this revision

Viewing changes to libavcodec/libzvbi-teletextdec.c

  • Committer: Package Import Robot
  • Author(s): Andreas Cadhalpun
  • Date: 2014-11-05 01:18:23 UTC
  • mfrom: (0.2.17 sid)
  • Revision ID: package-import@ubuntu.com-20141105011823-xsbeceffs43wtkn7
Tags: 7:2.4.3-1
* Import new upstream bugfix release 2.4.3.
   - Refresh Change-symbol-versioning.patch.
   - Add new symbols to the libavdevice symbols file.
* Enable libbs2b on arm64, since it is now available.
* Disable frei0r and libx264 on x32, libsoxr and openal on sparc64
  and libopencv on m68k, sh4, sparc64 and x32, because they are not
  (yet) avialable there.
* Disable assembler optimizations on x32, as they wouldn't work there.
* Include config.log in the build-log, when compiling fails.
* Add fix-hppa-tests.patch to work around a gcc bug on hppa.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 "libavutil/opt.h"
 
24
#include "libavutil/bprint.h"
 
25
#include "libavutil/intreadwrite.h"
 
26
#include "libavutil/log.h"
 
27
 
 
28
#include <libzvbi.h>
 
29
 
 
30
#define TEXT_MAXSZ    (25 * (56 + 1) * 4 + 2)
 
31
#define VBI_NB_COLORS 40
 
32
#define RGBA(r,g,b,a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
 
33
#define VBI_R(rgba)   (((rgba) >> 0) & 0xFF)
 
34
#define VBI_G(rgba)   (((rgba) >> 8) & 0xFF)
 
35
#define VBI_B(rgba)   (((rgba) >> 16) & 0xFF)
 
36
#define VBI_A(rgba)   (((rgba) >> 24) & 0xFF)
 
37
#define MAX_BUFFERED_PAGES 25
 
38
#define BITMAP_CHAR_WIDTH  12
 
39
#define BITMAP_CHAR_HEIGHT 10
 
40
#define MAX_SLICES 64
 
41
 
 
42
typedef struct TeletextPage
 
43
{
 
44
    AVSubtitleRect *sub_rect;
 
45
    int pgno;
 
46
    int subno;
 
47
    int64_t pts;
 
48
} TeletextPage;
 
49
 
 
50
typedef struct TeletextContext
 
51
{
 
52
    AVClass        *class;
 
53
    char           *pgno;
 
54
    int             x_offset;
 
55
    int             y_offset;
 
56
    int             format_id; /* 0 = bitmap, 1 = text/ass */
 
57
    int             chop_top;
 
58
    int             sub_duration; /* in msec */
 
59
    int             transparent_bg;
 
60
    int             chop_spaces;
 
61
 
 
62
    int             lines_processed;
 
63
    TeletextPage    *pages;
 
64
    int             nb_pages;
 
65
    int64_t         pts;
 
66
    int             handler_ret;
 
67
 
 
68
    vbi_decoder *   vbi;
 
69
#ifdef DEBUG
 
70
    vbi_export *    ex;
 
71
#endif
 
72
    vbi_sliced      sliced[MAX_SLICES];
 
73
} TeletextContext;
 
74
 
 
75
static int chop_spaces_utf8(const unsigned char* t, int len)
 
76
{
 
77
    t += len;
 
78
    while (len > 0) {
 
79
        if (*--t != ' ' || (len-1 > 0 && *(t-1) & 0x80))
 
80
            break;
 
81
        --len;
 
82
    }
 
83
    return len;
 
84
}
 
85
 
 
86
static void subtitle_rect_free(AVSubtitleRect **sub_rect)
 
87
{
 
88
    av_freep(&(*sub_rect)->pict.data[0]);
 
89
    av_freep(&(*sub_rect)->pict.data[1]);
 
90
    av_freep(&(*sub_rect)->ass);
 
91
    av_freep(sub_rect);
 
92
}
 
93
 
 
94
static int create_ass_text(TeletextContext *ctx, const char *text, char **ass)
 
95
{
 
96
    int ret;
 
97
    AVBPrint buf, buf2;
 
98
    const int ts_start    = av_rescale_q(ctx->pts,          AV_TIME_BASE_Q,        (AVRational){1, 100});
 
99
    const int ts_duration = av_rescale_q(ctx->sub_duration, (AVRational){1, 1000}, (AVRational){1, 100});
 
100
 
 
101
    /* First we escape the plain text into buf. */
 
102
    av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED);
 
103
    ff_ass_bprint_text_event(&buf, text, strlen(text), "", 0);
 
104
 
 
105
    if (!av_bprint_is_complete(&buf)) {
 
106
        av_bprint_finalize(&buf, NULL);
 
107
        return AVERROR(ENOMEM);
 
108
    }
 
109
 
 
110
    /* Then we create the ass dialog line in buf2 from the escaped text in buf. */
 
111
    av_bprint_init(&buf2, 0, AV_BPRINT_SIZE_UNLIMITED);
 
112
    ff_ass_bprint_dialog(&buf2, buf.str, ts_start, ts_duration, 0);
 
113
    av_bprint_finalize(&buf, NULL);
 
114
 
 
115
    if (!av_bprint_is_complete(&buf2)) {
 
116
        av_bprint_finalize(&buf2, NULL);
 
117
        return AVERROR(ENOMEM);
 
118
    }
 
119
 
 
120
    if ((ret = av_bprint_finalize(&buf2, ass)) < 0)
 
121
        return ret;
 
122
 
 
123
    return 0;
 
124
}
 
125
 
 
126
/* Draw a page as text */
 
127
static int gen_sub_text(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top)
 
128
{
 
129
    const char *in;
 
130
    AVBPrint buf;
 
131
    char *vbi_text = av_malloc(TEXT_MAXSZ);
 
132
    int sz;
 
133
 
 
134
    if (!vbi_text)
 
135
        return AVERROR(ENOMEM);
 
136
 
 
137
    sz = vbi_print_page_region(page, vbi_text, TEXT_MAXSZ-1, "UTF-8",
 
138
                                   /*table mode*/ TRUE, FALSE,
 
139
                                   0,             chop_top,
 
140
                                   page->columns, page->rows-chop_top);
 
141
    if (sz <= 0) {
 
142
        av_log(ctx, AV_LOG_ERROR, "vbi_print error\n");
 
143
        av_free(vbi_text);
 
144
        return AVERROR_EXTERNAL;
 
145
    }
 
146
    vbi_text[sz] = '\0';
 
147
    in  = vbi_text;
 
148
    av_bprint_init(&buf, 0, TEXT_MAXSZ);
 
149
 
 
150
    if (ctx->chop_spaces) {
 
151
        for (;;) {
 
152
            int nl, sz;
 
153
 
 
154
            // skip leading spaces and newlines
 
155
            in += strspn(in, " \n");
 
156
            // compute end of row
 
157
            for (nl = 0; in[nl]; ++nl)
 
158
                if (in[nl] == '\n' && (nl==0 || !(in[nl-1] & 0x80)))
 
159
                    break;
 
160
            if (!in[nl])
 
161
                break;
 
162
            // skip trailing spaces
 
163
            sz = chop_spaces_utf8(in, nl);
 
164
            av_bprint_append_data(&buf, in, sz);
 
165
            av_bprintf(&buf, "\n");
 
166
            in += nl;
 
167
        }
 
168
    } else {
 
169
        av_bprintf(&buf, "%s\n", vbi_text);
 
170
    }
 
171
    av_free(vbi_text);
 
172
 
 
173
    if (!av_bprint_is_complete(&buf)) {
 
174
        av_bprint_finalize(&buf, NULL);
 
175
        return AVERROR(ENOMEM);
 
176
    }
 
177
 
 
178
    if (buf.len) {
 
179
        int ret;
 
180
        sub_rect->type = SUBTITLE_ASS;
 
181
        if ((ret = create_ass_text(ctx, buf.str, &sub_rect->ass)) < 0) {
 
182
            av_bprint_finalize(&buf, NULL);
 
183
            return ret;
 
184
        }
 
185
        av_log(ctx, AV_LOG_DEBUG, "subtext:%s:txetbus\n", sub_rect->ass);
 
186
    } else {
 
187
        sub_rect->type = SUBTITLE_NONE;
 
188
    }
 
189
    av_bprint_finalize(&buf, NULL);
 
190
    return 0;
 
191
}
 
192
 
 
193
static void fix_transparency(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page,
 
194
                             int chop_top, uint8_t transparent_color, int resx, int resy)
 
195
{
 
196
    int iy;
 
197
 
 
198
    // Hack for transparency, inspired by VLC code...
 
199
    for (iy = 0; iy < resy; iy++) {
 
200
        uint8_t *pixel = sub_rect->pict.data[0] + iy * sub_rect->pict.linesize[0];
 
201
        vbi_char *vc = page->text + (iy / BITMAP_CHAR_HEIGHT + chop_top) * page->columns;
 
202
        vbi_char *vcnext = vc + page->columns;
 
203
        for (; vc < vcnext; vc++) {
 
204
            uint8_t *pixelnext = pixel + BITMAP_CHAR_WIDTH;
 
205
            switch (vc->opacity) {
 
206
                case VBI_TRANSPARENT_SPACE:
 
207
                    memset(pixel, transparent_color, BITMAP_CHAR_WIDTH);
 
208
                    break;
 
209
                case VBI_OPAQUE:
 
210
                case VBI_SEMI_TRANSPARENT:
 
211
                    if (!ctx->transparent_bg)
 
212
                        break;
 
213
                case VBI_TRANSPARENT_FULL:
 
214
                    for(; pixel < pixelnext; pixel++)
 
215
                        if (*pixel == vc->background)
 
216
                            *pixel = transparent_color;
 
217
                    break;
 
218
            }
 
219
            pixel = pixelnext;
 
220
        }
 
221
    }
 
222
}
 
223
 
 
224
/* Draw a page as bitmap */
 
225
static int gen_sub_bitmap(TeletextContext *ctx, AVSubtitleRect *sub_rect, vbi_page *page, int chop_top)
 
226
{
 
227
    int resx = page->columns * BITMAP_CHAR_WIDTH;
 
228
    int resy = (page->rows - chop_top) * BITMAP_CHAR_HEIGHT;
 
229
    uint8_t ci, cmax = 0;
 
230
    int ret;
 
231
    vbi_char *vc = page->text + (chop_top * page->columns);
 
232
    vbi_char *vcend = page->text + (page->rows * page->columns);
 
233
 
 
234
    for (; vc < vcend; vc++) {
 
235
        if (vc->opacity != VBI_TRANSPARENT_SPACE) {
 
236
            cmax = VBI_NB_COLORS;
 
237
            break;
 
238
        }
 
239
    }
 
240
 
 
241
    if (cmax == 0) {
 
242
        av_log(ctx, AV_LOG_DEBUG, "dropping empty page %3x\n", page->pgno);
 
243
        sub_rect->type = SUBTITLE_NONE;
 
244
        return 0;
 
245
    }
 
246
 
 
247
    if ((ret = avpicture_alloc(&sub_rect->pict, AV_PIX_FMT_PAL8, resx, resy)) < 0)
 
248
        return ret;
 
249
    // Yes, we want to allocate the palette on our own because AVSubtitle works this way
 
250
    sub_rect->pict.data[1] = NULL;
 
251
 
 
252
    vbi_draw_vt_page_region(page, VBI_PIXFMT_PAL8,
 
253
                            sub_rect->pict.data[0], sub_rect->pict.linesize[0],
 
254
                            0, chop_top, page->columns, page->rows - chop_top,
 
255
                            /*reveal*/ 1, /*flash*/ 1);
 
256
 
 
257
    fix_transparency(ctx, sub_rect, page, chop_top, cmax, resx, resy);
 
258
    sub_rect->x = ctx->x_offset;
 
259
    sub_rect->y = ctx->y_offset + chop_top * BITMAP_CHAR_HEIGHT;
 
260
    sub_rect->w = resx;
 
261
    sub_rect->h = resy;
 
262
    sub_rect->nb_colors = (int)cmax + 1;
 
263
    sub_rect->pict.data[1] = av_mallocz(AVPALETTE_SIZE);
 
264
    if (!sub_rect->pict.data[1]) {
 
265
        av_freep(&sub_rect->pict.data[0]);
 
266
        return AVERROR(ENOMEM);
 
267
    }
 
268
    for (ci = 0; ci < cmax; ci++) {
 
269
        int r, g, b, a;
 
270
 
 
271
        r = VBI_R(page->color_map[ci]);
 
272
        g = VBI_G(page->color_map[ci]);
 
273
        b = VBI_B(page->color_map[ci]);
 
274
        a = VBI_A(page->color_map[ci]);
 
275
        ((uint32_t *)sub_rect->pict.data[1])[ci] = RGBA(r, g, b, a);
 
276
        av_dlog(ctx, "palette %0x\n", ((uint32_t *)sub_rect->pict.data[1])[ci]);
 
277
    }
 
278
    ((uint32_t *)sub_rect->pict.data[1])[cmax] = RGBA(0, 0, 0, 0);
 
279
    sub_rect->type = SUBTITLE_BITMAP;
 
280
    return 0;
 
281
}
 
282
 
 
283
static void handler(vbi_event *ev, void *user_data)
 
284
{
 
285
    TeletextContext *ctx = user_data;
 
286
    TeletextPage *new_pages;
 
287
    vbi_page page;
 
288
    int res;
 
289
    char pgno_str[12];
 
290
    vbi_subno subno;
 
291
    vbi_page_type vpt;
 
292
    int chop_top;
 
293
    char *lang;
 
294
 
 
295
    snprintf(pgno_str, sizeof pgno_str, "%03x", ev->ev.ttx_page.pgno);
 
296
    av_log(ctx, AV_LOG_DEBUG, "decoded page %s.%02x\n",
 
297
           pgno_str, ev->ev.ttx_page.subno & 0xFF);
 
298
 
 
299
    if (strcmp(ctx->pgno, "*") && !strstr(ctx->pgno, pgno_str))
 
300
        return;
 
301
    if (ctx->handler_ret < 0)
 
302
        return;
 
303
 
 
304
    res = vbi_fetch_vt_page(ctx->vbi, &page,
 
305
                            ev->ev.ttx_page.pgno,
 
306
                            ev->ev.ttx_page.subno,
 
307
                            VBI_WST_LEVEL_3p5, 25, TRUE);
 
308
 
 
309
    if (!res)
 
310
        return;
 
311
 
 
312
#ifdef DEBUG
 
313
    fprintf(stderr, "\nSaving res=%d dy0=%d dy1=%d...\n",
 
314
            res, page.dirty.y0, page.dirty.y1);
 
315
    fflush(stderr);
 
316
 
 
317
    if (!vbi_export_stdio(ctx->ex, stderr, &page))
 
318
        fprintf(stderr, "failed: %s\n", vbi_export_errstr(ctx->ex));
 
319
#endif
 
320
 
 
321
    vpt = vbi_classify_page(ctx->vbi, ev->ev.ttx_page.pgno, &subno, &lang);
 
322
    chop_top = ctx->chop_top ||
 
323
        ((page.rows > 1) && (vpt == VBI_SUBTITLE_PAGE));
 
324
 
 
325
    av_log(ctx, AV_LOG_DEBUG, "%d x %d page chop:%d\n",
 
326
           page.columns, page.rows, chop_top);
 
327
 
 
328
    if (ctx->nb_pages < MAX_BUFFERED_PAGES) {
 
329
        if ((new_pages = av_realloc_array(ctx->pages, ctx->nb_pages + 1, sizeof(TeletextPage)))) {
 
330
            TeletextPage *cur_page = new_pages + ctx->nb_pages;
 
331
            ctx->pages = new_pages;
 
332
            cur_page->sub_rect = av_mallocz(sizeof(*cur_page->sub_rect));
 
333
            cur_page->pts = ctx->pts;
 
334
            cur_page->pgno = ev->ev.ttx_page.pgno;
 
335
            cur_page->subno = ev->ev.ttx_page.subno;
 
336
            if (cur_page->sub_rect) {
 
337
                res = (ctx->format_id == 0) ?
 
338
                    gen_sub_bitmap(ctx, cur_page->sub_rect, &page, chop_top) :
 
339
                    gen_sub_text  (ctx, cur_page->sub_rect, &page, chop_top);
 
340
                if (res < 0) {
 
341
                    av_freep(&cur_page->sub_rect);
 
342
                    ctx->handler_ret = res;
 
343
                } else {
 
344
                    ctx->pages[ctx->nb_pages++] = *cur_page;
 
345
                }
 
346
            } else {
 
347
                ctx->handler_ret = AVERROR(ENOMEM);
 
348
            }
 
349
        } else {
 
350
            ctx->handler_ret = AVERROR(ENOMEM);
 
351
        }
 
352
    } else {
 
353
        //TODO: If multiple packets contain more than one page, pages may got queued up, and this may happen...
 
354
        av_log(ctx, AV_LOG_ERROR, "Buffered too many pages, dropping page %s.\n", pgno_str);
 
355
        ctx->handler_ret = AVERROR(ENOSYS);
 
356
    }
 
357
 
 
358
    vbi_unref_page(&page);
 
359
}
 
360
 
 
361
static inline int data_identifier_is_teletext(int data_identifier) {
 
362
    /* See EN 301 775 section 4.4.2. */
 
363
    return (data_identifier >= 0x10 && data_identifier <= 0x1F ||
 
364
            data_identifier >= 0x99 && data_identifier <= 0x9B);
 
365
}
 
366
 
 
367
static int slice_to_vbi_lines(TeletextContext *ctx, uint8_t* buf, int size)
 
368
{
 
369
    int lines = 0;
 
370
    while (size >= 2 && lines < MAX_SLICES) {
 
371
        int data_unit_id     = buf[0];
 
372
        int data_unit_length = buf[1];
 
373
        if (data_unit_length + 2 > size)
 
374
            return AVERROR_INVALIDDATA;
 
375
        if (data_unit_id == 0x02 || data_unit_id == 0x03) {
 
376
            if (data_unit_length != 0x2c)
 
377
                return AVERROR_INVALIDDATA;
 
378
            else {
 
379
                int line_offset  = buf[2] & 0x1f;
 
380
                int field_parity = buf[2] & 0x20;
 
381
                int i;
 
382
                ctx->sliced[lines].id = VBI_SLICED_TELETEXT_B;
 
383
                ctx->sliced[lines].line = (line_offset > 0 ? (line_offset + (field_parity ? 0 : 313)) : 0);
 
384
                for (i = 0; i < 42; i++)
 
385
                    ctx->sliced[lines].data[i] = vbi_rev8(buf[4 + i]);
 
386
                lines++;
 
387
            }
 
388
        }
 
389
        size -= data_unit_length + 2;
 
390
        buf += data_unit_length + 2;
 
391
    }
 
392
    if (size)
 
393
        av_log(ctx, AV_LOG_WARNING, "%d bytes remained after slicing data\n", size);
 
394
    return lines;
 
395
}
 
396
 
 
397
static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *pkt)
 
398
{
 
399
    TeletextContext *ctx = avctx->priv_data;
 
400
    AVSubtitle      *sub = data;
 
401
    int             ret = 0;
 
402
 
 
403
    if (!ctx->vbi) {
 
404
        if (!(ctx->vbi = vbi_decoder_new()))
 
405
            return AVERROR(ENOMEM);
 
406
        if (!vbi_event_handler_add(ctx->vbi, VBI_EVENT_TTX_PAGE, handler, ctx)) {
 
407
            vbi_decoder_delete(ctx->vbi);
 
408
            ctx->vbi = NULL;
 
409
            return AVERROR(ENOMEM);
 
410
        }
 
411
    }
 
412
 
 
413
    if (avctx->pkt_timebase.den && pkt->pts != AV_NOPTS_VALUE)
 
414
        ctx->pts = av_rescale_q(pkt->pts, avctx->pkt_timebase, AV_TIME_BASE_Q);
 
415
 
 
416
    if (pkt->size) {
 
417
        int lines;
 
418
        const int full_pes_size = pkt->size + 45; /* PES header is 45 bytes */
 
419
 
 
420
        // We allow unreasonably big packets, even if the standard only allows a max size of 1472
 
421
        if (full_pes_size < 184 || full_pes_size > 65504 || full_pes_size % 184 != 0)
 
422
            return AVERROR_INVALIDDATA;
 
423
 
 
424
        ctx->handler_ret = pkt->size;
 
425
 
 
426
        if (data_identifier_is_teletext(*pkt->data)) {
 
427
            if ((lines = slice_to_vbi_lines(ctx, pkt->data + 1, pkt->size - 1)) < 0)
 
428
                return lines;
 
429
            av_dlog(avctx, "ctx=%p buf_size=%d lines=%u pkt_pts=%7.3f\n",
 
430
                    ctx, pkt->size, lines, (double)pkt->pts/90000.0);
 
431
            if (lines > 0) {
 
432
#ifdef DEBUG
 
433
                int i;
 
434
                av_log(avctx, AV_LOG_DEBUG, "line numbers:");
 
435
                for(i = 0; i < lines; i++)
 
436
                    av_log(avctx, AV_LOG_DEBUG, " %d", ctx->sliced[i].line);
 
437
                av_log(avctx, AV_LOG_DEBUG, "\n");
 
438
#endif
 
439
                vbi_decode(ctx->vbi, ctx->sliced, lines, 0.0);
 
440
                ctx->lines_processed += lines;
 
441
            }
 
442
        }
 
443
        ctx->pts = AV_NOPTS_VALUE;
 
444
        ret = ctx->handler_ret;
 
445
    }
 
446
 
 
447
    if (ret < 0)
 
448
        return ret;
 
449
 
 
450
    // is there a subtitle to pass?
 
451
    if (ctx->nb_pages) {
 
452
        int i;
 
453
        sub->format = ctx->format_id;
 
454
        sub->start_display_time = 0;
 
455
        sub->end_display_time = ctx->sub_duration;
 
456
        sub->num_rects = 0;
 
457
        sub->pts = ctx->pages->pts;
 
458
 
 
459
        if (ctx->pages->sub_rect->type != SUBTITLE_NONE) {
 
460
            sub->rects = av_malloc(sizeof(*sub->rects));
 
461
            if (sub->rects) {
 
462
                sub->num_rects = 1;
 
463
                sub->rects[0] = ctx->pages->sub_rect;
 
464
            } else {
 
465
                ret = AVERROR(ENOMEM);
 
466
            }
 
467
        } else {
 
468
            av_log(avctx, AV_LOG_DEBUG, "sending empty sub\n");
 
469
            sub->rects = NULL;
 
470
        }
 
471
        if (!sub->rects) // no rect was passed
 
472
            subtitle_rect_free(&ctx->pages->sub_rect);
 
473
 
 
474
        for (i = 0; i < ctx->nb_pages - 1; i++)
 
475
            ctx->pages[i] = ctx->pages[i + 1];
 
476
        ctx->nb_pages--;
 
477
 
 
478
        if (ret >= 0)
 
479
            *data_size = 1;
 
480
    } else
 
481
        *data_size = 0;
 
482
 
 
483
    return ret;
 
484
}
 
485
 
 
486
static int teletext_init_decoder(AVCodecContext *avctx)
 
487
{
 
488
    TeletextContext *ctx = avctx->priv_data;
 
489
    unsigned int maj, min, rev;
 
490
 
 
491
    vbi_version(&maj, &min, &rev);
 
492
    if (!(maj > 0 || min > 2 || min == 2 && rev >= 26)) {
 
493
        av_log(avctx, AV_LOG_ERROR, "decoder needs zvbi version >= 0.2.26.\n");
 
494
        return AVERROR_EXTERNAL;
 
495
    }
 
496
 
 
497
    if (ctx->format_id == 0) {
 
498
        avctx->width  = 41 * BITMAP_CHAR_WIDTH;
 
499
        avctx->height = 25 * BITMAP_CHAR_HEIGHT;
 
500
    }
 
501
 
 
502
    ctx->vbi = NULL;
 
503
    ctx->pts = AV_NOPTS_VALUE;
 
504
 
 
505
#ifdef DEBUG
 
506
    {
 
507
        char *t;
 
508
        ctx->ex = vbi_export_new("text", &t);
 
509
    }
 
510
#endif
 
511
    av_log(avctx, AV_LOG_VERBOSE, "page filter: %s\n", ctx->pgno);
 
512
    return (ctx->format_id == 1) ? ff_ass_subtitle_header_default(avctx) : 0;
 
513
}
 
514
 
 
515
static int teletext_close_decoder(AVCodecContext *avctx)
 
516
{
 
517
    TeletextContext *ctx = avctx->priv_data;
 
518
 
 
519
    av_dlog(avctx, "lines_total=%u\n", ctx->lines_processed);
 
520
    while (ctx->nb_pages)
 
521
        subtitle_rect_free(&ctx->pages[--ctx->nb_pages].sub_rect);
 
522
    av_freep(&ctx->pages);
 
523
 
 
524
    vbi_decoder_delete(ctx->vbi);
 
525
    ctx->vbi = NULL;
 
526
    ctx->pts = AV_NOPTS_VALUE;
 
527
    return 0;
 
528
}
 
529
 
 
530
static void teletext_flush(AVCodecContext *avctx)
 
531
{
 
532
    teletext_close_decoder(avctx);
 
533
}
 
534
 
 
535
#define OFFSET(x) offsetof(TeletextContext, x)
 
536
#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
 
537
static const AVOption options[] = {
 
538
    {"txt_page",        "list of teletext page numbers to decode, * is all", OFFSET(pgno),           AV_OPT_TYPE_STRING, {.str = "*"},      0, 0,        SD},
 
539
    {"txt_chop_top",    "discards the top teletext line",                    OFFSET(chop_top),       AV_OPT_TYPE_INT,    {.i64 = 1},        0, 1,        SD},
 
540
    {"txt_format",      "format of the subtitles (bitmap or text)",          OFFSET(format_id),      AV_OPT_TYPE_INT,    {.i64 = 0},        0, 1,        SD,  "txt_format"},
 
541
    {"bitmap",          NULL,                                                0,                      AV_OPT_TYPE_CONST,  {.i64 = 0},        0, 0,        SD,  "txt_format"},
 
542
    {"text",            NULL,                                                0,                      AV_OPT_TYPE_CONST,  {.i64 = 1},        0, 0,        SD,  "txt_format"},
 
543
    {"txt_left",        "x offset of generated bitmaps",                     OFFSET(x_offset),       AV_OPT_TYPE_INT,    {.i64 = 0},        0, 65535,    SD},
 
544
    {"txt_top",         "y offset of generated bitmaps",                     OFFSET(y_offset),       AV_OPT_TYPE_INT,    {.i64 = 0},        0, 65535,    SD},
 
545
    {"txt_chop_spaces", "chops leading and trailing spaces from text",       OFFSET(chop_spaces),    AV_OPT_TYPE_INT,    {.i64 = 1},        0, 1,        SD},
 
546
    {"txt_duration",    "display duration of teletext pages in msecs",       OFFSET(sub_duration),   AV_OPT_TYPE_INT,    {.i64 = 30000},    0, 86400000, SD},
 
547
    {"txt_transparent", "force transparent background of the teletext",      OFFSET(transparent_bg), AV_OPT_TYPE_INT,    {.i64 = 0},        0, 1,        SD},
 
548
    { NULL },
 
549
};
 
550
 
 
551
static const AVClass teletext_class = {
 
552
    .class_name = "libzvbi_teletextdec",
 
553
    .item_name  = av_default_item_name,
 
554
    .option     = options,
 
555
    .version    = LIBAVUTIL_VERSION_INT,
 
556
};
 
557
 
 
558
AVCodec ff_libzvbi_teletext_decoder = {
 
559
    .name      = "libzvbi_teletextdec",
 
560
    .long_name = NULL_IF_CONFIG_SMALL("Libzvbi DVB teletext decoder"),
 
561
    .type      = AVMEDIA_TYPE_SUBTITLE,
 
562
    .id        = AV_CODEC_ID_DVB_TELETEXT,
 
563
    .priv_data_size = sizeof(TeletextContext),
 
564
    .init      = teletext_init_decoder,
 
565
    .close     = teletext_close_decoder,
 
566
    .decode    = teletext_decode_frame,
 
567
    .capabilities = CODEC_CAP_DELAY,
 
568
    .flush     = teletext_flush,
 
569
    .priv_class= &teletext_class,
 
570
};