input_dvd.c 39 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
Henri Fallon's avatar
 
Henri Fallon committed
13
 * $Id: input_dvd.c,v 1.44 2001/04/13 01:49:22 henri 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 367 368 369 370
intf_WarnMsg( 1, "FindCell: i_cell %d i_index %d found %d nb %d",
                    p_dvd->i_cell,
                    p_dvd->i_prg_cell,
                    i_cell,
                    cell.i_cell_nb );
371
*/
372
    if( i_cell == cell.i_cell_nb )
373
    {
Stéphane Borel's avatar
Stéphane Borel committed
374
        intf_ErrMsg( "dvd error: can't find cell" );
375 376 377 378 379 380 381
        return -1;
    }
    else
    {
        p_dvd->i_cell = i_cell;
        return 0;
    }
382 383
#undef title
#undef cell
384
}
385

386 387 388 389 390 391
/*****************************************************************************
 * 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 )
{
392 393
#define title \
        p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_program_chain-1].title
394

395
    if( p_dvd->i_sector > title.p_cell_play[p_dvd->i_prg_cell].i_end_sector )
396 397 398 399 400 401
    {
        p_dvd->i_prg_cell++;
    }

    if( DVDFindCell( p_dvd ) < 0 )
    {
Stéphane Borel's avatar
Stéphane Borel committed
402
        intf_ErrMsg( "dvd error: can't find sector" );
403 404
        return -1;
    }
405 406 407

    /* Find start and end sectors of new cell */
    p_dvd->i_sector = MAX(
408 409
         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 );
410
    p_dvd->i_end_sector = MIN(
411 412
         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 );
413

414
/*    intf_WarnMsg( 1, "cell: %d sector1: 0x%x end1: 0x%x\n"
415 416 417 418 419 420 421
                     "index: %d sector2: 0x%x end2: 0x%x", 
        p_dvd->i_cell,
        p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_start_sector,
        p_dvd->p_ifo->vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector,
        p_dvd->i_prg_cell,
        title.p_cell_play[p_dvd->i_prg_cell].i_start_sector,
        title.p_cell_play[p_dvd->i_prg_cell].i_end_sector );
422
*/
423
#undef title
424 425

    return 0;
426 427
}

428
/*****************************************************************************
429
 * DVDChapterSelect: find the cell corresponding to requested chapter
430
 * When called to find chapter 1, also sets title size and end.
431
 *****************************************************************************/
432
static int DVDChapterSelect( thread_dvd_data_t * p_dvd, int i_chapter )
433
{
434 435
#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
436

437
    /* Find cell index in Program chain for current chapter */
438
    p_dvd->i_prg_cell = title.chapter_map.pi_start_cell[i_chapter-1] - 1;
439
    p_dvd->i_cell = 0;
Stéphane Borel's avatar
Stéphane Borel committed
440
    p_dvd->i_sector = 0;
441

442
    /* Search for cell_index in cell adress_table and initialize start sector */
443 444 445 446 447
    if( DVDFindSector( p_dvd ) < 0 )
    {
        intf_ErrMsg( "dvd error: can't select chapter" );
        return -1;
    }
448

449 450 451
    /* 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
452

453 454
    /* Position the fd pointer on the right address */
    p_dvd->i_start = lseek( p_dvd->i_fd, p_dvd->i_start, SEEK_SET );
455

456
    p_dvd->i_chapter = i_chapter;
457
#undef title
458 459
    return 0;
}
Stéphane Borel's avatar
 
Stéphane Borel committed
460

461 462 463 464 465 466 467 468 469
/*****************************************************************************
 * 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
 *****************************************************************************/
470
static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
471
{
472
    thread_dvd_data_t *  p_dvd;
473
    es_descriptor_t *    p_es;
474 475
    int                  i_audio;
    int                  i_spu;
476 477 478 479 480
    u16                  i_id;
    u8                   i_ac3;
    u8                   i_mpeg;
    u8                   i_sub_pic;
    u8                   i;
481
    int                  j;
482
    boolean_t            b_last;
483

484
    p_dvd = (thread_dvd_data_t*)p_input->p_plugin_data;
Stéphane Borel's avatar
 
Stéphane Borel committed
485 486 487

    vlc_mutex_lock( &p_input->stream.stream_lock );

488
    if( p_area != p_input->stream.p_selected_area )
Stéphane Borel's avatar
 
Stéphane Borel committed
489
    {
490

491 492 493 494
        /*
         *  We have to load all title information
         */
        /* Change the default area */
495 496
        p_input->stream.p_selected_area =
                    p_input->stream.pp_areas[p_area->i_id];
497

498 499
        /* title number: it is not vts nb!,
         * it is what appears in the interface list */
500
        p_dvd->i_title = p_area->i_id;
501 502 503
        p_dvd->p_ifo->i_title = p_dvd->i_title;

        /* ifo vts */
504 505 506 507 508 509 510
        if( IfoTitleSet( p_dvd->p_ifo ) < 0 )
        {
            intf_ErrMsg( "dvd error: fatal error in vts ifo" );
            free( p_dvd );
            p_input->b_error = 1;
            return -1;
        }
511

512 513
#define vmg p_dvd->p_ifo->vmg
#define vts p_dvd->p_ifo->vts
514
        /* title position inside the selected vts */
515
        p_dvd->i_vts_title =
516 517 518
                    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;
519

520
/*        intf_WarnMsg( 1, "dvd: title %d vts_title %d pgc %d",
521 522 523
                        p_dvd->i_title,
                        p_dvd->i_vts_title,
                        p_dvd->i_program_chain );
524
*/
525
        /* css title key for current vts */
526
        if( p_dvd->b_encrypted )
Stéphane Borel's avatar
 
Stéphane Borel committed
527
        {
528
            /* this one is vts number */
529
            p_dvd->p_css->i_title =
530
                    vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_set_num;
531
            p_dvd->p_css->i_title_pos =
532 533
                    vts.i_pos +
                    vts.manager_inf.i_title_vob_start_sector * DVD_LB_SIZE;
534

Sam Hocevar's avatar
 
Sam Hocevar committed
535
            j = CSSGetKey( p_input->i_handle, p_dvd->p_css );
536 537 538 539 540 541 542 543 544 545 546 547 548 549
            if( j < 0 )
            {
                intf_ErrMsg( "dvd error: fatal error in vts css key" );
                free( p_dvd );
                p_input->b_error = 1;
                return -1;
            }
            else if( j > 0 )
            {
                intf_ErrMsg( "dvd error: css decryption unavailable" );
                free( p_dvd );
                p_input->b_error = 1;
                return -1;
            }
Stéphane Borel's avatar
 
Stéphane Borel committed
550
        }
551 552 553 554
    
        /*
         * Set selected title start and size
         */
555 556
        
        /* title set offset */
557 558
        p_dvd->i_title_start = vts.i_pos + DVD_LB_SIZE *
                      (off_t)( vts.manager_inf.i_title_vob_start_sector );
559 560

        /* last video cell */
561
        p_dvd->i_cell = 0;
562
        p_dvd->i_prg_cell = -1 +
563
            vts.title_unit.p_title[p_dvd->i_program_chain-1].title.i_cell_nb;
564

565 566 567 568 569 570
        if( DVDFindCell( p_dvd ) < 0 )
        {
            intf_ErrMsg( "dvd error: can't find title end" );
            p_input->b_error = 1;
            return -1;
        }
571

572
        /* temporary hack to fix size in some dvds */
573
        if( p_dvd->i_cell >= vts.cell_inf.i_cell_nb )
574
        {
575
            p_dvd->i_cell = vts.cell_inf.i_cell_nb - 1;
576 577
        }

578
        p_dvd->i_sector = 0;
579
        p_dvd->i_size = DVD_LB_SIZE *
580
          (off_t)( vts.cell_inf.p_cell_map[p_dvd->i_cell].i_end_sector );
581

582 583 584 585 586 587
        if( DVDChapterSelect( p_dvd, 1 ) < 0 )
        {
            intf_ErrMsg( "dvd error: can't find first chapter" );
            p_input->b_error = 1;
            return -1;
        }
588 589 590

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

591
        intf_WarnMsg( 2, "dvd info: title: %d", p_dvd->i_title );
592 593
        intf_WarnMsg( 2, "dvd info: vobstart at: %lld", p_dvd->i_start );
        intf_WarnMsg( 2, "dvd info: stream size: %lld", p_dvd->i_size );
594
        intf_WarnMsg( 2, "dvd info: number of chapters: %d",
595
                   vmg.title_inf.p_attr[p_dvd->i_title-1].i_chapter_nb );
596

597
        /* Area definition */
598 599
        p_input->stream.p_selected_area->i_start = p_dvd->i_start;
        p_input->stream.p_selected_area->i_size = p_dvd->i_size;
600 601 602 603 604 605

        /*
         * 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
606
        {
607 608 609 610 611 612 613 614
            /* 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] );
            }

615
            input_DelProgram( p_input, p_input->stream.pp_programs[0] );
616 617 618

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

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

Stéphane Borel's avatar
Stéphane Borel committed
623 624 625 626
        /* 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;

627
        p_es = NULL;
628

629 630 631 632
        /* 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
633
        p_es->i_cat = VIDEO_ES;
634 635 636 637 638
        intf_WarnMsg( 1, "dvd info: video mpeg2 stream" );
        if( p_main->b_video )
        {
            input_SelectES( p_input, p_es );
        }
639

640
        /* Audio ES, in the order they appear in .ifo */
641
            
642
        i_ac3 = 0x7f;
643
        i_mpeg = 0xc0;
Stéphane Borel's avatar
 
Stéphane Borel committed
644

645
        for( i = 1 ; i <= vts.manager_inf.i_audio_nb ; i++ )
646
        {
647

648
#ifdef DEBUG
Stéphane Borel's avatar
Stéphane Borel committed
649
        intf_WarnMsg( 1, "Audio %d: %x %x %x %x %x %x %x %x %x %x %x %x", i,
650 651 652 653 654 655
            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
656
            vts.manager_inf.p_audio_attr[i-1].i_test,
657 658 659 660 661
            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 );
662
#endif
663

664
            switch( vts.manager_inf.p_audio_attr[i-1].i_coding_mode )
665 666
            {
            case 0x00:              /* AC3 */
667
                i_id = ( ( i_ac3 + i ) << 8 ) | 0xbd;
668 669 670 671 672
                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
673
                p_es->i_cat = AUDIO_ES;
674
                strcpy( p_es->psz_desc, Language( hton16(
675
                    vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) ); 
Stéphane Borel's avatar
Stéphane Borel committed
676
                strcat( p_es->psz_desc, " (ac3)" );
677 678 679

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

681 682 683 684 685 686 687 688 689
                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
690
                p_es->i_cat = AUDIO_ES;
691
                strcpy( p_es->psz_desc, Language( hton16(
692
                    vts.manager_inf.p_audio_attr[i-1].i_lang_code ) ) ); 
Stéphane Borel's avatar
Stéphane Borel committed
693
                strcat( p_es->psz_desc, " (mpeg)" );
694 695 696

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

698
                break;
699 700
            case 0x04:              /* LPCM */
                i_id = 0;
701
                intf_ErrMsg( "dvd warning: LPCM audio not handled yet" );
702 703 704
                break;
            case 0x06:              /* DTS */
                i_id = 0;
705
                i_ac3--;
706
                intf_ErrMsg( "dvd warning: DTS audio not handled yet" );
707
                break;
708 709
            default:
                i_id = 0;
710
                intf_ErrMsg( "dvd warning: unknown audio type %.2x",
711
                         vts.manager_inf.p_audio_attr[i-1].i_coding_mode );
712
            }
713 714 715 716
        
        }
    
        /* Sub Picture ES */
717
           
718 719
        b_last = 0;
        i_sub_pic = 0x20;
720
        for( i = 1 ; i <= vts.manager_inf.i_spu_nb; i++ )
721 722
        {
            if( !b_last )
723
            {
724 725 726 727 728
                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
729
                p_es->i_cat = SPU_ES;
730
                strcpy( p_es->psz_desc, Language( hton16(
731
                    vts.manager_inf.p_spu_attr[i-1].i_lang_code ) ) ); 
732
                intf_WarnMsg( 1, "dvd info: spu stream %d %s\t(0x%x)",
733 734 735 736
                              i, p_es->psz_desc, i_id );
    
                /* The before the last spu has a 0x0 prefix */
                b_last =
737
                    ( vts.manager_inf.p_spu_attr[i].i_prefix == 0 ); 
738
            }
739 740
        }

741
        if( p_main->b_audio )
742
        {
743 744 745 746 747 748 749 750 751 752 753
            /* 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;
            }
            if( i_audio > 0 && vts.manager_inf.i_audio_nb > 0 )
            {
                input_SelectES( p_input, p_input->stream.pp_es[i_audio] );
            }
754
        }
755 756

        if( p_main->b_video )
757
        {
758 759 760 761
            /* 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 )
            {
Henri Fallon's avatar
 
Henri Fallon committed
762
                main_PutIntVariable( INPUT_SUBTITLE_VAR, 0 );
763 764 765 766 767 768 769
                i_spu = 0;
            }
            if( i_spu > 0 && vts.manager_inf.i_spu_nb > 0 )
            {
                i_spu += vts.manager_inf.i_audio_nb;
                input_SelectES( p_input, p_input->stream.pp_es[i_spu] );
            }
770
        }
771
    } /* i_title >= 0 */
772
    else
773
    {
774
        p_area = p_input->stream.p_selected_area;
775
    }
776 777 778 779 780

    /*
     * Chapter selection
     */

781 782
    if( ( p_area->i_part > 0 ) &&
        ( p_area->i_part <= p_area->i_part_nb ) )
783
    {
784 785 786 787 788 789
        if( DVDChapterSelect( p_dvd, p_area->i_part ) < 0 )
        {
            intf_ErrMsg( "dvd error: can't set chapter in area" );
            p_input->b_error = 1;
            return -1;
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
790

791
        p_input->stream.p_selected_area->i_tell = p_dvd->i_start -
792
                                                  p_area->i_start;
793
        p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
794

795 796
        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
797
    }
798 799

    vlc_mutex_unlock( &p_input->stream.stream_lock );
800 801
#undef vts
#undef vmg
802

803 804 805 806 807 808 809 810
    return 0;
}

/*****************************************************************************
 * DVDInit: initializes DVD structures
 *****************************************************************************/
static void DVDInit( input_thread_t * p_input )
{
811
    thread_dvd_data_t *  p_dvd;
812
    input_area_t *       p_area;
813 814
    int                  i_title;
    int                  i_chapter;
Stéphane Borel's avatar
 
Stéphane Borel committed
815
    int                  i;
816

817 818 819
    /* I don't want DVDs to start playing immediately */
//    p_input->stream.i_new_status = PAUSE_S;

Sam Hocevar's avatar
 
Sam Hocevar committed
820 821
    p_dvd = malloc( sizeof(thread_dvd_data_t) );
    if( p_dvd == NULL )
822
    {
823
        intf_ErrMsg( "dvd error: out of memory" );
824 825 826 827
        p_input->b_error = 1;
        return;
    }

828
    p_input->p_plugin_data = (void *)p_dvd;
829 830
    p_input->p_method_data = NULL;

831
    p_dvd->i_fd = p_input->i_handle;
832

833 834 835 836
    /* 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;
837
    p_input->i_read_once = 8;//128;
838

Sam Hocevar's avatar
 
Sam Hocevar committed
839 840 841 842 843 844 845 846 847 848
    i = CSSTest( p_input->i_handle );

    if( i < 0 )
    {
        free( p_dvd );
        p_input->b_error = 1;
        return;
    }

    p_dvd->b_encrypted = i;
849 850 851 852

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

    /* Reading structures initialisation */
853
    p_input->p_method_data =
854
        DVDNetlistInit( 2048, 8192, 2048, DVD_LB_SIZE, p_dvd->i_block_once );
855
    intf_WarnMsg( 2, "dvd info: netlist initialized" );
856

857 858 859
    /* Ifo allocation & initialisation */
    if( IfoCreate( p_dvd ) < 0 )
    {
860
        intf_ErrMsg( "dvd error: allcation error in ifo" );
861 862 863 864 865
        p_input->b_error = 1;
        return;
    }

    if( IfoInit( p_dvd->p_ifo ) < 0 )
866
    {
867
        intf_ErrMsg( "dvd error: fatal failure in ifo" );
Sam Hocevar's avatar
 
Sam Hocevar committed
868 869 870
        free( p_dvd );
        p_input->b_error = 1;
        return;
871
    }
872 873

    /* CSS initialisation */
874
    if( p_dvd->b_encrypted )
875
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
876
        p_dvd->p_css = malloc( sizeof(css_t) );
877
        if( p_dvd->p_css == NULL )
Sam Hocevar's avatar
 
Sam Hocevar committed
878
        {
879
            intf_ErrMsg( "dvd error: couldn't create css structure" );
Sam Hocevar's avatar
 
Sam Hocevar committed
880 881 882 883 884
            free( p_dvd );
            p_input->b_error = 1;
            return;
        }

885 886
        p_dvd->p_css->i_agid = 0;

Sam Hocevar's avatar
 
Sam Hocevar committed
887
        if( CSSInit( p_input->i_handle, p_dvd->p_css ) < 0 )
888
        {
889
            intf_ErrMsg( "dvd error: fatal failure in css" );
Sam Hocevar's avatar
 
Sam Hocevar committed
890
            free( p_dvd->p_css );
891
            free( p_dvd );
892
            p_input->b_error = 1;
893 894
            return;
        }
895

896
        intf_WarnMsg( 2, "dvd info: css initialized" );
897 898
    }

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

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

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

Stéphane Borel's avatar
 
Stéphane Borel committed
908
#define area p_input->stream.pp_areas
909 910
    /* We start from 1 here since the default area 0
     * is reserved for video_ts.vob */
911
    for( i = 1 ; i <= title_inf.i_title_nb ; i++ )
Stéphane Borel's avatar
 
Stéphane Borel committed
912 913 914
    {
        input_AddArea( p_input );

915
        /* Titles are Program Chains */
Stéphane Borel's avatar
 
Stéphane Borel committed
916 917 918 919 920 921 922 923
        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;

924
        /* Number of chapters */
925
        area[i]->i_part_nb = title_inf.p_attr[i-1].i_chapter_nb;
Stéphane Borel's avatar
 
Stéphane Borel committed
926
        area[i]->i_part = 1;
927

Stéphane Borel's avatar
 
Stéphane Borel committed
928
        /* Offset to vts_i_0.ifo */
929 930
        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
931 932 933
    }   
#undef area

934
    /* Get requested title - if none try the first title */
935
    i_title = main_GetIntVariable( INPUT_TITLE_VAR, 1 );
936
    if( i_title <= 0 || i_title > title_inf.i_title_nb )
937
    {
938
        i_title = 1;
939
    }
940
#undef title_inf
941 942 943 944 945 946 947
    /* Get requested chapter - if none defaults to first one */
    i_chapter = main_GetIntVariable( INPUT_CHAPTER_VAR, 1 );
    if( i_chapter <= 0 )
    {
        i_chapter = 1;
    }

948 949
    p_input->stream.pp_areas[i_title]->i_part = i_chapter;

950 951 952 953
    p_area = p_input->stream.pp_areas[i_title];

    vlc_mutex_unlock( &p_input->stream.stream_lock );

954
    /* set title, chapter, audio and subpic */
955
    DVDSetArea( p_input, p_area );
956

957
    return;
Sam Hocevar's avatar
 
Sam Hocevar committed
958 959 960 961 962 963
}

/*****************************************************************************
 * DVDEnd: frees unused data
 *****************************************************************************/
static void DVDEnd( input_thread_t * p_input )
964
{
965
    thread_dvd_data_t *     p_dvd;
966 967
    dvd_netlist_t *         p_netlist;

968
    p_dvd = (thread_dvd_data_t*)p_input->p_plugin_data;
969 970
    p_netlist = (dvd_netlist_t *)p_input->p_method_data;

971 972
    if( p_dvd->b_encrypted )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
973
        free( p_dvd->p_css );
974 975
    }

976
    IfoDestroy( p_dvd->p_ifo );
977
    free( p_dvd );
978
    DVDNetlistEnd( p_netlist );
979 980