From 51e76e128b736d2cc722ba37e300179bc00617c1 Mon Sep 17 00:00:00 2001 From: Gildas Bazin Date: Fri, 25 Jun 2004 00:09:41 +0000 Subject: [PATCH] * modules/access/dvdread, modules/access/dvdread.c: + major rewrite of the dvdread module. + dvdread is now an access_demux module. --- configure.ac | 129 ++- modules/access/Modules.am | 2 +- modules/access/dvdread.c | 1269 +++++++++++++++++++++++++++++ modules/access/dvdread/Modules.am | 6 - modules/access/dvdread/dvdread.c | 52 -- modules/access/dvdread/input.c | 1268 ---------------------------- modules/access/dvdread/input.h | 64 -- 7 files changed, 1334 insertions(+), 1456 deletions(-) create mode 100644 modules/access/dvdread.c delete mode 100644 modules/access/dvdread/Modules.am delete mode 100644 modules/access/dvdread/dvdread.c delete mode 100644 modules/access/dvdread/input.c delete mode 100644 modules/access/dvdread/input.h diff --git a/configure.ac b/configure.ac index c43998b8de..e02b0a8375 100644 --- a/configure.ac +++ b/configure.ac @@ -1211,71 +1211,70 @@ if test "${enable_livedotcom}" = "yes"; then fi fi -dnl -dnl dnl -dnl dnl dvdread module: check for libdvdread -dnl dnl -dnl AC_ARG_ENABLE(dvdread, -dnl [ --enable-dvdread dvdread input module (default disabled)]) -dnl if test "${enable_dvdread}" != "no" -dnl then -dnl AC_ARG_WITH(dvdread, -dnl [ --with-dvdread=PATH libdvdread headers and libraries]) -dnl AC_ARG_WITH(dvdread-tree, -dnl [ --with-dvdread-tree=PATH libdvdread tree for static linking]) -dnl if test -z "${with_dvdread}" -dnl then -dnl if test -z "${with_dvdread_tree}" -dnl then -dnl AC_CHECK_HEADERS(dvdread/dvd_reader.h, -dnl [ AX_ADD_PLUGINS([dvdread]) -dnl AX_ADD_LDFLAGS([dvdread],[-ldvdread ${LDFLAGS_dvdcss}]) -dnl ],[ -dnl if test -n "${enable_dvdread}" -dnl then -dnl AC_MSG_WARN([Please get libdvdread from http://www.dtek.chalmers.se/groups/dvd/downloads.shtml]) -dnl AC_MSG_ERROR([cannot find libdvdread headers]) -dnl fi -dnl ]) -dnl else -dnl AC_MSG_CHECKING(for libdvdread.a in ${with_dvdread_tree}) -dnl real_dvdread_tree="`cd ${with_dvdread_tree} 2>/dev/null && pwd`" -dnl if test -z "${real_dvdread_tree}" -dnl then -dnl dnl The given directory can't be found -dnl AC_MSG_RESULT(no) -dnl AC_MSG_ERROR([cannot cd to ${with_dvdread_tree}]) -dnl fi -dnl if test -f "${real_dvdread_tree}/dvdread/.libs/libdvdread.a" -dnl then -dnl dnl Use a custom libdvdread -dnl AC_MSG_RESULT(${real_dvdread_tree}/dvdread/.libs/libdvdread.a) -dnl AX_ADD_BUILTINS([dvdread]) -dnl AX_ADD_LDFLAGS([dvdread],[-L${real_dvdread_tree}/dvdread/.libs -ldvdread ${LDFLAGS_dvdcss}]) -dnl AX_ADD_CPPFLAGS([dvdread],[-I${real_dvdread_tree}]) -dnl else -dnl dnl The given libdvdread wasn't built -dnl AC_MSG_RESULT(no) -dnl AC_MSG_ERROR([cannot find ${real_dvdread_tree}/dvdread/.libs/libdvdread.a, make sure you compiled libdvdread in ${with_dvdread_tree}]) -dnl fi -dnl fi -dnl else -dnl AC_MSG_CHECKING(for dvdread headers in ${with_dvdread}) -dnl if test -f ${with_dvdread}/include/dvdread/dvd_reader.h -dnl then -dnl dnl Use ${with_dvdread}/include/dvdread/dvd_reader.h -dnl AC_MSG_RESULT(yes) -dnl AX_ADD_PLUGINS([dvdread]) -dnl AX_ADD_LDFLAGS([dvdread],[-L${with_dvdread}/lib -ldvdread ${LDFLAGS_dvdcss}]) -dnl AX_ADD_CPPFLAGS([dvdread],[-I${with_dvdread}/include]) -dnl else -dnl dnl No libdvdread could be found, sorry -dnl AC_MSG_RESULT(no) -dnl AC_MSG_ERROR([cannot find ${with_dvdread}/include/dvdread/dvd_reader.h]) -dnl fi -dnl fi -dnl fi -dnl + +dnl +dnl dvdread module: check for libdvdread +dnl +AC_ARG_ENABLE(dvdread, +[ --enable-dvdread dvdread input module (default disabled)]) +if test "${enable_dvdread}" != "no" +then + AC_ARG_WITH(dvdread, + [ --with-dvdread=PATH libdvdread headers and libraries]) + AC_ARG_WITH(dvdread-tree, + [ --with-dvdread-tree=PATH libdvdread tree for static linking]) + if test -z "${with_dvdread}" + then + if test -z "${with_dvdread_tree}" + then + AC_CHECK_HEADERS(dvdread/dvd_reader.h, + [ AX_ADD_PLUGINS([dvdread]) + AX_ADD_LDFLAGS([dvdread],[-ldvdread ${LDFLAGS_dvdcss}]) + ],[ + if test -n "${enable_dvdread}" + then + AC_MSG_WARN([Please get libdvdread from http://www.dtek.chalmers.se/groups/dvd/downloads.shtml]) + AC_MSG_ERROR([cannot find libdvdread headers]) + fi + ]) + else + AC_MSG_CHECKING(for libdvdread.a in ${with_dvdread_tree}) + real_dvdread_tree="`cd ${with_dvdread_tree} 2>/dev/null && pwd`" + if test -z "${real_dvdread_tree}" + then + dnl The given directory can't be found + AC_MSG_RESULT(no) + AC_MSG_ERROR([cannot cd to ${with_dvdread_tree}]) + fi + if test -f "${real_dvdread_tree}/dvdread/.libs/libdvdread.a" + then + dnl Use a custom libdvdread + AC_MSG_RESULT(${real_dvdread_tree}/dvdread/.libs/libdvdread.a) + AX_ADD_BUILTINS([dvdread]) + AX_ADD_LDFLAGS([dvdread],[-L${real_dvdread_tree}/dvdread/.libs -ldvdread ${LDFLAGS_dvdcss}]) + AX_ADD_CPPFLAGS([dvdread],[-I${real_dvdread_tree}]) + else + dnl The given libdvdread wasn't built + AC_MSG_RESULT(no) + AC_MSG_ERROR([cannot find ${real_dvdread_tree}/dvdread/.libs/libdvdread.a, make sure you compiled libdvdread in ${with_dvdread_tree}]) + fi + fi + else + AC_MSG_CHECKING(for dvdread headers in ${with_dvdread}) + if test -f ${with_dvdread}/include/dvdread/dvd_reader.h + then + dnl Use ${with_dvdread}/include/dvdread/dvd_reader.h + AC_MSG_RESULT(yes) + AX_ADD_PLUGINS([dvdread]) + AX_ADD_LDFLAGS([dvdread],[-L${with_dvdread}/lib -ldvdread ${LDFLAGS_dvdcss}]) + AX_ADD_CPPFLAGS([dvdread],[-I${with_dvdread}/include]) + else + dnl No libdvdread could be found, sorry + AC_MSG_RESULT(no) + AC_MSG_ERROR([cannot find ${with_dvdread}/include/dvdread/dvd_reader.h]) + fi + fi +fi dnl dnl libdvdnav plugin diff --git a/modules/access/Modules.am b/modules/access/Modules.am index 12dfb04c95..698415b2bb 100644 --- a/modules/access/Modules.am +++ b/modules/access/Modules.am @@ -4,8 +4,8 @@ SOURCES_access_udp = udp.c SOURCES_access_tcp = tcp.c SOURCES_access_http = http.c SOURCES_access_ftp = ftp.c +SOURCES_dvdread = dvdread.c SOURCES_slp = slp.c -SOURCES_access2 = access2.c SOURCES_cdda = \ cdda.c \ vcd/cdrom.c \ diff --git a/modules/access/dvdread.c b/modules/access/dvdread.c new file mode 100644 index 0000000000..3140680f6d --- /dev/null +++ b/modules/access/dvdread.c @@ -0,0 +1,1269 @@ +/***************************************************************************** + * dvdread.c : DvdRead input module for vlc + ***************************************************************************** + * Copyright (C) 2001-2004 VideoLAN + * $Id$ + * + * Authors: Stéphane Borel + * Gildas Bazin + * + * 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 +#include /* malloc(), free() */ +#include /* strdup() */ + +#include +#include + +#include "iso_lang.h" + +#include "../demux/ps.h" + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define CACHING_TEXT N_("caching value in ms") +#define CACHING_LONGTEXT N_( \ + "Allows you to modify the default caching value for DVDread streams. " \ + "This value should be set in millisecond units." ) + +#define CSSMETHOD_TEXT N_("Method used by libdvdcss for decryption") +#define CSSMETHOD_LONGTEXT N_( \ + "Set the method used by libdvdcss for key decryption.\n" \ + "title: decrypted title key is guessed from the encrypted sectors of " \ + "the stream. Thus it should work with a file as well as the " \ + "DVD device. But it sometimes takes much time to decrypt a title " \ + "key and may even fail. With this method, the key is only checked "\ + "at the beginning of each title, so it won't work if the key " \ + "changes in the middle of a title.\n" \ + "disc: the disc key is first cracked, then all title keys can be " \ + "decrypted instantly, which allows us to check them often.\n" \ + "key: the same as \"disc\" if you don't have a file with player keys " \ + "at compilation time. If you do, the decryption of the disc key " \ + "will be faster with this method. It is the one that was used by " \ + "libcss.\n" \ + "The default method is: key.") + +static char *psz_css_list[] = { "title", "disc", "key" }; +static char *psz_css_list_text[] = { N_("title"), N_("Disc"), N_("Key") }; + +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); + +vlc_module_begin(); + set_description( _("DVDRead Input") ); + add_integer( "dvdread-caching", DEFAULT_PTS_DELAY / 1000, NULL, + CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE ); + add_string( "dvdread-css-method", NULL, NULL, CSSMETHOD_TEXT, + CSSMETHOD_LONGTEXT, VLC_TRUE ); + change_string_list( psz_css_list, psz_css_list_text, 0 ); + set_capability( "access_demux", 0 ); + add_shortcut( "dvd" ); + add_shortcut( "dvdread" ); + set_callbacks( Open, Close ); +vlc_module_end(); + +/* how many blocks DVDRead will read in each loop */ +#define DVD_BLOCK_READ_ONCE 64 + +/***************************************************************************** + * Local prototypes + *****************************************************************************/ + +struct demux_sys_t +{ + /* DVDRead state */ + dvd_reader_t *p_dvdread; + dvd_file_t *p_title; + + ifo_handle_t *p_vmg_file; + ifo_handle_t *p_vts_file; + + unsigned int i_title; + unsigned int i_chapter, i_chapters; + unsigned int i_angle, i_angles; + + tt_srpt_t *p_tt_srpt; + pgc_t *p_cur_pgc; + + dsi_t dsi_pack; + + int i_ttn; + + unsigned int i_pack_len; + unsigned int i_cur_block; + unsigned int i_next_vobu; + + /* Current title start/end blocks */ + unsigned int i_title_start_block; + unsigned int i_title_end_block; + unsigned int i_title_blocks; + unsigned int i_title_offset; + + unsigned int i_title_start_cell; + unsigned int i_cur_cell; + unsigned int i_next_cell; + + /* track */ + ps_track_t tk[PS_TK_COUNT]; + + /* for spu variables */ + input_thread_t *p_input; + + /* FIXME */ + uint8_t alpha[4]; + uint32_t clut[16]; + + /* */ + int i_aspect; + + int i_titles; + input_title_t **titles; +}; + +static char *ParseCL( vlc_object_t *, char *, vlc_bool_t, int *, int *, int *); + +static int Control ( demux_t *, int, va_list ); +static int Demux ( demux_t * ); +static int DemuxBlock( demux_t *, uint8_t *, int ); + +enum +{ + AR_SQUARE_PICTURE = 1, /* square pixels */ + AR_3_4_PICTURE = 2, /* 3:4 picture (TV) */ + AR_16_9_PICTURE = 3, /* 16:9 picture (wide screen) */ + AR_221_1_PICTURE = 4, /* 2.21:1 picture (movie) */ +}; + +static void DemuxTitles( demux_t *, int *, int *, int * ); +static void ESNew( demux_t *, int, int ); + +static int DvdReadSetArea ( demux_t *, int, int, int ); +static void DvdReadSeek ( demux_t *, int ); +static void DvdReadHandleDSI( demux_t *, uint8_t * ); +static void DvdReadFindCell ( demux_t * ); + +/***************************************************************************** + * Open: + *****************************************************************************/ +static int Open( vlc_object_t *p_this ) +{ + demux_t *p_demux = (demux_t*)p_this; + demux_sys_t *p_sys; + int i_title, i_chapter, i_angle; + char *psz_name; + char *psz_dvdcss_env; + dvd_reader_t *p_dvdread; + ifo_handle_t *p_vmg_file; + + psz_name = ParseCL( VLC_OBJECT(p_demux), p_demux->psz_path, VLC_TRUE, + &i_title, &i_chapter, &i_angle ); + if( !psz_name ) + { + return VLC_EGENERIC; + } + + /* Override environment variable DVDCSS_METHOD with config option + * (FIXME: this creates a small memory leak) */ + psz_dvdcss_env = config_GetPsz( p_demux, "dvdread-css-method" ); + if( psz_dvdcss_env && *psz_dvdcss_env ) + { + char *psz_env; + + psz_env = malloc( strlen("DVDCSS_METHOD=") + + strlen( psz_dvdcss_env ) + 1 ); + + if( !psz_env ) + { + free( psz_dvdcss_env ); + return VLC_ENOMEM; + } + + sprintf( psz_env, "%s%s", "DVDCSS_METHOD=", psz_dvdcss_env ); + + putenv( psz_env ); + } + if( psz_dvdcss_env ) free( psz_dvdcss_env ); + + /* Open dvdread */ + if( !(p_dvdread = DVDOpen( psz_name )) ) + { + msg_Err( p_demux, "DVDRead cannot open source: %s", psz_name ); + free( psz_name ); + return VLC_EGENERIC; + } + free( psz_name ); + + /* Ifo allocation & initialisation */ + if( !( p_vmg_file = ifoOpen( p_dvdread, 0 ) ) ) + { + msg_Warn( p_demux, "cannot open VMG info" ); + return VLC_EGENERIC; + } + msg_Dbg( p_demux, "VMG opened" ); + + /* Fill p_demux field */ + p_demux->pf_demux = Demux; + p_demux->pf_control = Control; + p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); + memset( p_sys, 0, sizeof( demux_sys_t ) ); + + ps_track_init( p_sys->tk ); + p_sys->i_aspect = -1; + + p_sys->p_dvdread = p_dvdread; + p_sys->p_vmg_file = p_vmg_file; + p_sys->p_title = NULL; + p_sys->p_vts_file = NULL; + + p_sys->i_title = p_sys->i_chapter = -1; + p_sys->i_angle = i_angle; + + DemuxTitles( p_demux, &i_title, &i_chapter, &i_angle ); + + DvdReadSetArea( p_demux, i_title - 1, i_chapter, i_angle ); + + /* Update default_pts to a suitable value for dvdread access */ + var_Create( p_demux, "dvdread-caching", + VLC_VAR_INTEGER|VLC_VAR_DOINHERIT ); + + return VLC_SUCCESS; +} + +/***************************************************************************** + * Close: + *****************************************************************************/ +static void Close( vlc_object_t *p_this ) +{ + demux_t *p_demux = (demux_t*)p_this; + demux_sys_t *p_sys = p_demux->p_sys; + int i; + + for( i = 0; i < PS_TK_COUNT; i++ ) + { + ps_track_t *tk = &p_sys->tk[i]; + if( tk->b_seen ) + { + es_format_Clean( &tk->fmt ); + if( tk->es ) es_out_Del( p_demux->out, tk->es ); + } + } + + /* Close libdvdread */ + if( p_sys->p_title ) DVDCloseFile( p_sys->p_title ); + if( p_sys->p_vts_file ) ifoClose( p_sys->p_vts_file ); + if( p_sys->p_vmg_file ) ifoClose( p_sys->p_vmg_file ); + DVDClose( p_sys->p_dvdread ); + + free( p_sys ); +} + +/***************************************************************************** + * Control: + *****************************************************************************/ +static int Control( demux_t *p_demux, int i_query, va_list args ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + double f, *pf; + vlc_bool_t *pb; + int64_t *pi64; + input_title_t ***ppp_title; + int *pi_int; + int i; + + switch( i_query ) + { + case DEMUX_GET_POSITION: + { + pf = (double*) va_arg( args, double* ); + + if( p_sys->i_title_blocks > 0 ) + *pf = (double)p_sys->i_title_offset / p_sys->i_title_blocks; + else + *pf = 0.0; + + return VLC_SUCCESS; + } + case DEMUX_SET_POSITION: + { + f = (double)va_arg( args, double ); + + DvdReadSeek( p_demux, f * p_sys->i_title_blocks ); + + return VLC_SUCCESS; + } + + /* Special for access_demux */ + case DEMUX_CAN_PAUSE: + case DEMUX_CAN_CONTROL_PACE: + /* TODO */ + pb = (vlc_bool_t*)va_arg( args, vlc_bool_t * ); + *pb = VLC_TRUE; + return VLC_SUCCESS; + + case DEMUX_SET_PAUSE_STATE: + return VLC_SUCCESS; + + case DEMUX_GET_TITLE_INFO: + ppp_title = (input_title_t***)va_arg( args, input_title_t*** ); + pi_int = (int*)va_arg( args, int* ); + + /* Duplicate title infos */ + *pi_int = p_sys->i_titles; + *ppp_title = malloc( sizeof(input_title_t **) * p_sys->i_titles ); + for( i = 0; i < p_sys->i_titles; i++ ) + { + (*ppp_title)[i] = vlc_input_title_Duplicate(p_sys->titles[i]); + } + return VLC_SUCCESS; + + case DEMUX_SET_TITLE: + i = (int)va_arg( args, int ); + if( DvdReadSetArea( p_demux, i, 0, -1 ) != VLC_SUCCESS ) + { + msg_Warn( p_demux, "cannot set title/chapter" ); + return VLC_EGENERIC; + } + p_demux->info.i_update |= + INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT; + p_demux->info.i_title = i; + p_demux->info.i_seekpoint = 0; + return VLC_SUCCESS; + + case DEMUX_SET_SEEKPOINT: + i = (int)va_arg( args, int ); + if( DvdReadSetArea( p_demux, -1, i, -1 ) != VLC_SUCCESS ) + { + 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: + pi64 = (int64_t*)va_arg( args, int64_t * ); + *pi64 = (int64_t)var_GetInteger( p_demux, "dvdread-caching" )*1000; + return VLC_SUCCESS; + + /* TODO implement others */ + default: + return VLC_EGENERIC; + } +} + +/***************************************************************************** + * Demux: + *****************************************************************************/ +static int Demux( demux_t *p_demux ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + + uint8_t p_buffer[DVD_VIDEO_LB_LEN * DVD_BLOCK_READ_ONCE]; + int i_blocks_once, i_read; + int i; + + /* + * Playback by cell in this pgc, starting at the cell for our chapter. + */ + + /* + * Check end of pack, and select the following one + */ + if( !p_sys->i_pack_len ) + { + /* Read NAV packet */ + if( DVDReadBlocks( p_sys->p_title, p_sys->i_next_vobu, + 1, p_buffer ) != 1 ) + { + msg_Err( p_demux, "read failed for block %d", p_sys->i_next_vobu ); + return -1; + } + + /* Basic check to be sure we don't have a empty title + * go to next title if so */ + //assert( p_buffer[41] == 0xbf && p_buffer[1027] == 0xbf ); + + /* Parse the contained dsi packet */ + DvdReadHandleDSI( p_demux, p_buffer ); + + /* End of title */ + if( p_sys->i_next_vobu > p_sys->i_title_end_block ) + { + if( p_sys->i_title + 1 >= p_sys->i_titles ) return 0; /* EOF */ + + DvdReadSetArea( p_demux, p_sys->i_title + 1, 0, -1 ); + } + + if( p_sys->i_pack_len <= 0 ) + { + msg_Err( p_demux, "i_pack_len <= 0. This shouldn't happen!" ); + return 0; /* EOF */ + } + + /* FIXME: Ugly kludge: we send the pack block to the input for it + * sometimes has a zero scr and restart the sync */ + p_sys->i_cur_block++; + p_sys->i_title_offset++; + + DemuxBlock( p_demux, p_buffer, DVD_VIDEO_LB_LEN ); + } + + if( p_sys->i_cur_block > p_sys->i_title_end_block ) + { + if( p_sys->i_title + 1 >= p_sys->i_titles ) return 0; /* EOF */ + + DvdReadSetArea( p_demux, p_sys->i_title + 1, 0, -1 ); + } + + /* + * Read actual data + */ + i_blocks_once = __MIN( p_sys->i_pack_len, DVD_BLOCK_READ_ONCE ); + p_sys->i_pack_len -= i_blocks_once; + + /* Reads from DVD */ + i_read = DVDReadBlocks( p_sys->p_title, p_sys->i_cur_block, + i_blocks_once, p_buffer ); + if( i_read != i_blocks_once ) + { + msg_Err( p_demux, "read failed for %d/%d blocks at 0x%02x", + i_read, i_blocks_once, p_sys->i_cur_block ); + return -1; + } + + p_sys->i_cur_block += i_read; + p_sys->i_title_offset += i_read; + +#if 0 + msg_Dbg( p_demux, "i_blocks: %d len: %d current: 0x%02x", + i_read, p_sys->i_pack_len, p_sys->i_cur_block ); +#endif + + for( i = 0; i < i_read; i++ ) + { + DemuxBlock( p_demux, p_buffer + i * DVD_VIDEO_LB_LEN, + DVD_VIDEO_LB_LEN ); + } + +#undef p_pgc + + return 1; +} + +/***************************************************************************** + * DemuxBlock: demux a given block + *****************************************************************************/ +static int DemuxBlock( demux_t *p_demux, uint8_t *pkt, int i_pkt ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + uint8_t *p = pkt; + + while( p < &pkt[i_pkt] ) + { + int i_size = ps_pkt_size( p, &pkt[i_pkt] - p ); + block_t *p_pkt; + if( i_size <= 0 ) + { + break; + } + + /* Create a block */ + p_pkt = block_New( p_demux, i_size ); + memcpy( p_pkt->p_buffer, p, i_size); + + /* Parse it and send it */ + switch( 0x100 | p[3] ) + { + case 0x1b9: + case 0x1bb: + case 0x1bc: + +#ifdef DVDREAD_DEBUG + if( p[3] == 0xbc ) + { + msg_Warn( p_demux, "received a PSM packet" ); + } + else if( p[3] == 0xbb ) + { + msg_Warn( p_demux, "received a SYSTEM packet" ); + } +#endif + block_Release( p_pkt ); + break; + + case 0x1ba: + { + int64_t i_scr; + int i_mux_rate; + if( !ps_pkt_parse_pack( p_pkt, &i_scr, &i_mux_rate ) ) + { + es_out_Control( p_demux->out, ES_OUT_SET_PCR, i_scr ); + } + block_Release( p_pkt ); + break; + } + default: + { + int i_id = ps_pkt_id( p_pkt ); + if( i_id >= 0xc0 ) + { + ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(i_id)]; + + if( !tk->b_seen ) + { + ESNew( p_demux, i_id, 0 ); + } + if( tk->b_seen && tk->es && + !ps_pkt_parse_pes( p_pkt, tk->i_skip ) ) + { + es_out_Send( p_demux->out, tk->es, p_pkt ); + } + else + { + block_Release( p_pkt ); + } + } + else + { + block_Release( p_pkt ); + } + break; + } + } + + p += i_size; + } + + return VLC_SUCCESS; +} + +/***************************************************************************** + * ESNew: register a new elementary stream + *****************************************************************************/ +static void ESNew( demux_t *p_demux, int i_id, int i_lang ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + ps_track_t *tk = &p_sys->tk[PS_ID_TO_TK(i_id)]; + char psz_language[3]; + + if( tk->b_seen ) return; + + if( ps_track_fill( tk, i_id ) ) + { + msg_Warn( p_demux, "unknown codec for id=0x%x", i_id ); + return; + } + + psz_language[0] = psz_language[1] = psz_language[2] = 0; + if( i_lang && i_lang != 0xffff ) + { + psz_language[0] = (i_lang >> 8)&0xff; + psz_language[1] = (i_lang )&0xff; + } + + /* Add a new ES */ + if( tk->fmt.i_cat == VIDEO_ES ) + { + if( p_sys->i_aspect >= 0 ) + { + tk->fmt.video.i_aspect = p_sys->i_aspect; + } + } + else if( tk->fmt.i_cat == AUDIO_ES ) + { + int i_audio = -1; + /* find the audio number PLEASE find another way */ + if( (i_id&0xbdf8) == 0xbd88 ) /* dts */ + { + i_audio = i_id&0x07; + } + else if( (i_id&0xbdf0) == 0xbd80 ) /* a52 */ + { + i_audio = i_id&0xf; + } + else if( (i_id&0xbdf0) == 0xbda0 ) /* lpcm */ + { + i_audio = i_id&0x1f; + } + else if( ( i_id&0xe0 ) == 0xc0 ) /* mpga */ + { + i_audio = i_id&0x1f; + } + + if( psz_language[0] ) tk->fmt.psz_language = strdup( psz_language ); + } + else if( tk->fmt.i_cat == SPU_ES ) + { + /* Palette */ + tk->fmt.subs.spu.palette[0] = 0xBeef; + memcpy( &tk->fmt.subs.spu.palette[1], p_sys->clut, + 16 * sizeof( uint32_t ) ); + + if( psz_language[0] ) tk->fmt.psz_language = strdup( psz_language ); + } + + tk->es = es_out_Add( p_demux->out, &tk->fmt ); + tk->b_seen = VLC_TRUE; +} + +/***************************************************************************** + * DvdReadSetArea: initialize input data for title x, chapter y. + * It should be called for each user navigation request. + ***************************************************************************** + * Take care that i_title and i_chapter start from 0. + *****************************************************************************/ +static int DvdReadSetArea( demux_t *p_demux, int i_title, int i_chapter, + int i_angle ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + int pgc_id = 0; + int pgn = 0; + int i; + vlc_value_t val; + +#define p_pgc p_sys->p_cur_pgc +#define p_vmg p_sys->p_vmg_file +#define p_vts p_sys->p_vts_file + + if( i_title >= 0 && i_title < p_sys->i_titles && + i_title != p_sys->i_title ) + { + int i_start_cell, i_end_cell; + + if( p_sys->p_title != NULL ) DVDCloseFile( p_sys->p_title ); + if( p_vts != NULL ) ifoClose( p_vts ); + p_sys->i_title = i_title; + + /* + * We have to load all title information + */ + msg_Dbg( p_demux, "open VTS %d, for title %d", + p_vmg->tt_srpt->title[i_title].title_set_nr, i_title + 1 ); + + /* Ifo vts */ + if( !( p_vts = ifoOpen( p_sys->p_dvdread, + p_vmg->tt_srpt->title[i_title].title_set_nr ) ) ) + { + msg_Err( p_demux, "fatal error in vts ifo" ); + return VLC_EGENERIC; + } + + /* Title position inside the selected vts */ + p_sys->i_ttn = p_vmg->tt_srpt->title[i_title].vts_ttn; + + /* Find title start/end */ + pgc_id = p_vts->vts_ptt_srpt->title[p_sys->i_ttn - 1].ptt[0].pgcn; + pgn = p_vts->vts_ptt_srpt->title[p_sys->i_ttn - 1].ptt[0].pgn; + p_pgc = p_vts->vts_pgcit->pgci_srp[pgc_id - 1].pgc; + + p_sys->i_title_start_cell = + i_start_cell = p_pgc->program_map[pgn - 1] - 1; + p_sys->i_title_start_block = + p_pgc->cell_playback[i_start_cell].first_sector; + + i_end_cell = p_pgc->nr_of_cells - 1; + p_sys->i_title_end_block = + p_pgc->cell_playback[i_end_cell].last_sector; + + p_sys->i_title_offset = 0; + + p_sys->i_title_blocks = 0; + for( i = i_start_cell; i <= i_end_cell; i++ ) + { + p_sys->i_title_blocks += p_pgc->cell_playback[i].last_sector - + p_pgc->cell_playback[i].first_sector + 1; + } + + msg_Dbg( p_demux, "title %d vts_title %d pgc %d pgn %d " + "start %d end %d blocks: %d", + i_title + 1, p_sys->i_ttn, pgc_id, pgn, + p_sys->i_title_start_block, p_sys->i_title_end_block, + p_sys->i_title_blocks ); + + /* + * Set properties for current chapter + */ + p_sys->i_chapter = 0; + p_sys->i_chapters = + p_vts->vts_ptt_srpt->title[p_sys->i_ttn - 1].nr_of_ptts; + + pgc_id = p_vts->vts_ptt_srpt->title[ + p_sys->i_ttn - 1].ptt[p_sys->i_chapter].pgcn; + pgn = p_vts->vts_ptt_srpt->title[ + p_sys->i_ttn - 1].ptt[p_sys->i_chapter].pgn; + + p_pgc = p_vts->vts_pgcit->pgci_srp[pgc_id - 1].pgc; + p_sys->i_pack_len = 0; + p_sys->i_next_cell = + p_sys->i_cur_cell = p_pgc->program_map[pgn - 1] - 1; + DvdReadFindCell( p_demux ); + + p_sys->i_next_vobu = p_sys->i_cur_block = + p_pgc->cell_playback[p_sys->i_cur_cell].first_sector; + + /* + * Angle management + */ + p_sys->i_angles = p_vmg->tt_srpt->title[i_title].nr_of_angles; + if( p_sys->i_angle > p_sys->i_angles ) p_sys->i_angle = 1; + + /* + * We've got enough info, time to open the title set data. + */ + if( !( p_sys->p_title = DVDOpenFile( p_sys->p_dvdread, + p_vmg->tt_srpt->title[i_title].title_set_nr, + DVD_READ_TITLE_VOBS ) ) ) + { + msg_Err( p_demux, "cannot open title (VTS_%02d_1.VOB)", + p_vmg->tt_srpt->title[i_title].title_set_nr ); + return VLC_EGENERIC; + } + + //IfoPrintTitle( p_demux ); + + /* + * Destroy obsolete ES by reinitializing program 0 + * and find all ES in title with ifo data + */ + es_out_Control( p_demux->out, ES_OUT_RESET_PCR ); + + for( i = 0; i < PS_TK_COUNT; i++ ) + { + ps_track_t *tk = &p_sys->tk[i]; + if( tk->b_seen ) + { + es_format_Clean( &tk->fmt ); + if( tk->es ) es_out_Del( p_demux->out, tk->es ); + } + tk->b_seen = VLC_FALSE; + } + + if( p_demux->info.i_title != i_title ) + { + p_demux->info.i_update |= + INPUT_UPDATE_TITLE | INPUT_UPDATE_SEEKPOINT; + p_demux->info.i_title = i_title; + p_demux->info.i_seekpoint = 0; + } + + /* TODO: re-add angles */ + + + ESNew( p_demux, 0xe0, 0 ); /* Video, FIXME ? */ + +#define audio_control \ + p_sys->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->audio_control[i-1] + + /* Audio ES, in the order they appear in the .ifo */ + for( i = 1; i <= p_vts->vtsi_mat->nr_of_vts_audio_streams; i++ ) + { + int i_position = 0; + uint16_t i_id; + + //IfoPrintAudio( p_demux, i ); + + /* Audio channel is active if first byte is 0x80 */ + if( audio_control & 0x8000 ) + { + i_position = ( audio_control & 0x7F00 ) >> 8; + + msg_Dbg( p_demux, "audio position %d", i_position ); + switch( p_vts->vtsi_mat->vts_audio_attr[i - 1].audio_format ) + { + case 0x00: /* A52 */ + i_id = (0x80 + i_position) | 0xbd00; + break; + case 0x02: + case 0x03: /* MPEG audio */ + i_id = 0xc000 + i_position; + break; + case 0x04: /* LPCM */ + i_id = (0xa0 + i_position) | 0xbd00; + break; + case 0x06: /* DTS */ + i_id = (0x88 + i_position) | 0xbd00; + break; + default: + i_id = 0; + msg_Err( p_demux, "unknown audio type %.2x", + p_vts->vtsi_mat->vts_audio_attr[i - 1].audio_format ); + } + + ESNew( p_demux, i_id, p_sys->p_vts_file->vtsi_mat-> + vts_audio_attr[i - 1].lang_code ); + } + } +#undef audio_control + +#define spu_control \ + p_sys->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->subp_control[i-1] + + /* Sub Picture ES */ + for( i = 1; i <= p_vts->vtsi_mat->nr_of_vts_subp_streams; i++ ) + { + int i_position = 0; + uint16_t i_id; + + //IfoPrintSpu( p_sys, i ); + msg_Dbg( p_demux, "spu %d 0x%02x", i, spu_control ); + + if( spu_control & 0x80000000 ) + { + /* there are several streams for one spu */ + if( p_vts->vtsi_mat->vts_video_attr.display_aspect_ratio ) + { + /* 16:9 */ + switch( p_vts->vtsi_mat->vts_video_attr.permitted_df ) + { + case 1: + i_position = spu_control & 0xff; + break; + case 2: + i_position = ( spu_control >> 8 ) & 0xff; + break; + default: + i_position = ( spu_control >> 16 ) & 0xff; + break; + } + } + else + { + /* 4:3 */ + i_position = ( spu_control >> 24 ) & 0x7F; + } + + i_id = (0x20 + i_position) | 0xbd00; + + ESNew( p_demux, i_id, p_sys->p_vts_file->vtsi_mat-> + vts_subp_attr[i - 1].lang_code ); + } + } +#undef spu_control + + } + else + { + /* TODO: update input ? */ + } + + /* + * Chapter selection + */ + + if( i_chapter >= 0 && i_chapter <= p_sys->i_chapters && + i_chapter != p_sys->i_chapter ) + { + pgc_id = p_vts->vts_ptt_srpt->title[ + p_sys->i_ttn - 1].ptt[i_chapter].pgcn; + pgn = p_vts->vts_ptt_srpt->title[ + p_sys->i_ttn - 1].ptt[i_chapter].pgn; + + p_pgc = p_vts->vts_pgcit->pgci_srp[pgc_id - 1].pgc; + + p_sys->i_cur_cell = p_pgc->program_map[pgn - 1] - 1; + p_sys->i_chapter = i_chapter; + DvdReadFindCell( p_demux ); + + p_sys->i_title_offset = 0; + for( i = p_sys->i_title_start_cell; i < p_sys->i_cur_cell; i++ ) + { + p_sys->i_title_offset += p_pgc->cell_playback[i].last_sector - + p_pgc->cell_playback[i].first_sector + 1; + } + + p_sys->i_pack_len = 0; + p_sys->i_next_vobu = p_sys->i_cur_block = + p_pgc->cell_playback[p_sys->i_cur_cell].first_sector; + + if( p_demux->info.i_seekpoint != i_chapter ) + { + p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT; + p_demux->info.i_seekpoint = i_chapter; + } + } + +#undef p_pgc +#undef p_vts +#undef p_vmg + + return VLC_SUCCESS; +} + +/***************************************************************************** + * DvdReadSeek : Goes to a given position on the stream. + ***************************************************************************** + * This one is used by the input and translate chronological position from + * input to logical position on the device. + *****************************************************************************/ +static void DvdReadSeek( demux_t *p_demux, int i_block_offset ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + unsigned int i_tmp; + unsigned int i_chapter = 0; + unsigned int i_cell = 0; + unsigned int i_vobu = 0; + unsigned int i_sub_cell = 0; + int i_block; + +#define p_pgc p_sys->p_cur_pgc +#define p_vts p_sys->p_vts_file + + /* Find cell */ + p_sys->i_title_offset = i_block = i_block_offset; + while( i_block >= (int)p_pgc->cell_playback[i_cell].last_sector - + (int)p_pgc->cell_playback[i_cell].first_sector + 1 ) + { + i_cell++; + + i_block -= p_pgc->cell_playback[i_cell].last_sector - + p_pgc->cell_playback[i_cell].first_sector + 1; + } + + i_block += p_pgc->cell_playback[i_cell].first_sector; + + /* Find chapter */ + do + { + int pgc_id, pgn; + + i_chapter++; + pgc_id = p_vts->vts_ptt_srpt->title[ + p_sys->i_ttn - 1].ptt[i_chapter].pgcn; + pgn = p_vts->vts_ptt_srpt->title[ + p_sys->i_ttn - 1].ptt[i_chapter].pgn; + + i_tmp = p_vts->vts_pgcit->pgci_srp[pgc_id - 1].pgc->program_map[pgn-1]; + + } while( i_tmp <= i_cell ); + + /* Find vobu */ + while( p_vts->vts_vobu_admap->vobu_start_sectors[i_vobu] <= i_block ) + { + i_vobu++; + } + + /* Find sub_cell */ + while( p_vts->vts_c_adt->cell_adr_table[i_sub_cell].start_sector < + p_vts->vts_vobu_admap->vobu_start_sectors[i_vobu-1] ) + { + i_sub_cell++; + } + +#if 1 + msg_Dbg( p_demux, "cell %d i_sub_cell %d chapter %d vobu %d " + "cell_sector %d vobu_sector %d sub_cell_sector %d", + i_cell, i_sub_cell,i_chapter, i_vobu, + p_sys->p_cur_pgc->cell_playback[i_cell].first_sector, + p_vts->vts_vobu_admap->vobu_start_sectors[i_vobu], + p_vts->vts_c_adt->cell_adr_table[i_sub_cell - 1].start_sector); +#endif + + p_sys->i_cur_block = i_block; + p_sys->i_next_vobu = p_vts->vts_vobu_admap->vobu_start_sectors[i_vobu]; + p_sys->i_pack_len = p_sys->i_next_vobu - i_block; + p_sys->i_cur_cell = i_cell; + p_sys->i_chapter = i_chapter; + DvdReadFindCell( p_demux ); + +#undef p_vts +#undef p_pgc + + return; +} + +/***************************************************************************** + * DvdReadHandleDSI + *****************************************************************************/ +static void DvdReadHandleDSI( demux_t *p_demux, uint8_t *p_data ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + + navRead_DSI( &p_sys->dsi_pack, &p_data[DSI_START_BYTE] ); + + /* + * Determine where we go next. These values are the ones we mostly + * care about. + */ + p_sys->i_cur_block = p_sys->dsi_pack.dsi_gi.nv_pck_lbn; + + /* + * If we're not at the end of this cell, we can determine the next + * VOBU to display using the VOBU_SRI information section of the + * DSI. Using this value correctly follows the current angle, + * avoiding the doubled scenes in The Matrix, and makes our life + * really happy. + */ + if( p_sys->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL ) + { + switch( ( p_sys->dsi_pack.sml_pbi.category & 0xf000 ) >> 12 ) + { + case 0x4: + /* Interleaved unit with no angle */ + if( p_sys->dsi_pack.sml_pbi.ilvu_sa != 0 ) + { + p_sys->i_next_vobu = p_sys->i_cur_block + + p_sys->dsi_pack.sml_pbi.ilvu_sa; + p_sys->i_pack_len = p_sys->dsi_pack.sml_pbi.ilvu_ea; + } + else + { + p_sys->i_next_vobu = p_sys->i_cur_block + + p_sys->dsi_pack.dsi_gi.vobu_ea + 1; + p_sys->i_pack_len = p_sys->dsi_pack.dsi_gi.vobu_ea; + } + break; + case 0x5: + /* vobu is end of ilvu */ + if( p_sys->dsi_pack.sml_agli.data[p_sys->i_angle-1].address ) + { + p_sys->i_next_vobu = p_sys->i_cur_block + + p_sys->dsi_pack.sml_agli.data[p_sys->i_angle-1].address; + p_sys->i_pack_len = p_sys->dsi_pack.sml_pbi.ilvu_ea; + + break; + } + case 0x6: + /* vobu is beginning of ilvu */ + case 0x9: + /* next scr is 0 */ + case 0xa: + /* entering interleaved section */ + case 0x8: + /* non interleaved cells in interleaved section */ + default: + p_sys->i_next_vobu = p_sys->i_cur_block + + ( p_sys->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); + p_sys->i_pack_len = p_sys->dsi_pack.dsi_gi.vobu_ea; + break; + } + } + else + { + p_sys->i_cur_cell = p_sys->i_next_cell; + DvdReadFindCell( p_demux ); + + p_sys->i_pack_len = p_sys->dsi_pack.dsi_gi.vobu_ea; + p_sys->i_next_vobu = + p_sys->p_cur_pgc->cell_playback[p_sys->i_cur_cell].first_sector; + } + +#if 0 + msg_Dbg( p_input, 12, "scr %d lbn 0x%02x vobu_ea %d vob_id %d c_id %d", + p_sys->dsi_pack.dsi_gi.nv_pck_scr, + p_sys->dsi_pack.dsi_gi.nv_pck_lbn, + p_sys->dsi_pack.dsi_gi.vobu_ea, + p_sys->dsi_pack.dsi_gi.vobu_vob_idn, + p_sys->dsi_pack.dsi_gi.vobu_c_idn ); + + msg_Dbg( p_input, 12, "cat 0x%02x ilvu_ea %d ilvu_sa %d size %d", + p_sys->dsi_pack.sml_pbi.category, + p_sys->dsi_pack.sml_pbi.ilvu_ea, + p_sys->dsi_pack.sml_pbi.ilvu_sa, + p_sys->dsi_pack.sml_pbi.size ); + + msg_Dbg( p_input, 12, "next_vobu %d next_ilvu1 %d next_ilvu2 %d", + p_sys->dsi_pack.vobu_sri.next_vobu & 0x7fffffff, + p_sys->dsi_pack.sml_agli.data[ p_sys->i_angle - 1 ].address, + p_sys->dsi_pack.sml_agli.data[ p_sys->i_angle ].address); +#endif +} + +/***************************************************************************** + * DvdReadFindCell + *****************************************************************************/ +static void DvdReadFindCell( demux_t *p_demux ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + + pgc_t *p_pgc; + int pgc_id, pgn; + int i = 0; + +#define cell p_sys->p_cur_pgc->cell_playback + + if( cell[p_sys->i_cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) + { +#if 0 + p_sys->i_next_cell = p_sys->i_cur_cell + p_sys->i_angle_nb; + p_sys->i_cur_cell += p_sys->i_angle - 1; +#else + p_sys->i_cur_cell += p_sys->i_angle - 1; + + while( cell[p_sys->i_cur_cell+i].block_mode != BLOCK_MODE_LAST_CELL ) + { + i++; + } + p_sys->i_next_cell = p_sys->i_cur_cell + i + 1; +#endif + } + else + { + p_sys->i_next_cell = p_sys->i_cur_cell + 1; + } + +#undef cell + + pgc_id = p_sys->p_vts_file->vts_ptt_srpt->title[ + p_sys->i_ttn - 1].ptt[p_sys->i_chapter].pgcn; + pgn = p_sys->p_vts_file->vts_ptt_srpt->title[ + p_sys->i_ttn - 1].ptt[p_sys->i_chapter].pgn; + p_pgc = p_sys->p_vts_file->vts_pgcit->pgci_srp[pgc_id - 1].pgc; + + if( p_pgc->program_map[pgn - 1] <= p_sys->i_cur_cell ) + { + p_sys->i_chapter++; + + if( p_sys->i_chapter < p_sys->i_chapters && + p_demux->info.i_seekpoint != p_sys->i_chapter ) + { + p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT; + p_demux->info.i_seekpoint = p_sys->i_chapter; + } + } +} + +/***************************************************************************** + * DemuxTitles: get the titles/chapters structure + *****************************************************************************/ +static void DemuxTitles( demux_t *p_demux, + int *pi_title, int *pi_chapter, int *pi_angle ) +{ + demux_sys_t *p_sys = p_demux->p_sys; + input_title_t *t; + seekpoint_t *s; + int32_t i_titles; + int i; + + /* Find out number of titles/chapters */ +#define tt_srpt p_sys->p_vmg_file->tt_srpt + + i_titles = tt_srpt->nr_of_srpts; + msg_Dbg( p_demux, "number of titles: %d", i_titles ); + + for( i = 0; i < i_titles; i++ ) + { + int32_t i_chapters = 0; + int j; + + i_chapters = tt_srpt->title[i].nr_of_ptts; + msg_Dbg( p_demux, "title %d has %d chapters", i, i_chapters ); + + t = vlc_input_title_New(); + for( j = 0; j < __MAX( i_chapters, 1 ); j++ ) + { + s = vlc_seekpoint_New(); + TAB_APPEND( t->i_seekpoint, t->seekpoint, s ); + } + + TAB_APPEND( p_sys->i_titles, p_sys->titles, t ); + } + + /* Set forced title/chapter/angle */ + *pi_title = (*pi_title >= 1 && *pi_title <= i_titles) ? *pi_title : 1; + *pi_chapter = (*pi_chapter >= 0 && *pi_chapter < + tt_srpt->title[*pi_title].nr_of_ptts) ? *pi_chapter : 0; + +#undef tt_srpt +} + +/***************************************************************************** + * ParseCL: parse command line + *****************************************************************************/ +static char *ParseCL( vlc_object_t *p_this, char *psz_name, vlc_bool_t b_force, + int *i_title, int *i_chapter, int *i_angle ) +{ + char *psz_parser, *psz_source, *psz_next; + + psz_source = strdup( psz_name ); + if( psz_source == NULL ) return NULL; + + *i_title = 0; + *i_chapter = 0; + *i_angle = 1; + + /* Start with the end, because you could have : + * dvdnav:/Volumes/my@toto/VIDEO_TS@1,1 + * (yes, this is kludgy). */ + for( psz_parser = psz_source + strlen(psz_source) - 1; + psz_parser >= psz_source && *psz_parser != '@'; + psz_parser-- ); + + if( psz_parser >= psz_source && *psz_parser == '@' ) + { + /* Found options */ + *psz_parser = '\0'; + ++psz_parser; + + *i_title = (int)strtol( psz_parser, &psz_next, 10 ); + if( *psz_next ) + { + psz_parser = psz_next + 1; + *i_chapter = (int)strtol( psz_parser, &psz_next, 10 ); + if( *psz_next ) + { + *i_angle = (int)strtol( psz_next + 1, NULL, 10 ); + } + } + } + + *i_title = *i_title >= 0 ? *i_title : 0; + *i_chapter = *i_chapter ? *i_chapter : 0; + *i_angle = *i_angle ? *i_angle : 1; + + if( !*psz_source ) + { + free( psz_source ); + if( !b_force ) + { + return NULL; + } + psz_source = config_GetPsz( p_this, "dvd" ); + if( !psz_source ) return NULL; + } + +#ifdef WIN32 + if( psz_source[0] && psz_source[1] == ':' && + psz_source[2] == '\\' && psz_source[3] == '\0' ) + { + psz_source[2] = '\0'; + } +#endif + + msg_Dbg( p_this, "dvdroot=%s title=%d chapter=%d angle=%d", + psz_source, *i_title, *i_chapter, *i_angle ); + + return psz_source; +} diff --git a/modules/access/dvdread/Modules.am b/modules/access/dvdread/Modules.am deleted file mode 100644 index b1f0612898..0000000000 --- a/modules/access/dvdread/Modules.am +++ /dev/null @@ -1,6 +0,0 @@ -SOURCES_dvdread = \ - dvdread.c \ - input.c \ - input.h \ - $(NULL) - diff --git a/modules/access/dvdread/dvdread.c b/modules/access/dvdread/dvdread.c deleted file mode 100644 index fccf632e77..0000000000 --- a/modules/access/dvdread/dvdread.c +++ /dev/null @@ -1,52 +0,0 @@ -/***************************************************************************** - * dvdread.c : DvdRead input module for vlc - ***************************************************************************** - * Copyright (C) 2001 VideoLAN - * $Id: dvdread.c,v 1.7 2003/06/17 16:09:16 gbazin Exp $ - * - * Authors: Samuel Hocevar - * - * 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 /* malloc(), free() */ -#include /* strdup() */ - -#include - -/***************************************************************************** - * External prototypes - *****************************************************************************/ -int E_(OpenDVD) ( vlc_object_t * ); -void E_(CloseDVD) ( vlc_object_t * ); - -int E_(InitDVD) ( vlc_object_t * ); -void E_(EndDVD) ( vlc_object_t * ); - -/***************************************************************************** - * Module descriptor - *****************************************************************************/ -vlc_module_begin(); - set_description( _("DVD input (using libdvdread)") ); - set_capability( "access", 110 ); - set_callbacks( E_(OpenDVD), E_(CloseDVD) ); - add_submodule(); - set_capability( "demux", 0 ); - set_callbacks( E_(InitDVD), E_(EndDVD) ); -vlc_module_end(); - diff --git a/modules/access/dvdread/input.c b/modules/access/dvdread/input.c deleted file mode 100644 index 2f206dcad4..0000000000 --- a/modules/access/dvdread/input.c +++ /dev/null @@ -1,1268 +0,0 @@ -/***************************************************************************** - * input.c: DvdRead plugin. - ***************************************************************************** - * This plugins should handle all the known specificities of the DVD format, - * especially the 2048 bytes logical block size. - * It depends on: libdvdread for ifo files and block reading. - ***************************************************************************** - * Copyright (C) 2001, 2003 VideoLAN - * $Id: input.c,v 1.24 2004/03/03 20:39:51 gbazin Exp $ - * - * Author: Stéphane Borel - * - * Some code taken form the play_title.c by Billy Biggs - * in libdvdread. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 -#include - -#include -#include - -#include "../../demux/mpeg/system.h" - -#ifdef HAVE_UNISTD_H -# include -#endif - -#include -#include -#include -#include -#include -#include - -#ifdef STRNCASECMP_IN_STRINGS_H -# include -#endif - -#if defined( WIN32 ) -# include /* read() */ -#endif - -#include -#include -#include -#include -#include - -#include "input.h" - -#include "iso_lang.h" - -/* how many blocks DVDRead will read in each loop */ -#define DVD_BLOCK_READ_ONCE 64 - -/***************************************************************************** - * Private structure - *****************************************************************************/ -struct demux_sys_t -{ - module_t * p_module; - mpeg_demux_t mpeg; -}; - -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -/* called from outside */ -static int DvdReadDemux ( input_thread_t * ); -static int DvdReadRewind ( input_thread_t * ); - -static int DvdReadSetArea ( input_thread_t *, input_area_t * ); -static int DvdReadSetProgram ( input_thread_t *, pgrm_descriptor_t * ); -static ssize_t DvdReadRead ( input_thread_t *, byte_t *, size_t ); -static void DvdReadSeek ( input_thread_t *, off_t ); - -/* called only from here */ -static void DvdReadLauchDecoders( input_thread_t * p_input ); -static void DvdReadHandleDSI( thread_dvd_data_t * p_dvd, uint8_t * p_data ); -static void DvdReadFindCell ( thread_dvd_data_t * p_dvd ); - -/* - * Data demux functions - */ - -/***************************************************************************** - * InitDVD: initialize DVD structures - *****************************************************************************/ -int E_(InitDVD) ( vlc_object_t *p_this ) -{ - input_thread_t *p_input = (input_thread_t *)p_this; - demux_sys_t * p_demux; - - if( p_input->stream.i_method != INPUT_METHOD_DVD ) - { - return VLC_EGENERIC; - } - - p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) ); - if( p_demux == NULL ) - { - return VLC_ENOMEM; - } - - p_input->p_private = (void*)&p_demux->mpeg; - p_demux->p_module = module_Need( p_input, "mpeg-system", NULL, 0 ); - if( p_demux->p_module == NULL ) - { - free( p_input->p_demux_data ); - return VLC_ENOMOD; - } - - p_input->pf_demux = DvdReadDemux; - p_input->pf_demux_control = demux_vaControlDefault; - p_input->pf_rewind = NULL; - - vlc_mutex_lock( &p_input->stream.stream_lock ); - - DvdReadLauchDecoders( p_input ); - - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - return VLC_SUCCESS; -} - -/***************************************************************************** - * EndDVD: end DVD structures - *****************************************************************************/ -void E_(EndDVD) ( vlc_object_t *p_this ) -{ - input_thread_t *p_input = (input_thread_t *)p_this; - - module_Unneed( p_input, p_input->p_demux_data->p_module ); - free( p_input->p_demux_data ); -} - -/***************************************************************************** - * DvdReadDemux - *****************************************************************************/ -#define PEEK( SIZE ) \ - i_result = input_Peek( p_input, &p_peek, SIZE ); \ - if( i_result == -1 ) \ - { \ - return -1; \ - } \ - else if( i_result < SIZE ) \ - { \ - /* EOF */ \ - return 0; \ - } - -static int DvdReadDemux( input_thread_t * p_input ) -{ - int i; - byte_t * p_peek; - data_packet_t * p_data; - ssize_t i_result; - int i_packet_size; - - - /* Read headers to compute payload length */ - for( i = 0 ; i < DVD_BLOCK_READ_ONCE ; i++ ) - { - - /* Read what we believe to be a packet header. */ - PEEK( 4 ); - - /* Default header */ - if( U32_AT( p_peek ) != 0x1BA ) - { - /* That's the case for all packets, except pack header. */ - i_packet_size = U16_AT( p_peek + 4 ); - } - else - { - /* MPEG-2 Pack header. */ - i_packet_size = 8; - } - - /* Fetch a packet of the appropriate size. */ - i_result = input_SplitBuffer( p_input, &p_data, i_packet_size + 6 ); - if( i_result <= 0 ) - { - return( i_result ); - } - - /* In MPEG-2 pack headers we still have to read stuffing bytes. */ - if( (p_data->p_demux_start[3] == 0xBA) && (i_packet_size == 8) ) - { - ssize_t i_stuffing = (p_data->p_demux_start[13] & 0x7); - /* Force refill of the input buffer - though we don't care - * about p_peek. Please note that this is unoptimized. */ - PEEK( i_stuffing ); - p_input->p_current_data += i_stuffing; - } - - p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data ); - - } - - return i; -} - -/***************************************************************************** - * DVDRewind : reads a stream backward - *****************************************************************************/ -static int DvdReadRewind( input_thread_t * p_input ) -{ - return -1; -} - -/* - * Data access functions - */ - -/***************************************************************************** - * OpenDVD: open libdvdread - *****************************************************************************/ -int E_(OpenDVD) ( vlc_object_t *p_this ) -{ - input_thread_t * p_input = (input_thread_t *)p_this; - char * psz_parser; - char * psz_source; - char * psz_next; - struct stat stat_info; - thread_dvd_data_t * p_dvd; - dvd_reader_t * p_dvdread; - input_area_t * p_area; - unsigned int i_title = 1; - unsigned int i_chapter = 1; - unsigned int i_angle = 1; - unsigned int i; - - psz_source = strdup( p_input->psz_name ); - if( psz_source == NULL ) - { - return VLC_ENOMEM; - } - - p_input->pf_read = DvdReadRead; - p_input->pf_seek = DvdReadSeek; - p_input->pf_set_area = DvdReadSetArea; - p_input->pf_set_program = DvdReadSetProgram; - - /* Start with the end, because you could have : - * dvdread:/Volumes/my@toto/VIDEO_TS@1,1 - * (yes, this is kludgy). */ - for ( psz_parser = psz_source + strlen(psz_source) - 1; - psz_parser >= psz_source && *psz_parser != '@'; - psz_parser-- ); - - if( psz_parser >= psz_source && *psz_parser == '@' ) - { - /* Found options */ - *psz_parser = '\0'; - ++psz_parser; - - i_title = (int)strtol( psz_parser, &psz_next, 10 ); - if( *psz_next ) - { - psz_parser = psz_next + 1; - i_chapter = (int)strtol( psz_parser, &psz_next, 10 ); - if( *psz_next ) - { - i_angle = (int)strtol( psz_next + 1, NULL, 10 ); - } - } - - i_title = i_title ? i_title : 1; - i_chapter = i_chapter ? i_chapter : 1; - i_angle = i_angle ? i_angle : 1; - } - - if( !*psz_source ) - { - free( psz_source ); - if( !p_input->psz_access ) - { - return VLC_EGENERIC; - } - psz_source = config_GetPsz( p_input, "dvd" ); - if( !psz_source ) return VLC_EGENERIC; - } - - if( stat( psz_source, &stat_info ) == -1 ) - { - msg_Warn( p_input, "cannot stat() source `%s' (%s)", - psz_source, strerror(errno) ); - free( psz_source ); - return VLC_EGENERIC; - } - if( !S_ISBLK(stat_info.st_mode) && - !S_ISCHR(stat_info.st_mode) && - !S_ISDIR(stat_info.st_mode) ) - { - msg_Warn( p_input, "dvdread module discarded (not a valid source)" ); - free( psz_source ); - return VLC_EGENERIC; - } - - msg_Dbg( p_input, "dvdroot=%s title=%d chapter=%d angle=%d", - psz_source, i_title, i_chapter, i_angle ); - - - p_dvdread = DVDOpen( psz_source ); - - /* free allocated strings */ - free( psz_source ); - - if( ! p_dvdread ) - { - msg_Err( p_input, "libdvdcss cannot open source" ); - return VLC_EGENERIC; - } - - /* set up input */ - p_input->i_mtu = 0; - - p_dvd = malloc( sizeof(thread_dvd_data_t) ); - if( p_dvd == NULL ) - { - msg_Err( p_input, "out of memory" ); - return VLC_ENOMEM; - } - - p_dvd->p_dvdread = p_dvdread; - p_dvd->p_title = NULL; - p_dvd->p_vts_file = NULL; - - - p_input->p_access_data = (void *)p_dvd; - - /* Ifo allocation & initialisation */ - if( ! ( p_dvd->p_vmg_file = ifoOpen( p_dvd->p_dvdread, 0 ) ) ) - { - msg_Warn( p_input, "cannot open VMG info" ); - free( p_dvd ); - return VLC_EGENERIC; - } - msg_Dbg( p_input, "VMG opened" ); - - /* Set stream and area data */ - vlc_mutex_lock( &p_input->stream.stream_lock ); - - p_input->stream.i_method = INPUT_METHOD_DVD; - - /* If we are here we can control the pace... */ - p_input->stream.b_pace_control = VLC_TRUE; - p_input->stream.b_seekable = VLC_TRUE; - - p_input->stream.p_selected_area->i_size = 0; - p_input->stream.p_selected_area->i_tell = 0; - - /* Initialize ES structures */ - input_InitStream( p_input, sizeof( stream_ps_data_t ) ); - - /* disc input method */ - p_input->stream.i_method = INPUT_METHOD_DVD; - -#define tt_srpt p_dvd->p_vmg_file->tt_srpt - msg_Dbg( p_input, "number of titles: %d", tt_srpt->nr_of_srpts ); - -#define area p_input->stream.pp_areas - /* We start from 1 here since the default area 0 - * is reserved for video_ts.vob */ - for( i = 1 ; i <= tt_srpt->nr_of_srpts ; i++ ) - { - /* Titles are Program Chains */ - input_AddArea( p_input, i, tt_srpt->title[i-1].nr_of_ptts ); - - /* 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; - - /* Default Chapter */ - area[i]->i_part = 1; - - area[i]->i_plugin_data = tt_srpt->title[i-1].title_set_nr; - } -#undef area - - p_dvd->i_title = i_title <= tt_srpt->nr_of_srpts ? i_title : 1; -#undef tt_srpt - - p_area = p_input->stream.pp_areas[p_dvd->i_title]; - p_dvd->i_chapter = i_chapter; - - p_dvd->i_chapter = i_chapter < p_area->i_part_nb ? i_chapter : 1; - p_area->i_part = p_dvd->i_chapter; - - p_dvd->i_angle = i_angle; - - /* set title, chapter, audio and subpic */ - if( DvdReadSetArea( p_input, p_area ) ) - { - vlc_mutex_unlock( &p_input->stream.stream_lock ); - return VLC_EGENERIC; - } - - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - if( !p_input->psz_demux || !*p_input->psz_demux ) - { - p_input->psz_demux = "dvdread"; - } - - return VLC_SUCCESS; -} - -/***************************************************************************** - * CloseDVD: close libdvdread - *****************************************************************************/ -void E_(CloseDVD) ( vlc_object_t *p_this ) -{ - input_thread_t * p_input = (input_thread_t *)p_this; - thread_dvd_data_t * p_dvd = (thread_dvd_data_t *)p_input->p_access_data; - - /* This is a very nasty side-effect in the DVD plug-in : language - * selection here influences language selection of other streams. So - * unset those variables (may not be what the user wants). - * FIXME FIXME FIXME FIXME FIXME FIXME FIXME --Meuuh */ - config_PutInt( p_input, "audio-channel", -1 ); - config_PutInt( p_input, "spu-channel", -1 ); - - /* close libdvdread */ - DVDCloseFile( p_dvd->p_title ); - ifoClose( p_dvd->p_vts_file ); - ifoClose( p_dvd->p_vmg_file ); - - DVDClose( p_dvd->p_dvdread ); - free( p_dvd ); - p_input->p_access_data = NULL; - -} - -/***************************************************************************** - * DvdReadSetProgram: Does nothing, a DVD is mono-program - *****************************************************************************/ -static int DvdReadSetProgram( input_thread_t * p_input, - pgrm_descriptor_t * p_program ) -{ - if( p_input->stream.p_selected_program != p_program ) - { - thread_dvd_data_t * p_dvd; - vlc_value_t val; - - p_dvd = (thread_dvd_data_t*)(p_input->p_access_data); - p_dvd->i_angle = p_program->i_number; - - memcpy( p_program, p_input->stream.p_selected_program, - sizeof(pgrm_descriptor_t) ); - p_program->i_number = p_dvd->i_angle; - p_input->stream.p_selected_program = p_program; - - msg_Dbg( p_input, "angle %d selected", p_dvd->i_angle ); - - /* Update the navigation variables without triggering a callback */ - val.i_int = p_program->i_number; - var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL ); - } - - return VLC_SUCCESS; -} - -#define p_pgc p_dvd->p_cur_pgc - -/***************************************************************************** - * DvdReadSetArea: initialize input data for title x, chapter y. - * It should be called for each user navigation request. - ***************************************************************************** - * Take care that i_title starts from 0 (vmg) and i_chapter start from 1. - * Note that you have to take the lock before entering here. - *****************************************************************************/ -static int DvdReadSetArea( input_thread_t * p_input, input_area_t * p_area ) -{ - thread_dvd_data_t * p_dvd; - int pgc_id = 0; - int pgn = 0; - vlc_value_t val; - - p_dvd = (thread_dvd_data_t*)p_input->p_access_data; - - /* we can't use the interface slider until initilization is complete */ - p_input->stream.b_seekable = VLC_FALSE; - - if( p_area != p_input->stream.p_selected_area ) - { - es_descriptor_t * p_es; - unsigned int i_cell = 0; - unsigned int i_audio_nb = 0; - unsigned int i_spu_nb = 0; - unsigned int i; - -#define p_vmg p_dvd->p_vmg_file -#define p_vts p_dvd->p_vts_file - if( p_dvd->p_title != NULL ) - { - DVDCloseFile( p_dvd->p_title ); - } - - if( p_vts != NULL ) - { - ifoClose( p_vts ); - } - - /* Reset the Chapter position of the old title */ - p_input->stream.p_selected_area->i_part = 1; - - /* - * We have to load all title information - */ - /* Change the default area */ - p_input->stream.p_selected_area = p_area; - - msg_Dbg( p_input, "open VTS %d, for title %d", - p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr, - p_area->i_id ); - - /* ifo vts */ - if( ! ( p_vts = ifoOpen( p_dvd->p_dvdread, - p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr ) ) ) - { - msg_Err( p_input, "fatal error in vts ifo" ); - ifoClose( p_vmg ); - DVDClose( p_dvd->p_dvdread ); - return VLC_EGENERIC; - } - - /* title position inside the selected vts */ - p_dvd->i_ttn = p_vmg->tt_srpt->title[ p_area->i_id - 1 ].vts_ttn; - - /* - * Set selected title start - */ - pgc_id = p_vts->vts_ptt_srpt->title[p_dvd->i_ttn-1].ptt[0].pgcn; - pgn = p_vts->vts_ptt_srpt->title[p_dvd->i_ttn-1].ptt[0].pgn; - p_pgc = p_vts->vts_pgcit->pgci_srp[ pgc_id - 1 ].pgc; - i_cell = p_pgc->program_map[ pgn - 1 ] - 1; - - p_area->i_start = - LB2OFF( p_dvd->p_cur_pgc->cell_playback[ i_cell ].first_sector ); - - msg_Dbg( p_input, "start %d vts_title %d pgc %d pgn %d", - p_area->i_id, p_dvd->i_ttn, pgc_id, pgn ); - - /* - * Find title end - */ - i_cell = p_dvd->p_cur_pgc->nr_of_cells - 1; - - p_dvd->i_end_block = p_pgc->cell_playback[ i_cell ].last_sector; - p_area->i_size = LB2OFF( p_dvd->i_end_block )- p_area->i_start; - - msg_Dbg( p_input, "start "I64Fd" size "I64Fd" end %d", - p_area->i_start , p_area->i_size, p_dvd->i_end_block ); - - /* - * Set properties for current chapter - */ - /* Remeber current chapter */ - p_dvd->i_chapter = p_area->i_part; - p_dvd->b_eoc = VLC_FALSE; - - pgc_id = p_vts->vts_ptt_srpt->title[ - p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgcn; - pgn = p_vts->vts_ptt_srpt->title[ - p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgn; - - p_pgc = p_vts->vts_pgcit->pgci_srp[pgc_id-1].pgc; - p_dvd->i_pack_len = 0; - p_dvd->i_next_cell = p_dvd->i_cur_cell = p_pgc->program_map[pgn-1] - 1; - DvdReadFindCell( p_dvd ); - - p_dvd->i_next_vobu = p_dvd->i_cur_block = - p_pgc->cell_playback[p_dvd->i_cur_cell].first_sector; - - /* - * Angle management - */ - p_dvd->i_angle_nb = p_vmg->tt_srpt->title[p_area->i_id-1].nr_of_angles; - - if( p_dvd->i_angle > p_dvd->i_angle_nb ) - { - p_dvd->i_angle = 1; - } - - /* - * We've got enough info, time to open the title set data. - */ - if( ! ( p_dvd->p_title = DVDOpenFile( p_dvd->p_dvdread, - p_vmg->tt_srpt->title[ p_area->i_id - 1 ].title_set_nr, - DVD_READ_TITLE_VOBS ) ) ) - { - msg_Err( p_input, "cannot open title (VTS_%02d_1.VOB)", - p_vmg->tt_srpt->title[p_area->i_id-1].title_set_nr ); - ifoClose( p_vts ); - ifoClose( p_vmg ); - DVDClose( p_dvd->p_dvdread ); - return VLC_EGENERIC; - } - -// IfoPrintTitle( p_dvd ); - - /* - * Destroy obsolete ES by reinitializing program 0 - * and find all ES in title with ifo data - */ - if( p_input->stream.pp_programs != NULL ) - { - /* We don't use input_EndStream here since - * we keep area structures */ - - while( p_input->stream.i_es_number ) - { - input_DelES( p_input, p_input->stream.pp_es[0] ); - } - - while( p_input->stream.i_pgrm_number ) - { - input_DelProgram( p_input, p_input->stream.pp_programs[0] ); - } - - if( p_input->stream.pp_selected_es ) - { - free( p_input->stream.pp_selected_es ); - p_input->stream.pp_selected_es = NULL; - } - p_input->stream.i_selected_es_number = 0; - } - - input_AddProgram( p_input, 1, sizeof( stream_ps_data_t ) ); - p_input->stream.p_selected_program = p_input->stream.pp_programs[0]; - - for( i = 1 ; i < p_dvd->i_angle_nb ; i++ ) - { - input_AddProgram( p_input, i+1, 0 ); - } - - DvdReadSetProgram( p_input, - p_input->stream.pp_programs[p_dvd->i_angle-1] ); - - /* No PSM to read in DVD mode, we already have all information */ - p_input->stream.p_selected_program->b_is_ok = VLC_TRUE; - - p_es = NULL; - - /* ES 0 -> video MPEG2 */ -// IfoPrintVideo( p_dvd ); - - p_es = input_AddES( p_input, NULL, 0xe0, VIDEO_ES, NULL, 0 ); - p_es->i_stream_id = 0xe0; - p_es->i_fourcc = VLC_FOURCC('m','p','g','v'); - -#define audio_control \ - p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->audio_control[i-1] - /* Audio ES, in the order they appear in .ifo */ - for( i = 1 ; i <= p_vts->vtsi_mat->nr_of_vts_audio_streams ; i++ ) - { - int i_position = 0; - uint16_t i_id; - -// IfoPrintAudio( p_dvd, i ); - - /* audio channel is active if first byte is 0x80 */ - if( audio_control & 0x8000 ) - { - i_audio_nb++; - i_position = ( audio_control & 0x7F00 ) >> 8; - - msg_Dbg( p_input, "audio position %d", i_position ); - switch( p_vts->vtsi_mat->vts_audio_attr[i-1].audio_format ) - { - case 0x00: /* A52 */ - i_id = ( ( 0x80 + i_position ) << 8 ) | 0xbd; - p_es = input_AddES( p_input, NULL, i_id, AUDIO_ES, - DecodeLanguage( - p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ), 0 ); - p_es->i_stream_id = 0xbd; - p_es->i_fourcc = VLC_FOURCC('a','5','2','b'); - - break; - case 0x02: - case 0x03: /* MPEG audio */ - i_id = 0xc0 + i_position; - p_es = input_AddES( p_input, NULL, i_id, AUDIO_ES, - DecodeLanguage( - p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ), 0 ); - p_es->i_stream_id = i_id; - p_es->i_fourcc = VLC_FOURCC('m','p','g','a'); - - break; - case 0x04: /* LPCM */ - - i_id = ( ( 0xa0 + i_position ) << 8 ) | 0xbd; - p_es = input_AddES( p_input, NULL, i_id, AUDIO_ES, - DecodeLanguage( - p_vts->vtsi_mat->vts_audio_attr[i-1].lang_code ), 0 ); - p_es->i_stream_id = i_id; - p_es->i_fourcc = VLC_FOURCC('l','p','c','b'); - - break; - case 0x06: /* DTS */ - i_id = ( ( 0x88 + i_position ) << 8 ) | 0xbd; - msg_Err( p_input, "DTS audio not handled yet" - "(0x%x)", i_id ); - break; - default: - i_id = 0; - msg_Err( p_input, "unknown audio type %.2x", - p_vts->vtsi_mat->vts_audio_attr[i-1].audio_format ); - } - } - } -#undef audio_control -#define spu_control \ - p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc->subp_control[i-1] - - /* Sub Picture ES */ - - for( i = 1 ; i <= p_vts->vtsi_mat->nr_of_vts_subp_streams; i++ ) - { - int i_position = 0; - uint16_t i_id; - -// IfoPrintSpu( p_dvd, i ); - msg_Dbg( p_input, "spu %d 0x%02x", i, spu_control ); - - if( spu_control & 0x80000000 ) - { - i_spu_nb++; - - /* there are several streams for one spu */ - if( p_vts->vtsi_mat->vts_video_attr.display_aspect_ratio ) - { - /* 16:9 */ - switch( p_vts->vtsi_mat->vts_video_attr.permitted_df ) - { - case 1: - i_position = spu_control & 0xff; - break; - case 2: - i_position = ( spu_control >> 8 ) & 0xff; - break; - default: - i_position = ( spu_control >> 16 ) & 0xff; - break; - } - } - else - { - /* 4:3 */ - i_position = ( spu_control >> 24 ) & 0x7F; - } - - i_id = ( ( 0x20 + i_position ) << 8 ) | 0xbd; - p_es = input_AddES( p_input, NULL, i_id, SPU_ES, - DecodeLanguage( - p_vts->vtsi_mat->vts_subp_attr[i-1].lang_code ), 0 ); - p_es->i_stream_id = 0xbd; - p_es->i_fourcc = VLC_FOURCC('s','p','u','b'); - } - } -#undef spu_control - - /* FIXME: hack to check that the demuxer is ready, and set - * the decoders */ - if( p_input->p_demux ) - { - DvdReadLauchDecoders( p_input ); - } - - /* Update the navigation variables without triggering a callback */ - val.i_int = p_area->i_id; - var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL ); - var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL ); - for( i = 1; i <= p_area->i_part_nb; i++ ) - { - val.i_int = i; - var_Change( p_input, "chapter", VLC_VAR_ADDCHOICE, &val, NULL ); - } - - } /* i_title >= 0 */ - else - { - p_area = p_input->stream.p_selected_area; - } - - /* - * Chapter selection - */ - - if( p_area->i_part != p_dvd->i_chapter ) - { - if( ( p_area->i_part > 0 ) && - ( p_area->i_part <= p_area->i_part_nb )) - { - p_dvd->i_ttn = p_vmg->tt_srpt->title[p_area->i_id-1].vts_ttn; - pgc_id = p_vts->vts_ptt_srpt->title[ - p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgcn; - pgn = p_vts->vts_ptt_srpt->title[ - p_dvd->i_ttn-1].ptt[p_area->i_part-1].pgn; - - p_pgc = p_vts->vts_pgcit->pgci_srp[ pgc_id - 1 ].pgc; - - p_dvd->i_cur_cell = p_pgc->program_map[ pgn - 1 ] - 1; - p_dvd->i_chapter = p_area->i_part; - DvdReadFindCell( p_dvd ); - - p_dvd->i_pack_len = 0; - p_dvd->i_next_vobu = p_dvd->i_cur_block = - p_pgc->cell_playback[p_dvd->i_cur_cell].first_sector; - } - else - { - p_area->i_part = p_dvd->i_chapter; - } - } -#undef p_vts -#undef p_vmg - - /* warn interface that something has changed */ - p_area->i_tell = LB2OFF( p_dvd->i_next_vobu ) - p_area->i_start; - p_input->stream.b_seekable = VLC_TRUE; - p_input->stream.b_changed = VLC_TRUE; - - /* Update the navigation variables without triggering a callback */ - val.i_int = p_area->i_part; - var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &val, NULL ); - - return VLC_SUCCESS; -} - - -/***************************************************************************** - * DvdReadRead: reads data packets. - ***************************************************************************** - * Returns -1 in case of error, 0 in case of EOF, otherwise the number of - * bytes. - *****************************************************************************/ -static ssize_t DvdReadRead( input_thread_t * p_input, - byte_t * p_buffer, size_t i_count ) -{ - thread_dvd_data_t * p_dvd; - byte_t * p_buf; - unsigned int i_blocks_once; - unsigned int i_blocks; - int i_read; - int i_read_total; - vlc_bool_t b_eot = VLC_FALSE; - - p_dvd = (thread_dvd_data_t *)p_input->p_access_data; - p_buf = p_buffer; - - /* - * Playback by cell in this pgc, starting at the cell for our chapter. - */ - i_blocks = OFF2LB( i_count ); - i_read_total = 0; - i_read = 0; - - while( i_blocks ) - { - /* - * End of pack, we select the following one - */ - if( ! p_dvd->i_pack_len ) - { - /* - * Read NAV packet. - */ - if( ( i_read = DVDReadBlocks( p_dvd->p_title, p_dvd->i_next_vobu, - 1, p_buf ) ) != 1 ) - { - msg_Err( p_input, "read failed for block %d", - p_dvd->i_next_vobu ); - return -1; - } - - /* basic check to be sure we don't have a empty title - * go to next title if so */ - //assert( p_buffer[41] == 0xbf && p_buffer[1027] == 0xbf ); - - /* - * Parse the contained dsi packet. - */ - - DvdReadHandleDSI( p_dvd, p_buf ); - - /* End of title */ - if( p_dvd->i_next_vobu >= p_dvd->i_end_block + 1 ) - { - b_eot = 1; - break; - } - - assert( p_dvd->i_pack_len < 1024 ); - /* FIXME: Ugly kludge: we send the pack block to the input for it - * sometimes has a zero scr and restart the sync */ - p_dvd->i_cur_block ++; - //p_dvd->i_pack_len++; - - i_read_total++; - p_buf += DVD_VIDEO_LB_LEN; - i_blocks--; - } - - /* - * Compute the number of blocks to read - */ - i_blocks_once = __MIN( p_dvd->i_pack_len, i_blocks ); - p_dvd->i_pack_len -= i_blocks_once; - - /* Reads from DVD */ - i_read = DVDReadBlocks( p_dvd->p_title, p_dvd->i_cur_block, - i_blocks_once, p_buf ); - if( (unsigned int)i_read != i_blocks_once ) - { - msg_Err( p_input, "read failed for %d/%d blocks at 0x%02x", - i_read, i_blocks_once, p_dvd->i_cur_block ); - return -1; - } - - i_blocks -= i_read; - i_read_total += i_read; - p_dvd->i_cur_block += i_read; - p_buf += LB2OFF( i_read ); - - } -/* - msg_Dbg( p_input, "i_blocks: %d len: %d current: 0x%02x", i_read, p_dvd->i_pack_len, p_dvd->i_cur_block ); -*/ - - vlc_mutex_lock( &p_input->stream.stream_lock ); - - if( p_dvd->b_eoc ) - { - /* We modify i_part only at end of chapter not to erase - * some modification from the interface */ - p_input->stream.p_selected_area->i_part = p_dvd->i_chapter; - p_dvd->b_eoc = VLC_FALSE; - } - - if( ( LB2OFF( p_dvd->i_cur_block ) - - p_input->stream.p_selected_area->i_start ) - >= p_input->stream.p_selected_area->i_size || b_eot ) - { - if( ( p_input->stream.p_selected_area->i_id + 1 ) >= - p_input->stream.i_area_nb ) - { - /* EOF */ - vlc_mutex_unlock( &p_input->stream.stream_lock ); - return 0; - } - - /* EOT */ - msg_Dbg( p_input, "new title" ); - DvdReadSetArea( p_input, p_input->stream.pp_areas[ - p_input->stream.p_selected_area->i_id+1] ); - } - - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - return LB2OFF( i_read_total ); -} -#undef p_pgc - -/***************************************************************************** - * DvdReadSeek : Goes to a given position on the stream. - ***************************************************************************** - * This one is used by the input and translate chronological position from - * input to logical position on the device. - * The lock should be taken before calling this function. - *****************************************************************************/ -static void DvdReadSeek( input_thread_t * p_input, off_t i_off ) -{ - thread_dvd_data_t * p_dvd; - unsigned int i_lb; - unsigned int i_tmp; - unsigned int i_chapter = 0; - unsigned int i_cell = 0; - unsigned int i_vobu = 0; - unsigned int i_sub_cell = 0; - - vlc_mutex_lock( &p_input->stream.stream_lock ); - i_off += p_input->stream.p_selected_area->i_start; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - i_lb = OFF2LB( i_off ); - p_dvd = ( thread_dvd_data_t * )p_input->p_access_data; - - /* find cell */ - while( p_dvd->p_cur_pgc->cell_playback[i_cell].last_sector < i_lb ) - { - i_cell++; - } - - /* find chapter */ - do - { - pgc_t * p_pgc; - int pgc_id, pgn; - - i_chapter++; - pgc_id = p_dvd->p_vts_file->vts_ptt_srpt->title[ - p_dvd->i_ttn-1].ptt[i_chapter-1].pgcn; - pgn = p_dvd->p_vts_file->vts_ptt_srpt->title[ - p_dvd->i_ttn-1].ptt[i_chapter-1].pgn; - - p_pgc = p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc; - i_tmp = p_pgc->program_map[pgn-1]; - - } while( i_tmp <= i_cell ); - - /* find vobu */ - while( p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu] - <= i_lb ) - { - i_vobu++; - } - - /* find sub_cell */ - while( p_dvd->p_vts_file->vts_c_adt->cell_adr_table[i_sub_cell].start_sector < - p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu-1] ) - { - i_sub_cell++; - } - -/* - msg_Dbg( p_input, "cell %d i_sub_cell %d chapter %d vobu %d cell_sector %d vobu_sector %d sub_cell_sector %d", - i_cell, i_sub_cell,i_chapter, i_vobu, - p_dvd->p_cur_pgc->cell_playback[i_cell].first_sector, - p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu], - p_dvd->p_vts_file->vts_c_adt->cell_adr_table[i_sub_cell-1].start_sector); -*/ - p_dvd->i_cur_block = i_lb; - p_dvd->i_next_vobu = - p_dvd->p_vts_file->vts_vobu_admap->vobu_start_sectors[i_vobu]; - p_dvd->i_pack_len = p_dvd->i_next_vobu - i_lb; - p_dvd->i_cur_cell = i_cell; - p_dvd->i_chapter = i_chapter; - DvdReadFindCell( p_dvd ); - - vlc_mutex_lock( &p_input->stream.stream_lock ); - p_input->stream.p_selected_area->i_tell = - LB2OFF ( p_dvd->i_cur_block ) - - p_input->stream.p_selected_area->i_start; - p_input->stream.p_selected_area->i_part = p_dvd->i_chapter; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - - return; -} - -/***************************************************************************** - * DvdReadHandleDSI - *****************************************************************************/ -static void DvdReadHandleDSI( thread_dvd_data_t * p_dvd, uint8_t * p_data ) -{ - navRead_DSI( &(p_dvd->dsi_pack), &(p_data[ DSI_START_BYTE ]) ); - - /* - * Determine where we go next. These values are the ones we mostly - * care about. - */ - p_dvd->i_cur_block = p_dvd->dsi_pack.dsi_gi.nv_pck_lbn; - - /* - * If we're not at the end of this cell, we can determine the next - * VOBU to display using the VOBU_SRI information section of the - * DSI. Using this value correctly follows the current angle, - * avoiding the doubled scenes in The Matrix, and makes our life - * really happy. - */ - if( p_dvd->dsi_pack.vobu_sri.next_vobu != SRI_END_OF_CELL ) - { -#if 1 - switch( ( p_dvd->dsi_pack.sml_pbi.category & 0xf000 ) >> 12 ) - { - case 0x4: - /* interleaved unit with no angle */ - if( p_dvd->dsi_pack.sml_pbi.ilvu_sa != 0 ) - { - p_dvd->i_next_vobu = p_dvd->i_cur_block + - p_dvd->dsi_pack.sml_pbi.ilvu_sa; - p_dvd->i_pack_len = p_dvd->dsi_pack.sml_pbi.ilvu_ea; - } - else - { - p_dvd->i_next_vobu = p_dvd->i_cur_block + - p_dvd->dsi_pack.dsi_gi.vobu_ea + 1; - p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea; - } - break; - case 0x5: - /* vobu is end of ilvu */ - if( p_dvd->dsi_pack.sml_agli.data[p_dvd->i_angle-1].address ) - { - p_dvd->i_next_vobu = p_dvd->i_cur_block + - p_dvd->dsi_pack.sml_agli.data[p_dvd->i_angle-1].address; - p_dvd->i_pack_len = p_dvd->dsi_pack.sml_pbi.ilvu_ea; - - break; - } - case 0x6: - /* vobu is beginning of ilvu */ - case 0x9: - /* next scr is 0 */ - case 0xa: - /* entering interleaved section */ - case 0x8: - /* non interleaved cells in interleaved section */ - default: - p_dvd->i_next_vobu = p_dvd->i_cur_block + - ( p_dvd->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); - p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea; - break; - } -#else - p_dvd->i_next_vobu = p_dvd->i_cur_block + - ( p_dvd->dsi_pack.vobu_sri.next_vobu & 0x7fffffff ); - p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea; -#endif - } - else - { - p_dvd->i_cur_cell = p_dvd->i_next_cell; - DvdReadFindCell( p_dvd ); - - p_dvd->i_pack_len = p_dvd->dsi_pack.dsi_gi.vobu_ea; - p_dvd->i_next_vobu = - p_dvd->p_cur_pgc->cell_playback[p_dvd->i_cur_cell].first_sector; - } - -#if 0 - msg_Dbg( p_input, 12, "scr %d lbn 0x%02x vobu_ea %d vob_id %d c_id %d", - p_dvd->dsi_pack.dsi_gi.nv_pck_scr, - p_dvd->dsi_pack.dsi_gi.nv_pck_lbn, - p_dvd->dsi_pack.dsi_gi.vobu_ea, - p_dvd->dsi_pack.dsi_gi.vobu_vob_idn, - p_dvd->dsi_pack.dsi_gi.vobu_c_idn ); - - msg_Dbg( p_input, 12, "cat 0x%02x ilvu_ea %d ilvu_sa %d size %d", - p_dvd->dsi_pack.sml_pbi.category, - p_dvd->dsi_pack.sml_pbi.ilvu_ea, - p_dvd->dsi_pack.sml_pbi.ilvu_sa, - p_dvd->dsi_pack.sml_pbi.size ); - - msg_Dbg( p_input, 12, "next_vobu %d next_ilvu1 %d next_ilvu2 %d", - p_dvd->dsi_pack.vobu_sri.next_vobu & 0x7fffffff, - p_dvd->dsi_pack.sml_agli.data[ p_dvd->i_angle - 1 ].address, - p_dvd->dsi_pack.sml_agli.data[ p_dvd->i_angle ].address); -#endif -} - -/***************************************************************************** - * DvdReadFindCell - *****************************************************************************/ -static void DvdReadFindCell( thread_dvd_data_t * p_dvd ) -{ - int pgc_id, pgn; - int i = 0; - pgc_t * p_pgc; -#define cell p_dvd->p_cur_pgc->cell_playback - if( cell[p_dvd->i_cur_cell].block_type == BLOCK_TYPE_ANGLE_BLOCK ) - { -#if 0 - p_dvd->i_next_cell = p_dvd->i_cur_cell + p_dvd->i_angle_nb; - p_dvd->i_cur_cell += p_dvd->i_angle - 1; -#else - p_dvd->i_cur_cell += p_dvd->i_angle - 1; - - while( cell[p_dvd->i_cur_cell+i].block_mode != BLOCK_MODE_LAST_CELL ) - { - i++; - } - p_dvd->i_next_cell = p_dvd->i_cur_cell + i + 1; -#endif - } - else - { - p_dvd->i_next_cell = p_dvd->i_cur_cell + 1; - } -#undef cell - pgc_id = p_dvd->p_vts_file->vts_ptt_srpt->title[ - p_dvd->i_ttn-1].ptt[p_dvd->i_chapter-1].pgcn; - pgn = p_dvd->p_vts_file->vts_ptt_srpt->title[ - p_dvd->i_ttn-1].ptt[p_dvd->i_chapter-1].pgn; - p_pgc = p_dvd->p_vts_file->vts_pgcit->pgci_srp[pgc_id-1].pgc; - - if( p_pgc->program_map[pgn-1] <= p_dvd->i_cur_cell ) - { - p_dvd->i_chapter++; - p_dvd->b_eoc = VLC_TRUE; - } -} - -/***************************************************************************** - * DvdReadLaunchDecoders - *****************************************************************************/ -static void DvdReadLauchDecoders( input_thread_t * p_input ) -{ - thread_dvd_data_t * p_dvd = (thread_dvd_data_t*)(p_input->p_access_data); - int i_audio, i_spu; - - input_SelectES( p_input, p_input->stream.pp_es[0] ); - - /* For audio: first one if none or a not existing one specified */ - i_audio = config_GetInt( p_input, "audio-channel" ); - if( i_audio < 0 /*|| i_audio > i_audio_nb*/ ) - { - config_PutInt( p_input, "audio-channel", 1 ); - i_audio = 1; - } - if( i_audio > 0/* && i_audio_nb > 0*/ ) - { - if( config_GetInt( p_input, "audio-type" ) == REQUESTED_A52 ) - { - int i_a52 = i_audio; - while( ( p_input->stream.pp_es[i_a52]->i_fourcc != - VLC_FOURCC('a','5','2','b') ) && ( i_a52 <= - p_dvd->p_vts_file->vtsi_mat->nr_of_vts_audio_streams ) ) - { - i_a52++; - } - if( p_input->stream.pp_es[i_a52]->i_fourcc - == VLC_FOURCC('a','5','2','b') ) - { - input_SelectES( p_input, p_input->stream.pp_es[i_a52] ); - } - } - else - { - input_SelectES( p_input, p_input->stream.pp_es[i_audio] ); - } - } - - /* for spu, default is none */ - i_spu = config_GetInt( p_input, "spu-channel" ); - if( i_spu < 0 /*|| i_spu > i_spu_nb*/ ) - { - config_PutInt( p_input, "spu-channel", 0 ); - i_spu = 0; - } - if( i_spu > 0 /*&& i_spu_nb > 0*/ ) - { - i_spu += p_dvd->p_vts_file->vtsi_mat->nr_of_vts_audio_streams; - input_SelectES( p_input, p_input->stream.pp_es[i_spu] ); - } -} diff --git a/modules/access/dvdread/input.h b/modules/access/dvdread/input.h deleted file mode 100644 index 3c40a885c0..0000000000 --- a/modules/access/dvdread/input.h +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************** - * input.h: thread structure of the DVD plugin - ***************************************************************************** - * Copyright (C) 1999-2001 VideoLAN - * $Id: input.h,v 1.2 2003/01/23 15:52:04 sam Exp $ - * - * Author: Stéphane Borel - * - * 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 - *****************************************************************************/ - -/* Logical block size for DVD-VIDEO */ -#define LB2OFF(x) ((off_t)(x) * (off_t)(DVD_VIDEO_LB_LEN)) -#define OFF2LB(x) ((x) >> 11) - -/***************************************************************************** - * thread_dvd_data_t: extension of input_thread_t for DVD specificity. - *****************************************************************************/ -typedef struct thread_dvd_data_s -{ - dvd_reader_t * p_dvdread; - dvd_file_t * p_title; - - ifo_handle_t * p_vmg_file; - ifo_handle_t * p_vts_file; - - unsigned int i_title; - unsigned int i_chapter; - unsigned int i_angle; - unsigned int i_angle_nb; - - tt_srpt_t * p_tt_srpt; - pgc_t * p_cur_pgc; - - dsi_t dsi_pack; - - int i_ttn; - - unsigned int i_pack_len; - unsigned int i_cur_block; - unsigned int i_next_vobu; - unsigned int i_end_block; - - unsigned int i_cur_cell; - unsigned int i_next_cell; - vlc_bool_t b_eoc; -} thread_dvd_data_t; - -- 2.39.2