Commit 9eb3e68f authored by Gildas Bazin's avatar Gildas Bazin

* configure.ac, modules/access/dvd, modules/access/dvdplay:

  + removed dvdplay module which was deprecated in favor of the dvdnav one.
  + removed dvd module which is going to be replace with a new dvdread one.
parent 41b93de1
......@@ -1211,74 +1211,6 @@ if test "${enable_livedotcom}" = "yes"; then
fi
fi
dnl dnl
dnl dnl DVD module: optionally check for installed libdvdcss
dnl dnl
dnl AC_ARG_ENABLE(dvd,
dnl [ --enable-dvd DVD input module (default enabled)])
dnl if test "${enable_dvd}" != "no"
dnl then
dnl AC_ARG_WITH(dvdcss,
dnl [ --with-dvdcss=PATH libdvdcss headers and libraries])
dnl AC_ARG_WITH(dvdcss-tree,
dnl [ --with-dvdcss-tree=PATH libdvdcss tree for static linking])
dnl case "${with_dvdcss}" in
dnl ""|yes)
dnl if test -z "${with_dvdcss_tree}"
dnl then
dnl AC_CHECK_HEADERS(dvdcss/dvdcss.h,
dnl [ AX_ADD_PLUGINS([dvd])
dnl AX_ADD_LDFLAGS([dvd dvdcss],[-ldvdcss])],
dnl [ AC_MSG_WARN([libdvdcss is no longer provided with vlc; please get libdvdcss from http://www.videolan.org/libdvdcss/ and build it. Then either use --with-dvdcss=<path/where/libdvdcss/was/installed> for dynamic linking (recommended under Unix) or --with-dvdcss-tree=<path/where/libdvdcss/was/built> for static linking (recommended under BeOS, Windows, MacOS X). Alternatively you can use --disable-dvd to disable the DVD plugin.])
dnl AC_MSG_ERROR([cannot find libdvdcss headers]) ])
dnl else
dnl AC_MSG_CHECKING(for libdvdcss.a in ${with_dvdcss_tree})
dnl real_dvdcss_tree="`cd ${with_dvdcss_tree} 2>/dev/null && pwd`"
dnl if test -z "${real_dvdcss_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_dvdcss_tree}])
dnl fi
dnl if test -f "${real_dvdcss_tree}/src/.libs/libdvdcss.a"
dnl then
dnl dnl Use a custom libdvdcss
dnl AC_MSG_RESULT(${real_dvdcss_tree}/src/.libs/libdvdcss.a)
dnl AX_ADD_BUILTINS([dvd])
dnl AX_ADD_LDFLAGS([dvd dvdcss],[-L${real_dvdcss_tree}/src/.libs -ldvdcss])
dnl AX_ADD_CPPFLAGS([dvd],[-I${real_dvdcss_tree}/src])
dnl else
dnl dnl The given libdvdcss wasn't built
dnl AC_MSG_RESULT(no)
dnl AC_MSG_ERROR([cannot find ${real_dvdcss_tree}/src/.libs/libdvdcss.a, make sure you compiled libdvdcss in ${with_dvdcss_tree}])
dnl fi
dnl fi
dnl ;;
dnl no)
dnl dnl Compile without dvdcss (dlopen version, works only under Linux)
dnl AX_ADD_PLUGINS([dvd])
dnl AX_ADD_CPPFLAGS([dvd],[-DGOD_DAMN_DMCA])
dnl AX_ADD_LDFLAGS([dvd],[-ldl])
dnl ;;
dnl *)
dnl AC_MSG_CHECKING(for dvdcss headers in ${with_dvdcss})
dnl if test -f ${with_dvdcss}/include/dvdcss/dvdcss.h
dnl then
dnl dnl Use ${with_dvdcss}/include/dvdcss/dvdcss.h
dnl AC_MSG_RESULT(yes)
dnl AX_ADD_PLUGINS([dvd])
dnl AX_ADD_LDFLAGS([dvd dvdcss],[-L${with_dvdcss}/lib -ldvdcss])
dnl AX_ADD_CPPFLAGS([dvd],[-I${with_dvdcss}/include])
dnl else
dnl dnl No libdvdcss could be found, sorry
dnl AC_MSG_RESULT(no)
dnl AC_MSG_ERROR([cannot find ${with_dvdcss}/include/dvdcss/dvdcss.h])
dnl fi
dnl ;;
dnl esac
dnl fi
dnl
dnl dnl
dnl dnl dvdread module: check for libdvdread
......@@ -1344,70 +1276,6 @@ dnl fi
dnl fi
dnl fi
dnl
dnl dnl
dnl dnl dvdplay module: check for libdvdplay
dnl dnl
dnl AC_ARG_ENABLE(dvdplay,
dnl [ --enable-dvdplay dvdplay input module (default enabled)])
dnl if test "${enable_dvdplay}" != "no"
dnl then
dnl AC_ARG_WITH(dvdplay,
dnl [ --with-dvdplay=PATH libdvdplay headers and libraries])
dnl AC_ARG_WITH(dvdplay-tree,
dnl [ --with-dvdplay-tree=PATH libdvdplay tree for static linking])
dnl if test -z "${with_dvdplay}"
dnl then
dnl if test -z "${with_dvdplay_tree}"
dnl then
dnl AC_CHECK_HEADERS(dvdplay/dvdplay.h,[
dnl AX_ADD_PLUGINS([dvdplay])
dnl AX_ADD_LDFLAGS([dvdplay],[-ldvdplay ${LDFLAGS_dvdread} ${LDFLAGS_dvdcss}])
dnl AX_ADD_CPPFLAGS([dvdplay],[${CPPFLAGS_dvdread}])
dnl ],[
dnl if test -n "${enable_dvdplay}"
dnl then
dnl AC_MSG_WARN([Please get libdvdplay from http://www.videolan.org/.])
dnl AC_MSG_ERROR([cannot find libdvdplay headers])
dnl fi
dnl ])
dnl else
dnl AC_MSG_CHECKING(for libdvdplay.a in ${with_dvdplay_tree})
dnl real_dvdplay_tree="`cd ${with_dvdplay_tree} 2>/dev/null && pwd`"
dnl if test -z "${real_dvdplay_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_dvdplay_tree}])
dnl fi
dnl if test -f "${real_dvdplay_tree}/src/.libs/libdvdplay.a"
dnl then
dnl dnl Use a custom libdvdplay
dnl AC_MSG_RESULT(${real_dvdplay_tree}/src/.libs/libdvdplay.a)
dnl AX_ADD_BUILTINS([dvdplay])
dnl AX_ADD_LDFLAGS([dvdplay],[-L${real_dvdplay_tree}/src/.libs -ldvdplay ${LDFLAGS_dvdread} ${LDFLAGS_dvdcss}])
dnl AX_ADD_CPPFLAGS([dvdplay],[${CPPFLAGS_dvdread} -I${real_dvdplay_tree}/src])
dnl else
dnl dnl The given libdvdplay wasn't built
dnl AC_MSG_RESULT(no)
dnl AC_MSG_ERROR([cannot find ${real_dvdplay_tree}/src/.libs/libdvdplay.a, make sure you compiled libdvdplay in ${with_dvdplay_tree}])
dnl fi
dnl fi
dnl else
dnl AC_MSG_CHECKING(for dvdplay headers in ${with_dvdplay})
dnl if test -f "${with_dvdplay}/include/dvdplay/dvdplay.h"
dnl then
dnl dnl Use ${with_dvdplay}/include/dvdplay/dvdplay.h
dnl AC_MSG_RESULT(yes)
dnl AX_ADD_PLUGINS([dvdplay])
dnl AX_ADD_LDFLAGS([dvdplay],[-L${with_dvdplay}/lib -ldvdplay ${LDFLAGS_dvdread} ${LDFLAGS_dvdcss}])
dnl AX_ADD_CPPFLAGS([dvdplay],[${CPPFLAGS_dvdread} -I${with_dvdplay}/include])
dnl else
dnl dnl No libdvdplay could be found, sorry
dnl AC_MSG_RESULT(no)
dnl AC_MSG_ERROR([cannot find ${with_dvdplay}/include/dvdplay/dvdplay.h])
dnl fi
dnl fi
dnl fi
dnl
dnl libdvdnav plugin
......@@ -3904,8 +3772,6 @@ AC_CONFIG_FILES([
modules/access/Makefile
modules/access/dshow/Makefile
modules/access/dvb/Makefile
modules/access/dvd/Makefile
modules/access/dvdplay/Makefile
modules/access/dvdread/Makefile
modules/access/mms/Makefile
modules/access/pvr/Makefile
......
SOURCES_dvd = \
dvd.c \
dvd.h \
access.c \
demux.c \
seek.c \
seek.h \
es.c \
es.h \
ifo.c \
ifo.h \
udf.c \
udf.h \
summary.c \
summary.h \
dvdcss.h \
$(NULL)
/* access.c: DVD access plugin.
*****************************************************************************
* This plugins should handle all the known specificities of the DVD format,
* especially the 2048 bytes logical block size.
* It depends on:
* -libdvdcss for access and unscrambling
* -ifo.* for ifo parsing and analyse
* -udf.* to find files
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: access.c,v 1.15 2003/12/22 14:32:55 sam Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "../../demux/mpeg/system.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "es.h"
#include "seek.h"
#include "ifo.h"
#include "summary.h"
#include "iso_lang.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
/* called from outside */
static int DVDSetArea ( input_thread_t *, input_area_t * );
static int DVDSetProgram ( input_thread_t *, pgrm_descriptor_t * );
static ssize_t DVDRead ( input_thread_t *, byte_t *, size_t );
static void DVDSeek ( input_thread_t *, off_t );
static char * DVDParse( input_thread_t * );
/*
* Data access functions
*/
#define DVDTell LB2OFF( p_dvd->i_vts_start + p_dvd->i_vts_lb ) \
- p_input->stream.p_selected_area->i_start
/*****************************************************************************
* DVDOpen: open dvd
*****************************************************************************/
int E_(DVDOpen) ( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
char * psz_device;
thread_dvd_data_t * p_dvd;
input_area_t * p_area;
int i;
char * psz_dvdcss_env;
p_dvd = malloc( sizeof(thread_dvd_data_t) );
if( p_dvd == NULL )
{
msg_Err( p_input, "out of memory" );
return -1;
}
p_input->p_access_data = (void *)p_dvd;
p_input->pf_read = DVDRead;
p_input->pf_seek = DVDSeek;
p_input->pf_set_area = DVDSetArea;
p_input->pf_set_program = DVDSetProgram;
/* Parse command line */
if( !( psz_device = DVDParse( p_input ) ) )
{
free( p_dvd );
return -1;
}
/*
* set up input
*/
p_input->i_mtu = 0;
/* override environment variable DVDCSS_METHOD with config option
* (FIXME: this creates a small memory leak) */
psz_dvdcss_env = config_GetPsz( p_input, "dvdcss-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( p_dvd );
return -1;
}
sprintf( psz_env, "%s%s", "DVDCSS_METHOD=", psz_dvdcss_env );
putenv( psz_env );
}
if( psz_dvdcss_env ) free( psz_dvdcss_env );
/*
* get plugin ready
*/
p_dvd->dvdhandle = dvdcss_open( psz_device );
/* free allocated string */
free( psz_device );
if( p_dvd->dvdhandle == NULL )
{
msg_Err( p_input, "dvdcss cannot open device" );
free( p_dvd );
return -1;
}
if( dvdcss_seek( p_dvd->dvdhandle, 0, DVDCSS_NOFLAGS ) < 0 )
{
msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
dvdcss_close( p_dvd->dvdhandle );
free( p_dvd );
return -1;
}
/* Ifo allocation & initialisation */
if( IfoCreate( p_dvd ) < 0 )
{
msg_Err( p_input, "allcation error in ifo" );
dvdcss_close( p_dvd->dvdhandle );
free( p_dvd );
return -1;
}
if( IfoInit( p_dvd->p_ifo ) < 0 )
{
msg_Err( p_input, "fatal failure in ifo" );
IfoDestroy( p_dvd->p_ifo );
dvdcss_close( p_dvd->dvdhandle );
free( p_dvd );
return -1;
}
/* Set stream and area data */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.i_method = INPUT_METHOD_DVD;
p_input->stream.b_pace_control = 1;
p_input->stream.b_seekable = 1;
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 ) );
#define title_inf p_dvd->p_ifo->vmg.title_inf
msg_Dbg( p_input, "number of titles: %d", title_inf.i_title_nb );
#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 <= title_inf.i_title_nb ; i++ )
{
/* Titles are Program Chains */
input_AddArea( p_input, i, title_inf.p_attr[i-1].i_chapter_nb );
/* 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;
/* Offset to vts_i_0.ifo */
area[i]->i_plugin_data = p_dvd->p_ifo->i_start +
title_inf.p_attr[i-1].i_start_sector;
}
#undef area
p_dvd->i_title = p_dvd->i_title <= title_inf.i_title_nb ?
p_dvd->i_title : 1;
#undef title_inf
p_area = p_input->stream.pp_areas[p_dvd->i_title];
p_area->i_part = p_dvd->i_chapter <= p_area->i_part_nb ?
p_dvd->i_chapter : 1;
p_dvd->i_chapter = 1;
p_dvd->b_new_chapter = 0;
p_dvd->i_audio_nb = 0;
p_dvd->i_spu_nb = 0;
/* set title, chapter, audio and subpic */
if( DVDSetArea( p_input, p_area ) < 0 )
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
IfoDestroy( p_dvd->p_ifo );
dvdcss_close( p_dvd->dvdhandle );
free( p_dvd );
return -1;
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
if( !p_input->psz_demux || !*p_input->psz_demux )
{
p_input->psz_demux = "dvdold";
}
return 0;
}
/*****************************************************************************
* DVDClose: close dvd
*****************************************************************************/
void E_(DVDClose) ( 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 );
IfoDestroy( p_dvd->p_ifo );
dvdcss_close( p_dvd->dvdhandle );
free( p_dvd );
}
/*****************************************************************************
* DVDSetProgram: used to change angle
*****************************************************************************/
static int DVDSetProgram( 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;
int i_angle;
vlc_value_t val;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
i_angle = p_program->i_number;
/* DVD is actually mono-program: we only need the current angle
* number, so copy the data between programs */
memcpy( p_program,
p_input->stream.p_selected_program,
sizeof(pgrm_descriptor_t) );
p_program->i_number = i_angle;
p_input->stream.p_selected_program = p_program;
#define title \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
if( title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000 )
{
if( ( p_program->i_number - p_dvd->i_angle ) < 0 )
{
/* we have to go backwards */
p_dvd->i_map_cell = 0;
}
p_dvd->i_prg_cell += ( p_program->i_number - p_dvd->i_angle );
p_dvd->i_map_cell = CellPrg2Map( p_dvd );
p_dvd->i_map_cell += p_dvd->i_angle_cell;
p_dvd->i_vts_lb = CellFirstSector( p_dvd );
p_dvd->i_last_lb = CellLastSector( p_dvd );
p_dvd->i_angle = p_program->i_number;
}
else
{
p_dvd->i_angle = p_program->i_number;
}
#undef title
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 0;
}
/*****************************************************************************
* DVDSetArea: 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.
*****************************************************************************/
#define vmg p_dvd->p_ifo->vmg
#define vts p_dvd->p_ifo->vts
static void DVDFlushStream( input_thread_t * p_input )
{
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;
}
return;
}
static int DVDReadAngle( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
int i_angle_nb;
int i;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
i_angle_nb = vmg.title_inf.p_attr[p_dvd->i_title-1].i_angle_nb;
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 < i_angle_nb ; i++ )
{
input_AddProgram( p_input, i+1, 0 );
}
return i_angle_nb;
}
static int DVDSetArea( input_thread_t * p_input, input_area_t * p_area )
{
thread_dvd_data_t * p_dvd;
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 = 0;
if( p_area != p_input->stream.p_selected_area )
{
int i_vts_title;
uint32_t i_first;
uint32_t i_last;
unsigned int i;
/* Reset the Chapter position of the old title */
p_input->stream.p_selected_area->i_part = 1;
p_input->stream.p_selected_area = p_area;
/*
* We have to load all title information
*/
/* title number as it appears in the interface list */
p_dvd->i_title = p_area->i_id;
p_dvd->i_chapter_nb = p_area->i_part_nb;
if( IfoTitleSet( p_dvd->p_ifo, p_dvd->i_title ) < 0 )
{
msg_Err( p_input, "fatal error in vts ifo" );
free( p_dvd );
return -1;
}
/* title position inside the selected vts */
i_vts_title = vmg.title_inf.p_attr[p_dvd->i_title-1].i_title_num;
p_dvd->i_title_id =
vts.title_inf.p_title_start[i_vts_title-1].i_title_id;
msg_Dbg( p_input, "title %d vts_title %d pgc %d",
p_dvd->i_title, i_vts_title, p_dvd->i_title_id );
/* title set offset XXX: convert to block values */
p_dvd->i_vts_start =
vts.i_pos + vts.manager_inf.i_title_vob_start_sector;
/* last cell */
p_dvd->i_prg_cell = -1 +
vts.title_unit.p_title[p_dvd->i_title_id-1].title.i_cell_nb;
p_dvd->i_map_cell = 0;
p_dvd->i_map_cell = CellPrg2Map( p_dvd );
i_last = CellLastSector( p_dvd );
/* first cell */
p_dvd->i_prg_cell = 0;
p_dvd->i_map_cell = 0;
p_dvd->i_angle_cell = 0;
p_dvd->i_map_cell = CellPrg2Map ( p_dvd );
p_dvd->i_vts_lb = CellFirstSector( p_dvd );
p_dvd->i_last_lb = CellLastSector ( p_dvd );
/* Force libdvdcss to check its title key.
* It is only useful for title cracking method. Methods using the
* decrypted disc key are fast enough to check the key at each seek */
i_first = dvdcss_seek( p_dvd->dvdhandle,
p_dvd->i_vts_start + p_dvd->i_vts_lb,
DVDCSS_SEEK_KEY );
if( i_first < 0 )
{
msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
return -1;
}
/* Area definition */
p_input->stream.p_selected_area->i_start = LB2OFF( i_first );
p_input->stream.p_selected_area->i_size =
LB2OFF( i_last + 1 - p_dvd->i_vts_lb );
/* Destroy obsolete ES by reinitializing programs */
DVDFlushStream( p_input );
/* Angle management: angles are handled through programs */
p_dvd->i_angle_nb = DVDReadAngle( p_input );
if( ( p_dvd->i_angle <= 0 ) || p_dvd->i_angle > p_dvd->i_angle_nb )
{
p_dvd->i_angle = 1;
}
DVDSetProgram( p_input,
p_input->stream.pp_programs[p_dvd->i_angle-1] );
msg_Dbg( p_input, "title first %i, last %i, size %i",
i_first, i_last, i_last + 1 - p_dvd->i_vts_lb );
IfoPrintTitle( p_dvd );
/* No PSM to read in DVD mode, we already have all information */
p_input->stream.p_selected_program->b_is_ok = 1;
/* Find all ES in title with ifo data */
DVDReadVideo( p_input );
DVDReadAudio( p_input );
DVDReadSPU ( p_input );
if( p_input->p_demux )
{
DVDLaunchDecoders( 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 */
p_dvd->i_chapter = DVDSetChapter( p_dvd, p_area->i_part );
p_input->stream.p_selected_area->i_tell = DVDTell;
/* warn interface that something has changed */
p_input->stream.b_seekable = 1;
p_input->stream.b_changed = 1;
/* 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 0;
}
#undef vts
#undef vmg
#define title \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
/*****************************************************************************
* DVDRead: reads data packets.
*****************************************************************************
* Returns -1 in case of error, 0 in case of EOF, otherwise the number of
* bytes.
*****************************************************************************/
static ssize_t DVDRead( input_thread_t * p_input,
byte_t * p_buffer, size_t i_count )
{
thread_dvd_data_t * p_dvd;
int i_read;
int i_blocks;
int i_block_once = 0;
p_dvd = (thread_dvd_data_t *)(p_input->p_access_data);
i_read = 0;
i_blocks = OFF2LB(i_count);
while( i_blocks )
{
i_block_once = LbMaxOnce( p_dvd );
if( i_block_once > i_blocks )
{
i_block_once = i_blocks;
}
else if( i_block_once <= 0 )
{
/* EOT */
break;
}
if( i_block_once != dvdcss_read( p_dvd->dvdhandle, p_buffer,
i_block_once, DVDCSS_READ_DECRYPT ) )
{
return -1;
}
i_blocks -= i_block_once;
i_read += i_block_once;
p_buffer += LB2OFF( i_block_once );
/* Update global position */
p_dvd->i_vts_lb += i_block_once;
}
vlc_mutex_lock( &p_input->stream.stream_lock );
if( p_dvd->b_new_chapter )
{
p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
p_dvd->b_new_chapter = 0;
}
if( ( p_input->stream.p_selected_area->i_tell + LB2OFF( i_read )
>= p_input->stream.p_selected_area->i_size )
|| ( i_block_once <= 0 ) )
{
if( ( p_dvd->i_title + 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" );
p_dvd->i_title++;
DVDSetArea( p_input, p_input->stream.pp_areas[p_dvd->i_title] );
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
return LB2OFF( i_read );
}
/*****************************************************************************
* DVDSeek : 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 DVDSeek( input_thread_t * p_input, off_t i_off )
{
thread_dvd_data_t * p_dvd;
p_dvd = ( thread_dvd_data_t * )(p_input->p_access_data);
vlc_mutex_lock( &p_input->stream.stream_lock );
p_dvd->i_vts_lb = OFF2LB(i_off + p_input->stream.p_selected_area->i_start)
- p_dvd->i_vts_start;
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_dvd->i_prg_cell = Lb2CellPrg( p_dvd );
p_dvd->i_map_cell = Lb2CellMap( p_dvd );
if( CellIsInterleaved( p_dvd ) )
{
/* if we're inside a multi-angle zone, we have to choose i_sector
* in the current angle ; we can't do it all the time since cells
* can be very wide out of such zones */
p_dvd->i_vts_lb = CellFirstSector( p_dvd );
}
p_dvd->i_last_lb = CellLastSector( p_dvd );
p_dvd->i_chapter = CellPrg2Chapter( p_dvd );
if( dvdcss_seek( p_dvd->dvdhandle, p_dvd->i_vts_start + p_dvd->i_vts_lb,
DVDCSS_SEEK_MPEG ) < 0 )
{
msg_Err( p_input, "%s", dvdcss_error( p_dvd->dvdhandle ) );
p_input->b_error = 1;
return;
}
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.p_selected_area->i_part = p_dvd->i_chapter;
p_input->stream.p_selected_area->i_tell = DVDTell;
vlc_mutex_unlock( &p_input->stream.stream_lock );
msg_Dbg( p_input, "program cell: %d cell: %d chapter: %d tell "I64Fd,
p_dvd->i_prg_cell, p_dvd->i_map_cell, p_dvd->i_chapter, DVDTell );
return;
}
/*****************************************************************************
* DVDParse: parse command line
*****************************************************************************/
static char * DVDParse( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
struct stat stat_info;
char * psz_parser;
char * psz_device;
char * psz_raw;
char * psz_next;
vlc_bool_t b_options = 0;
int i_title = 1;
int i_chapter = 1;
int i_angle = 1;
int i;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
#ifdef WIN32
/* On Win32 we want the DVD access plugin to be explicitly requested,
* we end up with lots of problems otherwise */
if( !p_input->psz_access || !*p_input->psz_access ) return NULL;
#endif
psz_parser = psz_device = strdup( p_input->psz_name );
if( !psz_parser )
{
return NULL;
}
/* Parse input string :
* [device][@rawdevice][@[title][,[chapter][,angle]]] */
while( *psz_parser && *psz_parser != '@' )
{
psz_parser++;
}
if( *psz_parser == '@' )
{
/* Maybe found raw device or option list */
*psz_parser = '\0';
psz_raw = ++psz_parser;
}
else
{
psz_raw = "";
}
if( *psz_parser && !strtol( psz_parser, NULL, 10 ) )
{
/* what we've found is either a raw device or a partial option
* list e.g. @,29 or both a device and a list ; search end of string */
while( *psz_parser && *psz_parser != '@' )
{
psz_parser++;
}
if( *psz_parser == '@' )
{
/* found end of raw device, and beginning of options */
*psz_parser = '\0';
++psz_parser;
b_options = 1;
}
else
{
psz_parser = psz_raw + 1;
for( i=0 ; i<3 ; i++ )
{
if( !*psz_parser )
{
/* we have only a raw device */
break;
}
if( strtol( psz_parser, NULL, 10 ) )
{
/* we have only a partial list of options, no device */
psz_parser = psz_raw;
psz_raw = "";
b_options = 1;
break;
}
psz_parser++;
}
}
}
else
{
/* found beginning of options ; no raw device specified */
psz_raw = "";
b_options = 1;
}
if( b_options )
{
/* Found options */
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 );
}
}
p_dvd->i_title = i_title ? i_title : 1;
p_dvd->i_chapter = i_chapter ? i_chapter : 1;
p_dvd->i_angle = i_angle ? i_angle : 1;
}
if( *psz_raw )
{
if( *psz_raw )
{
/* check the raw device */
if( stat( psz_raw, &stat_info ) == -1 )
{
msg_Warn( p_input, "cannot stat() raw device `%s' (%s)",
psz_raw, strerror(errno));
/* put back '@' */
*(psz_raw - 1) = '@';
psz_raw = "";
}
else
{
char * psz_env;
#ifndef WIN32
if( !S_ISCHR(stat_info.st_mode) )
{
msg_Warn( p_input, "raw device %s is"
" not a valid char device", psz_raw );
/* put back '@' */
*(psz_raw - 1) = '@';
psz_raw = "";
}
else
#endif
{
psz_env = malloc( strlen("DVDCSS_RAW_DEVICE=")
+ strlen( psz_raw ) + 1 );
sprintf( psz_env, "DVDCSS_RAW_DEVICE=%s", psz_raw );
putenv( psz_env );
}
}
}
else
{
psz_raw = "";
}
}
if( !*psz_device )
{
free( psz_device );
if( !p_input->psz_access )
{
/* no device and no access specified: we probably don't want DVD */
return NULL;
}
psz_device = config_GetPsz( p_input, "dvd" );
}
#ifndef WIN32
/* check block device */
if( stat( psz_device, &stat_info ) == -1 )
{
msg_Warn( p_input, "cannot stat() device `%s' (%s)",
psz_device, strerror(errno));
free( psz_device );
return NULL;
}
if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode) )
{
msg_Warn( p_input,
"dvd module discarded (not a valid block device)" );
free( psz_device );
return NULL;
}
#endif
msg_Dbg( p_input, "dvd=%s raw=%s title=%d chapter=%d angle=%d",
psz_device, psz_raw, p_dvd->i_title,
p_dvd->i_chapter, p_dvd->i_angle );
return psz_device;
}
/* demux.c: DVD demux functions.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: demux.c,v 1.4 2004/03/03 20:39:51 gbazin Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "../../demux/mpeg/system.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
/* how many packets DVDDemux will read in each loop */
#define DVD_READ_ONCE 64
/*****************************************************************************
* Private structure
*****************************************************************************/
struct demux_sys_t
{
module_t * p_module;
mpeg_demux_t mpeg;
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int DVDDemux ( input_thread_t * );
void DVDLaunchDecoders( input_thread_t * );
/*****************************************************************************
* DVDInit: initialize DVD structures
*****************************************************************************/
int E_(DVDInit) ( 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 -1;
}
p_demux = p_input->p_demux_data = malloc( sizeof(demux_sys_t ) );
if( p_demux == NULL )
{
return -1;
}
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 -1;
}
p_input->pf_demux = DVDDemux;
p_input->pf_demux_control = demux_vaControlDefault;
p_input->pf_rewind = NULL;
vlc_mutex_lock( &p_input->stream.stream_lock );
DVDLaunchDecoders( p_input );
vlc_mutex_unlock( &p_input->stream.stream_lock );
return 0;
}
/*****************************************************************************
* DVDEnd: free DVD structures
*****************************************************************************/
void E_(DVDEnd) ( 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 );
}
/*****************************************************************************
* DVDDemux
*****************************************************************************/
static int DVDDemux( input_thread_t * p_input )
{
data_packet_t * p_data;
ssize_t i_result;
int i;
/* Read headers to compute payload length */
for( i = 0 ; i < DVD_READ_ONCE ; i++ )
{
i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data );
if( i_result < 0 )
{
return i_result;
}
else if( i_result == 0 )
{
return i;
}
p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
}
return i;
}
/*****************************************************************************
* dvd.c : DVD input module for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: dvd.c,v 1.11 2004/01/25 18:53:06 gbazin Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
* 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 <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <vlc/vlc.h>
#ifdef GOD_DAMN_DMCA
# include <stdio.h>
# include <fcntl.h>
# include <unistd.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <sys/uio.h> /* struct iovec */
# include <sys/ioctl.h>
# include <dlfcn.h>
# include <netinet/in.h>
# include <linux/cdrom.h>
# include "dvdcss.h"
#endif
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
int E_(DVDOpen) ( vlc_object_t * );
void E_(DVDClose) ( vlc_object_t * );
int E_(DVDInit) ( vlc_object_t * );
void E_(DVDEnd) ( vlc_object_t * );
#ifdef GOD_DAMN_DMCA
static void *p_libdvdcss;
static void ProbeLibDVDCSS ( void );
static void UnprobeLibDVDCSS( void );
#endif
/*****************************************************************************
* Module descriptor
*****************************************************************************/
#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") };
vlc_module_begin();
int i;
add_usage_hint( N_("[dvd:][device][@raw_device][@[title][,[chapter][,angle]]]") );
add_string( "dvdcss-method", NULL, NULL, CSSMETHOD_TEXT,
CSSMETHOD_LONGTEXT, VLC_TRUE );
change_string_list( psz_css_list, psz_css_list_text, 0 );
#ifdef GOD_DAMN_DMCA
set_description( _("DVD input (uses libdvdcss if installed)") );
i = 90;
#else
set_description( _("DVD input (uses libdvdcss)") );
i = 100;
#endif
add_shortcut( "dvdold" );
add_shortcut( "dvdsimple" );
set_capability( "access", i );
set_callbacks( E_(DVDOpen), E_(DVDClose) );
add_submodule();
set_capability( "demux", 0 );
set_callbacks( E_(DVDInit), E_(DVDEnd) );
#ifdef GOD_DAMN_DMCA
ProbeLibDVDCSS();
#endif
vlc_module_end();
#if 0 /* FIXME */
UnprobeLibDVDCSS();
#endif
/* Following functions are local */
#ifdef GOD_DAMN_DMCA
/*****************************************************************************
* ProbeLibDVDCSS: look for a libdvdcss object.
*****************************************************************************
* This functions looks for libdvdcss, using dlopen(), and fills function
* pointers with what it finds. On failure, uses the dummy libdvdcss
* replacement provided by vlc.
*****************************************************************************/
static void ProbeLibDVDCSS( void )
{
static char *pp_filelist[] = { "libdvdcss.so.2",
"./libdvdcss.so.2",
"./lib/libdvdcss.so.2",
"libdvdcss.so.1",
"./libdvdcss.so.1",
"./lib/libdvdcss.so.1",
NULL };
char **pp_file = pp_filelist;
/* Try to open the dynamic object */
do
{
p_libdvdcss = dlopen( *pp_file, RTLD_LAZY );
if( p_libdvdcss != NULL )
{
//X intf_WarnMsg( 2, "module: builtin module `dvd' found libdvdcss "
//X "in `%s'", *pp_file );
break;
}
pp_file++;
} while( *pp_file != NULL );
/* If libdvdcss.so was found, check that it's valid */
if( p_libdvdcss == NULL )
{
//X intf_ErrMsg( "dvd warning: libdvdcss.so.2 not present" );
}
else
{
____dvdcss_open = dlsym( p_libdvdcss, "dvdcss_open" );
____dvdcss_close = dlsym( p_libdvdcss, "dvdcss_close" );
____dvdcss_title = dlsym( p_libdvdcss, "dvdcss_title" );
____dvdcss_seek = dlsym( p_libdvdcss, "dvdcss_seek" );
____dvdcss_read = dlsym( p_libdvdcss, "dvdcss_read" );
____dvdcss_readv = dlsym( p_libdvdcss, "dvdcss_readv" );
____dvdcss_error = dlsym( p_libdvdcss, "dvdcss_error" );
if( ____dvdcss_open == NULL || ____dvdcss_close == NULL
|| ____dvdcss_title == NULL || ____dvdcss_seek == NULL
|| ____dvdcss_read == NULL || ____dvdcss_readv == NULL
|| ____dvdcss_error == NULL )
{
//X intf_ErrMsg( "dvd warning: missing symbols in libdvdcss.so.2, "
//X "this shouldn't happen !" );
dlclose( p_libdvdcss );
p_libdvdcss = NULL;
}
}
/* If libdvdcss was not found or was not valid, use the dummy
* replacement functions. */
if( p_libdvdcss == NULL )
{
//X intf_ErrMsg( "dvd warning: no valid libdvdcss found, "
//X "I will only play unencrypted DVDs" );
//X intf_ErrMsg( "dvd warning: get libdvdcss at "
//X "http://www.videolan.org/libdvdcss/" );
____dvdcss_open = dummy_dvdcss_open;
____dvdcss_close = dummy_dvdcss_close;
____dvdcss_title = dummy_dvdcss_title;
____dvdcss_seek = dummy_dvdcss_seek;
____dvdcss_read = dummy_dvdcss_read;
____dvdcss_readv = dummy_dvdcss_readv;
____dvdcss_error = dummy_dvdcss_error;
}
}
/*****************************************************************************
* UnprobeLibDVDCSS: free resources allocated by ProbeLibDVDCSS, if any.
*****************************************************************************/
static void UnprobeLibDVDCSS( void )
{
if( p_libdvdcss != NULL )
{
dlclose( p_libdvdcss );
p_libdvdcss = NULL;
}
}
/* Dummy libdvdcss with minimal DVD access. */
/*****************************************************************************
* Local structure
*****************************************************************************/
struct dvdcss_s
{
/* File descriptor */
int i_fd;
};
/*****************************************************************************
* dvdcss_open: initialize library, open a DVD device, crack CSS key
*****************************************************************************/
extern dvdcss_handle dummy_dvdcss_open ( char *psz_target )
{
dvdcss_handle dvdcss;
dvd_struct dvd;
/* Allocate the library structure */
dvdcss = malloc( sizeof( struct dvdcss_s ) );
if( dvdcss == NULL )
{
fprintf( stderr, "dvd error: "
"dummy libdvdcss could not allocate memory\n" );
return NULL;
}
/* Open the device */
dvdcss->i_fd = open( psz_target, 0 );
if( dvdcss->i_fd < 0 )
{
fprintf( stderr, "dvd error: "
"dummy libdvdcss could not open device\n" );
free( dvdcss );
return NULL;
}
/* Check for encryption or ioctl failure */
dvd.type = DVD_STRUCT_COPYRIGHT;
dvd.copyright.layer_num = 0;
if( ioctl( dvdcss->i_fd, DVD_READ_STRUCT, &dvd ) != 0
|| dvd.copyright.cpst )
{
fprintf( stderr, "dvd error: "
"dummy libdvdcss could not decrypt disc\n" );
close( dvdcss->i_fd );
free( dvdcss );
return NULL;
}
return dvdcss;
}
/*****************************************************************************
* dvdcss_error: return the last libdvdcss error message
*****************************************************************************/
extern char * dummy_dvdcss_error ( dvdcss_handle dvdcss )
{
return "generic error";
}
/*****************************************************************************
* dvdcss_seek: seek into the device
*****************************************************************************/
extern int dummy_dvdcss_seek ( dvdcss_handle dvdcss, int i_blocks,
int i_flags )
{
off_t i_read;
i_read = lseek( dvdcss->i_fd,
(off_t)i_blocks * (off_t)DVDCSS_BLOCK_SIZE, SEEK_SET );
return i_read / DVDCSS_BLOCK_SIZE;
}
/*****************************************************************************
* dvdcss_title: crack the current title key if needed
*****************************************************************************/
extern int dummy_dvdcss_title ( dvdcss_handle dvdcss, int i_block )
{
return 0;
}
/*****************************************************************************
* dvdcss_read: read data from the device, decrypt if requested
*****************************************************************************/
extern int dummy_dvdcss_read ( dvdcss_handle dvdcss, void *p_buffer,
int i_blocks,
int i_flags )
{
int i_bytes;
i_bytes = read( dvdcss->i_fd, p_buffer,
(size_t)i_blocks * DVDCSS_BLOCK_SIZE );
return i_bytes / DVDCSS_BLOCK_SIZE;
}
/*****************************************************************************
* dvdcss_readv: read data to an iovec structure, decrypt if reaquested
*****************************************************************************/
extern int dummy_dvdcss_readv ( dvdcss_handle dvdcss, void *p_iovec,
int i_blocks,
int i_flags )
{
int i_read;
i_read = readv( dvdcss->i_fd, (struct iovec*)p_iovec, i_blocks );
return i_read / DVDCSS_BLOCK_SIZE;
}
/*****************************************************************************
* dvdcss_close: close the DVD device and clean up the library
*****************************************************************************/
extern int dummy_dvdcss_close ( dvdcss_handle dvdcss )
{
int i_ret;
i_ret = close( dvdcss->i_fd );
if( i_ret < 0 )
{
return i_ret;
}
free( dvdcss );
return 0;
}
#endif
/*****************************************************************************
* dvd.h: thread structure of the DVD plugin
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd.h,v 1.2 2002/12/06 16:34:04 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* 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 DVD_LB_SIZE 2048
#define LB2OFF(x) ((off_t)(x) * (off_t)(DVD_LB_SIZE))
#define OFF2LB(x) ((x) >> 11)
/*****************************************************************************
* thread_dvd_data_t: extension of input_thread_t for DVD specificity.
*****************************************************************************/
typedef struct thread_dvd_data_s
{
dvdcss_handle dvdhandle; /* libdvdcss handle */
unsigned int i_audio_nb;
unsigned int i_spu_nb;
/* Navigation information */
unsigned int i_title;
unsigned int i_title_id;
unsigned int i_chapter_nb;
unsigned int i_chapter;
vlc_bool_t b_new_chapter;
unsigned int i_angle_nb;
unsigned int i_angle;
unsigned int i_map_cell; /* cell index in adress map */
unsigned int i_prg_cell; /* cell index in program map */
unsigned int i_angle_cell; /* cell index in the current angle */
unsigned int i_vts_start; /* offset to beginning of vts */
unsigned int i_vts_lb; /* sector in vts */
unsigned int i_last_lb; /* last sector of current cell */
/* Structure that contains all information of the DVD */
struct ifo_s * p_ifo;
} thread_dvd_data_t;
/*****************************************************************************
* dvdcss.h: Dummy libdvdcss header.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: dvdcss.h,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
* 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.
*****************************************************************************/
/*****************************************************************************
* The libdvdcss structure
*****************************************************************************/
typedef struct dvdcss_s* dvdcss_handle;
/*****************************************************************************
* Defines and flags
*****************************************************************************/
#define DVDCSS_BLOCK_SIZE 2048
#define DVDCSS_NOFLAGS 0
#define DVDCSS_READ_DECRYPT (1 << 0)
#define DVDCSS_SEEK_MPEG (1 << 0)
#define DVDCSS_SEEK_KEY (1 << 1)
/*****************************************************************************
* Exported prototypes
*****************************************************************************/
dvdcss_handle dummy_dvdcss_open ( char * );
int dummy_dvdcss_close ( dvdcss_handle );
int dummy_dvdcss_title ( dvdcss_handle, int );
int dummy_dvdcss_seek ( dvdcss_handle, int, int );
int dummy_dvdcss_read ( dvdcss_handle, void *, int, int );
int dummy_dvdcss_readv ( dvdcss_handle, void *, int, int );
char * dummy_dvdcss_error ( dvdcss_handle );
/*****************************************************************************
* Pointers which will be filled either with dummy_dvdcss functions or
* with the dlopen()ed ones.
*****************************************************************************/
#define ____dvdcss_open dvdcss_open
#define ____dvdcss_close dvdcss_close
#define ____dvdcss_title dvdcss_title
#define ____dvdcss_seek dvdcss_seek
#define ____dvdcss_read dvdcss_read
#define ____dvdcss_readv dvdcss_readv
#define ____dvdcss_error dvdcss_error
dvdcss_handle (* ____dvdcss_open ) ( char * );
int (* ____dvdcss_close ) ( dvdcss_handle );
int (* ____dvdcss_title ) ( dvdcss_handle, int );
int (* ____dvdcss_seek ) ( dvdcss_handle, int, int );
int (* ____dvdcss_read ) ( dvdcss_handle, void *, int, int );
int (* ____dvdcss_readv ) ( dvdcss_handle, void *, int, int );
char * (* ____dvdcss_error ) ( dvdcss_handle );
/* es.c: functions to find and select ES
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: es.c,v 1.6 2003/10/25 00:49:13 sam Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "ifo.h"
#include "summary.h"
#include "iso_lang.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
void DVDLaunchDecoders( input_thread_t * p_input );
#define vmg p_dvd->p_ifo->vmg
#define vts p_dvd->p_ifo->vts
#define ADDES( stream_id, private_id, fourcc, cat, lang, descr, size ) \
i_id = ( (private_id) << 8 ) | (stream_id); \
{ \
char *psz_descr; \
psz_descr = malloc( strlen(DecodeLanguage( lang )) + \
strlen(descr) + 1 ); \
if( psz_descr ) {strcpy( psz_descr, DecodeLanguage( lang ) ); \
strcat( psz_descr, descr );} \
p_es = input_AddES( p_input, NULL, i_id, cat, \
psz_descr, size ); \
if( psz_descr ) free( psz_descr ); \
} \
p_es->i_stream_id = (stream_id); \
p_es->i_fourcc = (fourcc);
/*****************************************************************************
* DVDReadVideo: read video ES
*****************************************************************************/
void DVDReadVideo( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
es_descriptor_t * p_es;
int i_id;
int i_ratio;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
/* ES 0 -> video MPEG2 */
IfoPrintVideo( p_dvd );
i_ratio = vts.manager_inf.video_attr.i_ratio;
if( i_ratio )
{
ADDES( 0xe0, 0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0,
"", sizeof(int) );
*(int*)(p_es->p_demux_data) = i_ratio;
}
else
{
ADDES( 0xe0, 0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0, "", 0 );
}
}
/*****************************************************************************
* DVDReadAudio: read audio ES
*****************************************************************************/
#define audio_status \
vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_audio_status[i-1]
void DVDReadAudio( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
es_descriptor_t * p_es;
int i_lang;
int i_id;
int i;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
p_dvd->i_audio_nb = 0;
/* Audio ES, in the order they appear in .ifo */
for( i = 1 ; i <= vts.manager_inf.i_audio_nb ; i++ )
{
IfoPrintAudio( p_dvd, i );
/* audio channel is active if first byte is 0x80 */
if( audio_status.i_available )
{
p_dvd->i_audio_nb++;
i_lang = vts.manager_inf.p_audio_attr[i-1].i_lang_code;
i_id = audio_status.i_position;
switch( vts.manager_inf.p_audio_attr[i-1].i_coding_mode )
{
case 0x00: /* A52 */
ADDES( 0xbd, 0x80 + audio_status.i_position,
VLC_FOURCC('a','5','2','b'), AUDIO_ES, i_lang,
" (A52)", 0 );
break;
case 0x02:
case 0x03: /* MPEG audio */
ADDES( 0xc0 + audio_status.i_position, 0,
VLC_FOURCC('m','p','g','a'), AUDIO_ES, i_lang,
" (mpeg)", 0 );
break;
case 0x04: /* LPCM */
ADDES( 0xbd, 0xa0 + audio_status.i_position,
VLC_FOURCC('l','p','c','b'), AUDIO_ES, i_lang,
" (lpcm)", 0 );
break;
case 0x06: /* DTS */
ADDES( 0xbd, 0x88 + audio_status.i_position,
VLC_FOURCC('d','t','s','b'), AUDIO_ES, i_lang,
" (dts)", 0 );
break;
default:
i_id = 0;
msg_Err( p_input, "unknown audio type %.2x",
vts.manager_inf.p_audio_attr[i-1].i_coding_mode );
}
}
}
}
#undef audio_status
/*****************************************************************************
* DVDReadSPU: read subpictures ES
*****************************************************************************/
#define spu_status \
vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_spu_status[i-1]
#define palette \
vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_yuv_color
void DVDReadSPU( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
es_descriptor_t * p_es;
int i_id;
int i;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
p_dvd->i_spu_nb = 0;
for( i = 1 ; i <= vts.manager_inf.i_spu_nb; i++ )
{
IfoPrintSpu( p_dvd, i );
if( spu_status.i_available )
{
p_dvd->i_spu_nb++;
/* there are several streams for one spu */
if( vts.manager_inf.video_attr.i_ratio )
{
/* 16:9 */
switch( vts.manager_inf.video_attr.i_perm_displ )
{
case 1:
i_id = spu_status.i_position_pan;
break;
case 2:
i_id = spu_status.i_position_letter;
break;
default:
i_id = spu_status.i_position_wide;
break;
}
}
else
{
/* 4:3 */
i_id = spu_status.i_position_43;
}
if( vmg.title.pi_yuv_color )
{
ADDES( 0xbd, 0x20 + i_id, VLC_FOURCC('s','p','u','b'), SPU_ES,
vts.manager_inf.p_spu_attr[i-1].i_lang_code, "",
sizeof(int) + 16*sizeof(uint32_t) );
*(int*)p_es->p_demux_data = 0xBeeF;
memcpy( (char*)p_es->p_demux_data + sizeof(int),
palette, 16*sizeof(uint32_t) );
}
else
{
ADDES( 0xbd, 0x20 + i_id, VLC_FOURCC('s','p','u','b'), SPU_ES,
vts.manager_inf.p_spu_attr[i-1].i_lang_code, "", 0 );
}
}
}
}
#undef palette
#undef spu_status
#undef vts
#undef vmg
/*****************************************************************************
* DVDLaunchDecoders: select ES for video, audio and spu
*****************************************************************************/
void DVDLaunchDecoders( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
unsigned int i_audio;
unsigned int i_spu;
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
/* Select Video stream (always 0) */
input_SelectES( p_input, p_input->stream.pp_es[0] );
/* Select audio stream */
if( p_dvd->i_audio_nb > 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 > p_dvd->i_audio_nb )
{
config_PutInt( p_input, "audio-channel", 1 );
i_audio = 1;
}
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_ifo->vts.manager_inf.i_audio_nb ) )
{
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] );
}
}
/* Select subtitle */
if( p_dvd->i_spu_nb )
{
/* for spu, default is none */
i_spu = config_GetInt( p_input, "spu-channel" );
if( i_spu < 0 || i_spu > p_dvd->i_spu_nb )
{
config_PutInt( p_input, "spu-channel", 0 );
i_spu = 0;
}
if( i_spu > 0 )
{
unsigned int i = 0, j = 0;
for( i = 0; i < p_input->stream.i_es_number; i++ )
{
if ( p_input->stream.pp_es[i]->i_fourcc
== VLC_FOURCC('s','p','u','b') )
{
j++;
if ( i_spu == j ) break;
}
}
if( i_spu == j )
{
input_SelectES( p_input, p_input->stream.pp_es[i] );
}
}
}
}
/* dvd_es.h: functions to find and select ES
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: es.h,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* 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.
*****************************************************************************/
void DVDLaunchDecoders ( input_thread_t * );
void DVDReadVideo ( input_thread_t * );
void DVDReadAudio ( input_thread_t * );
void DVDReadSPU ( input_thread_t * );
/*****************************************************************************
* ifo.c: Functions for ifo parsing
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: ifo.c,v 1.6 2003/10/25 00:49:13 sam Exp $
*
* Authors: Stphane Borel <stef@via.ecp.fr>
* German Tischler <tanis@gaspode.franken.de>
*
* based on:
* - libifo by Thomas Mirlacher <dent@cosy.sbg.ac.at>
* - IFO structure documentation by Thomas Mirlacher, Bjrn Englund,
* Hkan Hjort
*
* 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 <stdio.h>
#include <stdlib.h>
#include <vlc/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <string.h>
#include <fcntl.h>
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "ifo.h"
#include "udf.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
void CommandRead ( command_desc_t );
static int ReadTitle ( ifo_t * , title_t *, int, int );
static int FreeTitle ( title_t * );
static int ReadUnitInf ( ifo_t * , unit_inf_t *, int, int );
static int FreeUnitInf ( unit_inf_t * );
static int ReadTitleUnit ( ifo_t * , title_unit_t *, int );
static int FreeTitleUnit ( title_unit_t * );
static int ReadVobuMap ( ifo_t * , vobu_map_t *, int );
static int FreeVobuMap ( vobu_map_t * );
static int ReadCellInf ( ifo_t * , cell_inf_t *, int );
static int FreeCellInf ( cell_inf_t * );
static int FreeTitleSet ( vts_t * );
static uint8_t* FillBuffer ( ifo_t *, uint8_t *, int );
static uint8_t ReadByte ( ifo_t *, uint8_t *, uint8_t ** );
static void ReadBytes ( ifo_t *, uint8_t *, uint8_t **, uint8_t *, int );
static void DumpBytes ( ifo_t *, uint8_t *, uint8_t **, int );
static uint16_t ReadWord ( ifo_t *, uint8_t *, uint8_t ** );
static uint32_t ReadDouble ( ifo_t *, uint8_t *, uint8_t ** );
static uint64_t ReadQuad ( ifo_t *, uint8_t *, uint8_t ** );
/*
* IFO Management.
*/
/*****************************************************************************
* IfoCreate : Creates an ifo structure and prepares for parsing directly
* on DVD device
*****************************************************************************/
int IfoCreate( thread_dvd_data_t * p_dvd )
{
p_dvd->p_ifo = malloc( sizeof(ifo_t) );
if( p_dvd->p_ifo == NULL )
{
return -1;
}
/* memset to 0 to avoid crashing on deallocation later */
memset( p_dvd->p_ifo, 0, sizeof(ifo_t) );
/* if we are here the dvd device has already been opened */
p_dvd->p_ifo->dvdhandle = p_dvd->dvdhandle;
return 0;
}
/*****************************************************************************
* IfoInit : Reads information from the management table.
*****************************************************************************/
int IfoInit( ifo_t * p_ifo )
{
uint8_t p_buf[DVD_LB_SIZE];
uint8_t * p_tmp;
uint64_t i_temp;
int i, j, k;
int i_start;
/* find the start sector of video information on the dvd */
p_ifo->i_start = DVDUDFFindFile( p_ifo->dvdhandle, "/VIDEO_TS/VIDEO_TS.IFO" );
if( !p_ifo->i_start ) return -1;
p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start );
/*i_start = p_ifo->i_pos; */
/*
* read the video manager information table
*/
#define MGINF p_ifo->vmg.manager_inf
/*fprintf( stderr, "VMGI\n" ); */
ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id, 12 );
MGINF.psz_id[12] = '\0';
MGINF.i_vmg_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 12 );
MGINF.i_vmg_inf_end_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp );
MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_volume_nb = ReadWord( p_ifo, p_buf, &p_tmp );
MGINF.i_volume = ReadWord( p_ifo, p_buf, &p_tmp );
MGINF.i_disc_side = ReadByte( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 19 );
MGINF.i_title_set_nb = ReadWord( p_ifo, p_buf, &p_tmp );
ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.ps_provider_id, 32 );
MGINF.i_pos_code = ReadQuad( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 24 );
MGINF.i_vmg_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_first_play_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 56 );
MGINF.i_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_parental_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_vts_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_text_data_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 32 );
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "vmgi audio nb : %d\n", MGINF.i_audio_nb ); */
for( i = 0 ; i < 8 ; i++ )
{
i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
}
DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "vmgi subpic nb : %d\n", MGINF.i_spu_nb ); */
for( i = 0 ; i < MGINF.i_spu_nb ; i++ )
{
ReadBytes( p_ifo, p_buf, &p_tmp, (uint8_t*)(&i_temp), 6 );
/* FIXME : take care of endianness */
}
/*
* read first play title.
*/
/*fprintf(stderr,"readtitle %i\n", MGINF.i_first_play_title_start_byte & 0x7ff ); */
if( ReadTitle( p_ifo, &p_ifo->vmg.title, p_ifo->i_start
+ OFF2LB( MGINF.i_first_play_title_start_byte ),
MGINF.i_first_play_title_start_byte & 0x7ff ) < 0 )
{
return -1;
}
/*
* fills the title information structure.
*/
#define TITINF p_ifo->vmg.title_inf
if( MGINF.i_title_inf_start_sector )
{
p_tmp = FillBuffer( p_ifo, p_buf,
p_ifo->i_start + MGINF.i_title_inf_start_sector );
/*fprintf( stderr, "title inf %d\n", p_ifo->i_pos ); */
TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "title_inf: TTU nb %d\n", TITINF.i_title_nb ); */
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
TITINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
/* parsing of title attributes */
TITINF.p_attr = malloc( TITINF.i_title_nb *sizeof(title_attr_t) );
if( TITINF.p_attr == NULL )
{
return -1;
}
for( i = 0 ; i < TITINF.i_title_nb ; i++ )
{
TITINF.p_attr[i].i_play_type = ReadByte( p_ifo, p_buf, &p_tmp );
TITINF.p_attr[i].i_angle_nb = ReadByte( p_ifo, p_buf, &p_tmp );
TITINF.p_attr[i].i_chapter_nb = ReadWord( p_ifo, p_buf, &p_tmp );
TITINF.p_attr[i].i_parental_id = ReadWord( p_ifo, p_buf, &p_tmp );
TITINF.p_attr[i].i_title_set_num = ReadByte( p_ifo, p_buf, &p_tmp );
TITINF.p_attr[i].i_title_num = ReadByte( p_ifo, p_buf, &p_tmp );
TITINF.p_attr[i].i_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "title_inf: %d %d %d\n", TITINF.p_attr[i].i_chapter_nb, TITINF.p_attr[i].i_title_set_num, TITINF.p_attr[i].i_title_num ); */
}
}
else
{
TITINF.p_attr = NULL;
}
#undef TITINF
/*
* fills the title unit structure.
*/
if( MGINF.i_title_unit_start_sector )
{
if( ReadTitleUnit( p_ifo, &p_ifo->vmg.title_unit, p_ifo->i_start
+ MGINF.i_title_unit_start_sector ) < 0 )
{
return -1;
}
}
/*
* fills the structure about parental information.
*/
#define PARINF p_ifo->vmg.parental_inf
if( MGINF.i_parental_inf_start_sector )
{
p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start +
MGINF.i_parental_inf_start_sector );
i_start = p_ifo->i_pos;
/*fprintf( stderr, "PTL\n" ); */
PARINF.i_country_nb = ReadWord( p_ifo, p_buf, &p_tmp );
PARINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp );
PARINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
PARINF.p_parental_desc = malloc( PARINF.i_country_nb
* sizeof(parental_desc_t) );
if( PARINF.p_parental_desc == NULL )
{
return -1;
}
for( i = 0 ; i < PARINF.i_country_nb ; i++ )
{
ReadBytes( p_ifo, p_buf, &p_tmp,
PARINF.p_parental_desc[i].ps_country_code, 2 );
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
PARINF.p_parental_desc[i].i_parental_mask_start_byte =
ReadWord( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
}
PARINF.p_parental_mask = malloc( PARINF.i_country_nb
* sizeof(parental_mask_t) );
if( PARINF.p_parental_mask == NULL )
{
return -1;
}
for( i = 0 ; i < PARINF.i_country_nb ; i++ )
{
p_tmp = FillBuffer( p_ifo, p_buf, i_start + OFF2LB(
PARINF.p_parental_desc[i].i_parental_mask_start_byte ) )
+ (PARINF.p_parental_desc[i].i_parental_mask_start_byte & 0x7ff);
for( j = 0 ; j < 8 ; j++ )
{
PARINF.p_parental_mask[i].ppi_mask[j] =
malloc( ( PARINF.i_vts_nb + 1 ) * sizeof(uint16_t) );
if( PARINF.p_parental_mask[i].ppi_mask[j] == NULL )
{
return -1;
}
for( k = 0 ; k < PARINF.i_vts_nb + 1 ; k++ )
{
PARINF.p_parental_mask[i].ppi_mask[j][k] =
ReadWord( p_ifo, p_buf, &p_tmp );
}
}
}
}
#undef PARINF
/*
* information and attributes about for each vts.
*/
#define VTSINF p_ifo->vmg.vts_inf
if( MGINF.i_vts_inf_start_sector )
{
uint64_t i_temp;
p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_start +
MGINF.i_vts_inf_start_sector );
i_start = p_ifo->i_pos;
/*fprintf( stderr, "VTS ATTR\n" ); */
VTSINF.i_vts_nb = ReadWord( p_ifo, p_buf, &p_tmp );;
/*fprintf( stderr, "VTS ATTR Nb: %d\n", VTSINF.i_vts_nb ); */
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
VTSINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
VTSINF.pi_vts_attr_start_byte =
malloc( VTSINF.i_vts_nb * sizeof(uint32_t) );
if( VTSINF.pi_vts_attr_start_byte == NULL )
{
return -1;
}
for( i = 0 ; i < VTSINF.i_vts_nb ; i++ )
{
VTSINF.pi_vts_attr_start_byte[i] =
ReadDouble( p_ifo, p_buf, &p_tmp );
}
VTSINF.p_vts_attr = malloc( VTSINF.i_vts_nb * sizeof(vts_attr_t) );
if( VTSINF.p_vts_attr == NULL )
{
return -1;
}
for( i = 0 ; i < VTSINF.i_vts_nb ; i++ )
{
p_tmp = FillBuffer( p_ifo, p_buf, i_start +
OFF2LB( VTSINF.pi_vts_attr_start_byte[i] ) )
+ ( VTSINF.pi_vts_attr_start_byte[i] & 0x7ff );
VTSINF.p_vts_attr[i].i_last_byte =
ReadDouble( p_ifo, p_buf, &p_tmp );
VTSINF.p_vts_attr[i].i_cat_app_type =
ReadDouble( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
VTSINF.p_vts_attr[i].i_vts_menu_audio_nb =
ReadByte( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "m audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_audio_nb ); */
for( j = 0 ; j < 8 ; j++ )
{
i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
}
DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
VTSINF.p_vts_attr[i].i_vts_menu_spu_nb =
ReadByte( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "m subp nb : %d\n", VTSINF.p_vts_attr[i].i_vts_menu_spu_nb ); */
for( j = 0 ; j < 28 ; j++ )
{
/* FIXME : Fix endianness issue here */
ReadBytes( p_ifo, p_buf, &p_tmp, (uint8_t*)(&i_temp), 6 );
}
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
VTSINF.p_vts_attr[i].i_vts_title_audio_nb =
ReadDouble( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "tt audio nb : %d\n", VTSINF.p_vts_attr[i].i_vts_title_audio_nb ); */
for( j = 0 ; j < 8 ; j++ )
{
i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );;
}
DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
VTSINF.p_vts_attr[i].i_vts_title_spu_nb =
ReadByte( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "tt subp nb : %d\n", VTSINF.p_vts_attr[i].i_vts_title_spu_nb ); */
for( j = 0 ; j < 28 /*VTSINF.p_vts_vts_inf[i].i_vtstt_subpic_nb*/ ; j++ )
{
/* FIXME : Fix endianness issue here */
ReadBytes( p_ifo, p_buf, &p_tmp, (uint8_t*)(&i_temp), 6 );
}
}
}
#undef VTSINF
/*
* global cell map.
*/
if( MGINF.i_cell_inf_start_sector )
{
if( ReadCellInf( p_ifo, &p_ifo->vmg.cell_inf, p_ifo->i_start +
MGINF.i_cell_inf_start_sector ) < 0 )
{
return -1;
}
}
/*
* global vob unit map.
*/
if( MGINF.i_vobu_map_start_sector )
{
if( ReadVobuMap( p_ifo, &p_ifo->vmg.vobu_map, p_ifo->i_start +
MGINF.i_vobu_map_start_sector ) < 0 )
{
return -1;
}
}
#undef MGINF
p_ifo->vts.b_initialized = 0;
return 0;
}
/*****************************************************************************
* IfoTitleSet: Parse vts*.ifo files to fill the Video Title Set structure.
*****************************************************************************/
int IfoTitleSet( ifo_t * p_ifo, int i_title )
{
uint8_t p_buf[DVD_LB_SIZE];
uint8_t * p_tmp;
int i_off;
int i_start;
uint64_t i_temp;
uint16_t i_short;
int i, j;
if( p_ifo->vts.b_initialized )
{
FreeTitleSet( &p_ifo->vts );
}
i_off = p_ifo->vmg.title_inf.p_attr[i_title-1].i_start_sector
+ p_ifo->i_start;
/*fprintf(stderr, "offset: %d\n" , i_off ); */
p_tmp = FillBuffer( p_ifo, p_buf, i_off );
/*i_start = p_ifo->i_pos; */
p_ifo->vts.i_pos = p_ifo->i_pos;
#define MGINF p_ifo->vts.manager_inf
/*
* read manager information
*/
/*fprintf( stderr, "VTSI\n" ); */
ReadBytes( p_ifo, p_buf, &p_tmp, MGINF.psz_id , 12 );
MGINF.psz_id[12] = '\0';
MGINF.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 12 );
MGINF.i_inf_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
MGINF.i_spec_ver = ReadByte( p_ifo, p_buf, &p_tmp );
MGINF.i_cat = ReadDouble( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 90 );
MGINF.i_inf_end_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 60 );
MGINF.i_menu_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_title_vob_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_title_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_title_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_menu_unit_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_time_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_menu_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_menu_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_cell_inf_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
MGINF.i_vobu_map_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 24 );
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
MGINF.i_menu_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
for( i = 0 ; i < 8 ; i++ )
{
i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
}
DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
MGINF.i_menu_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
for( i = 0 ; i < 28 ; i++ )
{
/* FIXME : take care of endianness */
ReadBytes( p_ifo, p_buf, &p_tmp, (uint8_t*)(&i_temp), 6 );
}
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
i_short = ReadWord( p_ifo, p_buf, &p_tmp );
i_short >>= 2;
MGINF.video_attr.i_mode = i_short & 0x1;
i_short >>= 1;
MGINF.video_attr.i_letterboxed = i_short & 0x1;
i_short >>= 1;
MGINF.video_attr.i_source_res = i_short & 0x3;
i_short >>= 2;
MGINF.video_attr.i_line21_2 = i_short & 0x1;
i_short >>= 1;
MGINF.video_attr.i_line21_1 = i_short & 0x1;
i_short >>= 1;
MGINF.video_attr.i_perm_displ = i_short & 0x3;
i_short >>= 2;
MGINF.video_attr.i_ratio = i_short & 0x3;
i_short >>= 2;
MGINF.video_attr.i_system = i_short & 0x3;
i_short >>= 2;
MGINF.video_attr.i_compression = i_short & 0x3;
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
MGINF.i_audio_nb = ReadByte( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "vtsi audio nb : %d\n", MGINF.i_audio_nb ); */
for( i = 0 ; i < 8 ; i++ )
{
i_temp = ReadQuad( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "Audio %d: "I64Fx"\n", i, i_temp ); */
i_temp >>= 8;
MGINF.p_audio_attr[i].i_bar = i_temp & 0xff;
i_temp >>= 8;
MGINF.p_audio_attr[i].i_caption = i_temp & 0xff;
i_temp >>= 8;
MGINF.p_audio_attr[i].i_foo = i_temp & 0xff;
i_temp >>= 8;
MGINF.p_audio_attr[i].i_lang_code = i_temp & 0xffff;
i_temp >>= 16;
MGINF.p_audio_attr[i].i_num_channels = i_temp & 0x7;
i_temp >>= 3;
MGINF.p_audio_attr[i].i_test = i_temp & 0x1;
i_temp >>= 1;
MGINF.p_audio_attr[i].i_sample_freq = i_temp & 0x3;
i_temp >>= 2;
MGINF.p_audio_attr[i].i_quantization = i_temp & 0x3;
i_temp >>= 2;
MGINF.p_audio_attr[i].i_appl_mode = i_temp & 0x3;
i_temp >>= 2;
MGINF.p_audio_attr[i].i_type = i_temp & 0x3;
i_temp >>= 2;
MGINF.p_audio_attr[i].i_multichannel_extension = i_temp & 0x1;
i_temp >>= 1;
MGINF.p_audio_attr[i].i_coding_mode = i_temp & 0x7;
}
DumpBytes( p_ifo, p_buf, &p_tmp, 17 );
MGINF.i_spu_nb = ReadByte( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "vtsi subpic nb : %d\n", MGINF.i_spu_nb ); */
for( i=0 ; i<MGINF.i_spu_nb ; i++ )
{
ReadBytes( p_ifo, p_buf, &p_tmp, (uint8_t*)(&i_temp), 6 );
i_temp = hton64( i_temp ) >> 16;
/*fprintf( stderr, "Subpic %d: "I64Fx"\n", i, i_temp ); */
MGINF.p_spu_attr[i].i_caption = i_temp & 0xff;
i_temp >>= 8;
MGINF.p_spu_attr[i].i_foo = i_temp & 0xff;
i_temp >>= 8;
MGINF.p_spu_attr[i].i_lang_code = i_temp & 0xffff;
i_temp >>= 16;
MGINF.p_spu_attr[i].i_prefix = i_temp & 0xffff;
}
/*
* read title information: set of pointers to title
*/
#define TITINF p_ifo->vts.title_inf
if( MGINF.i_title_inf_start_sector )
{
p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos +
MGINF.i_title_inf_start_sector );
i_start = p_ifo->i_pos;
/*fprintf( stderr, "VTS PTR\n" ); */
TITINF.i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "VTS title_inf nb: %d\n", TITINF.i_title_nb ); */
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
TITINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
TITINF.pi_start_byte = malloc( TITINF.i_title_nb * sizeof(uint32_t) );
if( TITINF.pi_start_byte == NULL )
{
return -1;
}
for( i = 0 ; i < TITINF.i_title_nb ; i++ )
{
TITINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
}
/* Parsing of tts */
TITINF.p_title_start = malloc( TITINF.i_title_nb
* sizeof(title_start_t) );
if( TITINF.p_title_start == NULL )
{
return -1;
}
for( i = 0 ; i < TITINF.i_title_nb ; i++ )
{
p_tmp = FillBuffer( p_ifo, p_buf, i_start +
OFF2LB( TITINF.pi_start_byte[i] ) )
+ (TITINF.pi_start_byte[i] & 0x7ff);
TITINF.p_title_start[i].i_title_id =
ReadWord( p_ifo, p_buf, &p_tmp );
TITINF.p_title_start[i].i_chapter =
ReadWord( p_ifo, p_buf, &p_tmp );
}
}
#undef TITINF
/*
* menu unit information
*/
if( MGINF.i_menu_unit_start_sector )
{
if( ReadTitleUnit( p_ifo, &p_ifo->vts.menu_unit, p_ifo->vts.i_pos +
MGINF.i_menu_unit_start_sector ) < 0 )
{
return -1;
}
}
/*
* title unit information
*/
if( MGINF.i_title_unit_start_sector )
{
if( ReadUnitInf( p_ifo, &p_ifo->vts.title_unit, p_ifo->vts.i_pos +
MGINF.i_title_unit_start_sector, 0 ) < 0 )
{
return -1;
}
}
/*
* time map information
*/
#define TIMINF p_ifo->vts.time_inf
if( MGINF.i_time_inf_start_sector )
{
uint8_t p_buf[DVD_LB_SIZE];
p_tmp = FillBuffer( p_ifo, p_buf, p_ifo->vts.i_pos +
MGINF.i_time_inf_start_sector );
/*fprintf( stderr, "TMAP\n" ); */
TIMINF.i_nb = ReadWord( p_ifo, p_buf, &p_tmp );;
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
TIMINF.i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
TIMINF.pi_start_byte = malloc( TIMINF.i_nb * sizeof(uint32_t) );
if( TIMINF.pi_start_byte == NULL )
{
return -1;
}
for( i = 0 ; i < TIMINF.i_nb ; i++ )
{
TIMINF.pi_start_byte[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
}
TIMINF.p_time_map = malloc( TIMINF.i_nb * sizeof(time_map_t) );
if( TIMINF.p_time_map == NULL )
{
return -1;
}
for( i = 0 ; i < TIMINF.i_nb ; i++ )
{
TIMINF.p_time_map[i].i_time_unit = ReadByte( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
TIMINF.p_time_map[i].i_entry_nb = ReadWord( p_ifo, p_buf, &p_tmp );
if( TIMINF.p_time_map[i].i_entry_nb )
{
TIMINF.p_time_map[i].pi_sector =
malloc( TIMINF.p_time_map[i].i_entry_nb * sizeof(uint32_t) );
if( TIMINF.p_time_map[i].pi_sector == NULL )
{
return -1;
}
for( j = 0 ; j < TIMINF.p_time_map[i].i_entry_nb ; j++ )
{
TIMINF.p_time_map[i].pi_sector[j] =
ReadDouble( p_ifo, p_buf, &p_tmp );
}
}
}
}
#undef TIMINF
if( MGINF.i_menu_cell_inf_start_sector
&& ReadCellInf( p_ifo, &p_ifo->vts.menu_cell_inf, p_ifo->vts.i_pos +
MGINF.i_menu_cell_inf_start_sector ) < 0 )
{
return -1;
}
if( MGINF.i_menu_vobu_map_start_sector
&& ReadVobuMap( p_ifo, &p_ifo->vts.menu_vobu_map, p_ifo->vts.i_pos +
MGINF.i_menu_vobu_map_start_sector ) < 0 )
{
return -1;
}
if( MGINF.i_cell_inf_start_sector
&& ReadCellInf( p_ifo, &p_ifo->vts.cell_inf, p_ifo->vts.i_pos +
MGINF.i_cell_inf_start_sector ) )
{
return -1;
}
if( MGINF.i_vobu_map_start_sector
&& ReadVobuMap( p_ifo, &p_ifo->vts.vobu_map, p_ifo->vts.i_pos +
MGINF.i_vobu_map_start_sector ) )
{
return -1;
}
#undef MGINF
#if 0
intf_Warn( p_input, 4, "vts %d initialized",
p_ifo->vmg.title_inf.p_attr[i_title-1].i_title_set_num );
#endif
p_ifo->vts.b_initialized = 1;
return 0;
}
/*****************************************************************************
* FreeTitleSet : free all structures allocated by IfoTitleSet
*****************************************************************************/
static int FreeTitleSet( vts_t * p_vts )
{
int i;
if( p_vts->manager_inf.i_vobu_map_start_sector )
{
FreeVobuMap( &p_vts->vobu_map );
}
if( p_vts->manager_inf.i_cell_inf_start_sector )
{
FreeCellInf( &p_vts->cell_inf );
}
if( p_vts->manager_inf.i_menu_vobu_map_start_sector )
{
FreeVobuMap( &p_vts->menu_vobu_map );
}
if( p_vts->manager_inf.i_menu_cell_inf_start_sector )
{
FreeCellInf( &p_vts->menu_cell_inf );
}
if( p_vts->manager_inf.i_time_inf_start_sector )
{
for( i = 0 ; i < p_vts->time_inf.i_nb ; i++ )
{
if( p_vts->time_inf.p_time_map[i].i_entry_nb )
{
free( p_vts->time_inf.p_time_map[i].pi_sector );
}
}
free( p_vts->time_inf.p_time_map );
free( p_vts->time_inf.pi_start_byte );
}
if( p_vts->manager_inf.i_title_unit_start_sector )
{
FreeUnitInf( &p_vts->title_unit );
}
if( p_vts->manager_inf.i_menu_unit_start_sector )
{
FreeTitleUnit( &p_vts->menu_unit );
}
if( p_vts->manager_inf.i_title_inf_start_sector )
{
free( p_vts->title_inf.pi_start_byte );
free( p_vts->title_inf.p_title_start );
}
p_vts->b_initialized = 0;
return 0;
}
/*****************************************************************************
* IfoDestroy : Frees all the memory allocated to ifo structures
*****************************************************************************/
void IfoDestroy( ifo_t * p_ifo )
{
int i, j;
FreeTitleSet( &p_ifo->vts );
if( p_ifo->vmg.manager_inf.i_vobu_map_start_sector )
{
FreeVobuMap( &p_ifo->vmg.vobu_map );
}
if( p_ifo->vmg.manager_inf.i_cell_inf_start_sector )
{
FreeCellInf( &p_ifo->vmg.cell_inf );
}
if( p_ifo->vmg.manager_inf.i_vts_inf_start_sector )
{
free( p_ifo->vmg.vts_inf.p_vts_attr );
free( p_ifo->vmg.vts_inf.pi_vts_attr_start_byte );
}
/* free parental information structures */
if( p_ifo->vmg.manager_inf.i_parental_inf_start_sector )
{
for( i = 0 ; i < p_ifo->vmg.parental_inf.i_country_nb ; i++ )
{
for( j = 0 ; j < 8 ; j++ )
{
if ( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] != NULL )
free( p_ifo->vmg.parental_inf.p_parental_mask[i].ppi_mask[j] );
}
}
if ( p_ifo->vmg.parental_inf.p_parental_mask != NULL )
free( p_ifo->vmg.parental_inf.p_parental_mask );
if ( p_ifo->vmg.parental_inf.p_parental_desc != NULL )
free( p_ifo->vmg.parental_inf.p_parental_desc );
}
if( p_ifo->vmg.manager_inf.i_title_unit_start_sector )
{
FreeTitleUnit( &p_ifo->vmg.title_unit );
}
if( p_ifo->vmg.manager_inf.i_title_inf_start_sector )
{
free( p_ifo->vmg.title_inf.p_attr );
}
FreeTitle( &p_ifo->vmg.title );
free( p_ifo );
return;
}
/*
* Function common to Video Manager and Video Title set Processing
*/
/*****************************************************************************
* ReadTitle : Fills the title structure.
*****************************************************************************
* Titles are logical stream units that correspond to a whole inside the dvd.
* Several title can point to the same part of the physical DVD, and give
* map to different anglesfor instance.
*****************************************************************************/
static int ReadTitle( ifo_t * p_ifo, title_t * p_title, int i_block, int i_bytes )
{
uint8_t p_buf[DVD_LB_SIZE];
uint8_t * p_tmp;
int i_start;
uint16_t i_audio;
uint32_t i_spu;
int i;
p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
i_start = p_ifo->i_pos;
/*fprintf( stderr, "PGC @ %d + %d\n", p_ifo->i_pos, i_bytes ); */
DumpBytes( p_ifo, p_buf, &p_tmp, 2);
p_title->i_chapter_nb = ReadByte( p_ifo, p_buf, &p_tmp );
p_title->i_cell_nb = ReadByte( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "title: Prg: %d Cell: %d\n",p_title->i_chapter_nb,p_title->i_cell_nb ); */
p_title->i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
p_title->i_prohibited_user_op = ReadDouble( p_ifo, p_buf, &p_tmp );
for( i = 0 ; i < 8 ; i++ )
{
i_audio = ReadWord( p_ifo, p_buf, &p_tmp );
p_title->pi_audio_status[i].i_foo = i_audio & 0xff;
i_audio >>= 8;
p_title->pi_audio_status[i].i_position = i_audio & 0x07;
i_audio >>= 7;
p_title->pi_audio_status[i].i_available = i_audio;
}
for( i = 0 ; i < 32 ; i++ )
{
i_spu = ReadDouble( p_ifo, p_buf, &p_tmp );
p_title->pi_spu_status[i].i_position_pan = i_spu & 0x1f;
i_spu >>= 8;
p_title->pi_spu_status[i].i_position_letter = i_spu & 0x1f;
i_spu >>= 8;
p_title->pi_spu_status[i].i_position_wide = i_spu & 0x1f;
i_spu >>= 8;
p_title->pi_spu_status[i].i_position_43 = i_spu & 0x1f;
i_spu >>= 7;
p_title->pi_spu_status[i].i_available = i_spu;
}
p_title->i_next_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
p_title->i_prev_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
p_title->i_go_up_title_num = ReadWord( p_ifo, p_buf, &p_tmp );
p_title->i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
p_title->i_play_mode = ReadByte( p_ifo, p_buf, &p_tmp );
for( i = 0 ; i < 16 ; i++ )
{
/* FIXME : We have to erase the extra bit */
p_title->pi_yuv_color[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
}
p_title->i_command_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
p_title->i_chapter_map_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
p_title->i_cell_play_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
p_title->i_cell_pos_start_byte = ReadWord( p_ifo, p_buf, &p_tmp );
/* parsing of command_t */
if( p_title->i_command_start_byte )
{
p_tmp = FillBuffer( p_ifo, p_buf, i_start +
OFF2LB( p_title->i_command_start_byte + i_bytes ) )
+ ( (p_title->i_command_start_byte + i_bytes) & 0x7ff );
/* header */
p_title->command.i_pre_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
p_title->command.i_post_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
p_title->command.i_cell_command_nb = ReadWord( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
/* pre-title commands */
if( p_title->command.i_pre_command_nb )
{
p_title->command.p_pre_command =
malloc( p_title->command.i_pre_command_nb
* sizeof(command_desc_t) );
if( p_title->command.p_pre_command == NULL )
{
return -1;
}
for( i = 0 ; i < p_title->command.i_pre_command_nb ; i++ )
{
p_title->command.p_pre_command[i] =
ReadQuad( p_ifo, p_buf, &p_tmp );
}
}
else
{
p_title->command.p_pre_command = NULL;
}
/* post-title commands */
if( p_title->command.i_post_command_nb )
{
p_title->command.p_post_command =
malloc( p_title->command.i_post_command_nb
* sizeof(command_desc_t) );
if( p_title->command.p_post_command == NULL )
{
return -1;
}
for( i = 0 ; i < p_title->command.i_post_command_nb ; i++ )
{
p_title->command.p_post_command[i] =
ReadQuad( p_ifo, p_buf, &p_tmp );
}
}
else
{
p_title->command.p_post_command = NULL;
}
/* cell commands */
if( p_title->command.i_cell_command_nb )
{
p_title->command.p_cell_command =
malloc( p_title->command.i_cell_command_nb
* sizeof(command_desc_t) );
if( p_title->command.p_cell_command == NULL )
{
return -1;
}
for( i = 0 ; i < p_title->command.i_cell_command_nb ; i++ )
{
p_title->command.p_cell_command[i] =
ReadQuad( p_ifo, p_buf, &p_tmp );
}
}
else
{
p_title->command.p_cell_command = NULL;
}
}
/* parsing of chapter_map_t: it gives the entry cell for each chapter */
if( p_title->i_chapter_map_start_byte )
{
p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle,
OFF2LB( i_start + p_title->i_chapter_map_start_byte ),
DVDCSS_NOFLAGS );
p_title->chapter_map.pi_start_cell =
malloc( p_title->i_chapter_nb * sizeof(chapter_map_t) );
if( p_title->chapter_map.pi_start_cell == NULL )
{
return -1;
}
ReadBytes( p_ifo, p_buf, &p_tmp, p_title->chapter_map.pi_start_cell,
p_title->i_chapter_nb );
}
else
{
p_title->chapter_map.pi_start_cell = NULL;
}
/* parsing of cell_play_t */
if( p_title->i_cell_play_start_byte )
{
p_tmp = FillBuffer( p_ifo, p_buf, i_start +
OFF2LB( p_title->i_cell_play_start_byte+i_bytes ) )
+ ( (p_title->i_cell_play_start_byte+i_bytes) & 0x7ff );
p_title->p_cell_play = malloc( p_title->i_cell_nb
* sizeof(cell_play_t) );
if( p_title->p_cell_play == NULL )
{
return -1;
}
for( i = 0 ; i < p_title->i_cell_nb ; i++ )
{
#define PLAY p_title->p_cell_play[i]
PLAY.i_category = ReadWord( p_ifo, p_buf, &p_tmp );
PLAY.i_still_time = ReadByte( p_ifo, p_buf, &p_tmp );
PLAY.i_command_nb = ReadByte( p_ifo, p_buf, &p_tmp );
PLAY.i_play_time = ReadDouble( p_ifo, p_buf, &p_tmp );
PLAY.i_first_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
PLAY.i_first_ilvu_vobu_esector = ReadDouble( p_ifo, p_buf, &p_tmp );
PLAY.i_last_vobu_start_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
PLAY.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
#undef PLAY
}
}
/* Parsing of cell_pos_t */
if( p_title->i_cell_pos_start_byte )
{
p_tmp = FillBuffer( p_ifo, p_buf, i_start +
OFF2LB( p_title->i_cell_pos_start_byte + i_bytes ) )
+ ( (p_title->i_cell_pos_start_byte + i_bytes) & 0x7ff );
p_title->p_cell_pos = malloc( p_title->i_cell_nb
* sizeof(cell_pos_t) );
if( p_title->p_cell_pos == NULL )
{
return -1;
}
for( i = 0 ; i < p_title->i_cell_nb ; i++ )
{
p_title->p_cell_pos[i].i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
p_title->p_cell_pos[i].i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
}
}
return 0;
}
/*****************************************************************************
* FreeTitle: frees alla structure allocated by a call to ReadTitle
*****************************************************************************/
static int FreeTitle( title_t * p_title )
{
if( p_title->i_command_start_byte )
{
if( p_title->command.i_pre_command_nb )
{
free( p_title->command.p_pre_command );
}
if( p_title->command.i_post_command_nb )
{
free( p_title->command.p_post_command );
}
if( p_title->command.i_cell_command_nb )
{
free( p_title->command.p_cell_command );
}
}
if( p_title->i_chapter_map_start_byte )
{
free( p_title->chapter_map.pi_start_cell );
}
if( p_title->i_cell_play_start_byte )
{
free( p_title->p_cell_play );
}
if( p_title->i_cell_pos_start_byte )
{
free( p_title->p_cell_pos );
}
return 0;
}
/*****************************************************************************
* ReadUnitInf : Fills Menu Language Unit Table/ PGC Info Table
*****************************************************************************/
static int ReadUnitInf( ifo_t * p_ifo, unit_inf_t * p_unit_inf,
int i_block, int i_bytes )
{
uint8_t p_buf[DVD_LB_SIZE];
uint8_t * p_tmp;
int i_start;
int i;
p_tmp = FillBuffer( p_ifo, p_buf, i_block ) + i_bytes;
i_start = p_ifo->i_pos;
/*fprintf( stderr, "Unit\n" ); */
p_unit_inf->i_title_nb = ReadWord( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "Unit nb: %d\n", p_unit_inf->i_title_nb ); */
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
p_unit_inf->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
p_unit_inf->p_title =
malloc( p_unit_inf->i_title_nb * sizeof(unit_title_t) );
if( p_unit_inf->p_title == NULL )
{
return -1;
}
for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
{
#define TITLE p_unit_inf->p_title[i]
TITLE.i_category_mask = ReadByte( p_ifo, p_buf, &p_tmp );
TITLE.i_category = ReadByte( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "cat mask %d: %x cat %x\n", i, TITLE.i_category_mask, TITLE.i_category ); */
TITLE.i_parental_mask = ReadWord( p_ifo, p_buf, &p_tmp );
TITLE.i_title_start_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
#undef TITLE
}
for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
{
/*fprintf( stderr, "Unit: PGC %d @ %d\n", i, p_ifo->i_pos ); */
ReadTitle( p_ifo, &p_unit_inf->p_title[i].title, i_start +
OFF2LB( p_unit_inf->p_title[i].i_title_start_byte + i_bytes ),
(p_unit_inf->p_title[i].i_title_start_byte+i_bytes) & 0x7ff );
}
return 0;
}
/*****************************************************************************
* FreeUnitInf : frees a structure allocated by ReadUnit
*****************************************************************************/
static int FreeUnitInf( unit_inf_t * p_unit_inf )
{
int i;
if( p_unit_inf->p_title != NULL )
{
for( i = 0 ; i < p_unit_inf->i_title_nb ; i++ )
{
FreeTitle( &p_unit_inf->p_title[i].title );
}
free( p_unit_inf->p_title );
}
return 0;
}
/*****************************************************************************
* ReadTitleUnit: Fills the Title Unit structure.
*****************************************************************************/
static int ReadTitleUnit( ifo_t * p_ifo, title_unit_t * p_title_unit,
int i_block )
{
uint8_t p_buf[DVD_LB_SIZE];
uint8_t * p_tmp;
int i;
int i_start;
p_tmp = FillBuffer( p_ifo, p_buf, i_block );
i_start = p_ifo->i_pos;
/*fprintf( stderr, "Unit Table\n" ); */
p_title_unit->i_unit_nb = ReadWord( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
p_title_unit->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
/*fprintf(stderr, "Unit: nb %d last %d\n", p_title_unit->i_unit_nb, p_title_unit->i_last_byte ); */
p_title_unit->p_unit = malloc( p_title_unit->i_unit_nb * sizeof(unit_t) );
if( p_title_unit->p_unit == NULL )
{
return -1;
}
for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
{
/*ReadBytes( p_ifo, p_buf, &p_tmp, p_title_unit->p_unit[i].ps_lang_code, 2 ); */
p_title_unit->p_unit[i].i_lang_code = ReadWord( p_ifo, p_buf, &p_tmp );
/*fprintf( stderr, "lang %d %x\n", i,p_title_unit->p_unit[i].i_lang_code ); */
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
p_title_unit->p_unit[i].i_existence_mask =
ReadByte( p_ifo, p_buf, &p_tmp );
p_title_unit->p_unit[i].i_unit_inf_start_byte =
ReadDouble( p_ifo, p_buf, &p_tmp );
}
p_title_unit->p_unit_inf =
malloc( p_title_unit->i_unit_nb * sizeof(unit_inf_t) );
if( p_title_unit->p_unit_inf == NULL )
{
return -1;
}
for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
{
ReadUnitInf( p_ifo, &p_title_unit->p_unit_inf[i], i_start +
OFF2LB( p_title_unit->p_unit[i].i_unit_inf_start_byte ),
p_title_unit->p_unit[i].i_unit_inf_start_byte & 0x7ff );
}
return 0;
}
/*****************************************************************************
* FreeTitleUnit: frees a structure allocateed by ReadTitleUnit
*****************************************************************************/
static int FreeTitleUnit( title_unit_t * p_title_unit )
{
int i;
if( p_title_unit->p_unit_inf != NULL )
{
for( i = 0 ; i < p_title_unit->i_unit_nb ; i++ )
{
FreeUnitInf( &p_title_unit->p_unit_inf[i] );
}
free( p_title_unit->p_unit_inf );
}
return 0;
}
/*****************************************************************************
* ReadCellInf : Fills the Cell Information structure.
*****************************************************************************/
static int ReadCellInf( ifo_t * p_ifo, cell_inf_t * p_cell_inf, int i_block )
{
uint8_t p_buf[DVD_LB_SIZE];
uint8_t * p_tmp;
int i_start;
int i;
p_tmp = FillBuffer( p_ifo, p_buf, i_block );
i_start = p_ifo->i_pos;
/* fprintf( stderr, "CELL ADD\n" ); */
p_cell_inf->i_vob_nb = ReadWord( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 2 );
p_cell_inf->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
p_cell_inf->i_cell_nb = (p_cell_inf->i_last_byte + 1/* - 7*/) / sizeof(cell_map_t);
/* fprintf( stderr, "Cell inf: vob %d, %d cells, last byte %d\n", p_cell_inf->i_vob_nb, p_cell_inf->i_cell_nb, p_cell_inf->i_last_byte );
*/
p_cell_inf->p_cell_map =
malloc( p_cell_inf->i_cell_nb *sizeof(cell_map_t) );
if( p_cell_inf->p_cell_map == NULL )
{
return -1;
}
for( i = 0 ; i < p_cell_inf->i_cell_nb ; i++ )
{
#define MAP p_cell_inf->p_cell_map[i]
MAP.i_vob_id = ReadWord( p_ifo, p_buf, &p_tmp );
MAP.i_cell_id = ReadByte( p_ifo, p_buf, &p_tmp );
DumpBytes( p_ifo, p_buf, &p_tmp, 1 );
MAP.i_first_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
/* fprintf(stderr, "sector[%d] %d (%d)\n", i,ntohl(*(uint32_t*)(p_tmp)), p_ifo->i_pos);*/
MAP.i_last_sector = ReadDouble( p_ifo, p_buf, &p_tmp );
#undef MAP
}
return 0;
}
/*****************************************************************************
* FreeCellInf : frees structures allocated by ReadCellInf
*****************************************************************************/
static int FreeCellInf( cell_inf_t * p_cell_inf )
{
free( p_cell_inf->p_cell_map );
return 0;
}
/*****************************************************************************
* ReadVobuMap : Fills the VOBU Map structure.
*****************************************************************************/
static int ReadVobuMap( ifo_t * p_ifo, vobu_map_t * p_vobu_map, int i_block )
{
uint8_t p_buf[DVD_LB_SIZE];
uint8_t * p_tmp;
int i_start;
int i, i_max;
p_tmp = FillBuffer( p_ifo, p_buf, i_block );
i_start = p_ifo->i_pos;
/*fprintf( stderr, "VOBU ADMAP\n" ); */
p_vobu_map->i_last_byte = ReadDouble( p_ifo, p_buf, &p_tmp );
i_max = ( i_start + p_vobu_map->i_last_byte + 1 - p_ifo->i_pos )
/ sizeof(uint32_t);
p_vobu_map->pi_vobu_start_sector = malloc( i_max * sizeof(uint32_t) );
if( p_vobu_map->pi_vobu_start_sector == NULL )
{
return -1;
}
for( i = 0 ; i < i_max ; i++ )
{
p_vobu_map->pi_vobu_start_sector[i] = ReadDouble( p_ifo, p_buf, &p_tmp );
}
return 0;
}
/*****************************************************************************
* FreeVobuMap: frees structures allocated by ReadVobuMap
*****************************************************************************/
static int FreeVobuMap( vobu_map_t * p_vobu_map )
{
free( p_vobu_map->pi_vobu_start_sector );
return 0;
}
/*
* IFO virtual machine : a set of commands that give the
* interactive behaviour of the dvd
*/
#if 0
#define OP_VAL_16(i) (ntoh16( com.data.pi_16[i]))
#define OP_VAL_8(i) ((com.data.pi_8[i]))
static char ifo_reg[][80]=
{
"Menu_Language_Code",
"Audio_Stream_#",
"SubPicture_Stream_#",
"Angle_#",
"VTS_#",
"VTS_Title_#",
"PGC_#",
"PTT_#",
"Highlighted_Button_#",
"Nav_Timer",
"TimedPGC",
"Karaoke_audio_mixing_mode",
"Parental_mgmt_country_code",
"Parental_Level",
"Player_Video_Cfg",
"Player_Audio_Cfg",
"Audio_language_code_setting",
"Audio_language_extension_code",
"SPU_language_code_setting",
"SPU_language_extension_code",
"?Player_Regional_Code",
"Reserved_21",
"Reserved_22",
"Reserved_23"
};
static char * IfoMath( char val )
{
static char math_op[][10] =
{
"none",
"=",
"<->", /* swap */
"+=",
"-=",
"*=",
"/=",
"%=",
"rnd", /* rnd */
"&=",
"|=",
"^=",
"??", /* invalid */
"??", /* invalid */
"??", /* invalid */
"??" /* invalid */
};
return (char *) math_op[val & 0x0f];
}
char ifo_cmp[][10] =
{
"none",
"&&",
"==",
"!=",
">=",
">",
"<",
"<="
};
char ifo_parental[][10] =
{
"0",
"G",
"2",
"PG",
"PG-13",
"5",
"R",
"NC-17"
};
char ifo_menu_id[][80] =
{
"-0-",
"-1-",
"Title (VTS menu)",
"Root",
"Sub-Picture",
"Audio",
"Angle",
"Part of Title",
};
char * IfoMenuName( char index )
{
return ifo_menu_id[index&0x07];
}
static void IfoRegister( uint16_t i_data, uint8_t i_direct)
{
if( i_direct )
{
if( 0/*isalpha( i_data >> 8 & 0xff )*/ )
{
printf("'%c%c'", i_data>>8&0xff, i_data&0xff);
}
else
{
printf("0x%02x", i_data);
}
}
else
{
if( i_data & 0x80 )
{
i_data &= 0x1f;
if( i_data > 0x17 )
{
printf("s[ILL]");
}
else
{
printf("s[%s]", ifo_reg[i_data]);
}
}
else
{
i_data &= 0x1f;
if( i_data > 0xf )
{
printf("r[ILL]");
}
else
{
printf("r[0x%02x]", i_data);
}
}
}
}
static void IfoAdvanced( uint8_t *pi_code ){
uint8_t i_cmd = pi_code[0];
printf(" { ");
if( pi_code[1]>>2 )
{
printf( " Highlight button %d; ", pi_code[1]>>2 );
}
if( i_cmd == 0xff )
{
printf( " Illegal " );
}
if( i_cmd == 0x00 )
{
printf( "ReSuME %d", pi_code[7] );
}
else if( ( i_cmd & 0x06) == 0x02 )
{ /* XX01Y */
printf ("Link to %s cell ", ( i_cmd & 0x01 ) ? "prev" : "next");
}
else
{
printf( "advanced (0x%02x) ", i_cmd );
}
printf(" } ");
}
static void IfoJmp( ifo_command_t com )
{
printf ("jmp ");
switch( com.i_sub_cmd )
{
case 0x01:
printf( "Exit" );
break;
case 0x02:
printf( "VTS 0x%02x", OP_VAL_8(3) );
break;
case 0x03:
printf( "This VTS Title 0x%02x", OP_VAL_8(3) );
break;
case 0x05:
printf( "This VTS Title 0x%02x Part 0x%04x",
OP_VAL_8(3),
OP_VAL_8(0)<<8|OP_VAL_8(1));
break;
case 0x06:
#if 0
printf ("in SystemSpace ");
switch (OP_VAL_8(3)>>4) {
case 0x00:
printf ("to play first PGC");
break;
case 0x01: {
printf ("to menu \"%s\"", decode_menuname (OP_VAL_8(3)));
}
break;
case 0x02:
printf ("to VTS 0x%02x and TTN 0x%02x", OP_VAL_8(1), OP_VAL_8(2));
break;
case 0x03:
printf ("to VMGM PGC number 0x%02x", OP_VAL_8(0)<<8 | OP_VAL_8(1));
break;
case 0x08:
printf ("vts 0x%02x lu 0x%02x menu \"%s\"", OP_VAL_8(2), OP_VAL_8(1), decode_menuname (OP_VAL_8(3)));
break;
#else
switch( OP_VAL_8(3)>>6 )
{
case 0x00:
printf( "to play first PGC" );
break;
case 0x01:
printf( "to VMG title menu (?)" );
break;
case 0x02:
printf( "vts 0x%02x lu 0x%02x menu \"%s\"",
OP_VAL_8(2),
OP_VAL_8(1),
IfoMenuName( OP_VAL_8(3)&0xF ) );
break;
case 0x03:
printf( "vmg pgc 0x%04x (?)", ( OP_VAL_8(0)<<8) | OP_VAL_8(1) );
break;
#endif
}
break;
case 0x08:
#if 0
switch(OP_VAL_8(3)>>4) {
case 0x00:
printf ("system first pgc");
break;
case 0x01:
printf ("system title menu");
break;
case 0x02:
printf ("system menu \"%s\"", decode_menuname (OP_VAL_8(3)));
break;
case 0x03:
printf ("system vmg pgc %02x ????", OP_VAL_8(0)<<8|OP_VAL_8(1));
break;
case 0x08:
printf ("system lu 0x%02x menu \"%s\"", OP_VAL_8(2), decode_menuname (OP_VAL_8(3)));
break;
case 0x0c:
printf ("system vmg pgc 0x%02x", OP_VAL_8(0)<<8|OP_VAL_8(1));
break;
}
#else
/* OP_VAL_8(2) is number of cell */
/* it is processed BEFORE switch */
/* under some conditions, it is ignored */
/* I don't understand exactly what it means */
printf( " ( spec cell 0x%02X ) ", OP_VAL_8(2) );
switch( OP_VAL_8(3)>>6 )
{
case 0:
printf( "to FP PGC" );
break;
case 1:
printf( "to VMG root menu (?)" );
break;
case 2:
printf( "to VTS menu \"%s\" (?)",
IfoMenuName(OP_VAL_8(3)&0xF) );
break;
case 3:
printf( "vmg pgc 0x%02x (?)", (OP_VAL_8(0)<<8)|OP_VAL_8(1) );
break;
}
#endif
break;
}
}
static void IfoLnk( ifo_command_t com )
{
uint16_t i_button = OP_VAL_8(4)>>2;
printf ("lnk to ");
switch( com.i_sub_cmd )
{
case 0x01:
IfoAdvanced( &OP_VAL_8(4) );
break;
case 0x04:
printf( "PGC 0x%02x", OP_VAL_16(2) );
break;
case 0x05:
printf( "PTT 0x%02x", OP_VAL_16(2) );
break;
case 0x06:
printf( "Program 0x%02x this PGC", OP_VAL_8(5) );
break;
case 0x07:
printf( "Cell 0x%02x this PGC", OP_VAL_8(5) );
break;
default:
return;
}
if( i_button )
{
printf( ", Highlight 0x%02x", OP_VAL_8(4)>>2 );
}
}
void IfoSetSystem( ifo_command_t com )
{
switch( com.i_cmd )
{
case 1: {
int i;
for( i=1; i<=3; i++ )
{
if( OP_VAL_8(i)&0x80 )
{
if( com.i_direct )
{
printf ("s[%s] = 0x%02x;", ifo_reg[i], OP_VAL_8(i)&0xf);
}
else
{
printf ("s[%s] = r[0x%02x];", ifo_reg[i], OP_VAL_8(i)&0xf);
}
}
}
#if 0
if(op->direct) {
if(OP_VAL_8(1]&0x80)
printf ("s[%s] = 0x%02x;", reg_name[1], OP_VAL_8(1]&0xf);
if(OP_VAL_8(2)&0x80)
/*DENT: lwhat about 0x7f here ??? */
printf ("s[%s] = 0x%02x;", reg_name[2], OP_VAL_8(2)&0x7f);
if(OP_VAL_8(3)&0x80)
printf ("s[%s] = 0x%02x;", reg_name[3], OP_VAL_8(3)&0xf);
} else {
if(OP_VAL_8(1)&0x80)
printf ("s[%s] = r[0x%02x];", reg_name[1], OP_VAL_8(1)&0xf);
if(OP_VAL_8(2)&0x80)
printf ("s[%s] = r[0x%02x];", reg_name[2], OP_VAL_8(2)&0xf);
if(OP_VAL_8(3)&0x80)
printf ("s[%s] = r[0x%02x];", reg_name[3], OP_VAL_8(3)&0xf);
}
#endif
}
break;
case 2:
if( com.i_direct )
{
printf( "s[%s] = 0x%02x", ifo_reg[9], OP_VAL_16(0) );
}
else
{
printf( "s[%s] = r[0x%02x]", ifo_reg[9], OP_VAL_8(1)&0x0f );
}
printf( "s[%s] = (s[%s]&0x7FFF)|0x%02x",
ifo_reg[10], ifo_reg[10], OP_VAL_16(1)&0x8000);
break;
case 3:
if( com.i_direct )
{
printf( "r[0x%02x] = 0x%02x", OP_VAL_8(3)&0x0f, OP_VAL_16(0) );
}
else
{
printf ("r[r[0x%02x]] = r[0x%02x]",
OP_VAL_8(3)&0x0f, OP_VAL_8(1)&0x0f);
}
break;
case 4:
/*actually only bits 00011100 00011100 are set */
if( com.i_direct )
{
printf ("s[%s] = 0x%02x", ifo_reg[11], OP_VAL_16(1));
}
else
{
printf ("s[%s] = r[0x%02x]", ifo_reg[11], OP_VAL_8(3)&0x0f );
}
break;
case 6:
/*actually, */
/*s[%s]=(r[%s]&0x3FF) | (0x%02x << 0xA); */
/*but it is way too ugly */
if( com.i_direct )
{
printf( "s[%s] = 0x%02x", ifo_reg[8], OP_VAL_8(2)>>2 );
}
else
{
printf( "s[%s] = r[0x%02x]", ifo_reg[8], OP_VAL_8(3)&0x0f );
}
break;
default:
printf ("unknown");
}
}
static void IfoSet( ifo_command_t com )
{
IfoRegister( OP_VAL_16(0), 0 );
printf( " %s ", IfoMath( com.i_cmd ) );
IfoRegister( OP_VAL_16(1), com.i_direct );
}
/*****************************************************************************
* CommandRead : translates the command strings in ifo into command
* structures.
*****************************************************************************/
void CommandRead( ifo_command_t com )
{
uint8_t * pi_code = (uint8_t*)(&com);
switch( com.i_type )
{
/* Goto */
case 0:
/* Main command */
if( !pi_code[1] )
{
printf( "NOP\n" );
}
else
{
if( com.i_cmp )
{
printf ("if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
ifo_cmp[com.i_cmp]);
IfoRegister (OP_VAL_16(1), com.i_dir_cmp);
printf (") ");
}
/* Sub command */
switch( com.i_sub_cmd )
{
case 1:
printf( "goto Line 0x%02x", OP_VAL_16(2) );
break;
case 2:
printf( "stop VM" );
break;
case 3:
printf( "Set Parental Level To %s and goto Line 0x%02x",
ifo_parental[OP_VAL_8(4)&0x7],
OP_VAL_8(5) );
break;
default:
printf( "Illegal" );
break;
}
}
break;
/* Lnk */
case 1:
/* Main command */
if( !pi_code[1] )
{
printf( "NOP\n" );
}
else
{
if( com.i_direct )
{
if( com.i_cmp )
{
printf( "if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f,
ifo_cmp[com.i_cmp] );
IfoRegister( OP_VAL_8(5), 0 );
printf( ") " );
}
/* Sub command */
IfoJmp( com );
}
else
{
if( com.i_cmp )
{
printf( "if (r[0x%02x] %s ", OP_VAL_8(1)&0x0f,
ifo_cmp[com.i_cmp] );
IfoRegister( OP_VAL_16(1), com.i_dir_cmp );
printf( ") " );
}
/* Sub command */
IfoLnk( com );
}
}
break;
/* SetSystem */
case 2:
if( !pi_code[1] )
{
IfoSetSystem( com );
}
else if( com.i_cmp && !com.i_sub_cmd )
{
printf ("if (r[0x%02x] %s ", OP_VAL_8(4)&0x0f, ifo_cmp[com.i_cmp]);
IfoRegister( OP_VAL_8(5), 0 );
printf (") ");
IfoSetSystem( com );
}
else if( !com.i_cmp && com.i_sub_cmd )
{
printf( "if (" );
IfoSetSystem( com );
printf( ") " );
IfoLnk( com );
}
else
{
printf("nop");
}
break;
/* Set */
case 3:
if( ! pi_code[1] )
{
IfoSet( com );
}
else if( com.i_cmp && !com.i_sub_cmd )
{
printf ("if (r[0x%02x] %s ", OP_VAL_8(0)&0x0f, ifo_cmp[com.i_cmp]);
IfoRegister( OP_VAL_16(2), com.i_dir_cmp );
printf (") ");
IfoSet( com );
}
else if( !com.i_cmp && com.i_sub_cmd )
{
printf ("if (");
IfoSet( com );
printf (") ");
IfoLnk( com );
}
else
{
printf( "nop" );
}
break;
/*
* math command on r[opcode[1]] and
* direct?be2me_16(OP_VAL_8(0)):reg[OP_VAL_8(1)] is executed
* ( unless command is swap; then r[opcode[1]] and r[OP_VAL_8(1)]
* are swapped )
* boolean operation cmp on r[opcode[1]] and
* dir_cmp?be2me_16(OP_VAL_8(1)[1]):reg[OP_VAL_8(3)] is executed
* on true result, buttons(c[6], c[7]) is called
* problem is 'what is buttons()'
*/
case 4:
printf( "r[0x%X] ", pi_code[1] );
printf( " %s ", IfoMath( com.i_cmd ) );
if( com.i_cmd == 2 )
{
printf( "r[0x%X] ", OP_VAL_8(1) );
}
else
{
IfoRegister( OP_VAL_16(0), com.i_direct );
}
printf("; ");
printf( "if ( r[%d] %s ", pi_code[1], ifo_cmp[com.i_cmp] );
IfoRegister( OP_VAL_8(1), com.i_dir_cmp );
printf( " ) then {" );
IfoAdvanced( &OP_VAL_8(4) );
printf( "}" );
break;
/*
* opposite to case 4: boolean, math and buttons.
*/
case 5:
case 6:
printf("if (");
if( !com.i_direct && com.i_dir_cmp )
{
printf( "0x%X", OP_VAL_16(1) );
}
else
{
IfoRegister( OP_VAL_8(3), 0 );
if( OP_VAL_8(3)&0x80 )
{
printf( "s[%s]", ifo_reg[OP_VAL_8(3)&0x1F] );
}
else
{
printf( "r[0x%X]", OP_VAL_8(3)&0x1F);
/* 0x1F is either not a mistake, */
/* or Microsoft programmer's mistake!!! */
}
}
printf( " %s r[0x%X] ", ifo_cmp[com.i_cmp],
com.i_direct ? OP_VAL_8(2) : OP_VAL_8(1) );
printf( " ) then {" );
printf( "r[0x%X] ", pi_code[1] & 0xF );
printf( " %s ", IfoMath( com.i_cmd ) );
if( com.i_cmd == 0x02 ) /* swap */
{
printf("r[0x%X] ", OP_VAL_8(0)&0x1F);
}
else
{
if( com.i_direct )
{
printf( "0x%X", OP_VAL_16(0) );
}
else
{
if( OP_VAL_8(0) & 0x80 )
{
printf("s[%s]", ifo_reg[OP_VAL_8(0) & 0x1F] );
}
else
{
printf("r[0x%X]", OP_VAL_8(0) & 0x1F );
}
}
}
printf("; ");
IfoAdvanced( &OP_VAL_8(4) );
printf("}");
break;
default:
printf( "Unknown Command\n" );
break;
}
return;
}
/*****************************************************************************
* CommandPrint : print in clear text (I hope so !) what a command does
*****************************************************************************/
void CommandPrint( ifo_t ifo )
{
return;
}
#endif
/*****************************************************************************
* ReadByte and so
*****************************************************************************/
static uint8_t* FillBuffer( ifo_t* p_ifo, uint8_t* p_buf, int i_pos )
{
p_ifo->i_pos = dvdcss_seek( p_ifo->dvdhandle, i_pos, DVDCSS_NOFLAGS );
dvdcss_read( p_ifo->dvdhandle, p_buf, 1, DVDCSS_NOFLAGS );
return p_buf;
}
static void ReadBytes( ifo_t* p_ifo, uint8_t* p_buf, uint8_t** pp_tmp,
uint8_t* pi_dest, int i_nb )
{
if( i_nb > DVD_LB_SIZE )
{
#if 0
intf_Err( p_input, "excessive ReadBytes call (%i)", i_nb );
#endif
}
if( *pp_tmp + i_nb >= p_buf + DVD_LB_SIZE )
{
int i_spare = (int)( (p_buf + DVD_LB_SIZE) - *pp_tmp );
/* Copy the bytes remaining in the current buffer */
memcpy( pi_dest, *pp_tmp, i_spare );
pi_dest += i_spare;
i_nb -= i_spare;
/* Load the next buffer */
*pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 );
}
memcpy( pi_dest, *pp_tmp, i_nb );
*pp_tmp += i_nb;
return;
}
static void DumpBytes( ifo_t* p_ifo, uint8_t* p_buf, uint8_t** pp_tmp, int i_nb )
{
if( i_nb > DVD_LB_SIZE )
{
#if 0
intf_Err( p_input, "excessive DumpBytes call (%i)", i_nb );
#endif
}
*pp_tmp += i_nb;
if( *pp_tmp >= p_buf + DVD_LB_SIZE )
{
/* If we went too far, load the next buffer */
*pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 )
+ (int)( (*pp_tmp) - (p_buf + DVD_LB_SIZE) );
}
return;
}
#define ADDBYTE \
if( *pp_tmp >= p_buf + DVD_LB_SIZE ) \
{ \
*pp_tmp = FillBuffer( p_ifo, p_buf, p_ifo->i_pos + 1 ); \
} \
i_ret <<= 8; i_ret |= **pp_tmp; (*pp_tmp)++;
static uint8_t ReadByte( ifo_t * p_ifo, uint8_t* p_buf, uint8_t** pp_tmp )
{
uint8_t i_ret = 0;
ADDBYTE;
return i_ret;
}
static uint16_t ReadWord( ifo_t * p_ifo, uint8_t* p_buf, uint8_t** pp_tmp )
{
uint16_t i_ret = 0;
ADDBYTE; ADDBYTE;
return i_ret;
}
static uint32_t ReadDouble( ifo_t * p_ifo, uint8_t* p_buf, uint8_t** pp_tmp )
{
uint32_t i_ret = 0;
ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;
return i_ret;
}
static uint64_t ReadQuad( ifo_t * p_ifo, uint8_t* p_buf, uint8_t** pp_tmp )
{
uint64_t i_ret = 0;
ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE; ADDBYTE;
return i_ret;
}
/*****************************************************************************
* dvd_ifo.h: Structures for ifo parsing
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: ifo.h,v 1.4 2003/10/25 00:49:13 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* based on:
* - libifo by Thomas Mirlacher <dent@cosy.sbg.ac.at>
* - IFO structure documentation by Thomas Mirlacher, Björn Englund,
* Håkan Hjort
*
* 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.
*****************************************************************************/
/*****************************************************************************
* Common structures for Video Management and Video Title sets
*****************************************************************************/
/*
* Program Chain structures
*/
typedef struct ifo_video_s
{
uint8_t i_compression ;/* 2; */
uint8_t i_system ;/* 2; */
uint8_t i_ratio ;/* 2; */
uint8_t i_perm_displ ;/* 2; */
uint8_t i_line21_1 ;/* 1; */
uint8_t i_line21_2 ;/* 1; */
uint8_t i_source_res ;/* 2; */
uint8_t i_letterboxed ;/* 1; */
uint8_t i_mode ;/* 1; */
} ifo_video_t;
/* Audio type information */
typedef struct ifo_audio_s
{
uint8_t i_coding_mode ;/* 3; */
uint8_t i_multichannel_extension ;/* 1; */
uint8_t i_type ;/* 2; */
uint8_t i_appl_mode ;/* 2; */
uint8_t i_quantization ;/* 2; */
uint8_t i_sample_freq ;/* 2; */
uint8_t i_test ;/* 1; */
uint8_t i_num_channels ;/* 3; */
uint16_t i_lang_code ;/* 16; // <char> description */
uint8_t i_foo ;/* 8; // 0x00000000 ? */
uint8_t i_caption ;/* 8; */
uint8_t i_bar ;/* 8; // 0x00000000 ? */
} ifo_audio_t;
/* Audio Status */
typedef struct audio_status_s
{
uint8_t i_available; /* 1 */
uint8_t i_position; /* 7 */
uint8_t i_foo; /* 8 */
} audio_status_t;
typedef struct ifo_spu_t
{
uint16_t i_prefix ;/* 16; // 0x0100 ? */
uint16_t i_lang_code ;/* 16; // <char> description */
uint8_t i_foo ;/* 8; // dont know */
uint8_t i_caption ;/* 8; // 0x00 ? */
} ifo_spu_t;
/* Subpicture status */
typedef struct spu_status_s
{
uint8_t i_available; /*1*/
uint8_t i_position_43; /*7*/
uint8_t i_position_wide; /*8*/
uint8_t i_position_letter; /*8*/
uint8_t i_position_pan; /*8*/
} spu_status_t;
/* Ifo vitual machine Commands */
typedef struct command_desc_s
{
unsigned int i_type :3;
unsigned int i_direct :1;
unsigned int i_cmd :4;
unsigned int i_dir_cmp :1;
unsigned int i_cmp :3;
unsigned int i_sub_cmd :4;
union
{
uint8_t pi_8[6];
uint16_t pi_16[3];
} data;
} command_desc_t;
/* Program Chain Command Table
- start at i_pgc_com_tab_sbyte */
typedef struct command_s
{
uint16_t i_pre_command_nb; /* 2 bytes */
uint16_t i_post_command_nb; /* 2 bytes */
uint16_t i_cell_command_nb; /* 2 bytes */
/* char[2] ??? */
uint64_t * p_pre_command; /* i_pre_com_nb * 8 bytes */
uint64_t * p_post_command; /* i_post_com_nb * 8 bytes */
uint64_t * p_cell_command; /* i_pre_com_nb * 8 bytes */
/* command_desc_t* p_cell_command; // i_cell_com_nb * 8 bytes */
/* command_desc_t* p_post_command; // i_post_com_nb * 8 bytes */
/* command_desc_t* p_cell_command; // i_cell_com_nb * 8 bytes */
} command_t;
/* Program Chain Map Table
* - start at "i_pgc_prg_map_sbyte" */
typedef struct chapter_map_s
{
uint8_t * pi_start_cell; /* i_prg_nb * 1 byte */
} chapter_map_t;
/* Cell Playback Information Table
* we have a pointer to such a structure for each cell
* - first start at "i_cell_play_inf_sbyte" */
typedef struct cell_play_s
{
/* This information concerns the currently selected cell */
uint16_t i_category; /* 2 bytes */
uint8_t i_still_time; /* 1 byte; in seconds; ff=inf */
uint8_t i_command_nb; /* 1 byte; 0 = no com */
uint32_t i_play_time; /* 4 bytes */
uint32_t i_first_sector; /* 4 bytes */
uint32_t i_first_ilvu_vobu_esector; /* 4 bytes; ??? */
uint32_t i_last_vobu_start_sector; /* 4 bytes */
uint32_t i_last_sector; /* 4 bytes */
} cell_play_t;
/* Cell Position Information Table
* we have a pointer to such a structure for each cell
* - first start at "i_cell_pos_inf_sbyte" */
typedef struct cell_pos_s
{
/* This information concerns the currently selected cell */
uint16_t i_vob_id; /* 2 bytes */
/* char ??? */
uint8_t i_cell_id; /* 1 byte */
} cell_pos_t;
/* Main structure for Program Chain
* - start at i_fp_pgc_sbyte
* - or at i_vmgm_pgci_sbyte in vmgm_pgci_srp_t */
typedef struct title_s
{
/* Global features of program chain */
/* char[2] ??? */
uint8_t i_chapter_nb; /* 1 byte */
uint8_t i_cell_nb; /* 1 byte */
uint32_t i_play_time; /* 4 bytes */
uint32_t i_prohibited_user_op; /* 4 bytes */
audio_status_t pi_audio_status[8]; /* 8*2 bytes */
spu_status_t pi_spu_status[32]; /* 32*4 bytes */
uint16_t i_next_title_num; /* 2 bytes */
uint16_t i_prev_title_num; /* 2 bytes */
uint16_t i_go_up_title_num; /* 2 bytes */
uint8_t i_still_time; /* 1 byte ; in seconds */
uint8_t i_play_mode; /* 1 byte */
/* In video_ts.ifo, the 3 significant bytes of each color are
* preceded by 1 unsignificant byte */
uint32_t pi_yuv_color[16]; /* 16*3 bytes */
/* Here come the start bytes of the following structures */
uint16_t i_command_start_byte; /* 2 bytes */
uint16_t i_chapter_map_start_byte; /* 2 bytes */
uint16_t i_cell_play_start_byte; /* 2 bytes */
uint16_t i_cell_pos_start_byte; /* 2 bytes */
/* Predefined structures */
command_t command;
chapter_map_t chapter_map;
cell_play_t* p_cell_play; /* i_cell_nb * 24 bytes */
cell_pos_t* p_cell_pos; /* i_cell_nb * 4 bytes */
} title_t;
/*
* Menu PGCI Unit Table
*/
/* Menu PGCI Language unit Descriptor */
typedef struct unit_s
{
uint16_t i_lang_code; /* 2 bytes (ISO-xx) */
/* char ??? */
uint8_t i_existence_mask; /* 1 byte */
uint32_t i_unit_inf_start_byte; /* 4 bytes */
} unit_t;
typedef struct unit_title_s
{
uint8_t i_category_mask; /* 1 byte */
uint8_t i_category; /* 1 byte */
uint16_t i_parental_mask; /* 2 bytes */
uint32_t i_title_start_byte; /* 4 bytes */
title_t title;
} unit_title_t;
/* Menu PGCI Language Unit Table
* - start at i_lu_sbyte */
typedef struct unit_inf_s
{
uint16_t i_title_nb; /* 2 bytes */
/* char[2] ??? */
uint32_t i_last_byte; /* 4 bytes */
unit_title_t * p_title; /* i_srp_nb * 8 bytes */
} unit_inf_t;
/* Main Struct for Menu PGCI
* - start at i_*_pgci_ut_ssector */
typedef struct title_unit_s
{
uint16_t i_unit_nb; /* 2 bytes; ??? */
/* char[2] ??? */
uint32_t i_last_byte; /* 4 bytes */
unit_t* p_unit; /* i_lu_nb * 8 bytes */
unit_inf_t* p_unit_inf; /* i_lu_nb * 8 bytes */
} title_unit_t;
/*
* Cell Adress Table Information
*/
typedef struct cell_map_s
{
uint16_t i_vob_id; /* 2 bytes */
uint8_t i_cell_id; /* 1 byte */
/* char ??? */
uint32_t i_first_sector; /* 4 bytes */
uint32_t i_last_sector; /* 4 bytes */
} cell_map_t;
typedef struct cell_inf_s
{
uint16_t i_vob_nb; /* 2 bytes */
/* char[2] ??? */
uint32_t i_last_byte; /* 4 bytes */
uint16_t i_cell_nb; /* not in ifo; computed */
/* with e_byte */
cell_map_t* p_cell_map;
} cell_inf_t;
/*
* VOBU Adress Map Table
*/
typedef struct vobu_map_s
{
uint32_t i_last_byte; /* 4 bytes */
uint32_t * pi_vobu_start_sector; /* (nb of vobu) * 4 bytes */
} vobu_map_t;
/*****************************************************************************
* Structures for Video Management (cf video_ts.ifo)
*****************************************************************************/
/*
* Video Manager Information Management Table
*/
typedef struct manager_inf_s
{
byte_t psz_id[13]; /* 12 bytes (DVDVIDEO-VMG) */
uint32_t i_vmg_end_sector; /* 4 bytes */
/* char[12] ??? */
uint32_t i_vmg_inf_end_sector; /* 4 bytes */
/* char ??? */
uint8_t i_spec_ver; /* 1 byte */
uint32_t i_cat; /* 4 bytes */
uint16_t i_volume_nb; /* 2 bytes */
uint16_t i_volume; /* 2 bytes */
uint8_t i_disc_side; /* 1 bytes */
/* char[20] ??? */
uint16_t i_title_set_nb; /* 2 bytes */
byte_t ps_provider_id[32]; /* 32 bytes */
uint64_t i_pos_code; /* 8 bytes */
/* char[24] ??? */
uint32_t i_vmg_inf_end_byte; /* 4 bytes */
uint32_t i_first_play_title_start_byte; /* 4 bytes */
/* char[56] ??? */
uint32_t i_vob_start_sector; /* 4 bytes */
uint32_t i_title_inf_start_sector; /* 4 bytes */
uint32_t i_title_unit_start_sector; /* 4 bytes */
uint32_t i_parental_inf_start_sector; /* 4 bytes */
uint32_t i_vts_inf_start_sector; /* 4 bytes */
uint32_t i_text_data_start_sector; /* 4 bytes */
uint32_t i_cell_inf_start_sector; /* 4 bytes */
uint32_t i_vobu_map_start_sector; /* 4 bytes */
/* char[2] ??? */
ifo_video_t video_attr; /* 2 bytes */
/* char ??? */
uint8_t i_audio_nb; /* 1 byte */
ifo_audio_t p_audio_attr[8]; /* i_vmgm_audio_nb * 8 bytes */
/* char[16] ??? */
uint8_t i_spu_nb; /* 1 byte */
ifo_spu_t p_spu_attr[32]; /* i_subpic_nb * 6 bytes */
} manager_inf_t;
/*
* Part Of Title Search Pointer Table Information
*/
/* Title sets structure
* we have a pointer to this structure for each tts */
typedef struct title_attr_s
{
uint8_t i_play_type; /* 1 byte */
uint8_t i_angle_nb; /* 1 byte */
uint16_t i_chapter_nb; /* 2 bytes; Chapters/PGs */
uint16_t i_parental_id; /* 2 bytes */
uint8_t i_title_set_num; /* 1 byte (VTS#) */
uint8_t i_title_num; /* 1 byte ??? */
uint32_t i_start_sector; /* 4 bytes */
} title_attr_t;
/* Main struct for tts
* - start at "i_vmg_ptt_srpt_ssector" */
typedef struct title_inf_s
{
uint16_t i_title_nb; /* 2 bytes */
/* char[2] ??? */
uint32_t i_last_byte; /* 4 bytes */
title_attr_t * p_attr; /* i_ttu_nb * 12 bytes */
} title_inf_t;
/*
* Parental Management Information Table
*/
typedef struct parental_desc_s
{
byte_t ps_country_code[2]; /* 2 bytes */
/* char[2] ??? */
uint16_t i_parental_mask_start_byte; /* 2 bytes */
/* char[2] ??? */
} parental_desc_t;
typedef struct parental_mask_s
{
uint16_t * ppi_mask[8]; /* (i_vts_nb +1) * 8 * 2 bytes */
} parental_mask_t;
/* Main struct for parental management
* - start at i_vmg_ptl_mait_ssector */
typedef struct parental_inf_s
{
uint16_t i_country_nb; /* 2 bytes */
uint16_t i_vts_nb; /* 2 bytes */
uint32_t i_last_byte; /* 4 bytes */
parental_desc_t* p_parental_desc; /* i_country_nb * 8 bytes */
parental_mask_t* p_parental_mask; /* i_country_nb * sizeof(vmg_ptl_mask_t) */
} parental_inf_t;
/*
* Video Title Set Attribute Table
*/
/* Attribute structure : one for each vts
* - start at pi_atrt_sbyte */
typedef struct vts_attr_s
{
uint32_t i_last_byte; /* 4 bytes */
uint32_t i_cat_app_type; /* 4 bytes */
ifo_video_t vts_menu_video_attr; /* 2 bytes */
/* char ??? */
uint8_t i_vts_menu_audio_nb; /* 1 byte */
ifo_audio_t p_vts_menu_audio_attr[8]; /* 8 * 8 bytes */
/* char[17] ??? */
uint8_t i_vts_menu_spu_nb; /* 1 byte */
ifo_spu_t p_vts_menu_spu_attr[28]; /* i_vtsm_subpic_nb * 6 bytes */
/* char[2] ??? */
ifo_video_t vts_title_video_attr; /* 2 bytes */
/* char ??? */
uint8_t i_vts_title_audio_nb; /* 1 byte */
ifo_audio_t p_vts_title_audio_attr[8]; /* 8 * 8 bytes */
/* char[17] ??? */
uint8_t i_vts_title_spu_nb; /* 1 byte */
ifo_spu_t p_vts_title_spu_attr[28]; /* i_vtstt_subpic_nb * 6 bytes */
} vts_attr_t;
/* Main struct for vts attributes
* - start at i_vmg_vts_atrt_ssector */
typedef struct vts_inf_s
{
uint16_t i_vts_nb; /* 2 bytes */
/* char[2] ??? */
uint32_t i_last_byte; /* 4 bytes */
uint32_t * pi_vts_attr_start_byte; /* i_vts_nb * 4 bytes */
vts_attr_t* p_vts_attr;
} vts_inf_t;
/*
* Global Structure for Video Manager
*/
typedef struct vmg_s
{
manager_inf_t manager_inf;
title_t title;
title_inf_t title_inf;
title_unit_t title_unit;
parental_inf_t parental_inf;
vts_inf_t vts_inf;
cell_inf_t cell_inf;
vobu_map_t vobu_map;
} vmg_t;
/*****************************************************************************
* Structures for Video Title Sets (cf vts_*.ifo)
****************************************************************************/
/*
* Video Title Sets Information Management Table
*/
typedef struct vts_manager_s
{
byte_t psz_id[13]; /* 12 bytes (DVDVIDEO-VTS) */
uint32_t i_last_sector; /* 4 bytes */
/* char[12] ??? */
uint32_t i_inf_last_sector; /* 4 bytes */
/* char ??? */
uint8_t i_spec_ver; /* 1 byte */
uint32_t i_cat; /* 4 bytes */
/* char[90] ??? */
uint32_t i_inf_end_byte; /* 4 bytes */
/* char[60] ??? */
uint32_t i_menu_vob_start_sector; /* 4 bytes */
uint32_t i_title_vob_start_sector; /* 4 bytes */
uint32_t i_title_inf_start_sector; /* 4 bytes */
uint32_t i_title_unit_start_sector; /* 4 bytes */
uint32_t i_menu_unit_start_sector; /* 4 bytes */
uint32_t i_time_inf_start_sector; /* 4 bytes */
uint32_t i_menu_cell_inf_start_sector; /* 4 bytes */
uint32_t i_menu_vobu_map_start_sector; /* 4 bytes */
uint32_t i_cell_inf_start_sector; /* 4 bytes */
uint32_t i_vobu_map_start_sector; /* 4 bytes */
/* char[24] ??? */
ifo_video_t menu_video_attr; /* 2 bytes */
/* char ??? */
uint8_t i_menu_audio_nb; /* 1 byte */
ifo_audio_t p_menu_audio_attr[8]; /* i_vmgm_audio_nb * 8 bytes */
/* char[16] ??? */
uint8_t i_menu_spu_nb; /* 1 byte */
ifo_spu_t p_menu_spu_attr[32]; /* i_subpic_nb * 6 bytes */
/* !!! only 28 subpics ??? */
/* char[2] ??? */
ifo_video_t video_attr; /* 2 bytes */
/* char ??? */
uint8_t i_audio_nb; /* 1 byte */
ifo_audio_t p_audio_attr[8]; /* i_vmgm_audio_nb * 8 bytes */
/* char[16] ??? */
uint8_t i_spu_nb; /* 1 byte */
ifo_spu_t p_spu_attr[32]; /* i_subpic_nb * 6 bytes */
} vts_manager_t;
/*
* Part Of Title Search Pointer Table Information
*/
/* Title sets structure
* we have a pointer to this structure for each tts */
typedef struct title_start_s
{
uint16_t i_title_id; /* 2 bytes; Chapters/PGs */
uint16_t i_chapter; /* 2 bytes */
} title_start_t;
/* Main struct for tts
* - start at "i_vts_ptt_srpt_ssector" */
typedef struct vts_title_s
{
uint16_t i_title_nb; /* 2 bytes */
/* char[2] ??? */
uint32_t i_last_byte; /* 4 bytes */
uint32_t * pi_start_byte;
title_start_t * p_title_start; /* i_ttu_nb * 4 bytes */
} vts_title_t;
/*
* Time Map table information
*/
/* Time Map structure */
typedef struct time_map_s
{
uint8_t i_time_unit; /* 1 byte */
/* char ??? */
uint16_t i_entry_nb; /* 2 bytes */
uint32_t * pi_sector; /* i_entry_nb * 4 bytes */
} time_map_t;
/* Main structure for tmap_ti
* - start at "i_tmap_ti_ssector" */
typedef struct time_inf_s
{
uint16_t i_nb; /* 2 bytes */
/* char[2] ??? */
uint32_t i_last_byte; /* 4 bytes */
uint32_t * pi_start_byte; /* i_tmap_nb * 4 bytes */
time_map_t* p_time_map;
} time_inf_t;
/*
* Video Title Set
*/
typedef struct vts_s
{
vlc_bool_t b_initialized;
int i_pos;
vts_manager_t manager_inf;
vts_title_t title_inf;
title_unit_t menu_unit;
unit_inf_t title_unit;
time_inf_t time_inf;
cell_inf_t menu_cell_inf;
vobu_map_t menu_vobu_map;
cell_inf_t cell_inf;
vobu_map_t vobu_map;
} vts_t;
/*
* Global Ifo Structure
*/
typedef struct ifo_s
{
dvdcss_handle dvdhandle; /* File descriptor for the device */
int i_start; /* Offset to video_ts.ifo on the device */
int i_pos; /* Position of stream pointer */
vlc_bool_t b_error; /* Error Management */
vmg_t vmg; /* Structure described in video_ts */
vts_t vts; /* Vts ifo for current title set */
/* Remap buffer for unaligned reads */
uint8_t p_remap[ 2 * DVD_LB_SIZE ];
} ifo_t;
/*****************************************************************************
* Prototypes in dvd_ifo.c
*****************************************************************************/
struct thread_dvd_data_s;
int IfoCreate ( struct thread_dvd_data_s * );
int IfoInit ( struct ifo_s * );
int IfoTitleSet ( struct ifo_s *, int );
void IfoDestroy ( struct ifo_s * );
/* seek.c: functions to navigate through DVD.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: seek.c,v 1.3 2002/12/06 16:34:04 sam Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "seek.h"
#include "ifo.h"
#define title \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title
#define cell p_dvd->p_ifo->vts.cell_inf
int CellIsInterleaved( thread_dvd_data_t * p_dvd )
{
return title.p_cell_play[p_dvd->i_prg_cell].i_category & 0xf000;
}
int CellPrg2Map( thread_dvd_data_t * p_dvd )
{
int i_cell;
i_cell = p_dvd->i_map_cell;
if( i_cell >= cell.i_cell_nb )
{
return -1;
}
while( ( i_cell < cell.i_cell_nb ) &&
( ( title.p_cell_pos[p_dvd->i_prg_cell].i_vob_id !=
cell.p_cell_map[i_cell].i_vob_id ) ||
( title.p_cell_pos[p_dvd->i_prg_cell].i_cell_id !=
cell.p_cell_map[i_cell].i_cell_id ) ) )
{
i_cell++;
}
if( i_cell >= cell.i_cell_nb )
{
return -1;
}
return i_cell;
}
int CellAngleOffset( thread_dvd_data_t * p_dvd, int i_prg_cell )
{
int i_cell_off;
if( i_prg_cell >= title.i_cell_nb )
{
return 0;
}
/* basic handling of angles */
switch( ( ( title.p_cell_play[i_prg_cell].i_category & 0xf000 )
>> 12 ) )
{
/* we enter a muli-angle section */
case 0x5:
i_cell_off = p_dvd->i_angle - 1;
p_dvd->i_angle_cell = 0;
break;
/* we exit a multi-angle section */
case 0x9:
case 0xd:
i_cell_off = p_dvd->i_angle_nb - p_dvd->i_angle;
break;
default:
i_cell_off = 0;
}
return i_cell_off;
}
int CellFirstSector( thread_dvd_data_t * p_dvd )
{
return __MAX( cell.p_cell_map[p_dvd->i_map_cell].i_first_sector,
title.p_cell_play[p_dvd->i_prg_cell].i_first_sector );
}
int CellLastSector( thread_dvd_data_t * p_dvd )
{
return __MIN( cell.p_cell_map[p_dvd->i_map_cell].i_last_sector,
title.p_cell_play[p_dvd->i_prg_cell].i_last_sector );
}
int NextCellPrg( thread_dvd_data_t * p_dvd )
{
unsigned int i_cell = p_dvd->i_prg_cell;
if( p_dvd->i_vts_lb > title.p_cell_play[i_cell].i_last_sector )
{
i_cell ++;
i_cell += CellAngleOffset( p_dvd, i_cell );
if( i_cell >= title.i_cell_nb )
{
return -1;
}
}
return i_cell;
}
int Lb2CellPrg( thread_dvd_data_t * p_dvd )
{
unsigned int i_cell = 0;
while( p_dvd->i_vts_lb > title.p_cell_play[i_cell].i_last_sector )
{
i_cell ++;
i_cell += CellAngleOffset( p_dvd, i_cell );
if( i_cell >= title.i_cell_nb )
{
return -1;
}
}
return i_cell;
}
int Lb2CellMap( thread_dvd_data_t * p_dvd )
{
int i_cell = 0;
while( p_dvd->i_vts_lb > cell.p_cell_map[i_cell].i_last_sector )
{
i_cell ++;
if( i_cell >= cell.i_cell_nb )
{
return -1;
}
}
return i_cell;
}
int LbMaxOnce( thread_dvd_data_t * p_dvd )
{
int i_block_once = p_dvd->i_last_lb + 1 - p_dvd->i_vts_lb;
/* Get the position of the next cell if we're at cell end */
if( i_block_once <= 0 )
{
p_dvd->i_map_cell++;
p_dvd->i_angle_cell++;
p_dvd->i_prg_cell = NextCellPrg( p_dvd );
if( p_dvd->i_prg_cell < 0 )
{
/* EOF */
return 0;
}
p_dvd->i_map_cell = CellPrg2Map( p_dvd );
if( p_dvd->i_map_cell < 0 )
{
return 0;
}
p_dvd->i_vts_lb = CellFirstSector( p_dvd );
p_dvd->i_last_lb = CellLastSector( p_dvd );
p_dvd->i_chapter = NextChapter( p_dvd );
if( p_dvd->i_chapter < 0 )
{
return 0;
}
/* Position the fd pointer on the right address */
if( dvdcss_seek( p_dvd->dvdhandle,
p_dvd->i_vts_start + p_dvd->i_vts_lb,
DVDCSS_SEEK_MPEG ) < 0 )
{
#if 0
intf_ErrMsg( "dvd error: %s",
dvdcss_error( p_dvd->dvdhandle ) );
#endif
return 0;
}
i_block_once = p_dvd->i_last_lb + 1 - p_dvd->i_vts_lb;
}
return i_block_once;
}
int CellPrg2Chapter( thread_dvd_data_t * p_dvd )
{
unsigned int i_chapter = 1;
unsigned int i_cell = p_dvd->i_prg_cell;
if( CellIsInterleaved( p_dvd ) )
{
i_cell -= (p_dvd->i_angle - 1);
}
while( title.chapter_map.pi_start_cell[i_chapter] <= i_cell+1 )
{
i_chapter ++;
if( i_chapter >= p_dvd->i_chapter_nb )
{
return p_dvd->i_chapter_nb;
}
}
return i_chapter;
}
int NextChapter( thread_dvd_data_t * p_dvd )
{
int i_cell = p_dvd->i_prg_cell;
if( CellIsInterleaved( p_dvd ) )
{
i_cell -= (p_dvd->i_angle - 1);
}
if( title.chapter_map.pi_start_cell[p_dvd->i_chapter] <= i_cell+1 )
{
p_dvd->i_chapter++;
if( p_dvd->i_chapter > p_dvd->i_chapter_nb )
{
return -1;
}
p_dvd->b_new_chapter = 1;
return p_dvd->i_chapter;
}
return p_dvd->i_chapter;
}
int DVDSetChapter( thread_dvd_data_t * p_dvd, unsigned int i_chapter )
{
if( i_chapter <= 0 || i_chapter > p_dvd->i_chapter_nb )
{
i_chapter = 1;
}
if( p_dvd->i_chapter != i_chapter )
{
/* Find cell index in Program chain for current chapter */
p_dvd->i_prg_cell = title.chapter_map.pi_start_cell[i_chapter-1] - 1;
p_dvd->i_prg_cell += CellAngleOffset( p_dvd, p_dvd->i_prg_cell );
if( i_chapter < p_dvd->i_chapter )
{
p_dvd->i_map_cell = 0;
}
p_dvd->i_map_cell = CellPrg2Map( p_dvd );
p_dvd->i_vts_lb = CellFirstSector( p_dvd );
p_dvd->i_last_lb = CellLastSector( p_dvd );
/* Position the fd pointer on the right address */
if( dvdcss_seek( p_dvd->dvdhandle,
p_dvd->i_vts_start + p_dvd->i_vts_lb,
DVDCSS_SEEK_MPEG ) < 0 )
{
#if 0
intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) );
#endif
return -1;
}
#if 0
intf_WarnMsg( 4, "dvd info: chapter %d prg_cell %d map_cell %d",
i_chapter, p_dvd->i_prg_cell, p_dvd->i_map_cell );
#endif
}
return i_chapter;
}
#undef cell
#undef title
/* dvd_seek.h: DVD access plugin.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: seek.h,v 1.2 2002/12/06 16:34:04 sam Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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.
*****************************************************************************/
int CellIsInterleaved( thread_dvd_data_t * );
int CellAngleOffset ( thread_dvd_data_t *, int );
int CellPrg2Map ( thread_dvd_data_t * );
int CellFirstSector ( thread_dvd_data_t * );
int CellLastSector ( thread_dvd_data_t * );
int NextCellPrg ( thread_dvd_data_t * );
int Lb2CellPrg ( thread_dvd_data_t * );
int Lb2CellMap ( thread_dvd_data_t * );
int LbMaxOnce ( thread_dvd_data_t * );
int CellPrg2Chapter ( thread_dvd_data_t * );
int NextChapter ( thread_dvd_data_t * );
int DVDSetChapter ( thread_dvd_data_t *, unsigned int );
/*****************************************************************************
* summary.c: set of functions to print options of selected title
* found in .ifo.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: summary.c,v 1.2 2002/08/08 00:35:10 sam Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <vlc/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if !defined( WIN32 )
# include <netinet/in.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include <errno.h>
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "ifo.h"
#include "iso_lang.h"
/*
* Local tools to decode some data in ifo
*/
/****************************************************************************
* IfoPrintTitle
****************************************************************************/
void IfoPrintTitle( thread_dvd_data_t * p_dvd )
{
#if 0
intf_WarnMsg( 5, "dvd info: title %d, %d chapter%s, %d angle%s",
p_dvd->i_title, p_dvd->i_chapter_nb,
(p_dvd->i_chapter_nb == 1) ? "" : "s",
p_dvd->i_angle_nb,
(p_dvd->i_angle_nb == 1) ? "" : "s" );
#endif
}
/****************************************************************************
* IfoPrintVideo
****************************************************************************/
#define video p_dvd->p_ifo->vts.manager_inf.video_attr
void IfoPrintVideo( thread_dvd_data_t * p_dvd )
{
#if 0
char* psz_perm_displ[4] =
{
"pan-scan & letterboxed",
"pan-scan",
"letterboxed",
"not specified"
};
char* psz_source_res[4] =
{
"720x480 ntsc or 720x576 pal",
"704x480 ntsc or 704x576 pal",
"352x480 ntsc or 352x576 pal",
"352x240 ntsc or 352x288 pal"
};
intf_WarnMsg( 5, "dvd info: MPEG-%d video, %sHz, aspect ratio %s",
video.i_compression + 1,
video.i_system ? "pal 625 @50" : "ntsc 525 @60",
video.i_ratio ? (video.i_ratio == 3) ? "16:9"
: "unknown"
: "4:3" );
intf_WarnMsg( 5, "dvd info: display mode %s, %s, %s",
psz_perm_displ[video.i_perm_displ],
video.i_line21_1 ? "line21-1 data in GOP"
: "no line21-1 data",
video.i_line21_2 ? "line21-2 data in GOP"
: "no line21-2 data" );
intf_WarnMsg( 5, "dvd info: source is %s, %sletterboxed, %s mode",
psz_source_res[video.i_source_res],
video.i_letterboxed ? "" : "not ",
video.i_mode ? "film (625/50 only)" : "camera" );
#endif
}
#undef video
/****************************************************************************
* IfoPrintAudio
****************************************************************************/
#define audio p_dvd->p_ifo->vts.manager_inf.p_audio_attr[i-1]
#define audio_status \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_audio_status[i-1]
void IfoPrintAudio( thread_dvd_data_t * p_dvd, int i )
{
if( audio_status.i_available )
{
#if 0
char* ppsz_mode[8] =
{ "A52", "unknown", "MPEG", "MPEG-2", "LPCM", "SDDS", "DTS", "" };
char* ppsz_appl_mode[4] =
{ "no application specified", "karaoke", "surround sound", "" };
char* ppsz_quant[4] =
{ "16 bits", "20 bits", "24 bits", "drc" };
intf_WarnMsg( 5, "dvd info: audio %d (%s) is %s, "
"%d%s channel%s, %dHz, %s", i,
DecodeLanguage( audio.i_lang_code ),
ppsz_mode[audio.i_coding_mode & 0x7],
audio.i_num_channels + 1,
audio.i_multichannel_extension ? " ext." : "",
audio.i_num_channels ? "s" : "",
audio.i_sample_freq ? 96000 : 48000,
ppsz_appl_mode[audio.i_appl_mode & 0x3] );
intf_WarnMsg( 5, "dvd info: %s, quantization %s, status %x",
(audio.i_caption == 1) ? "normal caption"
: (audio.i_caption == 3) ? "directors comments"
: "unknown caption",
ppsz_quant[audio.i_quantization & 0x3],
audio_status.i_position );
#endif
}
}
#undef audio_status
#undef audio
/****************************************************************************
* IfoPrintSpu
****************************************************************************/
#define spu p_dvd->p_ifo->vts.manager_inf.p_spu_attr[i-1]
#define spu_status \
p_dvd->p_ifo->vts.title_unit.p_title[p_dvd->i_title_id-1].title.pi_spu_status[i-1]
void IfoPrintSpu( thread_dvd_data_t * p_dvd, int i )
{
if( spu_status.i_available )
{
#if 0
intf_WarnMsg( 5, "dvd info: spu %d (%s), caption %d "
"prefix %x, modes [%s%s%s%s ]", i,
DecodeLanguage( spu.i_lang_code ),
spu.i_caption, spu.i_prefix,
spu_status.i_position_43 ? " 4:3" : "",
spu_status.i_position_wide ? " wide" : "",
spu_status.i_position_letter ? " letter" : "",
spu_status.i_position_pan ? " pan" : "" );
#endif
}
}
#undef spu_status
#undef spu
/*****************************************************************************
* dvd_summary.h: prototype of functions that print out current options.
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: summary.h,v 1.1 2002/08/04 17:23:41 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* 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.
*****************************************************************************/
struct thread_dvd_data_s;
void IfoPrintTitle( struct thread_dvd_data_s * );
void IfoPrintVideo( struct thread_dvd_data_s * );
void IfoPrintAudio( struct thread_dvd_data_s *, int );
void IfoPrintSpu ( struct thread_dvd_data_s *, int );
/*****************************************************************************
* udf.c: udf filesystem tools.
*****************************************************************************
* Mainly used to find asolute logical block adress of *.ifo files. It only
* contains the basic udf handling functions
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: udf.c,v 1.5 2003/03/03 14:21:08 gbazin Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* based on:
* - dvdudf by Christian Wolff <scarabaeus@convergence.de>
* - fixes by Billy Biggs <vektor@dumbterm.net>
*
* 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 <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <vlc/vlc.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#ifdef GOD_DAMN_DMCA
# include "dvdcss.h"
#else
# include <dvdcss/dvdcss.h>
#endif
#include "dvd.h"
#include "ifo.h"
#define UDFADshort 1
#define UDFADlong 2
#define UDFADext 4
typedef struct partition_s
{
vlc_bool_t b_valid;
uint8_t pi_volume_desc[128];
uint16_t i_flags;
uint16_t i_number;
uint8_t pi_contents[32];
uint32_t i_access_type;
uint32_t i_start;
uint32_t i_length;
dvdcss_handle dvdhandle;
} partition_t;
typedef struct ad_s
{
uint32_t i_location;
uint32_t i_length;
uint8_t i_flags;
uint16_t i_partition;
} ad_t;
/* for direct data access, LSB first */
#define GETN1(p) ((uint8_t)pi_data[p])
#define GETN2(p) ((uint16_t)pi_data[p]|((uint16_t)pi_data[(p)+1]<<8))
#define GETN4(p) ((uint32_t)pi_data[p]|((uint32_t)pi_data[(p)+1]<<8)|((uint32_t)pi_data[(p)+2]<<16)|((uint32_t)pi_data[(p)+3]<<24))
#define GETN(p,n,target) memcpy(target,&pi_data[p],n)
/*****************************************************************************
* UDFReadLB: reads absolute Logical Block of the disc
*****************************************************************************
* Returns number of read bytes on success, 0 on error
*****************************************************************************/
static int UDFReadLB( dvdcss_handle dvdhandle, off_t i_lba,
size_t i_block_count, uint8_t *pi_data )
{
if( dvdcss_seek( dvdhandle, i_lba, DVDCSS_NOFLAGS ) < 0 )
{
#if 0
intf_ErrMsg( "dvd error: block %i not found", i_lba );
#endif
return 0;
}
return dvdcss_read( dvdhandle, pi_data, i_block_count, DVDCSS_NOFLAGS );
}
/*****************************************************************************
* UDFDecode: decode unicode encoded udf data
*****************************************************************************/
static int UDFDecode( uint8_t * pi_data, int i_len, char * psz_target )
{
int p = 1;
int i = 0;
if( !( pi_data[0] & 0x18 ) )
{
psz_target[0] = '\0';
return 0;
}
if( pi_data[0] & 0x10 )
{
/* ignore MSB of unicode16 */
p++;
while( p < i_len )
{
psz_target[i++] = pi_data[p+=2];
}
}
else
{
while( p < i_len )
{
psz_target[i++] = pi_data[p++];
}
}
psz_target[i]='\0';
return 0;
}
#if 0
/**
*
**/
int UDFEntity (uint8_t *data, uint8_t *Flags, char *Identifier)
{
Flags[0] = data[0];
strncpy (Identifier, &data[1], 5);
return 0;
}
#endif
/*****************************************************************************
* UDFDescriptor: gives a tag ID from your data to find out what it refers to
*****************************************************************************/
static int UDFDescriptor( uint8_t * pi_data, uint16_t * pi_tag_id )
{
pi_tag_id[0] = GETN2( 0 );
/* TODO: check CRC 'n stuff */
return 0;
}
/*****************************************************************************
* UDFExtendAD: main volume information
*****************************************************************************/
static int UDFExtentAD ( uint8_t * pi_data, uint32_t * pi_length,
uint32_t * pi_location)
{
pi_length[0] = GETN4( 0 );
pi_location[0] = GETN4( 4 );
return 0;
}
/*****************************************************************************
* UDFAD: file set information
*****************************************************************************/
static int UDFAD( uint8_t * pi_data, struct ad_s * p_ad, uint8_t i_type,
struct partition_s partition )
{
p_ad->i_length = GETN4( 0 );
p_ad->i_flags = p_ad->i_length >> 30;
p_ad->i_length &= 0x3FFFFFFF;
switch( i_type )
{
case UDFADshort:
p_ad->i_location = GETN4( 4 );
/* use number of current partition */
p_ad->i_partition = partition.i_number;
break;
case UDFADlong:
p_ad->i_location = GETN4( 4 );
p_ad->i_partition = GETN2( 8 );
break;
case UDFADext:
p_ad->i_location = GETN4( 12 );
p_ad->i_partition = GETN2( 16 );
break;
}
return 0;
}
/*****************************************************************************
* UDFICB: takes Information Control Block from pi_data
*****************************************************************************/
static int UDFICB( uint8_t * pi_data, uint8_t * pi_file_type,
uint16_t * pi_flags)
{
pi_file_type[0] = GETN1( 11 );
pi_flags[0] = GETN2( 18 );
return 0;
}
/*****************************************************************************
* UDFPartition: gets partition descriptor
*****************************************************************************/
static int UDFPartition( uint8_t * pi_data, uint16_t * pi_flags,
uint16_t * pi_nb, byte_t * ps_contents,
uint32_t * pi_start, uint32_t * pi_length )
{
pi_flags[0] = GETN2( 20 );
pi_nb[0] = GETN2( 22 );
GETN( 24, 32, ps_contents );
pi_start[0] = GETN4( 188 );
pi_length[0] = GETN4( 192 );
return 0;
}
/*****************************************************************************
* UDFLogVolume: reads the volume descriptor and checks the parameters
*****************************************************************************
* Returns 0 on OK, 1 on error
*****************************************************************************/
static int UDFLogVolume( uint8_t * pi_data, byte_t * p_volume_descriptor )
{
uint32_t i_lb_size;
uint32_t i_MT_L;
uint32_t i_N_PM;
UDFDecode( &pi_data[84], 128, (char *)p_volume_descriptor );
i_lb_size = GETN4( 212 ); /* should be 2048 */
i_MT_L = GETN4( 264 ); /* should be 6 */
i_N_PM = GETN4( 268 ); /* should be 1 */
if( i_lb_size != DVD_LB_SIZE )
{
#if 0
intf_ErrMsg( "dvd error: invalid UDF sector size (%d)", i_lb_size );
#endif
return 1;
}
return 0;
}
/*****************************************************************************
* UDFFileEntry: fills a ad_t struct with information at pi_data
*****************************************************************************/
static int UDFFileEntry( uint8_t * pi_data, uint8_t * pi_file_type,
struct ad_s * p_ad, struct partition_s partition )
{
uint8_t i_file_type;
uint16_t i_flags;
uint32_t i_L_EA;
uint32_t i_L_AD;
unsigned int p;
UDFICB( &pi_data[16], &i_file_type, &i_flags );
pi_file_type[0] = i_file_type;
i_L_EA = GETN4( 168 );
i_L_AD = GETN4( 172 );
p = 176 + i_L_EA;
while( p < 176 + i_L_EA + i_L_AD )
{
switch( i_flags & 0x07 )
{
case 0:
UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
p += 0x08;
break;
case 1:
UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
p += 0x10;
break;
case 2:
UDFAD( &pi_data[p], p_ad, UDFADext, partition );
p += 0x14;
break;
case 3:
switch( i_L_AD )
{
case 0x08:
UDFAD( &pi_data[p], p_ad, UDFADshort, partition );
break;
case 0x10:
UDFAD( &pi_data[p], p_ad, UDFADlong, partition );
break;
case 0x14:
UDFAD( &pi_data[p], p_ad, UDFADext, partition );
break;
}
default:
p += i_L_AD;
break;
}
}
return 0;
}
/*****************************************************************************
* UDFFileIdentifier: gives filename and characteristics of pi_data
*****************************************************************************/
static int UDFFileIdentifier( uint8_t * pi_data, uint8_t * pi_file_info,
char * psz_filename, struct ad_s * p_file_icb,
struct partition_s partition )
{
uint8_t i_L_FI;
uint16_t i_L_IU;
pi_file_info[0] = GETN1( 18 );
i_L_FI = GETN1( 19 );
UDFAD( &pi_data[20], p_file_icb, UDFADlong, partition );
i_L_IU = GETN2( 36 );
if( i_L_FI )
{
UDFDecode( &pi_data[38+i_L_IU], i_L_FI, psz_filename );
}
else
{
psz_filename[0]='\0';
}
return 4 * ( ( 38 + i_L_FI + i_L_IU + 3 ) / 4 );
}
/*****************************************************************************
* UDFMapICB: Maps ICB to FileAD
*****************************************************************************
* ICB: Location of ICB of directory to scan
* FileType: Type of the file
* File: Location of file the ICB is pointing to
* return 1 on success, 0 on error;
*****************************************************************************/
static int UDFMapICB( struct ad_s icb, uint8_t * pi_file_type,
struct ad_s * p_file, struct partition_s partition )
{
uint8_t pi_lb[DVD_LB_SIZE];
uint32_t i_lba;
uint16_t i_tag_id;
i_lba = partition.i_start + icb.i_location;
do
{
if( !UDFReadLB( partition.dvdhandle, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
UDFDescriptor( pi_lb , &i_tag_id );
}
if( i_tag_id == 261 )
{
UDFFileEntry( pi_lb, pi_file_type, p_file, partition );
return 1;
}
} while( ( i_lba <= partition.i_start + icb.i_location +
( icb.i_length - 1 ) / DVD_LB_SIZE ) && ( i_tag_id != 261 ) );
return 0;
}
/*****************************************************************************
* UDFScanDir: serach filename in dir
*****************************************************************************
* Dir: Location of directory to scan
* FileName: Name of file to look for
* FileICB: Location of ICB of the found file
* return 1 on success, 0 on error;
*****************************************************************************/
static int UDFScanDir( struct ad_s dir, char * psz_filename,
struct ad_s * p_file_icb, struct partition_s partition )
{
uint8_t pi_lb[2*DVD_LB_SIZE];
uint32_t i_lba;
uint16_t i_tag_id;
uint8_t i_file_char;
char psz_temp[DVD_LB_SIZE];
unsigned int p;
/* Scan dir for ICB of file */
i_lba = partition.i_start + dir.i_location;
#if 0
do
{
if( !UDFReadLB( partition.dvdhandle, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
p=0;
while( p < DVD_LB_SIZE )
{
UDFDescriptor( &pi_lb[p], &i_tag_id );
if( i_tag_id == 257 )
{
p += UDFFileIdentifier( &pi_lb[p], &i_file_char,
psz_temp, p_file_icb, partition );
if( !strcasecmp( psz_filename, psz_temp ) )
{
return 1;
}
}
else
{
p = DVD_LB_SIZE;
}
}
}
} while( i_lba <=
partition.i_start + dir.i_location + ( dir.i_length - 1 ) / DVD_LB_SIZE );
#else
if( UDFReadLB( partition.dvdhandle, i_lba, 2, pi_lb ) <= 0 ) {
return 0;
}
p = 0;
while( p < dir.i_length )
{
if( p > DVD_LB_SIZE )
{
++i_lba;
p -= DVD_LB_SIZE;
dir.i_length -= DVD_LB_SIZE;
if( UDFReadLB( partition.dvdhandle, i_lba, 2, pi_lb ) <= 0 )
{
return 0;
}
}
UDFDescriptor( &pi_lb[p], &i_tag_id );
if( i_tag_id == 257 )
{
p += UDFFileIdentifier( &pi_lb[p], &i_file_char,
psz_temp, p_file_icb, partition );
if( !strcasecmp( psz_filename, psz_temp ) )
{
return 1;
}
}
else
{
return 0;
}
}
#endif
return 0;
}
/*****************************************************************************
* UDFFindPartition: looks for a partition on the disc
*****************************************************************************
* partnum: number of the partition, starting at 0
* part: structure to fill with the partition information
* return 1 if partition found, 0 on error;
*****************************************************************************/
static int UDFFindPartition( int i_part_nb, struct partition_s *p_partition )
{
uint8_t pi_lb[DVD_LB_SIZE];
uint8_t pi_anchor[DVD_LB_SIZE];
uint16_t i_tag_id;
uint32_t i_lba;
uint32_t i_MVDS_location;
uint32_t i_MVDS_length;
uint32_t i_last_sector;
vlc_bool_t b_term;
vlc_bool_t b_vol_valid;
int i;
/* Find Anchor */
i_last_sector = 0;
/* try #1, prime anchor */
i_lba = 256;
b_term = 0;
/* Search anchor loop */
while( 1 )
{
if( UDFReadLB( p_partition->dvdhandle, i_lba, 1, pi_anchor ) )
{
UDFDescriptor( pi_anchor, &i_tag_id );
}
else
{
i_tag_id = 0;
}
if( i_tag_id != 2 )
{
/* not an anchor? */
if( b_term )
{
/* final try failed */
return 0;
}
if( i_last_sector )
{
/* we already found the last sector
* try #3, alternative backup anchor */
i_lba = i_last_sector;
/* but that's just about enough, then! */
b_term = 1;
}
else
{
/* TODO: find last sector of the disc (this is optional) */
if( i_last_sector )
{
/* try #2, backup anchor */
i_lba = i_last_sector - 256;
}
else
{
/* unable to find last sector */
return 0;
}
}
}
else
{
/* it is an anchor! continue... */
break;
}
}
/* main volume descriptor */
UDFExtentAD( &pi_anchor[16], &i_MVDS_length, &i_MVDS_location );
p_partition->b_valid = 0;
b_vol_valid = 0;
p_partition->pi_volume_desc[0] = '\0';
i = 1;
/* Find Volume Descriptor */
do
{
i_lba = i_MVDS_location;
do
{
if( !UDFReadLB( p_partition->dvdhandle, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
UDFDescriptor( pi_lb, &i_tag_id );
}
if( ( i_tag_id == 5 ) && ( !p_partition->b_valid ) )
{
/* Partition Descriptor */
UDFPartition( pi_lb,
&p_partition->i_flags,
&p_partition->i_number,
p_partition->pi_contents,
&p_partition->i_start,
&p_partition->i_length );
p_partition->b_valid = ( i_part_nb == p_partition->i_number );
}
else if( ( i_tag_id == 6 ) && ( !b_vol_valid) )
{
/* Logical Volume Descriptor */
if( UDFLogVolume( pi_lb , p_partition->pi_volume_desc ) )
{
/* TODO: sector size wrong! */
}
else
{
b_vol_valid = 1;
}
}
} while( ( i_lba <= i_MVDS_location +
( i_MVDS_length - 1 ) / DVD_LB_SIZE )
&& ( i_tag_id != 8 )
&& ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
if( ( !p_partition->b_valid ) || ( !b_vol_valid ) )
{
/* backup volume descriptor */
UDFExtentAD( &pi_anchor[24], &i_MVDS_length, &i_MVDS_location );
}
} while( i-- && ( ( !p_partition->b_valid ) || ( !b_vol_valid ) ) );
/* we only care for the partition, not the volume */
return( p_partition->b_valid);
}
/*****************************************************************************
* DVDUDFFindFile: looks for a file on the UDF disc/imagefile
*****************************************************************************
* Path has to be the absolute pathname on the UDF filesystem,
* starting with '/'.
* returns absolute LB number, or 0 on error
*****************************************************************************/
uint32_t DVDUDFFindFile( dvdcss_handle dvdhandle, char * psz_path )
{
struct partition_s partition;
struct ad_s root_icb;
struct ad_s file;
struct ad_s icb;
uint32_t i_lba;
uint16_t i_tag_id;
uint8_t pi_lb[DVD_LB_SIZE];
uint8_t i_file_type;
char psz_tokenline[DVD_LB_SIZE] = "";
char * psz_token;
int i_partition;
strcat( psz_tokenline, psz_path );
/* Init file descriptor of UDF filesystem (== DVD) */
partition.dvdhandle = dvdhandle;
/* Find partition 0, standard partition for DVD-Video */
i_partition = 0;
if( !UDFFindPartition( i_partition, &partition ) )
{
#if 0
intf_ErrMsg( "dvd error: partition 0 not found" );
#endif
return 0;
}
/* Find root dir ICB */
i_lba = partition.i_start;
do
{
if( !UDFReadLB( dvdhandle, i_lba++, 1, pi_lb ) )
{
i_tag_id = 0;
}
else
{
UDFDescriptor( pi_lb, &i_tag_id );
}
if( i_tag_id == 256 )
{
/* File Set Descriptor */
UDFAD( &pi_lb[400], &root_icb, UDFADlong, partition );
}
} while( ( i_lba < partition.i_start + partition.i_length )
&& ( i_tag_id != 8) && ( i_tag_id != 256 ) );
if( i_tag_id != 256 )
{
#if 0
intf_ErrMsg( "dvd error: bad UDF descriptor" );
#endif
return 0;
}
if( root_icb.i_partition != i_partition )
{
#if 0
intf_ErrMsg( "dvd error: bad UDF partition" );
#endif
return 0;
}
/* Find root dir */
if( !UDFMapICB( root_icb, &i_file_type, &file, partition ) )
{
#if 0
intf_ErrMsg( "dvd error: can't find root dir" );
#endif
return 0;
}
/* root dir should be dir */
if( i_file_type != 4 )
{
#if 0
intf_ErrMsg( "dvd error: root dir error" );
#endif
return 0;
}
/* Tokenize filepath */
psz_token = strtok( psz_tokenline, "/" );
while( psz_token )
{
if( !UDFScanDir( file, psz_token, &icb, partition ) )
{
#if 0
intf_ErrMsg( "dvd error: scan dir error" );
#endif
return 0;
}
if( !UDFMapICB ( icb, &i_file_type, &file, partition ) )
{
#if 0
intf_ErrMsg( "dvd error: ICB error" );
#endif
return 0;
}
psz_token = strtok( NULL, "/" );
}
return partition.i_start + file.i_location;
}
/*****************************************************************************
* dvd_udf.h: structures for udf filesystem tools.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: udf.h,v 1.2 2003/10/25 00:49:13 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* based on:
* - dvdudf by Christian Wolff <scarabaeus@convergence.de>
*
* 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.
*****************************************************************************/
/*
* Fonctions in dvd_udf.c
*/
uint32_t DVDUDFFindFile( dvdcss_handle, char * );
SOURCES_dvdplay = \
dvd.c \
dvd.h \
access.c \
access.h \
demux.c \
demux.h \
intf.c \
intf.h \
es.c \
es.h \
tools.c \
tools.h \
$(NULL)
/*****************************************************************************
* access.c: access capabilities for dvdplay plugin.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: access.c,v 1.19 2003/08/13 01:45:13 gbazin Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include "../../demux/mpeg/system.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include "dvd.h"
#include "es.h"
#include "tools.h"
#include "intf.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
/* called from outside */
static int dvdplay_SetArea ( input_thread_t *, input_area_t * );
static int dvdplay_SetProgram ( input_thread_t *, pgrm_descriptor_t * );
static ssize_t dvdplay_Read ( input_thread_t *, byte_t *, size_t );
static void dvdplay_Seek ( input_thread_t *, off_t );
static void pf_vmg_callback ( void*, dvdplay_event_t );
/* only from inside */
static int dvdNewArea( input_thread_t *, input_area_t * );
static int dvdNewPGC ( input_thread_t * );
static int MenusCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
/*****************************************************************************
* OpenDVD: open libdvdplay
*****************************************************************************/
int E_(OpenDVD) ( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
char * psz_source;
dvd_data_t * p_dvd;
input_area_t * p_area;
unsigned int i_title_nr;
unsigned int i_title;
unsigned int i_chapter;
unsigned int i_angle;
unsigned int i;
vlc_value_t val, text;
p_dvd = malloc( sizeof(dvd_data_t) );
if( p_dvd == NULL )
{
msg_Err( p_input, "out of memory" );
return -1;
}
p_input->p_access_data = (void *)p_dvd;
p_input->pf_read = dvdplay_Read;
p_input->pf_seek = dvdplay_Seek;
p_input->pf_set_area = dvdplay_SetArea;
p_input->pf_set_program = dvdplay_SetProgram;
/* command line */
if( ( psz_source = dvdplay_ParseCL( p_input,
&i_title, &i_chapter, &i_angle ) ) == NULL )
{
free( p_dvd );
return -1;
}
/* Open libdvdplay */
p_dvd->vmg = dvdplay_open( psz_source, pf_vmg_callback, (void*)p_input );
if( p_dvd->vmg == NULL )
{
msg_Warn( p_input, "cannot open %s", psz_source );
free( psz_source );
free( p_dvd );
return -1;
}
/* free allocated strings */
free( psz_source );
p_dvd->p_intf = NULL;
p_dvd->i_still_time = 0;
/* set up input */
p_input->i_mtu = 0;
/* Set stream and area data */
vlc_mutex_lock( &p_input->stream.stream_lock );
/* If we are here we can control the pace... */
p_input->stream.b_pace_control = 1;
/* seek is only allowed when we have size info */
p_input->stream.b_seekable = 0;
/* Initialize ES structures */
input_InitStream( p_input, sizeof( stream_ps_data_t ) );
/* disc input method */
p_input->stream.i_method = INPUT_METHOD_DVD;
i_title_nr = dvdplay_title_nr( p_dvd->vmg );
#define area p_input->stream.pp_areas
/* Area 0 for menu */
area[0]->i_plugin_data = 0;
input_DelArea( p_input, p_input->stream.pp_areas[0] );
input_AddArea( p_input, 0, 1 );
for( i = 1 ; i <= i_title_nr ; i++ )
{
input_AddArea( p_input, i, dvdplay_chapter_nr( p_dvd->vmg, i ) );
area[i]->i_plugin_data = 0;
}
#undef area
msg_Dbg( p_input, "number of titles: %d", i_title_nr );
i_title = i_title <= i_title_nr ? i_title : 0;
p_area = p_input->stream.pp_areas[i_title];
p_area->i_part = i_chapter;
p_input->stream.p_selected_area = NULL;
/* set title, chapter, audio and subpic */
if( dvdplay_SetArea( p_input, p_area ) )
{
vlc_mutex_unlock( &p_input->stream.stream_lock );
return -1;
}
if( i_angle <= p_input->stream.i_pgrm_number )
{
dvdplay_SetProgram( p_input,
p_input->stream.pp_programs[i_angle - 1] );
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
if( !p_input->psz_demux || !*p_input->psz_demux )
{
p_input->psz_demux = "dvdplay";
}
/* FIXME: we might lose variables here */
var_Create( p_input, "x-start", VLC_VAR_INTEGER );
var_Create( p_input, "y-start", VLC_VAR_INTEGER );
var_Create( p_input, "x-end", VLC_VAR_INTEGER );
var_Create( p_input, "y-end", VLC_VAR_INTEGER );
var_Create( p_input, "color", VLC_VAR_ADDRESS );
var_Create( p_input, "contrast", VLC_VAR_ADDRESS );
var_Create( p_input, "highlight", VLC_VAR_BOOL );
var_Create( p_input, "highlight-mutex", VLC_VAR_MUTEX );
/* Create a few object variables used for navigation in the interfaces */
var_Create( p_input, "dvd_menus",
VLC_VAR_INTEGER | VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
text.psz_string = _("DVD menus");
var_Change( p_input, "dvd_menus", VLC_VAR_SETTEXT, &text, NULL );
var_AddCallback( p_input, "dvd_menus", MenusCallback, NULL );
val.i_int = ROOT_MENU; text.psz_string = _("Root");
var_Change( p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = TITLE_MENU; text.psz_string = _("Title");
var_Change( p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = PART_MENU; text.psz_string = _("Chapter");
var_Change( p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = SUBPICTURE_MENU; text.psz_string = _("Subtitle");
var_Change( p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = AUDIO_MENU; text.psz_string = _("Audio");
var_Change( p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = ANGLE_MENU; text.psz_string = _("Angle");
var_Change( p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = 99; text.psz_string = _("Resume");
var_Change( p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
return 0;
}
/*****************************************************************************
* CloseDVD: close libdvdplay
*****************************************************************************/
void E_(CloseDVD) ( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
dvd_data_t * p_dvd = (dvd_data_t *)p_input->p_access_data;
var_Destroy( p_input, "highlight-mutex" );
var_Destroy( p_input, "highlight" );
var_Destroy( p_input, "x-start" );
var_Destroy( p_input, "x-end" );
var_Destroy( p_input, "y-start" );
var_Destroy( p_input, "y-end" );
var_Destroy( p_input, "color" );
var_Destroy( p_input, "contrast" );
/* close libdvdplay */
dvdplay_close( p_dvd->vmg );
free( p_dvd );
p_input->p_access_data = NULL;
}
/*****************************************************************************
* dvdplay_SetProgram: set dvd angle.
*****************************************************************************
* This is actually a hack to make angle change through vlc interface with
* no need for a specific button.
*****************************************************************************/
static int dvdplay_SetProgram( input_thread_t * p_input,
pgrm_descriptor_t * p_program )
{
if( p_input->stream.p_selected_program != p_program )
{
dvd_data_t * p_dvd;
int i_angle;
vlc_value_t val;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
i_angle = p_program->i_number;
if( !dvdplay_angle( p_dvd->vmg, i_angle ) )
{
memcpy( p_program, p_input->stream.p_selected_program,
sizeof(pgrm_descriptor_t) );
p_program->i_number = i_angle;
p_input->stream.p_selected_program = p_program;
msg_Dbg( p_input, "angle %d selected", 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 0;
}
/*****************************************************************************
* dvdplay_SetArea: 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 dvdplay_SetArea( input_thread_t * p_input, input_area_t * p_area )
{
dvd_data_t * p_dvd;
vlc_value_t val;
p_dvd = (dvd_data_t*)p_input->p_access_data;
/*
* Title selection
*/
if( p_area != p_input->stream.p_selected_area )
{
int i_chapter;
/* prevent intf to try to seek */
p_input->stream.b_seekable = 0;
/* Store selected chapter */
i_chapter = p_area->i_part;
dvdNewArea( p_input, p_area );
dvdNewPGC( p_input );
dvdplay_start( p_dvd->vmg, p_area->i_id );
p_area->i_part = i_chapter;
} /* i_title >= 0 */
else
{
p_area = p_input->stream.p_selected_area;
}
/*
* Chapter selection
*/
if( (int)p_area->i_part != dvdplay_chapter_cur( p_dvd->vmg ) )
{
if( ( p_area->i_part > 0 ) &&
( p_area->i_part <= p_area->i_part_nb ))
{
dvdplay_pg( p_dvd->vmg, p_area->i_part );
}
p_area->i_part = dvdplay_chapter_cur( p_dvd->vmg );
}
/* warn interface that something has changed */
p_area->i_tell =
LB2OFF( dvdplay_position( p_dvd->vmg ) ) - p_area->i_start;
p_input->stream.b_changed = 1;
/* 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 0;
}
/*****************************************************************************
* dvdplay_Read: reads data packets.
*****************************************************************************
* Returns -1 in case of error, the number of bytes read if everything went
* well.
*****************************************************************************/
static ssize_t dvdplay_Read( input_thread_t * p_input,
byte_t * p_buffer, size_t i_count )
{
dvd_data_t * p_dvd;
off_t i_read;
p_dvd = (dvd_data_t *)p_input->p_access_data;
vlc_mutex_lock( &p_input->stream.stream_lock );
i_read = LB2OFF( dvdplay_read( p_dvd->vmg, p_buffer, OFF2LB( i_count ) ) );
vlc_mutex_unlock( &p_input->stream.stream_lock );
return i_read;
}
/*****************************************************************************
* dvdplay_Seek : 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 dvdplay_Seek( input_thread_t * p_input, off_t i_off )
{
dvd_data_t * p_dvd;
p_dvd = (dvd_data_t *)p_input->p_access_data;
vlc_mutex_lock( &p_input->stream.stream_lock );
dvdplay_seek( p_dvd->vmg, OFF2LB( i_off ) );
p_input->stream.p_selected_area->i_tell =
LB2OFF( dvdplay_position( p_dvd->vmg ) ) -
p_input->stream.p_selected_area->i_start;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return;
}
/*****************************************************************************
* pf_vmg_callback: called by libdvdplay when some event happens
*****************************************************************************
* The stream lock has to be taken before entering here
*****************************************************************************/
static void pf_vmg_callback( void* p_args, dvdplay_event_t event )
{
input_thread_t * p_input;
dvd_data_t * p_dvd;
vlc_value_t val;
unsigned int i;
p_input = (input_thread_t*)p_args;
p_dvd = (dvd_data_t*)p_input->p_access_data;
switch( event )
{
case NEW_DOMAIN:
break;
case NEW_VTS:
break;
case NEW_FILE:
break;
case NEW_PGC:
/* prevent intf to try to seek by default */
p_input->stream.b_seekable = 0;
i = dvdplay_title_cur( p_dvd->vmg );
if( i != p_input->stream.p_selected_area->i_id )
{
/* the title number has changed: update area */
msg_Warn( p_input, "new title %d (%d)", i,
p_input->stream.p_selected_area->i_id );
dvdNewArea( p_input,
p_input->stream.pp_areas[i] );
}
/* new pgc in same title: reinit ES */
dvdplay_ES( p_input );
dvdNewPGC( p_input );
p_input->stream.b_changed = 1;
break;
case JUMP:
dvdplay_ES( p_input );
dvdNewPGC( p_input );
case NEW_PG:
/* update current chapter */
p_input->stream.p_selected_area->i_part =
dvdplay_chapter_cur( p_dvd->vmg );
p_input->stream.p_selected_area->i_tell =
LB2OFF( dvdplay_position( p_dvd->vmg ) ) -
p_input->stream.p_selected_area->i_start;
/* warn interface that something has changed */
p_input->stream.b_changed = 1;
/* Update the navigation variables without triggering a callback */
val.i_int = p_input->stream.p_selected_area->i_part;
var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &val, NULL );
break;
case NEW_CELL:
p_dvd->b_end_of_cell = 0;
break;
case END_OF_CELL:
p_dvd->b_end_of_cell = 1;
break;
case STILL_TIME:
/* we must pause only from demux
* when the data in cache has been decoded */
p_dvd->i_still_time = dvdplay_still_time( p_dvd->vmg );
msg_Dbg( p_input, "still time %d", p_dvd->i_still_time );
break;
case COMPLETE_VIDEO:
break;
case NEW_HIGHLIGHT:
if( var_Get( p_input, "highlight-mutex", &val ) == VLC_SUCCESS )
{
vlc_mutex_t *p_mutex = val.p_address;
vlc_mutex_lock( p_mutex );
/* Retrieve the highlight from dvdplay */
dvdplay_highlight( p_dvd->vmg, &p_dvd->hli );
if( p_dvd->hli.i_x_start || p_dvd->hli.i_y_start ||
p_dvd->hli.i_x_end || p_dvd->hli.i_y_end )
{
/* Fill our internal variables with this data */
val.i_int = p_dvd->hli.i_x_start;
var_Set( p_input, "x-start", val );
val.i_int = p_dvd->hli.i_y_start;
var_Set( p_input, "y-start", val );
val.i_int = p_dvd->hli.i_x_end;
var_Set( p_input, "x-end", val );
val.i_int = p_dvd->hli.i_y_end;
var_Set( p_input, "y-end", val );
val.p_address = (void *)p_dvd->hli.pi_color;
var_Set( p_input, "color", val );
val.p_address = (void *)p_dvd->hli.pi_contrast;
var_Set( p_input, "contrast", val );
/* Tell the SPU decoder that there's a new highlight */
val.b_bool = VLC_TRUE;
}
else
{
/* Turn off the highlight */
val.b_bool = VLC_FALSE;
}
var_Set( p_input, "highlight", val );
vlc_mutex_unlock( p_mutex );
}
break;
default:
msg_Err( p_input, "unknown event from libdvdplay (%d)", event );
}
return;
}
static int dvdNewArea( input_thread_t * p_input, input_area_t * p_area )
{
dvd_data_t * p_dvd;
int i_angle_nb, i_angle;
vlc_value_t val;
int i;
p_dvd = (dvd_data_t*)p_input->p_access_data;
p_input->stream.p_selected_area = p_area;
/*
* One program for each angle
*/
while( p_input->stream.i_pgrm_number )
{
input_DelProgram( p_input, p_input->stream.pp_programs[0] );
}
input_AddProgram( p_input, 1, sizeof( stream_ps_data_t ) );
p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
dvdplay_angle_info( p_dvd->vmg, &i_angle_nb, &i_angle );
for( i = 1 ; i < i_angle_nb ; i++ )
{
input_AddProgram( p_input, i+1, 0 );
}
if( i_angle )
dvdplay_SetProgram( p_input,
p_input->stream.pp_programs[i_angle-1] );
else
dvdplay_SetProgram( p_input,
p_input->stream.pp_programs[0] );
/* No PSM to read in DVD mode, we already have all information */
p_input->stream.p_selected_program->b_is_ok = 1;
/* Reinit ES */
dvdplay_ES( 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; (unsigned int)i <= p_area->i_part_nb; i++ )
{
val.i_int = i;
var_Change( p_input, "chapter", VLC_VAR_ADDCHOICE, &val, NULL );
}
/* 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 0;
}
static int dvdNewPGC( input_thread_t * p_input )
{
dvd_data_t * p_dvd = (dvd_data_t*)p_input->p_access_data;
p_input->stream.p_selected_area->i_start =
LB2OFF( dvdplay_title_first( p_dvd->vmg ) );
p_input->stream.p_selected_area->i_size =
LB2OFF( dvdplay_title_end ( p_dvd->vmg ) ) -
p_input->stream.p_selected_area->i_start;
p_input->stream.p_selected_area->i_tell = 0;
if( p_input->stream.p_selected_area->i_size > 0 )
{
p_input->stream.b_seekable = 1;
}
else
{
p_input->stream.b_seekable = 0;
}
return 0;
}
static int MenusCallback( vlc_object_t *p_this, char const *psz_name,
vlc_value_t oldval, vlc_value_t newval, void *p_arg )
{
input_thread_t * p_input;
dvd_data_t * p_dvd;
p_input = (input_thread_t*)p_this;
p_dvd = (dvd_data_t*)p_input->p_access_data;
vlc_mutex_lock( &p_input->stream.stream_lock );
if( newval.i_int < 99 )
dvdplay_menu( p_dvd->vmg, newval.i_int, 0 );
else
dvdplay_resume( p_dvd->vmg );
vlc_mutex_unlock( &p_input->stream.stream_lock );
if( p_dvd->p_intf ) dvdIntfResetStillTime( p_dvd->p_intf );
return VLC_SUCCESS;
}
/*****************************************************************************
* access.h: send info to access plugin.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: access.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* 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.
*****************************************************************************/
union dvdplay_ctrl_u;
void dvdAccessSendControl( struct input_thread_t *, union dvdplay_ctrl_u * );
/*****************************************************************************
* demux.c: demux functions for dvdplay.
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id$
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/intf.h>
#include "../../demux/mpeg/system.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include "dvd.h"
#include "intf.h"
#include "es.h"
/* how many packets dvdplay_Demux will read in each loop */
#define dvdplay_READ_ONCE 64
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int Demux ( input_thread_t * );
/*****************************************************************************
* Private structure
*****************************************************************************/
struct demux_sys_t
{
dvd_data_t * p_dvd;
module_t * p_module;
mpeg_demux_t mpeg;
};
/*****************************************************************************
* InitDVD: initializes dvdplay structures
*****************************************************************************/
int E_(InitDVD) ( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
dvd_data_t * p_dvd = (dvd_data_t *)p_input->p_access_data;
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->p_demux_data->p_dvd = p_dvd;
p_input->pf_demux = Demux;
p_input->pf_demux_control = demux_vaControlDefault;
p_input->pf_rewind = NULL;
p_dvd->p_intf = intf_Create( p_input, "dvdplay" );
p_dvd->p_intf->b_block = VLC_FALSE;
intf_RunThread( p_dvd->p_intf );
return VLC_SUCCESS;
}
/*****************************************************************************
* EndDVD: frees unused data
*****************************************************************************/
void E_(EndDVD) ( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
dvd_data_t * p_dvd = p_input->p_demux_data->p_dvd;
intf_thread_t * p_intf = NULL;
p_intf = vlc_object_find( p_input, VLC_OBJECT_INTF, FIND_CHILD );
if( p_intf != NULL )
{
intf_StopThread( p_intf );
vlc_object_detach( p_intf );
vlc_object_release( p_intf );
intf_Destroy( p_intf );
}
p_dvd->p_intf = NULL;
module_Unneed( p_input, p_input->p_demux_data->p_module );
free( p_input->p_demux_data );
}
/*****************************************************************************
* Demux
*****************************************************************************/
static int Demux( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
data_packet_t * p_data;
ssize_t i_result;
ptrdiff_t i_remains;
int i_data_nb = 0;
p_dvd = p_input->p_demux_data->p_dvd;
/* Read headers to compute payload length */
do
{
i_result = p_input->p_demux_data->mpeg.pf_read_ps( p_input, &p_data );
if( i_result <= 0 )
{
return i_result;
}
i_remains = p_input->p_last_data - p_input->p_current_data;
p_input->p_demux_data->mpeg.pf_demux_ps( p_input, p_data );
++i_data_nb;
}
while( i_remains );
// if( p_dvd->b_still && p_dvd->b_end_of_cell && p_dvd->p_intf != NULL )
if( p_dvd->i_still_time && p_dvd->b_end_of_cell && p_dvd->p_intf != NULL )
{
pgrm_descriptor_t * p_pgrm;
/* when we receive still_time flag, we have to pause immediately */
var_SetInteger( p_input, "state", PAUSE_S );
dvdIntfStillTime( p_dvd->p_intf, p_dvd->i_still_time );
p_dvd->i_still_time = 0;
vlc_mutex_lock( &p_input->stream.stream_lock );
p_pgrm = p_input->stream.p_selected_program;
p_pgrm->i_synchro_state = SYNCHRO_REINIT;
vlc_mutex_unlock( &p_input->stream.stream_lock );
input_ClockManageControl( p_input, p_pgrm, 0 );
}
return i_data_nb;
}
/*****************************************************************************
* es.h: functions to handle elementary streams.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: demux.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* 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.
*****************************************************************************/
void dvdplay_DeleteES( struct input_thread_s * );
void dvdplay_Video( struct input_thread_s * );
void dvdplay_Audio( struct input_thread_s * );
void dvdplay_Subp( struct input_thread_s * );
void dvdplay_ES( struct input_thread_s * );
void dvdplay_LaunchDecoders( struct input_thread_s * );
/*****************************************************************************
* dvd.c : dvdplay module for vlc
*****************************************************************************
* This plugins should handle all the known specificities of the DVD format,
* especially the 2048 bytes logical block size.
* It depends on: libdvdplay for ifo files and block reading.
*****************************************************************************
*
* Copyright (C) 2001 VideoLAN
* $Id: dvd.c,v 1.6 2003/06/17 16:09:16 gbazin Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
* 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 <stdlib.h> /* malloc(), free() */
#include <string.h> /* strdup() */
#include <vlc/vlc.h>
/*****************************************************************************
* Exported 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 * );
int E_(OpenIntf) ( vlc_object_t * );
void E_(CloseIntf) ( vlc_object_t * );
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
add_usage_hint( N_("[dvdplay:][device][@[title][,[chapter][,angle]]]") );
set_description( _("DVD input with menus support") );
set_capability( "access", 120 );
set_callbacks( E_(OpenDVD), E_(CloseDVD) );
add_shortcut( "dvd" );
add_submodule();
set_capability( "demux", 0 );
set_callbacks( E_(InitDVD), E_(EndDVD) );
add_submodule();
set_capability( "interface", 0 );
set_callbacks( E_(OpenIntf), E_(CloseIntf) );
vlc_module_end();
/*****************************************************************************
* dvd.h: structure of the dvdplay plugin
*****************************************************************************
* Copyright (C) 1999-2001 VideoLAN
* $Id: dvd.h,v 1.2 2002/11/06 18:07:57 sam Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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 <dvdread/dvd_reader.h>
#include <dvdread/ifo_types.h>
#include <dvdread/ifo_read.h>
#include <dvdread/nav_read.h>
#include <dvdread/nav_print.h>
#include <dvdplay/dvdplay.h>
#include <dvdplay/info.h>
#include <dvdplay/nav.h>
#include <dvdplay/state.h>
#define LB2OFF(x) ((off_t)(x) * (off_t)(DVD_VIDEO_LB_LEN))
#define OFF2LB(x) ((x) / DVD_VIDEO_LB_LEN)
/*****************************************************************************
* dvd_data_t: structure for communication between dvdplay access, demux
* and intf.
*****************************************************************************/
typedef struct
{
dvdplay_ptr vmg;
intf_thread_t * p_intf;
int i_audio_nb;
int i_spu_nb;
int i_still_time;
vlc_bool_t b_end_of_cell;
dvdplay_event_t event;
dvdplay_ctrl_t control;
dvdplay_highlight_t hli;
} dvd_data_t;
/*****************************************************************************
* es.c: functions to handle elementary streams.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: es.c,v 1.7 2003/10/25 00:49:13 sam Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#ifdef STRNCASECMP_IN_STRINGS_H
# include <strings.h>
#endif
#include "dvd.h"
#include "iso_lang.h"
void dvdplay_LaunchDecoders( input_thread_t * p_input );
/*****************************************************************************
* dvdplay_DeleteES:
*****************************************************************************/
void dvdplay_DeleteES( input_thread_t* p_input )
{
free( p_input->stream.pp_selected_es );
p_input->stream.pp_selected_es = NULL;
p_input->stream.i_selected_es_number = 0;
while( p_input->stream.i_es_number )
{
input_DelES( p_input, p_input->stream.pp_es[0] );
}
free( p_input->stream.pp_es );
p_input->stream.pp_es = NULL;
p_input->stream.i_es_number = 0;
}
#define ADDES( id, fourcc, cat, lang, descr, size ) \
msg_Dbg( p_input, "new es 0x%x", i_id ); \
{ \
char *psz_descr; \
psz_descr = malloc( strlen(DecodeLanguage( lang )) + \
strlen(descr) + 1 ); \
if( psz_descr ) {strcpy( psz_descr, DecodeLanguage( lang ) ); \
strcat( psz_descr, descr );} \
p_es = input_AddES( p_input, NULL, id, cat, \
psz_descr, size ); \
if( psz_descr ) free( psz_descr ); \
} \
p_es->i_stream_id = i_id & 0xff; \
p_es->i_fourcc = (fourcc);
/*****************************************************************************
* dvdplay_Video: read video ES
*****************************************************************************/
void dvdplay_Video( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
es_descriptor_t * p_es;
video_attr_t * p_attr;
int i_id;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
p_attr = dvdplay_video_attr( p_dvd->vmg );
/* ES 0 -> video MPEG2 */
i_id = 0xe0;
if( p_attr->display_aspect_ratio )
{
ADDES( 0xe0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0,
"", sizeof(int) );
*(int*)(p_es->p_demux_data) = p_attr->display_aspect_ratio;
}
else
{
ADDES( 0xe0, VLC_FOURCC('m','p','g','v'), VIDEO_ES, 0, "", 0 );
}
}
/*****************************************************************************
* dvdplay_Audio: read audio ES
*****************************************************************************/
void dvdplay_Audio( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
es_descriptor_t * p_es;
audio_attr_t * p_attr;
int i_audio_nr = -1;
int i_audio = -1;
int i_channels;
int i_lang;
int i_id;
int i;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
p_dvd->i_audio_nb = 0;
dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_audio );
/* Audio ES, in the order they appear in .ifo */
for( i = 1 ; i <= i_audio_nr ; i++ )
{
if( ( i_id = dvdplay_audio_id( p_dvd->vmg, i-1 ) ) > 0 )
{
p_attr = dvdplay_audio_attr( p_dvd->vmg, i-1 );
i_channels = p_attr->channels;
i_lang = p_attr->lang_code;
++p_dvd->i_audio_nb;
switch( p_attr->audio_format )
{
case 0x00: /* A52 */
ADDES( i_id, VLC_FOURCC('a','5','2','b'), AUDIO_ES, i_lang,
" (A52)", 0 );
break;
case 0x02:
case 0x03: /* MPEG audio */
ADDES( i_id, VLC_FOURCC('m','p','g','a'), AUDIO_ES, i_lang,
" (mpeg)", 0 );
break;
case 0x04: /* LPCM */
ADDES( i_id, VLC_FOURCC('l','p','c','b'), AUDIO_ES, i_lang,
" (lpcm)", 0 );
break;
case 0x05: /* SDDS */
ADDES( i_id, VLC_FOURCC('s','d','d','b'), AUDIO_ES, i_lang,
" (sdds)", 0 );
break;
case 0x06: /* DTS */
ADDES( i_id, VLC_FOURCC('d','t','s','b'), AUDIO_ES, i_lang,
" (dts)", 0 );
break;
default:
i_id = 0;
msg_Warn( p_input, "unknown audio type %.2x",
p_attr->audio_format );
}
}
}
}
/*****************************************************************************
* dvdplay_Subp: read subpictures ES
*****************************************************************************/
void dvdplay_Subp( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
es_descriptor_t * p_es;
subp_attr_t * p_attr;
uint32_t * pi_palette;
int i_subp_nr = -1;
int i_subp = -1;
int i_id;
int i;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
p_dvd->i_spu_nb = 0;
dvdplay_subp_info( p_dvd->vmg, &i_subp_nr, &i_subp );
pi_palette = dvdplay_subp_palette( p_dvd->vmg );
for( i = 1 ; i <= i_subp_nr; i++ )
{
if( ( i_id = dvdplay_subp_id( p_dvd->vmg, i-1 ) ) >= 0 )
{
p_attr = dvdplay_subp_attr( p_dvd->vmg, i-1 );
++p_dvd->i_spu_nb;
if( pi_palette )
{
ADDES( i_id, VLC_FOURCC('s','p','u','b'), SPU_ES,
p_attr->lang_code, "", sizeof(int) + 16*sizeof(uint32_t) );
*(int*)p_es->p_demux_data = 0xBeeF;
memcpy( (void*)p_es->p_demux_data + sizeof(int),
pi_palette, 16*sizeof(uint32_t) );
}
else
{
ADDES( i_id, VLC_FOURCC('s','p','u','b'), SPU_ES,
p_attr->lang_code, "", 0 );
}
}
}
}
/*****************************************************************************
* dvdplay_LaunchDecoders
*****************************************************************************/
void dvdplay_LaunchDecoders( input_thread_t * p_input )
{
dvd_data_t * p_dvd;
int i_audio_nr = -1;
int i_audio = -1;
int i_subp_nr = -1;
int i_subp = -1;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
/* For audio: check user settings first, then check dvdplay settings. */
i_audio = config_GetInt( p_input, "audio-channel" );
if( i_audio <= 0 || i_audio > p_dvd->i_audio_nb )
{
/* if i_audio = -1 dvdplay_audio_info() will select a default channel,
* otherwise it warns libdvdplay that we have chosen another stream. */
i_audio = -1;
}
dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_audio );
/* For spu: check user settings first, the check dvdplay settings. */
i_subp = config_GetInt( p_input, "spu-channel" );
if( i_subp <= 0 || i_subp > p_dvd->i_spu_nb )
{
i_subp = -1;
}
dvdplay_subp_info( p_dvd->vmg, &i_subp_nr, &i_subp );
input_SelectES( p_input, p_input->stream.pp_es[0] );
if( i_audio > p_dvd->i_audio_nb ) i_audio = 1;
if( ( i_audio > 0 ) && ( p_dvd->i_audio_nb > 0 ) )
{
if( config_GetInt( p_input, "audio-type" ) == REQUESTED_A52 )
{
int i_a52 = i_audio;
while( ( i_a52 < p_dvd->i_audio_nb ) &&
( p_input->stream.pp_es[i_a52]->i_fourcc !=
VLC_FOURCC('a','5','2','b') ) )
{
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] );
/* warn libdvdplay that we have chosen another stream */
dvdplay_audio_info( p_dvd->vmg, &i_audio_nr, &i_a52 );
}
else
{
/* none found, select the default one */
input_SelectES( p_input,
p_input->stream.pp_es[i_audio] );
}
}
else
{
input_SelectES( p_input,
p_input->stream.pp_es[i_audio] );
}
}
if( i_subp > p_dvd->i_spu_nb ) i_subp = -1;
if( ( i_subp > 0 ) && ( p_dvd->i_spu_nb > 0 ) )
{
i_subp += p_dvd->i_audio_nb;
input_SelectES( p_input, p_input->stream.pp_es[i_subp] );
}
}
/*****************************************************************************
* dvdplay_ES:
*****************************************************************************/
void dvdplay_ES( input_thread_t * p_input )
{
dvdplay_DeleteES ( p_input );
dvdplay_Video ( p_input );
dvdplay_Audio ( p_input );
dvdplay_Subp ( p_input );
dvdplay_LaunchDecoders( p_input );
}
/*****************************************************************************
* es.h: functions to handle elementary streams.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: es.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* 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.
*****************************************************************************/
void dvdplay_DeleteES( struct input_thread_t * );
void dvdplay_Video( struct input_thread_t * );
void dvdplay_Audio( struct input_thread_t * );
void dvdplay_Subp( struct input_thread_t * );
void dvdplay_ES( struct input_thread_t * );
void dvdplay_LaunchDecoders( struct input_thread_t * );
/*****************************************************************************
* intf.c: interface for DVD video manager
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id$
*
* Authors: Stphane Borel <stef@via.ecp.fr>
*
* 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 <stdlib.h> /* malloc(), free() */
#include <string.h>
#include <unistd.h>
#include <vlc/vlc.h>
#include <vlc/intf.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "vlc_keys.h"
#include "dvd.h"
/*****************************************************************************
* intf_sys_t: description and status of interface
*****************************************************************************/
struct intf_sys_t
{
input_thread_t * p_input;
dvd_data_t * p_dvd;
vlc_bool_t b_still;
vlc_bool_t b_inf_still;
mtime_t m_still_time;
dvdplay_ctrl_t control;
vlc_bool_t b_click, b_move, b_key_pressed;
};
/*****************************************************************************
* Local prototypes.
*****************************************************************************/
static int InitThread ( intf_thread_t *p_intf );
static int MouseEvent ( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
static int KeyEvent ( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * );
/* Exported functions */
static void RunIntf ( intf_thread_t *p_intf );
/*****************************************************************************
* OpenIntf: initialize dummy interface
*****************************************************************************/
int E_(OpenIntf) ( vlc_object_t *p_this )
{
intf_thread_t *p_intf = (intf_thread_t *)p_this;
/* Allocate instance and initialize some members */
p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
if( p_intf->p_sys == NULL )
{
return( 1 );
};
p_intf->pf_run = RunIntf;
var_AddCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf );
p_intf->p_sys->m_still_time = 0;
p_intf->p_sys->b_inf_still = 0;
p_intf->p_sys->b_still = 0;
return( 0 );
}
/*****************************************************************************
* CloseIntf: destroy dummy interface
*****************************************************************************/
void E_(CloseIntf) ( vlc_object_t *p_this )
{
intf_thread_t *p_intf = (intf_thread_t *)p_this;
var_DelCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf );
/* Destroy structure */
free( p_intf->p_sys );
}
/*****************************************************************************
* RunIntf: main loop
*****************************************************************************/
static void RunIntf( intf_thread_t *p_intf )
{
vlc_object_t * p_vout = NULL;
mtime_t mtime = 0;
mtime_t mlast = 0;
if( InitThread( p_intf ) < 0 )
{
msg_Err( p_intf, "can't initialize intf" );
return;
}
msg_Dbg( p_intf, "intf initialized" );
/* Main loop */
while( !p_intf->b_die )
{
vlc_mutex_lock( &p_intf->change_lock );
/*
* still images
*/
#if 1
if( p_intf->p_sys->b_still && !p_intf->p_sys->b_inf_still )
{
if( p_intf->p_sys->m_still_time > 0 )
{
/* update remaining still time */
mtime = mdate();
if( mlast )
{
p_intf->p_sys->m_still_time -= mtime - mlast;
}
mlast = mtime;
}
else
{
/* still time elasped */
var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S );
p_intf->p_sys->m_still_time = 0;
p_intf->p_sys->b_still = 0;
mlast = 0;
}
}
#else
if( p_intf->p_sys->m_still_time != (mtime_t)(-1) )
{
if( p_intf->p_sys->m_still_time )
{
mtime = mdate();
if( mlast )
{
p_intf->p_sys->m_still_time -= mtime - mlast;
}
if( !p_intf->p_sys->m_still_time )
{
var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S );
}
mlast = mtime;
}
}
#endif
/*
* mouse cursor
*/
if( p_vout && ( p_intf->p_sys->b_click || p_intf->p_sys->b_move ) )
{
vlc_value_t val;
int i_activate;
var_Get( p_vout, "mouse-x", &val );
p_intf->p_sys->control.mouse.i_x = val.i_int;
var_Get( p_vout, "mouse-y", &val );
p_intf->p_sys->control.mouse.i_y = val.i_int;
if( p_intf->p_sys->b_click )
{
p_intf->p_sys->control.type = DVDCtrlMouseActivate;
p_intf->p_sys->b_click = VLC_FALSE;
}
else
{
p_intf->p_sys->control.type = DVDCtrlMouseSelect;
p_intf->p_sys->b_move = VLC_FALSE;
}
/* we can safely interact with libdvdplay
* with the stream lock */
vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
i_activate = dvdplay_button( p_intf->p_sys->p_dvd->vmg,
&p_intf->p_sys->control );
vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
if( i_activate && p_intf->p_sys->b_still )
{
var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S );
p_intf->p_sys->b_still = 0;
p_intf->p_sys->b_inf_still = 0;
p_intf->p_sys->m_still_time = 0;
}
}
/*
* keyboard event
*/
if( p_intf->p_sys->b_key_pressed )
{
vlc_value_t val;
int i, i_activate, i_action = -1;
struct hotkey *p_hotkeys = p_intf->p_vlc->p_hotkeys;
p_intf->p_sys->b_key_pressed = VLC_FALSE;
/* Find action triggered by hotkey (if any) */
var_Get( p_intf->p_vlc, "key-pressed", &val );
for( i = 0; p_hotkeys[i].psz_action != NULL; i++ )
{
if( p_hotkeys[i].i_key == val.i_int )
{
i_action = p_hotkeys[i].i_action;
}
}
if( i_action )
{
if( i_action == ACTIONID_NAV_LEFT )
{
p_intf->p_sys->control.type = DVDCtrlLeftButtonSelect;
}
else if( i_action == ACTIONID_NAV_RIGHT )
{
p_intf->p_sys->control.type = DVDCtrlRightButtonSelect;
}
else if( i_action == ACTIONID_NAV_UP )
{
p_intf->p_sys->control.type = DVDCtrlUpperButtonSelect;
}
else if( i_action == ACTIONID_NAV_DOWN )
{
p_intf->p_sys->control.type = DVDCtrlLowerButtonSelect;
}
else if( i_action == ACTIONID_NAV_ACTIVATE )
{
p_intf->p_sys->control.type = DVDCtrlButtonActivate;
}
/* we can safely interact with libdvdplay
* with the stream lock */
vlc_mutex_lock( &p_intf->p_sys->p_input->stream.stream_lock );
i_activate = dvdplay_button( p_intf->p_sys->p_dvd->vmg,
&p_intf->p_sys->control );
vlc_mutex_unlock( &p_intf->p_sys->p_input->stream.stream_lock );
if( i_activate && p_intf->p_sys->b_still )
{
var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S );
p_intf->p_sys->b_still = 0;
p_intf->p_sys->b_inf_still = 0;
p_intf->p_sys->m_still_time = 0;
}
}
}
vlc_mutex_unlock( &p_intf->change_lock );
/*
* video output
*/
if( p_vout && p_vout->b_die )
{
var_DelCallback( p_vout, "mouse-moved", MouseEvent, p_intf );
var_DelCallback( p_vout, "mouse-clicked", MouseEvent, p_intf );
vlc_object_release( p_vout );
p_vout = NULL;
}
if( p_vout == NULL )
{
p_vout = vlc_object_find( p_intf->p_sys->p_input,
VLC_OBJECT_VOUT, FIND_CHILD );
if( p_vout )
{
var_AddCallback( p_vout, "mouse-moved", MouseEvent, p_intf );
var_AddCallback( p_vout, "mouse-clicked", MouseEvent, p_intf );
}
}
/* Wait a bit */
msleep( INTF_IDLE_SLEEP );
}
if( p_vout )
{
var_DelCallback( p_vout, "mouse-moved", MouseEvent, p_intf );
var_DelCallback( p_vout, "mouse-clicked", MouseEvent, p_intf );
vlc_object_release( p_vout );
}
vlc_object_release( p_intf->p_sys->p_input );
}
/*****************************************************************************
* InitThread:
*****************************************************************************/
static int InitThread( intf_thread_t * p_intf )
{
/* We might need some locking here */
if( !p_intf->b_die )
{
input_thread_t * p_input;
dvd_data_t * p_dvd;
p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_PARENT );
/* Maybe the input just died */
if( p_input == NULL )
{
return VLC_EGENERIC;
}
p_dvd = (dvd_data_t*)p_input->p_access_data;
p_dvd->p_intf = p_intf;
vlc_mutex_lock( &p_intf->change_lock );
p_intf->p_sys->p_input = p_input;
p_intf->p_sys->p_dvd = p_dvd;
p_intf->p_sys->b_move = VLC_FALSE;
p_intf->p_sys->b_click = VLC_FALSE;
p_intf->p_sys->b_key_pressed = VLC_FALSE;
vlc_mutex_unlock( &p_intf->change_lock );
return VLC_SUCCESS;
}
else
{
return VLC_EGENERIC;
}
}
/*****************************************************************************
* MouseEvent: callback for mouse events
*****************************************************************************/
static int MouseEvent( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
intf_thread_t *p_intf = (intf_thread_t *)p_data;
vlc_mutex_lock( &p_intf->change_lock );
if( psz_var[6] == 'c' ) /* "mouse-clicked" */
{
p_intf->p_sys->b_click = VLC_TRUE;
}
else if( psz_var[6] == 'm' ) /* "mouse-moved" */
{
p_intf->p_sys->b_move = VLC_TRUE;
}
vlc_mutex_unlock( &p_intf->change_lock );
return VLC_SUCCESS;
}
/*****************************************************************************
* KeyEvent: callback for keyboard events
*****************************************************************************/
static int KeyEvent( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
intf_thread_t *p_intf = (intf_thread_t *)p_data;
vlc_mutex_lock( &p_intf->change_lock );
p_intf->p_sys->b_key_pressed = VLC_TRUE;
vlc_mutex_unlock( &p_intf->change_lock );
return VLC_SUCCESS;
}
/*****************************************************************************
* dvdIntfStillTime: function provided to demux plugin to request
* still images
*****************************************************************************/
int dvdIntfStillTime( intf_thread_t *p_intf, int i_sec )
{
vlc_mutex_lock( &p_intf->change_lock );
#if 1
if( i_sec == 0xff )
{
p_intf->p_sys->b_still = 1;
p_intf->p_sys->b_inf_still = 1;
}
else if( i_sec > 0 )
{
p_intf->p_sys->b_still = 1;
p_intf->p_sys->m_still_time = 1000000 * i_sec;
}
#else
if( i_sec > 0 )
{
if( i_sec == 0xff )
{
p_intf->p_sys->m_still_time = (mtime_t)(-1);
msg_Warn( p_intf, I64Fd, p_intf->p_sys->m_still_time );
}
else
{
p_intf->p_sys->m_still_time = 1000000 * i_sec;
}
}
#endif
vlc_mutex_unlock( &p_intf->change_lock );
return VLC_SUCCESS;
}
/*****************************************************************************
* dvdIntfStillTime: function provided to reset still image
*****************************************************************************/
int dvdIntfResetStillTime( intf_thread_t *p_intf )
{
vlc_mutex_lock( &p_intf->change_lock );
p_intf->p_sys->m_still_time = 0;
var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S );
vlc_mutex_unlock( &p_intf->change_lock );
return VLC_SUCCESS;
}
/*****************************************************************************
* intf.h: send info to intf.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: intf.h,v 1.2 2003/08/13 01:45:13 gbazin Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* 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.
*****************************************************************************/
int dvdIntfStillTime( struct intf_thread_t *, int );
int dvdIntfResetStillTime( intf_thread_t *p_intf );
/*****************************************************************************
* tools.c: tools for dvd plugin.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id$
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
* 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 <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <errno.h>
#include <vlc/vlc.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "input_ext-plugins.h"
#include "dvd.h"
/*****************************************************************************
* dvdplay_ParseCL: parse command line
*****************************************************************************/
char * dvdplay_ParseCL( input_thread_t * p_input,
int * i_title, int * i_chapter, int * i_angle )
{
dvd_data_t * p_dvd;
struct stat stat_info;
char * psz_parser;
char * psz_source;
char * psz_next;
p_dvd = (dvd_data_t*)(p_input->p_access_data);
psz_source = strdup( p_input->psz_name );
if( psz_source == NULL )
{
return NULL;
}
*i_title = 0;
*i_chapter = 1;
*i_angle = 1;
/* Start with the end, because you could have :
* dvdplay:/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 : 1;
*i_angle = *i_angle ? *i_angle : 1;
if( !*psz_source )
{
free( psz_source );
if( !p_input->psz_access )
{
return NULL;
}
psz_source = config_GetPsz( p_input, "dvd" );
if( !psz_source ) return NULL;
}
#ifdef WIN32
if( psz_source[0] && psz_source[1] == ':' && psz_source[2] == '\0' )
{
/* Don't try to stat the file */
}
else if( psz_source[0] && psz_source[1] == ':' &&
psz_source[2] == '\\' && psz_source[3] == '\0' )
{
/* Don't try to stat the file */
psz_source[2] = '\0';
}
else
#endif
{
if( stat( psz_source, &stat_info ) == -1 )
{
msg_Warn( p_input, "cannot stat() source `%s' (%s)",
psz_source, strerror(errno) );
free( psz_source );
return NULL;
}
if( !S_ISBLK(stat_info.st_mode) &&
!S_ISCHR(stat_info.st_mode) &&
!S_ISDIR(stat_info.st_mode) )
{
msg_Dbg( p_input, "plugin discarded (not a valid source)" );
free( psz_source );
return NULL;
}
}
msg_Dbg( p_input, "dvdroot=%s title=%d chapter=%d angle=%d",
psz_source, *i_title, *i_chapter, *i_angle );
return psz_source;
}
/*****************************************************************************
* tools.h: tools for dvdplay plugin.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: tools.h,v 1.1 2002/08/04 17:23:42 sam Exp $
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
* 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.
*****************************************************************************/
char * dvdplay_ParseCL( struct input_thread_t *, int*, int*, int* );
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment