telx.c 23.2 KB
Newer Older
1 2 3 4 5 6 7
/*****************************************************************************
 * telx.c : Minimalistic Teletext subtitles decoder
 *****************************************************************************
 * Copyright (C) 2007 Vincent Penne
 * Some code converted from ProjectX java dvb decoder (c) 2001-2005 by dvb.matt
 * $Id$
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
8 9 10
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
11 12 13 14
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
15 16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
17
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
18 19 20
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21 22
 *****************************************************************************/
/*****************************************************************************
23 24
 *
 * information on teletext format can be found here :
25 26 27
 * http://pdc.ro.nu/teletext.html
 *
 *****************************************************************************/
28 29 30
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
31 32
#include <assert.h>
#include <stdint.h>
33

34
#include <vlc_common.h>
35
#include <vlc_plugin.h>
36

37 38
#include <vlc_bits.h>
#include <vlc_codec.h>
39 40 41

/* #define TELX_DEBUG */
#ifdef TELX_DEBUG
42
#   define dbg( a ) msg_Dbg a
43 44 45 46 47 48 49 50 51
#else
#   define dbg( a )
#endif

/*****************************************************************************
 * Module descriptor.
 *****************************************************************************/
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );
52
static int  Decode( decoder_t *, block_t * );
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

#define OVERRIDE_PAGE_TEXT N_("Override page")
#define OVERRIDE_PAGE_LONGTEXT N_("Override the indicated page, try this if " \
        "your subtitles don't appear (-1 = autodetect from TS, " \
        "0 = autodetect from teletext, " \
        ">0 = actual page number, usually 888 or 889).")

#define IGNORE_SUB_FLAG_TEXT N_("Ignore subtitle flag")
#define IGNORE_SUB_FLAG_LONGTEXT N_("Ignore the subtitle flag, try this if " \
        "your subtitles don't appear.")

#define FRENCH_WORKAROUND_TEXT N_("Workaround for France")
#define FRENCH_WORKAROUND_LONGTEXT N_("Some French channels do not flag " \
        "their subtitling pages correctly due to a historical " \
        "interpretation mistake. Try using this wrong interpretation if " \
        "your subtitles don't appear.")

70 71 72
vlc_module_begin ()
    set_description( N_("Teletext subtitles decoder") )
    set_shortname( "Teletext" )
73
    set_capability( "spu decoder", 50 )
74 75 76
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_SCODEC )
    set_callbacks( Open, Close )
77

78
    add_integer( "telx-override-page", -1,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
79
                 OVERRIDE_PAGE_TEXT, OVERRIDE_PAGE_LONGTEXT, true )
80
    add_bool( "telx-ignore-subtitle-flag", false,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
81
              IGNORE_SUB_FLAG_TEXT, IGNORE_SUB_FLAG_LONGTEXT, true )
82
    add_bool( "telx-french-workaround", false,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
83
              FRENCH_WORKAROUND_TEXT, FRENCH_WORKAROUND_LONGTEXT, true )
84

85
vlc_module_end ()
86 87 88 89 90 91 92 93

/****************************************************************************
 * Local structures
 ****************************************************************************/

struct decoder_sys_t
{
  int         i_align;
94
  bool        b_is_subtitle[9];
95 96 97 98
  char        ppsz_lines[32][128];
  char        psz_prev_text[512];
  mtime_t     prev_pts;
  int         i_page[9];
99
  bool        b_erase[9];
100
  const uint16_t *  pi_active_national_set[9];
101
  int         i_wanted_page, i_wanted_magazine;
102
  bool        b_ignore_sub_flag;
103 104 105 106 107 108 109
};

/****************************************************************************
 * Local data
 ****************************************************************************/

/*
110
 * My doc only mentions 13 national characters, but experiments show there
111 112 113 114 115 116 117 118 119
 * are more, in france for example I already found two more (0x9 and 0xb).
 *
 * Conversion is in this order :
 *
 * 0x23 0x24 0x40 0x5b 0x5c 0x5d 0x5e 0x5f 0x60 0x7b 0x7c 0x7d 0x7e
 * (these are the standard ones)
 * 0x08 0x09 0x0a 0x0b 0x0c 0x0d (apparently a control character) 0x0e 0x0f
 */

120
static const uint16_t ppi_national_subsets[][20] =
121
{
122
  { 0x00a3, 0x0024, 0x0040, 0x00ab, 0x00bd, 0x00bb, 0x005e, 0x0023,
123 124 125 126 127
    0x002d, 0x00bc, 0x00a6, 0x00be, 0x00f7 }, /* english ,000 */

  { 0x00e9, 0x00ef, 0x00e0, 0x00eb, 0x00ea, 0x00f9, 0x00ee, 0x0023,
    0x00e8, 0x00e2, 0x00f4, 0x00fb, 0x00e7, 0, 0x00eb, 0, 0x00ef }, /* french  ,001 */

128
  { 0x0023, 0x00a4, 0x00c9, 0x00c4, 0x00d6, 0x00c5, 0x00dc, 0x005f,
129 130
    0x00e9, 0x00e4, 0x00f6, 0x00e5, 0x00fc }, /* swedish,finnish,hungarian ,010 */

131
  { 0x0023, 0x016f, 0x010d, 0x0165, 0x017e, 0x00fd, 0x00ed, 0x0159,
132
    0x00e9, 0x00e1, 0x011b, 0x00fa, 0x0161 }, /* czech,slovak  ,011 */
133

134
  { 0x0023, 0x0024, 0x00a7, 0x00c4, 0x00d6, 0x00dc, 0x005e, 0x005f,
135 136
    0x00b0, 0x00e4, 0x00f6, 0x00fc, 0x00df }, /* german ,100 */

137
  { 0x00e7, 0x0024, 0x00a1, 0x00e1, 0x00e9, 0x00ed, 0x00f3, 0x00fa,
138 139
    0x00bf, 0x00fc, 0x00f1, 0x00e8, 0x00e0 }, /* portuguese,spanish ,101 */

140
  { 0x00a3, 0x0024, 0x00e9, 0x00b0, 0x00e7, 0x00bb, 0x005e, 0x0023,
141 142
    0x00f9, 0x00e0, 0x00f2, 0x00e8, 0x00ec }, /* italian  ,110 */

143
  { 0x0023, 0x00a4, 0x0162, 0x00c2, 0x015e, 0x0102, 0x00ce, 0x0131,
144 145 146
    0x0163, 0x00e2, 0x015f, 0x0103, 0x00ee }, /* rumanian ,111 */

  /* I have these tables too, but I don't know how they can be triggered */
147
  { 0x0023, 0x0024, 0x0160, 0x0117, 0x0119, 0x017d, 0x010d, 0x016b,
148 149
    0x0161, 0x0105, 0x0173, 0x017e, 0x012f }, /* lettish,lithuanian ,1000 */

150
  { 0x0023, 0x0144, 0x0105, 0x005a, 0x015a, 0x0141, 0x0107, 0x00f3,
151 152
    0x0119, 0x017c, 0x015b, 0x0142, 0x017a }, /* polish,  1001 */

153
  { 0x0023, 0x00cb, 0x010c, 0x0106, 0x017d, 0x0110, 0x0160, 0x00eb,
154 155
    0x010d, 0x0107, 0x017e, 0x0111, 0x0161 }, /* serbian,croatian,slovenian, 1010 */

156
  { 0x0023, 0x00f5, 0x0160, 0x00c4, 0x00d6, 0x017e, 0x00dc, 0x00d5,
157 158
    0x0161, 0x00e4, 0x00f6, 0x017e, 0x00fc }, /* estonian  ,1011 */

159
  { 0x0054, 0x011f, 0x0130, 0x015e, 0x00d6, 0x00c7, 0x00dc, 0x011e,
160 161 162 163 164 165 166 167 168 169 170 171 172 173
    0x0131, 0x015f, 0x00f6, 0x00e7, 0x00fc }, /* turkish  ,1100 */
};


/*****************************************************************************
 * Open: probe the decoder and return score
 *****************************************************************************
 * Tries to launch a decoder and return score so that the interface is able
 * to chose.
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
    decoder_t     *p_dec = (decoder_t *) p_this;
    decoder_sys_t *p_sys = NULL;
174 175
    int            i_val;

176

177
    if( p_dec->fmt_in.i_codec != VLC_CODEC_TELETEXT)
178 179 180 181
    {
        return VLC_EGENERIC;
    }

182
    p_dec->pf_decode = Decode;
183
    p_sys = p_dec->p_sys = calloc( 1, sizeof(*p_sys) );
184 185
    if( p_sys == NULL )
        return VLC_ENOMEM;
186
    p_dec->fmt_out.i_codec = 0;
187 188

    p_sys->i_align = 0;
189
    for ( int i = 0; i < 9; i++ )
190 191
        p_sys->pi_active_national_set[i] = ppi_national_subsets[1];

192 193
    i_val = var_CreateGetInteger( p_dec, "telx-override-page" );
    if( i_val == -1 && p_dec->fmt_in.subs.teletext.i_magazine != -1 &&
194 195
        ( p_dec->fmt_in.subs.teletext.i_magazine != 1 ||
          p_dec->fmt_in.subs.teletext.i_page != 0 ) ) /* ignore if TS demux wants page 100 (unlikely to be sub) */
196
    {
197
        bool b_val;
198 199
        p_sys->i_wanted_magazine = p_dec->fmt_in.subs.teletext.i_magazine;
        p_sys->i_wanted_page = p_dec->fmt_in.subs.teletext.i_page;
200

201
        b_val = var_CreateGetBool( p_dec, "telx-french-workaround" );
202
        if( p_sys->i_wanted_page < 100 &&
203
            (b_val || (p_sys->i_wanted_page % 16) >= 10))
204 205 206 207 208 209 210 211
        {
            /* See http://www.nada.kth.se/~ragge/vdr/ttxtsubs/TROUBLESHOOTING.txt
             * paragraph about French channels - they mix up decimal and
             * hexadecimal */
            p_sys->i_wanted_page = (p_sys->i_wanted_page / 10) * 16 +
                                   (p_sys->i_wanted_page % 10);
        }
    }
212
    else if( i_val <= 0 )
213 214 215 216 217 218
    {
        p_sys->i_wanted_magazine = -1;
        p_sys->i_wanted_page = -1;
    }
    else
    {
219 220 221
        p_sys->i_wanted_magazine = i_val / 100;
        p_sys->i_wanted_page = (((i_val % 100) / 10) << 4)
                               |((i_val % 100) % 10);
222
    }
223 224
    p_sys->b_ignore_sub_flag = var_CreateGetBool( p_dec,
                                    "telx-ignore-subtitle-flag" );
225

226
    msg_Dbg( p_dec, "starting telx on magazine %d page %02x flag %d",
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
             p_sys->i_wanted_magazine, p_sys->i_wanted_page,
             p_sys->b_ignore_sub_flag );

    return VLC_SUCCESS;

/*  error: */
/*     if (p_sys) { */
/*       free(p_sys); */
/*       p_sys = NULL; */
/*     } */
/*     return VLC_EGENERIC; */
}

/*****************************************************************************
 * Close:
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
    decoder_t     *p_dec = (decoder_t*) p_this;
    decoder_sys_t *p_sys = p_dec->p_sys;

    free( p_sys );
}

/**************************
 * change bits endianness *
 **************************/
static uint8_t bytereverse( int n )
{
    n = (((n >> 1) & 0x55) | ((n << 1) & 0xaa));
    n = (((n >> 2) & 0x33) | ((n << 2) & 0xcc));
    n = (((n >> 4) & 0x0f) | ((n << 4) & 0xf0));
    return n;
}

static int hamming_8_4( int a )
{
    switch (a) {
265
    case 0xA8:
266
        return 0;
267
    case 0x0B:
268
        return 1;
269
    case 0x26:
270
        return 2;
271
    case 0x85:
272
        return 3;
273
    case 0x92:
274
        return 4;
275
    case 0x31:
276
        return 5;
277
    case 0x1C:
278
        return 6;
279
    case 0xBF:
280
        return 7;
281
    case 0x40:
282
        return 8;
283
    case 0xE3:
284
        return 9;
285
    case 0xCE:
286
        return 10;
287
    case 0x6D:
288
        return 11;
289
    case 0x7A:
290
        return 12;
291
    case 0xD9:
292
        return 13;
293
    case 0xF4:
294
        return 14;
295
    case 0x57:
296
        return 15;
297
    default:
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
        return -1;     // decoding error , not yet corrected
    }
}

// utc-2 --> utf-8
// this is not a general function, but it's enough for what we do here
// the result buffer need to be at least 4 bytes long
static void to_utf8( char * res, uint16_t ch )
{
    if( ch >= 0x80 )
    {
        if( ch >= 0x800 )
        {
            res[0] = (ch >> 12) | 0xE0;
            res[1] = ((ch >> 6) & 0x3F) | 0x80;
            res[2] = (ch & 0x3F) | 0x80;
            res[3] = 0;
        }
        else
        {
            res[0] = (ch >> 6) | 0xC0;
            res[1] = (ch & 0x3F) | 0x80;
            res[2] = 0;
        }
    }
    else
    {
        res[0] = ch;
        res[1] = 0;
    }
}

330 331
static void decode_string( char * res, int res_len,
                           decoder_sys_t *p_sys, int magazine,
332 333 334 335 336
                           uint8_t * packet, int len )
{
    char utf8[7];
    char * pt = res;

337
    for ( int i = 0; i < len; i++ )
338 339 340 341 342 343 344 345 346
    {
        int in = bytereverse( packet[i] ) & 0x7f;
        uint16_t out = 32;
        size_t l;

        switch ( in )
        {
        /* special national characters */
        case 0x23:
347 348
            out = p_sys->pi_active_national_set[magazine][0];
            break;
349
        case 0x24:
350 351
            out = p_sys->pi_active_national_set[magazine][1];
            break;
352
        case 0x40:
353 354
            out = p_sys->pi_active_national_set[magazine][2];
            break;
355
        case 0x5b:
356 357
            out = p_sys->pi_active_national_set[magazine][3];
            break;
358
        case 0x5c:
359 360
            out = p_sys->pi_active_national_set[magazine][4];
            break;
361
        case 0x5d:
362 363
            out = p_sys->pi_active_national_set[magazine][5];
            break;
364
        case 0x5e:
365 366
            out = p_sys->pi_active_national_set[magazine][6];
            break;
367
        case 0x5f:
368 369
            out = p_sys->pi_active_national_set[magazine][7];
            break;
370
        case 0x60:
371 372
            out = p_sys->pi_active_national_set[magazine][8];
            break;
373
        case 0x7b:
374 375
            out = p_sys->pi_active_national_set[magazine][9];
            break;
376
        case 0x7c:
377 378
            out = p_sys->pi_active_national_set[magazine][10];
            break;
379
        case 0x7d:
380 381
            out = p_sys->pi_active_national_set[magazine][11];
            break;
382
        case 0x7e:
383 384
            out = p_sys->pi_active_national_set[magazine][12];
            break;
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424

        /* some special control characters (empirical) */
        case 0x0d:
            /* apparently this starts a sequence that ends with 0xb 0xb */
            while ( i + 1 < len && (bytereverse( packet[i+1] ) & 0x7f) != 0x0b )
                i++;
            i += 2;
            break;
            /* goto skip; */

        default:
            /* non documented national range 0x08 - 0x0f */
            if ( in >= 0x08 && in <= 0x0f )
            {
                out = p_sys->pi_active_national_set[magazine][13 + in - 8];
                break;
            }

            /* normal ascii */
            if ( in > 32 && in < 0x7f )
                out = in;
        }

        /* handle undefined national characters */
        if ( out == 0 )
            out = 32;

        /* convert to utf-8 */
        to_utf8( utf8, out );
        l = strlen( utf8 );
        if ( pt + l < res + res_len - 1 )
        {
            strcpy(pt, utf8);
            pt += l;
        }

        /* skip: ; */
    }
    /* end: */
    *pt++ = 0;
425
}
426 427 428 429

/*****************************************************************************
 * Decode:
 *****************************************************************************/
430
static int Decode( decoder_t *p_dec, block_t *p_block )
431 432 433 434 435
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    subpicture_t  *p_spu = NULL;
    video_format_t fmt;
    /* int erase = 0; */
436
    int len;
437 438 439 440 441
#if 0
    int i_wanted_magazine = i_conf_wanted_page / 100;
    int i_wanted_page = 0x10 * ((i_conf_wanted_page % 100) / 10)
                         | (i_conf_wanted_page % 10);
#endif
442
    bool b_update = false;
443 444
    char psz_text[512], *pt = psz_text;
    char psz_line[256];
445
    int total;
446

447 448
    if( p_block == NULL ) /* No Drain */
        return VLCDEC_SUCCESS;
449 450 451 452

    dbg((p_dec, "start of telx packet with header %2x\n",
                * (uint8_t *) p_block->p_buffer));
    len = p_block->i_buffer;
453
    for ( int offset = 1; offset + 46 <= len; offset += 46 )
454 455 456
    {
        uint8_t * packet = (uint8_t *) p_block->p_buffer+offset;
//        int vbi = ((0x20 & packet[2]) != 0 ? 0 : 313) + (0x1F & packet[2]);
457

458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487
//        dbg((p_dec, "vbi %d header %02x %02x %02x\n", vbi, packet[0], packet[1], packet[2]));
        if ( packet[0] == 0xFF ) continue;

/*      if (packet[1] != 0x2C) { */
/*         printf("wrong header\n"); */
/*         //goto error; */
/*         continue; */
/*       } */

        int mpag = (hamming_8_4( packet[4] ) << 4) | hamming_8_4( packet[5] );
        int row, magazine;
        if ( mpag < 0 )
        {
            /* decode error */
            dbg((p_dec, "mpag hamming error\n"));
            continue;
        }

        row = 0xFF & bytereverse(mpag);
        magazine = (7 & row) == 0 ? 8 : (7 & row);
        row >>= 3;

        if ( p_sys->i_wanted_page != -1
              && magazine != p_sys->i_wanted_magazine )
            continue;

        if ( row == 0 )
        {
            /* row 0 : flags and header line */
            int flag = 0;
488

489
            for ( int a = 0; a < 6; a++ )
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
            {
                flag |= (0xF & (bytereverse( hamming_8_4(packet[8 + a]) ) >> 4))
                          << (a * 4);
            }

    /*         if (!p_sys->b_ignore_sub_flag && !(1 & flag>>15)) */
    /*           continue; */

            p_sys->i_page[magazine] = (0xF0 & bytereverse( hamming_8_4(packet[7]) )) |
                             (0xF & (bytereverse( hamming_8_4(packet[6]) ) >> 4) );

            decode_string( psz_line, sizeof(psz_line), p_sys, magazine,
                           packet + 14, 40 - 14 );

            dbg((p_dec, "mag %d flags %x page %x character set %d subtitles %d", magazine, flag,
                 p_sys->i_page[magazine],
                 7 & flag>>21, 1 & flag>>15, psz_line));

            p_sys->pi_active_national_set[magazine] =
                                 ppi_national_subsets[7 & (flag >> 21)];

            p_sys->b_is_subtitle[magazine] = p_sys->b_ignore_sub_flag
                                              || ( (1 & (flag >> 15))
                                                  && (1 & (flag>>16)) );

            dbg(( p_dec, "FLAGS%s%s%s%s%s%s%s mag_ser %d",
                  (1 & (flag>>14))? " news" : "",
                  (1 & (flag>>15))? " subtitle" : "",
                  (1 & (flag>>7))? " erase" : "",
                  (1 & (flag>>16))? " suppressed_head" : "",
                  (1 & (flag>>17))? " update" : "",
                  (1 & (flag>>18))? " interrupt" : "",
                  (1 & (flag>>19))? " inhibit" : "",
                  (1 & (flag>>20)) ));
524

525 526 527 528 529 530 531 532
            if ( (p_sys->i_wanted_page != -1
                   && p_sys->i_page[magazine] != p_sys->i_wanted_page)
                   || !p_sys->b_is_subtitle[magazine] )
                continue;

            p_sys->b_erase[magazine] = (1 & (flag >> 7));

            dbg((p_dec, "%ld --> %ld\n", (long int) p_block->i_pts, (long int)(p_sys->prev_pts+1500000)));
533
            /* kludge here :
534 535 536 537 538 539 540 541 542 543
             * we ignore the erase flag if it happens less than 1.5 seconds
             * before last caption
             * TODO   make this time configurable
             * UPDATE the kludge seems to be no more necessary
             *        so it's commented out*/
            if ( /*p_block->i_pts > p_sys->prev_pts + 1500000 && */
                 p_sys->b_erase[magazine] )
            {
                dbg((p_dec, "ERASE !\n"));

544
                p_sys->b_erase[magazine] = 0;
545
                for ( int i = 1; i < 32; i++ )
546 547
                {
                    if ( !p_sys->ppsz_lines[i][0] ) continue;
548
                    /* b_update = true; */
549 550 551 552 553 554 555 556 557 558
                    p_sys->ppsz_lines[i][0] = 0;
                }
            }

            /* replace the row if it's different */
            if ( strcmp(psz_line, p_sys->ppsz_lines[row]) )
            {
                strncpy( p_sys->ppsz_lines[row], psz_line,
                         sizeof(p_sys->ppsz_lines[row]) - 1);
            }
559
            b_update = true;
560 561 562 563 564 565 566 567 568 569

        }
        else if ( row < 24 )
        {
            char * t;
            int i;
            /* row 1-23 : normal lines */

            if ( (p_sys->i_wanted_page != -1
                   && p_sys->i_page[magazine] != p_sys->i_wanted_page)
570
                   || !p_sys->b_is_subtitle[magazine]
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
                   || (p_sys->i_wanted_page == -1
                        && p_sys->i_page[magazine] > 0x99) )
                continue;

            decode_string( psz_line, sizeof(psz_line), p_sys, magazine,
                           packet + 6, 40 );
            t = psz_line;

            /* remove starting spaces */
            while ( *t == 32 ) t++;

            /* remove trailing spaces */
            for ( i = strlen(t) - 1; i >= 0 && t[i] == 32; i-- );
            t[i + 1] = 0;

            /* replace the row if it's different */
            if ( strcmp( t, p_sys->ppsz_lines[row] ) )
            {
                strncpy( p_sys->ppsz_lines[row], t,
                         sizeof(p_sys->ppsz_lines[row]) - 1 );
591
                b_update = true;
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
            }

            if (t[0])
                p_sys->prev_pts = p_block->i_pts;

            dbg((p_dec, "%d %d : ", magazine, row));
            dbg((p_dec, "%s\n", t));

#ifdef TELX_DEBUG
            {
                char dbg[256];
                dbg[0] = 0;
                for ( i = 0; i < 40; i++ )
                {
                    int in = bytereverse(packet[6 + i]) & 0x7f;
                    sprintf(dbg + strlen(dbg), "%02x ", in);
                }
                dbg((p_dec, "%s\n", dbg));
                dbg[0] = 0;
                for ( i = 0; i < 40; i++ )
                {
                    decode_string( psz_line, sizeof(psz_line), p_sys, magazine,
                                   packet + 6 + i, 1 );
                    sprintf( dbg + strlen(dbg), "%s  ", psz_line );
                }
                dbg((p_dec, "%s\n", dbg));
            }
#endif
        }
        else if ( row == 25 )
        {
            /* row 25 : alternate header line */
            if ( (p_sys->i_wanted_page != -1
                   && p_sys->i_page[magazine] != p_sys->i_wanted_page)
                   || !p_sys->b_is_subtitle[magazine] )
                continue;

            decode_string( psz_line, sizeof(psz_line), p_sys, magazine,
                           packet + 6, 40 );

            /* replace the row if it's different */
            if ( strcmp( psz_line, p_sys->ppsz_lines[0] ) )
            {
                strncpy( p_sys->ppsz_lines[0], psz_line,
                         sizeof(p_sys->ppsz_lines[0]) - 1 );
637
                /* b_update = true; */
638 639 640 641 642 643 644 645 646 647 648 649
            }
        }
/*       else if (row == 26) { */
/*         // row 26 : TV listings */
/*       } else */
/*         dbg((p_dec, "%d %d : %s\n", magazine, row, decode_string(p_sys, magazine, packet+6, 40))); */
    }

    if ( !b_update )
        goto error;

    total = 0;
650
    for ( int i = 1; i < 24; i++ )
651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
    {
        size_t l = strlen( p_sys->ppsz_lines[i] );

        if ( l > sizeof(psz_text) - total - 1 )
            l = sizeof(psz_text) - total - 1;

        if ( l > 0 )
        {
            memcpy( pt, p_sys->ppsz_lines[i], l );
            total += l;
            pt += l;
            if ( sizeof(psz_text) - total - 1 > 0 )
            {
                *pt++ = '\n';
                total++;
            }
        }
    }
    *pt = 0;

    if ( !strcmp(psz_text, p_sys->psz_prev_text) )
        goto error;

    dbg((p_dec, "UPDATE TELETEXT PICTURE\n"));

    assert( sizeof(p_sys->psz_prev_text) >= sizeof(psz_text) );
    strcpy( p_sys->psz_prev_text, psz_text );

    /* Create the subpicture unit */
680
    p_spu = decoder_NewSubpicture( p_dec, NULL );
681 682 683 684 685
    if( !p_spu )
    {
        msg_Warn( p_dec, "can't get spu buffer" );
        goto error;
    }
686

687
    /* Create a new subpicture region */
688
    video_format_Init(&fmt, VLC_CODEC_TEXT);
689 690
    fmt.i_width = fmt.i_height = 0;
    fmt.i_x_offset = fmt.i_y_offset = 0;
691
    p_spu->p_region = subpicture_region_New( &fmt );
692 693 694 695 696 697 698 699
    if( p_spu->p_region == NULL )
    {
        msg_Err( p_dec, "cannot allocate SPU region" );
        goto error;
    }

    /* Normal text subs, easy markup */
    p_spu->p_region->i_align = SUBPICTURE_ALIGN_BOTTOM | p_sys->i_align;
700 701
    p_spu->p_region->i_x = p_sys->i_align ? 20 : 0;
    p_spu->p_region->i_y = 10;
702
    p_spu->p_region->p_text = text_segment_New(psz_text);
703

704 705 706
    p_spu->i_start = p_block->i_pts;
    p_spu->i_stop = p_block->i_pts + p_block->i_length;
    p_spu->b_ephemer = (p_block->i_length == 0);
707
    p_spu->b_absolute = false;
708 709 710
    dbg((p_dec, "%ld --> %ld\n", (long int) p_block->i_pts/100000, (long int)p_block->i_length/100000));

    block_Release( p_block );
711 712 713
    if( p_spu != NULL )
        decoder_QueueSub( p_dec, p_spu );
    return VLCDEC_SUCCESS;
714 715 716 717

error:
    if ( p_spu != NULL )
    {
718
        subpicture_Delete( p_spu );
719 720 721 722
        p_spu = NULL;
    }

    block_Release( p_block );
723
    return VLCDEC_SUCCESS;
724
}