Commit 27fdfcfd authored by Rocky Bernstein's avatar Rocky Bernstein

First attempt to libcdio VCD working under new regime. It is still

mostly disabled or broken.
parent 2cbb6002
......@@ -2,11 +2,11 @@ SOURCES_vcdx = \
access.c \
cdrom.c \
cdrom.h \
demux.c \
intf.c \
intf.h \
vcd.c \
vcd.h \
vcdplayer.h \
vcdplayer.c \
info.c \
info.h \
$(NULL)
......@@ -7,7 +7,8 @@
* $Id$
*
* Authors: Rocky Bernstein <rocky@panix.com>
* Johan Bilien <jobi@via.ecp.fr>
* Some code is based on the non-libcdio VCD plugin (as there really
* isn't real documentation yet.)
*
* 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
......@@ -29,13 +30,14 @@
*****************************************************************************/
#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/intf.h>
#include <vlc/input.h>
#include "../../demux/mpeg/system.h"
#include "vcd.h"
#include "vcdplayer.h"
#include "intf.h"
#include "info.h"
#include "vlc_keys.h"
#include <cdio/cdio.h>
#include <cdio/cd_types.h>
......@@ -48,34 +50,37 @@
/* how many blocks VCDRead will read in each loop */
#define VCD_BLOCKS_ONCE 20
#define VCD_DATA_ONCE (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE)
#define VCD_MRL_PREFIX "vcdx://"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
/* First those which are accessed from outside (via pointers). */
static int VCDRead ( input_thread_t *, byte_t *, size_t );
static int VCDSetProgram ( input_thread_t *, pgrm_descriptor_t * );
static block_t *VCDReadBlock ( access_t * );
static int VCDControl ( access_t *p_access, int i_query,
va_list args );
/* 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 void VCDSetOrigin ( access_t *p_access,
lsn_t origin_lsn,
lsn_t i_lsn, lsn_t end_lsn,
track_t track,
const vcdinfo_itemid_t * p_itemid );
static int VCDEntryPoints ( access_t * );
static int VCDLIDs ( access_t * );
#ifdef FIXED
static int VCDSegments ( access_t * );
#endif
static int VCDTitles ( access_t * );
static int VCDReadSector ( vlc_object_t *p_this,
const vcdinfo_obj_t *p_vcd, lsn_t cur_lsn,
const vcdinfo_obj_t *p_vcd, lsn_t i_lsn,
byte_t * p_buffer );
static char *VCDParse ( input_thread_t *,
static char *VCDParse ( access_t *,
/*out*/ vcdinfo_itemid_t * p_itemid ,
/*out*/ vlc_bool_t *play_single_item );
static void VCDUpdateVar( input_thread_t *p_input, int i_entry, int i_action,
static void VCDUpdateVar( access_t *p_access, int i_entry, int i_action,
const char *p_varname, char *p_label,
const char *p_debug_label );
......@@ -88,28 +93,28 @@ static vcdinfo_obj_t *vcd_Open ( vlc_object_t *p_this, const char *psz_dev );
/* FIXME: This variable is a hack. Would be nice to eliminate the
global-ness. */
static input_thread_t *p_vcd_input = NULL;
static access_t *p_vcd_access = NULL;
/* 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;
const access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
switch (level) {
case CDIO_LOG_DEBUG:
case CDIO_LOG_INFO:
if (p_vcd->i_debug & INPUT_DBG_CDIO)
msg_Dbg( p_vcd_input, message);
msg_Dbg( p_vcd_access, message);
break;
case CDIO_LOG_WARN:
msg_Warn( p_vcd_input, message);
msg_Warn( p_vcd_access, message);
break;
case CDIO_LOG_ERROR:
case CDIO_LOG_ASSERT:
msg_Err( p_vcd_input, message);
msg_Err( p_vcd_access, message);
break;
default:
msg_Warn( p_vcd_input, message,
msg_Warn( p_vcd_access, message,
_("The above message had unknown log level"),
level);
}
......@@ -120,22 +125,22 @@ cdio_log_handler (cdio_log_level_t level, const char message[])
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;
access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
switch (level) {
case VCD_LOG_DEBUG:
case VCD_LOG_INFO:
if (p_vcd->i_debug & INPUT_DBG_VCDINFO)
msg_Dbg( p_vcd_input, message);
msg_Dbg( p_vcd_access, message);
break;
case VCD_LOG_WARN:
msg_Warn( p_vcd_input, message);
msg_Warn( p_vcd_access, message);
break;
case VCD_LOG_ERROR:
case VCD_LOG_ASSERT:
msg_Err( p_vcd_input, message);
msg_Err( p_vcd_access, message);
break;
default:
msg_Warn( p_vcd_input, "%s\n%s %d", message,
msg_Warn( p_vcd_access, "%s\n%s %d", message,
_("The above message had unknown vcdimager log level"),
level);
}
......@@ -143,16 +148,15 @@ vcd_log_handler (vcd_log_level_t level, const char message[])
}
/*****************************************************************************
* 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.
VCDRead: reads VCD_BLOCKS_ONCE from the VCD and returns that.
NULL is returned if something went wrong.
*****************************************************************************/
static int
VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
static block_t *
VCDReadBlock( access_t * p_access )
{
thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
int i_blocks;
access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
block_t *p_block;
int i_blocks = VCD_BLOCKS_ONCE;
int i_index;
int i_read;
byte_t p_last_sector[ M2F2_SECTOR_SIZE ];
......@@ -160,40 +164,47 @@ VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
i_read = 0;
dbg_print( (INPUT_DBG_CALL), "lsn: %lu",
(long unsigned int) p_vcd->cur_lsn );
(long unsigned int) p_vcd->i_lsn );
/* Compute the number of blocks we have to read */
i_blocks = i_len / M2F2_SECTOR_SIZE;
i_blocks = VCD_BLOCKS_ONCE ;
/* Allocate a block for the reading */
if( !( p_block = block_New( p_access, i_blocks * M2F2_SECTOR_SIZE ) ) )
{
msg_Err( p_access, "cannot get a new block of size: %i",
i_blocks * M2F2_SECTOR_SIZE );
block_Release( p_block );
return NULL;
}
for ( i_index = 0 ; i_index < i_blocks ; i_index++ )
{
if ( p_vcd->cur_lsn == p_vcd->end_lsn ) {
if ( p_vcd->i_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: %lu",
(long unsigned int) p_vcd->cur_lsn );
(long unsigned int) p_vcd->i_lsn );
read_status = vcdplayer_pbc_is_on( p_vcd )
? vcdplayer_pbc_nav( p_input )
: vcdplayer_non_pbc_nav( p_input );
? vcdplayer_pbc_nav( p_access )
: vcdplayer_non_pbc_nav( p_access );
switch (read_status) {
case READ_END:
/* End reached. Return NULL to indicated this. */
case READ_ERROR:
/* Some sort of error. */
return i_read;
return NULL;
case READ_STILL_FRAME:
{
/* Reached the end of a still frame. */
byte_t * p_buf = p_buffer;
pgrm_descriptor_t * p_pgrm = p_input->stream.p_selected_program;;
byte_t * p_buf = (byte_t *) p_block->p_buffer;
p_buf += (i_index*M2F2_SECTOR_SIZE);
memset(p_buf, 0, M2F2_SECTOR_SIZE);
......@@ -201,24 +212,10 @@ VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
*p_buf = 0x01;
dbg_print(INPUT_DBG_STILL, "Handled still event");
#if 1
p_vcd->p_intf->p_sys->b_still = 1;
var_SetInteger( p_input, "state", PAUSE_S );
#endif
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 );
p_vcd->p_intf->p_sys->b_still = 1;
var_SetInteger( p_input, "state", PAUSE_S );
p_vcd->p_intf->p_sys->b_still = VLC_TRUE;
var_SetInteger( p_access, "state", PAUSE_S );
return i_read + M2F2_SECTOR_SIZE;
return p_block;
}
default:
case READ_BLOCK:
......@@ -226,206 +223,115 @@ VCDRead( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
}
}
if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
p_vcd->cur_lsn,
p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
p_vcd->i_lsn,
(byte_t *) p_block->p_buffer + (i_index*M2F2_SECTOR_SIZE) ) < 0 )
{
LOG_ERR ("could not read sector %lu",
(long unsigned int) p_vcd->cur_lsn );
return -1;
(long unsigned int) p_vcd->i_lsn );
return NULL;
}
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 %lu, es %u",
i_entry, (long unsigned int) 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", _("Entry"), "Setting entry" );
}
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
p_vcd->i_lsn ++;
i_read += M2F2_SECTOR_SIZE;
}
if ( i_len % M2F2_SECTOR_SIZE ) /* this should not happen */
if ( i_index != i_blocks ) /* this should not happen */
{
if ( VCDReadSector( VLC_OBJECT(p_input), p_vcd->vcd,
p_vcd->cur_lsn, p_last_sector ) < 0 )
if ( VCDReadSector( VLC_OBJECT(p_access), p_vcd->vcd,
p_vcd->i_lsn, p_last_sector ) < 0 )
{
LOG_ERR ("could not read sector %lu",
(long unsigned int) p_vcd->cur_lsn );
return -1;
(long unsigned int) p_vcd->i_lsn );
}
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 NULL;
}
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, area %lx, select area %lx ",
i_track, i_entry, old_seekable,
(long unsigned int) p_area,
(long unsigned int) p_input->stream.p_selected_area );
/* 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",
_("Track"), "Setting track");
var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
for( i = p_area->i_plugin_data; i < i_nb; i++ )
/* Update seekpoints */
for( i_read = 0; i_read < i_blocks; i_read++ )
{
VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
"chapter",
p_vcd->play_item.type == VCDINFO_ITEM_TYPE_SEGMENT ?
_("Segment"): _("Entry"),
"Adding entry choice");
}
input_title_t *t = p_vcd->p_title[p_access->info.i_title];
if (p_vcd->b_svd) {
unsigned int audio_type =
vcdinfo_get_track_audio_type(p_vcd->vcd, i_track);
unsigned int i_channels =
vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type);
var_Change( p_input, "audio_channels", VLC_VAR_CLEARCHOICES, NULL,
NULL );
for( i = 0; i < i_channels; i++ )
if( t->i_seekpoint > 0 &&
p_access->info.i_seekpoint + 1 < t->i_seekpoint &&
p_access->info.i_pos + i_read * M2F2_SECTOR_SIZE >=
t->seekpoint[p_access->info.i_seekpoint+1]->i_byte_offset )
{
VCDUpdateVar( p_input, i , VLC_VAR_ADDCHOICE,
"audio_channels", NULL, "Adding audio choice");
msg_Dbg( p_access, "seekpoint change" );
p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
p_access->info.i_seekpoint++;
}
}
}
/* Update a few values */
p_vcd->i_lsn += i_blocks;
p_access->info.i_pos += p_block->i_buffer;
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;
return p_block;
}
/****************************************************************************
* VCDSeek
****************************************************************************/
void
VCDSeek( input_thread_t * p_input, off_t i_off )
int
VCDSeek( access_t * p_access, int64_t i_pos )
{
thread_vcd_data_t * p_vcd;
unsigned int i_entry=0; /* invalid entry */
if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
{
access_vcd_data_t *p_vcd =
(access_vcd_data_t *)p_vcd_access->p_sys;
const input_title_t *t = p_vcd->p_title[p_access->info.i_title];
int i_seekpoint;
unsigned int i_entry=VCDINFO_INVALID_ENTRY;
p_vcd->cur_lsn = p_vcd->origin_lsn + (i_off / (off_t)M2F2_SECTOR_SIZE);
/* Next sector to read */
p_access->info.i_pos = i_pos;
p_vcd->i_lsn = (i_pos / (int64_t)M2F2_SECTOR_SIZE) +
p_vcd->origin_lsn;
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 = 0 ; i_entry < p_vcd->num_entries ; i_entry ++ )
for( i_entry = 0 ; i_entry < p_vcd->i_entries ; i_entry ++ )
{
if( p_vcd->cur_lsn < p_vcd->p_entries[i_entry] )
if( p_vcd->i_lsn < p_vcd->p_entries[i_entry] )
{
VCDUpdateVar( p_input, i_entry, VLC_VAR_SETVALUE,
VCDUpdateVar( p_access, i_entry, VLC_VAR_SETVALUE,
"chapter", _("Entry"), "Setting entry" );
break;
}
}
p_vcd->play_item.num = p_area->i_part = i_entry;
p_vcd->play_item.num = i_entry;
p_vcd->play_item.type = VCDINFO_ITEM_TYPE_ENTRY;
}
#undef p_area
p_input->stream.p_selected_area->i_tell = i_off;
/* Find seekpoint */
for( i_seekpoint = 0; i_seekpoint < t->i_seekpoint; i_seekpoint++ )
{
if( i_seekpoint + 1 >= t->i_seekpoint ) break;
if( i_pos < t->seekpoint[i_seekpoint + 1]->i_byte_offset ) break;
}
/* Update current seekpoint */
if( i_seekpoint != p_access->info.i_seekpoint )
{
msg_Dbg( p_access, "seekpoint change" );
p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
p_access->info.i_seekpoint = i_seekpoint;
}
dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_SEEK),
"orig %lu, cur: %lu, offset: %lld, start: %lld, entry %d",
"orig %lu, cur: %lu, offset: %lld, entry %d",
(long unsigned int) p_vcd->origin_lsn,
(long unsigned int) p_vcd->cur_lsn, i_off,
p_input->stream.p_selected_area->i_start, i_entry );
(long unsigned int) p_vcd->i_lsn, i_pos,
i_entry );
}
return VLC_SUCCESS;
vlc_mutex_unlock( &p_input->stream.stream_lock );
}
/*****************************************************************************
......@@ -436,75 +342,86 @@ VCDSeek( input_thread_t * p_input, off_t i_off )
for differences in numbering.
*****************************************************************************/
int
VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
VCDPlay( access_t *p_access, vcdinfo_itemid_t itemid )
{
thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
input_area_t * p_area;
vlc_bool_t b_was_still;
if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
itemid.num, itemid.type);
if (!p_input->p_access_data) return VLC_EGENERIC;
{
b_was_still = p_vcd->in_still;
access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
#if 0
const vlc_bool_t b_was_still = p_vcd->in_still;
#endif
#define area p_input->stream.pp_areas
dbg_print(INPUT_DBG_CALL, "itemid.num: %d, itemid.type: %d\n",
itemid.num, itemid.type);
switch (itemid.type) {
case VCDINFO_ITEM_TYPE_TRACK:
/* Valid tracks go from 1...num_tracks-1, because track 0 is unplayable.
*/
{
track_t i_track = itemid.num;
unsigned int i_entry =
vcdinfo_track_get_entry( p_vcd->vcd, i_track);
/* Valid tracks go from 1...i_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 );
if (i_track == 0 || i_track >= p_vcd->i_tracks) {
LOG_ERR ("Invalid track number %d", i_track );
return VLC_EGENERIC;
}
p_vcd->in_still = VLC_FALSE;
p_area = area[itemid.num];
p_area->i_part = p_area->i_plugin_data;
p_input->stream.b_seekable = 1;
VCDSetOrigin( p_access, p_vcd->p_sectors[i_track],
vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
p_vcd->p_sectors[i_track+1],
i_track, &itemid );
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 );
{
int i_seg = itemid.num;
/* Valid segments go from 0...i_segments-1. */
if (itemid.num >= p_vcd->i_segments) {
LOG_ERR ( "Invalid segment number: %d", i_seg );
return VLC_EGENERIC;
} else {
vcdinfo_video_segment_type_t segtype =
vcdinfo_get_video_type(p_vcd->vcd, itemid.num);
vcdinfo_get_video_type(p_vcd->vcd, i_seg);
dbg_print(INPUT_DBG_PBC, "%s (%d), seg_num: %d",
vcdinfo_video_type2str(p_vcd->vcd, itemid.num),
vcdinfo_video_type2str(p_vcd->vcd, i_seg),
(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 = VLC_TRUE;
break;
default:
p_input->stream.b_seekable = 1;
p_vcd->in_still = VLC_FALSE;
}
VCDSetOrigin( p_access, p_vcd->p_segments[i_seg],
p_vcd->p_segments[i_seg],
p_vcd->p_segments[i_seg+1],
0, &itemid );
}
}
break;
case VCDINFO_ITEM_TYPE_LID:
/* LIDs go from 1..num_lids. */
if (itemid.num == 0 || itemid.num > p_vcd->num_lids) {
/* LIDs go from 1..i_lids. */
if (itemid.num == 0 || itemid.num > p_vcd->i_lids) {
LOG_ERR ( "Invalid LID number: %d", itemid.num );
return VLC_EGENERIC;
} else {
p_vcd->cur_lid = itemid.num;
p_vcd->i_lid = itemid.num;
vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), itemid.num);
switch (p_vcd->pxd.descriptor_type) {
......@@ -519,14 +436,14 @@ VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
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 );
return VCDPlay( p_access, 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)
return vcdplayer_inc_play_item(p_access)
? VLC_SUCCESS : VLC_EGENERIC;
break;
}
......@@ -540,42 +457,33 @@ VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
}
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 );
{
int i_entry = itemid.num;
/* Entries go from 0..i_entries-1. */
if (itemid.num >= p_vcd->i_entries) {
LOG_ERR ("Invalid entry number: %d", i_entry );
return VLC_EGENERIC;
} else {
track_t cur_track = vcdinfo_get_track(p_vcd->vcd, itemid.num);
track_t i_track = vcdinfo_get_track(p_vcd->vcd, i_entry);
p_vcd->in_still = VLC_FALSE;
p_area = area[cur_track];
p_area->i_part = itemid.num;
p_input->stream.b_seekable = 1;
VCDSetOrigin( p_access, p_vcd->p_sectors[i_track],
vcdinfo_get_entry_lsn(p_vcd->vcd, i_entry),
p_vcd->p_sectors[i_track+1],
i_track, &itemid );
}
break;
}
default:
LOG_ERR ("unknown entry type" );
return VLC_EGENERIC;
}
VCDSetArea( p_input, p_area );
#undef area
p_vcd->play_item = itemid;
#if 1
if ( p_vcd->in_still != b_was_still ) {
if (p_input->stream.pp_selected_es) {
var_SetInteger( p_input, "state", PLAYING_S );
}
}
#endif
p_vcd->play_item = itemid;
dbg_print( (INPUT_DBG_CALL),
"i_start %lld, i_size: %lld, i_tell: %lld, lsn %lu",
p_area->i_start, p_area->i_size,
p_area->i_tell,
(long unsigned int) p_vcd->cur_lsn );
return VLC_SUCCESS;
}
......@@ -586,78 +494,81 @@ VCDPlay( input_thread_t *p_input, vcdinfo_itemid_t itemid )
Before calling this track information should have been read in.
*****************************************************************************/
static int
VCDEntryPoints( input_thread_t * p_input )
VCDEntryPoints( access_t * p_access )
{
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;
if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
{
access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
const unsigned int i_entries = vcdinfo_get_num_entries(p_vcd->vcd);
const track_t i_last_track
= cdio_get_num_tracks(vcdinfo_get_cd_image(p_vcd->vcd))
+ cdio_get_first_track_num(vcdinfo_get_cd_image(p_vcd->vcd));
unsigned int i;
i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
if (0 == i_nb)
return -1;
if (0 == i_entries) {
LOG_ERR ("no entires found -- something is wrong" );
return VLC_EGENERIC;
}
p_vcd->p_entries = malloc( sizeof( lba_t ) * i_nb );
p_vcd->p_entries = malloc( sizeof( lsn_t ) * i_entries );
if( p_vcd->p_entries == NULL )
{
LOG_ERR ("not enough memory for entry points treatment" );
return -1;
return VLC_EGENERIC;
}
p_vcd->num_entries = 0;
p_vcd->i_entries = i_entries;
for( i = 0 ; i < i_nb ; i++ )
for( i = 0 ; i < i_entries ; 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 ++;
const track_t i_track = vcdinfo_get_track(p_vcd->vcd, i);
if( i_track <= i_last_track ) {
seekpoint_t *s = vlc_seekpoint_New();
char psz_entry[100];
/* 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" );
snprintf(psz_entry, sizeof(psz_entry), "%s%02d", _("Entry "), i );
p_vcd->p_entries[i] = vcdinfo_get_entry_lsn(p_vcd->vcd, i);
s->psz_name = strdup(psz_entry);
s->i_byte_offset = (p_vcd->p_entries[i] - p_vcd->p_sectors[i_track])
* M2F2_SECTOR_SIZE;
TAB_APPEND( p_vcd->p_title[i_track-1]->i_seekpoint,
p_vcd->p_title[i_track-1]->seekpoint, s );
} else
msg_Warn( p_access, "wrong track number found in entry points" );
}
p_vcd->b_valid_ep = VLC_TRUE;
return 0;
}
}
/*????? FIXME!!! */
#ifdef FIXED
/*****************************************************************************
* VCDSegments: Reads the information about the segments the disc.
*****************************************************************************/
static int
VCDSegments( input_thread_t * p_input )
VCDSegments( access_t * p_access )
{
thread_vcd_data_t * p_vcd;
access_vcd_data_t * p_vcd;
unsigned int i;
unsigned int num_segments;
unsigned int i_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);
p_vcd = (access_vcd_data_t *) p_access->p_sys;
i_segments = p_vcd->num_segments = vcdinfo_get_num_segments(p_vcd->vcd);
#define area p_input->stream.pp_areas
#define area p_access->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 );
input_DelArea( p_access, area[0] );
input_AddArea( p_access, 0, 0 );
area[0]->i_start = (off_t)p_vcd->p_sectors[0]
* (off_t)M2F2_SECTOR_SIZE;
......@@ -677,12 +588,12 @@ VCDSegments( input_thread_t * p_input )
"area[0] id: %d, i_start: %lld, i_size: %lld",
area[0]->i_id, area[0]->i_start, area[0]->i_size );
if (num_segments == 0) return 0;
if (i_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) );
p_vcd->p_segments = malloc( sizeof( lsn_t ) * (i_segments+1) );
if( p_vcd->p_segments == NULL )
{
LOG_ERR ("not enough memory for segment treatment" );
......@@ -690,82 +601,85 @@ VCDSegments( input_thread_t * p_input )
}
/* Update the navigation variables without triggering a callback */
VCDUpdateVar( p_input, 0, VLC_VAR_SETVALUE, "title", _("Track"),
VCDUpdateVar( p_access, 0, VLC_VAR_SETVALUE, "title", _("Track"),
"Setting track" );
var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
var_Change( p_access, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
for( i = 0 ; i < num_segments ; i++ )
for( i = 0 ; i < i_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,
VCDUpdateVar( p_access, i , VLC_VAR_ADDCHOICE,
"chapter", _("Segment"), "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);
p_vcd->p_segments[i_segments] = p_vcd->p_segments[i_segments-1]+
vcdinfo_get_seg_sector_count(p_vcd->vcd, i_segments-1);
return 0;
}
#endif
/*****************************************************************************
VCDTracks: initializes area information.
Before calling this track information should have been read in.
Build title table which will be returned via ACCESS_GET_TITLE_INFO.
We start area addressing for tracks at 1 since the default area 0
is reserved for segments.
*****************************************************************************/
static void
VCDTracks( input_thread_t * p_input )
static int
VCDTitles( access_t * p_access )
{
thread_vcd_data_t * p_vcd;
unsigned int i;
p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
/* We'll assume a VCD has its first MPEG track
cdio_get_first_track_num()+1 could be used if one wanted to be
very careful about this. Note: cdio_get_first_track() will give the
ISO-9660 track before the MPEG tracks.
*/
const unsigned int i_first_mpeg_track=2;
#define area p_input->stream.pp_areas
if (!p_access || !p_access->p_sys) return VLC_EGENERIC;
/* We start area addressing for tracks at 1 since the default area 0
is reserved for segments */
{
access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
track_t i;
for( i = 1 ; i < p_vcd->num_tracks ; i++ )
p_vcd->i_titles = 0;
for( i = 2 ; i <= p_vcd->i_tracks ; i++ )
{
/* Tracks are Program Chains */
input_AddArea( p_input, i, i );
input_title_t *t = p_vcd->p_title[i - i_first_mpeg_track]
= vlc_input_title_New();
char psz_track[100];
uint32_t i_secsize =
cdio_get_track_sec_count( vcdinfo_get_cd_image(p_vcd->vcd), 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;
snprintf(psz_track, sizeof(psz_track), "%s%02d", _("Track "),
i-1 );
/* Current entry being played in track */
area[i]->i_part = 0;
t->i_size = (i_secsize) * (int64_t) M2F2_SECTOR_SIZE;
t->psz_name = strdup(psz_track);
/* 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, "track[%d] i_size: %lld",
i, t->i_size );
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 );
p_vcd->i_titles++;
}
#undef area
return ;
return VLC_SUCCESS;
}
}
/*****************************************************************************
VCDLIDs: Reads the LIST IDs from the LOT.
*****************************************************************************/
static int
VCDLIDs( input_thread_t * p_input )
VCDLIDs( access_t * p_access )
{
thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
p_vcd->num_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
p_vcd->cur_lid = VCDINFO_INVALID_ENTRY;
p_vcd->i_lids = vcdinfo_get_num_LIDs(p_vcd->vcd);
p_vcd->i_lid = VCDINFO_INVALID_ENTRY;
if (vcdinfo_read_psd (p_vcd->vcd)) {
......@@ -784,7 +698,7 @@ VCDLIDs( input_thread_t * p_input )
}
dbg_print( (INPUT_DBG_CALL|INPUT_DBG_MRL),
"num LIDs=%d", p_vcd->num_lids);
"num LIDs=%d", p_vcd->i_lids);
return 0;
}
......@@ -793,15 +707,15 @@ VCDLIDs( input_thread_t * p_input )
* VCDParse: parse command line
*****************************************************************************/
static char *
VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid,
VCDParse( access_t * p_access, /*out*/ vcdinfo_itemid_t * p_itemid,
/*out*/ vlc_bool_t *play_single_item )
{
thread_vcd_data_t *p_vcd = (thread_vcd_data_t *)p_input->p_access_data;
access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_access->p_sys;
char * psz_parser;
char * psz_source;
char * psz_next;
if( config_GetInt( p_input, MODULE_STRING "-PBC" ) ) {
if( config_GetInt( p_access, MODULE_STRING "-PBC" ) ) {
p_itemid->type = VCDINFO_ITEM_TYPE_LID;
p_itemid->num = 1;
*play_single_item = VLC_FALSE;
......@@ -815,15 +729,15 @@ VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid,
#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;
if( !p_access->psz_access || !*p_access->psz_access ) return NULL;
#endif
if( !p_input->psz_name )
if( !p_access->psz_path )
{
return NULL;
}
psz_parser = psz_source = strdup( p_input->psz_name );
psz_parser = psz_source = strdup( p_access->psz_path );
/* Parse input string :
* [device][@[type][title]] */
......@@ -881,9 +795,9 @@ VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid,
if( !*psz_source ) {
/* No source specified, so figure it out. */
if( !p_input->psz_access ) return NULL;
if( !p_access->psz_access ) return NULL;
psz_source = config_GetPsz( p_input, "vcd" );
psz_source = config_GetPsz( p_access, "vcd" );
if( !psz_source || 0==strlen(psz_source) ) {
/* Scan for a CD-ROM drive with a VCD in it. */
......@@ -913,30 +827,33 @@ VCDParse( input_thread_t * p_input, /*out*/ vcdinfo_itemid_t * p_itemid,
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 )
VCDSetOrigin( access_t *p_access, lsn_t origin_lsn,
lsn_t i_lsn, lsn_t end_lsn, track_t i_track,
const vcdinfo_itemid_t *p_itemid )
{
thread_vcd_data_t * p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
p_vcd->origin_lsn = origin_lsn;
p_vcd->cur_lsn = cur_lsn;
p_vcd->i_lsn = i_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;
p_vcd->i_track = i_track;
p_vcd->play_item.num = p_itemid->num;
p_vcd->play_item.type = p_itemid->type;
p_access->info.i_title = i_track-1;
p_access->info.i_seekpoint = p_itemid->num;
p_access->info.i_size = p_vcd->p_title[i_track]->i_size;
p_access->info.i_pos = ( i_lsn - origin_lsn ) * M2F2_SECTOR_SIZE;
dbg_print( (INPUT_DBG_CALL|INPUT_DBG_LSN),
"origin: %lu, cur_lsn: %lu, end_lsn: %lu, entry: %d, track: %d",
"origin: %lu, cur_lsn: %lu, end_lsn: %lu, track: %d",
(long unsigned int) origin_lsn,
(long unsigned int) cur_lsn,
(long unsigned int) end_lsn, cur_entry, cur_track );
(long unsigned int) i_lsn,
(long unsigned int) end_lsn, i_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,
VCDUpdateVar( p_access, p_itemid->num, VLC_VAR_SETVALUE,
"chapter",
p_vcd->play_item.type == VCDINFO_ITEM_TYPE_ENTRY ?
p_itemid->type == VCDINFO_ITEM_TYPE_ENTRY ?
_("Entry") : _("Segment"),
"Setting entry/segment");
}
......@@ -968,21 +885,21 @@ vcd_Open( vlc_object_t *p_this, const char *psz_dev )
****************************************************************************/
static int
VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
lsn_t cur_lsn, byte_t * p_buffer )
lsn_t i_lsn, byte_t * p_buffer )
{
typedef struct {
uint8_t subheader [8];
uint8_t subheader [CDIO_CD_SUBHEADER_SIZE];
uint8_t data [M2F2_SECTOR_SIZE];
uint8_t spare [4];
} vcdsector_t;
vcdsector_t vcd_sector;
if( cdio_read_mode2_sector( vcdinfo_get_cd_image( p_vcd ),
&vcd_sector, cur_lsn, VLC_TRUE )
&vcd_sector, i_lsn, VLC_TRUE )
!= 0)
{
msg_Warn( p_this, "Could not read LSN %lu",
(long unsigned int) cur_lsn );
(long unsigned int) i_lsn );
return -1;
}
......@@ -995,399 +912,24 @@ VCDReadSector( vlc_object_t *p_this, const vcdinfo_obj_t *p_vcd,
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,
VCDUpdateVar( access_t *p_access, int i_num, int i_action,
const char *p_varname, char *p_label,
const char *p_debug_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;
if (p_access) {
const access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
dbg_print( INPUT_DBG_PBC, "%s %d", p_debug_label, i_num );
}
if (p_label) {
vlc_value_t text;
text.psz_string = p_label;
var_Change( p_input, p_varname, VLC_VAR_SETTEXT, &text, NULL );
}
var_Change( p_input, p_varname, i_action, &val, NULL );
}
static inline void
MetaInfoAddStr(input_thread_t *p_input, char *p_cat,
char *title, const char *str)
{
thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
if ( str ) {
dbg_print( INPUT_DBG_META, "field: %s: %s\n", title, str);
input_Control( p_input, INPUT_ADD_INFO, p_cat, title, "%s", str);
}
}
static inline void
MetaInfoAddNum(input_thread_t *p_input, char *p_cat, char *title, int num)
{
thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
dbg_print( INPUT_DBG_META, "field %s: %d\n", title, num);
input_Control( p_input, INPUT_ADD_INFO, p_cat, title, "%d", num );
}
#define addstr(title, str) \
MetaInfoAddStr( p_input, p_cat, title, str );
#define addnum(title, num) \
MetaInfoAddNum( p_input, p_cat, title, num );
static void InformationCreate( input_thread_t *p_input )
{
thread_vcd_data_t *p_vcd = (thread_vcd_data_t *) p_input->p_access_data;
unsigned int i_nb = vcdinfo_get_num_entries(p_vcd->vcd);
unsigned int last_entry = 0;
char *p_cat;
track_t i_track;
p_cat = _("General");
addstr( _("VCD Format"), vcdinfo_get_format_version_str(p_vcd->vcd) );
addstr( _("Album"), vcdinfo_get_album_id(p_vcd->vcd));
addstr( _("Application"), vcdinfo_get_application_id(p_vcd->vcd) );
addstr( _("Preparer"), vcdinfo_get_preparer_id(p_vcd->vcd) );
addnum( _("Vol #"), vcdinfo_get_volume_num(p_vcd->vcd) );
addnum( _("Vol max #"), vcdinfo_get_volume_count(p_vcd->vcd) );
addstr( _("Volume Set"), vcdinfo_get_volumeset_id(p_vcd->vcd) );
addstr( _("Volume"), vcdinfo_get_volume_id(p_vcd->vcd) );
addstr( _("Publisher"), vcdinfo_get_publisher_id(p_vcd->vcd) );
addstr( _("System Id"), vcdinfo_get_system_id(p_vcd->vcd) );
addnum( "LIDs", vcdinfo_get_num_LIDs(p_vcd->vcd) );
addnum( _("Entries"), vcdinfo_get_num_entries(p_vcd->vcd) );
addnum( _("Segments"), vcdinfo_get_num_segments(p_vcd->vcd) );
addnum( _("Tracks"), vcdinfo_get_num_tracks(p_vcd->vcd) );
/* Spit out track information. Could also include MSF info.
*/
#define TITLE_MAX 30
for( i_track = 1 ; i_track < p_vcd->num_tracks ; i_track++ ) {
char psz_track[TITLE_MAX];
unsigned int audio_type = vcdinfo_get_track_audio_type(p_vcd->vcd,
i_track);
snprintf(psz_track, TITLE_MAX, "%s%02d", _("Track "), i_track);
p_cat = psz_track;
if (p_vcd->b_svd) {
addnum(_("Audio Channels"),
vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type) );
}
addnum(_("First Entry Point"), last_entry );
for ( ; last_entry < i_nb
&& vcdinfo_get_track(p_vcd->vcd, last_entry) == i_track;
last_entry++ ) ;
addnum(_("Last Entry Point"), last_entry-1 );
}
}
#define add_format_str_info(val) \
{ \
const char *str = val; \
unsigned int len; \
if (val != NULL) { \
len=strlen(str); \
if (len != 0) { \
strncat(tp, str, TEMP_STR_LEN-(tp-temp_str)); \
tp += len; \
} \
saw_control_prefix = VLC_FALSE; \
} \
}
#define add_format_num_info( val, fmt ) \
{ \
char num_str[10]; \
unsigned int len; \
sprintf(num_str, fmt, val); \
len = strlen(num_str); \
if( len != 0 ) \
{ \
strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str)); \
tp += len; \
} \
saw_control_prefix = VLC_FALSE; \
}
/*!
Take a format string and expand escape sequences, that is sequences that
begin with %, with information from the current VCD.
The expanded string is returned. Here is a list of escape sequences:
%A : The album information
%C : The VCD volume count - the number of CD's in the collection.
%c : The VCD volume num - the number of the CD in the collection.
%F : The VCD Format, e.g. VCD 1.0, VCD 1.1, VCD 2.0, or SVCD
%I : The current entry/segment/playback type, e.g. ENTRY, TRACK, SEGMENT...
%L : The playlist ID prefixed with " LID" if it exists
%M : MRL
%N : The current number of the %I - a decimal number
%P : The publisher ID
%p : The preparer ID
%S : If we are in a segment (menu), the kind of segment
%T : The track number
%V : The volume set ID
%v : The volume ID
A number between 1 and the volume count.
%% : a %
*/
static char *
VCDFormatStr(const input_thread_t *p_input, thread_vcd_data_t *p_vcd,
const char format_str[], const char *mrl,
const vcdinfo_itemid_t *itemid)
{
#define TEMP_STR_SIZE 256
#define TEMP_STR_LEN (TEMP_STR_SIZE-1)
static char temp_str[TEMP_STR_SIZE];
size_t i;
char * tp = temp_str;
vlc_bool_t saw_control_prefix = VLC_FALSE;
size_t format_len = strlen(format_str);
memset(temp_str, 0, TEMP_STR_SIZE);
for (i=0; i<format_len; i++) {
if (!saw_control_prefix && format_str[i] != '%') {
*tp++ = format_str[i];
saw_control_prefix = VLC_FALSE;
continue;
}
switch(format_str[i]) {
case '%':
if (saw_control_prefix) {
*tp++ = '%';
}
saw_control_prefix = !saw_control_prefix;
break;
case 'A':
add_format_str_info(vcdinfo_strip_trail(vcdinfo_get_album_id(p_vcd->vcd),
MAX_ALBUM_LEN));
break;
case 'c':
add_format_num_info(vcdinfo_get_volume_num(p_vcd->vcd), "%d");
break;
case 'C':
add_format_num_info(vcdinfo_get_volume_count(p_vcd->vcd), "%d");
break;
case 'F':
add_format_str_info(vcdinfo_get_format_version_str(p_vcd->vcd));
break;
case 'I':
{
switch (itemid->type) {
case VCDINFO_ITEM_TYPE_TRACK:
strncat(tp, _("Track"), TEMP_STR_LEN-(tp-temp_str));
tp += strlen(_("Track"));
break;
case VCDINFO_ITEM_TYPE_ENTRY:
strncat(tp, _("Entry"), TEMP_STR_LEN-(tp-temp_str));
tp += strlen(_("Entry"));
break;
case VCDINFO_ITEM_TYPE_SEGMENT:
strncat(tp, _("Segment"), TEMP_STR_LEN-(tp-temp_str));
tp += strlen(_("Segment"));
break;
case VCDINFO_ITEM_TYPE_LID:
strncat(tp, _("List ID"), TEMP_STR_LEN-(tp-temp_str));
tp += strlen(_("List ID"));
break;
case VCDINFO_ITEM_TYPE_SPAREID2:
strncat(tp, _("Navigation"), TEMP_STR_LEN-(tp-temp_str));
tp += strlen(_("Navigation"));
break;
default:
/* What to do? */
;
}
saw_control_prefix = VLC_FALSE;
var_Change( p_access, p_varname, VLC_VAR_SETTEXT, &text, NULL );
}
break;
case 'L':
if (vcdplayer_pbc_is_on(p_vcd)) {
char num_str[40];
sprintf(num_str, "%s %d", _("List ID"), p_vcd->cur_lid);
strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));
tp += strlen(num_str);
}
saw_control_prefix = VLC_FALSE;
break;
case 'M':
add_format_str_info(mrl);
break;
case 'N':
add_format_num_info(itemid->num, "%d");
break;
case 'p':
add_format_str_info(vcdinfo_get_preparer_id(p_vcd->vcd));
break;
case 'P':
add_format_str_info(vcdinfo_get_publisher_id(p_vcd->vcd));
break;
case 'S':
if ( VCDINFO_ITEM_TYPE_SEGMENT==itemid->type ) {
char seg_type_str[10];
sprintf(seg_type_str, " %s",
vcdinfo_video_type2str(p_vcd->vcd, itemid->num));
strncat(tp, seg_type_str, TEMP_STR_LEN-(tp-temp_str));
tp += strlen(seg_type_str);
}
saw_control_prefix = VLC_FALSE;
break;
case 'T':
add_format_num_info(p_vcd->cur_track, "%d");
break;
case 'V':
add_format_str_info(vcdinfo_get_volumeset_id(p_vcd->vcd));
break;
case 'v':
add_format_str_info(vcdinfo_get_volume_id(p_vcd->vcd));
break;
default:
*tp++ = '%';
*tp++ = format_str[i];
saw_control_prefix = VLC_FALSE;
}
}
return strdup(temp_str);
}
static void
VCDCreatePlayListItem(const input_thread_t *p_input,
thread_vcd_data_t *p_vcd,
playlist_t *p_playlist,
const vcdinfo_itemid_t *itemid,
char *psz_mrl, int psz_mrl_max,
const char *psz_source, int playlist_operation,
int i_pos)
{
char *p_author;
char *p_title;
char c_type;
switch(itemid->type) {
case VCDINFO_ITEM_TYPE_TRACK:
c_type='T';
break;
case VCDINFO_ITEM_TYPE_SEGMENT:
c_type='S';
break;
case VCDINFO_ITEM_TYPE_LID:
c_type='P';
break;
case VCDINFO_ITEM_TYPE_ENTRY:
c_type='E';
break;
default:
c_type='?';
break;
}
snprintf(psz_mrl, psz_mrl_max, "%s%s@%c%u", VCD_MRL_PREFIX, psz_source,
c_type, itemid->num);
p_title =
VCDFormatStr( p_input, p_vcd,
config_GetPsz( p_input, MODULE_STRING "-title-format" ),
psz_mrl, itemid );
playlist_Add( p_playlist, psz_mrl, p_title, playlist_operation, i_pos );
p_author =
VCDFormatStr( p_input, p_vcd,
config_GetPsz( p_input, MODULE_STRING "-author-format" ),
psz_mrl, itemid );
if( i_pos == PLAYLIST_END ) i_pos = p_playlist->i_size - 1;
playlist_AddInfo(p_playlist, i_pos, _("General"), _("Author"), "%s",
p_author);
var_Change( p_access, p_varname, i_action, &val, NULL );
}
static int
VCDFixupPlayList( input_thread_t *p_input, thread_vcd_data_t *p_vcd,
const char *psz_source, vcdinfo_itemid_t *itemid,
vlc_bool_t play_single_item )
{
unsigned int i;
playlist_t * p_playlist;
char * psz_mrl;
unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) +
strlen("@T") + strlen("100") + 1;
psz_mrl = malloc( psz_mrl_max );
if( psz_mrl == NULL )
{
msg_Warn( p_input, "out of memory" );
return -1;
}
p_playlist = (playlist_t *) vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( !p_playlist )
{
msg_Warn( p_input, "can't find playlist" );
free(psz_mrl);
return -1;
}
if ( play_single_item )
{
/* May fill out more information when the playlist user interface becomes
more mature.
*/
VCDCreatePlayListItem(p_input, p_vcd, p_playlist, itemid,
psz_mrl, psz_mrl_max, psz_source, PLAYLIST_REPLACE,
p_playlist->i_index);
}
else
{
vcdinfo_itemid_t list_itemid;
list_itemid.type=VCDINFO_ITEM_TYPE_ENTRY;
playlist_LockDelete( p_playlist, p_playlist->i_index);
for( i = 0 ; i < p_vcd->num_entries ; i++ )
{
list_itemid.num=i;
VCDCreatePlayListItem(p_input, p_vcd, p_playlist, &list_itemid,
psz_mrl, psz_mrl_max, psz_source,
PLAYLIST_APPEND, PLAYLIST_END);
}
playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
}
vlc_object_release( p_playlist );
free(psz_mrl);
return 0;
}
/*****************************************************************************
* Public routines.
......@@ -1396,14 +938,14 @@ int
E_(DebugCallback) ( 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;
access_vcd_data_t *p_vcd;
if (NULL == p_vcd_input) return VLC_EGENERIC;
if (NULL == p_vcd_access) return VLC_EGENERIC;
p_vcd = (thread_vcd_data_t *)p_vcd_input->p_access_data;
p_vcd = (access_vcd_data_t *)p_vcd_access->p_sys;
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",
msg_Dbg( p_vcd_access, "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;
......@@ -1411,35 +953,8 @@ E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
}
/*
The front-ends change spu-es - which sort of represents a symbolic
name. Internally we use spu-channel which runs from 0..3.
So we add a callback to intercept changes to spu-es and change them
to updates to spu-channel. Ugly.
*/
static int
VCDSPUCallback( vlc_object_t *p_this, const char *psz_variable,
vlc_value_t old_val, vlc_value_t new_val, void *param)
{
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;
vlc_value_t val;
dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EVENT), "old_val: %x, new_val %x",
old_val.i_int, new_val.i_int);
val.i_int = new_val.i_int;
var_Set( p_this, "spu-channel", val );
return VLC_SUCCESS;
}
/*****************************************************************************
Open: open VCD.
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.
......@@ -1448,21 +963,28 @@ VCDSPUCallback( vlc_object_t *p_this, const char *psz_variable,
and VLC_EGENERIC for some other error.
*****************************************************************************/
int
E_(Open) ( vlc_object_t *p_this )
E_(VCDOpen) ( vlc_object_t *p_this )
{
input_thread_t * p_input = (input_thread_t *)p_this;
thread_vcd_data_t * p_vcd;
access_t * p_access = (access_t *)p_this;
access_vcd_data_t * p_vcd;
char * psz_source;
vcdinfo_itemid_t itemid;
vlc_bool_t b_play_ok;
vlc_bool_t play_single_item = VLC_FALSE;
p_input->pf_read = VCDRead;
p_input->pf_seek = VCDSeek;
p_input->pf_set_area = VCDSetArea;
p_input->pf_set_program = VCDSetProgram;
p_access->pf_read = NULL;
p_access->pf_block = VCDReadBlock;
p_access->pf_control = VCDControl;
p_access->pf_seek = VCDSeek;
p_vcd = malloc( sizeof(thread_vcd_data_t) );
p_access->info.i_update = 0;
p_access->info.i_size = 0;
p_access->info.i_pos = 0;
p_access->info.b_eof = VLC_FALSE;
p_access->info.i_title = 0;
p_access->info.i_seekpoint = 0;
p_vcd = malloc( sizeof(access_vcd_data_t) );
if( p_vcd == NULL )
{
......@@ -1470,17 +992,21 @@ E_(Open) ( vlc_object_t *p_this )
return VLC_ENOMEM;
}
p_input->p_access_data = (void *)p_vcd;
p_access->p_sys = (access_sys_t *) p_vcd;
p_vcd->i_debug = config_GetInt( p_this, MODULE_STRING "-debug" );
p_vcd->in_still = VLC_FALSE;
p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT,
FIND_PARENT );
p_vcd->p_meta = vlc_meta_New();
/* Set where to log errors messages from libcdio. */
p_vcd_input = (input_thread_t *)p_this;
p_vcd_access = p_access;
cdio_log_set_handler ( cdio_log_handler );
vcd_log_set_handler ( vcd_log_handler );
psz_source = VCDParse( p_input, &itemid, &play_single_item );
psz_source = VCDParse( p_access, &itemid, &play_single_item );
if ( NULL == psz_source )
{
......@@ -1489,108 +1015,85 @@ E_(Open) ( vlc_object_t *p_this )
}
dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "source: %s: mrl: %s",
psz_source, p_input->psz_name );
psz_source, p_access->psz_path );
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 );
msg_Warn( p_access, "could not open %s", psz_source );
goto err_exit;
}
p_vcd->b_svd= (vlc_bool_t) vcdinfo_get_tracksSVD(p_vcd->vcd);;
/* Get track information. */
p_vcd->num_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_input),
p_vcd->i_tracks = ioctl_GetTracksMap( VLC_OBJECT(p_access),
vcdinfo_get_cd_image(p_vcd->vcd),
&p_vcd->p_sectors );
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)
{
if( p_vcd->i_tracks <= 1 ) {
vcdinfo_close( p_vcd->vcd );
LOG_ERR ("no movie tracks found" );
goto err_exit;
}
/* 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;
#ifdef FIXED
/* Initialize segment information. */
VCDSegments( p_input );
VCDSegments( p_access );
#endif
/* Initialize track area information. */
VCDTracks( p_input );
/* Build Navigation Title table. */
VCDTitles( p_access );
if( VCDEntryPoints( p_input ) < 0 )
/* Map entry points into Chapters */
if( VCDEntryPoints( p_access ) < 0 )
{
msg_Warn( p_input, "could not read entry points, will not use them" );
msg_Warn( p_access, "could not read entry points, will not use them" );
p_vcd->b_valid_ep = VLC_FALSE;
}
if( VCDLIDs( p_input ) < 0 )
if( VCDLIDs( p_access ) < 0 )
{
msg_Warn( p_input, "could not read entry LIDs" );
msg_Warn( p_access, "could not read entry LIDs" );
}
b_play_ok = (VLC_SUCCESS == VCDPlay( p_input, itemid ));
vlc_mutex_unlock( &p_input->stream.stream_lock );
#if FIXED
b_play_ok = (VLC_SUCCESS == VCDPlay( p_access, itemid ));
if ( ! b_play_ok ) {
vcdinfo_close( p_vcd->vcd );
goto err_exit;
}
if( !p_input->psz_demux || !*p_input->psz_demux )
{
#if FIXED
p_input->psz_demux = "vcdx";
#else
p_input->psz_demux = "ps";
/* We assume playing CD track 2 (1st MPEG data) for now */
p_vcd->origin_lsn = p_vcd->i_lsn = p_vcd->p_sectors[1];
p_access->info.i_title = 0;
p_access->info.i_seekpoint = 0;
p_access->info.i_size = p_vcd->p_title[0]->i_size;
p_access->info.i_pos = 0;
#endif
}
p_vcd->p_intf = intf_Create( p_input, "vcdx" );
p_access->psz_demux = strdup( "ps" );
#if FIXED
p_vcd->p_intf = intf_Create( p_access, "vcdx" );
p_vcd->p_intf->b_block = VLC_FALSE;
intf_RunThread( p_vcd->p_intf );
#endif
InformationCreate( p_input );
#if FIXED
if (play_single_item)
VCDFixupPlayList( p_input, p_vcd, psz_source, &itemid,
VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
play_single_item );
#endif
free( psz_source );
var_AddCallback( p_this, "spu-es", VCDSPUCallback, NULL );
free( psz_source );
return VLC_SUCCESS;
err_exit:
......@@ -1600,17 +1103,16 @@ E_(Open) ( vlc_object_t *p_this )
}
/*****************************************************************************
* Close: closes VCD releasing allocated memory.
* VCDClose: closes VCD releasing allocated memory.
*****************************************************************************/
void
E_(Close) ( vlc_object_t *p_this )
E_(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;
access_t *p_access = (access_t *)p_this;
access_vcd_data_t *p_vcd = (access_vcd_data_t *)p_access->p_sys;
dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT), "VCDClose" );
var_DelCallback( p_this, "spu-es", VCDSPUCallback, NULL );
vcdinfo_close( p_vcd->vcd );
free( p_vcd->p_entries );
......@@ -1627,6 +1129,164 @@ E_(Close) ( vlc_object_t *p_this )
}
free( p_vcd );
p_input->p_access_data = NULL;
p_vcd_input = NULL;
p_access->p_sys = NULL;
p_vcd_access = NULL;
}
/*****************************************************************************
* Control: The front-end or vlc engine calls here to ether get
* information such as meta information or plugin capabilities or to
* issue miscellaneous "set" requests.
*****************************************************************************/
static int VCDControl( access_t *p_access, int i_query, va_list args )
{
access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
int *pi_int;
int i;
dbg_print( (INPUT_DBG_CALL|INPUT_DBG_EXT|INPUT_DBG_EVENT),
"query %d", i_query );
switch( i_query )
{
/* Pass back a copy of meta information that was gathered when we
during the Open/Initialize call.
*/
case ACCESS_GET_META:
{
vlc_meta_t **pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
dbg_print( INPUT_DBG_EVENT, "get meta info" );
if ( p_vcd->p_meta ) {
*pp_meta = vlc_meta_Duplicate( p_vcd->p_meta );
dbg_print( INPUT_DBG_META, "%s", "Meta copied" );
} else
msg_Warn( p_access, "tried to copy NULL meta info" );
return VLC_SUCCESS;
}
return VLC_EGENERIC;
case ACCESS_CAN_SEEK:
case ACCESS_CAN_FASTSEEK:
case ACCESS_CAN_PAUSE:
case ACCESS_CAN_CONTROL_PACE:
{
vlc_bool_t *pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
dbg_print( INPUT_DBG_EVENT,
"seek/fastseek/pause/can_control_pace" );
*pb_bool = VLC_TRUE;
return VLC_SUCCESS;
break;
}
/* */
case ACCESS_GET_MTU:
pi_int = (int*)va_arg( args, int * );
*pi_int = (VCD_BLOCKS_ONCE * M2F2_SECTOR_SIZE);
dbg_print( INPUT_DBG_EVENT, "GET MTU: %d", *pi_int );
break;
case ACCESS_GET_PTS_DELAY:
{
int64_t *pi_64 = (int64_t*)va_arg( args, int64_t * );
*pi_64 = var_GetInteger( p_access, MODULE_STRING "-caching" )
* MILLISECONDS_PER_SEC;
dbg_print( INPUT_DBG_EVENT, "GET PTS DELAY" );
return VLC_SUCCESS;
break;
}
/* */
case ACCESS_SET_PAUSE_STATE:
dbg_print( INPUT_DBG_EVENT, "SET PAUSE STATE" );
return VLC_SUCCESS;
break;
case ACCESS_GET_TITLE_INFO:
{
input_title_t ***ppp_title;
unsigned int i;
ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
pi_int = (int*)va_arg( args, int* );
dbg_print( INPUT_DBG_EVENT, "GET TITLE: i_titles %d",
p_vcd->i_titles );
VCDMetaInfo( p_access );
/* Duplicate title info */
if( p_vcd->i_titles == 0 )
{
*pi_int = 0; ppp_title = NULL;
return VLC_SUCCESS;
}
*pi_int = p_vcd->i_titles;
*ppp_title = malloc(sizeof( input_title_t **) * p_vcd->i_titles );
if (!*ppp_title) return VLC_ENOMEM;
for( i = 0; i < p_vcd->i_titles; i++ )
{
if ( p_vcd->p_title[i] )
(*ppp_title)[i] =
vlc_input_title_Duplicate( p_vcd->p_title[i] );
}
return VLC_SUCCESS;
}
break;
case ACCESS_SET_TITLE:
i = (int)va_arg( args, int );
dbg_print( INPUT_DBG_EVENT, "set title %d" , i);
if( i != p_access->info.i_title )
{
/* Update info */
p_access->info.i_update |=
INPUT_UPDATE_TITLE|INPUT_UPDATE_SIZE;
p_access->info.i_title = i;
p_access->info.i_size = p_vcd->p_title[i]->i_size;
p_access->info.i_pos = 0;
/* Next sector to read */
p_vcd->i_lsn = p_vcd->p_sectors[i];
}
break;
case ACCESS_SET_SEEKPOINT:
{
input_title_t *t = p_vcd->p_title[p_access->info.i_title];
i = (int)va_arg( args, int );
if( t->i_seekpoint > 0 )
{
p_access->info.i_update |= INPUT_UPDATE_SEEKPOINT;
p_access->info.i_seekpoint = i;
p_vcd->i_lsn = p_vcd->p_sectors[1+p_access->info.i_title] +
t->seekpoint[i]->i_byte_offset / M2F2_SECTOR_SIZE;
p_access->info.i_pos =
(int64_t)(p_vcd->i_lsn -
p_vcd->p_sectors[1+p_access->info.i_title])
* M2F2_SECTOR_SIZE;
}
return VLC_SUCCESS;
}
case ACCESS_SET_PRIVATE_ID_STATE:
dbg_print( INPUT_DBG_EVENT, "set seekpoint/set private id" );
return VLC_EGENERIC;
default:
msg_Warn( p_access, "unimplemented query in control" );
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
......@@ -95,13 +95,15 @@ void ioctl_Close( cddev_t *p_cddev )
* 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,
track_t ioctl_GetTracksMap( vlc_object_t *p_this, const CdIo *p_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_tracks = cdio_get_num_tracks(p_cdio);
track_t first_track = cdio_get_first_track_num(p_cdio);
track_t i;
if (CDIO_INVALID_TRACK == i_tracks)
return 0;
*pp_sectors = malloc( (i_tracks + 1) * sizeof(lsn_t) );
if( *pp_sectors == NULL )
......@@ -116,7 +118,7 @@ track_t ioctl_GetTracksMap( vlc_object_t *p_this, const CdIo *cdio,
*/
for( i = 0 ; i <= i_tracks ; i++ )
{
(*pp_sectors)[ i ] = cdio_get_track_lsn(cdio, first_track+i);
(*pp_sectors)[ i ] = cdio_get_track_lsn(p_cdio, first_track+i);
}
return i_tracks;
......
......@@ -2,7 +2,7 @@
* cdrom.h: cdrom tools header
*****************************************************************************
* Copyright (C) 1998-2001 VideoLAN
* $Id: cdrom.h,v 1.2 2003/11/26 03:34:22 rocky Exp $
* $Id$
*
* Authors: Johan Bilien <jobi@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
......
......@@ -32,8 +32,6 @@
#include <vlc/input.h>
#include <vlc/intf.h>
#include "../../demux/mpeg/system.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
......@@ -72,15 +70,15 @@ struct demux_sys_t
};
/*****************************************************************************
* InitVCD: initializes structures
* VCDInit: initializes structures
*****************************************************************************/
int E_(InitVCD) ( vlc_object_t *p_this )
int E_(VCDInit) ( 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;
vcd_data_t * p_vcd = (vcd_data_t *)p_input->p_sys;
demux_sys_t * p_demux;
printf("++++ InitVCD CALLED\n");
printf("++++ VCDInit CALLED\n");
if( p_input->stream.i_method != INPUT_METHOD_VCD )
......@@ -115,9 +113,9 @@ int E_(InitVCD) ( vlc_object_t *p_this )
}
/*****************************************************************************
* EndVCD: frees unused data
* VCDEnd: frees unused data
*****************************************************************************/
void E_(EndVCD) ( vlc_object_t *p_this )
void E_(VCDEnd) ( 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;
......
/*****************************************************************************
* info.c : CD digital audio input information routines
*****************************************************************************
* Copyright (C) 2004 VideoLAN
* $Id: info.c 8845 2004-09-29 09:00:41Z rocky $
*
* 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 <vlc/vlc.h>
#include <vlc/input.h>
#include "vcd.h"
#include <vlc_playlist.h>
#include "vcdplayer.h"
#include "vlc_keys.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>
static inline void
MetaInfoAddStr(access_t *p_access, char *p_cat,
char *title, const char *str)
{
access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
if ( str ) {
dbg_print( INPUT_DBG_META, "field: %s: %s", title, str);
input_Control( p_vcd->p_input, INPUT_ADD_INFO, p_cat, title, "%s", str);
}
}
static inline void
MetaInfoAddNum(access_t *p_access, char *psz_cat, char *title, int num)
{
access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
dbg_print( INPUT_DBG_META, "field %s: %d", title, num);
input_Control( p_vcd->p_input, INPUT_ADD_INFO, psz_cat, title, "%d", num );
}
#define addstr(title, str) \
MetaInfoAddStr( p_access, psz_cat, title, str );
#define addnum(title, num) \
MetaInfoAddNum( p_access, psz_cat, title, num );
void
VCDMetaInfo( access_t *p_access )
{
access_vcd_data_t *p_vcd = (access_vcd_data_t *) p_access->p_sys;
unsigned int i_entries = vcdinfo_get_num_entries(p_vcd->vcd);
unsigned int last_entry = 0;
char *psz_cat;
track_t i_track;
psz_cat = _("General");
addstr( _("VCD Format"), vcdinfo_get_format_version_str(p_vcd->vcd) );
addstr( _("Album"), vcdinfo_get_album_id(p_vcd->vcd));
addstr( _("Application"), vcdinfo_get_application_id(p_vcd->vcd) );
addstr( _("Preparer"), vcdinfo_get_preparer_id(p_vcd->vcd) );
addnum( _("Vol #"), vcdinfo_get_volume_num(p_vcd->vcd) );
addnum( _("Vol max #"), vcdinfo_get_volume_count(p_vcd->vcd) );
addstr( _("Volume Set"), vcdinfo_get_volumeset_id(p_vcd->vcd) );
addstr( _("Volume"), vcdinfo_get_volume_id(p_vcd->vcd) );
addstr( _("Publisher"), vcdinfo_get_publisher_id(p_vcd->vcd) );
addstr( _("System Id"), vcdinfo_get_system_id(p_vcd->vcd) );
addnum( "LIDs", vcdinfo_get_num_LIDs(p_vcd->vcd) );
addnum( _("Entries"), vcdinfo_get_num_entries(p_vcd->vcd) );
addnum( _("Segments"), vcdinfo_get_num_segments(p_vcd->vcd) );
addnum( _("Tracks"), vcdinfo_get_num_tracks(p_vcd->vcd) );
/* Spit out track information. Could also include MSF info.
Also build title table.
*/
#define TITLE_MAX 30
for( i_track = 1 ; i_track < p_vcd->i_tracks ; i_track++ ) {
unsigned int audio_type = vcdinfo_get_track_audio_type(p_vcd->vcd,
i_track);
uint32_t i_secsize =
p_vcd->p_sectors[i_track+1] - p_vcd->p_sectors[i_track];
if (p_vcd->b_svd) {
addnum(_("Audio Channels"),
vcdinfo_audio_type_num_channels(p_vcd->vcd, audio_type) );
}
addnum(_("First Entry Point"), last_entry );
for ( ; last_entry < i_entries
&& vcdinfo_get_track(p_vcd->vcd, last_entry) == i_track;
last_entry++ ) ;
addnum(_("Last Entry Point"), last_entry-1 );
addnum(_("Track size (in sectors)"), i_secsize );
}
}
#define add_format_str_info(val) \
{ \
const char *str = val; \
unsigned int len; \
if (val != NULL) { \
len=strlen(str); \
if (len != 0) { \
strncat(tp, str, TEMP_STR_LEN-(tp-temp_str)); \
tp += len; \
} \
saw_control_prefix = VLC_FALSE; \
} \
}
#define add_format_num_info( val, fmt ) \
{ \
char num_str[10]; \
unsigned int len; \
sprintf(num_str, fmt, val); \
len = strlen(num_str); \
if( len != 0 ) \
{ \
strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str)); \
tp += len; \
} \
saw_control_prefix = VLC_FALSE; \
}
/*!
Take a format string and expand escape sequences, that is sequences that
begin with %, with information from the current VCD.
The expanded string is returned. Here is a list of escape sequences:
%A : The album information
%C : The VCD volume count - the number of CD's in the collection.
%c : The VCD volume num - the number of the CD in the collection.
%F : The VCD Format, e.g. VCD 1.0, VCD 1.1, VCD 2.0, or SVCD
%I : The current entry/segment/playback type, e.g. ENTRY, TRACK, SEGMENT...
%L : The playlist ID prefixed with " LID" if it exists
%M : MRL
%N : The current number of the %I - a decimal number
%P : The publisher ID
%p : The preparer ID
%S : If we are in a segment (menu), the kind of segment
%T : The track number
%V : The volume set ID
%v : The volume ID
A number between 1 and the volume count.
%% : a %
*/
char *
VCDFormatStr(const access_t *p_access, access_vcd_data_t *p_vcd,
const char format_str[], const char *mrl,
const vcdinfo_itemid_t *itemid)
{
#define TEMP_STR_SIZE 256
#define TEMP_STR_LEN (TEMP_STR_SIZE-1)
static char temp_str[TEMP_STR_SIZE];
size_t i;
char * tp = temp_str;
vlc_bool_t saw_control_prefix = VLC_FALSE;
size_t format_len = strlen(format_str);
memset(temp_str, 0, TEMP_STR_SIZE);
for (i=0; i<format_len; i++) {
if (!saw_control_prefix && format_str[i] != '%') {
*tp++ = format_str[i];
saw_control_prefix = VLC_FALSE;
continue;
}
switch(format_str[i]) {
case '%':
if (saw_control_prefix) {
*tp++ = '%';
}
saw_control_prefix = !saw_control_prefix;
break;
case 'A':
add_format_str_info(vcdinfo_strip_trail(vcdinfo_get_album_id(p_vcd->vcd),
MAX_ALBUM_LEN));
break;
case 'c':
add_format_num_info(vcdinfo_get_volume_num(p_vcd->vcd), "%d");
break;
case 'C':
add_format_num_info(vcdinfo_get_volume_count(p_vcd->vcd), "%d");
break;
case 'F':
add_format_str_info(vcdinfo_get_format_version_str(p_vcd->vcd));
break;
case 'I':
{
switch (itemid->type) {
case VCDINFO_ITEM_TYPE_TRACK:
strncat(tp, _("Track"), TEMP_STR_LEN-(tp-temp_str));
tp += strlen(_("Track"));
break;
case VCDINFO_ITEM_TYPE_ENTRY:
strncat(tp, _("Entry"), TEMP_STR_LEN-(tp-temp_str));
tp += strlen(_("Entry"));
break;
case VCDINFO_ITEM_TYPE_SEGMENT:
strncat(tp, _("Segment"), TEMP_STR_LEN-(tp-temp_str));
tp += strlen(_("Segment"));
break;
case VCDINFO_ITEM_TYPE_LID:
strncat(tp, _("List ID"), TEMP_STR_LEN-(tp-temp_str));
tp += strlen(_("List ID"));
break;
case VCDINFO_ITEM_TYPE_SPAREID2:
strncat(tp, _("Navigation"), TEMP_STR_LEN-(tp-temp_str));
tp += strlen(_("Navigation"));
break;
default:
/* What to do? */
;
}
saw_control_prefix = VLC_FALSE;
}
break;
case 'L':
if (vcdplayer_pbc_is_on(p_vcd)) {
char num_str[40];
sprintf(num_str, "%s %d", _("List ID"), p_vcd->i_lid);
strncat(tp, num_str, TEMP_STR_LEN-(tp-temp_str));
tp += strlen(num_str);
}
saw_control_prefix = VLC_FALSE;
break;
case 'M':
add_format_str_info(mrl);
break;
case 'N':
add_format_num_info(itemid->num, "%d");
break;
case 'p':
add_format_str_info(vcdinfo_get_preparer_id(p_vcd->vcd));
break;
case 'P':
add_format_str_info(vcdinfo_get_publisher_id(p_vcd->vcd));
break;
case 'S':
if ( VCDINFO_ITEM_TYPE_SEGMENT==itemid->type ) {
char seg_type_str[10];
sprintf(seg_type_str, " %s",
vcdinfo_video_type2str(p_vcd->vcd, itemid->num));
strncat(tp, seg_type_str, TEMP_STR_LEN-(tp-temp_str));
tp += strlen(seg_type_str);
}
saw_control_prefix = VLC_FALSE;
break;
case 'T':
add_format_num_info(p_vcd->i_track, "%d");
break;
case 'V':
add_format_str_info(vcdinfo_get_volumeset_id(p_vcd->vcd));
break;
case 'v':
add_format_str_info(vcdinfo_get_volume_id(p_vcd->vcd));
break;
default:
*tp++ = '%';
*tp++ = format_str[i];
saw_control_prefix = VLC_FALSE;
}
}
return strdup(temp_str);
}
static void
VCDCreatePlayListItem(const access_t *p_access,
access_vcd_data_t *p_vcd,
playlist_t *p_playlist,
const vcdinfo_itemid_t *itemid,
char *psz_mrl, int psz_mrl_max,
const char *psz_source, int playlist_operation,
int i_pos)
{
char *p_author;
char *p_title;
char c_type;
switch(itemid->type) {
case VCDINFO_ITEM_TYPE_TRACK:
c_type='T';
break;
case VCDINFO_ITEM_TYPE_SEGMENT:
c_type='S';
break;
case VCDINFO_ITEM_TYPE_LID:
c_type='P';
break;
case VCDINFO_ITEM_TYPE_ENTRY:
c_type='E';
break;
default:
c_type='?';
break;
}
snprintf(psz_mrl, psz_mrl_max, "%s%s@%c%u", VCD_MRL_PREFIX, psz_source,
c_type, itemid->num);
p_title =
VCDFormatStr( p_access, p_vcd,
config_GetPsz( p_access, MODULE_STRING "-title-format" ),
psz_mrl, itemid );
playlist_Add( p_playlist, psz_mrl, p_title, playlist_operation, i_pos );
p_author =
VCDFormatStr( p_access, p_vcd,
config_GetPsz( p_access, MODULE_STRING "-author-format" ),
psz_mrl, itemid );
if( i_pos == PLAYLIST_END ) i_pos = p_playlist->i_size - 1;
playlist_AddInfo(p_playlist, i_pos, _("General"), _("Author"), "%s",
p_author);
}
int
VCDFixupPlayList( access_t *p_access, access_vcd_data_t *p_vcd,
const char *psz_source, vcdinfo_itemid_t *itemid,
vlc_bool_t b_single_item )
{
unsigned int i;
playlist_t * p_playlist;
char * psz_mrl;
unsigned int psz_mrl_max = strlen(VCD_MRL_PREFIX) + strlen(psz_source) +
strlen("@T") + strlen("100") + 1;
psz_mrl = malloc( psz_mrl_max );
if( psz_mrl == NULL )
{
msg_Warn( p_access, "out of memory" );
return -1;
}
p_playlist = (playlist_t *) vlc_object_find( p_access, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( !p_playlist )
{
msg_Warn( p_access, "can't find playlist" );
free(psz_mrl);
return -1;
}
{
vcdinfo_itemid_t list_itemid;
list_itemid.type=VCDINFO_ITEM_TYPE_ENTRY;
playlist_LockDelete( p_playlist, p_playlist->i_index);
for( i = 0 ; i < p_vcd->i_entries ; i++ )
{
list_itemid.num=i;
VCDCreatePlayListItem(p_access, p_vcd, p_playlist, &list_itemid,
psz_mrl, psz_mrl_max, psz_source,
PLAYLIST_APPEND, PLAYLIST_END);
}
#if LOOKED_OVER
playlist_Command( p_playlist, PLAYLIST_GOTO, 0 );
#endif
}
vlc_object_release( p_playlist );
free(psz_mrl);
return 0;
}
/*****************************************************************************
* info.h : VCD information routine headers
*****************************************************************************
* Copyright (C) 2004 VideoLAN
* $Id: info.h 8606 2004-08-31 18:32:54Z rocky $
*
* 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.
*****************************************************************************/
/*
Fills out playlist information.
*/
int VCDFixupPlayList( access_t *p_access, access_vcd_data_t *p_vcd,
const char *psz_source, vcdinfo_itemid_t *itemid,
vlc_bool_t b_single_track );
/*
Sets VCD meta information and navigation/playlist entries.
*/
void VCDMetaInfo( access_t *p_access );
char *
VCDFormatStr(const access_t *p_access, access_vcd_data_t *p_vcd,
const char format_str[], const char *mrl,
const vcdinfo_itemid_t *itemid);
......@@ -2,7 +2,7 @@
* intf.h: send info to intf.
*****************************************************************************
* Copyright (C) 2001 VideoLAN
* $Id: intf.h,v 1.4 2003/12/22 14:32:55 sam Exp $
* $Id$
*
* Author: Stéphane Borel <stef@via.ecp.fr>
*
......@@ -27,7 +27,7 @@
struct intf_sys_t
{
input_thread_t * p_input;
thread_vcd_data_t * p_vcd;
access_vcd_data_t * p_vcd;
vlc_bool_t b_still; /* True if we are in a still frame */
vlc_bool_t b_inf_still; /* True if still wait time is infinite */
......
/*****************************************************************************
* vcd.c : VCD input module for vlc
*****************************************************************************
* Copyright (C) 2000,2003 VideoLAN
* Copyright (C) 2000, 2003, 2004 VideoLAN
* $Id$
*
* Authors: Rocky Bernstein <rocky@panix.com>
......@@ -34,12 +34,12 @@
/*****************************************************************************
* Exported prototypes
*****************************************************************************/
int E_(Open) ( vlc_object_t * );
void E_(Close) ( vlc_object_t * );
int E_(VCDOpen) ( vlc_object_t * );
void E_(VCDClose) ( vlc_object_t * );
int E_(OpenIntf) ( vlc_object_t * );
void E_(CloseIntf) ( vlc_object_t * );
int E_(InitVCD) ( vlc_object_t * );
void E_(EndVCD) ( vlc_object_t * );
int E_(VCDInit) ( vlc_object_t * );
void E_(VCDEnd) ( vlc_object_t * );
int E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
vlc_value_t oldval, vlc_value_t val,
......@@ -90,12 +90,9 @@ int E_(DebugCallback) ( vlc_object_t *p_this, const char *psz_name,
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_(Open), E_(Close) );
add_shortcut( "vcd" );
set_capability( "access2", 55 /* slightly lower than vcd */ );
set_callbacks( E_(VCDOpen), E_(VCDClose) );
add_shortcut( "vcdx" );
set_category( CAT_INPUT );
set_subcategory( SUBCAT_INPUT_ACCESS );
/* Configuration options */
add_integer ( MODULE_STRING "-debug", 0, E_(DebugCallback),
......@@ -123,11 +120,11 @@ vlc_module_begin();
#ifdef FIXED
add_submodule();
set_capability( "demux", 0 );
set_callbacks( E_(InitVCD), E_(EndVCD) );
#endif
set_callbacks( E_(VCDInit), E_(VCDEnd) );
add_submodule();
set_capability( "interface", 0 );
set_callbacks( E_(OpenIntf), E_(CloseIntf) );
#endif
vlc_module_end();
......@@ -2,7 +2,7 @@
* vcd.h : VCD input module header for vlc
* using libcdio, libvcd and libvcdinfo
*****************************************************************************
* Copyright (C) 2003 VideoLAN
* Copyright (C) 2003, 2004 VideoLAN
* $Id$
*
* Authors: Rocky Bernstein <rocky@panix.com>
......@@ -24,6 +24,8 @@
#include <libvcd/info.h>
#define VCD_MRL_PREFIX "vcdx://"
/*****************************************************************************
* vcd_data_t: structure for communication between access and intf.
*****************************************************************************/
......@@ -50,6 +52,6 @@ typedef struct
} 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 );
int VCDSetArea ( access_t * );
int VCDSeek ( access_t *, off_t );
int VCDPlay ( access_t *, vcdinfo_itemid_t );
......@@ -2,7 +2,7 @@
* vcdplayer.c : VCD input module for vlc
* using libcdio, libvcd and libvcdinfo
*****************************************************************************
* Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
* Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
* $Id$
*
* This program is free software; you can redistribute it and/or modify
......@@ -50,15 +50,17 @@
/*!
Return VLC_TRUE if playback control (PBC) is on
*/
vlc_bool_t vcdplayer_pbc_is_on( const thread_vcd_data_t *p_vcd )
vlc_bool_t
vcdplayer_pbc_is_on( const access_vcd_data_t *p_vcd )
{
return VCDINFO_INVALID_ENTRY != p_vcd->cur_lid;
return VCDINFO_INVALID_ENTRY != p_vcd->i_lid;
}
static void vcdplayer_update_entry( input_thread_t * p_input, uint16_t ofs,
static void
vcdplayer_update_entry( access_t * p_access, uint16_t ofs,
uint16_t *entry, const char *label)
{
thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
if ( ofs == VCDINFO_INVALID_OFFSET ) {
*entry = VCDINFO_INVALID_ENTRY;
......@@ -79,17 +81,18 @@ static void vcdplayer_update_entry( input_thread_t * p_input, uint16_t ofs,
return VLC_TRUE if the caller should return.
*/
vcdplayer_read_status_t vcdplayer_non_pbc_nav ( input_thread_t * p_input )
vcdplayer_read_status_t
vcdplayer_non_pbc_nav ( access_t * p_access )
{
thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
/* 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: {
dbg_print( INPUT_DBG_LSN, "new track %d, lsn %d", p_vcd->cur_track,
p_vcd->p_sectors[p_vcd->cur_track+1] );
dbg_print( INPUT_DBG_LSN, "new track %d, lsn %d", p_vcd->i_track,
p_vcd->p_sectors[p_vcd->i_track+1] );
return READ_END;
break;
}
......@@ -97,7 +100,6 @@ vcdplayer_read_status_t vcdplayer_non_pbc_nav ( input_thread_t * p_input )
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 ;
......@@ -112,7 +114,6 @@ vcdplayer_read_status_t vcdplayer_non_pbc_nav ( input_thread_t * p_input )
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),
......@@ -126,9 +127,9 @@ vcdplayer_read_status_t vcdplayer_non_pbc_nav ( input_thread_t * p_input )
/* Handles PBC navigation when reaching the end of a play item. */
vcdplayer_read_status_t
vcdplayer_pbc_nav ( input_thread_t * p_input )
vcdplayer_pbc_nav ( access_t * p_access )
{
thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
/* We are in playback control. */
vcdinfo_itemid_t itemid;
......@@ -137,12 +138,12 @@ vcdplayer_pbc_nav ( input_thread_t * p_input )
sequence (or track). */
if ( (VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type) &&
(p_vcd->cur_lsn < p_vcd->end_lsn) ) {
(p_vcd->i_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 );
VCDPlay( p_access, p_vcd->play_item );
/* p_vcd->update_title(); */
return READ_BLOCK;
}
......@@ -156,20 +157,22 @@ vcdplayer_pbc_nav ( input_thread_t * p_input )
dbg_print(INPUT_DBG_PBC, "playlist wait_time: %d", wait_time);
if (vcdplayer_inc_play_item(p_input))
if (vcdplayer_inc_play_item(p_access))
return READ_BLOCK;
/* Handle any wait time given. */
#if FIXED
if (p_vcd->in_still) {
vcdIntfStillTime( p_vcd->p_intf, wait_time );
return READ_STILL_FRAME;
}
#endif
vcdplayer_update_entry( p_input,
vcdplayer_update_entry( p_access,
vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
&itemid.num, "next" );
itemid.type = VCDINFO_ITEM_TYPE_LID;
VCDPlay( p_input, itemid );
VCDPlay( p_access, itemid );
break;
}
case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
......@@ -185,16 +188,18 @@ vcdplayer_pbc_nav ( input_thread_t * p_input )
wait_time, p_vcd->loop_count, max_loop);
/* Handle any wait time given */
#if FIXED
if (p_vcd->in_still) {
vcdIntfStillTime( p_vcd->p_intf, wait_time );
return READ_STILL_FRAME;
}
#endif
/* 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 );
VCDSeek( p_access, 0 );
/* if (p_vcd->in_still) p_vcd->force_redisplay();*/
return READ_BLOCK;
}
......@@ -207,7 +212,7 @@ vcdplayer_pbc_nav ( input_thread_t * p_input )
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 );
VCDPlay( p_access, itemid );
return READ_BLOCK;
} else {
int num_selections = vcdinf_get_num_selections(p_vcd->pxd.psd);
......@@ -217,13 +222,13 @@ vcdplayer_pbc_nav ( input_thread_t * p_input )
int rand_selection=bsn +
(int) ((num_selections+0.0)*rand()/(RAND_MAX+1.0));
lid_t rand_lid=vcdinfo_selection_get_lid (p_vcd->vcd,
p_vcd->cur_lid,
p_vcd->i_lid,
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 );
VCDPlay( p_access, itemid );
return READ_BLOCK;
} else if (p_vcd->in_still) {
/* Hack: Just go back and do still again */
......@@ -257,9 +262,10 @@ vcdplayer_pbc_nav ( input_thread_t * p_input )
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.
*/
vlc_bool_t vcdplayer_inc_play_item( input_thread_t *p_input )
vlc_bool_t
vcdplayer_inc_play_item( access_t *p_access )
{
thread_vcd_data_t * p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
access_vcd_data_t * p_vcd= (access_vcd_data_t *)p_access->p_sys;
int noi;
......@@ -287,7 +293,7 @@ vlc_bool_t vcdplayer_inc_play_item( input_thread_t *p_input )
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 );
return VLC_SUCCESS == VCDPlay( p_access, trans_itemid );
}
}
......@@ -296,9 +302,10 @@ vlc_bool_t vcdplayer_inc_play_item( input_thread_t *p_input )
Return VLC_FALSE if there was some problem.
*/
vlc_bool_t vcdplayer_play_default( input_thread_t * p_input )
vlc_bool_t
vcdplayer_play_default( access_t * p_access )
{
thread_vcd_data_t *p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
vcdinfo_itemid_t itemid;
......@@ -317,27 +324,27 @@ vlc_bool_t vcdplayer_play_default( input_thread_t * p_input )
if (vcdplayer_pbc_is_on(p_vcd)) {
#if defined(LIBVCD_VERSION)
lid_t lid=vcdinfo_get_multi_default_lid(p_vcd->vcd, p_vcd->cur_lid,
p_vcd->cur_lsn);
lid_t lid=vcdinfo_get_multi_default_lid(p_vcd->vcd, p_vcd->i_lid,
p_vcd->i_lsn);
if (VCDINFO_INVALID_LID != lid) {
itemid.num = lid;
itemid.type = VCDINFO_ITEM_TYPE_LID;
dbg_print(INPUT_DBG_PBC, "DEFAULT to %d\n", itemid.num);
} else {
dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d\n", p_vcd->cur_lid);
dbg_print(INPUT_DBG_PBC, "no DEFAULT for LID %d\n", p_vcd->i_lid);
}
#else
vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), p_vcd->cur_lid);
vcdinfo_lid_get_pxd(p_vcd->vcd, &(p_vcd->pxd), p_vcd->i_lid);
switch (p_vcd->pxd.descriptor_type) {
case PSD_TYPE_SELECTION_LIST:
case PSD_TYPE_EXT_SELECTION_LIST:
if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
vcdplayer_update_entry( p_input,
vcdplayer_update_entry( p_access,
vcdinfo_get_default_offset(p_vcd->vcd,
p_vcd->cur_lid),
p_vcd->i_lid),
&itemid.num, "default");
break;
......@@ -360,7 +367,7 @@ vlc_bool_t vcdplayer_play_default( input_thread_t * p_input )
}
/** ??? p_vcd->update_title(); ***/
return VLC_SUCCESS == VCDPlay( p_input, itemid );
return VLC_SUCCESS == VCDPlay( p_access, itemid );
}
......@@ -369,9 +376,10 @@ vlc_bool_t vcdplayer_play_default( input_thread_t * p_input )
Return VLC_FALSE if there was some problem.
*/
vlc_bool_t vcdplayer_play_next( input_thread_t * p_input )
vlc_bool_t
vcdplayer_play_next( access_t * p_access )
{
thread_vcd_data_t *p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
vcdinfo_obj_t *obj;
vcdinfo_itemid_t itemid;
......@@ -387,13 +395,13 @@ vlc_bool_t vcdplayer_play_next( input_thread_t * p_input )
if (vcdplayer_pbc_is_on(p_vcd)) {
vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), p_vcd->cur_lid);
vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), p_vcd->i_lid);
switch (p_vcd->pxd.descriptor_type) {
case PSD_TYPE_SELECTION_LIST:
case PSD_TYPE_EXT_SELECTION_LIST:
if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
vcdplayer_update_entry( p_input,
vcdplayer_update_entry( p_access,
vcdinf_psd_get_next_offset(p_vcd->pxd.psd),
&itemid.num, "next");
itemid.type = VCDINFO_ITEM_TYPE_LID;
......@@ -401,7 +409,7 @@ vlc_bool_t vcdplayer_play_next( input_thread_t * p_input )
case PSD_TYPE_PLAY_LIST:
if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
vcdplayer_update_entry( p_input,
vcdplayer_update_entry( p_access,
vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
&itemid.num, "next");
itemid.type = VCDINFO_ITEM_TYPE_LID;
......@@ -425,13 +433,13 @@ vlc_bool_t vcdplayer_play_next( input_thread_t * p_input )
switch (p_vcd->play_item.type) {
case VCDINFO_ITEM_TYPE_ENTRY:
max_entry = p_vcd->num_entries;
max_entry = p_vcd->i_entries;
break;
case VCDINFO_ITEM_TYPE_SEGMENT:
max_entry = p_vcd->num_segments;
max_entry = p_vcd->i_segments;
break;
case VCDINFO_ITEM_TYPE_TRACK:
max_entry = p_vcd->num_tracks;
max_entry = p_vcd->i_tracks;
break;
default: ; /* Handle exceptional cases below */
}
......@@ -457,7 +465,7 @@ vlc_bool_t vcdplayer_play_next( input_thread_t * p_input )
}
/** ??? p_vcd->update_title(); ***/
return VLC_SUCCESS == VCDPlay( p_input, itemid );
return VLC_SUCCESS == VCDPlay( p_access, itemid );
}
......@@ -466,9 +474,10 @@ vlc_bool_t vcdplayer_play_next( input_thread_t * p_input )
Return VLC_FALSE if there was some problem.
*/
vlc_bool_t vcdplayer_play_prev( input_thread_t * p_input )
vlc_bool_t
vcdplayer_play_prev( access_t * p_access )
{
thread_vcd_data_t *p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
vcdinfo_obj_t *obj = p_vcd->vcd;
vcdinfo_itemid_t itemid;
......@@ -480,13 +489,13 @@ vlc_bool_t vcdplayer_play_prev( input_thread_t * p_input )
if (vcdplayer_pbc_is_on(p_vcd)) {
vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), p_vcd->cur_lid);
vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), p_vcd->i_lid);
switch (p_vcd->pxd.descriptor_type) {
case PSD_TYPE_SELECTION_LIST:
case PSD_TYPE_EXT_SELECTION_LIST:
if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
vcdplayer_update_entry( p_input,
vcdplayer_update_entry( p_access,
vcdinf_psd_get_prev_offset(p_vcd->pxd.psd),
&itemid.num, "prev");
itemid.type = VCDINFO_ITEM_TYPE_LID;
......@@ -494,7 +503,7 @@ vlc_bool_t vcdplayer_play_prev( input_thread_t * p_input )
case PSD_TYPE_PLAY_LIST:
if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
vcdplayer_update_entry( p_input,
vcdplayer_update_entry( p_access,
vcdinf_pld_get_prev_offset(p_vcd->pxd.pld),
&itemid.num, "prev");
itemid.type = VCDINFO_ITEM_TYPE_LID;
......@@ -522,7 +531,7 @@ vlc_bool_t vcdplayer_play_prev( input_thread_t * p_input )
}
/** ??? p_vcd->update_title(); ***/
return VLC_SUCCESS == VCDPlay( p_input, itemid );
return VLC_SUCCESS == VCDPlay( p_access, itemid );
}
......@@ -531,9 +540,10 @@ vlc_bool_t vcdplayer_play_prev( input_thread_t * p_input )
Return VLC_FALSE if there was some problem.
*/
vlc_bool_t vcdplayer_play_return( input_thread_t * p_input )
vlc_bool_t
vcdplayer_play_return( access_t * p_access )
{
thread_vcd_data_t *p_vcd= (thread_vcd_data_t *)p_input->p_access_data;
access_vcd_data_t *p_vcd= (access_vcd_data_t *)p_access->p_sys;
vcdinfo_obj_t *obj = p_vcd->vcd;
vcdinfo_itemid_t itemid;
......@@ -545,13 +555,13 @@ vlc_bool_t vcdplayer_play_return( input_thread_t * p_input )
if (vcdplayer_pbc_is_on(p_vcd)) {
vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), p_vcd->cur_lid);
vcdinfo_lid_get_pxd(obj, &(p_vcd->pxd), p_vcd->i_lid);
switch (p_vcd->pxd.descriptor_type) {
case PSD_TYPE_SELECTION_LIST:
case PSD_TYPE_EXT_SELECTION_LIST:
if (p_vcd->pxd.psd == NULL) return VLC_FALSE;
vcdplayer_update_entry( p_input,
vcdplayer_update_entry( p_access,
vcdinf_psd_get_return_offset(p_vcd->pxd.psd),
&itemid.num, "return");
itemid.type = VCDINFO_ITEM_TYPE_LID;
......@@ -559,7 +569,7 @@ vlc_bool_t vcdplayer_play_return( input_thread_t * p_input )
case PSD_TYPE_PLAY_LIST:
if (p_vcd->pxd.pld == NULL) return VLC_FALSE;
vcdplayer_update_entry( p_input,
vcdplayer_update_entry( p_access,
vcdinf_pld_get_return_offset(p_vcd->pxd.pld),
&itemid.num, "return");
itemid.type = VCDINFO_ITEM_TYPE_LID;
......@@ -580,6 +590,6 @@ vlc_bool_t vcdplayer_play_return( input_thread_t * p_input )
}
/** ??? p_vcd->update_title(); ***/
return VLC_SUCCESS == VCDPlay( p_input, itemid );
return VLC_SUCCESS == VCDPlay( p_access, itemid );
}
......@@ -25,6 +25,7 @@
#define _VCDPLAYER_H_
#include <libvcd/info.h>
#include "vlc_meta.h"
#define INPUT_DBG_META 1 /* Meta information */
#define INPUT_DBG_EVENT 2 /* input (keyboard/mouse) events */
......@@ -43,13 +44,13 @@
#if INPUT_DEBUG
#define dbg_print(mask, s, args...) \
if (p_vcd && p_vcd->i_debug & mask) \
msg_Dbg(p_input, "%s: "s, __func__ , ##args)
msg_Dbg(p_access, "%s: "s, __func__ , ##args)
#else
#define dbg_print(mask, s, args...)
#endif
#define LOG_ERR(args...) msg_Err( p_input, args )
#define LOG_WARN(args...) msg_Warn( p_input, args )
#define LOG_ERR(args...) msg_Err( p_access, args )
#define LOG_WARN(args...) msg_Warn( p_access, args )
/* vcdplayer_read return status */
typedef enum {
......@@ -60,29 +61,25 @@ typedef enum {
} vcdplayer_read_status_t;
/*****************************************************************************
* thread_vcd_data_t: VCD information
* access_vcd_data_t: VCD information
*****************************************************************************/
typedef struct thread_vcd_data_s
{
vcdinfo_obj_t *vcd; /* CD device descriptor */
vlc_bool_t in_still; /* true if in still */
vlc_bool_t b_svd; /* true if we have SVD info */
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 */
track_t i_tracks; /* # of tracks */
unsigned int i_segments; /* # of segments */
unsigned int i_entries; /* # of entries */
unsigned int i_lids; /* # of List IDs */
unsigned int i_titles; /* # of navigatable titles. */
vcdinfo_itemid_t play_item; /* play-item, VCDPLAYER_BAD_ENTRY
if none */
int cur_lid; /* LID that play item is in. Implies
int i_lid; /* LID that play item is in. Implies
PBC is on. VCDPLAYER_BAD_ENTRY if
not none or not in PBC */
#if (defined LIBVCD_VERSION_NUM) && (LIBVCD_VERSION_NUM >= 21)
PsdListDescriptor_t pxd; /* If PBC is on, the relevant
PSD/PLD */
#else
PsdListDescriptor pxd; /* If PBC is on, the relevant
PSD/PLD */
#endif
int pdi; /* current pld index of pxd. -1 if
no index*/
vcdinfo_itemid_t loop_item; /* Where do we loop back to?
......@@ -91,25 +88,37 @@ typedef struct thread_vcd_data_s
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 */
track_t i_track; /* Current track number */
lsn_t i_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_sectors; /* Track sectors. This is 0 origin
so the first VCD track will be
at 0 and this is the ISO9660
filesystem. The first Mode2 form2
MPEG track is probably track 2 or
p_sectors[1].
*/
lsn_t * p_entries; /* Entry points */
lsn_t * p_segments; /* Segments */
vlc_bool_t 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 */
/* Information about CD */
vlc_meta_t *p_meta;
input_title_t *p_title[CDIO_CD_MAX_TRACKS];
/* Probably gets moved into another structure...*/
intf_thread_t * p_intf;
intf_thread_t *p_intf;
int i_audio_nb;
int i_still_time;
vlc_bool_t b_end_of_cell;
input_thread_t *p_input;
} thread_vcd_data_t;
} access_vcd_data_t;
/*!
Get the next play-item in the list given in the LIDs. Note play-item
......@@ -117,33 +126,33 @@ typedef struct thread_vcd_data_s
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.
*/
vlc_bool_t vcdplayer_inc_play_item( input_thread_t *p_input );
vlc_bool_t vcdplayer_inc_play_item( access_t *p_access );
/*!
Return true if playback control (PBC) is on
*/
vlc_bool_t vcdplayer_pbc_is_on(const thread_vcd_data_t *p_this);
vlc_bool_t vcdplayer_pbc_is_on(const access_vcd_data_t *p_this);
/*!
Play item assocated with the "default" selection.
Return false if there was some problem.
*/
vlc_bool_t vcdplayer_play_default( input_thread_t * p_input );
vlc_bool_t vcdplayer_play_default( access_t * p_access );
/*!
Play item assocated with the "next" selection.
Return false if there was some problem.
*/
vlc_bool_t vcdplayer_play_next( input_thread_t * p_input );
vlc_bool_t vcdplayer_play_next( access_t * p_access );
/*!
Play item assocated with the "prev" selection.
Return false if there was some problem.
*/
vlc_bool_t vcdplayer_play_prev( input_thread_t * p_input );
vlc_bool_t vcdplayer_play_prev( access_t * p_access );
/*!
Play item assocated with the "return" selection.
......@@ -151,10 +160,10 @@ vlc_bool_t vcdplayer_play_prev( input_thread_t * p_input );
Return false if there was some problem.
*/
vlc_bool_t
vcdplayer_play_return( input_thread_t * p_input );
vcdplayer_play_return( access_t * p_access );
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 );
vcdplayer_read_status_t vcdplayer_pbc_nav ( access_t * p_access );
vcdplayer_read_status_t vcdplayer_non_pbc_nav ( access_t * p_access );
#endif /* _VCDPLAYER_H_ */
/*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment