dvdnav.c 50.2 KB
Newer Older
1
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
2
 * dvdnav.c: DVD module using the dvdnav library.
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2004-2009 VLC authors and VideoLAN
5
 * $Id$
6 7 8
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
9 10 11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12 13 14 15
 * (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
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
19 20 21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 23
 *****************************************************************************/

Jean-Baptiste Kempf's avatar
LGPL  
Jean-Baptiste Kempf committed
24 25 26 27 28 29 30 31
/*****************************************************************************
 * NOTA BENE: this module requires the linking against a library which is
 * known to require licensing under the GNU General Public License version 2
 * (or later). Therefore, the result of compiling this module will normally
 * be subject to the terms of that later license.
 *****************************************************************************/


32 33 34 35
/*****************************************************************************
 * Preamble
 *****************************************************************************/

36 37 38 39
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

40
#include <assert.h>
41
#include <sys/stat.h>
42
#include <fcntl.h>
Felix Paul Kühne's avatar
Felix Paul Kühne committed
43
#include <errno.h>
KO Myung-Hun's avatar
KO Myung-Hun committed
44
#include <unistd.h>     /* close() */
45

46 47 48 49 50 51 52 53 54
#include <vlc_common.h>
#include <vlc_plugin.h>
#include <vlc_input.h>
#include <vlc_access.h>
#include <vlc_demux.h>
#include <vlc_charset.h>
#include <vlc_fs.h>
#include <vlc_vout.h>
#include <vlc_dialog.h>
55
#include <vlc_iso_lang.h>
56

57
/* FIXME we should find a better way than including that */
58
#include "../../src/text/iso-639_def.h"
59 60


61 62
#include <dvdnav/dvdnav.h>

63
#include "../demux/mpeg/pes.h"
64
#include "../demux/mpeg/ps.h"
65 66 67 68

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
69 70
#define ANGLE_TEXT N_("DVD angle")
#define ANGLE_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
71
     "Default DVD angle." )
72

73 74
#define MENU_TEXT N_("Start directly in menu")
#define MENU_LONGTEXT N_( \
Clément Stenac's avatar
Clément Stenac committed
75 76
    "Start the DVD directly in the main menu. This "\
    "will try to skip all the useless warning introductions." )
77

78 79
#define LANGUAGE_DEFAULT ("en")

Thomas Guillem's avatar
Thomas Guillem committed
80
static int  AccessDemuxOpen ( vlc_object_t * );
Laurent Aimar's avatar
Laurent Aimar committed
81
static void Close( vlc_object_t * );
82

83
#if DVDREAD_VERSION >= 50300 && defined( HAVE_STREAM_CB_IN_DVDNAV_H )
Thomas Guillem's avatar
Thomas Guillem committed
84 85 86 87
#define HAVE_DVDNAV_DEMUX
static int  DemuxOpen ( vlc_object_t * );
#endif

88 89 90 91 92
vlc_module_begin ()
    set_shortname( N_("DVD with menus") )
    set_description( N_("DVDnav Input") )
    set_category( CAT_INPUT )
    set_subcategory( SUBCAT_INPUT_ACCESS )
93
    add_integer( "dvdnav-angle", 1, ANGLE_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
94
        ANGLE_LONGTEXT, false )
95
    add_bool( "dvdnav-menu", true,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
96
        MENU_TEXT, MENU_LONGTEXT, false )
97
    set_capability( "access_demux", 5 )
98
    add_shortcut( "dvd", "dvdnav", "file" )
Thomas Guillem's avatar
Thomas Guillem committed
99 100 101 102 103 104 105 106 107 108
    set_callbacks( AccessDemuxOpen, Close )
#ifdef HAVE_DVDNAV_DEMUX
    add_submodule()
        set_description( N_("DVDnav demuxer") )
        set_category( CAT_INPUT )
        set_subcategory( SUBCAT_INPUT_DEMUX )
        set_capability( "demux", 5 )
        set_callbacks( DemuxOpen, Close )
        add_shortcut( "dvd", "iso" )
#endif
109
vlc_module_end ()
110

111
/* Shall we use libdvdnav's read ahead cache? */
112 113 114
#ifdef __OS2__
#define DVD_READ_CACHE 0
#else
115
#define DVD_READ_CACHE 1
116
#endif
117

118 119 120 121 122 123 124
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
struct demux_sys_t
{
    dvdnav_t    *dvdnav;

Laurent Aimar's avatar
Laurent Aimar committed
125 126
    /* */
    bool        b_reset_pcr;
Thomas Guillem's avatar
Thomas Guillem committed
127
    bool        b_readahead;
Laurent Aimar's avatar
Laurent Aimar committed
128

129 130 131 132 133
    struct
    {
        bool         b_created;
        bool         b_enabled;
        vlc_mutex_t  lock;
134
        vlc_timer_t  timer;
135 136
    } still;

137 138
    /* track */
    ps_track_t  tk[PS_TK_COUNT];
139
    int         i_mux_rate;
140 141

    /* event */
142
    vout_thread_t *p_vout;
143

144 145 146
    /* palette for menus */
    uint32_t clut[16];
    uint8_t  palette[4][4];
147
    bool b_spu_change;
148

149 150 151 152 153 154
    /* Aspect ration */
    struct {
        unsigned i_num;
        unsigned i_den;
    } sar;

155
    /* */
Laurent Aimar's avatar
Laurent Aimar committed
156 157
    int           i_title;
    input_title_t **title;
158

Sebastian Ramacher's avatar
Sebastian Ramacher committed
159
    /* length of program group chain */
160
    mtime_t     i_pgc_length;
161 162
    int         i_vobu_index;
    int         i_vobu_flush;
163 164
};

Laurent Aimar's avatar
Laurent Aimar committed
165
static int Control( demux_t *, int, va_list );
166
static int Demux( demux_t * );
167
static int DemuxBlock( demux_t *, const uint8_t *, int );
168
static void DemuxForceStill( demux_t * );
169

170
static void DemuxTitles( demux_t * );
Laurent Aimar's avatar
Laurent Aimar committed
171
static void ESSubtitleUpdate( demux_t * );
172
static void ButtonUpdate( demux_t *, bool );
Laurent Aimar's avatar
Laurent Aimar committed
173

174
static void ESNew( demux_t *, int );
175
static int ProbeDVD( const char * );
176

Laurent Aimar's avatar
Laurent Aimar committed
177
static char *DemuxGetLanguageCode( demux_t *p_demux, const char *psz_var );
178

179 180
static int ControlInternal( demux_t *, int, ... );

181
static void StillTimer( void * );
182

183 184 185 186
static int EventMouse( vlc_object_t *, char const *,
                       vlc_value_t, vlc_value_t, void * );
static int EventIntf( vlc_object_t *, char const *,
                      vlc_value_t, vlc_value_t, void * );
187

188
/*****************************************************************************
Thomas Guillem's avatar
Thomas Guillem committed
189
 * CommonOpen:
190
 *****************************************************************************/
Thomas Guillem's avatar
Thomas Guillem committed
191 192
static int CommonOpen( vlc_object_t *p_this,
                       dvdnav_t *p_dvdnav, bool b_readahead )
193
{
Gildas Bazin's avatar
 
Gildas Bazin committed
194 195
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys;
196
    int         i_angle;
197
    char        *psz_code;
198

Thomas Guillem's avatar
Thomas Guillem committed
199
    assert( p_dvdnav );
Gildas Bazin's avatar
 
Gildas Bazin committed
200

201
    /* Fill p_demux field */
202
    DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys;
203
    p_sys->dvdnav = p_dvdnav;
Laurent Aimar's avatar
Laurent Aimar committed
204
    p_sys->b_reset_pcr = false;
205 206

    ps_track_init( p_sys->tk );
207 208
    p_sys->sar.i_num = 0;
    p_sys->sar.i_den = 0;
209
    p_sys->i_mux_rate = 0;
210
    p_sys->i_pgc_length = 0;
211
    p_sys->b_spu_change = false;
212 213
    p_sys->i_vobu_index = 0;
    p_sys->i_vobu_flush = 0;
Thomas Guillem's avatar
Thomas Guillem committed
214
    p_sys->b_readahead = b_readahead;
215

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
    if( 1 )
    {
        // Hack for libdvdnav CVS.
        // Without it dvdnav_get_number_of_titles() fails.
        // Remove when fixed in libdvdnav CVS.
        uint8_t buffer[DVD_VIDEO_LB_LEN];
        int i_event, i_len;

        if( dvdnav_get_next_block( p_sys->dvdnav, buffer, &i_event, &i_len )
              == DVDNAV_STATUS_ERR )
        {
            msg_Warn( p_demux, "dvdnav_get_next_block failed" );
        }

        dvdnav_sector_search( p_sys->dvdnav, 0, SEEK_SET );
    }

233
    /* Configure dvdnav */
Thomas Guillem's avatar
Thomas Guillem committed
234
    if( dvdnav_set_readahead_flag( p_sys->dvdnav, p_sys->b_readahead ) !=
235
          DVDNAV_STATUS_OK )
236
    {
Derk-Jan Hartman's avatar
Derk-Jan Hartman committed
237
        msg_Warn( p_demux, "cannot set read-a-head flag" );
238
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
239 240 241

    if( dvdnav_set_PGC_positioning_flag( p_sys->dvdnav, 1 ) !=
          DVDNAV_STATUS_OK )
242 243 244
    {
        msg_Warn( p_demux, "cannot set PGC positioning flag" );
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
245

246 247
    /* Set menu language */
    psz_code = DemuxGetLanguageCode( p_demux, "menu-language" );
248
    if( dvdnav_menu_language_select( p_sys->dvdnav, psz_code ) !=
249
        DVDNAV_STATUS_OK )
250
    {
251
        msg_Warn( p_demux, "can't set menu language to '%s' (%s)",
252 253 254 255
                  psz_code, dvdnav_err_to_string( p_sys->dvdnav ) );
        /* We try to fall back to 'en' */
        if( strcmp( psz_code, LANGUAGE_DEFAULT ) )
            dvdnav_menu_language_select( p_sys->dvdnav, (char*)LANGUAGE_DEFAULT );
256
    }
257
    free( psz_code );
258 259 260

    /* Set audio language */
    psz_code = DemuxGetLanguageCode( p_demux, "audio-language" );
261
    if( dvdnav_audio_language_select( p_sys->dvdnav, psz_code ) !=
262
        DVDNAV_STATUS_OK )
263
    {
264 265
        msg_Warn( p_demux, "can't set audio language to '%s' (%s)",
                  psz_code, dvdnav_err_to_string( p_sys->dvdnav ) );
266 267
        /* We try to fall back to 'en' */
        if( strcmp( psz_code, LANGUAGE_DEFAULT ) )
268
            dvdnav_audio_language_select( p_sys->dvdnav, (char*)LANGUAGE_DEFAULT );
269 270 271 272
    }
    free( psz_code );

    /* Set spu language */
273 274
    psz_code = DemuxGetLanguageCode( p_demux, "sub-language" );
    if( dvdnav_spu_language_select( p_sys->dvdnav, psz_code ) !=
275
        DVDNAV_STATUS_OK )
276
    {
277 278
        msg_Warn( p_demux, "can't set spu language to '%s' (%s)",
                  psz_code, dvdnav_err_to_string( p_sys->dvdnav ) );
279 280
        /* We try to fall back to 'en' */
        if( strcmp( psz_code, LANGUAGE_DEFAULT ) )
281
            dvdnav_spu_language_select(p_sys->dvdnav, (char*)LANGUAGE_DEFAULT );
282
    }
283
    free( psz_code );
284

Laurent Aimar's avatar
Laurent Aimar committed
285 286
    DemuxTitles( p_demux );

287
    if( var_CreateGetBool( p_demux, "dvdnav-menu" ) )
288 289 290 291 292
    {
        msg_Dbg( p_demux, "trying to go to dvd menu" );

        if( dvdnav_title_play( p_sys->dvdnav, 1 ) != DVDNAV_STATUS_OK )
        {
293
            msg_Err( p_demux, "cannot set title (can't decrypt DVD?)" );
Thomas Guillem's avatar
Thomas Guillem committed
294 295 296
            vlc_dialog_display_error( p_demux, _("Playback failure"), "%s",
                _("VLC cannot set the DVD's title. It possibly "
                  "cannot decrypt the entire disc.") );
297 298
            free( p_sys );
            return VLC_EGENERIC;
299 300 301 302 303
        }

        if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Title ) !=
            DVDNAV_STATUS_OK )
        {
304 305 306 307
            /* Try going to menu root */
            if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root ) !=
                DVDNAV_STATUS_OK )
                    msg_Warn( p_demux, "cannot go to dvd menu" );
308 309 310
        }
    }

311 312
    i_angle = var_CreateGetInteger( p_demux, "dvdnav-angle" );
    if( i_angle <= 0 ) i_angle = 1;
313

314
    /* FIXME hack hack hack hack FIXME */
315
    /* Get p_input and create variable */
316 317 318 319 320 321 322
    var_Create( p_demux->p_input, "x-start", VLC_VAR_INTEGER );
    var_Create( p_demux->p_input, "y-start", VLC_VAR_INTEGER );
    var_Create( p_demux->p_input, "x-end", VLC_VAR_INTEGER );
    var_Create( p_demux->p_input, "y-end", VLC_VAR_INTEGER );
    var_Create( p_demux->p_input, "color", VLC_VAR_ADDRESS );
    var_Create( p_demux->p_input, "menu-palette", VLC_VAR_ADDRESS );
    var_Create( p_demux->p_input, "highlight", VLC_VAR_BOOL );
323

324
    /* catch vout creation event */
325
    var_AddCallback( p_demux->p_input, "intf-event", EventIntf, p_demux );
326

327 328
    p_sys->still.b_enabled = false;
    vlc_mutex_init( &p_sys->still.lock );
329 330 331
    if( !vlc_timer_create( &p_sys->still.timer, StillTimer, p_sys ) )
        p_sys->still.b_created = true;

332 333 334
    return VLC_SUCCESS;
}

Thomas Guillem's avatar
Thomas Guillem committed
335 336 337 338 339 340 341 342 343 344 345 346
/*****************************************************************************
 * AccessDemuxOpen:
 *****************************************************************************/
static int AccessDemuxOpen ( vlc_object_t *p_this )
{
    demux_t *p_demux = (demux_t*)p_this;
    dvdnav_t *p_dvdnav = NULL;
    char *psz_file = NULL;
    const char *psz_path = NULL;
    int i_ret = VLC_EGENERIC;
    bool forced = false;

347
    if( !strncmp(p_demux->psz_access, "dvd", 3) )
Thomas Guillem's avatar
Thomas Guillem committed
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 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
        forced = true;

    if( !p_demux->psz_file || !*p_demux->psz_file )
    {
        /* Only when selected */
        if( !forced )
            return VLC_EGENERIC;

        psz_file = var_InheritString( p_this, "dvd" );
    }
    else
        psz_file = strdup( p_demux->psz_file );

#if defined( _WIN32 ) || defined( __OS2__ )
    if( psz_file != NULL )
    {
        /* Remove trailing backslash, otherwise dvdnav_open will fail */
        size_t flen = strlen( psz_file );
        if( flen > 0 && psz_file[flen - 1] == '\\' )
            psz_file[flen - 1] = '\0';
    }
    else
        psz_file = strdup("");
#endif

    if( unlikely(psz_file == NULL) )
        return VLC_EGENERIC;

    /* Try some simple probing to avoid going through dvdnav_open too often */
    if( !forced && ProbeDVD( psz_file ) != VLC_SUCCESS )
        goto bailout;

    /* Open dvdnav */
    psz_path = ToLocale( psz_file );
    if( dvdnav_open( &p_dvdnav, psz_path ) != DVDNAV_STATUS_OK )
    {
        msg_Warn( p_demux, "cannot open DVD (%s)", psz_file);
        goto bailout;
    }

    i_ret = CommonOpen( p_this, p_dvdnav, !!DVD_READ_CACHE );
    if( i_ret != VLC_SUCCESS )
        dvdnav_close( p_dvdnav );

bailout:
    free( psz_file );
    if( psz_path )
        LocaleFree( psz_path );
    return i_ret;
}

#ifdef HAVE_DVDNAV_DEMUX
/*****************************************************************************
 * StreamProbeDVD: very weak probing that avoids going too often into a dvdnav_open()
 *****************************************************************************/
static int StreamProbeDVD( stream_t *s )
{
405
    /* first sector should be filled with zeros */
406
    ssize_t i_peek;
407
    const uint8_t *p_peek;
408
    i_peek = vlc_stream_Peek( s, &p_peek, 2048 );
409 410 411 412 413 414 415 416 417
    if( i_peek < 512 ) {
        return VLC_EGENERIC;
    }
    while (i_peek > 0) {
        if (p_peek[ --i_peek ]) {
            return VLC_EGENERIC;
        }
    }

Thomas Guillem's avatar
Thomas Guillem committed
418 419
    /* ISO 9660 volume descriptor */
    char iso_dsc[6];
420 421
    if( vlc_stream_Seek( s, 0x8000 + 1 ) != VLC_SUCCESS
     || vlc_stream_Read( s, iso_dsc, sizeof (iso_dsc) ) < (int)sizeof (iso_dsc)
Thomas Guillem's avatar
Thomas Guillem committed
422 423 424 425 426 427
     || memcmp( iso_dsc, "CD001\x01", 6 ) )
        return VLC_EGENERIC;

    /* Try to find the anchor (2 bytes at LBA 256) */
    uint16_t anchor;

428 429
    if( vlc_stream_Seek( s, 256 * DVD_VIDEO_LB_LEN ) == VLC_SUCCESS
     && vlc_stream_Read( s, &anchor, 2 ) == 2
Thomas Guillem's avatar
Thomas Guillem committed
430 431 432 433 434 435 436 437 438 439 440
     && GetWLE( &anchor ) == 2 )
        return VLC_SUCCESS;
    else
        return VLC_EGENERIC;
}

/*****************************************************************************
 * dvdnav stream callbacks
 *****************************************************************************/
static int stream_cb_seek( void *s, uint64_t pos )
{
441
    return vlc_stream_Seek( (stream_t *)s, pos );
Thomas Guillem's avatar
Thomas Guillem committed
442 443 444 445
}

static int stream_cb_read( void *s, void* buffer, int size )
{
446
    return vlc_stream_Read( (stream_t *)s, buffer, size );
Thomas Guillem's avatar
Thomas Guillem committed
447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463
}

/*****************************************************************************
 * DemuxOpen:
 *****************************************************************************/
static int DemuxOpen ( vlc_object_t *p_this )
{
    demux_t *p_demux = (demux_t*)p_this;
    dvdnav_t *p_dvdnav = NULL;
    bool forced = false, b_seekable = false;

    if( p_demux->psz_demux != NULL
     && !strncmp(p_demux->psz_demux, "dvd", 3) )
        forced = true;

    /* StreamProbeDVD need FASTSEEK, but if dvd is forced, we don't probe thus
     * don't need fastseek */
464
    vlc_stream_Control( p_demux->s, forced ? STREAM_CAN_SEEK : STREAM_CAN_FASTSEEK,
Thomas Guillem's avatar
Thomas Guillem committed
465 466 467 468 469
                    &b_seekable );
    if( !b_seekable )
        return VLC_EGENERIC;

    /* Try some simple probing to avoid going through dvdnav_open too often */
470
    if( !forced && StreamProbeDVD( p_demux->s ) != VLC_SUCCESS )
471
        return VLC_EGENERIC;
Thomas Guillem's avatar
Thomas Guillem committed
472 473 474 475 476 477 478 479 480 481 482 483 484

    static dvdnav_stream_cb stream_cb =
    {
        .pf_seek = stream_cb_seek,
        .pf_read = stream_cb_read,
        .pf_readv = NULL,
    };

    /* Open dvdnav with stream callbacks */
    if( dvdnav_open_stream( &p_dvdnav, p_demux->s,
                            &stream_cb ) != DVDNAV_STATUS_OK )
    {
        msg_Warn( p_demux, "cannot open DVD with open_stream" );
485
        return VLC_EGENERIC;
Thomas Guillem's avatar
Thomas Guillem committed
486 487
    }

488
    int i_ret = CommonOpen( p_this, p_dvdnav, false );
Thomas Guillem's avatar
Thomas Guillem committed
489 490 491 492 493 494
    if( i_ret != VLC_SUCCESS )
        dvdnav_close( p_dvdnav );
    return i_ret;
}
#endif

495
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
496
 * Close:
497
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
498
static void Close( vlc_object_t *p_this )
499 500 501 502
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;

503
    /* Stop vout event handler */
504
    var_DelCallback( p_demux->p_input, "intf-event", EventIntf, p_demux );
505 506 507
    if( p_sys->p_vout != NULL )
    {   /* Should not happen, but better be safe than sorry. */
        msg_Warn( p_sys->p_vout, "removing dangling mouse DVD callbacks" );
508 509
        var_DelCallback( p_sys->p_vout, "mouse-moved", EventMouse, p_demux );
        var_DelCallback( p_sys->p_vout, "mouse-clicked", EventMouse, p_demux );
510 511
    }

512 513
    /* Stop still image handler */
    if( p_sys->still.b_created )
514
        vlc_timer_destroy( p_sys->still.timer );
515
    vlc_mutex_destroy( &p_sys->still.lock );
516

517 518 519 520 521 522 523
    var_Destroy( p_demux->p_input, "highlight" );
    var_Destroy( p_demux->p_input, "x-start" );
    var_Destroy( p_demux->p_input, "x-end" );
    var_Destroy( p_demux->p_input, "y-start" );
    var_Destroy( p_demux->p_input, "y-end" );
    var_Destroy( p_demux->p_input, "color" );
    var_Destroy( p_demux->p_input, "menu-palette" );
524

525
    for( int i = 0; i < PS_TK_COUNT; i++ )
526 527
    {
        ps_track_t *tk = &p_sys->tk[i];
528
        if( tk->b_configured )
529 530 531 532 533 534
        {
            es_format_Clean( &tk->fmt );
            if( tk->es ) es_out_Del( p_demux->out, tk->es );
        }
    }

Rémi Duraffort's avatar
Rémi Duraffort committed
535 536 537 538 539
    /* Free the array of titles */
    for( int i = 0; i < p_sys->i_title; i++ )
        vlc_input_title_Delete( p_sys->title[i] );
    TAB_CLEAN( p_sys->i_title, p_sys->title );

540 541 542 543 544
    dvdnav_close( p_sys->dvdnav );
    free( p_sys );
}

/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
545
 * Control:
546
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
547
static int Control( demux_t *p_demux, int i_query, va_list args )
548 549
{
    demux_sys_t *p_sys = p_demux->p_sys;
Laurent Aimar's avatar
Laurent Aimar committed
550 551
    input_title_t ***ppp_title;
    int i;
552 553 554

    switch( i_query )
    {
555
        case DEMUX_SET_POSITION:
556
        case DEMUX_GET_POSITION:
557 558
        case DEMUX_GET_TIME:
        case DEMUX_GET_LENGTH:
559 560
        {
            uint32_t pos, len;
561 562
            if( dvdnav_get_position( p_sys->dvdnav, &pos, &len ) !=
                  DVDNAV_STATUS_OK || len == 0 )
563
            {
564
                return VLC_EGENERIC;
565
            }
566

JP Dinger's avatar
JP Dinger committed
567
            switch( i_query )
568
            {
JP Dinger's avatar
JP Dinger committed
569 570
            case DEMUX_GET_POSITION:
                *va_arg( args, double* ) = (double)pos / (double)len;
571
                return VLC_SUCCESS;
JP Dinger's avatar
JP Dinger committed
572 573 574

            case DEMUX_SET_POSITION:
                pos = va_arg( args, double ) * len;
Gildas Bazin's avatar
 
Gildas Bazin committed
575 576
                if( dvdnav_sector_search( p_sys->dvdnav, pos, SEEK_SET ) ==
                      DVDNAV_STATUS_OK )
577 578 579
                {
                    return VLC_SUCCESS;
                }
JP Dinger's avatar
JP Dinger committed
580 581 582
                break;

            case DEMUX_GET_TIME:
583
                if( p_sys->i_pgc_length > 0 )
584
                {
JP Dinger's avatar
JP Dinger committed
585
                    *va_arg( args, int64_t * ) = p_sys->i_pgc_length*pos/len;
586 587
                    return VLC_SUCCESS;
                }
JP Dinger's avatar
JP Dinger committed
588 589 590
                break;

            case DEMUX_GET_LENGTH:
591
                if( p_sys->i_pgc_length > 0 )
592
                {
JP Dinger's avatar
JP Dinger committed
593
                    *va_arg( args, int64_t * ) = (int64_t)p_sys->i_pgc_length;
594 595
                    return VLC_SUCCESS;
                }
JP Dinger's avatar
JP Dinger committed
596
                break;
597
            }
598 599 600
            return VLC_EGENERIC;
        }

Laurent Aimar's avatar
Laurent Aimar committed
601 602
        /* Special for access_demux */
        case DEMUX_CAN_PAUSE:
603
        case DEMUX_CAN_SEEK:
Laurent Aimar's avatar
Laurent Aimar committed
604 605
        case DEMUX_CAN_CONTROL_PACE:
            /* TODO */
JP Dinger's avatar
JP Dinger committed
606
            *va_arg( args, bool * ) = true;
Laurent Aimar's avatar
Laurent Aimar committed
607 608 609 610 611 612
            return VLC_SUCCESS;

        case DEMUX_SET_PAUSE_STATE:
            return VLC_SUCCESS;

        case DEMUX_GET_TITLE_INFO:
JP Dinger's avatar
JP Dinger committed
613 614 615 616
            ppp_title = va_arg( args, input_title_t*** );
            *va_arg( args, int* ) = p_sys->i_title;
            *va_arg( args, int* ) = 0; /* Title offset */
            *va_arg( args, int* ) = 1; /* Chapter offset */
Laurent Aimar's avatar
Laurent Aimar committed
617 618

            /* Duplicate title infos */
619
            *ppp_title = malloc( p_sys->i_title * sizeof( input_title_t * ) );
Laurent Aimar's avatar
Laurent Aimar committed
620 621 622 623 624 625 626
            for( i = 0; i < p_sys->i_title; i++ )
            {
                (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->title[i] );
            }
            return VLC_SUCCESS;

        case DEMUX_SET_TITLE:
627
            i = va_arg( args, int );
628 629
            if( i == 0 && dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root )
                  != DVDNAV_STATUS_OK )
Laurent Aimar's avatar
Laurent Aimar committed
630 631 632 633
            {
                msg_Warn( p_demux, "cannot set title/chapter" );
                return VLC_EGENERIC;
            }
634 635 636 637 638 639 640 641 642 643 644

            if( i != 0 )
            {
                dvdnav_still_skip( p_sys->dvdnav );
                if( dvdnav_title_play( p_sys->dvdnav, i ) != DVDNAV_STATUS_OK )
                {
                    msg_Warn( p_demux, "cannot set title/chapter" );
                    return VLC_EGENERIC;
                }
            }

645 646
            p_demux->info.i_update |=
                INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
Laurent Aimar's avatar
Laurent Aimar committed
647 648 649 650 651
            p_demux->info.i_title = i;
            p_demux->info.i_seekpoint = 0;
            return VLC_SUCCESS;

        case DEMUX_SET_SEEKPOINT:
JP Dinger's avatar
JP Dinger committed
652
            i = va_arg( args, int );
Laurent Aimar's avatar
Laurent Aimar committed
653 654
            if( p_demux->info.i_title == 0 )
            {
JP Dinger's avatar
JP Dinger committed
655 656 657 658 659 660 661 662 663 664 665 666
                static const int argtab[] = {
                    DVD_MENU_Escape,
                    DVD_MENU_Root,
                    DVD_MENU_Title,
                    DVD_MENU_Part,
                    DVD_MENU_Subpicture,
                    DVD_MENU_Audio,
                    DVD_MENU_Angle
                };
                enum { numargs = sizeof(argtab)/sizeof(int) };
                if( (unsigned)i >= numargs || DVDNAV_STATUS_OK !=
                           dvdnav_menu_call(p_sys->dvdnav,argtab[i]) )
Laurent Aimar's avatar
Laurent Aimar committed
667 668
                    return VLC_EGENERIC;
            }
669
            else if( dvdnav_part_play( p_sys->dvdnav, p_demux->info.i_title,
670
                                       i + 1 ) != DVDNAV_STATUS_OK )
Laurent Aimar's avatar
Laurent Aimar committed
671 672 673 674 675 676 677 678 679
            {
                msg_Warn( p_demux, "cannot set title/chapter" );
                return VLC_EGENERIC;
            }
            p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
            p_demux->info.i_seekpoint = i;
            return VLC_SUCCESS;

        case DEMUX_GET_PTS_DELAY:
680 681
            *va_arg( args, int64_t * ) =
                INT64_C(1000) * var_InheritInteger( p_demux, "disc-caching" );
Laurent Aimar's avatar
Laurent Aimar committed
682 683
            return VLC_SUCCESS;

684 685 686 687 688 689 690
        case DEMUX_GET_META:
        {
            const char *title_name = NULL;

            dvdnav_get_title_string(p_sys->dvdnav, &title_name);
            if( (NULL != title_name) && ('\0' != title_name[0]) )
            {
691
                vlc_meta_t *p_meta = va_arg( args, vlc_meta_t* );
692
                vlc_meta_Set( p_meta, vlc_meta_Title, title_name );
693 694 695 696 697
                return VLC_SUCCESS;
            }
            return VLC_EGENERIC;
        }

698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
        case DEMUX_NAV_ACTIVATE:
        {
            pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );

            ButtonUpdate( p_demux, true );
            dvdnav_button_activate( p_sys->dvdnav, pci );
            break;
        }

        case DEMUX_NAV_UP:
        {
            pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );

            dvdnav_upper_button_select( p_sys->dvdnav, pci );
            break;
        }

        case DEMUX_NAV_DOWN:
        {
            pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );

            dvdnav_lower_button_select( p_sys->dvdnav, pci );
            break;
        }

        case DEMUX_NAV_LEFT:
        {
            pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );

            dvdnav_left_button_select( p_sys->dvdnav, pci );
            break;
        }

        case DEMUX_NAV_RIGHT:
        {
            pci_t *pci = dvdnav_get_current_nav_pci( p_sys->dvdnav );

            dvdnav_right_button_select( p_sys->dvdnav, pci );
            break;
        }

739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
        case DEMUX_NAV_MENU:
        {
            if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Title )
                != DVDNAV_STATUS_OK )
            {
                msg_Warn( p_demux, "cannot select Title menu" );
                if( dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root )
                    != DVDNAV_STATUS_OK )
                {
                    msg_Warn( p_demux, "cannot select Root menu" );
                    return VLC_EGENERIC;
                }
            }
            p_demux->info.i_update |=
                INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT;
            p_demux->info.i_title = 0;
            p_demux->info.i_seekpoint = 2;
            break;
        }

759 760 761 762
        /* TODO implement others */
        default:
            return VLC_EGENERIC;
    }
763 764

    return VLC_SUCCESS;
765 766
}

767 768 769 770 771 772 773 774 775 776 777
static int ControlInternal( demux_t *p_demux, int i_query, ... )
{
    va_list args;
    int     i_result;

    va_start( args, i_query );
    i_result = Control( p_demux, i_query, args );
    va_end( args );

    return i_result;
}
778
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
779
 * Demux:
780
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
781
static int Demux( demux_t *p_demux )
782 783 784
{
    demux_sys_t *p_sys = p_demux->p_sys;

785 786
    uint8_t buffer[DVD_VIDEO_LB_LEN];
    uint8_t *packet = buffer;
787 788
    int i_event;
    int i_len;
Thomas Guillem's avatar
Thomas Guillem committed
789
    dvdnav_status_t status;
790

Thomas Guillem's avatar
Thomas Guillem committed
791 792 793 794 795 796 797
    if( p_sys->b_readahead )
        status = dvdnav_get_next_cache_block( p_sys->dvdnav, &packet, &i_event,
                                              &i_len );
    else
        status = dvdnav_get_next_block( p_sys->dvdnav, packet, &i_event,
                                        &i_len );
    if( status == DVDNAV_STATUS_ERR )
798 799 800
    {
        msg_Warn( p_demux, "cannot get next block (%s)",
                  dvdnav_err_to_string( p_sys->dvdnav ) );
801 802 803 804 805
        if( p_demux->info.i_title == 0 )
        {
            msg_Dbg( p_demux, "jumping to first title" );
            return ControlInternal( p_demux, DEMUX_SET_TITLE, 1 ) == VLC_SUCCESS ? 1 : -1;
        }
806 807
        return -1;
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
808

809 810
    switch( i_event )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
811
    case DVDNAV_BLOCK_OK:   /* mpeg block */
812
        vlc_mutex_lock( &p_sys->still.lock );
813
        vlc_timer_schedule( p_sys->still.timer, false, 0, 0 );
814 815
        p_sys->still.b_enabled = false;
        vlc_mutex_unlock( &p_sys->still.lock );
Laurent Aimar's avatar
Laurent Aimar committed
816 817 818 819 820
        if( p_sys->b_reset_pcr )
        {
            es_out_Control( p_demux->out, ES_OUT_RESET_PCR );
            p_sys->b_reset_pcr = false;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
821
        DemuxBlock( p_demux, packet, i_len );
822 823 824 825 826 827
        if( p_sys->i_vobu_index > 0 )
        {
            if( p_sys->i_vobu_flush == p_sys->i_vobu_index )
                DemuxForceStill( p_demux );
            p_sys->i_vobu_index++;
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
828
        break;
829

Gildas Bazin's avatar
 
Gildas Bazin committed
830 831 832
    case DVDNAV_NOP:    /* Nothing */
        msg_Dbg( p_demux, "DVDNAV_NOP" );
        break;
833

Gildas Bazin's avatar
 
Gildas Bazin committed
834 835 836
    case DVDNAV_STILL_FRAME:
    {
        dvdnav_still_event_t *event = (dvdnav_still_event_t*)packet;
Laurent Aimar's avatar
Laurent Aimar committed
837 838
        bool b_still_init = false;

839 840
        vlc_mutex_lock( &p_sys->still.lock );
        if( !p_sys->still.b_enabled )
Laurent Aimar's avatar
Laurent Aimar committed
841 842 843
        {
            msg_Dbg( p_demux, "DVDNAV_STILL_FRAME" );
            msg_Dbg( p_demux, "     - length=0x%x", event->length );
844 845
            p_sys->still.b_enabled = true;

846
            if( event->length != 0xff && p_sys->still.b_created )
847
            {
Rémi Denis-Courmont's avatar
Cleanup  
Rémi Denis-Courmont committed
848
                mtime_t delay = event->length * CLOCK_FREQ;
849
                vlc_timer_schedule( p_sys->still.timer, false, delay, 0 );
850 851
            }

Laurent Aimar's avatar
Laurent Aimar committed
852 853
            b_still_init = true;
        }
854
        vlc_mutex_unlock( &p_sys->still.lock );
Laurent Aimar's avatar
Laurent Aimar committed
855 856

        if( b_still_init )
857
        {
858
            DemuxForceStill( p_demux );
Laurent Aimar's avatar
Laurent Aimar committed
859
            p_sys->b_reset_pcr = true;
860
        }
861
        msleep( 40000 );
Gildas Bazin's avatar
 
Gildas Bazin committed
862 863
        break;
    }
864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882

    case DVDNAV_SPU_CLUT_CHANGE:
    {
        int i;

        msg_Dbg( p_demux, "DVDNAV_SPU_CLUT_CHANGE" );
        /* Update color lookup table (16 *uint32_t in packet) */
        memcpy( p_sys->clut, packet, 16 * sizeof( uint32_t ) );

        /* HACK to get the SPU tracks registered in the right order */
        for( i = 0; i < 0x1f; i++ )
        {
            if( dvdnav_spu_stream_to_lang( p_sys->dvdnav, i ) != 0xffff )
                ESNew( p_demux, 0xbd20 + i );
        }
        /* END HACK */
        break;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
883 884 885 886
    case DVDNAV_SPU_STREAM_CHANGE:
    {
        dvdnav_spu_stream_change_event_t *event =
            (dvdnav_spu_stream_change_event_t*)packet;
887 888
        int i;

Gildas Bazin's avatar
 
Gildas Bazin committed
889
        msg_Dbg( p_demux, "DVDNAV_SPU_STREAM_CHANGE" );
Laurent Aimar's avatar
Laurent Aimar committed
890 891
        msg_Dbg( p_demux, "     - physical_wide=%d",
                 event->physical_wide );
Gildas Bazin's avatar
 
Gildas Bazin committed
892 893 894 895
        msg_Dbg( p_demux, "     - physical_letterbox=%d",
                 event->physical_letterbox);
        msg_Dbg( p_demux, "     - physical_pan_scan=%d",
                 event->physical_pan_scan );
Laurent Aimar's avatar
Laurent Aimar committed
896

897
        ESSubtitleUpdate( p_demux );
898
        p_sys->b_spu_change = true;
899 900 901 902 903 904 905 906

        /* HACK to get the SPU tracks registered in the right order */
        for( i = 0; i < 0x1f; i++ )
        {
            if( dvdnav_spu_stream_to_lang( p_sys->dvdnav, i ) != 0xffff )
                ESNew( p_demux, 0xbd20 + i );
        }
        /* END HACK */
Gildas Bazin's avatar
 
Gildas Bazin committed
907 908
        break;
    }
909

Gildas Bazin's avatar
 
Gildas Bazin committed
910 911 912 913 914 915
    case DVDNAV_AUDIO_STREAM_CHANGE:
    {
        dvdnav_audio_stream_change_event_t *event =
            (dvdnav_audio_stream_change_event_t*)packet;
        msg_Dbg( p_demux, "DVDNAV_AUDIO_STREAM_CHANGE" );
        msg_Dbg( p_demux, "     - physical=%d", event->physical );
Laurent Aimar's avatar
Laurent Aimar committed
916
        /* TODO */
Gildas Bazin's avatar
 
Gildas Bazin committed
917 918
        break;
    }
919

Gildas Bazin's avatar
 
Gildas Bazin committed
920 921
    case DVDNAV_VTS_CHANGE:
    {
Laurent Aimar's avatar
Laurent Aimar committed
922 923 924
        int32_t i_title = 0;
        int32_t i_part  = 0;

Gildas Bazin's avatar
 
Gildas Bazin committed
925 926 927 928 929
        dvdnav_vts_change_event_t *event = (dvdnav_vts_change_event_t*)packet;
        msg_Dbg( p_demux, "DVDNAV_VTS_CHANGE" );
        msg_Dbg( p_demux, "     - vtsN=%d", event->new_vtsN );
        msg_Dbg( p_demux, "     - domain=%d", event->new_domain );

Gildas Bazin's avatar
 
Gildas Bazin committed
930 931 932
        /* reset PCR */
        es_out_Control( p_demux->out, ES_OUT_RESET_PCR );

933
        for( int i = 0; i < PS_TK_COUNT; i++ )
Gildas Bazin's avatar
 
Gildas Bazin committed
934 935
        {
            ps_track_t *tk = &p_sys->tk[i];
936
            if( tk->b_configured )
Gildas Bazin's avatar
 
Gildas Bazin committed
937
            {
938 939
                es_format_Clean( &tk->fmt );
                if( tk->es ) es_out_Del( p_demux->out, tk->es );
Gildas Bazin's avatar
 
Gildas Bazin committed
940
            }
941
            tk->b_configured = false;
Gildas Bazin's avatar
 
Gildas Bazin committed
942
        }
943

944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963
        uint32_t i_width, i_height;
        if( dvdnav_get_video_resolution( p_sys->dvdnav,
                                         &i_width, &i_height ) )
            i_width = i_height = 0;
        switch( dvdnav_get_video_aspect( p_sys->dvdnav ) )
        {
        case 0:
            p_sys->sar.i_num = 4 * i_height;
            p_sys->sar.i_den = 3 * i_width;
            break;
        case 3:
            p_sys->sar.i_num = 16 * i_height;
            p_sys->sar.i_den =  9 * i_width;
            break;
        default:
            p_sys->sar.i_num = 0;
            p_sys->sar.i_den = 0;
            break;
        }

Laurent Aimar's avatar
Laurent Aimar committed
964 965
        if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
                                       &i_part ) == DVDNAV_STATUS_OK )
966
        {
Laurent Aimar's avatar
Laurent Aimar committed
967 968 969 970 971
            if( i_title >= 0 && i_title < p_sys->i_title &&
                p_demux->info.i_title != i_title )
            {
                p_demux->info.i_update |= INPUT_UPDATE_TITLE;
                p_demux->info.i_title = i_title;
972 973
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
974 975
        break;
    }
976

Gildas Bazin's avatar
 
Gildas Bazin committed
977 978
    case DVDNAV_CELL_CHANGE:
    {
Laurent Aimar's avatar
Laurent Aimar committed
979 980 981
        int32_t i_title = 0;
        int32_t i_part  = 0;

Gildas Bazin's avatar
 
Gildas Bazin committed
982 983 984 985 986
        dvdnav_cell_change_event_t *event =
            (dvdnav_cell_change_event_t*)packet;
        msg_Dbg( p_demux, "DVDNAV_CELL_CHANGE" );
        msg_Dbg( p_demux, "     - cellN=%d", event->cellN );
        msg_Dbg( p_demux, "     - pgN=%d", event->pgN );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
987 988 989 990 991
        msg_Dbg( p_demux, "     - cell_length=%"PRId64, event->cell_length );
        msg_Dbg( p_demux, "     - pg_length=%"PRId64, event->pg_length );
        msg_Dbg( p_demux, "     - pgc_length=%"PRId64, event->pgc_length );
        msg_Dbg( p_demux, "     - cell_start=%"PRId64, event->cell_start );
        msg_Dbg( p_demux, "     - pg_start=%"PRId64, event->pg_start );
Laurent Aimar's avatar
Laurent Aimar committed
992

Sebastian Ramacher's avatar
Sebastian Ramacher committed
993
        /* Store the length in time of the current PGC */
994
        p_sys->i_pgc_length = event->pgc_length / 90 * 1000;
995 996
        p_sys->i_vobu_index = 0;
        p_sys->i_vobu_flush = 0;
997

Laurent Aimar's avatar
Laurent Aimar committed
998 999 1000 1001
        /* FIXME is it correct or there is better way to know chapter change */
        if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
                                       &i_part ) == DVDNAV_STATUS_OK )
        {
1002
            if( i_title >= 0 && i_title < p_sys->i_title )
Laurent Aimar's avatar
Laurent Aimar committed
1003
            {
1004 1005 1006
                p_demux->info.i_update |= INPUT_UPDATE_TITLE;
                p_demux->info.i_title = i_title;

1007
                if( i_part >= 1 && i_part <= p_sys->title[i_title]->i_seekpoint )
1008 1009 1010 1011
                {
                    p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
                    p_demux->info.i_seekpoint = i_part - 1;
                }
Laurent Aimar's avatar
Laurent Aimar committed
1012 1013
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
1014 1015
        break;
    }
Laurent Aimar's avatar
Laurent Aimar committed
1016

Gildas Bazin's avatar
 
Gildas Bazin committed
1017 1018
    case DVDNAV_NAV_PACKET:
    {
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033