sub.c 36.5 KB
Newer Older
1
/*****************************************************************************
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
2
 * sub.c: subtitle demux for external subtitle files
3
 *****************************************************************************
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
4
 * Copyright (C) 1999-2004 VideoLAN
5
 * $Id$
6 7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
8
 *          Derk-Jan Hartman <hartman at videolan dot org>
9 10 11 12 13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
Laurent Aimar's avatar
Laurent Aimar committed
14
 *
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
31
#include <ctype.h>
32 33 34

#include <vlc/vlc.h>
#include <vlc/input.h>
Sam Hocevar's avatar
Sam Hocevar committed
35
#include "vlc_video.h"
36
#include <codecs.h>
37 38 39

#include "sub.h"

40 41 42
#if (!defined( WIN32 ) || defined(__MINGW32__))
#    include <dirent.h>
#endif
43

44 45
#define DVD_VIDEO_LB_LEN 2048

46 47
static int  Open ( vlc_object_t *p_this );

Laurent Aimar's avatar
Laurent Aimar committed
48
static int  sub_open ( subtitle_demux_t *p_sub,
49 50
                       input_thread_t  *p_input,
                       char  *psz_name,
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
51
                       mtime_t i_microsecperframe );
52 53 54 55 56 57
static int  sub_demux( subtitle_demux_t *p_sub, mtime_t i_maxdate );
static int  sub_seek ( subtitle_demux_t *p_sub, mtime_t i_date );
static void sub_close( subtitle_demux_t *p_sub );

static void sub_fix( subtitle_demux_t *p_sub );

58 59
static char *ppsz_sub_type[] = { "auto", "microdvd", "subrip", "ssa1",
  "ssa2-4", "vplayer", "sami", "vobsub" };
60

61 62 63
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
64 65
#define SUB_DELAY_LONGTEXT \
    "Delay subtitles (in 1/10s)"
66
#define SUB_FPS_LONGTEXT \
67
    "Override frames per second. " \
Gildas Bazin's avatar
 
Gildas Bazin committed
68
    "It will only work with MicroDVD subtitles."
69
#define SUB_TYPE_LONGTEXT \
Gildas Bazin's avatar
 
Gildas Bazin committed
70
    "One from \"microdvd\", \"subrip\", \"ssa1\", \"ssa2-4\", \"vplayer\" " \
71
    "\"sami\" (auto for autodetection, it should always work)."
72 73

vlc_module_begin();
Gildas Bazin's avatar
 
Gildas Bazin committed
74
    set_description( _("Text subtitles demux") );
75
    set_capability( "subtitle demux", 12 );
76
    add_float( "sub-fps", 0.0, NULL,
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
77 78 79 80 81 82 83 84
               N_("Frames per second"),
               SUB_FPS_LONGTEXT, VLC_TRUE );
    add_integer( "sub-delay", 0, NULL,
                 N_("Delay subtitles (in 1/10s)"),
                 SUB_DELAY_LONGTEXT, VLC_TRUE );
    add_string( "sub-type", "auto", NULL, "Subtitles fileformat",
                SUB_TYPE_LONGTEXT, VLC_TRUE );
        change_string_list( ppsz_sub_type, 0, 0 );
85 86 87 88 89 90 91 92 93 94 95 96 97 98
    set_callbacks( Open, NULL );
vlc_module_end();

/*****************************************************************************
 * Module initializer
 *****************************************************************************/
static int Open ( vlc_object_t *p_this )
{
    subtitle_demux_t *p_sub = (subtitle_demux_t*)p_this;

    p_sub->pf_open  = sub_open;
    p_sub->pf_demux = sub_demux;
    p_sub->pf_seek  = sub_seek;
    p_sub->pf_close = sub_close;
99

100
    /* Initialize the variables */
Gildas Bazin's avatar
 
Gildas Bazin committed
101 102 103
    var_Create( p_this, "sub-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
    var_Create( p_this, "sub-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Create( p_this, "sub-type", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
104

105 106 107 108
    return VLC_SUCCESS;
}
#define MAX_TRY     256
#define MAX_LINE    2048
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195

#define FREE( p ) if( p ) { free( p); (p) = NULL; }

typedef struct
{
    int     i_line_count;
    int     i_line;
    char    **line;
} text_t;

static int  text_load( text_t *txt, char *psz_name )
{
    FILE *f;
    int   i_line_max;

    /* init txt */
    i_line_max          = 100;
    txt->i_line_count   = 0;
    txt->i_line         = 0;
    txt->line           = calloc( i_line_max, sizeof( char * ) );

    /* open file */
    if( !( f = fopen( psz_name, "rb" ) ) )
    {
        return VLC_EGENERIC;
    }

    /* load the complete file */
    for( ;; )
    {
        char buffer[8096];
        char *p;

        if( fgets( buffer, 8096, f ) <= 0)
        {
            break;
        }
        while( ( p = strchr( buffer, '\r' ) ) )
        {
            *p = '\0';
        }
        while( ( p = strchr( buffer, '\n' ) ) )
        {
            *p = '\0';
        }

        txt->line[txt->i_line_count++] = strdup( buffer );

        if( txt->i_line_count >= i_line_max )
        {
            i_line_max += 100;
            txt->line = realloc( txt->line, i_line_max * sizeof( char*) );
        }
    }

    fclose( f );

    if( txt->i_line_count <= 0 )
    {
        FREE( txt->line );
        return( VLC_EGENERIC );
    }

    return( VLC_SUCCESS );
}
static void text_unload( text_t *txt )
{
    int i;

    for( i = 0; i < txt->i_line_count; i++ )
    {
        FREE( txt->line[i] );
    }
    FREE( txt->line );
    txt->i_line       = 0;
    txt->i_line_count = 0;
}

static char *text_get_line( text_t *txt )
{
    if( txt->i_line >= txt->i_line_count )
    {
        return( NULL );
    }

    return( txt->line[txt->i_line++] );
}
196 197 198 199 200 201 202
static void text_previous_line( text_t *txt )
{
    if( txt->i_line > 0 )
    {
        txt->i_line--;
    }
}
203 204 205 206 207
static void text_rewind( text_t *txt )
{
    txt->i_line = 0;
}

208 209 210 211 212
static int  sub_MicroDvdRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
static int  sub_SubRipRead  ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
static int  sub_SSARead     ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
static int  sub_Vplayer     ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
static int  sub_Sami        ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
213
static int  sub_VobSubIDX   ( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe );
214

215
static int  DemuxVobSub     ( subtitle_demux_t *, block_t * );
216

217 218 219 220 221
static struct
{
    char *psz_type_name;
    int  i_type;
    char *psz_name;
222
    int  (*pf_read_subtitle)    ( subtitle_demux_t *, text_t *, subtitle_t*, mtime_t );
223 224 225 226
} sub_read_subtitle_function [] =
{
    { "microdvd",   SUB_TYPE_MICRODVD,  "MicroDVD", sub_MicroDvdRead },
    { "subrip",     SUB_TYPE_SUBRIP,    "SubRIP",   sub_SubRipRead },
227 228
    { "ssa1",       SUB_TYPE_SSA1,      "SSA-1",    sub_SSARead },
    { "ssa2-4",     SUB_TYPE_SSA2_4,    "SSA-2/3/4",sub_SSARead },
229 230
    { "vplayer",    SUB_TYPE_VPLAYER,   "VPlayer",  sub_Vplayer },
    { "sami",       SUB_TYPE_SAMI,      "SAMI",     sub_Sami },
231
    { "vobsub",     SUB_TYPE_VOBSUB,    "VobSub",   sub_VobSubIDX },
232
    { NULL,         SUB_TYPE_UNKNOWN,   "Unknown",  NULL }
233 234
};

235 236 237
static char * local_stristr( char *psz_big, char *psz_little)
{
    char *p_pos = psz_big;
Eric Petit's avatar
Eric Petit committed
238

239 240 241 242
    if (!psz_big || !psz_little || !*psz_little) return psz_big;

    while (*p_pos)
    {
243
        if (toupper(*p_pos) == toupper(*psz_little))
244
        {
245 246 247
            char * psz_cur1 = p_pos + 1;
            char * psz_cur2 = psz_little + 1;
            while (*psz_cur1 && *psz_cur2 && toupper(*psz_cur1) == toupper(*psz_cur2))
248
            {
249 250 251 252 253 254
                psz_cur1++;
                psz_cur2++;
            }
            if (!*psz_cur2) return p_pos;
        }
        p_pos++;
255 256 257 258
    }
    return NULL;
}

259 260 261
/*****************************************************************************
 * sub_open: Open a subtitle file and add subtitle ES
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
262
static int sub_open( subtitle_demux_t *p_sub, input_thread_t  *p_input,
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
263
                     char *psz_name, mtime_t i_microsecperframe )
264
{
265
    text_t  txt;
266
    vlc_value_t val;
Gildas Bazin's avatar
 
Gildas Bazin committed
267 268 269 270
    es_format_t fmt;
    int i, i_sub_type, i_max;
    int (*pf_read_subtitle)( subtitle_demux_t *, text_t *, subtitle_t *,
                             mtime_t ) = NULL;
Laurent Aimar's avatar
Laurent Aimar committed
271

272 273 274 275
    p_sub->i_sub_type = SUB_TYPE_UNKNOWN;
    p_sub->p_es = NULL;
    p_sub->i_subtitles = 0;
    p_sub->subtitle = NULL;
Gildas Bazin's avatar
 
Gildas Bazin committed
276
    p_sub->p_vobsub_file = 0;
277
    p_sub->i_original_mspf = i_microsecperframe;
278 279
    p_sub->p_input = p_input;

Gildas Bazin's avatar
 
Gildas Bazin committed
280
    if( !psz_name || !*psz_name )
281
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
282
        msg_Err( p_sub, "no subtitle file specified" );
283
        return VLC_EGENERIC;
284
    }
Eric Petit's avatar
Eric Petit committed
285

286 287 288 289 290 291
    /* *** load the file *** */
    if( text_load( &txt, psz_name ) )
    {
        msg_Err( p_sub, "cannot open `%s' subtitle file", psz_name );
        return VLC_EGENERIC;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
292

293 294
    msg_Dbg( p_sub, "opened `%s'", psz_name );

295 296
    var_Get( p_sub, "sub-fps", &val );
    if( val.i_int >= 1.0 )
297
    {
298
        i_microsecperframe = (mtime_t)( (float)1000000 / val.f_float );
299
    }
300 301 302 303 304
    else if( val.f_float == 0 )
    {
        /* No value given */
        i_microsecperframe = 0;
    }
305
    else if( val.f_float <= 0 )
306
    {
307 308
        /* invalid value, default = 25fps */
        i_microsecperframe = 40000;
309 310
    }

311 312
    var_Get( p_sub, "sub-type", &val);
    if( val.psz_string && *val.psz_string )
313
    {
314 315 316
        int i;

        for( i = 0; ; i++ )
317
        {
318 319 320 321 322 323
            if( sub_read_subtitle_function[i].psz_type_name == NULL )
            {
                i_sub_type = SUB_TYPE_UNKNOWN;
                break;
            }
            if( !strcmp( sub_read_subtitle_function[i].psz_type_name,
324
                         val.psz_string ) )
325 326 327 328
            {
                i_sub_type = sub_read_subtitle_function[i].i_type;
                break;
            }
329 330 331 332 333 334
        }
    }
    else
    {
        i_sub_type = SUB_TYPE_UNKNOWN;
    }
335
    FREE( val.psz_string );
Laurent Aimar's avatar
Laurent Aimar committed
336

337 338 339
    /* *** Now try to autodetect subtitle format *** */
    if( i_sub_type == SUB_TYPE_UNKNOWN )
    {
340 341 342
        int     i_try;
        char    *s;

343 344 345 346
        msg_Dbg( p_input, "trying to autodetect file format" );
        for( i_try = 0; i_try < MAX_TRY; i_try++ )
        {
            int i_dummy;
347 348

            if( ( s = text_get_line( &txt ) ) == NULL )
349 350 351 352
            {
                break;
            }

353
            if( local_stristr( s, "<SAMI>" ) )
354 355 356 357 358 359
            {
                i_sub_type = SUB_TYPE_SAMI;
                break;
            }
            else if( sscanf( s, "{%d}{%d}", &i_dummy, &i_dummy ) == 2 ||
                     sscanf( s, "{%d}{}", &i_dummy ) == 1)
360 361 362 363
            {
                i_sub_type = SUB_TYPE_MICRODVD;
                break;
            }
364
            else if( sscanf( s,
365
                             "%d:%d:%d,%d --> %d:%d:%d,%d",
Laurent Aimar's avatar
Laurent Aimar committed
366
                             &i_dummy,&i_dummy,&i_dummy,&i_dummy,
367 368 369 370 371
                             &i_dummy,&i_dummy,&i_dummy,&i_dummy ) == 8 )
            {
                i_sub_type = SUB_TYPE_SUBRIP;
                break;
            }
372
            else if( sscanf( s,
373 374 375 376 377 378 379 380 381
                             "!: This is a Sub Station Alpha v%d.x script.",
                             &i_dummy ) == 1)
            {
                if( i_dummy <= 1 )
                {
                    i_sub_type = SUB_TYPE_SSA1;
                }
                else
                {
382
                    i_sub_type = SUB_TYPE_SSA2_4; /* I hope this will work */
383
                }
384
                break;
385
            }
386
            else if( local_stristr( s, "This is a Sub Station Alpha v4 script" ) )
387
            {
388 389
                i_sub_type = SUB_TYPE_SSA2_4; /* I hope this will work */
                break;
390
            }
391
            else if( !strncasecmp( s, "Dialogue: Marked", 16  ) )
392
            {
393
                i_sub_type = SUB_TYPE_SSA2_4; /* could be wrong */
394 395
                break;
            }
396 397
            else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 ||
                     sscanf( s, "%d:%d:%d ", &i_dummy, &i_dummy, &i_dummy ) == 3 )
398 399 400
            {
                i_sub_type = SUB_TYPE_VPLAYER;
                break;
401
            }
402 403 404 405 406
            else if( local_stristr( s, "# VobSub index file" ) )
            {
                i_sub_type = SUB_TYPE_VOBSUB;
                break;
            }
407
        }
408 409

        text_rewind( &txt );
410 411 412
    }

    /* *** Load this file in memory *** */
413
    for( i = 0; ; i++ )
414
    {
415 416
        if( sub_read_subtitle_function[i].i_type == SUB_TYPE_UNKNOWN )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
417
            msg_Dbg( p_input, "unknown subtitle file" );
418
            text_unload( &txt );
Laurent Aimar's avatar
Laurent Aimar committed
419
            return VLC_EGENERIC;
420
        }
Laurent Aimar's avatar
Laurent Aimar committed
421

422 423
        if( sub_read_subtitle_function[i].i_type == i_sub_type )
        {
Gildas Bazin's avatar
 
Gildas Bazin committed
424
            msg_Dbg( p_input, "detected %s format",
425
                    sub_read_subtitle_function[i].psz_name );
426
            p_sub->i_sub_type = i_sub_type;
427 428 429
            pf_read_subtitle = sub_read_subtitle_function[i].pf_read_subtitle;
            break;
        }
430
    }
431

432
    for( i_max = 0;; )
Laurent Aimar's avatar
Laurent Aimar committed
433 434
    {
        if( p_sub->i_subtitles >= i_max )
435 436
        {
            i_max += 128;
Gildas Bazin's avatar
 
Gildas Bazin committed
437 438
            if( !( p_sub->subtitle = realloc( p_sub->subtitle,
                                              sizeof(subtitle_t) * i_max ) ) )
439
            {
Gildas Bazin's avatar
 
Gildas Bazin committed
440 441
                msg_Err( p_sub, "out of memory");
                return VLC_ENOMEM;
442 443
            }
        }
444
        if( pf_read_subtitle( p_sub, &txt,
Laurent Aimar's avatar
Laurent Aimar committed
445
                              p_sub->subtitle + p_sub->i_subtitles,
446 447 448 449 450 451 452 453 454
                              i_microsecperframe ) < 0 )
        {
            break;
        }
        p_sub->i_subtitles++;
    }
    msg_Dbg( p_sub, "loaded %d subtitles", p_sub->i_subtitles );

    /* *** Close the file *** */
455
    text_unload( &txt );
456 457

    /* *** fix subtitle (order and time) *** */
458
    p_sub->i_subtitle = 0;  /* will be modified by sub_fix */
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
459
    
460 461 462 463
    if( p_sub->i_sub_type != SUB_TYPE_VOBSUB )
    {
        sub_fix( p_sub );
    }
Laurent Aimar's avatar
Laurent Aimar committed
464

465
    /* *** add subtitle ES *** */
466
    if( p_sub->i_sub_type == SUB_TYPE_VOBSUB )
467
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
468 469 470 471
        int i_len = strlen( psz_name );
        char *psz_vobname = strdup(psz_name);

        strcpy( psz_vobname + i_len - 4, ".sub" );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
472 473 474 475 476 477

        /* open file */
        if( !( p_sub->p_vobsub_file = fopen( psz_vobname, "rb" ) ) )
        {
            msg_Err( p_sub, "couldn't open .sub Vobsub file: %s", psz_vobname );
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
478
        free( psz_vobname );
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
479

480
        es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','p','u',' ' ) );
481
    }
482 483 484
    else if( p_sub->i_sub_type == SUB_TYPE_SSA1 ||
             p_sub->i_sub_type == SUB_TYPE_SSA2_4 )
    {
485
        es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','s','a',' ' ) );
486 487 488
    }
    else
    {
489
        es_format_Init( &fmt, SPU_ES, VLC_FOURCC( 's','u','b','t' ) );
490
    }
491 492 493 494 495 496
    if( p_sub->psz_header != NULL )
    {
        fmt.i_extra = strlen( p_sub->psz_header ) + 1;
        fmt.p_extra = strdup( p_sub->psz_header );
    }
    p_sub->p_es = es_out_Add( p_input->p_es_out, &fmt );
497
    p_sub->i_previously_selected = 0;
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
498

Laurent Aimar's avatar
Laurent Aimar committed
499
    return VLC_SUCCESS;
500 501 502 503 504 505 506
}

/*****************************************************************************
 * sub_demux: Send subtitle to decoder until i_maxdate
 *****************************************************************************/
static int  sub_demux( subtitle_demux_t *p_sub, mtime_t i_maxdate )
{
507 508
    input_thread_t *p_input = p_sub->p_input;
    vlc_bool_t     b;
509 510
    vlc_value_t    val;
    mtime_t i_delay;
511

512
    es_out_Control( p_input->p_es_out, ES_OUT_GET_ES_STATE, p_sub->p_es, &b );
513
    if( b && !p_sub->i_previously_selected )
514 515 516
    {
        p_sub->i_previously_selected = 1;
        p_sub->pf_seek( p_sub, i_maxdate );
Laurent Aimar's avatar
Laurent Aimar committed
517
        return VLC_SUCCESS;
518
    }
519
    else if( !b && p_sub->i_previously_selected )
520 521
    {
        p_sub->i_previously_selected = 0;
Laurent Aimar's avatar
Laurent Aimar committed
522
        return VLC_SUCCESS;
523 524
    }

525
    if( p_sub->i_sub_type != SUB_TYPE_VOBSUB )
526
    {
527 528
        var_Get( p_sub, "sub-delay", &val );
        i_delay = (mtime_t) val.i_int * 100000;
529
        while( p_sub->i_subtitle < p_sub->i_subtitles &&
530
               p_sub->subtitle[p_sub->i_subtitle].i_start < i_maxdate - i_delay )
531
        {
532 533 534
            block_t *p_block;
            int i_len = strlen( p_sub->subtitle[p_sub->i_subtitle].psz_text ) + 1;

535 536 537 538 539 540
            if( i_len <= 1 )
            {
                /* empty subtitle */
                p_sub->i_subtitle++;
                continue;
            }
541 542

            if( ( p_block = block_New( p_sub->p_input, i_len ) ) == NULL )
543 544 545 546
            {
                p_sub->i_subtitle++;
                continue;
            }
Laurent Aimar's avatar
Laurent Aimar committed
547

548 549 550 551 552 553 554
            /* XXX we should convert all demuxers to use es_out_Control to set              * pcr and then remove that */
            if( i_delay != 0 )
            {
                p_sub->subtitle[p_sub->i_subtitle].i_start += i_delay;
                p_sub->subtitle[p_sub->i_subtitle].i_stop += i_delay;
            }

555
            p_block->i_pts =
Laurent Aimar's avatar
Laurent Aimar committed
556
                input_ClockGetTS( p_sub->p_input,
557 558
                                  p_sub->p_input->stream.p_selected_program,
                                  p_sub->subtitle[p_sub->i_subtitle].i_start*9/100);
Gildas Bazin's avatar
 
Gildas Bazin committed
559
            p_block->i_dts = 0;
560 561 562 563 564 565 566 567
            if( p_sub->subtitle[p_sub->i_subtitle].i_stop > 0 )
            {
                /* FIXME kludge i_dts means end of display... */
                p_block->i_dts =
                    input_ClockGetTS( p_sub->p_input,
                                  p_sub->p_input->stream.p_selected_program,
                                  p_sub->subtitle[p_sub->i_subtitle].i_stop *9/100);
            }
568

569
            memcpy( p_block->p_buffer, p_sub->subtitle[p_sub->i_subtitle].psz_text, i_len );
570 571 572 573 574 575 576 577 578 579
            if( p_block->i_pts > 0 )
            {
                es_out_Send( p_input->p_es_out, p_sub->p_es, p_block );
            }
            else
            {
                block_Release( p_block );
            }
            p_sub->i_subtitle++;
        }
580 581 582 583 584
    }
    else
    {
        while( p_sub->i_subtitle < p_sub->i_subtitles &&
               p_sub->subtitle[p_sub->i_subtitle].i_start < i_maxdate )
585
        {
586 587 588 589 590 591 592 593 594 595 596 597
            int i_pos = p_sub->subtitle[p_sub->i_subtitle].i_vobsub_location;
            block_t *p_block;
            int i_size = 0;

            /* first compute SPU size */
            if( p_sub->i_subtitle + 1 < p_sub->i_subtitles )
            {
                i_size = p_sub->subtitle[p_sub->i_subtitle+1].i_vobsub_location - i_pos;
            }
            if( i_size <= 0 ) i_size = 65535;   /* Invalid or EOF */

            /* Seek at the right place (could be avoid if sub_seek is fixed to do his job) */
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
598
            if( fseek( p_sub->p_vobsub_file, i_pos, SEEK_SET ) )
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
            {
                msg_Warn( p_sub, "cannot seek at right vobsub location %d", i_pos );
                p_sub->i_subtitle++;
                continue;
            }

            /* allocate a packet */
            if( ( p_block = block_New( p_sub, i_size ) ) == NULL )
            {
                p_sub->i_subtitle++;
                continue;
            }

            /* read data */
            p_block->i_buffer = fread( p_block->p_buffer, 1, i_size, p_sub->p_vobsub_file );
            if( p_block->i_buffer <= 6 )
            {
                block_Release( p_block );
                p_sub->i_subtitle++;
                continue;
            }

            /* pts */
            p_block->i_pts =
                input_ClockGetTS( p_sub->p_input,
                                  p_sub->p_input->stream.p_selected_program,
                                  p_sub->subtitle[p_sub->i_subtitle].i_start*9/100);

            /* demux this block */
            DemuxVobSub( p_sub, p_block );

630
            p_sub->i_subtitle++;
631 632
        }
    }
633
    return VLC_SUCCESS;
634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
}

/*****************************************************************************
 * sub_seek: Seek to i_date
 *****************************************************************************/
static int  sub_seek ( subtitle_demux_t *p_sub, mtime_t i_date )
{
    /* should be fast enough... */
    p_sub->i_subtitle = 0;
    while( p_sub->i_subtitle < p_sub->i_subtitles &&
           p_sub->subtitle[p_sub->i_subtitle].i_start < i_date )
    {
        p_sub->i_subtitle++;
    }
    return( 0 );
}

/*****************************************************************************
 * sub_close: Close subtitle demux
 *****************************************************************************/
static void sub_close( subtitle_demux_t *p_sub )
{
    if( p_sub->subtitle )
    {
        int i;
        for( i = 0; i < p_sub->i_subtitles; i++ )
        {
            if( p_sub->subtitle[i].psz_text )
            {
                free( p_sub->subtitle[i].psz_text );
            }
        }
        free( p_sub->subtitle );
    }
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
668 669 670 671
    if( p_sub->p_vobsub_file )
    {
        fclose( p_sub->p_vobsub_file );
    }
672
}
673

674 675 676 677 678 679 680 681 682
/*****************************************************************************
 * sub_fix: fix time stamp and order of subtitle
 *****************************************************************************/
static void  sub_fix( subtitle_demux_t *p_sub )
{
    int     i;
    mtime_t i_delay;
    int     i_index;
    int     i_done;
683
    vlc_value_t val;
684 685 686 687 688 689 690 691 692 693 694 695 696 697

    /* *** fix order (to be sure...) *** */
    /* We suppose that there are near in order and this durty bubble sort
     * wont take too much time
     */
    do
    {
        i_done = 1;
        for( i_index = 1; i_index < p_sub->i_subtitles; i_index++ )
        {
            if( p_sub->subtitle[i_index].i_start <
                    p_sub->subtitle[i_index - 1].i_start )
            {
                subtitle_t sub_xch;
Laurent Aimar's avatar
Laurent Aimar committed
698 699
                memcpy( &sub_xch,
                        p_sub->subtitle + i_index - 1,
700
                        sizeof( subtitle_t ) );
Laurent Aimar's avatar
Laurent Aimar committed
701 702
                memcpy( p_sub->subtitle + i_index - 1,
                        p_sub->subtitle + i_index,
703 704 705 706 707 708 709 710
                        sizeof( subtitle_t ) );
                memcpy( p_sub->subtitle + i_index,
                        &sub_xch,
                        sizeof( subtitle_t ) );
                i_done = 0;
            }
        }
    } while( !i_done );
Laurent Aimar's avatar
Laurent Aimar committed
711

712
    /* *** and at the end add delay *** */
713 714
    var_Get( p_sub, "sub-delay", &val );
    i_delay = (mtime_t) val.i_int * 100000;
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731
    if( i_delay != 0 )
    {
        for( i = 0; i < p_sub->i_subtitles; i++ )
        {
            p_sub->subtitle[i].i_start += i_delay;
            p_sub->subtitle[i].i_stop += i_delay;
            if( p_sub->subtitle[i].i_start < 0 )
            {
                p_sub->i_subtitle = i + 1;
            }
        }
    }
}



/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
732
 * Specific Subtitle function
733
 *****************************************************************************/
734
static int  sub_MicroDvdRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
735 736 737 738 739 740 741
{
    /*
     * each line:
     *  {n1}{n2}Line1|Line2|Line3....
     * where n1 and n2 are the video frame number...
     *
     */
742 743
    char *s;

744
    char buffer_text[MAX_LINE + 1];
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
745 746
    unsigned int    i_start;
    unsigned int    i_stop;
747
    unsigned int i;
748 749 750 751 752
    
    p_subtitle->i_start = 0;
    p_subtitle->i_stop  = 0;
    p_subtitle->i_vobsub_location  = 0;
    p_subtitle->psz_text = NULL;
Laurent Aimar's avatar
Laurent Aimar committed
753

754 755
    for( ;; )
    {
756
        if( ( s = text_get_line( txt ) ) == NULL )
757
        {
758
            return( VLC_EGENERIC );
759 760 761
        }
        i_start = 0;
        i_stop  = 0;
Laurent Aimar's avatar
Laurent Aimar committed
762 763

        memset( buffer_text, '\0', MAX_LINE );
764 765
        if( sscanf( s, "{%d}{}%[^\r\n]", &i_start, buffer_text ) == 2 ||
            sscanf( s, "{%d}{%d}%[^\r\n]", &i_start, &i_stop, buffer_text ) == 3)
766 767 768 769 770
        {
            break;
        }
    }
    /* replace | by \n */
Laurent Aimar's avatar
Laurent Aimar committed
771
    for( i = 0; i < strlen( buffer_text ); i++ )
772 773 774 775 776 777
    {
        if( buffer_text[i] == '|' )
        {
            buffer_text[i] = '\n';
        }
    }
778 779 780 781
    if( i_microsecperframe == 0)
    {
        i_microsecperframe = 40000;
    }
782 783
    p_subtitle->i_start = (mtime_t)i_start * (mtime_t)i_microsecperframe;
    p_subtitle->i_stop  = (mtime_t)i_stop  * (mtime_t)i_microsecperframe;
784
    p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
785 786 787
    return( 0 );
}

788
static int  sub_SubRipRead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
789 790 791 792 793 794 795 796
{
    /*
     * n
     * h1:m1:s1,d1 --> h2:m2:s2,d2
     * Line1
     * Line2
     * ...
     * [empty line]
Laurent Aimar's avatar
Laurent Aimar committed
797
     *
798
     */
799
    char *s;
800 801 802 803 804
    char buffer_text[ 10 * MAX_LINE];
    int  i_buffer_text;
    mtime_t     i_start;
    mtime_t     i_stop;

805 806 807 808 809
    p_subtitle->i_start = 0;
    p_subtitle->i_stop  = 0;
    p_subtitle->i_vobsub_location  = 0;
    p_subtitle->psz_text = NULL;

810 811 812
    for( ;; )
    {
        int h1, m1, s1, d1, h2, m2, s2, d2;
813
        if( ( s = text_get_line( txt ) ) == NULL )
814
        {
815
            return( VLC_EGENERIC );
816
        }
817
        if( sscanf( s,
818 819 820 821
                    "%d:%d:%d,%d --> %d:%d:%d,%d",
                    &h1, &m1, &s1, &d1,
                    &h2, &m2, &s2, &d2 ) == 8 )
        {
Laurent Aimar's avatar
Laurent Aimar committed
822 823 824
            i_start = ( (mtime_t)h1 * 3600*1000 +
                        (mtime_t)m1 * 60*1000 +
                        (mtime_t)s1 * 1000 +
825 826
                        (mtime_t)d1 ) * 1000;

Laurent Aimar's avatar
Laurent Aimar committed
827 828 829
            i_stop  = ( (mtime_t)h2 * 3600*1000 +
                        (mtime_t)m2 * 60*1000 +
                        (mtime_t)s2 * 1000 +
830
                        (mtime_t)d2 ) * 1000;
831

832 833 834 835
            /* Now read text until an empty line */
            for( i_buffer_text = 0;; )
            {
                int i_len;
836
                if( ( s = text_get_line( txt ) ) == NULL )
837
                {
838
                    return( VLC_EGENERIC );
839
                }
840 841 842

                i_len = strlen( s );
                if( i_len <= 1 )
843
                {
844
                    /* empty line -> end of this subtitle */
845 846 847 848
                    buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
                    p_subtitle->i_start = i_start;
                    p_subtitle->i_stop = i_stop;
                    p_subtitle->psz_text = strdup( buffer_text );
849 850 851 852 853 854 855 856 857 858
                    /* If framerate is available, use sub-fps */
                    if( i_microsecperframe != 0 && p_sub->i_original_mspf != 0)
                    {
                        p_subtitle->i_start = (mtime_t)i_start *
                                              (mtime_t)p_sub->i_original_mspf /
                                              (mtime_t)i_microsecperframe;
                        p_subtitle->i_stop  = (mtime_t)i_stop  *
                                              (mtime_t)p_sub->i_original_mspf /
                                              (mtime_t)i_microsecperframe;
                    }
859 860 861 862
                    return( 0 );
                }
                else
                {
863 864 865
                    if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
                    {
                        memcpy( buffer_text + i_buffer_text,
866
                                s,
867 868 869 870 871 872
                                i_len );
                        i_buffer_text += i_len;

                        buffer_text[i_buffer_text] = '\n';
                        i_buffer_text++;
                    }
873 874 875 876 877 878 879
                }
            }
        }
    }
}


880
static int  sub_SSARead( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe )
881 882
{
    char buffer_text[ 10 * MAX_LINE];
883
    char *s;
884 885
    mtime_t     i_start;
    mtime_t     i_stop;
Laurent Aimar's avatar
Laurent Aimar committed
886

887 888 889 890 891
    p_subtitle->i_start = 0;
    p_subtitle->i_stop  = 0;
    p_subtitle->i_vobsub_location  = 0;
    p_subtitle->psz_text = NULL;

892 893 894 895
    for( ;; )
    {
        int h1, m1, s1, c1, h2, m2, s2, c2;
        int i_dummy;
896 897

        if( ( s = text_get_line( txt ) ) == NULL )
898
        {
899
            return( VLC_EGENERIC );
900
        }
901 902
        p_subtitle->psz_text = malloc( strlen( s ) );

903
        if( sscanf( s,
904
                    "Dialogue: Marked=%d,%d:%d:%d.%d,%d:%d:%d.%d%[^\r\n]",
Laurent Aimar's avatar
Laurent Aimar committed
905
                    &i_dummy,
906 907 908 909
                    &h1, &m1, &s1, &c1,
                    &h2, &m2, &s2, &c2,
                    buffer_text ) == 10 )
        {
Laurent Aimar's avatar
Laurent Aimar committed
910 911 912
            i_start = ( (mtime_t)h1 * 3600*1000 +
                        (mtime_t)m1 * 60*1000 +
                        (mtime_t)s1 * 1000 +
913 914
                        (mtime_t)c1 * 10 ) * 1000;

Laurent Aimar's avatar
Laurent Aimar committed
915 916 917
            i_stop  = ( (mtime_t)h2 * 3600*1000 +
                        (mtime_t)m2 * 60*1000 +
                        (mtime_t)s2 * 1000 +
918
                        (mtime_t)c2 * 10 ) * 1000;
Laurent Aimar's avatar
Laurent Aimar committed
919

920 921
            /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
            if( p_sub->i_sub_type == SUB_TYPE_SSA1 )
Laurent Aimar's avatar
Laurent Aimar committed
922
            {
923 924 925 926 927
                sprintf( p_subtitle->psz_text, ",%d%s", i_dummy, strdup( buffer_text) );
            }
            else
            {
                sprintf( p_subtitle->psz_text, ",%d,%s", i_dummy, strdup( buffer_text) );
928
            }
929 930 931 932 933 934 935 936
            p_subtitle->i_start = i_start;
            p_subtitle->i_stop = i_stop;
            return( 0 );
        }
        else
        {
            /* All the other stuff we add to the header field */
            if( p_sub->psz_header != NULL )
937
            {
938 939
                if( !( p_sub->psz_header = realloc( p_sub->psz_header,
                          strlen( p_sub->psz_header ) + strlen( s ) + 2 ) ) )
940
                {
941 942
                    msg_Err( p_sub, "out of memory");
                    return VLC_ENOMEM;
943
                }
944 945 946 947 948 949
                p_sub->psz_header = strcat( p_sub->psz_header, strdup( s ) );
                p_sub->psz_header = strcat( p_sub->psz_header, "\n" );
            }
            else
            {
                if( !( p_sub->psz_header = malloc( strlen( s ) + 2 ) ) )
950
                {
951 952
                    msg_Err( p_sub, "out of memory");
                    return VLC_ENOMEM;
953
                }
954 955
                p_sub->psz_header = strdup( s );
                p_sub->psz_header = strcat( p_sub->psz_header, "\n" );
956 957 958 959 960
            }
        }
    }
}

961
static int  sub_Vplayer( subtitle_demux_t *p_sub, text_t *txt, subtitle_t *p_subtitle, mtime_t i_microsecperframe)
962 963 964 965 966 967 968 969 970
{
    /*
     * each line:
     *  h:m:s:Line1|Line2|Line3....
     *  or
     *  h:m:s Line1|Line2|Line3....
     * where n1 and n2 are the video frame number...
     *
     */
971
    char *p;
972 973 974
    char buffer_text[MAX_LINE + 1];
    mtime_t    i_start;
    unsigned int i;
975 976 977 978 979
    
    p_subtitle->i_start = 0;
    p_subtitle->i_stop  = 0;
    p_subtitle->i_vobsub_location  = 0;
    p_subtitle->psz_text = NULL;
980 981 982 983 984 985

    for( ;; )
    {
        int h, m, s;
        char c;

986
        if( ( p = text_get_line( txt ) ) == NULL )
987
        {
988
            return( VLC_EGENERIC );
989
        }
990

991 992 993
        i_start = 0;

        memset( buffer_text, '\0', MAX_LINE );
994
        if( sscanf( p, "%d:%d:%d%[ :]%[^\r\n]", &h, &m, &s, &c, buffer_text ) == 5 )
995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
        {
            i_start = ( (mtime_t)h * 3600*1000 +
                        (mtime_t)m * 60*1000 +
                        (mtime_t)s * 1000 ) * 1000;
            break;
        }
    }

    /* replace | by \n */
    for( i = 0; i < strlen( buffer_text ); i++ )
    {
        if( buffer_text[i] == '|' )
        {
            buffer_text[i] = '\n';
        }
    }
    p_subtitle->i_start = i_start;

    p_subtitle->i_stop  = 0;
    p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
    return( 0 );
}
1017

1018
static char *sub_SamiSearch( text_t *txt, char *psz_start, char *psz_str )
1019
{
1020 1021
    if( psz_start )
    {
1022
        if( local_stristr( psz_start, psz_str ) )
1023
        {
1024
            char *s = local_stristr( psz_start, psz_str );
1025

1026 1027 1028 1029 1030
            s += strlen( psz_str );

            return( s );
        }
    }
1031 1032
    for( ;; )
    {
1033 1034
        char *p;
        if( ( p = text_get_line( txt ) ) == NULL )
1035
        {
1036
            return NULL;
1037
        }
1038
        if( local_stristr( p, psz_str ) )
1039
        {
1040
            char *s = local_stristr( p, psz_str );
1041 1042