~ubuntu-branches/ubuntu/maverick/vlc/maverick

« back to all changes in this revision

Viewing changes to modules/demux/subtitle.c

  • Committer: Bazaar Package Importer
  • Author(s): Reinhard Tartler
  • Date: 2008-09-17 21:56:14 UTC
  • mfrom: (1.1.17 upstream)
  • Revision ID: james.westby@ubuntu.com-20080917215614-tj0vx8xzd57e52t8
Tags: 0.9.2-1ubuntu1
* New Upstream Release, exception granted by
    - dktrkranz, norsetto, Hobbsee (via irc). LP: #270404

Changes done in ubuntu:

* add libxul-dev to build-depends
* make sure that vlc is build against libxul in configure. This doesn't
  change anything in the package, but makes it more robust if building
  in an 'unclean' chroot or when modifying the package.
* debian/control: make Vcs-* fields point to the motumedia branch
* add libx264-dev and libass-dev to build-depends
  LP: #210354, #199870
* actually enable libass support by passing --enable-libass to configure
* enable libdca: add libdca-dev to build depends and --enable-libdca
* install the x264 plugin.

Changes already in the pkg-multimedia branch in debian:

* don't install usr/share/vlc/mozilla in debian/mozilla-plugin-vlc.install  
* new upstream .desktop file now registers flash video mimetype LP: #261567
* add Xb-Npp-Applications to mozilla-plugin-vlc
* remove duplicate entries in debian/vlc-nox.install

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*****************************************************************************
2
2
 * subtitle.c: Demux for subtitle text files.
3
3
 *****************************************************************************
4
 
 * Copyright (C) 1999-2004 the VideoLAN team
5
 
 * $Id: 6990562ea05f756333a9a79d2d41a4dcc407331c $
 
4
 * Copyright (C) 1999-2007 the VideoLAN team
 
5
 * $Id: 8883d124d5305d889df7cb55055d27fbfc44bb9c $
6
6
 *
7
7
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8
8
 *          Derk-Jan Hartman <hartman at videolan dot org>
 
9
 *          Jean-Baptiste Kempf <jb@videolan.org>
9
10
 *
10
11
 * This program is free software; you can redistribute it and/or modify
11
12
 * it under the terms of the GNU General Public License as published by
25
26
/*****************************************************************************
26
27
 * Preamble
27
28
 *****************************************************************************/
28
 
#include <stdlib.h>
 
29
 
 
30
#ifdef HAVE_CONFIG_H
 
31
# include "config.h"
 
32
#endif
 
33
 
 
34
#include <vlc_common.h>
 
35
#include <vlc_plugin.h>
 
36
#include <vlc_input.h>
29
37
 
30
38
#include <errno.h>
31
39
#ifdef HAVE_SYS_TYPES_H
33
41
#endif
34
42
#include <ctype.h>
35
43
 
36
 
#include <vlc/vlc.h>
37
 
#include <vlc/input.h>
38
 
#include "vlc_video.h"
 
44
#include <vlc_demux.h>
 
45
#include <vlc_charset.h>
39
46
 
40
47
/*****************************************************************************
41
48
 * Module descriptor
50
57
    "This will only work with MicroDVD and SubRIP (SRT) subtitles.")
51
58
#define SUB_TYPE_LONGTEXT \
52
59
    N_("Force the subtiles format. Valid values are : \"microdvd\", " \
53
 
    "\"subrip\",  \"ssa1\", \"ssa2-4\", \"ass\", \"vplayer\" " \
54
 
    "\"sami\", \"dvdsubtitle\" and \"auto\" (meaning autodetection, this " \
55
 
    "should always work).")
56
 
static char *ppsz_sub_type[] =
 
60
    "\"subrip\", \"subviewer\", \"ssa1\", \"ssa2-4\", \"ass\", \"vplayer\", " \
 
61
    "\"sami\", \"dvdsubtitle\", \"mpl2\", \"aqt\", \"pjs\", "\
 
62
    "\"mpsub\", \"jacosub\", \"psb\", \"realtext\", \"dks\", \"subviewer1\", " \
 
63
    " and \"auto\" (meaning autodetection, this should always work).")
 
64
 
 
65
static const char *const ppsz_sub_type[] =
57
66
{
58
67
    "auto", "microdvd", "subrip", "subviewer", "ssa1",
59
 
    "ssa2-4", "ass", "vplayer", "sami", "dvdsubtitle"
 
68
    "ssa2-4", "ass", "vplayer", "sami", "dvdsubtitle", "mpl2",
 
69
    "aqt", "pjs", "mpsub", "jacosub", "psb", "realtext", "dks",
 
70
    "subviewer1"
60
71
};
61
72
 
62
73
vlc_module_begin();
63
 
    set_shortname( _("Subtitles"));
64
 
    set_description( _("Text subtitles parser") );
65
 
    set_capability( "demux2", 0 );
 
74
    set_shortname( N_("Subtitles"));
 
75
    set_description( N_("Text subtitles parser") );
 
76
    set_capability( "demux", 0 );
66
77
    set_category( CAT_INPUT );
67
78
    set_subcategory( SUBCAT_INPUT_DEMUX );
68
79
    add_float( "sub-fps", 0.0, NULL,
69
80
               N_("Frames per second"),
70
 
               SUB_FPS_LONGTEXT, VLC_TRUE );
 
81
               SUB_FPS_LONGTEXT, true );
71
82
    add_integer( "sub-delay", 0, NULL,
72
83
               N_("Subtitles delay"),
73
 
               SUB_DELAY_LONGTEXT, VLC_TRUE );
 
84
               SUB_DELAY_LONGTEXT, true );
74
85
    add_string( "sub-type", "auto", NULL, N_("Subtitles format"),
75
 
                SUB_TYPE_LONGTEXT, VLC_TRUE );
76
 
        change_string_list( ppsz_sub_type, 0, 0 );
 
86
                SUB_TYPE_LONGTEXT, true );
 
87
        change_string_list( ppsz_sub_type, NULL, NULL );
77
88
    set_callbacks( Open, Close );
78
89
 
79
90
    add_shortcut( "subtitle" );
92
103
    SUB_TYPE_ASS,
93
104
    SUB_TYPE_VPLAYER,
94
105
    SUB_TYPE_SAMI,
95
 
    SUB_TYPE_SUBVIEWER,
96
 
    SUB_TYPE_DVDSUBTITLE
 
106
    SUB_TYPE_SUBVIEWER, /* SUBVIEWER 2 */
 
107
    SUB_TYPE_DVDSUBTITLE, /* Mplayer calls it subviewer2 */
 
108
    SUB_TYPE_MPL2,
 
109
    SUB_TYPE_AQT,
 
110
    SUB_TYPE_PJS,
 
111
    SUB_TYPE_MPSUB,
 
112
    SUB_TYPE_JACOSUB,
 
113
    SUB_TYPE_PSB,
 
114
    SUB_TYPE_RT,
 
115
    SUB_TYPE_DKS,
 
116
    SUB_TYPE_SUBVIEW1 /* SUBVIEWER 1 - mplayer calls it subrip09,
 
117
                         and Gnome subtitles SubViewer 1.0 */
97
118
};
98
119
 
99
120
typedef struct
102
123
    int     i_line;
103
124
    char    **line;
104
125
} text_t;
 
126
 
105
127
static int  TextLoad( text_t *, stream_t *s );
106
128
static void TextUnload( text_t * );
107
129
 
121
143
    es_out_id_t *es;
122
144
 
123
145
    int64_t     i_next_demux_date;
124
 
 
125
146
    int64_t     i_microsecperframe;
126
 
    int64_t     i_original_mspf;
127
147
 
128
148
    char        *psz_header;
129
149
    int         i_subtitle;
131
151
    subtitle_t  *subtitle;
132
152
 
133
153
    int64_t     i_length;
 
154
 
 
155
    /* */
 
156
    struct
 
157
    {
 
158
        bool b_inited;
 
159
 
 
160
        int i_comment;
 
161
        int i_time_resolution;
 
162
        int i_time_shift;
 
163
    } jss;
 
164
    struct
 
165
    {
 
166
        bool  b_inited;
 
167
 
 
168
        float f_total;
 
169
        float f_factor;
 
170
    } mpsub;
134
171
};
135
172
 
136
 
static int  ParseMicroDvd   ( demux_t *, subtitle_t * );
137
 
static int  ParseSubRip     ( demux_t *, subtitle_t * );
138
 
static int  ParseSubViewer  ( demux_t *, subtitle_t * );
139
 
static int  ParseSSA        ( demux_t *, subtitle_t * );
140
 
static int  ParseVplayer    ( demux_t *, subtitle_t * );
141
 
static int  ParseSami       ( demux_t *, subtitle_t * );
142
 
static int  ParseDVDSubtitle( demux_t *, subtitle_t * );
 
173
static int  ParseMicroDvd   ( demux_t *, subtitle_t *, int );
 
174
static int  ParseSubRip     ( demux_t *, subtitle_t *, int );
 
175
static int  ParseSubViewer  ( demux_t *, subtitle_t *, int );
 
176
static int  ParseSSA        ( demux_t *, subtitle_t *, int );
 
177
static int  ParseVplayer    ( demux_t *, subtitle_t *, int );
 
178
static int  ParseSami       ( demux_t *, subtitle_t *, int );
 
179
static int  ParseDVDSubtitle( demux_t *, subtitle_t *, int );
 
180
static int  ParseMPL2       ( demux_t *, subtitle_t *, int );
 
181
static int  ParseAQT        ( demux_t *, subtitle_t *, int );
 
182
static int  ParsePJS        ( demux_t *, subtitle_t *, int );
 
183
static int  ParseMPSub      ( demux_t *, subtitle_t *, int );
 
184
static int  ParseJSS        ( demux_t *, subtitle_t *, int );
 
185
static int  ParsePSB        ( demux_t *, subtitle_t *, int );
 
186
static int  ParseRealText   ( demux_t *, subtitle_t *, int );
 
187
static int  ParseDKS        ( demux_t *, subtitle_t *, int );
 
188
static int  ParseSubViewer1 ( demux_t *, subtitle_t *, int );
143
189
 
144
 
static struct
 
190
static const struct
145
191
{
146
 
    char *psz_type_name;
 
192
    const char *psz_type_name;
147
193
    int  i_type;
148
 
    char *psz_name;
149
 
    int  (*pf_read)( demux_t *, subtitle_t* );
 
194
    const char *psz_name;
 
195
    int  (*pf_read)( demux_t *, subtitle_t*, int );
150
196
} sub_read_subtitle_function [] =
151
197
{
152
198
    { "microdvd",   SUB_TYPE_MICRODVD,    "MicroDVD",    ParseMicroDvd },
158
204
    { "vplayer",    SUB_TYPE_VPLAYER,     "VPlayer",     ParseVplayer },
159
205
    { "sami",       SUB_TYPE_SAMI,        "SAMI",        ParseSami },
160
206
    { "dvdsubtitle",SUB_TYPE_DVDSUBTITLE, "DVDSubtitle", ParseDVDSubtitle },
 
207
    { "mpl2",       SUB_TYPE_MPL2,        "MPL2",        ParseMPL2 },
 
208
    { "aqt",        SUB_TYPE_AQT,         "AQTitle",     ParseAQT },
 
209
    { "pjs",        SUB_TYPE_PJS,         "PhoenixSub",  ParsePJS },
 
210
    { "mpsub",      SUB_TYPE_MPSUB,       "MPSub",       ParseMPSub },
 
211
    { "jacosub",    SUB_TYPE_JACOSUB,     "JacoSub",     ParseJSS },
 
212
    { "psb",        SUB_TYPE_PSB,         "PowerDivx",   ParsePSB },
 
213
    { "realtext",   SUB_TYPE_RT,          "RealText",    ParseRealText },
 
214
    { "dks",        SUB_TYPE_DKS,         "DKS",         ParseDKS },
 
215
    { "subviewer1", SUB_TYPE_SUBVIEW1,    "Subviewer 1", ParseSubViewer1 },
161
216
    { NULL,         SUB_TYPE_UNKNOWN,     "Unknown",     NULL }
162
217
};
163
218
 
174
229
    demux_t        *p_demux = (demux_t*)p_this;
175
230
    demux_sys_t    *p_sys;
176
231
    es_format_t    fmt;
177
 
    input_thread_t *p_input;
178
232
    float          f_fps;
179
233
    char           *psz_type;
180
 
    int  (*pf_read)( demux_t *, subtitle_t* );
 
234
    int  (*pf_read)( demux_t *, subtitle_t*, int );
181
235
    int            i, i_max;
182
236
 
183
 
    if( strcmp( p_demux->psz_demux, "subtitle" ) )
 
237
    if( !p_demux->b_force )
184
238
    {
185
239
        msg_Dbg( p_demux, "subtitle demux discarded" );
186
240
        return VLC_EGENERIC;
189
243
    p_demux->pf_demux = Demux;
190
244
    p_demux->pf_control = Control;
191
245
    p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
 
246
    if( p_sys == NULL )
 
247
        return VLC_ENOMEM;
 
248
 
192
249
    p_sys->psz_header         = NULL;
193
250
    p_sys->i_subtitle         = 0;
194
251
    p_sys->i_subtitles        = 0;
195
252
    p_sys->subtitle           = NULL;
196
 
    p_sys->i_microsecperframe = 0;
197
 
    p_sys->i_original_mspf    = 0;
 
253
    p_sys->i_microsecperframe = 40000;
 
254
 
 
255
    p_sys->jss.b_inited       = false;
 
256
    p_sys->mpsub.b_inited     = false;
198
257
 
199
258
    /* Get the FPS */
 
259
    f_fps = var_CreateGetFloat( p_demux, "sub-original-fps" ); /* FIXME */
 
260
    if( f_fps >= 1.0 )
 
261
        p_sys->i_microsecperframe = (int64_t)( (float)1000000 / f_fps );
 
262
 
 
263
    msg_Dbg( p_demux, "Movie fps: %f", f_fps );
 
264
 
 
265
    /* Check for override of the fps */
200
266
    f_fps = var_CreateGetFloat( p_demux, "sub-fps" );
201
267
    if( f_fps >= 1.0 )
202
268
    {
204
270
        msg_Dbg( p_demux, "Override subtitle fps %f", f_fps );
205
271
    }
206
272
 
207
 
    p_input = (input_thread_t *)vlc_object_find( p_demux, VLC_OBJECT_INPUT, FIND_PARENT );
208
 
    if( p_input )
209
 
    {
210
 
        f_fps = var_GetFloat( p_input, "sub-original-fps" );
211
 
        if( f_fps >= 1.0 )
212
 
            p_sys->i_original_mspf = (int64_t)( (float)1000000 / f_fps );
213
 
 
214
 
        msg_Dbg( p_demux, "Movie fps: %f", f_fps );
215
 
        vlc_object_release( p_input );
216
 
    }
217
 
 
218
273
    /* Get or probe the type */
219
274
    p_sys->i_type = SUB_TYPE_UNKNOWN;
220
275
    psz_type = var_CreateGetString( p_demux, "sub-type" );
221
 
    if( *psz_type )
 
276
    if( psz_type && *psz_type )
222
277
    {
223
278
        int i;
224
279
 
247
302
        for( i_try = 0; i_try < 256; i_try++ )
248
303
        {
249
304
            int i_dummy;
 
305
            char p_dummy;
250
306
 
251
307
            if( ( s = stream_ReadLine( p_demux->s ) ) == NULL )
252
308
                break;
300
356
                p_sys->i_type = SUB_TYPE_SUBVIEWER; /* I hope this will work */
301
357
                break;
302
358
            }
 
359
            else if( sscanf( s, "%d:%d:%d.%d %d:%d:%d",
 
360
                                 &i_dummy, &i_dummy, &i_dummy, &i_dummy,
 
361
                                 &i_dummy, &i_dummy, &i_dummy ) == 7 ||
 
362
                     sscanf( s, "@%d @%d", &i_dummy, &i_dummy) == 2)
 
363
            {
 
364
                p_sys->i_type = SUB_TYPE_JACOSUB;
 
365
                break;
 
366
            }
303
367
            else if( sscanf( s, "%d:%d:%d:", &i_dummy, &i_dummy, &i_dummy ) == 3 ||
304
368
                     sscanf( s, "%d:%d:%d ", &i_dummy, &i_dummy, &i_dummy ) == 3 )
305
369
            {
312
376
                p_sys->i_type = SUB_TYPE_DVDSUBTITLE;
313
377
                break;
314
378
            }
 
379
            else if( sscanf( s, "[%d:%d:%d]%c",
 
380
                     &i_dummy, &i_dummy, &i_dummy, &p_dummy ) == 4 )
 
381
            {
 
382
                p_sys->i_type = SUB_TYPE_DKS;
 
383
                break;
 
384
            }
 
385
            else if( strstr( s, "*** START SCRIPT" ) )
 
386
            {
 
387
                p_sys->i_type = SUB_TYPE_SUBVIEW1;
 
388
                break;
 
389
            }
 
390
            else if( sscanf( s, "[%d][%d]", &i_dummy, &i_dummy ) == 2 ||
 
391
                     sscanf( s, "[%d][]", &i_dummy ) == 1)
 
392
            {
 
393
                p_sys->i_type = SUB_TYPE_MPL2;
 
394
                break;
 
395
            }
 
396
            else if( sscanf (s, "FORMAT=%d", &i_dummy) == 1 ||
 
397
                     ( sscanf (s, "FORMAT=TIM%c", &p_dummy) == 1
 
398
                       && p_dummy =='E' ) )
 
399
            {
 
400
                p_sys->i_type = SUB_TYPE_MPSUB;
 
401
                break;
 
402
            }
 
403
            else if( sscanf( s, "-->> %d", &i_dummy) == 1 )
 
404
            {
 
405
                p_sys->i_type = SUB_TYPE_AQT;
 
406
                break;
 
407
            }
 
408
            else if( sscanf( s, "%d,%d,", &i_dummy, &i_dummy ) == 2 )
 
409
            {
 
410
                p_sys->i_type = SUB_TYPE_PJS;
 
411
                break;
 
412
            }
 
413
            else if( sscanf( s, "{%d:%d:%d}",
 
414
                                &i_dummy, &i_dummy, &i_dummy ) == 3 )
 
415
            {
 
416
                p_sys->i_type = SUB_TYPE_PSB;
 
417
                break;
 
418
            }
 
419
            else if( strcasestr( s, "<time" ) )
 
420
            {
 
421
                p_sys->i_type = SUB_TYPE_RT;
 
422
                break;
 
423
            }
315
424
 
316
425
            free( s );
317
426
            s = NULL;
318
427
        }
319
428
 
320
 
        if( s ) free( s );
 
429
        free( s );
321
430
 
322
431
        /* It will nearly always work even for non seekable stream thanks the
323
 
         * caching system, and if it fails we loose just a few sub */
 
432
         * caching system, and if it fails we lose just a few sub */
324
433
        if( stream_Seek( p_demux->s, 0 ) )
325
434
        {
326
435
            msg_Warn( p_demux, "failed to rewind" );
327
436
        }
328
437
    }
 
438
 
 
439
    /* Quit on unknown subtitles */
329
440
    if( p_sys->i_type == SUB_TYPE_UNKNOWN )
330
441
    {
331
442
        msg_Err( p_demux, "failed to recognize subtitle type" );
358
469
            if( !( p_sys->subtitle = realloc( p_sys->subtitle,
359
470
                                              sizeof(subtitle_t) * i_max ) ) )
360
471
            {
361
 
                msg_Err( p_demux, "out of memory");
362
 
                if( p_sys->subtitle != NULL )
363
 
                    free( p_sys->subtitle );
 
472
                free( p_sys->subtitle );
364
473
                TextUnload( &p_sys->txt );
365
474
                free( p_sys );
366
475
                return VLC_ENOMEM;
367
476
            }
368
477
        }
369
478
 
370
 
        if( pf_read( p_demux, &p_sys->subtitle[p_sys->i_subtitles] ) )
 
479
        if( pf_read( p_demux, &p_sys->subtitle[p_sys->i_subtitles],
 
480
                     p_sys->i_subtitles ) )
371
481
            break;
372
482
 
373
483
        p_sys->i_subtitles++;
419
529
    int i;
420
530
 
421
531
    for( i = 0; i < p_sys->i_subtitles; i++ )
422
 
    {
423
 
        if( p_sys->subtitle[i].psz_text )
424
 
            free( p_sys->subtitle[i].psz_text );
425
 
    }
426
 
    if( p_sys->subtitle )
427
 
        free( p_sys->subtitle );
 
532
        free( p_sys->subtitle[i].psz_text );
 
533
    free( p_sys->subtitle );
428
534
 
429
535
    free( p_sys );
430
536
}
504
610
 
505
611
        case DEMUX_GET_FPS:
506
612
        case DEMUX_GET_META:
 
613
        case DEMUX_GET_ATTACHMENTS:
507
614
        case DEMUX_GET_TITLE_INFO:
 
615
        case DEMUX_HAS_UNSUPPORTED_META:
508
616
            return VLC_EGENERIC;
509
617
 
510
618
        default:
511
 
            msg_Err( p_demux, "unknown query in subtitle control" );
 
619
            msg_Err( p_demux, "unknown query %d in subtitle control", i_query );
512
620
            return VLC_EGENERIC;
513
621
    }
514
622
}
590
698
static void Fix( demux_t *p_demux )
591
699
{
592
700
    demux_sys_t *p_sys = p_demux->p_sys;
593
 
    vlc_bool_t b_done;
 
701
    bool b_done;
594
702
    int     i_index;
595
703
 
596
704
    /* *** fix order (to be sure...) *** */
599
707
     */
600
708
    do
601
709
    {
602
 
        b_done = VLC_TRUE;
 
710
        b_done = true;
603
711
        for( i_index = 1; i_index < p_sys->i_subtitles; i_index++ )
604
712
        {
605
713
            if( p_sys->subtitle[i_index].i_start <
615
723
                memcpy( p_sys->subtitle + i_index,
616
724
                        &sub_xch,
617
725
                        sizeof( subtitle_t ) );
618
 
                b_done = VLC_FALSE;
 
726
                b_done = false;
619
727
            }
620
728
        }
621
729
    } while( !b_done );
685
793
/*****************************************************************************
686
794
 * Specific Subtitle function
687
795
 *****************************************************************************/
688
 
#define MAX_LINE 8192 /* must store the null terminator */
689
 
#define MAX_LINE_STR "8191" /* used in *scanf() regexps */
690
 
static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle )
 
796
/* ParseMicroDvd:
 
797
 *  Format:
 
798
 *      {n1}{n2}Line1|Line2|Line3....
 
799
 *  where n1 and n2 are the video frame number (n2 can be empty)
 
800
 */
 
801
static int ParseMicroDvd( demux_t *p_demux, subtitle_t *p_subtitle,
 
802
                          int i_idx )
691
803
{
 
804
    VLC_UNUSED( i_idx );
692
805
    demux_sys_t *p_sys = p_demux->p_sys;
693
806
    text_t      *txt = &p_sys->txt;
694
 
    /*
695
 
     * each line:
696
 
     *  {n1}{n2}Line1|Line2|Line3....
697
 
     * where n1 and n2 are the video frame number...
698
 
     * {n2} can also be {}
699
 
     */
700
 
    char *s;
701
 
 
702
 
    char buffer_text[MAX_LINE + 1];
703
 
    int    i_start;
704
 
    int    i_stop;
705
 
    unsigned int i;
706
 
 
707
 
    /* Try sub-fps value if set, movie rate if know, else 25fps (40000) */
708
 
    int i_microsecperframe = p_sys->i_original_mspf > 0 ? p_sys->i_original_mspf : 40000;
709
 
    if( p_sys->i_microsecperframe > 0 )
710
 
        i_microsecperframe = p_sys->i_microsecperframe;
711
 
 
712
 
    p_subtitle->i_start = 0;
713
 
    p_subtitle->i_stop  = 0;
714
 
    p_subtitle->psz_text = NULL;
715
 
 
716
 
next:
 
807
    char *psz_text;
 
808
    int  i_start;
 
809
    int  i_stop;
 
810
    int  i;
 
811
 
717
812
    for( ;; )
718
813
    {
719
 
        if( ( s = TextGetLine( txt ) ) == NULL )
720
 
        {
721
 
            return( VLC_EGENERIC );
722
 
        }
 
814
        const char *s = TextGetLine( txt );
 
815
        if( !s )
 
816
            return VLC_EGENERIC;
 
817
 
 
818
        psz_text = malloc( strlen(s) + 1 );
 
819
        if( !psz_text )
 
820
            return VLC_ENOMEM;
 
821
 
723
822
        i_start = 0;
724
823
        i_stop  = 0;
725
 
 
726
 
        memset( buffer_text, '\0', MAX_LINE + 1 );
727
 
        if( sscanf( s, "{%d}{}%"MAX_LINE_STR"[^\r\n]", &i_start, buffer_text ) == 2 ||
728
 
            sscanf( s, "{%d}{%d}%"MAX_LINE_STR"[^\r\n]", &i_start, &i_stop, buffer_text ) == 3)
729
 
        {
 
824
        if( sscanf( s, "{%d}{}%[^\r\n]", &i_start, psz_text ) == 2 ||
 
825
            sscanf( s, "{%d}{%d}%[^\r\n]", &i_start, &i_stop, psz_text ) == 3)
 
826
        {
 
827
            float f_fps;
 
828
            if( i_start != 1 || i_stop != 1 )
 
829
                break;
 
830
 
 
831
            /* We found a possible setting of the framerate "{1}{1}23.976" */
 
832
            /* Check if it's usable, and if the sub-fps is not set */
 
833
            f_fps = us_strtod( psz_text, NULL );
 
834
            if( f_fps > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
 
835
                p_sys->i_microsecperframe = (int64_t)((float)1000000 / f_fps);
 
836
        }
 
837
        free( psz_text );
 
838
    }
 
839
 
 
840
    /* replace | by \n */
 
841
    for( i = 0; psz_text[i] != '\0'; i++ )
 
842
    {
 
843
        if( psz_text[i] == '|' )
 
844
            psz_text[i] = '\n';
 
845
    }
 
846
 
 
847
    /* */
 
848
    p_subtitle->i_start  = i_start * p_sys->i_microsecperframe;
 
849
    p_subtitle->i_stop   = i_stop  * p_sys->i_microsecperframe;
 
850
    p_subtitle->psz_text = psz_text;
 
851
    return VLC_SUCCESS;
 
852
}
 
853
 
 
854
/* ParseSubRipSubViewer
 
855
 *  Format SubRip
 
856
 *      n
 
857
 *      h1:m1:s1,d1 --> h2:m2:s2,d2
 
858
 *      Line1
 
859
 *      Line2
 
860
 *      ....
 
861
 *      [Empty line]
 
862
 *  Format SubViewer v1/v2
 
863
 *      h1:m1:s1.d1,h2:m2:s2.d2
 
864
 *      Line1[br]Line2
 
865
 *      Line3
 
866
 *      ...
 
867
 *      [empty line]
 
868
 *  We ignore line number for SubRip
 
869
 */
 
870
static int ParseSubRipSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,
 
871
                                 const char *psz_fmt,
 
872
                                 bool b_replace_br )
 
873
{
 
874
    demux_sys_t *p_sys = p_demux->p_sys;
 
875
    text_t      *txt = &p_sys->txt;
 
876
    char    *psz_text;
 
877
 
 
878
    for( ;; )
 
879
    {
 
880
        const char *s = TextGetLine( txt );
 
881
        int h1, m1, s1, d1, h2, m2, s2, d2;
 
882
 
 
883
        if( !s )
 
884
            return VLC_EGENERIC;
 
885
 
 
886
        if( sscanf( s, psz_fmt,
 
887
                    &h1, &m1, &s1, &d1,
 
888
                    &h2, &m2, &s2, &d2 ) == 8 )
 
889
        {
 
890
            p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
 
891
                                    (int64_t)m1 * 60*1000 +
 
892
                                    (int64_t)s1 * 1000 +
 
893
                                    (int64_t)d1 ) * 1000;
 
894
 
 
895
            p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
 
896
                                    (int64_t)m2 * 60*1000 +
 
897
                                    (int64_t)s2 * 1000 +
 
898
                                    (int64_t)d2 ) * 1000;
730
899
            break;
731
900
        }
732
901
    }
733
 
    if( i_start == 1 && i_stop == 1 )
734
 
    {
735
 
        /* We found a possible setting of the framerate "{1}{1}23.976" */
736
 
        /* Use it unless sub-fps was set */
737
 
        float tmp = us_strtod( buffer_text, NULL );
738
 
        if( tmp > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
739
 
            p_sys->i_microsecperframe = (int64_t)( (float)1000000 / tmp );
740
 
        goto next;
741
 
    }
742
 
 
743
 
    /* replace | by \n */
744
 
    for( i = 0; i < strlen( buffer_text ); i++ )
745
 
    {
746
 
        if( buffer_text[i] == '|' )
747
 
        {
748
 
            buffer_text[i] = '\n';
749
 
        }
750
 
    }
751
 
 
752
 
    p_subtitle->i_start = (int64_t)i_start * i_microsecperframe;
753
 
    p_subtitle->i_stop  = (int64_t)i_stop  * i_microsecperframe;
754
 
    p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
755
 
    return( 0 );
756
 
}
757
 
 
758
 
static int  ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle )
759
 
{
760
 
    demux_sys_t *p_sys = p_demux->p_sys;
761
 
    text_t      *txt = &p_sys->txt;
762
 
 
763
 
    /*
764
 
     * n
765
 
     * h1:m1:s1,d1 --> h2:m2:s2,d2
766
 
     * Line1
767
 
     * Line2
768
 
     * ...
769
 
     * [empty line]
770
 
     *
771
 
     */
772
 
    char *s;
773
 
    char buffer_text[ 10 * MAX_LINE];
774
 
    int  i_buffer_text;
775
 
    int64_t     i_start;
776
 
    int64_t     i_stop;
777
 
 
778
 
    p_subtitle->i_start = 0;
779
 
    p_subtitle->i_stop  = 0;
780
 
    p_subtitle->psz_text = NULL;
781
 
 
782
 
    for( ;; )
783
 
    {
784
 
        int h1, m1, s1, d1, h2, m2, s2, d2;
785
 
        if( ( s = TextGetLine( txt ) ) == NULL )
786
 
        {
787
 
            return( VLC_EGENERIC );
788
 
        }
789
 
        if( sscanf( s,
790
 
                    "%d:%d:%d,%d --> %d:%d:%d,%d",
791
 
                    &h1, &m1, &s1, &d1,
792
 
                    &h2, &m2, &s2, &d2 ) == 8 )
793
 
        {
794
 
            i_start = ( (int64_t)h1 * 3600*1000 +
795
 
                        (int64_t)m1 * 60*1000 +
796
 
                        (int64_t)s1 * 1000 +
797
 
                        (int64_t)d1 ) * 1000;
798
 
 
799
 
            i_stop  = ( (int64_t)h2 * 3600*1000 +
800
 
                        (int64_t)m2 * 60*1000 +
801
 
                        (int64_t)s2 * 1000 +
802
 
                        (int64_t)d2 ) * 1000;
803
 
 
804
 
            /* Now read text until an empty line */
805
 
            for( i_buffer_text = 0;; )
806
 
            {
807
 
                int i_len;
808
 
                if( ( s = TextGetLine( txt ) ) == NULL )
809
 
                {
810
 
                    return( VLC_EGENERIC );
811
 
                }
812
 
 
813
 
                i_len = strlen( s );
814
 
                if( i_len <= 0 )
815
 
                {
816
 
                    /* empty line -> end of this subtitle */
817
 
                    buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
818
 
                    p_subtitle->i_start = i_start;
819
 
                    p_subtitle->i_stop = i_stop;
820
 
                    p_subtitle->psz_text = strdup( buffer_text );
821
 
                    /* If framerate is available, use sub-fps */
822
 
                    if( p_sys->i_microsecperframe != 0 &&
823
 
                        p_sys->i_original_mspf != 0)
824
 
                    {
825
 
                        p_subtitle->i_start = (int64_t)i_start *
826
 
                                              p_sys->i_microsecperframe/
827
 
                                              p_sys->i_original_mspf;
828
 
                        p_subtitle->i_stop  = (int64_t)i_stop  *
829
 
                                              p_sys->i_microsecperframe /
830
 
                                              p_sys->i_original_mspf;
831
 
                    }
832
 
                    return 0;
833
 
                }
834
 
                else
835
 
                {
836
 
                    if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
837
 
                    {
838
 
                        memcpy( buffer_text + i_buffer_text,
839
 
                                s,
840
 
                                i_len );
841
 
                        i_buffer_text += i_len;
842
 
 
843
 
                        buffer_text[i_buffer_text] = '\n';
844
 
                        i_buffer_text++;
845
 
                    }
846
 
                }
847
 
            }
848
 
        }
849
 
    }
850
 
}
851
 
 
852
 
static int  ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle )
853
 
{
854
 
    demux_sys_t *p_sys = p_demux->p_sys;
855
 
    text_t      *txt = &p_sys->txt;
856
 
 
857
 
    /*
858
 
     * h1:m1:s1.d1,h2:m2:s2.d2
859
 
     * Line1[br]Line2
860
 
     * Line3
861
 
     * ...
862
 
     * [empty line]
863
 
     * ( works with subviewer and subviewer v2 )
864
 
     */
865
 
    char *s;
866
 
    char buffer_text[ 10 * MAX_LINE];
867
 
    int  i_buffer_text;
868
 
    int64_t     i_start;
869
 
    int64_t     i_stop;
870
 
 
871
 
    p_subtitle->i_start = 0;
872
 
    p_subtitle->i_stop  = 0;
873
 
    p_subtitle->psz_text = NULL;
874
 
 
875
 
    for( ;; )
876
 
    {
877
 
        int h1, m1, s1, d1, h2, m2, s2, d2;
878
 
        if( ( s = TextGetLine( txt ) ) == NULL )
879
 
        {
880
 
            return( VLC_EGENERIC );
881
 
        }
882
 
        if( sscanf( s,
883
 
                    "%d:%d:%d.%d,%d:%d:%d.%d",
884
 
                    &h1, &m1, &s1, &d1,
885
 
                    &h2, &m2, &s2, &d2 ) == 8 )
886
 
        {
887
 
            i_start = ( (int64_t)h1 * 3600*1000 +
888
 
                        (int64_t)m1 * 60*1000 +
889
 
                        (int64_t)s1 * 1000 +
890
 
                        (int64_t)d1 ) * 1000;
891
 
 
892
 
            i_stop  = ( (int64_t)h2 * 3600*1000 +
893
 
                        (int64_t)m2 * 60*1000 +
894
 
                        (int64_t)s2 * 1000 +
895
 
                        (int64_t)d2 ) * 1000;
896
 
 
897
 
            /* Now read text until an empty line */
898
 
            for( i_buffer_text = 0;; )
899
 
            {
900
 
                int i_len, i;
901
 
                if( ( s = TextGetLine( txt ) ) == NULL )
902
 
                {
903
 
                    return( VLC_EGENERIC );
904
 
                }
905
 
 
906
 
                i_len = strlen( s );
907
 
                if( i_len <= 0 )
908
 
                {
909
 
                    /* empty line -> end of this subtitle */
910
 
                    buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
911
 
                    p_subtitle->i_start = i_start;
912
 
                    p_subtitle->i_stop = i_stop;
913
 
 
914
 
                    /* replace [br] by \n */
915
 
                    for( i = 0; i < i_buffer_text - 3; i++ )
916
 
                    {
917
 
                        if( buffer_text[i] == '[' && buffer_text[i+1] == 'b' &&
918
 
                            buffer_text[i+2] == 'r' && buffer_text[i+3] == ']' )
919
 
                        {
920
 
                            char *temp = buffer_text + i + 1;
921
 
                            buffer_text[i] = '\n';
922
 
                            memmove( temp, temp+3, strlen( temp ) -3 );
923
 
                            temp[strlen( temp )-3] = '\0';
924
 
                        }
925
 
                    }
926
 
                    p_subtitle->psz_text = strdup( buffer_text );
927
 
                    return( 0 );
928
 
                }
929
 
                else
930
 
                {
931
 
                    if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
932
 
                    {
933
 
                        memcpy( buffer_text + i_buffer_text,
934
 
                                s,
935
 
                                i_len );
936
 
                        i_buffer_text += i_len;
937
 
 
938
 
                        buffer_text[i_buffer_text] = '\n';
939
 
                        i_buffer_text++;
940
 
                    }
941
 
                }
942
 
            }
943
 
        }
944
 
    }
945
 
}
946
 
 
947
 
 
948
 
static int  ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle )
949
 
{
950
 
    demux_sys_t *p_sys = p_demux->p_sys;
951
 
    text_t      *txt = &p_sys->txt;
952
 
 
953
 
    char buffer_text[ 10 * MAX_LINE + 1];
954
 
    char buffer_text2[ 10 * MAX_LINE + 1];
955
 
    char *s;
956
 
    int64_t     i_start;
957
 
    int64_t     i_stop;
958
 
 
959
 
    p_subtitle->i_start = 0;
960
 
    p_subtitle->i_stop  = 0;
961
 
    p_subtitle->psz_text = NULL;
962
 
 
963
 
    for( ;; )
964
 
    {
 
902
 
 
903
    /* Now read text until an empty line */
 
904
    psz_text = strdup("");
 
905
    if( !psz_text )
 
906
        return VLC_ENOMEM;
 
907
    for( ;; )
 
908
    {
 
909
        const char *s = TextGetLine( txt );
 
910
        int i_len;
 
911
        int i_old;
 
912
 
 
913
        if( !s )
 
914
        {
 
915
            free( psz_text );
 
916
            return VLC_EGENERIC;
 
917
        }
 
918
 
 
919
        i_len = strlen( s );
 
920
        if( i_len <= 0 )
 
921
        {
 
922
            p_subtitle->psz_text = psz_text;
 
923
            return VLC_SUCCESS;
 
924
        }
 
925
 
 
926
        i_old = strlen( psz_text );
 
927
        psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
 
928
        if( !psz_text )
 
929
            return VLC_ENOMEM;
 
930
        strcat( psz_text, s );
 
931
        strcat( psz_text, "\n" );
 
932
 
 
933
        /* replace [br] by \n */
 
934
        if( b_replace_br )
 
935
        {
 
936
            char *p;
 
937
 
 
938
            while( ( p = strstr( psz_text, "[br]" ) ) )
 
939
            {
 
940
                *p++ = '\n';
 
941
                memmove( p, &p[3], strlen(&p[3])+1 );
 
942
            }
 
943
        }
 
944
    }
 
945
}
 
946
/* ParseSubRip
 
947
 */
 
948
static int  ParseSubRip( demux_t *p_demux, subtitle_t *p_subtitle,
 
949
                         int i_idx )
 
950
{
 
951
    VLC_UNUSED( i_idx );
 
952
    return ParseSubRipSubViewer( p_demux, p_subtitle,
 
953
                                 "%d:%d:%d,%d --> %d:%d:%d,%d",
 
954
                                 false );
 
955
}
 
956
/* ParseSubViewer
 
957
 */
 
958
static int  ParseSubViewer( demux_t *p_demux, subtitle_t *p_subtitle,
 
959
                            int i_idx )
 
960
{
 
961
    VLC_UNUSED( i_idx );
 
962
 
 
963
    return ParseSubRipSubViewer( p_demux, p_subtitle,
 
964
                                 "%d:%d:%d.%d,%d:%d:%d.%d",
 
965
                                 true );
 
966
}
 
967
 
 
968
/* ParseSSA
 
969
 */
 
970
static int  ParseSSA( demux_t *p_demux, subtitle_t *p_subtitle,
 
971
                      int i_idx )
 
972
{
 
973
    demux_sys_t *p_sys = p_demux->p_sys;
 
974
    text_t      *txt = &p_sys->txt;
 
975
 
 
976
    for( ;; )
 
977
    {
 
978
        const char *s = TextGetLine( txt );
965
979
        int h1, m1, s1, c1, h2, m2, s2, c2;
 
980
        char *psz_text;
 
981
        char temp[16];
966
982
 
967
 
        if( ( s = TextGetLine( txt ) ) == NULL )
968
 
        {
969
 
            return( VLC_EGENERIC );
970
 
        }
971
 
        p_subtitle->psz_text = malloc( strlen( s ) );
 
983
        if( !s )
 
984
            return VLC_EGENERIC;
972
985
 
973
986
        /* We expect (SSA2-4):
974
987
         * Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
981
994
         * Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
982
995
         * Dialogue: Layer#,0:02:40.65,0:02:41.79,Wolf main,Cher,0000,0000,0000,,Et les enregistrements de ses ondes delta ?
983
996
         */
 
997
 
 
998
        /* The output text is - at least, not removing numbers - 18 chars shorter than the input text. */
 
999
        psz_text = malloc( strlen(s) );
 
1000
        if( !psz_text )
 
1001
            return VLC_ENOMEM;
 
1002
 
984
1003
        if( sscanf( s,
985
 
                    "Dialogue: %"MAX_LINE_STR"0[^,],%d:%d:%d.%d,%d:%d:%d.%d,%"MAX_LINE_STR"0[^\r\n]",
986
 
                    buffer_text2,
 
1004
                    "Dialogue: %15[^,],%d:%d:%d.%d,%d:%d:%d.%d,%[^\r\n]",
 
1005
                    temp,
987
1006
                    &h1, &m1, &s1, &c1,
988
1007
                    &h2, &m2, &s2, &c2,
989
 
                    buffer_text ) == 10 )
 
1008
                    psz_text ) == 10 )
990
1009
        {
991
 
            i_start = ( (int64_t)h1 * 3600*1000 +
992
 
                        (int64_t)m1 * 60*1000 +
993
 
                        (int64_t)s1 * 1000 +
994
 
                        (int64_t)c1 * 10 ) * 1000;
995
 
 
996
 
            i_stop  = ( (int64_t)h2 * 3600*1000 +
997
 
                        (int64_t)m2 * 60*1000 +
998
 
                        (int64_t)s2 * 1000 +
999
 
                        (int64_t)c2 * 10 ) * 1000;
1000
 
 
1001
1010
            /* The dec expects: ReadOrder, Layer, Style, Name, MarginL, MarginR, MarginV, Effect, Text */
1002
1011
            /* (Layer comes from ASS specs ... it's empty for SSA.) */
1003
1012
            if( p_sys->i_type == SUB_TYPE_SSA1 )
1004
1013
            {
1005
 
                sprintf( p_subtitle->psz_text,
1006
 
                         ",%s", strdup( buffer_text) ); /* SSA1 has only 8 commas before the text starts, not 9 */
1007
 
            }
1008
 
            else
1009
 
            {
1010
 
                sprintf( p_subtitle->psz_text,
1011
 
                         ",,%s", strdup( buffer_text) ); /* ReadOrder, Layer, %s(rest of fields) */
1012
 
            }
1013
 
            p_subtitle->i_start = i_start;
1014
 
            p_subtitle->i_stop = i_stop;
1015
 
            return 0;
1016
 
        }
1017
 
        else
1018
 
        {
1019
 
            /* All the other stuff we add to the header field */
1020
 
            if( p_sys->psz_header != NULL )
1021
 
            {
1022
 
                if( !( p_sys->psz_header = realloc( p_sys->psz_header,
1023
 
                          strlen( p_sys->psz_header ) + 1 + strlen( s ) + 2 ) ) )
1024
 
                {
1025
 
                    msg_Err( p_demux, "out of memory");
1026
 
                    return VLC_ENOMEM;
1027
 
                }
1028
 
                p_sys->psz_header = strcat( p_sys->psz_header,  s );
1029
 
                p_sys->psz_header = strcat( p_sys->psz_header, "\n" );
1030
 
            }
1031
 
            else
1032
 
            {
1033
 
                if( !( p_sys->psz_header = malloc( strlen( s ) + 2 ) ) )
1034
 
                {
1035
 
                    msg_Err( p_demux, "out of memory");
1036
 
                    return VLC_ENOMEM;
1037
 
                }
1038
 
                p_sys->psz_header = s;
1039
 
                p_sys->psz_header = strcat( p_sys->psz_header, "\n" );
1040
 
            }
1041
 
        }
 
1014
                /* SSA1 has only 8 commas before the text starts, not 9 */
 
1015
                memmove( &psz_text[1], psz_text, strlen(psz_text)+1 );
 
1016
                psz_text[0] = ',';
 
1017
            }
 
1018
            else
 
1019
            {
 
1020
                int i_layer = ( p_sys->i_type == SUB_TYPE_ASS ) ? atoi( temp ) : 0;
 
1021
 
 
1022
                /* ReadOrder, Layer, %s(rest of fields) */
 
1023
                snprintf( temp, sizeof(temp), "%d,%d,", i_idx, i_layer );
 
1024
                memmove( psz_text + strlen(temp), psz_text, strlen(psz_text)+1 );
 
1025
                memcpy( psz_text, temp, strlen(temp) );
 
1026
            }
 
1027
 
 
1028
            p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
 
1029
                                    (int64_t)m1 * 60*1000 +
 
1030
                                    (int64_t)s1 * 1000 +
 
1031
                                    (int64_t)c1 * 10 ) * 1000;
 
1032
            p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
 
1033
                                    (int64_t)m2 * 60*1000 +
 
1034
                                    (int64_t)s2 * 1000 +
 
1035
                                    (int64_t)c2 * 10 ) * 1000;
 
1036
            p_subtitle->psz_text = psz_text;
 
1037
            return VLC_SUCCESS;
 
1038
        }
 
1039
        free( psz_text );
 
1040
 
 
1041
        /* All the other stuff we add to the header field */
 
1042
        if( !p_sys->psz_header )
 
1043
            p_sys->psz_header = strdup( "" );
 
1044
        if( !p_sys->psz_header )
 
1045
            return VLC_ENOMEM;
 
1046
 
 
1047
        p_sys->psz_header =
 
1048
            realloc( p_sys->psz_header,
 
1049
                     strlen( p_sys->psz_header ) + strlen( s ) + 2 );
 
1050
        strcat( p_sys->psz_header,  s );
 
1051
        strcat( p_sys->psz_header, "\n" );
1042
1052
    }
1043
1053
}
1044
1054
 
1045
 
static int  ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle )
 
1055
/* ParseVplayer
 
1056
 *  Format
 
1057
 *      h:m:s:Line1|Line2|Line3....
 
1058
 *  or
 
1059
 *      h:m:s Line1|Line2|Line3....
 
1060
 */
 
1061
static int ParseVplayer( demux_t *p_demux, subtitle_t *p_subtitle,
 
1062
                          int i_idx )
1046
1063
{
 
1064
    VLC_UNUSED( i_idx );
 
1065
 
1047
1066
    demux_sys_t *p_sys = p_demux->p_sys;
1048
1067
    text_t      *txt = &p_sys->txt;
1049
 
 
1050
 
    /*
1051
 
     * each line:
1052
 
     *  h:m:s:Line1|Line2|Line3....
1053
 
     *  or
1054
 
     *  h:m:s Line1|Line2|Line3....
1055
 
     *
1056
 
     */
1057
 
    char *p;
1058
 
    char buffer_text[MAX_LINE + 1];
1059
 
    int64_t    i_start;
1060
 
    unsigned int i;
1061
 
 
1062
 
    p_subtitle->i_start = 0;
1063
 
    p_subtitle->i_stop  = 0;
1064
 
    p_subtitle->psz_text = NULL;
 
1068
    char *psz_text;
 
1069
    int i;
1065
1070
 
1066
1071
    for( ;; )
1067
1072
    {
1068
 
        int h, m, s;
1069
 
        char c;
1070
 
 
1071
 
        if( ( p = TextGetLine( txt ) ) == NULL )
1072
 
        {
1073
 
            return( VLC_EGENERIC );
1074
 
        }
1075
 
 
1076
 
        i_start = 0;
1077
 
 
1078
 
        memset( buffer_text, '\0', MAX_LINE + 1 );
1079
 
        if( sscanf( p, "%d:%d:%d%[ :]%"MAX_LINE_STR"0[^\r\n]", &h, &m, &s, &c, buffer_text ) == 5 )
1080
 
        {
1081
 
            i_start = ( (int64_t)h * 3600*1000 +
1082
 
                        (int64_t)m * 60*1000 +
1083
 
                        (int64_t)s * 1000 ) * 1000;
 
1073
        const char *s = TextGetLine( txt );
 
1074
        int h1, m1, s1;
 
1075
 
 
1076
        if( !s )
 
1077
            return VLC_EGENERIC;
 
1078
 
 
1079
        psz_text = malloc( strlen( s ) + 1 );
 
1080
        if( !psz_text )
 
1081
            return VLC_ENOMEM;
 
1082
 
 
1083
        if( sscanf( s, "%d:%d:%d%*c%[^\r\n]",
 
1084
                    &h1, &m1, &s1, psz_text ) == 4 )
 
1085
        {
 
1086
            p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
 
1087
                                    (int64_t)m1 * 60*1000 +
 
1088
                                    (int64_t)s1 * 1000 ) * 1000;
 
1089
            p_subtitle->i_stop  = 0;
1084
1090
            break;
1085
1091
        }
 
1092
        free( psz_text );
1086
1093
    }
1087
1094
 
1088
1095
    /* replace | by \n */
1089
 
    for( i = 0; i < strlen( buffer_text ); i++ )
 
1096
    for( i = 0; psz_text[i] != '\0'; i++ )
1090
1097
    {
1091
 
        if( buffer_text[i] == '|' )
1092
 
        {
1093
 
            buffer_text[i] = '\n';
1094
 
        }
 
1098
        if( psz_text[i] == '|' )
 
1099
            psz_text[i] = '\n';
1095
1100
    }
1096
 
    p_subtitle->i_start = i_start;
1097
 
 
1098
 
    p_subtitle->i_stop  = 0;
1099
 
    p_subtitle->psz_text = strndup( buffer_text, MAX_LINE );
1100
 
    return( 0 );
 
1101
    p_subtitle->psz_text = psz_text;
 
1102
    return VLC_SUCCESS;
1101
1103
}
1102
1104
 
1103
 
static char *ParseSamiSearch( text_t *txt, char *psz_start, char *psz_str )
 
1105
/* ParseSami
 
1106
 */
 
1107
static char *ParseSamiSearch( text_t *txt,
 
1108
                              char *psz_start, const char *psz_str )
1104
1109
{
1105
 
    if( psz_start )
 
1110
    if( psz_start && strcasestr( psz_start, psz_str ) )
1106
1111
    {
1107
 
        if( strcasestr( psz_start, psz_str ) )
1108
 
        {
1109
 
            char *s = strcasestr( psz_start, psz_str );
1110
 
 
1111
 
            s += strlen( psz_str );
1112
 
 
1113
 
            return( s );
1114
 
        }
 
1112
        char *s = strcasestr( psz_start, psz_str );
 
1113
        return &s[strlen( psz_str )];
1115
1114
    }
 
1115
 
1116
1116
    for( ;; )
1117
1117
    {
1118
 
        char *p;
1119
 
        if( ( p = TextGetLine( txt ) ) == NULL )
1120
 
        {
 
1118
        char *p = TextGetLine( txt );
 
1119
        if( !p )
1121
1120
            return NULL;
1122
 
        }
 
1121
 
1123
1122
        if( strcasestr( p, psz_str ) )
1124
1123
        {
1125
1124
            char *s = strcasestr( p, psz_str );
1126
 
 
1127
 
            s += strlen( psz_str );
1128
 
 
1129
 
            return(  s);
 
1125
            return &s[strlen( psz_str )];
1130
1126
        }
1131
1127
    }
1132
1128
}
1133
 
 
1134
 
static int  ParseSami( demux_t *p_demux, subtitle_t *p_subtitle )
 
1129
static int  ParseSami( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
1135
1130
{
 
1131
    VLC_UNUSED( i_idx );
1136
1132
    demux_sys_t *p_sys = p_demux->p_sys;
1137
1133
    text_t      *txt = &p_sys->txt;
1138
1134
 
1139
 
    char *p;
 
1135
    char *s;
1140
1136
    int64_t i_start;
1141
1137
 
1142
 
    int  i_text;
1143
 
    char buffer_text[10*MAX_LINE + 1];
1144
 
 
1145
 
    p_subtitle->i_start = 0;
1146
 
    p_subtitle->i_stop  = 0;
1147
 
    p_subtitle->psz_text = NULL;
1148
 
 
1149
 
#define ADDC( c ) \
1150
 
    if( i_text < 10*MAX_LINE )      \
1151
 
    {                               \
1152
 
        buffer_text[i_text++] = c;  \
1153
 
        buffer_text[i_text] = '\0'; \
1154
 
    }
 
1138
    unsigned int i_text;
 
1139
    char text[8192]; /* Arbitrary but should be long enough */
1155
1140
 
1156
1141
    /* search "Start=" */
1157
 
    if( !( p = ParseSamiSearch( txt, NULL, "Start=" ) ) )
1158
 
    {
 
1142
    if( !( s = ParseSamiSearch( txt, NULL, "Start=" ) ) )
1159
1143
        return VLC_EGENERIC;
1160
 
    }
1161
1144
 
1162
1145
    /* get start value */
1163
 
    i_start = strtol( p, &p, 0 );
 
1146
    i_start = strtol( s, &s, 0 );
1164
1147
 
1165
1148
    /* search <P */
1166
 
    if( !( p = ParseSamiSearch( txt, p, "<P" ) ) )
1167
 
    {
 
1149
    if( !( s = ParseSamiSearch( txt, s, "<P" ) ) )
1168
1150
        return VLC_EGENERIC;
1169
 
    }
 
1151
 
1170
1152
    /* search > */
1171
 
    if( !( p = ParseSamiSearch( txt, p, ">" ) ) )
1172
 
    {
 
1153
    if( !( s = ParseSamiSearch( txt, s, ">" ) ) )
1173
1154
        return VLC_EGENERIC;
1174
 
    }
1175
1155
 
1176
1156
    i_text = 0;
1177
 
    buffer_text[0] = '\0';
 
1157
    text[0] = '\0';
1178
1158
    /* now get all txt until  a "Start=" line */
1179
1159
    for( ;; )
1180
1160
    {
1181
 
        if( *p )
1182
 
        {
1183
 
            if( *p == '<' )
1184
 
            {
1185
 
                if( !strncasecmp( p, "<br", 3 ) )
1186
 
                {
1187
 
                    ADDC( '\n' );
1188
 
                }
1189
 
                else if( strcasestr( p, "Start=" ) )
1190
 
                {
1191
 
                    TextPreviousLine( txt );
1192
 
                    break;
1193
 
                }
1194
 
                p = ParseSamiSearch( txt, p, ">" );
1195
 
            }
1196
 
            else if( !strncmp( p, "&nbsp;", 6 ) )
1197
 
            {
1198
 
                ADDC( ' ' );
1199
 
                p += 6;
1200
 
            }
1201
 
            else if( *p == '\t' )
1202
 
            {
1203
 
                ADDC( ' ' );
1204
 
                p++;
1205
 
            }
1206
 
            else
1207
 
            {
1208
 
                ADDC( *p );
1209
 
                p++;
1210
 
            }
 
1161
        char c = '\0';
 
1162
        /* Search non empty line */
 
1163
        while( s && *s == '\0' )
 
1164
            s = TextGetLine( txt );
 
1165
        if( !s )
 
1166
            break;
 
1167
 
 
1168
        if( *s == '<' )
 
1169
        {
 
1170
            if( !strncasecmp( s, "<br", 3 ) )
 
1171
            {
 
1172
                c = '\n';
 
1173
            }
 
1174
            else if( strcasestr( s, "Start=" ) )
 
1175
            {
 
1176
                TextPreviousLine( txt );
 
1177
                break;
 
1178
            }
 
1179
            s = ParseSamiSearch( txt, s, ">" );
 
1180
        }
 
1181
        else if( !strncmp( s, "&nbsp;", 6 ) )
 
1182
        {
 
1183
            c = ' ';
 
1184
            s += 6;
 
1185
        }
 
1186
        else if( *s == '\t' )
 
1187
        {
 
1188
            c = ' ';
 
1189
            s++;
1211
1190
        }
1212
1191
        else
1213
1192
        {
1214
 
            p = TextGetLine( txt );
 
1193
            c = *s;
 
1194
            s++;
1215
1195
        }
1216
 
 
1217
 
        if( p == NULL )
 
1196
        if( c != '\0' && i_text+1 < sizeof(text) )
1218
1197
        {
1219
 
            break;
 
1198
            text[i_text++] = c;
 
1199
            text[i_text] = '\0';
1220
1200
        }
1221
1201
    }
1222
1202
 
1223
1203
    p_subtitle->i_start = i_start * 1000;
1224
1204
    p_subtitle->i_stop  = 0;
1225
 
    p_subtitle->psz_text = strndup( buffer_text, 10*MAX_LINE );
 
1205
    p_subtitle->psz_text = strdup( text );
1226
1206
 
1227
 
    return( VLC_SUCCESS );
1228
 
#undef ADDC
 
1207
    return VLC_SUCCESS;
1229
1208
}
1230
1209
 
1231
 
static int ParseDVDSubtitle( demux_t *p_demux, subtitle_t *p_subtitle )
 
1210
/* ParseDVDSubtitle
 
1211
 *  Format
 
1212
 *      {T h1:m1:s1:c1
 
1213
 *      Line1
 
1214
 *      Line2
 
1215
 *      ...
 
1216
 *      }
 
1217
 * TODO it can have a header
 
1218
 *      { HEAD
 
1219
 *          ...
 
1220
 *          CODEPAGE=...
 
1221
 *          FORMAT=...
 
1222
 *          LANG=English
 
1223
 *      }
 
1224
 *      LANG support would be cool
 
1225
 *      CODEPAGE is probably mandatory FIXME
 
1226
 */
 
1227
static int ParseDVDSubtitle( demux_t *p_demux, subtitle_t *p_subtitle,
 
1228
                             int i_idx )
1232
1229
{
 
1230
    VLC_UNUSED( i_idx );
 
1231
 
1233
1232
    demux_sys_t *p_sys = p_demux->p_sys;
1234
1233
    text_t      *txt = &p_sys->txt;
1235
 
 
1236
 
    /*
1237
 
     * {T h1:m1:s1:c1
1238
 
     * Line1
1239
 
     * Line2
1240
 
     * ...
1241
 
     * }
1242
 
     *
1243
 
     */
1244
 
    char *s;
1245
 
    char buffer_text[ 10 * MAX_LINE];
1246
 
    int  i_buffer_text;
1247
 
    int64_t     i_start;
1248
 
 
1249
 
    p_subtitle->i_start = 0;
1250
 
    p_subtitle->i_stop  = 0;
1251
 
    p_subtitle->psz_text = NULL;
 
1234
    char *psz_text;
1252
1235
 
1253
1236
    for( ;; )
1254
1237
    {
 
1238
        const char *s = TextGetLine( txt );
1255
1239
        int h1, m1, s1, c1;
1256
 
        if( ( s = TextGetLine( txt ) ) == NULL )
1257
 
        {
1258
 
            return( VLC_EGENERIC );
1259
 
        }
 
1240
 
 
1241
        if( !s )
 
1242
            return VLC_EGENERIC;
 
1243
 
1260
1244
        if( sscanf( s,
1261
1245
                    "{T %d:%d:%d:%d",
1262
1246
                    &h1, &m1, &s1, &c1 ) == 4 )
1263
1247
        {
1264
 
            i_start = ( (int64_t)h1 * 3600*1000 +
1265
 
                        (int64_t)m1 * 60*1000 +
1266
 
                        (int64_t)s1 * 1000 +
1267
 
                        (int64_t)c1 * 10) * 1000;
1268
 
 
1269
 
            /* Now read text until a line containing "}" */
1270
 
            for( i_buffer_text = 0;; )
1271
 
            {
1272
 
                int i_len;
1273
 
                if( ( s = TextGetLine( txt ) ) == NULL )
1274
 
                {
1275
 
                    return( VLC_EGENERIC );
1276
 
                }
1277
 
 
1278
 
                i_len = strlen( s );
1279
 
                if( i_len == 1 && s[0] == '}' )
1280
 
                {
1281
 
                    /* "}" -> end of this subtitle */
1282
 
                    buffer_text[__MAX( i_buffer_text - 1, 0 )] = '\0';
1283
 
                    p_subtitle->i_start = i_start;
1284
 
                    p_subtitle->i_stop  = 0;
1285
 
                    p_subtitle->psz_text = strdup( buffer_text );
1286
 
                    return 0;
1287
 
                }
1288
 
                else
1289
 
                {
1290
 
                    if( i_buffer_text + i_len + 1 < 10 * MAX_LINE )
1291
 
                    {
1292
 
                        memcpy( buffer_text + i_buffer_text,
1293
 
                                s,
1294
 
                                i_len );
1295
 
                        i_buffer_text += i_len;
1296
 
 
1297
 
                        buffer_text[i_buffer_text] = '\n';
1298
 
                        i_buffer_text++;
1299
 
                    }
1300
 
                }
1301
 
            }
1302
 
        }
1303
 
    }
 
1248
            p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
 
1249
                                    (int64_t)m1 * 60*1000 +
 
1250
                                    (int64_t)s1 * 1000 +
 
1251
                                    (int64_t)c1 * 10) * 1000;
 
1252
            p_subtitle->i_stop = 0;
 
1253
            break;
 
1254
        }
 
1255
    }
 
1256
 
 
1257
    /* Now read text until a line containing "}" */
 
1258
    psz_text = strdup("");
 
1259
    if( !psz_text )
 
1260
        return VLC_ENOMEM;
 
1261
    for( ;; )
 
1262
    {
 
1263
        const char *s = TextGetLine( txt );
 
1264
        int i_len;
 
1265
        int i_old;
 
1266
 
 
1267
        if( !s )
 
1268
        {
 
1269
            free( psz_text );
 
1270
            return VLC_EGENERIC;
 
1271
        }
 
1272
 
 
1273
        i_len = strlen( s );
 
1274
        if( i_len == 1 && s[0] == '}')
 
1275
        {
 
1276
            p_subtitle->psz_text = psz_text;
 
1277
            return VLC_SUCCESS;
 
1278
        }
 
1279
 
 
1280
        i_old = strlen( psz_text );
 
1281
        psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
 
1282
        if( !psz_text )
 
1283
            return VLC_ENOMEM;
 
1284
        strcat( psz_text, s );
 
1285
        strcat( psz_text, "\n" );
 
1286
    }
 
1287
}
 
1288
 
 
1289
/* ParseMPL2
 
1290
 *  Format
 
1291
 *     [n1][n2]Line1|Line2|Line3...
 
1292
 *  where n1 and n2 are the video frame number (n2 can be empty)
 
1293
 */
 
1294
static int ParseMPL2( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
 
1295
{
 
1296
    VLC_UNUSED( i_idx );
 
1297
 
 
1298
    demux_sys_t *p_sys = p_demux->p_sys;
 
1299
    text_t      *txt = &p_sys->txt;
 
1300
    char *psz_text;
 
1301
    int i;
 
1302
 
 
1303
    for( ;; )
 
1304
    {
 
1305
        const char *s = TextGetLine( txt );
 
1306
        int i_start;
 
1307
        int i_stop;
 
1308
 
 
1309
        if( !s )
 
1310
            return VLC_EGENERIC;
 
1311
 
 
1312
        psz_text = malloc( strlen(s) + 1 );
 
1313
        if( !psz_text )
 
1314
            return VLC_ENOMEM;
 
1315
 
 
1316
        i_start = 0;
 
1317
        i_stop  = 0;
 
1318
        if( sscanf( s, "[%d][] %[^\r\n]", &i_start, psz_text ) == 2 ||
 
1319
            sscanf( s, "[%d][%d] %[^\r\n]", &i_start, &i_stop, psz_text ) == 3)
 
1320
        {
 
1321
            p_subtitle->i_start = (int64_t)i_start * 100000;
 
1322
            p_subtitle->i_stop  = (int64_t)i_stop  * 100000;
 
1323
            break;
 
1324
        }
 
1325
        free( psz_text );
 
1326
    }
 
1327
 
 
1328
    for( i = 0; psz_text[i] != '\0'; )
 
1329
    {
 
1330
        /* replace | by \n */
 
1331
        if( psz_text[i] == '|' )
 
1332
            psz_text[i] = '\n';
 
1333
 
 
1334
        /* Remove italic */
 
1335
        if( psz_text[i] == '/' && ( i == 0 || psz_text[i-1] == '\n' ) )
 
1336
            memmove( &psz_text[i], &psz_text[i+1], strlen(&psz_text[i+1])+1 );
 
1337
        else
 
1338
            i++;
 
1339
    }
 
1340
    p_subtitle->psz_text = psz_text;
 
1341
    return VLC_SUCCESS;
 
1342
}
 
1343
 
 
1344
static int ParseAQT( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
 
1345
{
 
1346
    VLC_UNUSED( i_idx );
 
1347
 
 
1348
    demux_sys_t *p_sys = p_demux->p_sys;
 
1349
    text_t      *txt = &p_sys->txt;
 
1350
    char *psz_text = strdup( "" );
 
1351
    int i_old = 0;
 
1352
    int i_firstline = 1;
 
1353
 
 
1354
    for( ;; )
 
1355
    {
 
1356
        int t; /* Time */
 
1357
 
 
1358
        const char *s = TextGetLine( txt );
 
1359
 
 
1360
        if( !s )
 
1361
            return VLC_EGENERIC;
 
1362
 
 
1363
        /* Data Lines */
 
1364
        if( sscanf (s, "-->> %d", &t) == 1)
 
1365
        {
 
1366
            p_subtitle->i_start = (int64_t)t; /* * FPS*/
 
1367
            p_subtitle->i_stop  = 0;
 
1368
 
 
1369
            /* Starting of a subtitle */
 
1370
            if( i_firstline )
 
1371
            {
 
1372
                i_firstline = 0;
 
1373
            }
 
1374
            /* We have been too far: end of the subtitle, begin of next */
 
1375
            else
 
1376
            {
 
1377
                TextPreviousLine( txt );
 
1378
                break;
 
1379
            }
 
1380
        }
 
1381
        /* Text Lines */
 
1382
        else
 
1383
        {
 
1384
            i_old = strlen( psz_text ) + 1;
 
1385
            psz_text = realloc( psz_text, i_old + strlen( s ) + 1 );
 
1386
            if( !psz_text )
 
1387
                 return VLC_ENOMEM;
 
1388
            strcat( psz_text, s );
 
1389
            strcat( psz_text, "\n" );
 
1390
            if( txt->i_line == txt->i_line_count )
 
1391
                break;
 
1392
        }
 
1393
    }
 
1394
    p_subtitle->psz_text = psz_text;
 
1395
    return VLC_SUCCESS;
 
1396
}
 
1397
 
 
1398
static int ParsePJS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
 
1399
{
 
1400
    VLC_UNUSED( i_idx );
 
1401
 
 
1402
    demux_sys_t *p_sys = p_demux->p_sys;
 
1403
    text_t      *txt = &p_sys->txt;
 
1404
    char *psz_text;
 
1405
    int i;
 
1406
 
 
1407
    for( ;; )
 
1408
    {
 
1409
        const char *s = TextGetLine( txt );
 
1410
        int t1, t2;
 
1411
 
 
1412
        if( !s )
 
1413
            return VLC_EGENERIC;
 
1414
 
 
1415
        psz_text = malloc( strlen(s) + 1 );
 
1416
        if( !psz_text )
 
1417
            return VLC_ENOMEM;
 
1418
 
 
1419
        /* Data Lines */
 
1420
        if( sscanf (s, "%d,%d,\"%[^\n\r]", &t1, &t2, psz_text ) == 3 )
 
1421
        {
 
1422
            /* 1/10th of second ? Frame based ? FIXME */
 
1423
            p_subtitle->i_start = 10 * t1;
 
1424
            p_subtitle->i_stop = 10 * t2;
 
1425
            /* Remove latest " */
 
1426
            psz_text[ strlen(psz_text) - 1 ] = '\0';
 
1427
 
 
1428
            break;
 
1429
        }
 
1430
        free( psz_text );
 
1431
    }
 
1432
 
 
1433
    /* replace | by \n */
 
1434
    for( i = 0; psz_text[i] != '\0'; i++ )
 
1435
    {
 
1436
        if( psz_text[i] == '|' )
 
1437
            psz_text[i] = '\n';
 
1438
    }
 
1439
 
 
1440
    p_subtitle->psz_text = psz_text;
 
1441
    msg_Dbg( p_demux, "%s", psz_text );
 
1442
    return VLC_SUCCESS;
 
1443
}
 
1444
 
 
1445
static int ParseMPSub( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
 
1446
{
 
1447
    VLC_UNUSED( i_idx );
 
1448
 
 
1449
    demux_sys_t *p_sys = p_demux->p_sys;
 
1450
    text_t      *txt = &p_sys->txt;
 
1451
    char *psz_text = strdup( "" );
 
1452
 
 
1453
    if( !p_sys->mpsub.b_inited )
 
1454
    {
 
1455
        p_sys->mpsub.f_total = 0.0;
 
1456
        p_sys->mpsub.f_factor = 0.0;
 
1457
 
 
1458
        p_sys->mpsub.b_inited = true;
 
1459
    }
 
1460
 
 
1461
    for( ;; )
 
1462
    {
 
1463
        float f1, f2;
 
1464
        char p_dummy;
 
1465
        char *psz_temp;
 
1466
 
 
1467
        const char *s = TextGetLine( txt );
 
1468
        if( !s )
 
1469
            return VLC_EGENERIC;
 
1470
 
 
1471
        if( strstr( s, "FORMAT" ) )
 
1472
        {
 
1473
            if( sscanf (s, "FORMAT=TIM%c", &p_dummy ) == 1 && p_dummy == 'E')
 
1474
            {
 
1475
                p_sys->mpsub.f_factor = 100.0;
 
1476
                break;
 
1477
            }
 
1478
 
 
1479
            psz_temp = malloc( strlen(s) );
 
1480
            if( !psz_temp )
 
1481
                return VLC_ENOMEM;
 
1482
 
 
1483
            if( sscanf( s, "FORMAT=%[^\r\n]", psz_temp ) )
 
1484
            {
 
1485
                float f_fps;
 
1486
                f_fps = us_strtod( psz_temp, NULL );
 
1487
                if( f_fps > 0.0 && var_GetFloat( p_demux, "sub-fps" ) <= 0.0 )
 
1488
                    var_SetFloat( p_demux, "sub-fps", f_fps );
 
1489
 
 
1490
                p_sys->mpsub.f_factor = 1.0;
 
1491
                free( psz_temp );
 
1492
                break;
 
1493
            }
 
1494
            free( psz_temp );
 
1495
        }
 
1496
        /* Data Lines */
 
1497
        f1 = us_strtod( s, &psz_temp );
 
1498
        if( *psz_temp )
 
1499
        {
 
1500
            f2 = us_strtod( psz_temp, NULL );
 
1501
            p_sys->mpsub.f_total += f1 * p_sys->mpsub.f_factor;
 
1502
            p_subtitle->i_start = (int64_t)(10000.0 * p_sys->mpsub.f_total);
 
1503
            p_sys->mpsub.f_total += f2 * p_sys->mpsub.f_factor;
 
1504
            p_subtitle->i_stop = (int64_t)(10000.0 * p_sys->mpsub.f_total);
 
1505
            break;
 
1506
        }
 
1507
    }
 
1508
 
 
1509
    for( ;; )
 
1510
    {
 
1511
        const char *s = TextGetLine( txt );
 
1512
 
 
1513
        if( !s )
 
1514
            return VLC_EGENERIC;
 
1515
 
 
1516
        int i_len = strlen( s );
 
1517
        if( i_len == 0 )
 
1518
            break;
 
1519
 
 
1520
        int i_old = strlen( psz_text );
 
1521
 
 
1522
        psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
 
1523
        if( !psz_text )
 
1524
             return VLC_ENOMEM;
 
1525
 
 
1526
        strcat( psz_text, s );
 
1527
        strcat( psz_text, "\n" );
 
1528
    }
 
1529
 
 
1530
    p_subtitle->psz_text = psz_text;
 
1531
    return VLC_SUCCESS;
 
1532
}
 
1533
 
 
1534
static int ParseJSS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
 
1535
{
 
1536
    VLC_UNUSED( i_idx );
 
1537
 
 
1538
    demux_sys_t  *p_sys = p_demux->p_sys;
 
1539
    text_t       *txt = &p_sys->txt;
 
1540
    char         *psz_text, *psz_orig;
 
1541
    char         *psz_text2, *psz_orig2;
 
1542
    int h1, h2, m1, m2, s1, s2, f1, f2;
 
1543
 
 
1544
    if( !p_sys->jss.b_inited )
 
1545
    {
 
1546
        p_sys->jss.i_comment = 0;
 
1547
        p_sys->jss.i_time_resolution = 30;
 
1548
        p_sys->jss.i_time_shift = 0;
 
1549
 
 
1550
        p_sys->jss.b_inited = true;
 
1551
    }
 
1552
 
 
1553
    /* Parse the main lines */
 
1554
    for( ;; )
 
1555
    {
 
1556
        const char *s = TextGetLine( txt );
 
1557
        if( !s )
 
1558
            return VLC_EGENERIC;
 
1559
 
 
1560
        psz_orig = malloc( strlen( s ) + 1 );
 
1561
        if( !psz_orig )
 
1562
            return VLC_ENOMEM;
 
1563
        psz_text = psz_orig;
 
1564
 
 
1565
        /* Complete time lines */
 
1566
        if( sscanf( s, "%d:%d:%d.%d %d:%d:%d.%d %[^\n\r]",
 
1567
                    &h1, &m1, &s1, &f1, &h2, &m2, &s2, &f2, psz_text ) == 9 )
 
1568
        {
 
1569
            p_subtitle->i_start = ( (int64_t)( h1 *3600 + m1 * 60 + s1 ) +
 
1570
                (int64_t)( ( f1 +  p_sys->jss.i_time_shift ) /  p_sys->jss.i_time_resolution ) )
 
1571
                * 1000000;
 
1572
            p_subtitle->i_stop = ( (int64_t)( h2 *3600 + m2 * 60 + s2 ) +
 
1573
                (int64_t)( ( f2 +  p_sys->jss.i_time_shift ) /  p_sys->jss.i_time_resolution ) )
 
1574
                * 1000000;
 
1575
            break;
 
1576
        }
 
1577
        /* Short time lines */
 
1578
        else if( sscanf( s, "@%d @%d %[^\n\r]", &f1, &f2, psz_text ) == 3 )
 
1579
        {
 
1580
            p_subtitle->i_start = (int64_t)(
 
1581
                    ( f1 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution * 1000000.0 );
 
1582
            p_subtitle->i_stop = (int64_t)(
 
1583
                    ( f2 + p_sys->jss.i_time_shift ) / p_sys->jss.i_time_resolution * 1000000.0 );
 
1584
            break;
 
1585
        }
 
1586
        /* General Directive lines */
 
1587
        /* Only TIME and SHIFT are supported so far */
 
1588
        else if( s[0] == '#' )
 
1589
        {
 
1590
            int h = 0, m =0, sec = 1, f = 1;
 
1591
            unsigned shift = 1;
 
1592
            int inv = 1;
 
1593
 
 
1594
            strcpy( psz_text, s );
 
1595
 
 
1596
            switch( toupper( psz_text[1] ) )
 
1597
            {
 
1598
            case 'S':
 
1599
                 shift = isalpha( psz_text[2] ) ? 6 : 2 ;
 
1600
 
 
1601
                 if( sscanf( &psz_text[shift], "%d", &h ) )
 
1602
                 {
 
1603
                     /* Negative shifting */
 
1604
                     if( h < 0 )
 
1605
                     {
 
1606
                         h *= -1;
 
1607
                         inv = -1;
 
1608
                     }
 
1609
 
 
1610
                     if( sscanf( &psz_text[shift], "%*d:%d", &m ) )
 
1611
                     {
 
1612
                         if( sscanf( &psz_text[shift], "%*d:%*d:%d", &sec ) )
 
1613
                         {
 
1614
                             sscanf( &psz_text[shift], "%*d:%*d:%*d.%d", &f );
 
1615
                         }
 
1616
                         else
 
1617
                         {
 
1618
                             h = 0;
 
1619
                             sscanf( &psz_text[shift], "%d:%d.%d",
 
1620
                                     &m, &sec, &f );
 
1621
                             m *= inv;
 
1622
                         }
 
1623
                     }
 
1624
                     else
 
1625
                     {
 
1626
                         h = m = 0;
 
1627
                         sscanf( &psz_text[shift], "%d.%d", &sec, &f);
 
1628
                         sec *= inv;
 
1629
                     }
 
1630
                     p_sys->jss.i_time_shift = ( ( h * 3600 + m * 60 + sec )
 
1631
                         * p_sys->jss.i_time_resolution + f ) * inv;
 
1632
                 }
 
1633
                 break;
 
1634
 
 
1635
            case 'T':
 
1636
                shift = isalpha( psz_text[2] ) ? 8 : 2 ;
 
1637
 
 
1638
                sscanf( &psz_text[shift], "%d", &p_sys->jss.i_time_resolution );
 
1639
                break;
 
1640
            }
 
1641
            free( psz_orig );
 
1642
            continue;
 
1643
        }
 
1644
        else
 
1645
            /* Unkown type line, probably a comment */
 
1646
        {
 
1647
            free( psz_orig );
 
1648
            continue;
 
1649
        }
 
1650
    }
 
1651
        
 
1652
        while( psz_text[ strlen( psz_text ) - 1 ] == '\\' )
 
1653
        {
 
1654
        const char *s2 = TextGetLine( txt );
 
1655
 
 
1656
        if( !s2 )
 
1657
            return VLC_EGENERIC;
 
1658
 
 
1659
        int i_len = strlen( s2 );
 
1660
        if( i_len == 0 )
 
1661
            break;
 
1662
 
 
1663
        int i_old = strlen( psz_text );
 
1664
 
 
1665
        psz_text = realloc( psz_text, i_old + i_len + 1 );
 
1666
        if( !psz_text )
 
1667
             return VLC_ENOMEM;
 
1668
 
 
1669
                psz_orig = psz_text;
 
1670
        strcat( psz_text, s2 );
 
1671
        }
 
1672
 
 
1673
    /* Skip the blanks */
 
1674
    while( *psz_text == ' ' || *psz_text == '\t' ) psz_text++;
 
1675
 
 
1676
    /* Parse the directives */
 
1677
    if( isalpha( *psz_text ) || *psz_text == '[' )
 
1678
    {
 
1679
        while( *psz_text != ' ' )
 
1680
        { psz_text++ ;};
 
1681
 
 
1682
        /* Directives are NOT parsed yet */
 
1683
        /* This has probably a better place in a decoder ? */
 
1684
        /* directive = malloc( strlen( psz_text ) + 1 );
 
1685
           if( sscanf( psz_text, "%s %[^\n\r]", directive, psz_text2 ) == 2 )*/
 
1686
    }
 
1687
 
 
1688
    /* Skip the blanks after directives */
 
1689
    while( *psz_text == ' ' || *psz_text == '\t' ) psz_text++;
 
1690
 
 
1691
    /* Clean all the lines from inline comments and other stuffs */
 
1692
    psz_orig2 = calloc( strlen( psz_text) + 1, 1 );
 
1693
    psz_text2 = psz_orig2;
 
1694
 
 
1695
    for( ; *psz_text != '\0' && *psz_text != '\n' && *psz_text != '\r'; )
 
1696
    {
 
1697
        switch( *psz_text )
 
1698
        {
 
1699
        case '{':
 
1700
            p_sys->jss.i_comment++;
 
1701
            break;
 
1702
        case '}':
 
1703
            if( p_sys->jss.i_comment )
 
1704
            {
 
1705
                p_sys->jss.i_comment = 0;
 
1706
                if( (*(psz_text + 1 ) ) == ' ' ) psz_text++;
 
1707
            }
 
1708
            break;
 
1709
        case '~':
 
1710
            if( !p_sys->jss.i_comment )
 
1711
            {
 
1712
                *psz_text2 = ' ';
 
1713
                psz_text2++;
 
1714
            }
 
1715
            break;
 
1716
        case ' ':
 
1717
        case '\t':
 
1718
            if( (*(psz_text + 1 ) ) == ' ' || (*(psz_text + 1 ) ) == '\t' )
 
1719
                break;
 
1720
            if( !p_sys->jss.i_comment )
 
1721
            {
 
1722
                *psz_text2 = ' ';
 
1723
                psz_text2++;
 
1724
            }
 
1725
            break;
 
1726
        case '\\':
 
1727
            if( (*(psz_text + 1 ) ) == 'n' )
 
1728
            {
 
1729
                *psz_text2 = '\n';
 
1730
                psz_text++;
 
1731
                psz_text2++;
 
1732
                break;
 
1733
            }
 
1734
            if( ( toupper(*(psz_text + 1 ) ) == 'C' ) ||
 
1735
                    ( toupper(*(psz_text + 1 ) ) == 'F' ) )
 
1736
            {
 
1737
                psz_text++; psz_text++;
 
1738
                break;
 
1739
            }
 
1740
            if( (*(psz_text + 1 ) ) == 'B' || (*(psz_text + 1 ) ) == 'b' ||
 
1741
                (*(psz_text + 1 ) ) == 'I' || (*(psz_text + 1 ) ) == 'i' ||
 
1742
                (*(psz_text + 1 ) ) == 'U' || (*(psz_text + 1 ) ) == 'u' ||
 
1743
                (*(psz_text + 1 ) ) == 'D' || (*(psz_text + 1 ) ) == 'N' )
 
1744
            {
 
1745
                psz_text++;
 
1746
                break;
 
1747
            }
 
1748
            if( (*(psz_text + 1 ) ) == '~' || (*(psz_text + 1 ) ) == '{' ||
 
1749
                (*(psz_text + 1 ) ) == '\\' )
 
1750
                psz_text++;
 
1751
            else if( *(psz_text + 1 ) == '\r' ||  *(psz_text + 1 ) == '\n' ||
 
1752
                     *(psz_text + 1 ) == '\0' )
 
1753
            {
 
1754
                                psz_text++;
 
1755
            }
 
1756
            break;
 
1757
        default:
 
1758
            if( !p_sys->jss.i_comment )
 
1759
            {
 
1760
                *psz_text2 = *psz_text;
 
1761
                psz_text2++;
 
1762
            }
 
1763
        }
 
1764
        psz_text++;
 
1765
    }
 
1766
 
 
1767
    p_subtitle->psz_text = psz_orig2;
 
1768
    msg_Dbg( p_demux, "%s", p_subtitle->psz_text );
 
1769
    free( psz_orig );
 
1770
    return VLC_SUCCESS;
 
1771
}
 
1772
 
 
1773
static int ParsePSB( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
 
1774
{
 
1775
    VLC_UNUSED( i_idx );
 
1776
 
 
1777
    demux_sys_t *p_sys = p_demux->p_sys;
 
1778
    text_t      *txt = &p_sys->txt;
 
1779
    char *psz_text;
 
1780
    int i;
 
1781
 
 
1782
    for( ;; )
 
1783
    {
 
1784
        int h1, m1, s1;
 
1785
        int h2, m2, s2;
 
1786
        const char *s = TextGetLine( txt );
 
1787
 
 
1788
        if( !s )
 
1789
            return VLC_EGENERIC;
 
1790
 
 
1791
        psz_text = malloc( strlen( s ) + 1 );
 
1792
        if( !psz_text )
 
1793
            return VLC_ENOMEM;
 
1794
 
 
1795
        if( sscanf( s, "{%d:%d:%d}{%d:%d:%d}%[^\r\n]",
 
1796
                    &h1, &m1, &s1, &h2, &m2, &s2, psz_text ) == 7 )
 
1797
        {
 
1798
            p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
 
1799
                                    (int64_t)m1 * 60*1000 +
 
1800
                                    (int64_t)s1 * 1000 ) * 1000;
 
1801
            p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
 
1802
                                    (int64_t)m2 * 60*1000 +
 
1803
                                    (int64_t)s2 * 1000 ) * 1000;
 
1804
            break;
 
1805
        }
 
1806
        free( psz_text );
 
1807
    }
 
1808
 
 
1809
    /* replace | by \n */
 
1810
    for( i = 0; psz_text[i] != '\0'; i++ )
 
1811
    {
 
1812
        if( psz_text[i] == '|' )
 
1813
            psz_text[i] = '\n';
 
1814
    }
 
1815
    p_subtitle->psz_text = psz_text;
 
1816
    return VLC_SUCCESS;
 
1817
}
 
1818
 
 
1819
static int64_t ParseRealTime( char *psz, int *h, int *m, int *s, int *f )
 
1820
{
 
1821
    if( strlen( psz ) == 0 ) return 0;
 
1822
    if( sscanf( psz, "%d:%d:%d.%d", h, m, s, f ) == 4 ||
 
1823
            sscanf( psz, "%d:%d.%d", m, s, f ) == 3 ||
 
1824
            sscanf( psz, "%d.%d", s, f ) == 2 ||
 
1825
            sscanf( psz, "%d:%d", m, s ) == 2 ||
 
1826
            sscanf( psz, "%d", s ) == 1 )
 
1827
    {
 
1828
        return (int64_t)((( *h * 60 + *m ) * 60 ) + *s ) * 1000 * 1000
 
1829
               + (int64_t)*f * 10 * 1000;
 
1830
    }
 
1831
    else return VLC_EGENERIC;
 
1832
}
 
1833
 
 
1834
static int ParseRealText( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
 
1835
{
 
1836
    VLC_UNUSED( i_idx );
 
1837
    demux_sys_t *p_sys = p_demux->p_sys;
 
1838
    text_t      *txt = &p_sys->txt;
 
1839
    char *psz_text;
 
1840
    char psz_end[12]= "", psz_begin[12] = "";
 
1841
 
 
1842
    for( ;; )
 
1843
    {
 
1844
        int h1 = 0, m1 = 0, s1 = 0, f1 = 0;
 
1845
        int h2 = 0, m2 = 0, s2 = 0, f2 = 0;
 
1846
        const char *s = TextGetLine( txt );
 
1847
 
 
1848
        if( !s )
 
1849
            return VLC_EGENERIC;
 
1850
 
 
1851
        psz_text = malloc( strlen( s ) + 1 );
 
1852
        if( !psz_text )
 
1853
            return VLC_ENOMEM;
 
1854
 
 
1855
        /* Find the good begining. This removes extra spaces at the beginning
 
1856
           of the line.*/
 
1857
        char *psz_temp = strcasestr( s, "<time");
 
1858
        if( psz_temp != NULL )
 
1859
        {
 
1860
            /* Line has begin and end */
 
1861
            if( ( sscanf( psz_temp,
 
1862
                  "<%*[t|T]ime %*[b|B]egin=\"%[^\"]\" %*[e|E]nd=\"%[^\"]%*[^>]%[^\n\r]",
 
1863
                            psz_begin, psz_end, psz_text) != 3 ) &&
 
1864
                    /* Line has begin and no end */
 
1865
                    ( sscanf( psz_temp,
 
1866
                              "<%*[t|T]ime %*[b|B]egin=\"%[^\"]\"%*[^>]%[^\n\r]",
 
1867
                              psz_begin, psz_text ) != 2) )
 
1868
                /* Line is not recognized */
 
1869
            {
 
1870
                free( psz_text );
 
1871
                continue;
 
1872
            }
 
1873
 
 
1874
            /* Get the times */
 
1875
            int64_t i_time = ParseRealTime( psz_begin, &h1, &m1, &s1, &f1 );
 
1876
            if( i_time >= 0)
 
1877
            {
 
1878
                p_subtitle->i_start = i_time;
 
1879
            }
 
1880
 
 
1881
            i_time = ParseRealTime( psz_end, &h2, &m2, &s2, &f2 );
 
1882
            if( i_time >= 0 )
 
1883
            {
 
1884
                p_subtitle->i_stop = i_time;
 
1885
            }
 
1886
            break;
 
1887
        }
 
1888
        /* Line is not recognized */
 
1889
        else continue;
 
1890
        free( psz_text );
 
1891
    }
 
1892
 
 
1893
    /* Get the following Lines */
 
1894
    for( ;; )
 
1895
    {
 
1896
        const char *s = TextGetLine( txt );
 
1897
 
 
1898
        if( !s )
 
1899
            return VLC_EGENERIC;
 
1900
 
 
1901
        int i_len = strlen( s );
 
1902
        if( i_len == 0 ) break;
 
1903
 
 
1904
        if( strcasestr( s, "<time" ) ||
 
1905
            strcasestr( s, "<clear/") )
 
1906
        {
 
1907
            TextPreviousLine( txt );
 
1908
            break;
 
1909
        }
 
1910
 
 
1911
        int i_old = strlen( psz_text );
 
1912
 
 
1913
        psz_text = realloc( psz_text, i_old + i_len + 1 + 1 );
 
1914
        if( !psz_text )
 
1915
            return VLC_ENOMEM;
 
1916
 
 
1917
        strcat( psz_text, s );
 
1918
        strcat( psz_text, "\n" );
 
1919
    }
 
1920
 
 
1921
    /* Remove the starting ">" that remained after the sscanf */
 
1922
    memmove( &psz_text[0], &psz_text[1], strlen( psz_text ) );
 
1923
 
 
1924
    p_subtitle->psz_text = psz_text;
 
1925
 
 
1926
    return VLC_SUCCESS;
 
1927
}
 
1928
 
 
1929
static int ParseDKS( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
 
1930
{
 
1931
    VLC_UNUSED( i_idx );
 
1932
 
 
1933
    demux_sys_t *p_sys = p_demux->p_sys;
 
1934
    text_t      *txt = &p_sys->txt;
 
1935
    char *psz_text;
 
1936
 
 
1937
    for( ;; )
 
1938
    {
 
1939
        int h1, m1, s1;
 
1940
        int h2, m2, s2;
 
1941
        char *s = TextGetLine( txt );
 
1942
 
 
1943
        if( !s )
 
1944
            return VLC_EGENERIC;
 
1945
 
 
1946
        psz_text = malloc( strlen( s ) + 1 );
 
1947
        if( !psz_text )
 
1948
            return VLC_ENOMEM;
 
1949
 
 
1950
        if( sscanf( s, "[%d:%d:%d]%[^\r\n]",
 
1951
                    &h1, &m1, &s1, psz_text ) == 4 )
 
1952
        {
 
1953
            p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
 
1954
                                    (int64_t)m1 * 60*1000 +
 
1955
                                    (int64_t)s1 * 1000 ) * 1000;
 
1956
 
 
1957
            char *s = TextGetLine( txt );
 
1958
            if( !s )
 
1959
                return VLC_EGENERIC;
 
1960
 
 
1961
            if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 )
 
1962
                p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
 
1963
                                        (int64_t)m2 * 60*1000 +
 
1964
                                        (int64_t)s2 * 1000 ) * 1000;
 
1965
            break;
 
1966
        }
 
1967
        free( psz_text );
 
1968
    }
 
1969
 
 
1970
    /* replace [br] by \n */
 
1971
    char *p;
 
1972
    while( ( p = strstr( psz_text, "[br]" ) ) )
 
1973
    {
 
1974
        *p++ = '\n';
 
1975
        memmove( p, &p[3], strlen(&p[3])+1 );
 
1976
    }
 
1977
 
 
1978
    p_subtitle->psz_text = psz_text;
 
1979
    return VLC_SUCCESS;
 
1980
}
 
1981
 
 
1982
static int ParseSubViewer1( demux_t *p_demux, subtitle_t *p_subtitle, int i_idx )
 
1983
{
 
1984
    VLC_UNUSED( i_idx );
 
1985
 
 
1986
    demux_sys_t *p_sys = p_demux->p_sys;
 
1987
    text_t      *txt = &p_sys->txt;
 
1988
    char *psz_text;
 
1989
 
 
1990
    for( ;; )
 
1991
    {
 
1992
        int h1, m1, s1;
 
1993
        int h2, m2, s2;
 
1994
        char *s = TextGetLine( txt );
 
1995
 
 
1996
        if( !s )
 
1997
            return VLC_EGENERIC;
 
1998
 
 
1999
        if( sscanf( s, "[%d:%d:%d]", &h1, &m1, &s1 ) == 3 )
 
2000
        {
 
2001
            p_subtitle->i_start = ( (int64_t)h1 * 3600*1000 +
 
2002
                                    (int64_t)m1 * 60*1000 +
 
2003
                                    (int64_t)s1 * 1000 ) * 1000;
 
2004
 
 
2005
            char *s = TextGetLine( txt );
 
2006
            if( !s )
 
2007
                return VLC_EGENERIC;
 
2008
 
 
2009
            psz_text = strdup( s );
 
2010
            if( !psz_text )
 
2011
                return VLC_ENOMEM;
 
2012
 
 
2013
            s = TextGetLine( txt );
 
2014
            if( !s )
 
2015
                return VLC_EGENERIC;
 
2016
 
 
2017
            if( sscanf( s, "[%d:%d:%d]", &h2, &m2, &s2 ) == 3 )
 
2018
                p_subtitle->i_stop  = ( (int64_t)h2 * 3600*1000 +
 
2019
                                        (int64_t)m2 * 60*1000 +
 
2020
                                        (int64_t)s2 * 1000 ) * 1000;
 
2021
            break;
 
2022
        }
 
2023
    }
 
2024
 
 
2025
    p_subtitle->psz_text = psz_text;
 
2026
 
 
2027
    return VLC_SUCCESS;
1304
2028
}
1305
2029