* modules/access/cddax.c: Brand new CDDA input module using libcdio. Courtesy of Rocky Bernstein.
* modules/LIST: update.
dnl Autoconf settings for vlc
-dnl $Id: configure.ac,v 1.83 2003/10/04 11:59:59 gbazin Exp $
+dnl $Id: configure.ac,v 1.84 2003/10/04 18:55:12 gbazin Exp $
AC_INIT(vlc,0.6.3-cvs)
bsdi*)
SYS=bsdi
CFLAGS_save="${CFLAGS_save} -pthread"; CFLAGS="${CFLAGS_save}"
- AX_ADD_LDFLAGS([dvd dvdcss vcd cdda],[-ldvd])
+ AX_ADD_LDFLAGS([dvd dvdcss vcd cdda vcdx cddax],[-ldvd])
;;
*bsd*)
SYS="${target_os}"
fi
fi
+dnl
+dnl VCDX and CDX modules
+dnl
+AC_ARG_ENABLE(vcdx,
+ [ --enable-vcdx VCD support with Navigation for Linux and Win32 (default enabled)])
+
+if test "${enable_vcdx}" != "no"
+then
+ PKG_CHECK_MODULES(LIBCDIO, libcdio >= 0.63,
+ enable_cdda="no"
+ AX_ADD_LDFLAGS([cddax],[$LIBCDIO_LIBS])
+ AX_ADD_CFLAGS([cddax],[$LIBCDIO_CFLAGS])
+ AX_ADD_PLUGINS([cddax]),
+ [AC_MSG_WARN(libcdio library not found)])
+
+ PKG_CHECK_MODULES(VCDINFO, libvcdinfo >= 0.7.18-cdio,
+ enable_vcd="no"
+ AX_ADD_LDFLAGS([vcdx],[$VCDINFO_LIBS])
+ AX_ADD_CFLAGS([vcdx],[$VCDINFO_CFLAGS])
+ AX_ADD_PLUGINS([vcdx]),
+[AC_MSG_WARN(vcdinfo library not found)])
+fi
+
dnl
dnl Satellite input module
dnl
modules/access/satellite/Makefile
modules/access/v4l/Makefile
modules/access/vcd/Makefile
+ modules/access/vcdx/Makefile
modules/access_output/Makefile
modules/audio_filter/Makefile
modules/audio_filter/channel_mixer/Makefile
List of vlc plugins (221)
-$Id: LIST,v 1.12 2003/09/18 16:46:02 lool Exp $
+$Id: LIST,v 1.13 2003/10/04 18:55:13 gbazin Exp $
- * a52: A/52 basic parser
+ * a52: A/52 basic parser/packetizer
- * a52old: Old A/52 decoder
-
* a52sys: A/52 decapsulation demuxer.
* a52tofloat32: A/52 audio converter & decoder plugin, using liba52
* cdda: input module to read audio CDs
+ * cddax: input module to read audio CDs vi libcdio
+
* cinepak: Cinepack video decoder
* clone: Clone video filter
* distort: miscellaneous image effects filter.
- * downmix3dn: 3D Now! accelerated version of downmix.
-
- * downmix: downmix module, used by the AC3 decoder.
-
- * downmixsse: SSE accelerated version of downmix.
-
* dshow: DirectShow access plugin for encoding cards under Windows
- * dts: DTS basic parser
+ * dts: DTS basic parser/packetizer
* dtstospdif: Audio converter that encapsulates DTS into S/PDIF
* id3tag: ID3 tag parser/skipper using libid3tag
- * idctaltivec: AltiVec accelerated version of idct.
-
- * idctclassic: another version of idct.
-
- * idct: inverse DCT module, used by mpeg_video_old
-
- * idctmmxext: MMX EXT accelerated version of idct.
-
- * idctmmx: MMX accelerated version of idct.
-
- * imdct3dn: 3D Now! Accelerated A/52 DCT
-
- * imdct: IMDCT module for the A/52 decoder
-
- * imdctsse: SSE accelerated A/52 DCT
-
* invert: inverse video filter.
* ipv4: IPv4 network abstraction layer
* mkv: Matroska demuxer
- * motion3dnow: 3D Now! accelerated version of motion.
-
- * motionaltivec: AltiVec accelerated version of motion.
-
* motionblur: Motion blur filter
- * motionmmxext: MMX EXT accelerated version of motion.
-
- * motionmmx: MMX accelerated version of motion.
-
- * motion: motion compensation module for mpeg_video_old
-
* mp4: MP4 file input module
- * mpeg_audio: MPEG audio parser and packetizer
+ * mpeg_audio: MPEG audio parser/packetizer
* mpeg_system: helper module for TS, PS and PES management
- * mpeg_video_old: MPEG and MPEG2 video decoder.
-
* mpga: MPEG-I/II Audio demuxer
* mpgatofixed32: MPEG-1 & 2 audio layer I,II,III audio decoder using MAD
* oss: audio output module using the OSS /dev/dsp interface.
- * packetizer_a52: A/52 audio packetizer
-
* packetizer_copy: Simple copy packetizer
* packetizer_mpeg4audio: MPEG4 audio packetizer
* packetizer_mpeg4video: MPEG4 video packetizer
- * packetizer_mpegaudio: MPEG audio packetizer
-
* packetizer_mpegvideo: MPEG video packetizer
- * packetizer_vorbis: Vorbis packetizer
-
* pda: interface for iPaq using the Gtk2+ widget set.
* postprocessing_c: Video Postprocessing module
* stream_out_transcode: audio & video transcoder using ffmpeg
- * subsdec: Another SPU decoder
+ * subsdec: Another SPU decoder for text subtitles
* svgalib: SGVAlib output plugin
* test4: Stress test module
- * theora: a theora video decoder using the libtheora library.
+ * theora: a theora video decoder/packetizer using the libtheora library.
* transform: filter for horizontal and vertical image flips and
90° rotations.
* vcd: input module for accessing Video CDs.
+ * vcdx: input module for accessing Video CDs with navigation & stills
+
* visual: visualisation system
- * vorbis: a vorbis audio decoder using the libvorbis library.
+ * vorbis: a vorbis audio decoder/packetizer using the libvorbis library.
* vout_directx: video output module using the DirectX API.
vcd/cdrom.h \
vcd/cdrom_internals.h \
$(NULL)
+SOURCES_cddax = \
+ cddax.c \
+ vcdx/cdrom.c \
+ vcdx/cdrom.h
--- /dev/null
+/*****************************************************************************
+ * cddax.c : CD digital audio input module for vlc using libcdio
+ *****************************************************************************
+ * Copyright (C) 2000 VideoLAN
+ * $Id: cddax.c,v 1.1 2003/10/04 18:55:13 gbazin Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * Gildas Bazin <gbazin@netcourrier.com>
+ * Rocky Bernstein <rocky@panix.com>
+ *
+ * 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 <sys/types.h>
+#include <cdio/cdio.h>
+#include <cdio/cd_types.h>
+
+#include "codecs.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <string.h>
+
+#include "vcdx/cdrom.h"
+
+/* how many blocks CDDAOpen will read in each loop */
+#define CDDA_BLOCKS_ONCE 1
+#define CDDA_DATA_ONCE (CDDA_BLOCKS_ONCE * CDIO_CD_FRAMESIZE_RAW)
+
+/*****************************************************************************
+ * cdda_data_t: CD audio information
+ *****************************************************************************/
+typedef struct cdda_data_s
+{
+ cddev_t *p_cddev; /* CD device descriptor */
+ int i_nb_tracks; /* Nb of tracks (titles) */
+ int i_track; /* Current track */
+ lsn_t i_sector; /* Current Sector */
+ lsn_t * p_sectors; /* Track sectors */
+ vlc_bool_t b_end_of_track; /* If the end of track was reached */
+
+} cdda_data_t;
+
+struct demux_sys_t
+{
+ es_descriptor_t *p_es;
+ mtime_t i_pts;
+};
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int CDDAOpen ( vlc_object_t * );
+static void CDDAClose ( vlc_object_t * );
+static int CDDARead ( input_thread_t *, byte_t *, size_t );
+static void CDDASeek ( input_thread_t *, off_t );
+static int CDDASetArea ( input_thread_t *, input_area_t * );
+static int CDDASetProgram ( input_thread_t *, pgrm_descriptor_t * );
+
+static int CDDAOpenDemux ( vlc_object_t * );
+static void CDDACloseDemux ( vlc_object_t * );
+static int CDDADemux ( input_thread_t * p_input );
+
+/*****************************************************************************
+ * Module descriptior
+ *****************************************************************************/
+#define CACHING_TEXT N_("Caching value in ms")
+#define CACHING_LONGTEXT N_( \
+ "Allows you to modify the default caching value for cdda streams. This " \
+ "value should be set in miliseconds units." )
+
+vlc_module_begin();
+ set_description( _("CD Audio input") );
+ set_capability( "access", 75 /* slightly higher than cdda */ );
+ add_integer( "cddax-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
+ set_callbacks( CDDAOpen, CDDAClose );
+ add_shortcut( "cdda" );
+
+ add_submodule();
+ set_description( _("CD Audio demux") );
+ set_capability( "demux", 0 );
+ set_callbacks( CDDAOpenDemux, CDDACloseDemux );
+ add_shortcut( "cdda" );
+vlc_module_end();
+
+/*****************************************************************************
+ * CDDAOpen: open cdda
+ *****************************************************************************/
+static int CDDAOpen( vlc_object_t *p_this )
+{
+ input_thread_t * p_input = (input_thread_t *)p_this;
+ char * psz_orig;
+ char * psz_parser;
+ char * psz_source;
+ cdda_data_t * p_cdda;
+ int i;
+ input_area_t * p_area;
+ int i_title = 1;
+ cddev_t *p_cddev;
+
+ /* parse the options passed in command line : */
+ psz_orig = psz_parser = psz_source = strdup( p_input->psz_name );
+
+ if( !psz_orig )
+ {
+ return( -1 );
+ }
+
+ while( *psz_parser && *psz_parser != '@' )
+ {
+ psz_parser++;
+ }
+
+ if( *psz_parser == '@' )
+ {
+ /* Found options */
+ *psz_parser = '\0';
+ ++psz_parser;
+
+ if ('T' == *psz_parser || 't' == *psz_parser )
+ ++psz_parser;
+
+ i_title = (int)strtol( psz_parser, NULL, 10 );
+ i_title = i_title ? i_title : 1;
+ }
+
+ if( !*psz_source ) {
+ /* No source specified, so figure it out. */
+ if( !p_input->psz_access ) {
+ free( psz_orig );
+ return -1;
+ }
+ psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
+
+ if( !psz_source ) {
+ /* Scan for a CD with a VCD in it. */
+ char **cd_drives =
+ cdio_get_devices_with_cap(NULL, CDIO_FS_AUDIO, false);
+ if (NULL == cd_drives) return -1;
+ if (cd_drives[0] == NULL) {
+ cdio_free_device_list(cd_drives);
+ return -1;
+ }
+ psz_source = strdup(cd_drives[0]);
+ cdio_free_device_list(cd_drives);
+ }
+ }
+
+ /* Open CDDA */
+ if( !(p_cddev = ioctl_Open( p_this, psz_source )) )
+ {
+ msg_Warn( p_input, "could not open %s", psz_source );
+ free( psz_source );
+ return -1;
+ }
+ free( psz_source );
+
+ p_cdda = malloc( sizeof(cdda_data_t) );
+ if( p_cdda == NULL )
+ {
+ msg_Err( p_input, "out of memory" );
+ free( psz_source );
+ return -1;
+ }
+
+ p_cdda->p_cddev = p_cddev;
+ p_input->p_access_data = (void *)p_cdda;
+
+ p_input->i_mtu = CDDA_DATA_ONCE;
+
+ /* We read the Table Of Content information */
+ p_cdda->i_nb_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
+ p_cdda->p_cddev->cdio, &p_cdda->p_sectors );
+ if( p_cdda->i_nb_tracks < 0 )
+ msg_Err( p_input, "unable to count tracks" );
+ else if( p_cdda->i_nb_tracks <= 0 )
+ msg_Err( p_input, "no audio tracks found" );
+
+ if( p_cdda->i_nb_tracks <= 1)
+ {
+ ioctl_Close( p_cdda->p_cddev );
+ free( p_cdda );
+ return -1;
+ }
+
+ if( i_title >= p_cdda->i_nb_tracks || i_title < 1 )
+ i_title = 1;
+
+ /* Set stream and area data */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ /* Initialize ES structures */
+ input_InitStream( p_input, 0 );
+
+ /* cdda input method */
+ p_input->stream.i_method = INPUT_METHOD_CDDA;
+
+ p_input->stream.b_pace_control = 1;
+ p_input->stream.b_seekable = 1;
+ p_input->stream.i_mux_rate = 44100 * 4 / 50;
+
+#define area p_input->stream.pp_areas
+ for( i = 1 ; i <= p_cdda->i_nb_tracks ; i++ )
+ {
+ input_AddArea( p_input, i, 1 );
+
+ /* Absolute start offset and size */
+ area[i]->i_start =
+ (off_t)p_cdda->p_sectors[i-1] * (off_t)CDIO_CD_FRAMESIZE_RAW;
+ area[i]->i_size =
+ (off_t)(p_cdda->p_sectors[i] - p_cdda->p_sectors[i-1])
+ * (off_t)CDIO_CD_FRAMESIZE_RAW;
+ }
+#undef area
+
+ p_area = p_input->stream.pp_areas[i_title];
+
+ CDDASetArea( p_input, p_area );
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ if( !p_input->psz_demux || !*p_input->psz_demux )
+ {
+ p_input->psz_demux = "cdda";
+ }
+
+ p_input->pf_read = CDDARead;
+ p_input->pf_seek = CDDASeek;
+ p_input->pf_set_area = CDDASetArea;
+ p_input->pf_set_program = CDDASetProgram;
+
+ /* Update default_pts to a suitable value for cdda access */
+ p_input->i_pts_delay = config_GetInt( p_input, "cddax-caching" ) * 1000;
+
+ return 0;
+}
+
+/*****************************************************************************
+ * CDDAClose: closes cdda
+ *****************************************************************************/
+static void CDDAClose( vlc_object_t *p_this )
+{
+ input_thread_t * p_input = (input_thread_t *)p_this;
+ cdda_data_t *p_cdda = (cdda_data_t *)p_input->p_access_data;
+
+ ioctl_Close( p_cdda->p_cddev );
+ free( p_cdda );
+}
+
+/*****************************************************************************
+ * CDDARead: reads from the CDDA into PES packets.
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
+ * bytes.
+ *****************************************************************************/
+static int CDDARead( input_thread_t * p_input, byte_t * p_buffer,
+ size_t i_len )
+{
+ cdda_data_t * p_cdda;
+ int i_blocks;
+ int i_index;
+ int i_read;
+
+ p_cdda = (cdda_data_t *)p_input->p_access_data;
+
+ i_read = 0;
+
+ /* Compute the number of blocks we have to read */
+
+ i_blocks = i_len / CDIO_CD_FRAMESIZE_RAW;
+
+ for ( i_index = 0; i_index < i_blocks; i_index++ )
+ {
+
+ if (cdio_read_audio_sector(p_cdda->p_cddev->cdio, p_buffer,
+ p_cdda->i_sector) != 0)
+ {
+ msg_Err( p_input, "could not read sector %d", p_cdda->i_sector );
+ return -1;
+ }
+
+ p_cdda->i_sector ++;
+ if ( p_cdda->i_sector == p_cdda->p_sectors[p_cdda->i_track + 1] )
+ {
+ input_area_t *p_area;
+
+ if ( p_cdda->i_track >= p_cdda->i_nb_tracks - 1 )
+ return 0; /* EOF */
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_area = p_input->stream.pp_areas[
+ p_input->stream.p_selected_area->i_id + 1 ];
+
+ msg_Dbg( p_input, "new title" );
+
+ p_area->i_part = 1;
+ CDDASetArea( p_input, p_area );
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ }
+ i_read += CDIO_CD_FRAMESIZE_RAW;
+ }
+
+ if ( i_len % CDIO_CD_FRAMESIZE_RAW ) /* this should not happen */
+ {
+ msg_Err( p_input, "must read full sectors" );
+ }
+
+ return i_read;
+}
+
+/*****************************************************************************
+ * CDDASetProgram: Does nothing since a CDDA is mono_program
+ *****************************************************************************/
+static int CDDASetProgram( input_thread_t * p_input,
+ pgrm_descriptor_t * p_program)
+{
+ return 0;
+}
+
+/*****************************************************************************
+ * CDDASetArea: initialize input data for title x.
+ * It should be called for each user navigation request.
+ ****************************************************************************/
+static int CDDASetArea( input_thread_t * p_input, input_area_t * p_area )
+{
+ cdda_data_t *p_cdda = (cdda_data_t*)p_input->p_access_data;
+ vlc_value_t val;
+
+ /* 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 )
+ {
+ /* Change the default area */
+ p_input->stream.p_selected_area = p_area;
+
+ /* Change the current track */
+ p_cdda->i_track = p_area->i_id - 1;
+ p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
+
+ /* 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 );
+ }
+
+ p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track];
+
+ p_input->stream.p_selected_area->i_tell =
+ (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
+ - p_input->stream.p_selected_area->i_start;
+
+ /* warn interface that something has changed */
+ p_input->stream.b_seekable = 1;
+ p_input->stream.b_changed = 1;
+
+ return 0;
+}
+
+/****************************************************************************
+ * CDDASeek
+ ****************************************************************************/
+static void CDDASeek( input_thread_t * p_input, off_t i_off )
+{
+ cdda_data_t * p_cdda;
+
+ p_cdda = (cdda_data_t *) p_input->p_access_data;
+
+ p_cdda->i_sector = p_cdda->p_sectors[p_cdda->i_track]
+ + i_off / (off_t)CDIO_CD_FRAMESIZE_RAW;
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_input->stream.p_selected_area->i_tell =
+ (off_t)p_cdda->i_sector * (off_t)CDIO_CD_FRAMESIZE_RAW
+ - p_input->stream.p_selected_area->i_start;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+}
+
+/****************************************************************************
+ * Demux Part
+ ****************************************************************************/
+static int CDDAOpenDemux ( vlc_object_t * p_this)
+{
+ input_thread_t *p_input = (input_thread_t *)p_this;
+ demux_sys_t *p_demux;
+ WAVEFORMATEX *p_wf;
+
+ if( p_input->stream.i_method != INPUT_METHOD_CDDA )
+ {
+ return VLC_EGENERIC;
+ }
+
+ p_demux = malloc( sizeof( es_descriptor_t ) );
+ p_demux->i_pts = 0;
+ p_demux->p_es = NULL;
+
+ p_input->pf_demux = CDDADemux;
+ p_input->pf_rewind = NULL;
+ p_input->p_demux_data = p_demux;
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ if( input_AddProgram( p_input, 0, 0) == NULL )
+ {
+ msg_Err( p_input, "cannot add program" );
+ free( p_input->p_demux_data );
+ return( -1 );
+ }
+ p_input->stream.pp_programs[0]->b_is_ok = 0;
+ p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
+
+ /* create our ES */
+ p_demux->p_es = input_AddES( p_input,
+ p_input->stream.p_selected_program,
+ 1 /* id */, AUDIO_ES, NULL, 0 );
+ if( !p_demux->p_es )
+ {
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ msg_Err( p_input, "out of memory" );
+ free( p_input->p_demux_data );
+ return( -1 );
+ }
+ p_demux->p_es->i_stream_id = 1;
+ p_demux->p_es->i_fourcc = VLC_FOURCC('a','r','a','w');
+
+ p_demux->p_es->p_waveformatex = p_wf = malloc( sizeof( WAVEFORMATEX ) );
+ p_wf->wFormatTag = WAVE_FORMAT_PCM;
+ p_wf->nChannels = 2;
+ p_wf->nSamplesPerSec = 44100;
+ p_wf->nAvgBytesPerSec = 2 * 44100 * 2;
+ p_wf->nBlockAlign = 4;
+ p_wf->wBitsPerSample = 16;
+ p_wf->cbSize = 0;
+
+ input_SelectES( p_input, p_demux->p_es );
+
+ p_input->stream.p_selected_program->b_is_ok = 1;
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ return VLC_SUCCESS;
+}
+
+static void CDDACloseDemux( vlc_object_t * p_this)
+{
+ input_thread_t *p_input = (input_thread_t*)p_this;
+ demux_sys_t *p_demux = (demux_sys_t*)p_input->p_demux_data;
+
+ free( p_demux );
+ p_input->p_demux_data = NULL;
+ return;
+}
+
+static int CDDADemux( input_thread_t * p_input )
+{
+ demux_sys_t *p_demux = (demux_sys_t*)p_input->p_demux_data;
+ ssize_t i_read;
+ data_packet_t * p_data;
+ pes_packet_t * p_pes;
+
+ input_ClockManageRef( p_input,
+ p_input->stream.p_selected_program,
+ p_demux->i_pts );
+
+ i_read = input_SplitBuffer( p_input, &p_data, CDIO_CD_FRAMESIZE_RAW );
+ if( i_read <= 0 )
+ {
+ return 0; // EOF
+ }
+
+ p_pes = input_NewPES( p_input->p_method_data );
+
+ if( p_pes == NULL )
+ {
+ msg_Err( p_input, "out of memory" );
+ input_DeletePacket( p_input->p_method_data, p_data );
+ return -1;
+ }
+
+ p_pes->i_rate = p_input->stream.control.i_rate;
+ p_pes->p_first = p_pes->p_last = p_data;
+ p_pes->i_nb_data = 1;
+ p_pes->i_pes_size = i_read;
+
+ p_pes->i_dts =
+ p_pes->i_pts = input_ClockGetTS( p_input,
+ p_input->stream.p_selected_program,
+ p_demux->i_pts );
+
+ if( p_demux->p_es->p_decoder_fifo )
+ {
+ input_DecodePES( p_demux->p_es->p_decoder_fifo, p_pes );
+ }
+ else
+ {
+ input_DeletePES( p_input->p_method_data, p_pes );
+ }
+
+ p_demux->i_pts += ((mtime_t)90000) * i_read
+ / (mtime_t)44100 / 4 /* stereo 16 bits */;
+ return 1;
+}
--- /dev/null
+.deps
+.dirstamp
+Makefile
+Makefile.am
+Makefile.in
+*.dll
+*.dylib
+*.sl
+*.so
--- /dev/null
+SOURCES_vcdx = \
+ intf.c \
+ intf.h \
+ vcd.c \
+ vcd.h \
+ vcdplayer.h \
+ vcdplayer.c \
+ cdrom.c \
+ cdrom.h \
+ demux.c \
+ access.c \
+ $(NULL)
--- /dev/null
+/*****************************************************************************
+ * vcd.c : VCD input module for vlc
+ * using libcdio, libvcd and libvcdinfo. vlc-specific things tend
+ * to go here.
+ *****************************************************************************
+ * Copyright (C) 2000 VideoLAN
+ * $Id: access.c,v 1.1 2003/10/04 18:55:13 gbazin Exp $
+ *
+ * Authors: Johan Bilien <jobi@via.ecp.fr>
+ * Rocky Bernstein <rocky@panix.com>
+ *
+ * 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
+ *****************************************************************************/
+
+#if 0 // Disabled until this is working
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include "../../demux/mpeg/system.h"
+#include "vcd.h"
+#include "intf.h"
+#include "vcdplayer.h"
+
+#include <cdio/cdio.h>
+#include <cdio/logging.h>
+#include <cdio/util.h>
+#include <libvcd/info.h>
+#include <libvcd/logging.h>
+
+#include "cdrom.h"
+
+/* how many blocks VCDRead will read in each loop */
+#define VCD_BLOCKS_ONCE 20
+#define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE)
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+
+/* First those which are accessed from outside (via pointers). */
+static int VCDOpen ( vlc_object_t * );
+static void VCDClose ( vlc_object_t * );
+static int VCDRead ( input_thread_t *, byte_t *, size_t );
+static int VCDRead ( input_thread_t *, byte_t *, size_t );
+static int VCDSetProgram ( input_thread_t *, pgrm_descriptor_t * );
+
+/* Now those which are strictly internal */
+static void VCDSetOrigin ( input_thread_t *, lsn_t origin_lsn,
+ lsn_t cur_lsn, lsn_t end_lsn,
+ int cur_entry, track_t track );
+static int VCDEntryPoints ( input_thread_t * );
+static int VCDLIDs ( input_thread_t * );
+static int VCDSegments ( input_thread_t * );
+static void VCDTracks ( input_thread_t * );
+static int VCDReadSector ( vlc_object_t *p_this,
+ const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn,
+ byte_t * p_buffer );
+static char *VCDParse ( input_thread_t *,
+ /*out*/ vcdinfo_itemid_t * p_itemid );
+
+static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action,
+ const char *varname, const char *label );
+
+static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
+
+static int debug_callback ( vlc_object_t *p_this, const char *psz_name,
+ vlc_value_t oldval, vlc_value_t val,
+ void *p_data );
+
+#define DEBUG_TEXT N_("set debug mask for additional debugging.")
+#define DEBUG_LONGTEXT N_( \
+ "This integer when viewed in binary is a debugging mask\n" \
+ "MRL 1\n" \
+ "external call 2\n" \
+ "all calls 4\n" \
+ "LSN 8\n" \
+ "PBC (10) 16\n" \
+ "libcdio (20) 32\n" \
+ "seeks (40) 64\n" \
+ "still (80) 128\n" \
+ "vcdinfo (100) 256\n" )
+
+/****************************************************************************
+ * Private functions
+ ****************************************************************************/
+/* FIXME: This variable is a hack. Would be nice to eliminate the
+ global-ness. */
+static input_thread_t *p_vcd_input = NULL;
+
+int
+vcd_debug_callback ( vlc_object_t *p_this, const char *psz_name,
+ vlc_value_t oldval, vlc_value_t val, void *p_data )
+{
+ thread_vcd_data_t *p_vcd;
+
+ if (NULL == p_vcd_input) return VLC_EGENERIC;
+
+ p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
+
+ if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
+ msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
+ p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
+ }
+ p_vcd->i_debug = val.i_int;
+ return VLC_SUCCESS;
+}
+
+/* process messages that originate from libcdio. */
+static void
+cdio_log_handler (cdio_log_level_t level, const char message[])
+{
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
+ switch (level) {
+ case CDIO_LOG_DEBUG:
+ case CDIO_LOG_INFO:
+ if (p_vcd->i_debug & INPUT_DBG_CDIO)
+ msg_Dbg( p_vcd_input, message);
+ break;
+ case CDIO_LOG_WARN:
+ msg_Warn( p_vcd_input, message);
+ break;
+ case CDIO_LOG_ERROR:
+ case CDIO_LOG_ASSERT:
+ msg_Err( p_vcd_input, message);
+ break;
+ default:
+ msg_Warn( p_vcd_input, message,
+ _("The above message had unknown vcdimager log level"),
+ level);
+ }
+ return;
+}
+
+/* process messages that originate from vcdinfo. */
+static void
+vcd_log_handler (vcd_log_level_t level, const char message[])
+{
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
+ switch (level) {
+ case VCD_LOG_DEBUG:
+ case VCD_LOG_INFO:
+ if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
+ msg_Dbg( p_vcd_input, message);
+ break;
+ case VCD_LOG_WARN:
+ msg_Warn( p_vcd_input, message);
+ break;
+ case VCD_LOG_ERROR:
+ case VCD_LOG_ASSERT:
+ msg_Err( p_vcd_input, message);
+ break;
+ default:
+ msg_Warn( p_vcd_input, "%s\n%s %d", message,
+ _("The above message had unknown vcdimager log level"),
+ level);
+ }
+ return;
+}
+
+/*
+ * Data reading functions
+ */
+
+/*****************************************************************************
+ VCDOpen: open VCD.
+ read in meta-information about VCD: the number of tracks, segments,
+ entries, size and starting information. Then set up state variables so
+ that we read/seek starting at the location specified.
+
+ On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
+ and VLC_EGENERIC for some other error.
+ *****************************************************************************/
+static int
+VCDOpen( vlc_object_t *p_this )
+{
+ input_thread_t * p_input = (input_thread_t *)p_this;
+ thread_vcd_data_t * p_vcd;
+ char * psz_source;
+ vcdinfo_itemid_t itemid;
+ bool play_ok;
+
+ p_input->pf_read = VCDRead;
+ p_input->pf_seek = VCDSeek;
+ p_input->pf_set_area = VCDSetArea;
+ p_input->pf_set_program = VCDSetProgram;
+
+ p_vcd = malloc( sizeof(thread_vcd_data_t) );
+
+ if( p_vcd == NULL )
+ {
+ LOG_ERR ("out of memory" );
+ return VLC_ENOMEM;
+ }
+
+ p_input->p_access_data = (void *)p_vcd;
+ p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
+ psz_source = VCDParse( p_input, &itemid );
+
+ if ( NULL == psz_source )
+ {
+ free( p_vcd );
+ return( VLC_EGENERIC );
+ }
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
+
+ p_vcd->p_segments = NULL;
+ p_vcd->p_entries = NULL;
+
+ /* set up input */
+ p_input->i_mtu = VCD_DATA_ONCE;
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ /* 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 );
+
+ if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
+ {
+ msg_Warn( p_input, "could not open %s", psz_source );
+ free( psz_source );
+ free( p_vcd );
+ return VLC_EGENERIC;
+ }
+
+ /* Get track information. */
+ p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
+ vcdinfo_get_cd_image(p_vcd->vcd),
+ &p_vcd->p_sectors );
+ free( psz_source );
+ if( p_vcd->num_tracks < 0 )
+ LOG_ERR ("unable to count tracks" );
+ else if( p_vcd->num_tracks <= 1 )
+ LOG_ERR ("no movie tracks found" );
+ if( p_vcd->num_tracks <= 1)
+ {
+ vcdinfo_close( p_vcd->vcd );
+ free( p_vcd );
+ return VLC_EGENERIC;
+ }
+
+ /* Set stream and area data */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ /* Initialize ES structures */
+ input_InitStream( p_input, sizeof( stream_ps_data_t ) );
+
+ /* disc input method */
+ p_input->stream.i_method = INPUT_METHOD_VCD;
+
+ p_input->stream.i_area_nb = 1;
+
+
+ /* Initialize segment information. */
+ VCDSegments( p_input );
+
+ /* Initialize track area information. */
+ VCDTracks( p_input );
+
+ if( VCDEntryPoints( p_input ) < 0 )
+ {
+ msg_Warn( p_input, "could not read entry points, will not use them" );
+ p_vcd->b_valid_ep = false;
+ }
+
+ if( VCDLIDs( p_input ) < 0 )
+ {
+ msg_Warn( p_input, "could not read entry LIDs" );
+ }
+
+ play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ if ( ! play_ok ) {
+ vcdinfo_close( p_vcd->vcd );
+ free( p_vcd );
+ return VLC_EGENERIC;
+ }
+
+ if( !p_input->psz_demux || !*p_input->psz_demux )
+ {
+#if FIXED
+ p_input->psz_demux = "vcdx";
+#else
+ p_input->psz_demux = "ps";
+#endif
+ }
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * VCDClose: closes VCD releasing allocated memory.
+ *****************************************************************************/
+static void
+VCDClose( vlc_object_t *p_this )
+{
+ input_thread_t * p_input = (input_thread_t *)p_this;
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
+ vcdinfo_close( p_vcd->vcd );
+
+ free( p_vcd->p_entries );
+ free( p_vcd->p_segments );
+ free( p_vcd );
+ p_vcd_input = NULL;
+}
+
+/*****************************************************************************
+ * VCDRead: reads i_len bytes from the VCD into p_buffer.
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
+ * bytes.
+ *****************************************************************************/
+static int
+VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
+{
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+ int i_blocks;
+ int i_index;
+ int i_read;
+ byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
+
+ i_read = 0;
+
+ /* Compute the number of blocks we have to read */
+
+ i_blocks = i_len / M2F2_SECTOR_SIZE;
+
+ for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
+ {
+
+ if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
+ vcdplayer_read_status_t read_status;
+
+ /* We've run off of the end of this entry. Do we continue or stop? */
+ dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
+ "end reached, cur: %u", p_vcd->cur_lsn );
+
+ read_status = vcdplayer_pbc_is_on( p_vcd )
+ ? vcdplayer_pbc_nav( p_input )
+ : vcdplayer_non_pbc_nav( p_input );
+
+ switch (read_status) {
+ case READ_END:
+ /* End reached. Return NULL to indicated this. */
+ case READ_ERROR:
+ /* Some sort of error. */
+ return i_read;
+ case READ_STILL_FRAME:
+ {
+ byte_t * p_buf = p_buffer;
+ p_buf += (i_index*M2F2_SECTOR_SIZE);
+ memset(p_buf, 0, M2F2_SECTOR_SIZE);
+ p_buf += 2;
+ *p_buf = 0x01;
+ dbg_print(INPUT_DBG_STILL, "Handled still event\n");
+ return i_read + M2F2_SECTOR_SIZE;
+ }
+ default:
+ case READ_BLOCK:
+ break;
+ }
+ }
+
+ if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
+ p_vcd->cur_lsn,
+ p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
+ {
+ LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
+ return -1;
+ }
+
+ p_vcd->cur_lsn ++;
+
+ /* Update chapter */
+ if( p_vcd->b_valid_ep &&
+ /* FIXME kludge so that read does not update chapter
+ * when a manual chapter change was requested and not
+ * yet accomplished */
+ !p_input->stream.p_new_area )
+ {
+ unsigned int i_entry = p_input->stream.p_selected_area->i_part;
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ if( i_entry < p_vcd->num_entries &&
+ p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
+ {
+ dbg_print( INPUT_DBG_PBC,
+ "new entry, i_entry %d, sector %d, es %d",
+ i_entry, p_vcd->cur_lsn,
+ p_vcd->p_entries[i_entry] );
+ p_vcd->play_item.num =
+ ++ p_input->stream.p_selected_area->i_part;
+ p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
+ VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
+ "chapter", "Setting entry" );
+ }
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ }
+
+ i_read += M2F2_SECTOR_SIZE;
+ }
+
+ if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
+ {
+ if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
+ p_vcd->cur_lsn, p_last_sector ) < 0 )
+ {
+ LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
+ return -1;
+ }
+
+ p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
+ p_last_sector, i_len % M2F2_SECTOR_SIZE );
+ i_read += i_len % M2F2_SECTOR_SIZE;
+ }
+
+ return i_read;
+}
+
+
+/*****************************************************************************
+ * VCDSetProgram: Does nothing since a VCD is mono_program
+ *****************************************************************************/
+static int
+VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
+{
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
+ return 0;
+}
+
+
+/*****************************************************************************
+ * VCDSetArea: initialize internal data structures and input stream data
+ so set subsequent reading and seeking to reflect that we are
+ at track x, entry or segment y.
+ This is called for each user navigation request, e.g. the GUI
+ Chapter/Title selections or in initial MRL parsing.
+ ****************************************************************************/
+int
+VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
+{
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
+ unsigned int i_entry = p_area->i_part;
+ track_t i_track = p_area->i_id;
+ int old_seekable = p_input->stream.b_seekable;
+ unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb;
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
+ "track: %d, entry %d, seekable %d",
+ i_track, i_entry, old_seekable );
+
+ /* 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 )
+ {
+ unsigned int i;
+
+ /* If is the result of a track change, make the entry valid. */
+ if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
+ i_entry = p_area->i_plugin_data;
+
+ /* Change the default area */
+ p_input->stream.p_selected_area = p_area;
+
+ /* Update the navigation variables without triggering a callback */
+ VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
+ "Setting track");
+
+ var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
+ for( i = p_area->i_plugin_data; i < i_nb; i++ )
+ {
+ VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
+ "chapter", "Adding entry choice");
+ }
+ }
+
+ if (i_track == 0)
+ VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
+ p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
+ i_entry, 0 );
+ else
+ VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
+ vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
+ p_vcd->p_sectors[i_track+1],
+ i_entry, i_track );
+
+ p_input->stream.b_seekable = old_seekable;
+ /* warn interface that something has changed */
+ p_input->stream.b_changed = 1;
+
+ return VLC_SUCCESS;
+}
+
+
+/****************************************************************************
+ * VCDSeek
+ ****************************************************************************/
+void
+VCDSeek( input_thread_t * p_input, off_t i_off )
+{
+ thread_vcd_data_t * p_vcd;
+ unsigned int i_entry=0; /* invalid entry */
+
+ p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+
+ p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+#define p_area p_input->stream.p_selected_area
+ /* Find entry */
+ if( p_vcd->b_valid_ep )
+ {
+ for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ )
+ {
+ if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
+ {
+ VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
+ "chapter", "Setting entry" );
+ break;
+ }
+ }
+ p_vcd->play_item.num = p_area->i_part = i_entry;
+ p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
+ }
+#undef p_area
+
+ p_input->stream.p_selected_area->i_tell = i_off;
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
+ "orig %d, cur: %d, offset: %lld, start: %lld, entry %d",
+ p_vcd->origin_lsn, p_vcd->cur_lsn, i_off,
+ p_input->stream.p_selected_area->i_start, i_entry );
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+}
+
+/*****************************************************************************
+ VCDPlay: set up internal structures so seeking/reading places an item.
+ itemid: the thing to play.
+ user_entry: true if itemid is a user selection (rather than internally-
+ generated selection such as via PBC) in which case we may have to adjust
+ for differences in numbering.
+ *****************************************************************************/
+int
+VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
+{
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+ input_area_t * p_area;
+
+ p_vcd->in_still = 0;
+
+#define area p_input->stream.pp_areas
+
+ switch (itemid.type) {
+ case VCDINFO_ITEM_TYPE_TRACK:
+
+ /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
+ */
+
+ if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
+ LOG_ERR ("Invalid track number %d", itemid.num );
+ return VLC_EGENERIC;
+ }
+ p_area = area[itemid.num];
+ p_area->i_part = p_area->i_plugin_data;
+ p_input->stream.b_seekable = 1;
+ break;
+ case VCDINFO_ITEM_TYPE_SEGMENT:
+ /* Valid segments go from 0...num_segments-1. */
+ if (itemid.num >= p_vcd->num_segments) {
+ LOG_ERR ( "Invalid segment number: %d", itemid.num );
+ return VLC_EGENERIC;
+ } else {
+ vcdinfo_video_segment_type_t segtype =
+ vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
+
+ dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
+ vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
+ (int) segtype, itemid.num);
+
+ p_area = area[0];
+ p_area->i_part = itemid.num;
+
+ switch (segtype)
+ {
+ case VCDINFO_FILES_VIDEO_NTSC_STILL:
+ case VCDINFO_FILES_VIDEO_NTSC_STILL2:
+ case VCDINFO_FILES_VIDEO_PAL_STILL:
+ case VCDINFO_FILES_VIDEO_PAL_STILL2:
+ p_input->stream.b_seekable = 0;
+ p_vcd->in_still = -5;
+ break;
+ default:
+ p_input->stream.b_seekable = 1;
+ p_vcd->in_still = 0;
+ }
+ }
+ break;
+
+ case VCDINFO_ITEM_TYPE_LID:
+ /* LIDs go from 1..num_lids. */
+ if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
+ LOG_ERR ( "Invalid LID number: %d", itemid.num );
+ return VLC_EGENERIC;
+ } else {
+ p_vcd->cur_lid = itemid.num;
+ vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
+
+ switch (p_vcd->pxd.descriptor_type) {
+
+ case PSD_TYPE_SELECTION_LIST:
+ case PSD_TYPE_EXT_SELECTION_LIST: {
+ vcdinfo_itemid_t trans_itemid;
+ uint16_t trans_itemid_num;
+
+ if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
+ trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
+ vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
+ p_vcd->loop_count = 1;
+ p_vcd->loop_item = trans_itemid;
+ return VCDPlay( p_input, trans_itemid );
+ break;
+ }
+
+ case PSD_TYPE_PLAY_LIST: {
+ if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
+ p_vcd->pdi = -1;
+ return vcdplayer_inc_play_item(p_input)
+ ? VLC_SUCCESS : VLC_EGENERIC;
+ break;
+ }
+
+ case PSD_TYPE_END_LIST:
+ case PSD_TYPE_COMMAND_LIST:
+
+ default:
+ ;
+ }
+ }
+ return VLC_EGENERIC;
+ case VCDINFO_ITEM_TYPE_ENTRY:
+ /* Entries go from 0..num_entries-1. */
+ if (itemid.num >= p_vcd->num_entries) {
+ LOG_ERR ("Invalid entry number: %d", itemid.num );
+ return VLC_EGENERIC;
+ } else {
+ track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
+ p_area = area[cur_track];
+ p_area->i_part = itemid.num;
+ p_input->stream.b_seekable = 1;
+ }
+ break;
+ default:
+ LOG_ERR ("unknown entry type" );
+ return VLC_EGENERIC;
+ }
+
+ VCDSetArea( p_input, p_area );
+
+#undef area
+
+ p_vcd->play_item = itemid;
+
+ dbg_print( (INPUT_DBG_CALL),
+ "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d",
+ p_area->i_start, p_area->i_size,
+ p_area->i_tell, p_vcd->cur_lsn );
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ VCDEntryPoints: Reads the information about the entry points on the disc
+ and initializes area information with that.
+ Before calling this track information should have been read in.
+ *****************************************************************************/
+static int
+VCDEntryPoints( input_thread_t * p_input )
+{
+ thread_vcd_data_t * p_vcd;
+ unsigned int i_nb;
+ unsigned int i, i_entry_index = 0;
+ unsigned int i_previous_track = CDIO_INVALID_TRACK;
+
+ p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+
+ i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
+ if (0 == i_nb)
+ return -1;
+
+ p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
+
+ if( p_vcd->p_entries == NULL )
+ {
+ LOG_ERR ("not enough memory for entry points treatment" );
+ return -1;
+ }
+
+ p_vcd->num_entries = 0;
+
+ for( i = 0 ; i < i_nb ; i++ )
+ {
+ track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
+ if( i_track <= p_input->stream.i_area_nb )
+ {
+ p_vcd->p_entries[i] =
+ vcdinfo_get_entry_lsn(p_vcd->vcd, i);
+ p_input->stream.pp_areas[i_track]->i_part_nb ++;
+
+ /* if this entry belongs to a new track */
+ if( i_track != i_previous_track )
+ {
+ /* i_plugin_data is used to store the first entry of the area*/
+ p_input->stream.pp_areas[i_track]->i_plugin_data =
+ i_entry_index;
+ i_previous_track = i_track;
+ p_input->stream.pp_areas[i_track]->i_part_nb = 1;
+ }
+ i_entry_index ++;
+ p_vcd->num_entries ++;
+ }
+ else
+ msg_Warn( p_input, "wrong track number found in entry points" );
+ }
+ p_vcd->b_valid_ep = true;
+ return 0;
+}
+
+/*****************************************************************************
+ * VCDSegments: Reads the information about the segments the disc.
+ *****************************************************************************/
+static int
+VCDSegments( input_thread_t * p_input )
+{
+ thread_vcd_data_t * p_vcd;
+ unsigned int i;
+ unsigned int num_segments;
+
+
+ p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+ num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
+
+#define area p_input->stream.pp_areas
+
+ /* area 0 is reserved for segments. Set Absolute start offset
+ and size */
+ area[0]->i_plugin_data = 0;
+ input_DelArea( p_input, area[0] );
+ input_AddArea( p_input, 0, 0 );
+
+ area[0]->i_start = (off_t)p_vcd->p_sectors[0]
+ * (off_t)M2F2_SECTOR_SIZE;
+ area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
+ * (off_t)M2F2_SECTOR_SIZE;
+
+ /* Default Segment */
+ area[0]->i_part = 0;
+
+ /* i_plugin_data is used to store which entry point is the first
+ of the track (area) */
+ area[0]->i_plugin_data = 0;
+
+ area[0]->i_part_nb = 0;
+
+ dbg_print( INPUT_DBG_MRL, "area id %d, for segment track %d",
+ area[0]->i_id, 0 );
+
+ if (num_segments == 0) return 0;
+
+ /* We have one additional segment allocated so we can get the size
+ by subtracting seg[i+1] - seg[i].
+ */
+ p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
+ if( p_vcd->p_segments == NULL )
+ {
+ LOG_ERR ("not enough memory for segment treatment" );
+ return -1;
+ }
+
+ /* Update the navigation variables without triggering a callback */
+ VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" );
+ var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
+
+ for( i = 0 ; i < num_segments ; i++ )
+ {
+ p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
+ area[0]->i_part_nb ++;
+ VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
+ "chapter", "Adding segment choice");
+ }
+
+#undef area
+
+ p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
+ vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
+
+ return 0;
+}
+
+/*****************************************************************************
+ VCDTracks: initializes area information.
+ Before calling this track information should have been read in.
+ *****************************************************************************/
+static void
+VCDTracks( input_thread_t * p_input )
+{
+ thread_vcd_data_t * p_vcd;
+ unsigned int i;
+
+ p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+
+#define area p_input->stream.pp_areas
+
+ /* We start area addressing for tracks at 1 since the default area 0
+ is reserved for segments */
+
+ for( i = 1 ; i < p_vcd->num_tracks ; i++ )
+ {
+ /* Tracks are Program Chains */
+ input_AddArea( p_input, i, i );
+
+ /* Absolute start byte offset and byte size */
+ area[i]->i_start = (off_t) p_vcd->p_sectors[i]
+ * (off_t)M2F2_SECTOR_SIZE;
+ area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
+ * (off_t)M2F2_SECTOR_SIZE;
+
+ /* Current entry being played in track */
+ area[i]->i_part = 0;
+
+ /* i_plugin_data is used to store which entry point is the first
+ * of the track (area) */
+ area[i]->i_plugin_data = 0;
+
+ dbg_print( INPUT_DBG_MRL,
+ "area[%d] id: %d, i_start: %lld, i_size: %lld",
+ i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
+ }
+
+#undef area
+
+ return ;
+}
+
+/*****************************************************************************
+ VCDLIDs: Reads the LIST IDs from the LOT.
+ *****************************************************************************/
+static int
+VCDLIDs( input_thread_t * p_input )
+{
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+
+ p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
+ p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
+
+ if (vcdinfo_read_psd (p_vcd->vcd)) {
+
+ vcdinfo_visit_lot (p_vcd->vcd, false);
+
+ if (vcdinfo_get_psd_x_size(p_vcd->vcd))
+ vcdinfo_visit_lot (p_vcd->vcd, true);
+ }
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
+ "num LIDs=%d", p_vcd->num_lids);
+
+ return 0;
+}
+
+/*****************************************************************************
+ * VCDParse: parse command line
+ *****************************************************************************/
+static char *
+VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid )
+{
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
+ char * psz_parser;
+ char * psz_source;
+ char * psz_next;
+
+ p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
+ p_itemid->num=1;
+
+#ifdef WIN32
+ /* On Win32 we want the VCD 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
+
+ if( !p_input->psz_name )
+ {
+ return NULL;
+ }
+
+ psz_parser = psz_source = strdup( p_input->psz_name );
+
+ /* Parse input string :
+ * [device][@[type][title]] */
+ while( *psz_parser && *psz_parser != '@' )
+ {
+ psz_parser++;
+ }
+
+ if( *psz_parser == '@' )
+ {
+ /* Found the divide between the source name and the
+ type+entry number. */
+ unsigned int num;
+
+ *psz_parser = '\0';
+ ++psz_parser;
+ if( *psz_parser )
+ {
+ switch(*psz_parser) {
+ case 'E':
+ p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
+ ++psz_parser;
+ break;
+ case 'P':
+ p_itemid->type = VCDINFO_ITEM_TYPE_LID;
+ ++psz_parser;
+ break;
+ case 'S':
+ p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
+ ++psz_parser;
+ break;
+ case 'T':
+ p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
+ ++psz_parser;
+ break;
+ default: ;
+ }
+ }
+
+ num = strtol( psz_parser, &psz_next, 10 );
+ if ( *psz_parser != '\0' && *psz_next == '\0')
+ {
+ p_itemid->num = num;
+ }
+
+ }
+
+ if( !*psz_source )
+ {
+ if( !p_input->psz_access )
+ {
+ return NULL;
+ }
+ psz_source = config_GetPsz( p_input, "vcd" );
+ if( !psz_source ) return NULL;
+ }
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
+ "source=%s entry=%d type=%d",
+ psz_source, p_itemid->num, p_itemid->type);
+
+ return psz_source;
+}
+
+/*
+ Set's start origin subsequent seeks/reads
+*/
+static void
+VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
+ lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
+{
+ thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+
+ p_vcd->origin_lsn = origin_lsn;
+ p_vcd->cur_lsn = cur_lsn;
+ p_vcd->end_lsn = end_lsn;
+ p_vcd->cur_track = cur_track;
+ p_vcd->play_item.num = cur_entry;
+ p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
+ "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
+ origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
+
+ p_input->stream.p_selected_area->i_tell =
+ (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
+
+ VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
+ "chapter", "Setting entry");
+}
+
+/*****************************************************************************
+ * vcd_Open: Opens a VCD device or file and returns an opaque handle
+ *****************************************************************************/
+static vcdinfo_obj_t *
+vcd_Open( vlc_object_t *p_this, const char *psz_dev )
+{
+ vcdinfo_obj_t *p_vcdobj;
+ char *actual_dev;
+
+ if( !psz_dev ) return NULL;
+
+ /* Set where to log errors messages from libcdio. */
+ p_vcd_input = (input_thread_t *)p_this;
+ cdio_log_set_handler ( cdio_log_handler );
+ vcd_log_set_handler ( vcd_log_handler );
+
+ actual_dev=strdup(psz_dev);
+ if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
+ VCDINFO_OPEN_VCD) {
+ free(actual_dev);
+ return NULL;
+ }
+ free(actual_dev);
+
+ return p_vcdobj;
+}
+
+/****************************************************************************
+ * VCDReadSector: Read a sector (2324 bytes)
+ ****************************************************************************/
+static int
+VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
+ lsn_t cur_lsn, byte_t * p_buffer )
+{
+ typedef struct {
+ uint8_t subheader [8];
+ uint8_t data [M2F2_SECTOR_SIZE];
+ } vcdsector_t;
+ vcdsector_t vcd_sector;
+
+ if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
+ &vcd_sector, cur_lsn, true)
+ != 0)
+ {
+ msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
+ return -1;
+ }
+
+ memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
+
+ return( 0 );
+}
+
+/****************************************************************************
+ Update the "varname" variable to i_num without triggering a callback.
+****************************************************************************/
+static void
+VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
+ const char *varname, const char *label)
+{
+ vlc_value_t val;
+ val.i_int = i_num;
+ if (NULL != p_vcd_input) {
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
+ dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
+ }
+ var_Change( p_input, varname, i_action, &val, NULL );
+}
+#endif
--- /dev/null
+/****************************************************************************
+ * cdrom.c: cdrom tools
+ *****************************************************************************
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: cdrom.c,v 1.1 2003/10/04 18:55:13 gbazin Exp $
+ *
+ * Authors: Johan Bilien <jobi@via.ecp.fr>
+ * Gildas Bazin <gbazin@netcourrier.com>
+ * Jon Lech Johansen <jon-vl@nanocrew.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 <stdlib.h>
+
+#include <vlc/vlc.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include "cdrom.h"
+
+/*****************************************************************************
+ * Local Prototypes
+ *****************************************************************************/
+static void cd_log_handler (cdio_log_level_t level, const char message[]);
+
+/*****************************************************************************
+ * ioctl_Open: Opens a VCD device or file and returns an opaque handle
+ *****************************************************************************/
+cddev_t *ioctl_Open( vlc_object_t *p_this, const char *psz_dev )
+{
+ cddev_t *p_cddev;
+
+ if( !psz_dev ) return NULL;
+
+ /*
+ * Initialize structure with default values
+ */
+ p_cddev = (cddev_t *)malloc( sizeof(cddev_t) );
+ if( p_cddev == NULL )
+ {
+ msg_Err( p_this, "out of memory" );
+ return NULL;
+ }
+
+ /* Set where to log errors messages from libcdio. */
+ cdio_log_set_handler ( cd_log_handler );
+
+ p_cddev->cdio = cdio_open(psz_dev, DRIVER_UNKNOWN);
+
+ if( p_cddev->cdio == NULL )
+ {
+ free( p_cddev );
+ p_cddev = NULL;
+ }
+
+ return p_cddev;
+}
+
+/*****************************************************************************
+ * ioctl_Close: Closes an already opened VCD device or file.
+ *****************************************************************************/
+void ioctl_Close( cddev_t *p_cddev )
+{
+ cdio_destroy(p_cddev->cdio);
+}
+
+/*****************************************************************************
+ * ioctl_GetTracksMap: Read the Table of Contents, fill in the pp_sectors map
+ * if pp_sectors is not null and return the number of
+ * tracks available.
+ * We allocate and fill one more track than are on
+ * the CD. The last "track" is leadout track information.
+ * This makes finding the end of the last track uniform
+ * how it is done for other tracks.
+ *****************************************************************************/
+track_t ioctl_GetTracksMap( vlc_object_t *p_this, const CdIo *cdio,
+ lsn_t **pp_sectors )
+{
+ track_t i_tracks = cdio_get_num_tracks(cdio);
+ track_t first_track = cdio_get_first_track_num(cdio);
+ track_t i;
+
+
+ *pp_sectors = malloc( (i_tracks + 1) * sizeof(lsn_t) );
+ if( *pp_sectors == NULL )
+ {
+ msg_Err( p_this, "out of memory" );
+ return 0;
+ }
+
+ /* Fill the p_sectors structure with the track/sector matches.
+ Note cdio_get_track_lsn when given num_tracks + 1 will return
+ the leadout LSN.
+ */
+ for( i = 0 ; i <= i_tracks ; i++ )
+ {
+ (*pp_sectors)[ i ] = cdio_get_track_lsn(cdio, first_track+i);
+ }
+
+ return i_tracks;
+}
+
+/****************************************************************************
+ * ioctl_ReadSector: Read a sector (2324 bytes)
+ ****************************************************************************/
+int ioctl_ReadSector( vlc_object_t *p_this, const cddev_t *p_cddev,
+ int i_sector, byte_t * p_buffer )
+{
+ typedef struct {
+ uint8_t subheader [8];
+ uint8_t data [M2F2_SECTOR_SIZE];
+ } vcdsector_t;
+ vcdsector_t vcd_sector;
+
+ if (cdio_read_mode2_sector(p_cddev->cdio, &vcd_sector, i_sector, true)
+ != 0)
+ {
+ // msg_Err( p_this, "Could not read sector %d", i_sector );
+ return -1;
+ }
+
+ memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
+
+ return( 0 );
+}
+
+/****************************************************************************
+ * Private functions
+ ****************************************************************************/
+
+/* For now we're going to just discard error messages from libcdio... */
+static void
+cd_log_handler (cdio_log_level_t level, const char message[])
+{
+ return;
+}
--- /dev/null
+/****************************************************************************
+ * cdrom.h: cdrom tools header
+ *****************************************************************************
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: cdrom.h,v 1.1 2003/10/04 18:55:13 gbazin Exp $
+ *
+ * Authors: Johan Bilien <jobi@via.ecp.fr>
+ * Gildas Bazin <gbazin@netcourrier.com>
+ *
+ * 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.
+ *****************************************************************************/
+
+#include <cdio/cdio.h>
+#include <cdio/logging.h>
+
+/*****************************************************************************
+ * The cddev structure
+ *****************************************************************************/
+typedef struct cddev_s
+{
+ int *p_sectors; /* tracks layout on the vcd */
+ CdIo *cdio; /* libcdio uses this to read */
+
+} cddev_t;
+
+/*****************************************************************************
+ * Prototypes
+ *****************************************************************************/
+cddev_t *ioctl_Open ( vlc_object_t *, const char * );
+void ioctl_Close ( cddev_t * );
+track_t ioctl_GetTracksMap ( vlc_object_t *, const CdIo *, lsn_t ** );
+int ioctl_ReadSector ( vlc_object_t *, const cddev_t *,
+ int, byte_t * );
--- /dev/null
+/*****************************************************************************
+ * demux.c: demux functions for dvdplay.
+ *****************************************************************************
+ * Copyright (C) 1998-2001 VideoLAN
+ * $Id: demux.c,v 1.1 2003/10/04 18:55: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.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * 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 "vcd.h"
+#include "intf.h"
+
+/* how many packets vcdx_Demux will read in each loop */
+/* #define vcdplay_READ_ONCE 64 */
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int Demux ( input_thread_t * );
+
+/*****************************************************************************
+ * Private structure
+ *****************************************************************************/
+struct demux_sys_t
+{
+ vcd_data_t * p_vcd;
+
+ module_t * p_module;
+ mpeg_demux_t mpeg;
+};
+
+/*****************************************************************************
+ * InitVCD: initializes structures
+ *****************************************************************************/
+int E_(InitVCD) ( vlc_object_t *p_this )
+{
+ input_thread_t *p_input = (input_thread_t *)p_this;
+ vcd_data_t * p_vcd = (vcd_data_t *)p_input->p_access_data;
+ demux_sys_t * p_demux;
+
+ printf("++++ InitVCD CALLED\n");
+
+
+ if( p_input->stream.i_method != INPUT_METHOD_VCD )
+ {
+ 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 );
+ if( p_demux->p_module == NULL )
+ {
+ free( p_input->p_demux_data );
+ return VLC_ENOMOD;
+ }
+
+ p_input->p_demux_data->p_vcd = p_vcd;
+
+ p_input->pf_demux = Demux;
+ p_input->pf_rewind = NULL;
+
+ p_vcd->p_intf = NULL;
+ p_vcd->i_still_time = 0;
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * EndVCD: frees unused data
+ *****************************************************************************/
+void E_(EndVCD) ( vlc_object_t *p_this )
+{
+ input_thread_t *p_input = (input_thread_t *)p_this;
+ vcd_data_t * p_vcd = p_input->p_demux_data->p_vcd;
+ 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_vcd->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 )
+{
+ vcd_data_t * p_vcd;
+ data_packet_t * p_data;
+ ssize_t i_result;
+ ptrdiff_t i_remains;
+ int i_data_nb = 0;
+
+ p_vcd = p_input->p_demux_data->p_vcd;
+
+ /* 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_vcd->b_still && p_vcd->b_end_of_cell && p_vcd->p_intf != NULL )
+ if( p_vcd->i_still_time && p_vcd->b_end_of_cell && p_vcd->p_intf != NULL )
+ {
+ pgrm_descriptor_t * p_pgrm;
+
+ /* when we receive still_time flag, we have to pause immediately */
+ input_SetStatus( p_input, INPUT_STATUS_PAUSE );
+
+ vcdIntfStillTime( p_vcd->p_intf, p_vcd->i_still_time );
+ p_vcd->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;
+}
--- /dev/null
+/*****************************************************************************
+ * intf.c: Video CD interface to handle user interaction and still time
+ *****************************************************************************
+ * Copyright (C) 2002 VideoLAN
+ * $Id: intf.c,v 1.1 2003/10/04 18:55:13 gbazin Exp $
+ *
+ * Authors: Stéphane Borel <stef@via.ecp.fr>
+ * Current modification and breakage for VCD by rocky.
+ *
+ * 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 "vcd.h"
+
+/*****************************************************************************
+ * intf_sys_t: description and status of interface
+ *****************************************************************************/
+struct intf_sys_t
+{
+ input_thread_t * p_input;
+ vcd_data_t * p_vcd;
+
+ vlc_bool_t b_still;
+ vlc_bool_t b_inf_still;
+ mtime_t m_still_time;
+
+#if FINISHED
+ vcdplay_ctrl_t control;
+#else
+ int control;
+#endif
+ 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_(VCDOpenIntf) ( vlc_object_t *p_this )
+{
+ intf_thread_t *p_intf = (intf_thread_t *)p_this;
+
+ printf("+++++Called VCDOpenIntf\n");
+ /* 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;
+
+ 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_(VCDCloseIntf) ( vlc_object_t *p_this )
+{
+ intf_thread_t *p_intf = (intf_thread_t *)p_this;
+
+ /* Destroy structure */
+ free( p_intf->p_sys );
+}
+
+
+/*****************************************************************************
+ * RunIntf: main loop
+ *****************************************************************************/
+static void RunIntf( intf_thread_t *p_intf )
+{
+ vlc_object_t * p_vout = NULL;
+ printf("+++++Called RunIntf\n");
+
+ 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 );
+
+ /*
+ * keyboard event
+ */
+ if( p_vout && p_intf->p_sys->b_key_pressed )
+ {
+ p_intf->p_sys->b_key_pressed = VLC_FALSE;
+
+ printf("++++key pressed...\n");
+ }
+
+ vlc_mutex_unlock( &p_intf->change_lock );
+
+ 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 );
+ var_AddCallback( p_vout, "key-pressed", KeyEvent, p_intf );
+ }
+ }
+
+
+ /* Wait a bit */
+ msleep( INTF_IDLE_SLEEP );
+ }
+
+ 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;
+ vcd_data_t * p_vcd;
+
+ 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_vcd = (vcd_data_t*)p_input->p_access_data;
+ p_vcd->p_intf = p_intf;
+
+ vlc_mutex_lock( &p_intf->change_lock );
+
+ p_intf->p_sys->p_input = p_input;
+ p_intf->p_sys->p_vcd = p_vcd;
+
+ 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 vcdIntfStillTime( intf_thread_t *p_intf, int i_sec )
+{
+ vlc_mutex_lock( &p_intf->change_lock );
+
+ 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;
+ }
+ vlc_mutex_unlock( &p_intf->change_lock );
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * vcdIntfStillTime: function provided to reset still image
+ *****************************************************************************/
+int vcdIntfResetStillTime( intf_thread_t *p_intf )
+{
+ vlc_mutex_lock( &p_intf->change_lock );
+ p_intf->p_sys->m_still_time = 0;
+ input_SetStatus( p_intf->p_sys->p_input, INPUT_STATUS_PLAY );
+ vlc_mutex_unlock( &p_intf->change_lock );
+
+ return VLC_SUCCESS;
+}
--- /dev/null
+/*****************************************************************************
+ * intf.h: send info to intf.
+ *****************************************************************************
+ * Copyright (C) 2001 VideoLAN
+ * $Id: intf.h,v 1.1 2003/10/04 18:55: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 vcdIntfStillTime( struct intf_thread_t *, int );
+int vcdIntfResetStillTime( intf_thread_t *p_intf );
+
--- /dev/null
+/*****************************************************************************
+ * vcd.c : VCD input module for vlc
+ * using libcdio, libvcd and libvcdinfo. vlc-specific things tend
+ * to go here.
+ *****************************************************************************
+ * Copyright (C) 2000 VideoLAN
+ * $Id: vcd.c,v 1.1 2003/10/04 18:55:13 gbazin Exp $
+ *
+ * Authors: Johan Bilien <jobi@via.ecp.fr>
+ * Rocky Bernstein <rocky@panix.com>
+ *
+ * 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 <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include "../../demux/mpeg/system.h"
+#include "vcd.h"
+#include "intf.h"
+#include "vcdplayer.h"
+
+#include <cdio/cdio.h>
+#include <cdio/cd_types.h>
+#include <cdio/logging.h>
+#include <cdio/util.h>
+#include <libvcd/info.h>
+#include <libvcd/logging.h>
+
+#include "cdrom.h"
+
+/* how many blocks VCDRead will read in each loop */
+#define VCD_BLOCKS_ONCE 20
+#define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE)
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+
+/* First those which are accessed from outside (via pointers). */
+static int VCDOpen ( vlc_object_t * );
+static void VCDClose ( vlc_object_t * );
+static int VCDRead ( input_thread_t *, byte_t *, size_t );
+static int VCDRead ( input_thread_t *, byte_t *, size_t );
+static int VCDSetProgram ( input_thread_t *, pgrm_descriptor_t * );
+
+/* Now those which are strictly internal */
+static void VCDSetOrigin ( input_thread_t *, lsn_t origin_lsn,
+ lsn_t cur_lsn, lsn_t end_lsn,
+ int cur_entry, track_t track );
+static int VCDEntryPoints ( input_thread_t * );
+static int VCDLIDs ( input_thread_t * );
+static int VCDSegments ( input_thread_t * );
+static void VCDTracks ( input_thread_t * );
+static int VCDReadSector ( vlc_object_t *p_this,
+ const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn,
+ byte_t * p_buffer );
+static char *VCDParse ( input_thread_t *,
+ /*out*/ vcdinfo_itemid_t * p_itemid );
+
+static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action,
+ const char *varname, const char *label );
+
+static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
+
+static int debug_callback ( vlc_object_t *p_this, const char *psz_name,
+ vlc_value_t oldval, vlc_value_t val,
+ void *p_data );
+
+#define DEBUG_TEXT N_("set debug mask for additional debugging.")
+#define DEBUG_LONGTEXT N_( \
+ "This integer when viewed in binary is a debugging mask\n" \
+ "MRL 1\n" \
+ "external call 2\n" \
+ "all calls 4\n" \
+ "LSN 8\n" \
+ "PBC (10) 16\n" \
+ "libcdio (20) 32\n" \
+ "seeks (40) 64\n" \
+ "still (80) 128\n" \
+ "vcdinfo (100) 256\n" )
+
+/*****************************************************************************
+ * Exported prototypes
+ *****************************************************************************/
+int E_(VCDOpen) ( vlc_object_t * );
+void E_(VCDClose) ( vlc_object_t * );
+int E_(VCDOpenIntf) ( vlc_object_t * );
+void E_(VCDCloseIntf) ( vlc_object_t * );
+int E_(InitVCD) ( vlc_object_t * );
+void E_(EndVCD) ( vlc_object_t * );
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+ add_usage_hint( N_("vcdx:[device-or-file][@{P,S,T}num]") );
+ set_description( _("Video CD (VCD 1.0, 1.1, 2.0, SVCD, HQVCD) input") );
+ set_capability( "access", 85 /* slightly higher than vcd */ );
+ set_callbacks( E_(VCDOpen), E_(VCDClose) );
+ add_shortcut( "vcd" );
+ add_shortcut( "vcdx" );
+
+ /* Configuration options */
+ add_category_hint( N_("VCDX"), NULL, VLC_TRUE );
+ add_integer ( MODULE_STRING "-debug", 0, debug_callback, DEBUG_TEXT,
+ DEBUG_LONGTEXT, VLC_TRUE );
+
+#ifdef FIXED
+ add_submodule();
+ set_capability( "demux", 0 );
+ set_callbacks( E_(InitVCD), E_(EndVCD) );
+#endif
+
+ add_submodule();
+ set_capability( "interface", 0 );
+ set_callbacks( E_(VCDOpenIntf), E_(VCDCloseIntf) );
+vlc_module_end();
+
+/****************************************************************************
+ * Private functions
+ ****************************************************************************/
+/* FIXME: This variable is a hack. Would be nice to eliminate. */
+static input_thread_t *p_vcd_input = NULL;
+
+static int
+debug_callback ( vlc_object_t *p_this, const char *psz_name,
+ vlc_value_t oldval, vlc_value_t val, void *p_data )
+{
+ thread_vcd_data_t *p_vcd;
+
+ if (NULL == p_vcd_input) return VLC_EGENERIC;
+
+ p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
+
+ if (p_vcd->i_debug & (INPUT_DBG_CALL|INPUT_DBG_EXT)) {
+ msg_Dbg( p_vcd_input, "Old debug (x%0x) %d, new debug (x%0x) %d",
+ p_vcd->i_debug, p_vcd->i_debug, val.i_int, val.i_int);
+ }
+ p_vcd->i_debug = val.i_int;
+ return VLC_SUCCESS;
+}
+
+/* process messages that originate from libcdio. */
+static void
+cdio_log_handler (cdio_log_level_t level, const char message[])
+{
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
+ switch (level) {
+ case CDIO_LOG_DEBUG:
+ case CDIO_LOG_INFO:
+ if (p_vcd->i_debug & INPUT_DBG_CDIO)
+ msg_Dbg( p_vcd_input, message);
+ break;
+ case CDIO_LOG_WARN:
+ msg_Warn( p_vcd_input, message);
+ break;
+ case CDIO_LOG_ERROR:
+ case CDIO_LOG_ASSERT:
+ msg_Err( p_vcd_input, message);
+ break;
+ default:
+ msg_Warn( p_vcd_input, message,
+ _("The above message had unknown vcdimager log level"),
+ level);
+ }
+ return;
+}
+
+/* process messages that originate from vcdinfo. */
+static void
+vcd_log_handler (vcd_log_level_t level, const char message[])
+{
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
+ switch (level) {
+ case VCD_LOG_DEBUG:
+ case VCD_LOG_INFO:
+ if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
+ msg_Dbg( p_vcd_input, message);
+ break;
+ case VCD_LOG_WARN:
+ msg_Warn( p_vcd_input, message);
+ break;
+ case VCD_LOG_ERROR:
+ case VCD_LOG_ASSERT:
+ msg_Err( p_vcd_input, message);
+ break;
+ default:
+ msg_Warn( p_vcd_input, "%s\n%s %d", message,
+ _("The above message had unknown vcdimager log level"),
+ level);
+ }
+ return;
+}
+
+/*
+ * Data reading functions
+ */
+
+/*****************************************************************************
+ VCDOpen: open VCD.
+ read in meta-information about VCD: the number of tracks, segments,
+ entries, size and starting information. Then set up state variables so
+ that we read/seek starting at the location specified.
+
+ On success we return VLC_SUCCESS, on memory exhausted VLC_ENOMEM,
+ and VLC_EGENERIC for some other error.
+ *****************************************************************************/
+static int
+VCDOpen( vlc_object_t *p_this )
+{
+ input_thread_t * p_input = (input_thread_t *)p_this;
+ thread_vcd_data_t * p_vcd;
+ char * psz_source;
+ vcdinfo_itemid_t itemid;
+ bool play_ok;
+
+ p_input->pf_read = VCDRead;
+ p_input->pf_seek = VCDSeek;
+ p_input->pf_set_area = VCDSetArea;
+ p_input->pf_set_program = VCDSetProgram;
+
+ p_vcd = malloc( sizeof(thread_vcd_data_t) );
+
+ if( p_vcd == NULL )
+ {
+ LOG_ERR ("out of memory" );
+ return VLC_ENOMEM;
+ }
+
+ p_input->p_access_data = (void *)p_vcd;
+ p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
+ psz_source = VCDParse( p_input, &itemid );
+
+ if ( NULL == psz_source )
+ {
+ free( p_vcd );
+ return( VLC_EGENERIC );
+ }
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "%s", psz_source );
+
+ p_vcd->p_segments = NULL;
+ p_vcd->p_entries = NULL;
+
+ /* set up input */
+ p_input->i_mtu = VCD_DATA_ONCE;
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ /* 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 );
+
+ if( !(p_vcd->vcd = vcd_Open( p_this, psz_source )) )
+ {
+ msg_Warn( p_input, "could not open %s", psz_source );
+ free( psz_source );
+ free( p_vcd );
+ return VLC_EGENERIC;
+ }
+
+ /* Get track information. */
+ p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
+ vcdinfo_get_cd_image(p_vcd->vcd),
+ &p_vcd->p_sectors );
+ free( psz_source );
+ if( p_vcd->num_tracks < 0 )
+ LOG_ERR ("unable to count tracks" );
+ else if( p_vcd->num_tracks <= 1 )
+ LOG_ERR ("no movie tracks found" );
+ if( p_vcd->num_tracks <= 1)
+ {
+ vcdinfo_close( p_vcd->vcd );
+ free( p_vcd );
+ return VLC_EGENERIC;
+ }
+
+ /* Set stream and area data */
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ /* Initialize ES structures */
+ input_InitStream( p_input, sizeof( stream_ps_data_t ) );
+
+ /* disc input method */
+ p_input->stream.i_method = INPUT_METHOD_VCD;
+
+ p_input->stream.i_area_nb = 1;
+
+
+ /* Initialize segment information. */
+ VCDSegments( p_input );
+
+ /* Initialize track area information. */
+ VCDTracks( p_input );
+
+ if( VCDEntryPoints( p_input ) < 0 )
+ {
+ msg_Warn( p_input, "could not read entry points, will not use them" );
+ p_vcd->b_valid_ep = false;
+ }
+
+ if( VCDLIDs( p_input ) < 0 )
+ {
+ msg_Warn( p_input, "could not read entry LIDs" );
+ }
+
+ play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+ if ( ! play_ok ) {
+ vcdinfo_close( p_vcd->vcd );
+ free( p_vcd );
+ return VLC_EGENERIC;
+ }
+
+ if( !p_input->psz_demux || !*p_input->psz_demux )
+ {
+#if FIXED
+ p_input->psz_demux = "vcdx";
+#else
+ p_input->psz_demux = "ps";
+#endif
+ }
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * VCDClose: closes VCD releasing allocated memory.
+ *****************************************************************************/
+static void
+VCDClose( vlc_object_t *p_this )
+{
+ input_thread_t * p_input = (input_thread_t *)p_this;
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
+ vcdinfo_close( p_vcd->vcd );
+
+ free( p_vcd->p_entries );
+ free( p_vcd->p_segments );
+ free( p_vcd );
+ p_vcd_input = NULL;
+}
+
+/*****************************************************************************
+ * VCDRead: reads i_len bytes from the VCD into p_buffer.
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, otherwise the number of
+ * bytes.
+ *****************************************************************************/
+static int
+VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
+{
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+ int i_blocks;
+ int i_index;
+ int i_read;
+ byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
+
+ i_read = 0;
+
+ /* Compute the number of blocks we have to read */
+
+ i_blocks = i_len / M2F2_SECTOR_SIZE;
+
+ for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
+ {
+
+ if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
+ vcdplayer_read_status_t read_status;
+
+ /* We've run off of the end of this entry. Do we continue or stop? */
+ dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
+ "end reached, cur: %u", p_vcd->cur_lsn );
+
+ read_status = vcdplayer_pbc_is_on( p_vcd )
+ ? vcdplayer_pbc_nav( p_input )
+ : vcdplayer_non_pbc_nav( p_input );
+
+ switch (read_status) {
+ case READ_END:
+ /* End reached. Return NULL to indicated this. */
+ case READ_ERROR:
+ /* Some sort of error. */
+ return i_read;
+ case READ_STILL_FRAME:
+ {
+ byte_t * p_buf = p_buffer;
+ p_buf += (i_index*M2F2_SECTOR_SIZE);
+ memset(p_buf, 0, M2F2_SECTOR_SIZE);
+ p_buf += 2;
+ *p_buf = 0x01;
+ dbg_print(INPUT_DBG_STILL, "Handled still event\n");
+ return i_read + M2F2_SECTOR_SIZE;
+ }
+ default:
+ case READ_BLOCK:
+ break;
+ }
+ }
+
+ if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
+ p_vcd->cur_lsn,
+ p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
+ {
+ LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
+ return -1;
+ }
+
+ p_vcd->cur_lsn ++;
+
+ /* Update chapter */
+ if( p_vcd->b_valid_ep &&
+ /* FIXME kludge so that read does not update chapter
+ * when a manual chapter change was requested and not
+ * yet accomplished */
+ !p_input->stream.p_new_area )
+ {
+ unsigned int i_entry = p_input->stream.p_selected_area->i_part;
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+
+ if( i_entry < p_vcd->num_entries &&
+ p_vcd->cur_lsn >= p_vcd->p_entries[i_entry+1] )
+ {
+ dbg_print( INPUT_DBG_PBC,
+ "new entry, i_entry %d, sector %d, es %d",
+ i_entry, p_vcd->cur_lsn,
+ p_vcd->p_entries[i_entry] );
+ p_vcd->play_item.num =
+ ++ p_input->stream.p_selected_area->i_part;
+ p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
+ VCDUpdateVar( p_input, p_vcd->play_item.num, VLC_VAR_SETVALUE,
+ "chapter", "Setting entry" );
+ }
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ }
+
+ i_read += M2F2_SECTOR_SIZE;
+ }
+
+ if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
+ {
+ if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
+ p_vcd->cur_lsn, p_last_sector ) < 0 )
+ {
+ LOG_ERR ("could not read sector %d", p_vcd->cur_lsn );
+ return -1;
+ }
+
+ p_input->p_vlc->pf_memcpy( p_buffer + i_blocks * M2F2_SECTOR_SIZE,
+ p_last_sector, i_len % M2F2_SECTOR_SIZE );
+ i_read += i_len % M2F2_SECTOR_SIZE;
+ }
+
+ return i_read;
+}
+
+
+/*****************************************************************************
+ * VCDSetProgram: Does nothing since a VCD is mono_program
+ *****************************************************************************/
+static int
+VCDSetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_program)
+{
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDSetProgram" );
+ return 0;
+}
+
+
+/*****************************************************************************
+ * VCDSetArea: initialize internal data structures and input stream data
+ so set subsequent reading and seeking to reflect that we are
+ at track x, entry or segment y.
+ This is called for each user navigation request, e.g. the GUI
+ Chapter/Title selections or in initial MRL parsing.
+ ****************************************************************************/
+int
+VCDSetArea( input_thread_t * p_input, input_area_t * p_area )
+{
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t*)p_input->p_access_data;
+ unsigned int i_entry = p_area->i_part;
+ track_t i_track = p_area->i_id;
+ int old_seekable = p_input->stream.b_seekable;
+ unsigned int i_nb = p_area->i_plugin_data + p_area->i_part_nb;
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT),
+ "track: %d, entry %d, seekable %d",
+ i_track, i_entry, old_seekable );
+
+ /* 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 )
+ {
+ unsigned int i;
+
+ /* If is the result of a track change, make the entry valid. */
+ if (i_entry < p_area->i_plugin_data || i_entry >= i_nb)
+ i_entry = p_area->i_plugin_data;
+
+ /* Change the default area */
+ p_input->stream.p_selected_area = p_area;
+
+ /* Update the navigation variables without triggering a callback */
+ VCDUpdateVar( p_input, i_track, VLC_VAR_SETVALUE, "title",
+ "Setting track");
+
+ var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
+ for( i = p_area->i_plugin_data; i < i_nb; i++ )
+ {
+ VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
+ "chapter", "Adding entry choice");
+ }
+ }
+
+ if (i_track == 0)
+ VCDSetOrigin( p_input, p_vcd->p_segments[i_entry],
+ p_vcd->p_segments[i_entry], p_vcd->p_segments[i_entry+1],
+ i_entry, 0 );
+ else
+ VCDSetOrigin( p_input, p_vcd->p_sectors[i_track],
+ vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
+ p_vcd->p_sectors[i_track+1],
+ i_entry, i_track );
+
+ p_input->stream.b_seekable = old_seekable;
+ /* warn interface that something has changed */
+ p_input->stream.b_changed = 1;
+
+ return VLC_SUCCESS;
+}
+
+
+/****************************************************************************
+ * VCDSeek
+ ****************************************************************************/
+void
+VCDSeek( input_thread_t * p_input, off_t i_off )
+{
+ thread_vcd_data_t * p_vcd;
+ unsigned int i_entry=0; /* invalid entry */
+
+ p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+
+ p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+#define p_area p_input->stream.p_selected_area
+ /* Find entry */
+ if( p_vcd->b_valid_ep )
+ {
+ for( i_entry = 1 ; i_entry < p_vcd->num_entries ; i_entry ++ )
+ {
+ if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
+ {
+ VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
+ "chapter", "Setting entry" );
+ break;
+ }
+ }
+ p_vcd->play_item.num = p_area->i_part = i_entry;
+ p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
+ }
+#undef p_area
+
+ p_input->stream.p_selected_area->i_tell = i_off;
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
+ "orig %d, cur: %d, offset: %lld, start: %lld, entry %d",
+ p_vcd->origin_lsn, p_vcd->cur_lsn, i_off,
+ p_input->stream.p_selected_area->i_start, i_entry );
+
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+}
+
+/*****************************************************************************
+ VCDPlay: set up internal structures so seeking/reading places an item.
+ itemid: the thing to play.
+ user_entry: true if itemid is a user selection (rather than internally-
+ generated selection such as via PBC) in which case we may have to adjust
+ for differences in numbering.
+ *****************************************************************************/
+int
+VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
+{
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+ input_area_t * p_area;
+
+ p_vcd->in_still = 0;
+
+#define area p_input->stream.pp_areas
+
+ switch (itemid.type) {
+ case VCDINFO_ITEM_TYPE_TRACK:
+
+ /* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
+ */
+
+ if (itemid.num == 0 || itemid.num >= p_vcd->num_tracks) {
+ LOG_ERR ("Invalid track number %d", itemid.num );
+ return VLC_EGENERIC;
+ }
+ p_area = area[itemid.num];
+ p_area->i_part = p_area->i_plugin_data;
+ p_input->stream.b_seekable = 1;
+ break;
+ case VCDINFO_ITEM_TYPE_SEGMENT:
+ /* Valid segments go from 0...num_segments-1. */
+ if (itemid.num >= p_vcd->num_segments) {
+ LOG_ERR ( "Invalid segment number: %d", itemid.num );
+ return VLC_EGENERIC;
+ } else {
+ vcdinfo_video_segment_type_t segtype =
+ vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
+
+ dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
+ vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
+ (int) segtype, itemid.num);
+
+ p_area = area[0];
+ p_area->i_part = itemid.num;
+
+ switch (segtype)
+ {
+ case VCDINFO_FILES_VIDEO_NTSC_STILL:
+ case VCDINFO_FILES_VIDEO_NTSC_STILL2:
+ case VCDINFO_FILES_VIDEO_PAL_STILL:
+ case VCDINFO_FILES_VIDEO_PAL_STILL2:
+ p_input->stream.b_seekable = 0;
+ p_vcd->in_still = -5;
+ break;
+ default:
+ p_input->stream.b_seekable = 1;
+ p_vcd->in_still = 0;
+ }
+ }
+ break;
+
+ case VCDINFO_ITEM_TYPE_LID:
+ /* LIDs go from 1..num_lids. */
+ if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
+ LOG_ERR ( "Invalid LID number: %d", itemid.num );
+ return VLC_EGENERIC;
+ } else {
+ p_vcd->cur_lid = itemid.num;
+ vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
+
+ switch (p_vcd->pxd.descriptor_type) {
+
+ case PSD_TYPE_SELECTION_LIST:
+ case PSD_TYPE_EXT_SELECTION_LIST: {
+ vcdinfo_itemid_t trans_itemid;
+ uint16_t trans_itemid_num;
+
+ if (p_vcd->pxd.psd == NULL) return VLC_EGENERIC;
+ trans_itemid_num = vcdinf_psd_get_itemid(p_vcd->pxd.psd);
+ vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
+ p_vcd->loop_count = 1;
+ p_vcd->loop_item = trans_itemid;
+ return VCDPlay( p_input, trans_itemid );
+ break;
+ }
+
+ case PSD_TYPE_PLAY_LIST: {
+ if (p_vcd->pxd.pld == NULL) return VLC_EGENERIC;
+ p_vcd->pdi = -1;
+ return vcdplayer_inc_play_item(p_input)
+ ? VLC_SUCCESS : VLC_EGENERIC;
+ break;
+ }
+
+ case PSD_TYPE_END_LIST:
+ case PSD_TYPE_COMMAND_LIST:
+
+ default:
+ ;
+ }
+ }
+ return VLC_EGENERIC;
+ case VCDINFO_ITEM_TYPE_ENTRY:
+ /* Entries go from 0..num_entries-1. */
+ if (itemid.num >= p_vcd->num_entries) {
+ LOG_ERR ("Invalid entry number: %d", itemid.num );
+ return VLC_EGENERIC;
+ } else {
+ track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
+ p_area = area[cur_track];
+ p_area->i_part = itemid.num;
+ p_input->stream.b_seekable = 1;
+ }
+ break;
+ default:
+ LOG_ERR ("unknown entry type" );
+ return VLC_EGENERIC;
+ }
+
+ VCDSetArea( p_input, p_area );
+
+#undef area
+
+ p_vcd->play_item = itemid;
+
+ dbg_print( (INPUT_DBG_CALL),
+ "i_start %lld, i_size: %lld, i_tell: %lld, lsn %d",
+ p_area->i_start, p_area->i_size,
+ p_area->i_tell, p_vcd->cur_lsn );
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ VCDEntryPoints: Reads the information about the entry points on the disc
+ and initializes area information with that.
+ Before calling this track information should have been read in.
+ *****************************************************************************/
+static int
+VCDEntryPoints( input_thread_t * p_input )
+{
+ thread_vcd_data_t * p_vcd;
+ unsigned int i_nb;
+ unsigned int i, i_entry_index = 0;
+ unsigned int i_previous_track = CDIO_INVALID_TRACK;
+
+ p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+
+ i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
+ if (0 == i_nb)
+ return -1;
+
+ p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
+
+ if( p_vcd->p_entries == NULL )
+ {
+ LOG_ERR ("not enough memory for entry points treatment" );
+ return -1;
+ }
+
+ p_vcd->num_entries = 0;
+
+ for( i = 0 ; i < i_nb ; i++ )
+ {
+ track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
+ if( i_track <= p_input->stream.i_area_nb )
+ {
+ p_vcd->p_entries[i] =
+ vcdinfo_get_entry_lsn(p_vcd->vcd, i);
+ p_input->stream.pp_areas[i_track]->i_part_nb ++;
+
+ /* if this entry belongs to a new track */
+ if( i_track != i_previous_track )
+ {
+ /* i_plugin_data is used to store the first entry of the area*/
+ p_input->stream.pp_areas[i_track]->i_plugin_data =
+ i_entry_index;
+ i_previous_track = i_track;
+ p_input->stream.pp_areas[i_track]->i_part_nb = 1;
+ }
+ i_entry_index ++;
+ p_vcd->num_entries ++;
+ }
+ else
+ msg_Warn( p_input, "wrong track number found in entry points" );
+ }
+ p_vcd->b_valid_ep = true;
+ return 0;
+}
+
+/*****************************************************************************
+ * VCDSegments: Reads the information about the segments the disc.
+ *****************************************************************************/
+static int
+VCDSegments( input_thread_t * p_input )
+{
+ thread_vcd_data_t * p_vcd;
+ unsigned int i;
+ unsigned int num_segments;
+
+
+ p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+ num_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
+
+#define area p_input->stream.pp_areas
+
+ /* area 0 is reserved for segments. Set Absolute start offset
+ and size */
+ area[0]->i_plugin_data = 0;
+ input_DelArea( p_input, area[0] );
+ input_AddArea( p_input, 0, 0 );
+
+ area[0]->i_start = (off_t)p_vcd->p_sectors[0]
+ * (off_t)M2F2_SECTOR_SIZE;
+ area[0]->i_size = (off_t)(p_vcd->p_sectors[1] - p_vcd->p_sectors[0])
+ * (off_t)M2F2_SECTOR_SIZE;
+
+ /* Default Segment */
+ area[0]->i_part = 0;
+
+ /* i_plugin_data is used to store which entry point is the first
+ of the track (area) */
+ area[0]->i_plugin_data = 0;
+
+ area[0]->i_part_nb = 0;
+
+ dbg_print( INPUT_DBG_MRL, "area id %d, for segment track %d",
+ area[0]->i_id, 0 );
+
+ if (num_segments == 0) return 0;
+
+ /* We have one additional segment allocated so we can get the size
+ by subtracting seg[i+1] - seg[i].
+ */
+ p_vcd->p_segments = malloc( sizeof( lba_t ) * (num_segments+1) );
+ if( p_vcd->p_segments == NULL )
+ {
+ LOG_ERR ("not enough memory for segment treatment" );
+ return -1;
+ }
+
+ /* Update the navigation variables without triggering a callback */
+ VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", "Setting track" );
+ var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
+
+ for( i = 0 ; i < num_segments ; i++ )
+ {
+ p_vcd->p_segments[i] = vcdinfo_get_seg_lsn(p_vcd->vcd, i);
+ area[0]->i_part_nb ++;
+ VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
+ "chapter", "Adding segment choice");
+ }
+
+#undef area
+
+ p_vcd->p_segments[num_segments] = p_vcd->p_segments[num_segments-1]+
+ vcdinfo_get_seg_sector_count(p_vcd->vcd, num_segments-1);
+
+ return 0;
+}
+
+/*****************************************************************************
+ VCDTracks: initializes area information.
+ Before calling this track information should have been read in.
+ *****************************************************************************/
+static void
+VCDTracks( input_thread_t * p_input )
+{
+ thread_vcd_data_t * p_vcd;
+ unsigned int i;
+
+ p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+
+#define area p_input->stream.pp_areas
+
+ /* We start area addressing for tracks at 1 since the default area 0
+ is reserved for segments */
+
+ for( i = 1 ; i < p_vcd->num_tracks ; i++ )
+ {
+ /* Tracks are Program Chains */
+ input_AddArea( p_input, i, i );
+
+ /* Absolute start byte offset and byte size */
+ area[i]->i_start = (off_t) p_vcd->p_sectors[i]
+ * (off_t)M2F2_SECTOR_SIZE;
+ area[i]->i_size = (off_t)(p_vcd->p_sectors[i+1] - p_vcd->p_sectors[i])
+ * (off_t)M2F2_SECTOR_SIZE;
+
+ /* Current entry being played in track */
+ area[i]->i_part = 0;
+
+ /* i_plugin_data is used to store which entry point is the first
+ * of the track (area) */
+ area[i]->i_plugin_data = 0;
+
+ dbg_print( INPUT_DBG_MRL,
+ "area[%d] id: %d, i_start: %lld, i_size: %lld",
+ i, area[i]->i_id, area[i]->i_start, area[i]->i_size );
+ }
+
+#undef area
+
+ return ;
+}
+
+/*****************************************************************************
+ VCDLIDs: Reads the LIST IDs from the LOT.
+ *****************************************************************************/
+static int
+VCDLIDs( input_thread_t * p_input )
+{
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+
+ p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
+ p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
+
+ if (vcdinfo_read_psd (p_vcd->vcd)) {
+
+ vcdinfo_visit_lot (p_vcd->vcd, false);
+
+ if (vcdinfo_get_psd_x_size(p_vcd->vcd))
+ vcdinfo_visit_lot (p_vcd->vcd, true);
+ }
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
+ "num LIDs=%d", p_vcd->num_lids);
+
+ return 0;
+}
+
+/*****************************************************************************
+ * VCDParse: parse command line
+ *****************************************************************************/
+static char *
+VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid )
+{
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
+ char * psz_parser;
+ char * psz_source;
+ char * psz_next;
+
+ p_itemid->type=VCDINFO_ITEM_TYPE_TRACK;
+ p_itemid->num=1;
+
+#ifdef WIN32
+ /* On Win32 we want the VCD 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
+
+ if( !p_input->psz_name )
+ {
+ return NULL;
+ }
+
+ psz_parser = psz_source = strdup( p_input->psz_name );
+
+ /* Parse input string :
+ * [device][@[type][title]] */
+ while( *psz_parser && *psz_parser != '@' )
+ {
+ psz_parser++;
+ }
+
+ if( *psz_parser == '@' )
+ {
+ /* Found the divide between the source name and the
+ type+entry number. */
+ unsigned int num;
+
+ *psz_parser = '\0';
+ ++psz_parser;
+ if( *psz_parser )
+ {
+ switch(*psz_parser) {
+ case 'E':
+ p_itemid->type = VCDINFO_ITEM_TYPE_ENTRY;
+ ++psz_parser;
+ break;
+ case 'P':
+ p_itemid->type = VCDINFO_ITEM_TYPE_LID;
+ ++psz_parser;
+ break;
+ case 'S':
+ p_itemid->type = VCDINFO_ITEM_TYPE_SEGMENT;
+ ++psz_parser;
+ break;
+ case 'T':
+ p_itemid->type = VCDINFO_ITEM_TYPE_TRACK;
+ ++psz_parser;
+ break;
+ default: ;
+ }
+ }
+
+ num = strtol( psz_parser, &psz_next, 10 );
+ if ( *psz_parser != '\0' && *psz_next == '\0')
+ {
+ p_itemid->num = num;
+ }
+
+ }
+
+ if( !*psz_source ) {
+
+ /* No source specified, so figure it out. */
+ if( !p_input->psz_access ) return NULL;
+
+ psz_source = config_GetPsz( p_input, MODULE_STRING "-device" );
+
+ if( !psz_source ) {
+ /* Scan for a CD with a VCD in it. */
+ char **cd_drives = cdio_get_devices_with_cap(NULL,
+ (CDIO_FS_ANAL_SVCD|CDIO_FS_ANAL_CVD
+ |CDIO_FS_ANAL_VIDEOCD|CDIO_FS_UNKNOWN),
+ true);
+ if (NULL == cd_drives) return NULL;
+ if (cd_drives[0] == NULL) {
+ cdio_free_device_list(cd_drives);
+ return NULL;
+ }
+ psz_source = strdup(cd_drives[0]);
+ cdio_free_device_list(cd_drives);
+ }
+ }
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
+ "source=%s entry=%d type=%d",
+ psz_source, p_itemid->num, p_itemid->type);
+
+ return psz_source;
+}
+
+/*
+ Set's start origin subsequent seeks/reads
+*/
+static void
+VCDSetOrigin( input_thread_t *p_input, lsn_t origin_lsn,
+ lsn_t cur_lsn, lsn_t end_lsn, int cur_entry, track_t cur_track )
+{
+ thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
+
+ p_vcd->origin_lsn = origin_lsn;
+ p_vcd->cur_lsn = cur_lsn;
+ p_vcd->end_lsn = end_lsn;
+ p_vcd->cur_track = cur_track;
+ p_vcd->play_item.num = cur_entry;
+ p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
+ "origin: %d, cur_lsn: %d, end_lsn: %d, entry: %d, track: %d",
+ origin_lsn, cur_lsn, end_lsn, cur_entry, cur_track );
+
+ p_input->stream.p_selected_area->i_tell =
+ (off_t) (p_vcd->cur_lsn - p_vcd->origin_lsn) * (off_t)M2F2_SECTOR_SIZE;
+
+ VCDUpdateVar( p_input, cur_entry, VLC_VAR_SETVALUE,
+ "chapter", "Setting entry");
+}
+
+/*****************************************************************************
+ * vcd_Open: Opens a VCD device or file and returns an opaque handle
+ *****************************************************************************/
+static vcdinfo_obj_t *
+vcd_Open( vlc_object_t *p_this, const char *psz_dev )
+{
+ vcdinfo_obj_t *p_vcdobj;
+ char *actual_dev;
+
+ if( !psz_dev ) return NULL;
+
+ /* Set where to log errors messages from libcdio. */
+ p_vcd_input = (input_thread_t *)p_this;
+ cdio_log_set_handler ( cdio_log_handler );
+ vcd_log_set_handler ( vcd_log_handler );
+
+ actual_dev=strdup(psz_dev);
+ if ( vcdinfo_open(&p_vcdobj, &actual_dev, DRIVER_UNKNOWN, NULL) !=
+ VCDINFO_OPEN_VCD) {
+ free(actual_dev);
+ return NULL;
+ }
+ free(actual_dev);
+
+ return p_vcdobj;
+}
+
+/****************************************************************************
+ * VCDReadSector: Read a sector (2324 bytes)
+ ****************************************************************************/
+static int
+VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
+ lsn_t cur_lsn, byte_t * p_buffer )
+{
+ typedef struct {
+ uint8_t subheader [8];
+ uint8_t data [M2F2_SECTOR_SIZE];
+ } vcdsector_t;
+ vcdsector_t vcd_sector;
+
+ if (cdio_read_mode2_sector(vcdinfo_get_cd_image(p_vcd),
+ &vcd_sector, cur_lsn, true)
+ != 0)
+ {
+ msg_Warn( p_this, "Could not read LSN %d", cur_lsn );
+ return -1;
+ }
+
+ memcpy (p_buffer, vcd_sector.data, M2F2_SECTOR_SIZE);
+
+ return( 0 );
+}
+
+/****************************************************************************
+ Update the "varname" variable to i_num without triggering a callback.
+****************************************************************************/
+static void
+VCDUpdateVar( input_thread_t *p_input, int i_num, int i_action,
+ const char *varname, const char *label)
+{
+ vlc_value_t val;
+ val.i_int = i_num;
+ if (NULL != p_vcd_input) {
+ thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
+ dbg_print( INPUT_DBG_PBC, "%s %d", label, i_num );
+ }
+ var_Change( p_input, varname, i_action, &val, NULL );
+}
--- /dev/null
+/*****************************************************************************
+ * vcd.h : VCD input module for vlc
+ * using libcdio, libvcd and libvcdinfo
+ *****************************************************************************
+ * Copyright (C) 2003 VideoLAN
+ * $Id: vcd.h,v 1.1 2003/10/04 18:55:13 gbazin Exp $
+ *
+ * Authors: Rocky Bernstein <rocky@panix.com>
+ *
+ * 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.
+ *****************************************************************************/
+
+#include <libvcd/info.h>
+
+/*****************************************************************************
+ * dvd_data_t: structure for communication between dvdplay access, demux
+ * and intf.
+ *****************************************************************************/
+
+/*****************************************************************************
+ * vcd_data_t: structure for communication between access and intf.
+ *****************************************************************************/
+typedef struct
+{
+#if FINISHED
+ vcdplay_ptr vmg;
+#endif
+ intf_thread_t * p_intf;
+
+#if DEMUX_FINISHED
+ int i_audio_nb;
+ int i_spu_nb;
+#endif
+
+ int i_still_time;
+ vlc_bool_t b_end_of_cell;
+
+#if FINISHED
+ vcdplay_event_t event;
+ vcdplay_ctrl_t control;
+ vcdplay_highlight_t hli;
+#endif
+
+} vcd_data_t;
+
+int VCDSetArea ( input_thread_t *, input_area_t * );
+void VCDSeek ( input_thread_t *, off_t );
+int VCDPlay ( input_thread_t *, vcdinfo_itemid_t );
--- /dev/null
+/*****************************************************************************
+ * vcdplayer.c : VCD input module for vlc
+ * using libcdio, libvcd and libvcdinfo
+ *****************************************************************************
+ * Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
+ * $Id: vcdplayer.c,v 1.1 2003/10/04 18:55:13 gbazin Exp $
+ *
+ * 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.
+ *****************************************************************************/
+
+/*
+ This contains more of the vlc-independent parts that might be used
+ in any VCD input module for a media player. However at present there
+ are vlc-specific structures. See also vcdplayer.c of the xine plugin.
+ */
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#include "vcd.h"
+#include "vcdplayer.h"
+
+#include <string.h>
+
+#include <cdio/cdio.h>
+#include <cdio/util.h>
+#include <libvcd/info.h>
+
+/*!
+ Return true if playback control (PBC) is on
+*/
+bool
+vcdplayer_pbc_is_on(const thread_vcd_data_t *p_vcd)
+{
+ return VCDINFO_INVALID_ENTRY != p_vcd->cur_lid;
+}
+
+lid_t
+vcdplayer_selection2lid ( input_thread_t *p_input, int entry_num )
+{
+ /* FIXME: Some of this probably gets moved to vcdinfo. */
+ /* Convert selection number to lid and then entry number...*/
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+ unsigned int offset;
+ unsigned int bsn=vcdinf_get_bsn(p_vcd->pxd.psd);
+ vcdinfo_obj_t *obj = p_vcd->vcd;
+
+ dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
+ "Called lid %u, entry_num %d bsn %d", p_vcd->cur_lid,
+ entry_num, bsn);
+
+ if ( (entry_num - bsn + 1) > 0) {
+ offset = vcdinfo_lid_get_offset(obj, p_vcd->cur_lid, entry_num-bsn+1);
+ } else {
+ LOG_ERR( "Selection number %u too small. bsn %u", entry_num, bsn );
+ return VCDINFO_INVALID_LID;
+ }
+
+ if (offset != VCDINFO_INVALID_OFFSET) {
+ vcdinfo_offset_t *ofs;
+ int old = entry_num;
+
+ switch (offset) {
+ case PSD_OFS_DISABLED:
+ LOG_ERR( "Selection %u disabled", entry_num );
+ return VCDINFO_INVALID_LID;
+ case PSD_OFS_MULTI_DEF:
+ LOG_ERR( "Selection %u multi_def", entry_num );
+ return VCDINFO_INVALID_LID;
+ case PSD_OFS_MULTI_DEF_NO_NUM:
+ LOG_ERR( "Selection %u multi_def_no_num", entry_num );
+ return VCDINFO_INVALID_LID;
+ default: ;
+ }
+
+ ofs = vcdinfo_get_offset_t(obj, offset);
+
+ if (NULL == ofs) {
+ LOG_ERR( "error in vcdinfo_get_offset" );
+ return -1;
+ }
+ dbg_print(INPUT_DBG_PBC,
+ "entry %u turned into selection lid %u",
+ old, ofs->lid);
+ return ofs->lid;
+
+ } else {
+ LOG_ERR( "invalid or unset entry %u", entry_num );
+ return VCDINFO_INVALID_LID;
+ }
+}
+
+static void
+vcdplayer_update_entry( input_thread_t * p_input, uint16_t ofs,
+ uint16_t *entry, const char *label)
+{
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+
+ if ( ofs == VCDINFO_INVALID_OFFSET ) {
+ *entry = VCDINFO_INVALID_ENTRY;
+ } else {
+ vcdinfo_offset_t *off_t = vcdinfo_get_offset_t(p_vcd->vcd, ofs);
+ if (off_t != NULL) {
+ *entry = off_t->lid;
+ dbg_print(INPUT_DBG_PBC, "%s: %d\n", label, off_t->lid);
+ } else
+ *entry = VCDINFO_INVALID_ENTRY;
+ }
+}
+
+/* Handles navigation when NOT in PBC reaching the end of a play item.
+
+ The navigations rules here may be sort of made up, but the intent
+ is to do something that's probably right or helpful.
+
+ return true if the caller should return.
+*/
+vcdplayer_read_status_t
+vcdplayer_non_pbc_nav ( input_thread_t * p_input )
+{
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+
+ /* Not in playback control. Do we advance automatically or stop? */
+ switch (p_vcd->play_item.type) {
+ case VCDINFO_ITEM_TYPE_TRACK:
+ case VCDINFO_ITEM_TYPE_ENTRY: {
+ input_area_t *p_area;
+
+ dbg_print( INPUT_DBG_LSN, "new track %d, lsn %d", p_vcd->cur_track,
+ p_vcd->p_sectors[p_vcd->cur_track+1] );
+
+ if ( p_vcd->cur_track >= p_vcd->num_tracks - 1 )
+ return READ_END; /* EOF */
+
+ p_vcd->play_item.num = p_vcd->cur_track++;
+
+ vlc_mutex_lock( &p_input->stream.stream_lock );
+ p_area = p_input->stream.pp_areas[p_vcd->cur_track];
+
+ p_area->i_part = 1;
+ VCDSetArea( p_input, p_area );
+ vlc_mutex_unlock( &p_input->stream.stream_lock );
+ return READ_BLOCK;
+ break;
+ }
+ case VCDINFO_ITEM_TYPE_SPAREID2:
+ dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
+ "SPAREID2" );
+ /* FIXME */
+ p_input->stream.b_seekable = 0;
+ if (p_vcd->in_still)
+ {
+ return READ_STILL_FRAME ;
+ }
+ return READ_END;
+ case VCDINFO_ITEM_TYPE_NOTFOUND:
+ LOG_ERR ("NOTFOUND outside PBC -- not supposed to happen");
+ return READ_ERROR;
+ case VCDINFO_ITEM_TYPE_LID:
+ LOG_ERR ("LID outside PBC -- not supposed to happen");
+ return READ_ERROR;
+ case VCDINFO_ITEM_TYPE_SEGMENT:
+ /* Hack: Just go back and do still again */
+ /* FIXME */
+ p_input->stream.b_seekable = 0;
+ if (p_vcd->in_still)
+ {
+ dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
+ "End of Segment - looping" );
+ return READ_STILL_FRAME;
+ }
+ return READ_END;
+ }
+ return READ_BLOCK;
+}
+
+/* FIXME: Will do whatever the right thing is later. */
+#define SLEEP_1_SEC_AND_HANDLE_EVENTS sleep(1)
+
+/* Handles PBC navigation when reaching the end of a play item. */
+vcdplayer_read_status_t
+vcdplayer_pbc_nav ( input_thread_t * p_input )
+{
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+
+ /* We are in playback control. */
+ vcdinfo_itemid_t itemid;
+
+ if (0 != p_vcd->in_still && p_vcd->in_still != -5) {
+ SLEEP_1_SEC_AND_HANDLE_EVENTS;
+ if (p_vcd->in_still > 0) p_vcd->in_still--;
+ return READ_STILL_FRAME;
+ }
+
+ /* The end of an entry is really the end of the associated
+ sequence (or track). */
+
+ if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type) &&
+ (p_vcd->cur_lsn < p_vcd->end_lsn) ) {
+ /* Set up to just continue to the next entry */
+ p_vcd->play_item.num++;
+ dbg_print( (INPUT_DBG_LSN|INPUT_DBG_PBC),
+ "continuing into next entry: %u", p_vcd->play_item.num);
+ VCDPlay( p_input, p_vcd->play_item );
+ /* p_vcd->update_title(); */
+ return READ_BLOCK;
+ }
+
+ switch (p_vcd->pxd.descriptor_type) {
+ case PSD_TYPE_END_LIST:
+ return READ_END;
+ break;
+ case PSD_TYPE_PLAY_LIST: {
+ int wait_time = vcdinf_get_wait_time(p_vcd->pxd.pld);
+
+ dbg_print(INPUT_DBG_PBC, "playlist wait_time: %d", wait_time);
+
+ if (vcdplayer_inc_play_item(p_input))
+ return READ_BLOCK;
+
+ /* Handle any wait time given. */
+ if (-5 == p_vcd->in_still) {
+ if (wait_time != 0) {
+ /* FIXME */
+ p_vcd->in_still = wait_time - 1;
+ SLEEP_1_SEC_AND_HANDLE_EVENTS ;
+ return READ_STILL_FRAME;
+ }
+ }
+ vcdplayer_update_entry( p_input,
+ vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
+ &itemid.num, "next" );
+ itemid.type = VCDINFO_ITEM_TYPE_LID;
+ VCDPlay( p_input, itemid );
+ break;
+ }
+ case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
+ case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
+ {
+ int wait_time = vcdinf_get_timeout_time(p_vcd->pxd.psd);
+ uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcd->pxd.psd);
+ uint16_t max_loop = vcdinf_get_loop_count(p_vcd->pxd.psd);
+ vcdinfo_offset_t *offset_timeout_LID =
+ vcdinfo_get_offset_t(p_vcd->vcd, timeout_offs);
+
+ dbg_print(INPUT_DBG_PBC, "wait_time: %d, looped: %d, max_loop %d",
+ wait_time, p_vcd->loop_count, max_loop);
+
+ /* Handle any wait time given */
+ if (-5 == p_vcd->in_still) {
+ p_vcd->in_still = wait_time - 1;
+ SLEEP_1_SEC_AND_HANDLE_EVENTS ;
+ return READ_STILL_FRAME;
+ }
+
+ /* Handle any looping given. */
+ if ( max_loop == 0 || p_vcd->loop_count < max_loop ) {
+ p_vcd->loop_count++;
+ if (p_vcd->loop_count == 0x7f) p_vcd->loop_count = 0;
+ VCDSeek( p_input, 0 );
+ /* if (p_vcd->in_still) p_vcd->force_redisplay();*/
+ return READ_BLOCK;
+ }
+
+ /* Looping finished and wait finished. Move to timeout
+ entry or next entry, or handle still. */
+
+ if (NULL != offset_timeout_LID) {
+ /* Handle timeout_LID */
+ itemid.num = offset_timeout_LID->lid;
+ itemid.type = VCDINFO_ITEM_TYPE_LID;
+ dbg_print(INPUT_DBG_PBC, "timeout to: %d", itemid.num);
+ VCDPlay( p_input, itemid );
+ return READ_BLOCK;
+ } else {
+ int num_selections = vcdinf_get_num_selections(p_vcd->pxd.psd);
+ if (num_selections > 0) {
+ /* Pick a random selection. */
+ unsigned int bsn=vcdinf_get_bsn(p_vcd->pxd.psd);
+ int rand_selection=bsn +
+ (int) ((num_selections+0.0)*rand()/(RAND_MAX+1.0));
+ lid_t rand_lid=vcdplayer_selection2lid (p_input, rand_selection);
+ itemid.num = rand_lid;
+ itemid.type = VCDINFO_ITEM_TYPE_LID;
+ dbg_print(INPUT_DBG_PBC, "random selection %d, lid: %d",
+ rand_selection - bsn, rand_lid);
+ VCDPlay( p_input, itemid );
+ return READ_BLOCK;
+ } else if (p_vcd->in_still) {
+ /* Hack: Just go back and do still again */
+ SLEEP_1_SEC_AND_HANDLE_EVENTS ;
+ return READ_STILL_FRAME;
+ }
+ }
+ break;
+ }
+ case VCDINFO_ITEM_TYPE_NOTFOUND:
+ LOG_ERR( "NOTFOUND in PBC -- not supposed to happen" );
+ break;
+ case VCDINFO_ITEM_TYPE_SPAREID2:
+ LOG_ERR( "SPAREID2 in PBC -- not supposed to happen" );
+ break;
+ case VCDINFO_ITEM_TYPE_LID:
+ LOG_ERR( "LID in PBC -- not supposed to happen" );
+ break;
+
+ default:
+ ;
+ }
+ /* FIXME: Should handle autowait ... */
+
+ return READ_ERROR;
+}
+
+/*
+ Get the next play-item in the list given in the LIDs. Note play-item
+ here refers to list of play-items for a single LID It shouldn't be
+ confused with a user's list of favorite things to play or the
+ "next" field of a LID which moves us to a different LID.
+ */
+bool
+vcdplayer_inc_play_item( input_thread_t *p_input )
+{
+ thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
+
+ int noi;
+
+ dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcd->pdi);
+
+ if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return false;
+
+ noi = vcdinf_pld_get_noi(p_vcd->pxd.pld);
+
+ if ( noi <= 0 ) return false;
+
+ /* Handle delays like autowait or wait here? */
+
+ p_vcd->pdi++;
+
+ if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return false;
+
+ else {
+ uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld,
+ p_vcd->pdi);
+ vcdinfo_itemid_t trans_itemid;
+
+ if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
+
+ vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
+ dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
+ p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num));
+ return VLC_SUCCESS == VCDPlay( p_input, trans_itemid );
+ }
+}
--- /dev/null
+/*****************************************************************************
+ * Copyright (C) 2003 Rocky Bernstein (for VideoLAN)
+ * $Id: vcdplayer.h,v 1.1 2003/10/04 18:55:13 gbazin Exp $
+ *
+ * Authors: Rocky Bernstein <rocky@panix.com>
+ *
+ * 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.
+ *****************************************************************************/
+
+/* VCD Player header. More or less media-player independent */
+
+#ifndef _VCDPLAYER_H_
+#define _VCDPLAYER_H_
+
+#include <libvcd/info.h>
+
+#define INPUT_DBG_MRL 1
+#define INPUT_DBG_EXT 2 /* Calls from external routines */
+#define INPUT_DBG_CALL 4 /* all calls */
+#define INPUT_DBG_LSN 8 /* LSN changes */
+#define INPUT_DBG_PBC 16 /* Playback control */
+#define INPUT_DBG_CDIO 32 /* Debugging from CDIO */
+#define INPUT_DBG_SEEK 64 /* Seeks to set location */
+#define INPUT_DBG_STILL 128 /* Still-frame */
+#define INPUT_DBG_VCDINFO 256 /* Debugging from VCDINFO */
+
+#define INPUT_DEBUG 1
+#if INPUT_DEBUG
+#define dbg_print(mask, s, args...) \
+ if (p_vcd->i_debug & mask) \
+ msg_Dbg(p_input, "%s: "s, __func__ , ##args)
+#else
+#define dbg_print(mask, s, args...)
+#endif
+
+#define LOG_ERR(args...) msg_Err( p_input, args )
+
+/* vcdplayer_read return status */
+typedef enum {
+ READ_BLOCK,
+ READ_STILL_FRAME,
+ READ_ERROR,
+ READ_END,
+} vcdplayer_read_status_t;
+
+/*****************************************************************************
+ * thread_vcd_data_t: VCD information
+ *****************************************************************************/
+typedef struct thread_vcd_data_s
+{
+ vcdinfo_obj_t *vcd; /* CD device descriptor */
+ int in_still; /* 0 if not in still,
+ -2 if in infinite loop
+ -5 if a still but haven't
+ read wait time yet
+ >0 number of seconds yet to
+ wait */
+ unsigned int num_tracks; /* Nb of tracks (titles) */
+ unsigned int num_segments; /* Nb of segments */
+ unsigned int num_entries; /* Nb of entries */
+ unsigned int num_lids; /* Nb of List IDs */
+ vcdinfo_itemid_t play_item; /* play-item, VCDPLAYER_BAD_ENTRY
+ if none */
+ int cur_lid; /* LID that play item is in. Implies
+ PBC is on. VCDPLAYER_BAD_ENTRY if
+ not none or not in PBC */
+ PsdListDescriptor pxd; /* If PBC is on, the relevant
+ PSD/PLD */
+ int pdi; /* current pld index of pxd. -1 if
+ no index*/
+ vcdinfo_itemid_t loop_item; /* Where do we loop back to?
+ Meaningful only in a selection
+ list */
+ int loop_count; /* # of times play-item has been
+ played. Meaningful only in a
+ selection list. */
+ track_t cur_track; /* Current track number */
+ lsn_t cur_lsn; /* Current logical sector number */
+ lsn_t end_lsn; /* LSN of end of current
+ entry/segment/track. */
+ lsn_t origin_lsn; /* LSN of start of seek/slider */
+ lsn_t * p_sectors; /* Track sectors */
+ lsn_t * p_entries; /* Entry points */
+ lsn_t * p_segments; /* Segments */
+ bool b_valid_ep; /* Valid entry points flag */
+ vlc_bool_t b_end_of_track; /* If the end of track was reached */
+ int i_debug; /* Debugging mask */
+
+} thread_vcd_data_t;
+
+bool vcdplayer_inc_play_item( input_thread_t *p_input );
+bool vcdplayer_pbc_is_on(const thread_vcd_data_t *p_this);
+
+vcdplayer_read_status_t vcdplayer_pbc_nav ( input_thread_t * p_input );
+vcdplayer_read_status_t vcdplayer_non_pbc_nav ( input_thread_t * p_input );
+lid_t vcdplayer_selection2lid ( input_thread_t *p_input, int entry_num ) ;
+
+#endif /* _VCDPLAYER_H_ */
+/*
+ * Local variables:
+ * c-file-style: "gnu"
+ * tab-width: 8
+ * indent-tabs-mode: nil
+ * End:
+ */