input.c 41 KB
Newer Older
1
2
3
4
5
6
7
8
/*****************************************************************************
 * input.c: DvdRead plugin.
 *****************************************************************************
 * This plugins should handle all the known specificities of the DVD format,
 * especially the 2048 bytes logical block size.
 * It depends on: libdvdread for ifo files and block reading.
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
gbazin's avatar
   
gbazin committed
9
 * $Id: input.c,v 1.13 2003/01/23 10:25:40 gbazin Exp $
10
11
12
13
14
15
16
17
18
19
 *
 * Author: Stphane Borel <stef@via.ecp.fr>
 *
 * Some code taken form the play_title.c by Billy Biggs <vektor@dumbterm.net>
 * in libdvdread.
 *
 * 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.
20
 *
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 * 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 <stdio.h>
#include <stdlib.h>

#include <vlc/vlc.h>
#include <vlc/input.h>

40
41
#include "../../demux/mpeg/system.h"

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <assert.h>

#ifdef STRNCASECMP_IN_STRINGS_H
#   include <strings.h>
#endif

#if defined( WIN32 )
#   include <io.h>                                                 /* read() */
#endif

#include <dvdread/dvd_reader.h>
#include <dvdread/ifo_types.h>
#include <dvdread/ifo_read.h>
#include <dvdread/nav_read.h>
#include <dvdread/nav_print.h>

#include "input.h"

#include "iso_lang.h"

/* how many blocks DVDRead will read in each loop */
#define DVD_BLOCK_READ_ONCE 64

74
75
76
77
78
79
80
81
82
/*****************************************************************************
 * Private structure
 *****************************************************************************/
struct demux_sys_t
{
    module_t *   p_module;
    mpeg_demux_t mpeg;
};

83
84
85
86
87
88
89
90
91
92
93
94
95
96
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
/* called from outside */
static int  DvdReadDemux    ( input_thread_t * );
static int  DvdReadRewind   ( input_thread_t * );

static int  DvdReadSetArea    ( input_thread_t *, input_area_t * );
static int  DvdReadSetProgram ( input_thread_t *, pgrm_descriptor_t * );
static int  DvdReadRead       ( input_thread_t *, byte_t *, size_t );
static void DvdReadSeek       ( input_thread_t *, off_t );

/* called only from here */
static void DvdReadLauchDecoders( input_thread_t * p_input );
97
static void DvdReadHandleDSI( thread_dvd_data_t * p_dvd, uint8_t * p_data );
98
99
100
101
102
103
104
static void DvdReadFindCell ( thread_dvd_data_t * p_dvd );

/*
 * Data demux functions
 */

/*****************************************************************************
105
 * InitDVD: initialize DVD structures
106
107
108
109
 *****************************************************************************/
int E_(InitDVD) ( vlc_object_t *p_this )
{
    input_thread_t *p_input = (input_thread_t *)p_this;
110
    demux_sys_t *   p_demux;
111
112
113

    if( p_input->stream.i_method != INPUT_METHOD_DVD )
    {
114
        return VLC_EGENERIC;
115
116
    }

117
118
119
    p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
    if( p_demux == NULL )
    {
120
        return VLC_ENOMEM;
121
122
123
124
125
126
127
    }

    p_input->p_private = (void*)&p_demux->mpeg;
    p_demux->p_module = module_Need( p_input, "mpeg-system", NULL );
    if( p_demux->p_module == NULL )
    {
        free( p_input->p_demux_data );
gbazin's avatar
   
gbazin committed
128
        return VLC_ENOMOD;
129
130
    }

131
132
133
134
    p_input->pf_demux = DvdReadDemux;
    p_input->pf_rewind = NULL;

    vlc_mutex_lock( &p_input->stream.stream_lock );
135

136
    DvdReadLauchDecoders( p_input );
137

138
139
    vlc_mutex_unlock( &p_input->stream.stream_lock );

140
    return VLC_SUCCESS;
141
142
}

143
144
145
146
147
148
149
150
151
152
153
/*****************************************************************************
 * EndDVD: end DVD structures
 *****************************************************************************/
void E_(EndDVD) ( vlc_object_t *p_this )
{
    input_thread_t *p_input = (input_thread_t *)p_this;

    module_Unneed( p_input, p_input->p_demux_data->p_module );
    free( p_input->p_demux_data );
}

154
155
156
157
158
159
160
/*****************************************************************************
 * DvdReadDemux
 *****************************************************************************/
#define PEEK( SIZE )                                                        \
    i_result = input_Peek( p_input, &p_peek, SIZE );                        \
    if( i_result == -1 )                                                    \
    {                                                                       \
161
        return -1;                                                          \
162
163
164
165
    }                                                                       \
    else if( i_result < SIZE )                                              \
    {                                                                       \
        /* EOF */                                                           \
166
        return 0;                                                           \
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
    }

static int DvdReadDemux( input_thread_t * p_input )
{
    int                 i;
    byte_t *            p_peek;
    data_packet_t *     p_data;
    ssize_t             i_result;
    int                 i_packet_size;


    /* Read headers to compute payload length */
    for( i = 0 ; i < DVD_BLOCK_READ_ONCE ; i++ )
    {

        /* Read what we believe to be a packet header. */
        PEEK( 4 );
184
185

        /* Default header */
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
        if( U32_AT( p_peek ) != 0x1BA )
        {
            /* That's the case for all packets, except pack header. */
            i_packet_size = U16_AT( p_peek + 4 );
        }
        else
        {
            /* MPEG-2 Pack header. */
            i_packet_size = 8;
        }

        /* Fetch a packet of the appropriate size. */
        i_result = input_SplitBuffer( p_input, &p_data, i_packet_size + 6 );
        if( i_result <= 0 )
        {
            return( i_result );
        }

        /* In MPEG-2 pack headers we still have to read stuffing bytes. */
        if( (p_data->p_demux_start[3] == 0xBA) && (i_packet_size == 8) )
        {
            size_t i_stuffing = (p_data->p_demux_start[13] & 0x7);
            /* Force refill of the input buffer - though we don't care
             * about p_peek. Please note that this is unoptimized. */
            PEEK( i_stuffing );
            p_input->p_current_data += i_stuffing;
        }

214
        p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
215

216
217
218
219
220
221
222
223
224
225
    }

    return i;
}

/*****************************************************************************
 * DVDRewind : reads a stream backward
 *****************************************************************************/
static int DvdReadRewind( input_thread_t * p_input )
{
226
    return -1;
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
}

/*
 * Data access functions
 */

/*****************************************************************************
 * OpenDVD: open libdvdread
 *****************************************************************************/
int E_(OpenDVD) ( vlc_object_t *p_this )
{
    input_thread_t *        p_input = (input_thread_t *)p_this;
    char *                  psz_parser;
    char *                  psz_source;
    char *                  psz_next;
    struct stat             stat_info;
    thread_dvd_data_t *     p_dvd;
    dvd_reader_t *          p_dvdread;
    input_area_t *          p_area;
    int                     i_title = 1;
    int                     i_chapter = 1;
    int                     i_angle = 1;
    int                     i;

gbazin's avatar
   
gbazin committed
251
252
    psz_parser = psz_source = strdup( p_input->psz_name );
    if( !psz_source )
253
    {
254
        return VLC_ENOMEM;
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
    }

    p_input->pf_read = DvdReadRead;
    p_input->pf_seek = DvdReadSeek;
    p_input->pf_set_area = DvdReadSetArea;
    p_input->pf_set_program = DvdReadSetProgram;

    while( *psz_parser && *psz_parser != '@' )
    {
        psz_parser++;
    }

    if( *psz_parser == '@' )
    {
        /* Found options */
        *psz_parser = '\0';
        ++psz_parser;

        i_title = (int)strtol( psz_parser, &psz_next, 10 );
        if( *psz_next )
        {
            psz_parser = psz_next + 1;
            i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
            if( *psz_next )
            {
                i_angle = (int)strtol( psz_next + 1, NULL, 10 );
            }
        }

        i_title = i_title ? i_title : 1;
        i_chapter = i_chapter ? i_chapter : 1;
        i_angle = i_angle ? i_angle : 1;
    }

    if( !*psz_source )
    {
gbazin's avatar
   
gbazin committed
291
        free( psz_source );
292
293
        if( !p_input->psz_access )
        {
294
            return VLC_EGENERIC;
295
296
        }
        psz_source = config_GetPsz( p_input, "dvd" );
297
        if( !psz_source ) return VLC_EGENERIC;
298
299
300
301
    }

    if( stat( psz_source, &stat_info ) == -1 )
    {
302
303
        msg_Warn( p_input, "cannot stat() source `%s' (%s)",
                           psz_source, strerror(errno) );
gbazin's avatar
   
gbazin committed
304
        free( psz_source );
305
        return VLC_EGENERIC;
306
307
308
309
310
311
    }
    if( !S_ISBLK(stat_info.st_mode) &&
        !S_ISCHR(stat_info.st_mode) &&
        !S_ISDIR(stat_info.st_mode) )
    {
        msg_Warn( p_input, "dvdread module discarded (not a valid source)" );
gbazin's avatar
   
gbazin committed
312
        free( psz_source );
313
        return VLC_EGENERIC;
314
    }
315

316
317
    msg_Dbg( p_input, "dvdroot=%s title=%d chapter=%d angle=%d",
                      psz_source, i_title, i_chapter, i_angle );
318

319
320
321
322

    p_dvdread = DVDOpen( psz_source );

    /* free allocated strings */
gbazin's avatar
   
gbazin committed
323
    free( psz_source );
324
325
326
327

    if( ! p_dvdread )
    {
        msg_Err( p_input, "libdvdcss cannot open source" );
328
        return VLC_EGENERIC;
329
330
331
332
333
334
335
336
337
    }

    /* set up input  */
    p_input->i_mtu = 0;

    p_dvd = malloc( sizeof(thread_dvd_data_t) );
    if( p_dvd == NULL )
    {
        msg_Err( p_input, "out of memory" );
338
        return VLC_ENOMEM;
339
340
341
342
343
344
345
346
347
348
349
350
351
352
    }

    p_dvd->p_dvdread = p_dvdread;
    p_dvd->p_title = NULL;
    p_dvd->p_vts_file = NULL;


    p_input->p_access_data = (void *)p_dvd;

    /* Ifo allocation & initialisation */
    if( ! ( p_dvd->p_vmg_file = ifoOpen( p_dvd->p_dvdread, 0 ) ) )
    {
        msg_Err( p_input, "cannot open VMG info" );
        free( p_dvd );
353
        return VLC_EGENERIC;
354
355
356
357
358
359
360
361
362
    }
    msg_Dbg( p_input, "VMG opened" );

    /* Set stream and area data */
    vlc_mutex_lock( &p_input->stream.stream_lock );

    p_input->stream.i_method = INPUT_METHOD_DVD;

    /* If we are here we can control the pace... */
363
364
365
366
    p_input->stream.b_pace_control = VLC_TRUE;
    p_input->stream.b_seekable = VLC_TRUE;
    p_input->stream.b_connected = VLC_TRUE;

367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
    p_input->stream.p_selected_area->i_size = 0;
    p_input->stream.p_selected_area->i_tell = 0;

    /* Initialize ES structures */
    input_InitStream( p_input, sizeof( stream_ps_data_t ) );

    /* disc input method */
    p_input->stream.i_method = INPUT_METHOD_DVD;

#define tt_srpt p_dvd->p_vmg_file->tt_srpt
    msg_Dbg( p_input, "number of titles: %d", tt_srpt->nr_of_srpts );

#define area p_input->stream.pp_areas
    /* We start from 1 here since the default area 0
     * is reserved for video_ts.vob */
    for( i = 1 ; i <= tt_srpt->nr_of_srpts ; i++ )
    {
        input_AddArea( p_input );

        /* Titles are Program Chains */
        area[i]->i_id = i;

        /* Absolute start offset and size
         * We can only set that with vts ifo, so we do it during the
         * first call to DVDSetArea */
        area[i]->i_start = 0;
        area[i]->i_size = 0;

        /* Number of chapters */
        area[i]->i_part_nb = tt_srpt->title[i-1].nr_of_ptts;
        area[i]->i_part = 1;

        area[i]->i_plugin_data = tt_srpt->title[i-1].title_set_nr;
    }
#undef area

    p_dvd->i_title = i_title <= tt_srpt->nr_of_srpts ? i_title : 1;
#undef tt_srpt

    p_area = p_input->stream.pp_areas[p_dvd->i_title];
    p_dvd->i_chapter = i_chapter;

    p_dvd->i_chapter = i_chapter < p_area->i_part_nb ? i_chapter : 1;
    p_area->i_part = p_dvd->i_chapter;
411

412
413
414
415
416
417
    p_dvd->i_angle = i_angle;

    /* set title, chapter, audio and subpic */
    if( DvdReadSetArea( p_input, p_area ) )
    {
        vlc_mutex_unlock( &p_input->stream.stream_lock );
418
        return VLC_EGENERIC;
419
420
421
422
    }

    vlc_mutex_unlock( &p_input->stream.stream_lock );

423
424
425
426
    if( !p_input->psz_demux || !*p_input->psz_demux )
    {
        p_input->psz_demux = "dvdread";
    }
427

428
    return VLC_SUCCESS;
429
430
431
432
433
434
435
436
437
438
}

/*****************************************************************************
 * CloseDVD: close libdvdread
 *****************************************************************************/
void E_(CloseDVD) ( vlc_object_t *p_this )
{
    input_thread_t *    p_input = (input_thread_t *)p_this;
    thread_dvd_data_t * p_dvd = (thread_dvd_data_t *)p_input->p_access_data;

439
440
441
442
443
444
445
    /* This is a very nasty side-effect in the DVD plug-in : language
     * selection here influences language selection of other streams. So
     * unset those variables (may not be what the user wants).
     * FIXME FIXME FIXME FIXME FIXME FIXME FIXME --Meuuh */
    config_PutInt( p_input, "audio-channel", -1 );
    config_PutInt( p_input, "spu-channel", -1 );

446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
    /* close libdvdread */
    DVDCloseFile( p_dvd->p_title );
    ifoClose( p_dvd->p_vts_file );
    ifoClose( p_dvd->p_vmg_file );

    DVDClose( p_dvd->p_dvdread );
    free( p_dvd );
    p_input->p_access_data = NULL;

}

/*****************************************************************************
 * DvdReadSetProgram: Does nothing, a DVD is mono-program
 *****************************************************************************/
static int DvdReadSetProgram( input_thread_t * p_input,
                              pgrm_descriptor_t * p_program )
{
    if( p_input->stream.p_selected_program != p_program )
    {
        thread_dvd_data_t *  p_dvd;
466

467
468
469
470
471
472
473
474
475
476
477
        p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
        p_dvd->i_angle = p_program->i_number;

        memcpy( p_program, p_input->stream.p_selected_program,
                sizeof(pgrm_descriptor_t) );
        p_program->i_number = p_dvd->i_angle;
        p_input->stream.p_selected_program = p_program;

        msg_Dbg( p_input, "angle %d selected", p_dvd->i_angle );
    }

478
    return VLC_SUCCESS;
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
}

#define p_pgc         p_dvd->p_cur_pgc

/*****************************************************************************
 * DvdReadSetArea: initialize input data for title x, chapter y.
 * It should be called for each user navigation request.
 *****************************************************************************
 * Take care that i_title starts from 0 (vmg) and i_chapter start from 1.
 * Note that you have to take the lock before entering here.
 *****************************************************************************/
static int DvdReadSetArea( input_thread_t * p_input, input_area_t * p_area )
{
    thread_dvd_data_t *  p_dvd;
    int                  pgc_id = 0;
    int                  pgn = 0;

    p_dvd = (thread_dvd_data_t*)p_input->p_access_data;

    /* we can't use the interface slider until initilization is complete */
499
    p_input->stream.b_seekable = VLC_FALSE;
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540

    if( p_area != p_input->stream.p_selected_area )
    {
        es_descriptor_t *    p_es;
        int                  i_cell = 0;
        int                  i_audio_nb = 0;
        int                  i_spu_nb = 0;
        int                  i;

#define p_vmg         p_dvd->p_vmg_file
#define p_vts         p_dvd->p_vts_file
        if( p_dvd->p_title != NULL )
        {
            DVDCloseFile( p_dvd->p_title );
        }

        if( p_vts != NULL )
        {
            ifoClose( p_vts );
        }

        /* Reset the Chapter position of the old title */
        p_input->stream.p_selected_area->i_part = 1;

        /*
         *  We have to load all title information
         */
        /* Change the default area */
        p_input->stream.p_selected_area = p_area;

        msg_Dbg( p_input, "open VTS %d, for title %d",
            p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr,
            p_area->i_id );

        /* ifo vts */
        if( ! ( p_vts = ifoOpen( p_dvd->p_dvdread,
                p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr ) ) )
        {
            msg_Err( p_input, "fatal error in vts ifo" );
            ifoClose( p_vmg );
            DVDClose( p_dvd->p_dvdread );
541
            return VLC_EGENERIC;
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
        }

        /* title position inside the selected vts */
        p_dvd->i_ttn = p_vmg->tt_srpt->title[ p_area->i_id - 1 ].vts_ttn;

        /*
         * Set selected title start
         */
        pgc_id = p_vts->vts_ptt_srpt->title[p_dvd->i_ttn-1].ptt[0].pgcn;
        pgn = p_vts->vts_ptt_srpt->title[p_dvd->i_ttn-1].ptt[0].pgn;
        p_pgc = p_vts->vts_pgcit->pgci_srp[ pgc_id - 1 ].pgc;
        i_cell = p_pgc->program_map[ pgn - 1 ] - 1;

        p_area->i_start =
            LB2OFF( p_dvd->p_cur_pgc->cell_playback[ i_cell ].first_sector );

        msg_Dbg( p_input, "start %d vts_title %d pgc %d pgn %d",
                  p_area->i_id, p_dvd->i_ttn, pgc_id, pgn );

        /*
         * Find title end
         */
        i_cell = p_dvd->p_cur_pgc->nr_of_cells - 1;

        p_dvd->i_end_block = p_pgc->cell_playback[ i_cell ].last_sector;
        p_area->i_size = LB2OFF( p_dvd->i_end_block )- p_area->i_start;

gbazin's avatar
   
gbazin committed
569
        msg_Dbg( p_input, "start "I64Fd" size "I64Fd" end %d",
570
571
572
573
574
575
576
                  p_area->i_start , p_area->i_size, p_dvd->i_end_block );

        /*
         * Set properties for current chapter
         */
        /* Remeber current chapter */
        p_dvd->i_chapter = p_area->i_part;
577
        p_dvd->b_eoc = VLC_FALSE;
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613

        pgc_id = p_vts->vts_ptt_srpt->title[
                    p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgcn;
        pgn = p_vts->vts_ptt_srpt->title[
                    p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgn;

        p_pgc = p_vts->vts_pgcit->pgci_srp[pgc_id-1].pgc;
        p_dvd->i_pack_len = 0;
        p_dvd->i_next_cell = p_dvd->i_cur_cell = p_pgc->program_map[pgn-1] - 1;
        DvdReadFindCell( p_dvd );

        p_dvd->i_next_vobu = p_dvd->i_cur_block =
            p_pgc->cell_playback[p_dvd->i_cur_cell].first_sector;

        /*
         * Angle management
         */
        p_dvd->i_angle_nb = p_vmg->tt_srpt->title[p_area->i_id-1].nr_of_angles;

        if( p_dvd->i_angle > p_dvd->i_angle_nb )
        {
            p_dvd->i_angle = 1;
        }

        /*
         * We've got enough info, time to open the title set data.
         */
        if( ! ( p_dvd->p_title = DVDOpenFile( p_dvd->p_dvdread,
            p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr,
            DVD_READ_TITLE_VOBS ) ) )
        {
            msg_Err( p_input, "cannot open title (VTS_%02d_1.VOB)",
                     p_vmg->tt_srpt->title[p_area->i_id-1].title_set_nr );
            ifoClose( p_vts );
            ifoClose( p_vmg );
            DVDClose( p_dvd->p_dvdread );
614
            return VLC_EGENERIC;
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
        }

//        IfoPrintTitle( p_dvd );

        /*
         * Destroy obsolete ES by reinitializing program 0
         * and find all ES in title with ifo data
         */
        if( p_input->stream.pp_programs != NULL )
        {
            /* We don't use input_EndStream here since
             * we keep area structures */

            while( p_input->stream.i_es_number )
            {
                input_DelES( p_input, p_input->stream.pp_es[0] );
            }

            while( p_input->stream.i_pgrm_number )
            {
                input_DelProgram( p_input, p_input->stream.pp_programs[0] );
            }

            if( p_input->stream.pp_selected_es )
            {
                free( p_input->stream.pp_selected_es );
                p_input->stream.pp_selected_es = NULL;
            }
            p_input->stream.i_selected_es_number = 0;
        }

        input_AddProgram( p_input, 1, sizeof( stream_ps_data_t ) );
        p_input->stream.p_selected_program = p_input->stream.pp_programs[0];

        for( i = 1 ; i < p_dvd->i_angle_nb ; i++ )
        {
            input_AddProgram( p_input, i+1, 0 );
        }
653

654
        DvdReadSetProgram( p_input,
655
                           p_input->stream.pp_programs[p_dvd->i_angle-1] );
656
657

        /* No PSM to read in DVD mode, we already have all information */
658
        p_input->stream.p_selected_program->b_is_ok = VLC_TRUE;
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675

        p_es = NULL;

        /* ES 0 -> video MPEG2 */
//        IfoPrintVideo( p_dvd );

        p_es = input_AddES( p_input, NULL, 0xe0, 0 );
        p_es->i_stream_id = 0xe0;
        p_es->i_fourcc = VLC_FOURCC('m','p','g','v');
        p_es->i_cat = VIDEO_ES;

#define audio_control \
    p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->audio_control[i-1]
        /* Audio ES, in the order they appear in .ifo */
        for( i = 1 ; i <= p_vts->vtsi_mat->nr_of_vts_audio_streams ; i++ )
        {
            int i_position = 0;
676
            uint16_t i_id;
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692

//            IfoPrintAudio( p_dvd, i );

            /* audio channel is active if first byte is 0x80 */
            if( audio_control & 0x8000 )
            {
                i_audio_nb++;
                i_position = ( audio_control & 0x7F00 ) >> 8;

            msg_Dbg( p_input, "audio position  %d", i_position );
                switch( p_vts->vtsi_mat->vts_audio_attr[i-1].audio_format )
                {
                case 0x00:              /* A52 */
                    i_id = ( ( 0x80 + i_position ) << 8 ) | 0xbd;
                    p_es = input_AddES( p_input, NULL, i_id, 0 );
                    p_es->i_stream_id = 0xbd;
693
                    p_es->i_fourcc = VLC_FOURCC('a','5','2','b');
694
695
                    p_es->i_cat = AUDIO_ES;
                    strcpy( p_es->psz_desc, DecodeLanguage(
696
                        p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ) );
697
698
699
700
701
702
703
704
705
706
707
                    strcat( p_es->psz_desc, " (A52)" );

                    break;
                case 0x02:
                case 0x03:              /* MPEG audio */
                    i_id = 0xc0 + i_position;
                    p_es = input_AddES( p_input, NULL, i_id, 0 );
                    p_es->i_stream_id = i_id;
                    p_es->i_fourcc = VLC_FOURCC('m','p','g','a');
                    p_es->i_cat = AUDIO_ES;
                    strcpy( p_es->psz_desc, DecodeLanguage(
708
                        p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ) );
709
710
711
712
713
714
715
716
                    strcat( p_es->psz_desc, " (mpeg)" );

                    break;
                case 0x04:              /* LPCM */

                    i_id = ( ( 0xa0 + i_position ) << 8 ) | 0xbd;
                    p_es = input_AddES( p_input, NULL, i_id, 0 );
                    p_es->i_stream_id = i_id;
717
                    p_es->i_fourcc = VLC_FOURCC('l','p','c','b');
718
719
                    p_es->i_cat = AUDIO_ES;
                    strcpy( p_es->psz_desc, DecodeLanguage(
720
                        p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ) );
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
                    strcat( p_es->psz_desc, " (lpcm)" );

                    break;
                case 0x06:              /* DTS */
                    i_id = ( ( 0x88 + i_position ) << 8 ) | 0xbd;
                    msg_Err( p_input, "DTS audio not handled yet"
                                      "(0x%x)", i_id );
                    break;
                default:
                    i_id = 0;
                    msg_Err( p_input, "unknown audio type %.2x",
                          p_vts->vtsi_mat->vts_audio_attr[i-1].audio_format );
                }
            }
        }
#undef audio_control
#define spu_control \
    p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->subp_control[i-1]

        /* Sub Picture ES */

        for( i = 1 ; i <= p_vts->vtsi_mat->nr_of_vts_subp_streams; i++ )
        {
            int i_position = 0;
745
            uint16_t i_id;
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779

//            IfoPrintSpu( p_dvd, i );
            msg_Dbg( p_input, "spu %d 0x%02x", i, spu_control );

            if( spu_control & 0x80000000 )
            {
                i_spu_nb++;

                /*  there are several streams for one spu */
                if(  p_vts->vtsi_mat->vts_video_attr.display_aspect_ratio )
                {
                    /* 16:9 */
                    switch( p_vts->vtsi_mat->vts_video_attr.permitted_df )
                    {
                    case 1:
                        i_position = spu_control & 0xff;
                        break;
                    case 2:
                        i_position = ( spu_control >> 8 ) & 0xff;
                        break;
                    default:
                        i_position = ( spu_control >> 16 ) & 0xff;
                        break;
                    }
                }
                else
                {
                    /* 4:3 */
                    i_position = ( spu_control >> 24 ) & 0x7F;
                }

                i_id = ( ( 0x20 + i_position ) << 8 ) | 0xbd;
                p_es = input_AddES( p_input, NULL, i_id, 0 );
                p_es->i_stream_id = 0xbd;
780
                p_es->i_fourcc = VLC_FOURCC('s','p','u','b');
781
782
                p_es->i_cat = SPU_ES;
                strcpy( p_es->psz_desc, DecodeLanguage(
783
                    p_vts->vtsi_mat->vts_subp_attr[i-1].lang_code ) );
784
785
786
787
788
789
790
791
792
793
            }
        }
#undef spu_control

        /* FIXME: hack to check that the demuxer is ready, and set
         * the decoders */
        if( p_input->p_demux )
        {
            DvdReadLauchDecoders( p_input );
        }
794

795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
    } /* i_title >= 0 */
    else
    {
        p_area = p_input->stream.p_selected_area;
    }

    /*
     * Chapter selection
     */

    if( p_area->i_part != p_dvd->i_chapter )
    {
        if( ( p_area->i_part > 0 ) &&
            ( p_area->i_part <= p_area->i_part_nb ))
        {
            p_dvd->i_ttn = p_vmg->tt_srpt->title[p_area->i_id-1].vts_ttn;
            pgc_id = p_vts->vts_ptt_srpt->title[
                        p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgcn;
            pgn = p_vts->vts_ptt_srpt->title[
                        p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgn;

            p_pgc = p_vts->vts_pgcit->pgci_srp[ pgc_id - 1 ].pgc;

            p_dvd->i_cur_cell = p_pgc->program_map[ pgn - 1 ] - 1;
            p_dvd->i_chapter = p_area->i_part;
            DvdReadFindCell( p_dvd );

            p_dvd->i_pack_len = 0;
            p_dvd->i_next_vobu = p_dvd->i_cur_block =
                    p_pgc->cell_playback[p_dvd->i_cur_cell].first_sector;
        }
        else
        {
            p_area->i_part = p_dvd->i_chapter;
        }
    }
#undef p_vts
#undef p_vmg

    /* warn interface that something has changed */
    p_area->i_tell = LB2OFF( p_dvd->i_next_vobu ) - p_area->i_start;
836
837
    p_input->stream.b_seekable = VLC_TRUE;
    p_input->stream.b_changed = VLC_TRUE;
838

839
    return VLC_SUCCESS;
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
}


/*****************************************************************************
 * DvdReadRead: reads data packets into the netlist.
 *****************************************************************************
 * Returns -1 in case of error, 0 if everything went well, and 1 in case of
 * EOF.
 *****************************************************************************/
static int DvdReadRead( input_thread_t * p_input,
                        byte_t * p_buffer, size_t i_count )
{
    thread_dvd_data_t *     p_dvd;
    byte_t *                p_buf;
    int                     i_blocks_once;
    int                     i_blocks;
    int                     i_read;
    int                     i_read_total;
858
    vlc_bool_t              b_eot = VLC_FALSE;
859
860
861
862
863
864
865
866
867
868
869
870
871

    p_dvd = (thread_dvd_data_t *)p_input->p_access_data;
    p_buf = p_buffer;

    /*
     * Playback by cell in this pgc, starting at the cell for our chapter.
     */
    i_blocks = OFF2LB( i_count );
    i_read_total = 0;
    i_read = 0;

    while( i_blocks )
    {
872
        /*
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
         * End of pack, we select the following one
         */
        if( ! p_dvd->i_pack_len )
        {
            /*
             * Read NAV packet.
             */
            if( ( i_read = DVDReadBlocks( p_dvd->p_title, p_dvd->i_next_vobu,
                           1, p_buf ) ) != 1 )
            {
                msg_Err( p_input, "read failed for block %d",
                                  p_dvd->i_next_vobu );
                return -1;
            }

            /* basic check to be sure we don't have a empty title
             * go to next title if so */
            //assert( p_buffer[41] == 0xbf && p_buffer[1027] == 0xbf );
891

892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
            /*
             * Parse the contained dsi packet.
             */

            DvdReadHandleDSI( p_dvd, p_buf );

            /* End of File */
            if( p_dvd->i_next_vobu >= p_dvd->i_end_block + 1 )
            {
                return 1;
            }

            assert( p_dvd->i_pack_len < 1024 );
            /* FIXME: Ugly kludge: we send the pack block to the input for it
             * sometimes has a zero scr and restart the sync */
            p_dvd->i_cur_block ++;
            //p_dvd->i_pack_len++;

            i_read_total++;
            p_buf += DVD_VIDEO_LB_LEN;
            i_blocks--;
        }

        /*
         * Compute the number of blocks to read
         */
        i_blocks_once = p_dvd->i_pack_len >= i_blocks
                 ? i_blocks : p_dvd->i_pack_len;
        p_dvd->i_pack_len -= i_blocks_once;

        /* Reads from DVD */
        i_read = DVDReadBlocks( p_dvd->p_title, p_dvd->i_cur_block,
                                i_blocks_once, p_buf );
        if( i_read != i_blocks_once )
        {
            msg_Err( p_input, "read failed for %d/%d blocks at 0x%02x",
                              i_read, i_blocks_once, p_dvd->i_cur_block );
            return -1;
        }

        i_blocks -= i_read;
        i_read_total += i_read;
        p_dvd->i_cur_block += i_read;
        p_buf += LB2OFF( i_read );

    }
/*
    msg_Dbg( p_input, "i_blocks: %d len: %d current: 0x%02x", i_read, p_dvd->i_pack_len, p_dvd->i_cur_block );
*/

    vlc_mutex_lock( &p_input->stream.stream_lock );

    if( p_dvd->b_eoc )
    {
        /* We modify i_part only at end of chapter not to erase
         * some modification from the interface */
        p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
949
        p_dvd->b_eoc = VLC_FALSE;
950
    }
951

gbazin's avatar
   
gbazin committed
952
953
    if( ( LB2OFF( p_dvd->i_cur_block )
          - p_input->stream.p_selected_area->i_start )
954
955
            >= p_input->stream.p_selected_area->i_size || b_eot )
    {
956
        if( ( p_input->stream.p_selected_area->i_id + 1 ) >=
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
                        p_input->stream.i_area_nb )
        {
            /* EOF */
            vlc_mutex_unlock( &p_input->stream.stream_lock );
            return 1;
        }

        /* EOT */
        msg_Dbg( p_input, "new title" );
        DvdReadSetArea( p_input, p_input->stream.pp_areas[
                        p_input->stream.p_selected_area->i_id+1] );
        vlc_mutex_unlock( &p_input->stream.stream_lock );
        return 0;
    }

    vlc_mutex_unlock( &p_input->stream.stream_lock );

    return LB2OFF( i_read_total );
}
#undef p_pgc

/*****************************************************************************
 * DvdReadSeek : Goes to a given position on the stream.
 *****************************************************************************
 * This one is used by the input and translate chronological position from
 * input to logical position on the device.
 * The lock should be taken before calling this function.
 *****************************************************************************/
static void DvdReadSeek( input_thread_t * p_input, off_t i_off )
{
    thread_dvd_data_t *     p_dvd;
    int                     i_lb;
    int                     i_tmp;
    int                     i_chapter = 0;
    int                     i_cell = 0;
    int                     i_vobu = 0;
    int                     i_sub_cell = 0;

    vlc_mutex_lock( &p_input->stream.stream_lock );
    i_off += p_input->stream.p_selected_area->i_start;
    vlc_mutex_unlock( &p_input->stream.stream_lock );
998

999
1000
    i_lb = OFF2LB( i_off );
    p_dvd = ( thread_dvd_data_t * )p_input->p_access_data;