input_dvd.c 36.9 KB
Newer Older
1
/*****************************************************************************
2 3 4 5 6 7 8 9 10
 * input_dvd.c: DVD raw reading plugin.
 * ---
 * This plugins should handle all the known specificities of the DVD format,
 * especially the 2048 bytes logical block size.
 * It depends on:
 *  -input_netlist used to read packets
 *  -dvd_ifo for ifo parsing and analyse
 *  -dvd_css for unscrambling
 *  -dvd_udf to find files
11
 *****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
12
 * Copyright (C) 1998-2001 VideoLAN
Sam Hocevar's avatar
 
Sam Hocevar committed
13
 * $Id: input_dvd.c,v 1.40 2001/04/08 16:57:47 sam Exp $
14
 *
Sam Hocevar's avatar
 
Sam Hocevar committed
15
 * Author: Stphane Borel <stef@via.ecp.fr>
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
 *
 * 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.
 * 
 * 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 "defs.h"

Sam Hocevar's avatar
 
Sam Hocevar committed
37 38 39 40 41 42 43
#ifdef HAVE_CSS
#define MODULE_NAME dvd-css
#else /* HAVE_CSS */
#define MODULE_NAME dvd-nocss
#endif /* HAVE_CSS */
#include "modules_inner.h"

Sam Hocevar's avatar
 
Sam Hocevar committed
44
#include <stdio.h>
45
#include <stdlib.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
46 47 48 49 50
#include <unistd.h>
#include <netinet/in.h>

#include <fcntl.h>
#include <sys/types.h>
51
#include <sys/uio.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
52

53 54
#include <string.h>
#include <errno.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
55

56 57 58 59
#include "config.h"
#include "common.h"
#include "threads.h"
#include "mtime.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
60
#include "tests.h"
61 62 63

#include "intf_msg.h"

64 65
#include "main.h"

66 67 68 69 70
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"

#include "input.h"
71

72
#include "dvd_netlist.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
73 74 75
#include "dvd_ifo.h"
#include "dvd_css.h"
#include "input_dvd.h"
76 77 78 79
#include "mpeg_system.h"

#include "debug.h"

Sam Hocevar's avatar
 
Sam Hocevar committed
80 81
#include "modules.h"

82 83 84 85 86
/*****************************************************************************
 * Local tables
 *****************************************************************************/
static struct
{
Sam Hocevar's avatar
 
Sam Hocevar committed
87
    char    p_code[3];
88
    char    p_lang_long[20];
Sam Hocevar's avatar
 
Sam Hocevar committed
89
}
90

Sam Hocevar's avatar
 
Sam Hocevar committed
91 92
lang_tbl[] =
{
93 94 95
    /* The ISO 639 language codes.
     * Language names with * prefix are not spelled in their own language 
     */
Sam Hocevar's avatar
 
Sam Hocevar committed
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    { "  ", "Not Specified" },
    { "aa", "*Afar" },
    { "ab", "*Abkhazian" },
    { "af", "*Afrikaans" },
    { "am", "*Amharic" },
    { "ar", "*Arabic" },
    { "as", "*Assamese" },
    { "ay", "*Aymara" },
    { "az", "*Azerbaijani" },
    { "ba", "*Bashkir" },
    { "be", "*Byelorussian" },
    { "bg", "*Bulgarian" },
    { "bh", "*Bihari" },
    { "bi", "*Bislama" },
    { "bn", "*Bengali; Bangla" },
    { "bo", "*Tibetan" },
    { "br", "*Breton" },
    { "ca", "*Catalan" },
    { "co", "*Corsican" },
    { "cs", "*Czech(Ceske)" },
    { "cy", "*Welsh" },
    { "da", "Dansk" },
    { "de", "Deutsch" },
    { "dz", "*Bhutani" },
    { "el", "*Greek" },
    { "en", "English" },
    { "eo", "*Esperanto" },
    { "es", "Espanol" },
    { "et", "*Estonian" },
    { "eu", "*Basque" },
    { "fa", "*Persian" },
    { "fi", "Suomi" },
    { "fj", "*Fiji" },
    { "fo", "*Faroese" },
    { "fr", "Francais" },
    { "fy", "*Frisian" },
    { "ga", "*Irish" },
    { "gd", "*Scots Gaelic" },
    { "gl", "*Galician" },
    { "gn", "*Guarani" },
    { "gu", "*Gujarati" },
    { "ha", "*Hausa" },
    { "he", "*Hebrew" },                                      /* formerly iw */
    { "hi", "*Hindi" },
    { "hr", "Hrvatski" },                                        /* Croatian */
    { "hu", "Magyar" },
    { "hy", "*Armenian" },
    { "ia", "*Interlingua" },
    { "id", "*Indonesian" },                                  /* formerly in */
    { "ie", "*Interlingue" },
    { "ik", "*Inupiak" },
    { "in", "*Indonesian" },                               /* replaced by id */
    { "is", "Islenska" },
    { "it", "Italiano" },
    { "iu", "*Inuktitut" },
    { "iw", "*Hebrew" },                                   /* replaced by he */
    { "ja", "*Japanese" },
    { "ji", "*Yiddish" },                                  /* replaced by yi */
    { "jw", "*Javanese" },
    { "ka", "*Georgian" },
    { "kk", "*Kazakh" },
    { "kl", "*Greenlandic" },
    { "km", "*Cambodian" },
    { "kn", "*Kannada" },
    { "ko", "*Korean" },
    { "ks", "*Kashmiri" },
    { "ku", "*Kurdish" },
    { "ky", "*Kirghiz" },
    { "la", "*Latin" },
    { "ln", "*Lingala" },
    { "lo", "*Laothian" },
    { "lt", "*Lithuanian" },
    { "lv", "*Latvian, Lettish" },
    { "mg", "*Malagasy" },
    { "mi", "*Maori" },
    { "mk", "*Macedonian" },
    { "ml", "*Malayalam" },
    { "mn", "*Mongolian" },
    { "mo", "*Moldavian" },
    { "mr", "*Marathi" },
    { "ms", "*Malay" },
    { "mt", "*Maltese" },
    { "my", "*Burmese" },
    { "na", "*Nauru" },
    { "ne", "*Nepali" },
    { "nl", "Nederlands" },
    { "no", "Norsk" },
    { "oc", "*Occitan" },
    { "om", "*(Afan) Oromo" },
    { "or", "*Oriya" },
    { "pa", "*Punjabi" },
    { "pl", "*Polish" },
    { "ps", "*Pashto, Pushto" },
    { "pt", "Portugues" },
    { "qu", "*Quechua" },
    { "rm", "*Rhaeto-Romance" },
    { "rn", "*Kirundi" },
    { "ro", "*Romanian"  },
    { "ru", "*Russian" },
    { "rw", "*Kinyarwanda" },
    { "sa", "*Sanskrit" },
    { "sd", "*Sindhi" },
    { "sg", "*Sangho" },
    { "sh", "*Serbo-Croatian" },
    { "si", "*Sinhalese" },
    { "sk", "*Slovak" },
    { "sl", "*Slovenian" },
    { "sm", "*Samoan" },
    { "sn", "*Shona"  },
    { "so", "*Somali" },
    { "sq", "*Albanian" },
    { "sr", "*Serbian" },
    { "ss", "*Siswati" },
    { "st", "*Sesotho" },
    { "su", "*Sundanese" },
    { "sv", "Svenska" },
    { "sw", "*Swahili" },
    { "ta", "*Tamil" },
    { "te", "*Telugu" },
    { "tg", "*Tajik" },
    { "th", "*Thai" },
    { "ti", "*Tigrinya" },
    { "tk", "*Turkmen" },
    { "tl", "*Tagalog" },
    { "tn", "*Setswana" },
    { "to", "*Tonga" },
    { "tr", "*Turkish" },
    { "ts", "*Tsonga" },
    { "tt", "*Tatar" },
    { "tw", "*Twi" },
    { "ug", "*Uighur" },
    { "uk", "*Ukrainian" },
    { "ur", "*Urdu" },
    { "uz", "*Uzbek" },
    { "vi", "*Vietnamese" },
    { "vo", "*Volapuk" },
    { "wo", "*Wolof" },
    { "xh", "*Xhosa" },
    { "yi", "*Yiddish" },                                     /* formerly ji */
    { "yo", "*Yoruba" },
    { "za", "*Zhuang" },
    { "zh", "*Chinese" },
    { "zu", "*Zulu" },
    { "\0", "" }
};
241

242 243 244
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
245
static int  DVDProbe    ( probedata_t *p_data );
246
static int  DVDRead     ( struct input_thread_s *, data_packet_t ** );
Sam Hocevar's avatar
 
Sam Hocevar committed
247 248
static void DVDInit     ( struct input_thread_s * );
static void DVDEnd      ( struct input_thread_s * );
249
static void DVDSeek     ( struct input_thread_s *, off_t );
250
static int  DVDSetArea  ( struct input_thread_s *, struct input_area_s * );
Sam Hocevar's avatar
 
Sam Hocevar committed
251
static int  DVDRewind   ( struct input_thread_s * );
252

Sam Hocevar's avatar
 
Sam Hocevar committed
253 254 255 256
/*****************************************************************************
 * Functions exported as capabilities. They are declared as static so that
 * we don't pollute the namespace too much.
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
257
void _M( input_getfunctions )( function_list_t * p_function_list )
Sam Hocevar's avatar
 
Sam Hocevar committed
258 259 260 261
{
#define input p_function_list->functions.input
    p_function_list->pf_probe = DVDProbe;
    input.pf_init             = DVDInit;
262 263
    input.pf_open             = input_FileOpen;
    input.pf_close            = input_FileClose;
Sam Hocevar's avatar
 
Sam Hocevar committed
264 265
    input.pf_end              = DVDEnd;
    input.pf_read             = DVDRead;
Stéphane Borel's avatar
 
Stéphane Borel committed
266
    input.pf_set_area         = DVDSetArea;
Sam Hocevar's avatar
 
Sam Hocevar committed
267
    input.pf_demux            = input_DemuxPS;
268 269 270 271
    input.pf_new_packet       = DVDNewPacket;
    input.pf_new_pes          = DVDNewPES;
    input.pf_delete_packet    = DVDDeletePacket;
    input.pf_delete_pes       = DVDDeletePES;
272 273
    input.pf_rewind           = DVDRewind;
    input.pf_seek             = DVDSeek;
Sam Hocevar's avatar
 
Sam Hocevar committed
274 275 276
#undef input
}

277 278 279 280 281 282 283
/*
 * Local tools to decode some data in ifo
 */

/*****************************************************************************
 * Language: gives the long language name from the two-letters ISO-639 code
 *****************************************************************************/
284
static char * Language( u16 i_code )
285 286 287
{
    int     i = 0;

288 289
    while( memcmp( lang_tbl[i].p_code, &i_code, 2 ) &&
           lang_tbl[i].p_lang_long[0] )
290 291 292 293 294 295 296
    {
        i++;
    }

    return lang_tbl[i].p_lang_long;
}

297 298 299 300 301
/*
 * Data reading functions
 */

/*****************************************************************************
302
 * DVDProbe: verifies that the stream is a PS stream
303
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
304
static int DVDProbe( probedata_t *p_data )
305
{
Sam Hocevar's avatar
 
Sam Hocevar committed
306 307 308 309 310 311
    input_thread_t * p_input = (input_thread_t *)p_data;

    char * psz_name = p_input->p_source;
    int i_handle;
    int i_score = 5;

Sam Hocevar's avatar
 
Sam Hocevar committed
312 313
    if( TestMethod( INPUT_METHOD_VAR, "dvd" ) )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
314
#ifdef HAVE_CSS
Sam Hocevar's avatar
 
Sam Hocevar committed
315
        return( 999 );
Sam Hocevar's avatar
 
Sam Hocevar committed
316 317 318
#else /* HAVE_CSS */
        return( 998 );
#endif /* HAVE_CSS */
Sam Hocevar's avatar
 
Sam Hocevar committed
319 320
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
321 322 323
    if( ( strlen(psz_name) > 4 ) && !strncasecmp( psz_name, "dvd:", 4 ) )
    {
        /* If the user specified "dvd:" then it's probably a DVD */
Sam Hocevar's avatar
 
Sam Hocevar committed
324
#ifdef HAVE_CSS
Sam Hocevar's avatar
 
Sam Hocevar committed
325
        i_score = 100;
Sam Hocevar's avatar
 
Sam Hocevar committed
326 327 328
#else /* HAVE_CSS */
        i_score = 90;
#endif /* HAVE_CSS */
Sam Hocevar's avatar
 
Sam Hocevar committed
329 330 331 332 333 334 335 336 337 338 339
        psz_name += 4;
    }

    i_handle = open( psz_name, 0 );
    if( i_handle == -1 )
    {
        return( 0 );
    }
    close( i_handle );

    return( i_score );
Sam Hocevar's avatar
 
Sam Hocevar committed
340 341
}

342
/*****************************************************************************
343
 * DVDFindCell: adjust the title cell index with the program cell
344
 *****************************************************************************/
345
static int DVDFindCell( thread_dvd_data_t * p_dvd )
346
{
347 348
    int                 i_cell;
    int                 i_index;
349

350 351 352
#define title \
        p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_program_chain-1].title
#define cell  p_dvd->p_ifo->vts.cell_inf
353

354 355
    i_cell = p_dvd->i_cell;
    i_index = p_dvd->i_prg_cell;
356

357 358 359 360 361
    while( ( ( title.p_cell_pos[i_index].i_vob_id !=
                   cell.p_cell_map[i_cell].i_vob_id ) ||
      ( title.p_cell_pos[i_index].i_cell_id !=
                   cell.p_cell_map[i_cell].i_cell_id ) ) &&
           ( i_cell < cell.i_cell_nb ) )
362 363 364
    {
        i_cell++;
    }
365

366
    if( i_cell == cell.i_cell_nb )
367
    {
Stéphane Borel's avatar
Stéphane Borel committed
368
        intf_ErrMsg( "dvd error: can't find cell" );
369 370 371 372 373 374 375
        return -1;
    }
    else
    {
        p_dvd->i_cell = i_cell;
        return 0;
    }
376 377
#undef title
#undef cell
378
}
379

380 381 382 383 384 385
/*****************************************************************************
 * DVDFindSector: find cell index in adress map from index in
 * information table program map and give corresponding sectors.
 *****************************************************************************/
static int DVDFindSector( thread_dvd_data_t * p_dvd )
{
386 387
#define title \
        p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_program_chain-1].title
388

389
    if( p_dvd->i_sector > title.p_cell_play[p_dvd->i_prg_cell].i_end_sector )
390 391 392 393 394 395
    {
        p_dvd->i_prg_cell++;
    }

    if( DVDFindCell( p_dvd ) < 0 )
    {
Stéphane Borel's avatar
Stéphane Borel committed
396
        intf_ErrMsg( "dvd error: can't find sector" );
397 398
        return -1;
    }
399 400 401

    /* Find start and end sectors of new cell */
    p_dvd->i_sector = MAX(
402 403
         p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_start_sector,
         title.p_cell_play[p_dvd->i_prg_cell].i_start_sector );
404
    p_dvd->i_end_sector = MIN(
405 406
         p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector,
         title.p_cell_play[p_dvd->i_prg_cell].i_end_sector );
407

408 409
//intf_WarnMsg( 3, "cell: %d sector1: 0x%x end1: 0x%x\nindex: %d sector2: 0x%x end2: 0x%x", p_dvd->i_cell, p_dvd->p_ifo->p_vts->c_adt.p_cell_inf[p_dvd->i_cell].i_ssector, p_dvd->p_ifo->p_vts->c_adt.p_cell_inf[p_dvd->i_cell].i_esector, p_dvd->i_prg_cell, p_pgc->p_cell_play_inf[p_dvd->i_prg_cell].i_entry_sector, p_pgc->p_cell_play_inf[p_dvd->i_prg_cell].i_lsector );
#undef title
410 411

    return 0;
412 413
}

414
/*****************************************************************************
415
 * DVDChapterSelect: find the cell corresponding to requested chapter
416
 * When called to find chapter 1, also sets title size and end.
417
 *****************************************************************************/
418
static int DVDChapterSelect( thread_dvd_data_t * p_dvd, int i_chapter )
419
{
420 421
#define title \
        p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_program_chain-1].title
Sam Hocevar's avatar
 
Sam Hocevar committed
422

423
    /* Find cell index in Program chain for current chapter */
424
    p_dvd->i_prg_cell = title.chapter_map.pi_start_cell[i_chapter-1] - 1;
425
    p_dvd->i_cell = 0;
Stéphane Borel's avatar
Stéphane Borel committed
426
    p_dvd->i_sector = 0;
427

428
    /* Search for cell_index in cell adress_table and initialize start sector */
429
    DVDFindSector( p_dvd );
430

431 432 433
    /* start is : beginning of vts vobs + offset to vob x */
    p_dvd->i_start = p_dvd->i_title_start +
                     DVD_LB_SIZE * (off_t)( p_dvd->i_sector );
Stéphane Borel's avatar
 
Stéphane Borel committed
434

435 436
    /* Position the fd pointer on the right address */
    p_dvd->i_start = lseek( p_dvd->i_fd, p_dvd->i_start, SEEK_SET );
437

438
    p_dvd->i_chapter = i_chapter;
439
#undef title
440 441
    return 0;
}
Stéphane Borel's avatar
 
Stéphane Borel committed
442

443 444 445 446 447 448 449 450 451
/*****************************************************************************
 * DVDSetArea: initialize input data for title x, chapter y.
 * It should be called for each user navigation request, and to change
 * audio or sub-picture streams.
 * ---
 * Take care that i_title starts from 0 (vmg) and i_chapter start from 1.
 * i_audio, i_spu start from 1 ; 0 means off.
 * A negative value for an argument means it does not change
 *****************************************************************************/
452
static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
453
{
454
    thread_dvd_data_t *  p_dvd;
455
    es_descriptor_t *    p_es;
456 457
    int                  i_audio;
    int                  i_spu;
458 459 460 461 462 463
    u16                  i_id;
    u8                   i_ac3;
    u8                   i_mpeg;
    u8                   i_sub_pic;
    u8                   i;
    boolean_t            b_last;
464

465
    p_dvd = (thread_dvd_data_t*)p_input->p_plugin_data;
Stéphane Borel's avatar
 
Stéphane Borel committed
466 467 468

    vlc_mutex_lock( &p_input->stream.stream_lock );

469
    if( p_area != p_input->stream.p_selected_area )
Stéphane Borel's avatar
 
Stéphane Borel committed
470
    {
471

472 473 474 475
        /*
         *  We have to load all title information
         */
        /* Change the default area */
476 477
        p_input->stream.p_selected_area =
                    p_input->stream.pp_areas[p_area->i_id];
478

479
        /* title number: it is not vts nb! */
480
        p_dvd->i_title = p_area->i_id;
481 482 483 484 485
        p_dvd->p_ifo->i_title = p_dvd->i_title;

        /* ifo vts */
        IfoTitleSet( p_dvd->p_ifo );
        intf_WarnMsg( 2, "ifo info: vts initialized" );
486

487 488
#define vmg p_dvd->p_ifo->vmg
#define vts p_dvd->p_ifo->vts
489
        /* title position inside the selected vts */
490
        p_dvd->i_vts_title =
491 492 493
                    vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_num;
        p_dvd->i_program_chain =
          vts.title_inf.p_title_start[p_dvd->i_vts_title-1].i_program_chain_num;
494 495

        /* css title key for current vts */
496
        if( p_dvd->b_encrypted )
Stéphane Borel's avatar
 
Stéphane Borel committed
497
        {
498
            p_dvd->p_css->i_title =
499
                    vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_set_num;
500
            p_dvd->p_css->i_title_pos =
501 502
                    vts.i_pos +
                    vts.manager_inf.i_title_vob_start_sector * DVD_LB_SIZE;
503
            CSSGetKey( p_dvd->p_css );
504
            intf_WarnMsg( 2, "css info: vts key initialized" );
Stéphane Borel's avatar
 
Stéphane Borel committed
505
        }
506 507 508 509
    
        /*
         * Set selected title start and size
         */
510 511
        
        /* title set offset */
512 513
        p_dvd->i_title_start = vts.i_pos + DVD_LB_SIZE *
                      (off_t)( vts.manager_inf.i_title_vob_start_sector );
514 515

        /* last video cell */
516
        p_dvd->i_cell = 0;
517
        p_dvd->i_prg_cell = -1 +
518
            vts.title_unit.p_title[p_dvd->i_program_chain-1].title.i_cell_nb;
519
        DVDFindCell( p_dvd );
520

521
        /* temporary hack to fix size in some dvds */
522
        if( p_dvd->i_cell >= vts.cell_inf.i_cell_nb )
523
        {
524
            p_dvd->i_cell = vts.cell_inf.i_cell_nb - 1;
525 526
        }

527
        p_dvd->i_sector = 0;
528
        p_dvd->i_size = DVD_LB_SIZE *
529
          (off_t)( vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector );
530 531 532 533 534

        DVDChapterSelect( p_dvd, 1 );

        p_dvd->i_size -= (off_t)( p_dvd->i_sector + 1 ) *DVD_LB_SIZE;

535
        intf_WarnMsg( 2, "dvd info: title: %d", p_dvd->i_title );
536 537
        intf_WarnMsg( 2, "dvd info: vobstart at: %lld", p_dvd->i_start );
        intf_WarnMsg( 2, "dvd info: stream size: %lld", p_dvd->i_size );
538
        intf_WarnMsg( 2, "dvd info: number of chapters: %d",
539
                   vmg.title_inf.p_attr[p_dvd->i_title-1].i_chapter_nb );
540

541
        /* Area definition */
542 543
        p_input->stream.p_selected_area->i_start = p_dvd->i_start;
        p_input->stream.p_selected_area->i_size = p_dvd->i_size;
544 545 546 547 548 549

        /*
         * Destroy obsolete ES by reinitializing program 0
         * and find all ES in title with ifo data
         */
        if( p_input->stream.pp_programs != NULL )
Stéphane Borel's avatar
 
Stéphane Borel committed
550
        {
551 552 553 554 555 556 557 558
            /* We don't use input_EndStream here since
             * we keep area structures */

            for( i = 0 ; i < p_input->stream.i_selected_es_number ; i++ )
            {
                input_UnselectES( p_input, p_input->stream.pp_selected_es[i] );
            }

559
            input_DelProgram( p_input, p_input->stream.pp_programs[0] );
560 561 562

            p_input->stream.pp_selected_es = NULL;
            p_input->stream.i_selected_es_number = 0;
Stéphane Borel's avatar
 
Stéphane Borel committed
563 564
        }

565
        input_AddProgram( p_input, 0, sizeof( stream_ps_data_t ) );
Stéphane Borel's avatar
 
Stéphane Borel committed
566

Stéphane Borel's avatar
Stéphane Borel committed
567 568 569 570
        /* No PSM to read in DVD mode, we already have all information */
        p_input->stream.pp_programs[0]->b_is_ok = 1;
        p_input->stream.pp_programs[0]->i_synchro_state = SYNCHRO_START;

571
        p_es = NULL;
572

573 574 575 576
        /* ES 0 -> video MPEG2 */
        p_es = input_AddES( p_input, p_input->stream.pp_programs[0], 0xe0, 0 );
        p_es->i_stream_id = 0xe0;
        p_es->i_type = MPEG2_VIDEO_ES;
Stéphane Borel's avatar
Stéphane Borel committed
577
        p_es->i_cat = VIDEO_ES;
578
        input_SelectES( p_input, p_es );
579
        intf_WarnMsg( 1, "dvd info: video MPEG2 stream" );
580

581
        /* Audio ES, in the order they appear in .ifo */
582
            
583
        i_ac3 = 0x7f;
584
        i_mpeg = 0xc0;
Stéphane Borel's avatar
 
Stéphane Borel committed
585

586
        for( i = 1 ; i <= vts.manager_inf.i_audio_nb ; i++ )
587
        {
588

589
#ifdef DEBUG
Stéphane Borel's avatar
Stéphane Borel committed
590
        intf_WarnMsg( 1, "Audio %d: %x %x %x %x %x %x %x %x %x %x %x %x", i,
591 592 593 594 595 596
            vts.manager_inf.p_audio_attr[i-1].i_num_channels,
            vts.manager_inf.p_audio_attr[i-1].i_coding_mode,
            vts.manager_inf.p_audio_attr[i-1].i_multichannel_extension,
            vts.manager_inf.p_audio_attr[i-1].i_type,
            vts.manager_inf.p_audio_attr[i-1].i_appl_mode,
            vts.manager_inf.p_audio_attr[i-1].i_foo,
Stéphane Borel's avatar
Stéphane Borel committed
597
            vts.manager_inf.p_audio_attr[i-1].i_test,
598 599 600 601 602
            vts.manager_inf.p_audio_attr[i-1].i_bar,
            vts.manager_inf.p_audio_attr[i-1].i_quantization,
            vts.manager_inf.p_audio_attr[i-1].i_sample_freq,
            vts.manager_inf.p_audio_attr[i-1].i_lang_code,
            vts.manager_inf.p_audio_attr[i-1].i_caption );
603
#endif
604

605
            switch( vts.manager_inf.p_audio_attr[i-1].i_coding_mode )
606 607
            {
            case 0x00:              /* AC3 */
608
                i_id = ( ( i_ac3 + i ) << 8 ) | 0xbd;
609 610 611 612 613
                p_es = input_AddES( p_input,
                                    p_input->stream.pp_programs[0], i_id, 0 );
                p_es->i_stream_id = 0xbd;
                p_es->i_type = AC3_AUDIO_ES;
                p_es->b_audio = 1;
Stéphane Borel's avatar
Stéphane Borel committed
614
                p_es->i_cat = AUDIO_ES;
615
                strcpy( p_es->psz_desc, Language( hton16(
616
                    vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) ); 
Stéphane Borel's avatar
Stéphane Borel committed
617
                strcat( p_es->psz_desc, " (ac3)" );
618 619 620

                intf_WarnMsg( 1, "dvd info: audio stream %d %s\t(0x%x)",
                              i, p_es->psz_desc, i_id );
621

622 623 624 625 626 627 628 629 630
                break;
            case 0x02:
            case 0x03:              /* MPEG audio */
                i_id = 0xbf + i;
                p_es = input_AddES( p_input,
                                    p_input->stream.pp_programs[0], i_id, 0 );
                p_es->i_stream_id = i_id;
                p_es->i_type = MPEG2_AUDIO_ES;
                p_es->b_audio = 1;
Stéphane Borel's avatar
Stéphane Borel committed
631
                p_es->i_cat = AUDIO_ES;
632
                strcpy( p_es->psz_desc, Language( hton16(
633
                    vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) ); 
Stéphane Borel's avatar
Stéphane Borel committed
634
                strcat( p_es->psz_desc, " (mpeg)" );
635 636 637

                intf_WarnMsg( 1, "dvd info: audio stream %d %s\t(0x%x)",
                              i, p_es->psz_desc, i_id );
638

639
                break;
640 641
            case 0x04:              /* LPCM */
                i_id = 0;
642
                intf_ErrMsg( "dvd warning: LPCM audio not handled yet" );
643 644 645
                break;
            case 0x06:              /* DTS */
                i_id = 0;
646
                i_ac3--;
647
                intf_ErrMsg( "dvd warning: DTS audio not handled yet" );
648
                break;
649 650
            default:
                i_id = 0;
651
                intf_ErrMsg( "dvd warning: unknown audio type %.2x",
652
                         vts.manager_inf.p_audio_attr[i-1].i_coding_mode );
653
            }
654 655 656 657
        
        }
    
        /* Sub Picture ES */
658
           
659 660
        b_last = 0;
        i_sub_pic = 0x20;
661
        for( i = 1 ; i <= vts.manager_inf.i_spu_nb; i++ )
662 663
        {
            if( !b_last )
664
            {
665 666 667 668 669
                i_id = ( i_sub_pic++ << 8 ) | 0xbd;
                p_es = input_AddES( p_input,
                                    p_input->stream.pp_programs[0], i_id, 0 );
                p_es->i_stream_id = 0xbd;
                p_es->i_type = DVD_SPU_ES;
Stéphane Borel's avatar
Stéphane Borel committed
670
                p_es->i_cat = SPU_ES;
671
                strcpy( p_es->psz_desc, Language( hton16(
672
                    vts.manager_inf.p_spu_attr[i-1].i_lang_code ) ) ); 
673
                intf_WarnMsg( 1, "dvd info: spu stream %d %s\t(0x%x)",
674 675 676 677
                              i, p_es->psz_desc, i_id );
    
                /* The before the last spu has a 0x0 prefix */
                b_last =
678
                    ( vts.manager_inf.p_spu_attr[i].i_prefix == 0 ); 
679
            }
680 681
        }

682 683 684 685 686 687 688
        /* For audio: first one if none or a not existing one specified */
        i_audio = main_GetIntVariable( INPUT_CHANNEL_VAR, 1 );
        if( i_audio < 0 || i_audio > vts.manager_inf.i_audio_nb )
        {
            main_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
            i_audio = 1;
        }
Stéphane Borel's avatar
Stéphane Borel committed
689
        if( i_audio > 0 && vts.manager_inf.i_audio_nb > 0 )
690 691 692 693 694 695 696 697 698 699 700
        {
            input_SelectES( p_input, p_input->stream.pp_es[i_audio] );
        }
    
        /* for spu, default is none */
        i_spu = main_GetIntVariable( INPUT_SUBTITLE_VAR, 0 );
        if( i_spu < 0 || i_spu > vts.manager_inf.i_spu_nb )
        {
            main_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
            i_spu = 0;
        }
Stéphane Borel's avatar
Stéphane Borel committed
701
        if( i_spu > 0 && vts.manager_inf.i_spu_nb > 0 )
702 703 704 705
        {
            i_spu += vts.manager_inf.i_audio_nb;
            input_SelectES( p_input, p_input->stream.pp_es[i_spu] );
        }
706
    } /* i_title >= 0 */
707
    else
708
    {
709
        p_area = p_input->stream.p_selected_area;
710
    }
711 712 713 714 715

    /*
     * Chapter selection
     */

716 717
    if( ( p_area->i_part > 0 ) &&
        ( p_area->i_part <= p_area->i_part_nb ) )
718
    {
719
        DVDChapterSelect( p_dvd, p_area->i_part );
Sam Hocevar's avatar
 
Sam Hocevar committed
720

721
        p_input->stream.p_selected_area->i_tell = p_dvd->i_start -
722
                                                  p_area->i_start;
723
        p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
724

725 726
        intf_WarnMsg( 2, "dvd info: chapter %d start at: %lld",
                                    p_area->i_part, p_area->i_tell );
Sam Hocevar's avatar
 
Sam Hocevar committed
727
    }
728 729

    vlc_mutex_unlock( &p_input->stream.stream_lock );
730 731
#undef vts
#undef vmg
732 733 734 735 736 737 738 739
    return 0;
}

/*****************************************************************************
 * DVDInit: initializes DVD structures
 *****************************************************************************/
static void DVDInit( input_thread_t * p_input )
{
740
    thread_dvd_data_t *  p_dvd;
741 742
    int                  i_title;
    int                  i_chapter;
Stéphane Borel's avatar
 
Stéphane Borel committed
743
    int                  i;
744

745 746 747
    /* I don't want DVDs to start playing immediately */
//    p_input->stream.i_new_status = PAUSE_S;

Sam Hocevar's avatar
 
Sam Hocevar committed
748 749
    p_dvd = malloc( sizeof(thread_dvd_data_t) );
    if( p_dvd == NULL )
750
    {
751
        intf_ErrMsg( "dvd error: out of memory" );
752 753 754 755
        p_input->b_error = 1;
        return;
    }

756
    p_input->p_plugin_data = (void *)p_dvd;
757 758
    p_input->p_method_data = NULL;

759
    p_dvd->i_fd = p_input->i_handle;
760

761 762 763 764 765
    /* reading several block once seems to cause lock-up
     * when using input_ToggleES
     * who wrote thez damn buggy piece of shit ??? --stef */
    p_dvd->i_block_once = 1;//32;
    p_input->i_read_once = 4;//128;
766

Sam Hocevar's avatar
 
Sam Hocevar committed
767 768 769 770 771 772 773 774 775 776 777
    i = CSSTest( p_input->i_handle );

    if( i < 0 )
    {
        intf_ErrMsg( "css error: could not get copyright bit" );
        free( p_dvd );
        p_input->b_error = 1;
        return;
    }

    p_dvd->b_encrypted = i;
778 779 780 781

    lseek( p_input->i_handle, 0, SEEK_SET );

    /* Reading structures initialisation */
782
    p_input->p_method_data =
783
        DVDNetlistInit( 2048, 8192, 2048, DVD_LB_SIZE, p_dvd->i_block_once );
784
    intf_WarnMsg( 2, "dvd info: netlist initialized" );
785 786

    /* Ifo initialisation */
787 788
    if( IfoInit( &p_dvd->p_ifo, p_input->i_handle ) < 0 )
    {
789
        intf_ErrMsg( "dvd error: fatal failure in IFO" );
Sam Hocevar's avatar
 
Sam Hocevar committed
790 791 792
        free( p_dvd );
        p_input->b_error = 1;
        return;
793
    }
794 795

    /* CSS initialisation */
796
    if( p_dvd->b_encrypted )
797
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
798
        p_dvd->p_css = malloc( sizeof(css_t) );
799
        if( p_dvd->p_css == NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
800
        {
801
            intf_ErrMsg( "dvd error: couldn't create CSS structure" );
Sam Hocevar's avatar
 
Sam Hocevar committed
802 803 804 805 806 807 808 809 810
            free( p_dvd );
            p_input->b_error = 1;
            return;
        }

        p_dvd->p_css->i_fd = p_input->i_handle;
        p_dvd->p_css->i_agid = 0;

        if( CSSInit( p_dvd->p_css ) )
811
        {
812
            intf_ErrMsg( "dvd error: fatal failure in CSS" );
Sam Hocevar's avatar
 
Sam Hocevar committed
813
            free( p_dvd->p_css );
814
            free( p_dvd );
815
            p_input->b_error = 1;
816 817
            return;
        }
818

819
        intf_WarnMsg( 2, "dvd info: CSS initialized" );
820 821 822 823 824
    }

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

Stéphane Borel's avatar
 
Stéphane Borel committed
825
    /* Set stream and area data */
826
    vlc_mutex_lock( &p_input->stream.stream_lock );
Stéphane Borel's avatar
 
Stéphane Borel committed
827

828 829
#define title_inf p_dvd->p_ifo->vmg.title_inf
    intf_WarnMsg( 2, "dvd info: number of titles: %d", title_inf.i_title_nb );
830

Stéphane Borel's avatar
 
Stéphane Borel committed
831 832
#define area p_input->stream.pp_areas
    /* We start from 1 here since area 0 is reserved for video_ts.vob */
833
    for( i = 1 ; i <= title_inf.i_title_nb ; i++ )
Stéphane Borel's avatar
 
Stéphane Borel committed
834 835 836
    {
        input_AddArea( p_input );

837
        /* Titles are Program Chains */
Stéphane Borel's avatar
 
Stéphane Borel committed
838 839 840 841 842 843 844 845
        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;

846
        /* Number of chapters */
847
        area[i]->i_part_nb = title_inf.p_attr[i-1].i_chapter_nb;
Stéphane Borel's avatar
 
Stéphane Borel committed
848
        area[i]->i_part = 1;
849

Stéphane Borel's avatar
 
Stéphane Borel committed
850
        /* Offset to vts_i_0.ifo */
851 852
        area[i]->i_plugin_data = p_dvd->p_ifo->i_off +
                       ( title_inf.p_attr[i-1].i_start_sector * DVD_LB_SIZE );
Stéphane Borel's avatar
 
Stéphane Borel committed
853 854 855
    }   
#undef area

856 857
    vlc_mutex_unlock( &p_input->stream.stream_lock );

858
    /* Get requested title - if none try the first title */
859
    i_title = main_GetIntVariable( INPUT_TITLE_VAR, 1 );
860
    if( i_title <= 0 || i_title > title_inf.i_title_nb )
861
    {
862
        i_title = 1;
863
    }
864
#undef title_inf
865 866 867 868 869 870 871
    /* Get requested chapter - if none defaults to first one */
    i_chapter = main_GetIntVariable( INPUT_CHAPTER_VAR, 1 );
    if( i_chapter <= 0 )
    {
        i_chapter = 1;
    }

872 873
    p_input->stream.pp_areas[i_title]->i_part = i_chapter;

874 875
    /* set title, chapter, audio and subpic */
    DVDSetArea( p_input, p_input->stream.pp_areas[i_title] );
876

877
    return;
Sam Hocevar's avatar
 
Sam Hocevar committed
878 879 880 881 882 883
}

/*****************************************************************************
 * DVDEnd: frees unused data
 *****************************************************************************/
static void DVDEnd( input_thread_t * p_input )
884
{
885
    thread_dvd_data_t *     p_dvd;
886 887
    dvd_netlist_t *         p_netlist;

888
    p_dvd = (thread_dvd_data_t*)p_input->p_plugin_data;
889 890
    p_netlist = (dvd_netlist_t *)p_input->p_method_data;

891 892
    if( p_dvd->b_encrypted )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
893
        free( p_dvd->p_css );
894 895 896
    }

    IfoEnd( p_dvd->p_ifo );
897
    free( p_dvd );
898
    DVDNetlistEnd( p_netlist );
899 900 901
}

/*****************************************************************************
902
 * DVDRead: reads data packets into the netlist.
903 904 905 906
 *****************************************************************************
 * Returns -1 in case of error, 0 if everything went well, and 1 in case of
 * EOF.
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
907
static int DVDRead( input_thread_t * p_input,