Commit 9b393dab authored by Stéphane Borel's avatar Stéphane Borel

*dvd and dvdread support for input III.

Dvdread is known to segfault at title change. I'm working on this.
parent d0bf23fa
......@@ -6387,7 +6387,7 @@ if test "${with_dvdcss+set}" = set; then
case "x${withval}" in
xlocal-static|xyes)
# local libdvdcss, statically linked
#BUILTINS="${BUILTINS} dvd"
BUILTINS="${BUILTINS} dvd"
if test x${CAN_BUILD_LIBDVDCSS} = x1
then
NEED_LIBDVDCSS=1
......@@ -6398,7 +6398,7 @@ if test "${with_dvdcss+set}" = set; then
;;
xlocal-shared)
# local libdvdcss, dynamically linked
#PLUGINS="${PLUGINS} dvd"
PLUGINS="${PLUGINS} dvd"
if test x${CAN_BUILD_LIBDVDCSS} = x1
then
NEED_LIBDVDCSS=1
......@@ -6408,7 +6408,7 @@ if test "${with_dvdcss+set}" = set; then
;;
xno)
# don't use libdvdcss at all, build a DVD module that can dlopen() it
#BUILTINS="${BUILTINS} dvd"
BUILTINS="${BUILTINS} dvd"
DUMMY_LIBDVDCSS=1
SRC_DVD_EXTRA="${SRC_DVD_EXTRA} dummy_dvdcss.c"
CFLAGS_DVD="${CFLAGS_DVD} -DGOD_DAMN_DMCA"
......@@ -6417,7 +6417,7 @@ if test "${with_dvdcss+set}" = set; then
;;
*)
# existing libdvdcss
#PLUGINS="${PLUGINS} dvd"
PLUGINS="${PLUGINS} dvd"
if test "x$withval" != "xyes"
then
LIB_DVD="${LIB_DVD} -L"$withval"/lib"
......@@ -6430,14 +6430,14 @@ else
# if libdvdcss is in the archive, or to use the dummy replacement otherwise.
if test x${CAN_BUILD_LIBDVDCSS} = x1
then
#BUILTINS="${BUILTINS} dvd"
BUILTINS="${BUILTINS} dvd"
NEED_LIBDVDCSS=1
STATIC_LIBDVDCSS=1
CFLAGS_DVD="${CFLAGS_DVD} -I../../extras/libdvdcss"
LIB_DVD="${LIB_DVD} lib/libdvdcss.a ${LIB_LIBDVDCSS}"
else
# XXX: no check for libdl is done, don't try this at home !
#BUILTINS="${BUILTINS} dvd"
BUILTINS="${BUILTINS} dvd"
DUMMY_LIBDVDCSS=1
SRC_DVD_EXTRA="${SRC_DVD_EXTRA} dummy_dvdcss.c"
CFLAGS_DVD="${CFLAGS_DVD} -DGOD_DAMN_DMCA"
......
......@@ -788,7 +788,7 @@ AC_ARG_WITH(dvdcss,
[ case "x${withval}" in
xlocal-static|xyes)
# local libdvdcss, statically linked
#BUILTINS="${BUILTINS} dvd"
BUILTINS="${BUILTINS} dvd"
if test x${CAN_BUILD_LIBDVDCSS} = x1
then
NEED_LIBDVDCSS=1
......@@ -799,7 +799,7 @@ AC_ARG_WITH(dvdcss,
;;
xlocal-shared)
# local libdvdcss, dynamically linked
#PLUGINS="${PLUGINS} dvd"
PLUGINS="${PLUGINS} dvd"
if test x${CAN_BUILD_LIBDVDCSS} = x1
then
NEED_LIBDVDCSS=1
......@@ -809,7 +809,7 @@ AC_ARG_WITH(dvdcss,
;;
xno)
# don't use libdvdcss at all, build a DVD module that can dlopen() it
#BUILTINS="${BUILTINS} dvd"
BUILTINS="${BUILTINS} dvd"
DUMMY_LIBDVDCSS=1
SRC_DVD_EXTRA="${SRC_DVD_EXTRA} dummy_dvdcss.c"
CFLAGS_DVD="${CFLAGS_DVD} -DGOD_DAMN_DMCA"
......@@ -818,7 +818,7 @@ AC_ARG_WITH(dvdcss,
;;
*)
# existing libdvdcss
#PLUGINS="${PLUGINS} dvd"
PLUGINS="${PLUGINS} dvd"
if test "x$withval" != "xyes"
then
LIB_DVD="${LIB_DVD} -L"$withval"/lib"
......@@ -830,14 +830,14 @@ AC_ARG_WITH(dvdcss,
# if libdvdcss is in the archive, or to use the dummy replacement otherwise.
[ if test x${CAN_BUILD_LIBDVDCSS} = x1
then
#BUILTINS="${BUILTINS} dvd"
BUILTINS="${BUILTINS} dvd"
NEED_LIBDVDCSS=1
STATIC_LIBDVDCSS=1
CFLAGS_DVD="${CFLAGS_DVD} -I../../extras/libdvdcss"
LIB_DVD="${LIB_DVD} lib/libdvdcss.a ${LIB_LIBDVDCSS}"
else
# XXX: no check for libdl is done, don't try this at home !
#BUILTINS="${BUILTINS} dvd"
BUILTINS="${BUILTINS} dvd"
DUMMY_LIBDVDCSS=1
SRC_DVD_EXTRA="${SRC_DVD_EXTRA} dummy_dvdcss.c"
CFLAGS_DVD="${CFLAGS_DVD} -DGOD_DAMN_DMCA"
......
......@@ -2,7 +2,7 @@
* dvd.c : DVD input module for vlc
*****************************************************************************
* Copyright (C) 2000-2001 VideoLAN
* $Id: dvd.c,v 1.21 2002/03/01 00:33:18 massiot Exp $
* $Id: dvd.c,v 1.22 2002/03/01 01:12:28 stef Exp $
*
* Authors: Samuel Hocevar <sam@zoy.org>
*
......@@ -37,8 +37,8 @@
/*****************************************************************************
* Capabilities defined in the other files.
*****************************************************************************/
void _M( access_getfunctions )( function_list_t * p_function_list );
void _M( demux_getfunctions )( function_list_t * p_function_list );
void _M( access_getfunctions)( function_list_t * p_function_list );
void _M( demux_getfunctions)( function_list_t * p_function_list );
/*****************************************************************************
* Local prototypes.
......@@ -58,17 +58,19 @@ MODULE_CONFIG_STOP
MODULE_INIT_START
#ifdef GOD_DAMN_DMCA
SET_DESCRIPTION( "DVD input module, uses libdvdcss if present" )
ADD_CAPABILITY( DEMUX, 190 )
ADD_CAPABILITY( ACCESS, 90 )
#else
SET_DESCRIPTION( "DVD input module, linked with libdvdcss" )
ADD_CAPABILITY( DEMUX, 200 )
ADD_CAPABILITY( ACCESS, 100 )
#endif
ADD_CAPABILITY( ACCESS, 0 )
ADD_CAPABILITY( DEMUX, 0 )
ADD_SHORTCUT( "dvd" )
MODULE_INIT_STOP
MODULE_ACTIVATE_START
_M( access_getfunctions )( &p_module->p_functions->access );
_M( demux_getfunctions )( &p_module->p_functions->demux );
_M( access_getfunctions)( &p_module->p_functions->access );
_M( demux_getfunctions)( &p_module->p_functions->demux );
#ifdef GOD_DAMN_DMCA
ProbeLibDVDCSS();
#endif
......
......@@ -9,7 +9,7 @@
* -dvd_udf to find files
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: input_dvd.c,v 1.122 2002/02/27 03:47:56 sam Exp $
* $Id: input_dvd.c,v 1.123 2002/03/01 01:12:28 stef Exp $
*
* Author: Stphane Borel <stef@via.ecp.fr>
*
......@@ -78,23 +78,25 @@
#include "debug.h"
/* how many blocks DVDRead will read in each loop */
#define DVD_BLOCK_READ_ONCE 64
/* how many packets DVDDemux will read in each loop */
#define DVD_READ_ONCE 64
/*****************************************************************************
* Local prototypes
*****************************************************************************/
/* called from outside */
static int DVDProbe ( struct input_thread_s * );
static void DVDInit ( struct input_thread_s * );
static void DVDEnd ( struct input_thread_s * );
static void DVDOpen ( struct input_thread_s * );
static int DVDOpen ( struct input_thread_s * );
static void DVDClose ( struct input_thread_s * );
static int DVDSetArea ( struct input_thread_s *, struct input_area_s * );
static int DVDSetProgram ( struct input_thread_s *, pgrm_descriptor_t * );
static int DVDRead ( struct input_thread_s *, data_packet_t ** );
static int DVDRead ( struct input_thread_s *, byte_t *, size_t );
static void DVDSeek ( struct input_thread_s *, off_t );
static int DVDRewind ( struct input_thread_s * );
static int DVDDemux ( struct input_thread_s * );
static int DVDInit ( struct input_thread_s * );
static void DVDEnd ( struct input_thread_s * );
/* called only inside */
static int DVDChooseAngle( thread_dvd_data_t * );
......@@ -102,115 +104,300 @@ static int DVDFindCell( thread_dvd_data_t * );
static int DVDFindSector( thread_dvd_data_t * );
static int DVDChapterSelect( thread_dvd_data_t *, int );
/*****************************************************************************
* Declare a buffer manager
*****************************************************************************/
#define FLAGS BUFFERS_UNIQUE_SIZE
#define NB_LIFO 1
DECLARE_BUFFERS_SHARED( FLAGS, NB_LIFO );
DECLARE_BUFFERS_INIT( FLAGS, NB_LIFO );
DECLARE_BUFFERS_END_SHARED( FLAGS, NB_LIFO );
DECLARE_BUFFERS_NEWPACKET_SHARED( FLAGS, NB_LIFO );
DECLARE_BUFFERS_DELETEPACKET_SHARED( FLAGS, NB_LIFO, 1000 );
DECLARE_BUFFERS_NEWPES( FLAGS, NB_LIFO );
DECLARE_BUFFERS_DELETEPES( FLAGS, NB_LIFO, 1000 );
DECLARE_BUFFERS_TOIO( FLAGS, DVD_LB_SIZE );
DECLARE_BUFFERS_SHAREBUFFER( FLAGS );
/*****************************************************************************
* Functions exported as capabilities. They are declared as static so that
* we don't pollute the namespace too much.
*****************************************************************************/
void _M( input_getfunctions )( function_list_t * p_function_list )
void _M( access_getfunctions)( function_list_t * p_function_list )
{
#define input p_function_list->functions.input
input.pf_probe = DVDProbe;
input.pf_init = DVDInit;
#define input p_function_list->functions.access
input.pf_open = DVDOpen;
input.pf_close = DVDClose;
input.pf_end = DVDEnd;
input.pf_init_bit_stream = InitBitstream;
input.pf_read = DVDRead;
input.pf_set_area = DVDSetArea;
input.pf_set_program = DVDSetProgram;
input.pf_demux = input_DemuxPS;
input.pf_new_packet = input_NewPacket;
input.pf_new_pes = input_NewPES;
input.pf_delete_packet = input_DeletePacket;
input.pf_delete_pes = input_DeletePES;
input.pf_rewind = DVDRewind;
input.pf_seek = DVDSeek;
#undef input
}
void _M( demux_getfunctions)( function_list_t * p_function_list )
{
#define demux p_function_list->functions.demux
demux.pf_init = DVDInit;
demux.pf_end = DVDEnd;
demux.pf_demux = DVDDemux;
demux.pf_rewind = DVDRewind;
#undef demux
}
/*
* Data reading functions
* Data demux functions
*/
/*****************************************************************************
* DVDProbe: verifies that the stream is a PS stream
* DVDInit: initializes DVD structures
*****************************************************************************/
static int DVDProbe( input_thread_t * p_input )
static int DVDInit( input_thread_t * p_input )
{
char * psz_name = p_input->p_source;
thread_dvd_data_t * p_dvd;
int i_audio;
int i_spu;
if( strncmp( p_input->p_access_module->psz_name, "dvd", 3 ) )
{
return -1;
}
p_dvd = (thread_dvd_data_t*)(p_input->p_access_data);
/* Select Video stream (always 0) */
if( p_main->b_video )
{
input_SelectES( p_input, p_input->stream.pp_es[0] );
}
if( ( strlen(psz_name) > 4 ) && !strncasecmp( psz_name, "dvd:", 4 ) )
/* Select audio stream */
if( p_main->b_audio )
{
/* If the user specified "dvd:" then it's probably a DVD */
return 0;
/* For audio: first one if none or a not existing one specified */
i_audio = config_GetIntVariable( INPUT_CHANNEL_VAR );
if( i_audio < 0 /*|| i_audio > i_audio_nb*/ )
{
config_PutIntVariable( INPUT_CHANNEL_VAR, 1 );
i_audio = 1;
}
if( i_audio > 0 /*&& i_audio_nb > 0*/ )
{
if( config_GetIntVariable( AOUT_SPDIF_VAR ) ||
( config_GetIntVariable( INPUT_AUDIO_VAR ) ==
REQUESTED_AC3 ) )
{
int i_ac3 = i_audio;
while( ( p_input->stream.pp_es[i_ac3]->i_type !=
AC3_AUDIO_ES ) && ( i_ac3 <=
p_dvd->p_ifo->vts.manager_inf.i_audio_nb ) )
{
i_ac3++;
}
if( p_input->stream.pp_es[i_ac3]->i_type == AC3_AUDIO_ES )
{
input_SelectES( p_input,
p_input->stream.pp_es[i_ac3] );
}
}
else
{
input_SelectES( p_input,
p_input->stream.pp_es[i_audio] );
}
}
}
return -1;
/* Select subtitle */
if( p_main->b_video )
{
/* for spu, default is none */
i_spu = config_GetIntVariable( INPUT_SUBTITLE_VAR );
if( i_spu < 0 /*|| i_spu > i_spu_nb*/ )
{
config_PutIntVariable( INPUT_SUBTITLE_VAR, 0 );
i_spu = 0;
}
if( i_spu > 0 /* && i_spu_nb > 0*/ )
{
i_spu += p_dvd->p_ifo->vts.manager_inf.i_audio_nb;
input_SelectES( p_input, p_input->stream.pp_es[i_spu] );
}
}
return 0;
}
/*****************************************************************************
* DVDInit: initializes DVD structures
* DVDEnd: frees unused data
*****************************************************************************/
static void DVDEnd( input_thread_t * p_input )
{
}
/*****************************************************************************
* DVDDemux
*****************************************************************************/
static void DVDInit( input_thread_t * p_input )
#define PEEK( SIZE ) \
i_result = input_Peek( p_input, &p_peek, SIZE ); \
if( i_result == -1 ) \
{ \
return( -1 ); \
} \
else if( i_result < SIZE ) \
{ \
/* EOF */ \
return( 0 ); \
}
static int DVDDemux( input_thread_t * p_input )
{
int i;
byte_t * p_peek;
data_packet_t * p_data;
ssize_t i_result;
int i_packet_size;
/* Read headers to compute payload length */
for( i = 0 ; i < DVD_READ_ONCE ; i++ )
{
/* Read what we believe to be a packet header. */
PEEK( 4 );
/* Default header */
if( U32_AT( p_peek ) != 0x1BA )
{
/* That's the case for all packets, except pack header. */
i_packet_size = U16_AT( p_peek + 4 );
}
else
{
/* MPEG-2 Pack header. */
i_packet_size = 8;
}
/* Fetch a packet of the appropriate size. */
i_result = input_SplitBuffer( p_input, &p_data, i_packet_size + 6 );
if( i_result <= 0 )
{
return( i_result );
}
/* In MPEG-2 pack headers we still have to read stuffing bytes. */
if( (p_data->p_demux_start[3] == 0xBA) && (i_packet_size == 8) )
{
size_t i_stuffing = (p_data->p_demux_start[13] & 0x7);
/* Force refill of the input buffer - though we don't care
* about p_peek. Please note that this is unoptimized. */
PEEK( i_stuffing );
p_input->p_current_data += i_stuffing;
}
input_DemuxPS( p_input, p_data );
}
return i;
}
/*****************************************************************************
* DVDRewind : reads a stream backward
*****************************************************************************/
static int DVDRewind( input_thread_t * p_input )
{
return( -1 );
}
/*
* Data access functions
*/
/*****************************************************************************
* DVDOpen: open dvd
*****************************************************************************/
static int DVDOpen( struct input_thread_s *p_input )
{
struct stat stat_info;
char * psz_parser = p_input->psz_name;
char * psz_device = p_input->psz_name;
dvdcss_handle dvdhandle;
thread_dvd_data_t * p_dvd;
input_area_t * p_area;
int i_title;
int i_chapter;
int i;
p_dvd = malloc( sizeof(thread_dvd_data_t) );
if( p_dvd == NULL )
/* Parse input string : device[@rawdevice] */
while( *psz_parser && *psz_parser != '@' )
{
intf_ErrMsg( "dvd error: out of memory" );
p_input->b_error = 1;
return;
psz_parser++;
}
p_input->p_plugin_data = (void *)p_dvd;
if( *psz_parser == '@' )
{
/* Found raw device */
*psz_parser = '\0';
psz_parser++;
config_PutPszVariable( "DVDCSS_RAW_DEVICE", psz_parser );
}
if( (p_input->p_method_data = input_BuffersInit()) == NULL )
if( stat( psz_device, &stat_info ) == -1 )
{
p_input->b_error = 1;
return;
intf_ErrMsg( "input error: cannot stat() device `%s' (%s)",
psz_device, strerror(errno));
return( -1 );
}
if( !S_ISBLK(stat_info.st_mode) && !S_ISCHR(stat_info.st_mode) )
{
intf_WarnMsg( 3, "input : DVD plugin discarded"
" (not a valid block device)" );
return -1;
}
intf_WarnMsg( 2, "input: dvd=%s raw=%s", psz_device, psz_parser );
/*
* set up input
*/
p_input->i_mtu = 0;
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.i_method = INPUT_METHOD_DVD;
/* If we are here we can control the pace... */
p_input->stream.b_pace_control = 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;
vlc_mutex_unlock( &p_input->stream.stream_lock );
/*
* get plugin ready
*/
dvdhandle = dvdcss_open( psz_device );
if( dvdhandle == NULL )
{
intf_ErrMsg( "dvd error: dvdcss can't open device" );
return -1;
}
p_dvd->dvdhandle = (dvdcss_handle) p_input->p_handle;
p_dvd = malloc( sizeof(thread_dvd_data_t) );
if( p_dvd == NULL )
{
intf_ErrMsg( "dvd error: out of memory" );
return -1;
}
p_dvd->dvdhandle = (dvdcss_handle) dvdhandle;
p_input->p_access_data = (void *)p_dvd;
if( dvdcss_seek( p_dvd->dvdhandle, 0, DVDCSS_NOFLAGS ) < 0 )
{
intf_ErrMsg( "dvd error: %s", dvdcss_error( p_dvd->dvdhandle ) );
input_BuffersEnd( p_input->p_method_data );
p_input->b_error = 1;
return;
return -1;
}
/* We read DVD_BLOCK_READ_ONCE in each loop */
p_dvd->i_block_once = DVD_BLOCK_READ_ONCE;
/* Ifo allocation & initialisation */
if( IfoCreate( p_dvd ) < 0 )
{
intf_ErrMsg( "dvd error: allcation error in ifo" );
free( p_dvd );
input_BuffersEnd( p_input->p_method_data );
p_input->b_error = 1;
return;
return -1;
}
if( IfoInit( p_dvd->p_ifo ) < 0 )
......@@ -218,9 +405,7 @@ static void DVDInit( input_thread_t * p_input )
intf_ErrMsg( "dvd error: fatal failure in ifo" );
IfoDestroy( p_dvd->p_ifo );
free( p_dvd );
input_BuffersEnd( p_input->p_method_data );
p_input->b_error = 1;
return;
return -1;
}
/* Set stream and area data */
......@@ -282,98 +467,34 @@ static void DVDInit( input_thread_t * p_input )
p_area->i_part = i_chapter;
/* set title, chapter, audio and subpic */
DVDSetArea( p_input, p_area );
vlc_mutex_unlock( &p_input->stream.stream_lock );
return;
}
/*****************************************************************************
* DVDOpen: open dvd
*****************************************************************************/
static void DVDOpen( struct input_thread_s *p_input )
{
dvdcss_handle dvdhandle;
char * psz_parser;
char * psz_device;
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.i_method = INPUT_METHOD_DVD;
/* If we are here we can control the pace... */
p_input->stream.b_pace_control = 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;
vlc_mutex_unlock( &p_input->stream.stream_lock );
/* Parse input string : dvd:device[@rawdevice] */
if( strlen( p_input->p_source ) > 4
&& !strncasecmp( p_input->p_source, "dvd:", 4 ) )
{
psz_parser = psz_device = p_input->p_source + 4;
}
else
if( DVDSetArea( p_input, p_area ) )
{
psz_parser = psz_device = p_input->p_source;
}
while( *psz_parser && *psz_parser != '@' )
{
psz_parser++;
}
if( *psz_parser == '@' )
{
/* Found raw device */
*psz_parser = '\0';
psz_parser++;
config_PutPszVariable( "DVDCSS_RAW_DEVICE", psz_parser );
vlc_mutex_unlock( &p_input->stream.stream_lock );
return -1;
}
intf_WarnMsg( 2, "input: dvd=%s raw=%s", psz_device, psz_parser );
dvdhandle = dvdcss_open( psz_device );
vlc_mutex_unlock( &p_input->stream.stream_lock );
if( dvdhandle == NULL )
{
intf_ErrMsg( "dvd error: dvdcss can't open device" );
p_input->b_error = 1;
return;
}
return 0;
p_input->p_handle = (void *) dvdhandle;
}
/*****************************************************************************
* DVDClose: close dvd
*****************************************************************************/
static void DVDClose( struct input_thread_s *p_input )
{
/* Clean up libdvdcss */
dvdcss_close( (dvdcss_handle) p_input->p_handle );
}
/*****************************************************************************
* DVDEnd: frees unused data
*****************************************************************************/
static void DVDEnd( input_thread_t * p_input )
{
thread_dvd_data_t * p_dvd;
p_dvd = (thread_dvd_data_t*)p_input->p_plugin_data;
p_dvd = (thread_dvd_data_t*)p_input->p_access_data;
IfoDestroy( p_dvd->p_ifo );
p_input->p_access_data = (void *)(p_dvd->dvdhandle);
free( p_dvd );