Commit 0e5f99c2 authored by Rocky Bernstein's avatar Rocky Bernstein

info.c: Add LID info in stream and media info.

vcdplayer.{c,h}, since this tries to be platform independent use bool
rather than VLC_BOOL.

Some segment play back improvments. (I hope).
parent 6bafce69
SOURCES_vcdx = \ SOURCES_vcdx = \
access.c \ access.c \
intf.c \
intf.h \
vcd.c \ vcd.c \
vcd.h \ vcd.h \
vcdplayer.h \ vcdplayer.h \
......
...@@ -32,10 +32,6 @@ ...@@ -32,10 +32,6 @@
#include <vlc/vlc.h> #include <vlc/vlc.h>
#include <vlc/intf.h> #include <vlc/intf.h>
#include <vlc/input.h> #include <vlc/input.h>
#include "vcd.h"
#include "info.h"
#include "intf.h"
#include "vlc_keys.h" #include "vlc_keys.h"
#include <cdio/cdio.h> #include <cdio/cdio.h>
...@@ -44,6 +40,9 @@ ...@@ -44,6 +40,9 @@
#include <cdio/util.h> #include <cdio/util.h>
#include <libvcd/info.h> #include <libvcd/info.h>
#include <libvcd/logging.h> #include <libvcd/logging.h>
#include "vcd.h"
#include "info.h"
#include "intf.h"
#define FREE_AND_NULL(ptr) if (NULL != ptr) free(ptr); ptr = NULL; #define FREE_AND_NULL(ptr) if (NULL != ptr) free(ptr); ptr = NULL;
...@@ -147,6 +146,7 @@ VCDReadBlock( access_t * p_access ) ...@@ -147,6 +146,7 @@ VCDReadBlock( access_t * p_access )
block_t *p_block; block_t *p_block;
const int i_blocks = p_vcd->i_blocks_per_read; const int i_blocks = p_vcd->i_blocks_per_read;
int i_read; int i_read;
uint8_t * p_buf;
i_read = 0; i_read = 0;
...@@ -162,16 +162,42 @@ VCDReadBlock( access_t * p_access ) ...@@ -162,16 +162,42 @@ VCDReadBlock( access_t * p_access )
return NULL; return NULL;
} }
p_buf = (uint8_t *) p_block->p_buffer;
for ( i_read = 0 ; i_read < i_blocks ; i_read++ ) for ( i_read = 0 ; i_read < i_blocks ; i_read++ )
{ {
const lsn_t old_lsn = p_vcd->i_lsn; vcdplayer_read_status_t read_status = vcdplayer_read(p_access, p_buf);
p_access->info.i_pos += M2F2_SECTOR_SIZE;
switch ( vcdplayer_read(p_access, (byte_t *) p_block->p_buffer switch ( read_status ) {
+ (i_read*M2F2_SECTOR_SIZE)) ) {
case READ_END: case READ_END:
/* End reached. Return NULL to indicated this. */ /* End reached. Return NULL to indicated this. */
/* We also set the postion to the end so the higher level
(demux?) doesn't try to keep reading. If everything works out
right this shouldn't have to happen.
*/
#if 0
if ( p_access->info.i_pos != p_access->info.i_size ) {
msg_Warn( p_access,
"At end but pos (%llu) is not size (%llu). Adjusting.",
p_access->info.i_pos, p_access->info.i_size );
p_access->info.i_pos = p_access->info.i_size;
}
#endif
#if 1
block_Release( p_block ); block_Release( p_block );
return NULL; return NULL;
#else
{
memset(p_buf, 0, M2F2_SECTOR_SIZE);
p_buf += 2;
*p_buf = 0x01;
printf("++++hacked\n");
return p_block;
}
#endif
case READ_ERROR: case READ_ERROR:
/* Some sort of error. Should we increment lsn? to skip block? /* Some sort of error. Should we increment lsn? to skip block?
*/ */
...@@ -179,20 +205,26 @@ VCDReadBlock( access_t * p_access ) ...@@ -179,20 +205,26 @@ VCDReadBlock( access_t * p_access )
return NULL; return NULL;
case READ_STILL_FRAME: case READ_STILL_FRAME:
{ {
dbg_print(INPUT_DBG_STILL, "Handled still event\n"); /* FIXME The below should be done in an event thread.
/* Reached the end of a still frame. */ Until then...
byte_t * p_buf = (byte_t *) p_block->p_buffer; */
#if 0
msleep( MILLISECONDS_PER_SEC * *p_buf );
p_vcd->in_still = VLC_FALSE;
dbg_print(INPUT_DBG_STILL, "still wait time done");
#else
vcdIntfStillTime(p_vcd->p_intf, *p_buf);
#endif
p_buf += (i_read*M2F2_SECTOR_SIZE); #if 1
block_Release( p_block );
return NULL;
#else
memset(p_buf, 0, M2F2_SECTOR_SIZE); memset(p_buf, 0, M2F2_SECTOR_SIZE);
p_buf += 2; p_buf += 2;
*p_buf = 0x01; *p_buf = 0x01;
dbg_print(INPUT_DBG_STILL, "Handled still event");
p_vcd->in_still = VLC_TRUE;
var_SetInteger( p_access, "state", PAUSE_S );
return p_block; return p_block;
#endif
} }
default: default:
...@@ -201,14 +233,13 @@ VCDReadBlock( access_t * p_access ) ...@@ -201,14 +233,13 @@ VCDReadBlock( access_t * p_access )
; ;
} }
p_access->info.i_pos += (p_vcd->i_lsn - old_lsn) * M2F2_SECTOR_SIZE; p_buf += M2F2_SECTOR_SIZE;
/* Update seekpoint */ /* Update seekpoint */
if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type ) if ( VCDINFO_ITEM_TYPE_ENTRY == p_vcd->play_item.type )
{ {
unsigned int i_entry = p_vcd->play_item.num+1; unsigned int i_entry = p_vcd->play_item.num+1;
lsn_t i_lsn = vcdinfo_get_entry_lba(p_vcd->vcd, i_entry); lsn_t i_lsn = vcdinfo_get_entry_lba(p_vcd->vcd, i_entry);
if (p_vcd->i_lsn >= i_lsn ) if ( p_vcd->i_lsn >= i_lsn && i_lsn != VCDINFO_NULL_LBA )
{ {
const track_t i_track = p_vcd->i_track; const track_t i_track = p_vcd->i_track;
p_vcd->play_item.num = i_entry; p_vcd->play_item.num = i_entry;
...@@ -742,7 +773,7 @@ vcd_Open( vlc_object_t *p_this, const char *psz_dev ) ...@@ -742,7 +773,7 @@ vcd_Open( vlc_object_t *p_this, const char *psz_dev )
p_vcd->track[i].size = p_vcd->track[i].size =
vcdinfo_get_track_sect_count(p_vcdobj, track_num); vcdinfo_get_track_sect_count(p_vcdobj, track_num);
p_vcd->track[i].start_LSN = p_vcd->track[i].start_LSN =
vcdinfo_get_track_lsn(p_vcdobj, track_num); vcdinfo_get_track_lba(p_vcdobj, track_num);
} }
} else } else
p_vcd->track = NULL; p_vcd->track = NULL;
...@@ -810,7 +841,7 @@ VCDUpdateVar( access_t *p_access, int i_num, int i_action, ...@@ -810,7 +841,7 @@ VCDUpdateVar( access_t *p_access, int i_num, int i_action,
and VLC_EGENERIC for some other error. and VLC_EGENERIC for some other error.
*****************************************************************************/ *****************************************************************************/
int int
E_(VCDOpen) ( vlc_object_t *p_this ) VCDOpen ( vlc_object_t *p_this )
{ {
access_t *p_access = (access_t *)p_this; access_t *p_access = (access_t *)p_this;
vcdplayer_t *p_vcd; vcdplayer_t *p_vcd;
...@@ -865,6 +896,8 @@ E_(VCDOpen) ( vlc_object_t *p_this ) ...@@ -865,6 +896,8 @@ E_(VCDOpen) ( vlc_object_t *p_this )
p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND; p_vcd->play_item.type = VCDINFO_ITEM_TYPE_NOTFOUND;
p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT, p_vcd->p_input = vlc_object_find( p_access, VLC_OBJECT_INPUT,
FIND_PARENT ); FIND_PARENT );
p_vcd->p_demux = vlc_object_find( p_access, VLC_OBJECT_DEMUX,
FIND_PARENT );
p_vcd->p_meta = vlc_meta_New(); p_vcd->p_meta = vlc_meta_New();
p_vcd->p_segments = NULL; p_vcd->p_segments = NULL;
p_vcd->p_entries = NULL; p_vcd->p_entries = NULL;
...@@ -917,18 +950,19 @@ E_(VCDOpen) ( vlc_object_t *p_this ) ...@@ -917,18 +950,19 @@ E_(VCDOpen) ( vlc_object_t *p_this )
p_access->psz_demux = strdup( "ps" ); 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
#if FIXED #if FIXED
if (play_single_item) if (play_single_item)
VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid, VCDFixupPlayList( p_access, p_vcd, psz_source, &itemid,
play_single_item ); play_single_item );
#endif #endif
p_vcd->p_intf = intf_Create( p_access, "vcdx" );
p_vcd->p_intf->b_block = VLC_FALSE;
p_vcd->p_access = p_access;
#ifdef FIXED
intf_RunThread( p_vcd->p_intf );
#endif
free( psz_source ); free( psz_source );
...@@ -943,7 +977,7 @@ E_(VCDOpen) ( vlc_object_t *p_this ) ...@@ -943,7 +977,7 @@ E_(VCDOpen) ( vlc_object_t *p_this )
* VCDClose: closes VCD releasing allocated memory. * VCDClose: closes VCD releasing allocated memory.
*****************************************************************************/ *****************************************************************************/
void void
E_(VCDClose) ( vlc_object_t *p_this ) VCDClose ( vlc_object_t *p_this )
{ {
access_t *p_access = (access_t *)p_this; access_t *p_access = (access_t *)p_this;
vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys; vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
......
...@@ -37,13 +37,13 @@ ...@@ -37,13 +37,13 @@
#include <libvcd/logging.h> #include <libvcd/logging.h>
static inline void static inline void
MetaInfoAddStr(access_t *p_access, char *p_cat, MetaInfoAddStr(access_t *p_access, char *psz_cat,
char *title, const char *str) char *title, const char *psz)
{ {
vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys; vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
if ( str ) { if ( psz ) {
dbg_print( INPUT_DBG_META, "field: %s: %s", title, str); dbg_print( INPUT_DBG_META, "cat %s, field: %s: %s", psz_cat, title, psz);
input_Control( p_vcd->p_input, INPUT_ADD_INFO, p_cat, title, "%s", str); input_Control( p_vcd->p_input, INPUT_ADD_INFO, psz_cat, title, "%s", psz);
} }
} }
...@@ -52,16 +52,27 @@ static inline void ...@@ -52,16 +52,27 @@ static inline void
MetaInfoAddNum(access_t *p_access, char *psz_cat, char *title, int num) MetaInfoAddNum(access_t *p_access, char *psz_cat, char *title, int num)
{ {
vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys; vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
dbg_print( INPUT_DBG_META, "field %s: %d", title, num); dbg_print( INPUT_DBG_META, "cat %s, field %s: %d", psz_cat, title, num);
input_Control( p_vcd->p_input, INPUT_ADD_INFO, psz_cat, title, "%d", num ); input_Control( p_vcd->p_input, INPUT_ADD_INFO, psz_cat, title, "%d", num );
} }
static inline void
MetaInfoAddHex(access_t *p_access, char *psz_cat, char *title, int hex)
{
vcdplayer_t *p_vcd = (vcdplayer_t *) p_access->p_sys;
dbg_print( INPUT_DBG_META, "cat %s, field %s: %d", psz_cat, title, hex);
input_Control( p_vcd->p_input, INPUT_ADD_INFO, psz_cat, title, "%x", hex );
}
#define addstr(title, str) \ #define addstr(title, str) \
MetaInfoAddStr( p_access, psz_cat, title, str ); MetaInfoAddStr( p_access, psz_cat, title, str );
#define addnum(title, num) \ #define addnum(title, num) \
MetaInfoAddNum( p_access, psz_cat, title, num ); MetaInfoAddNum( p_access, psz_cat, title, num );
#define addhex(title, hex) \
MetaInfoAddHex( p_access, psz_cat, title, hex );
void void
VCDMetaInfo( access_t *p_access, /*const*/ char *psz_mrl ) VCDMetaInfo( access_t *p_access, /*const*/ char *psz_mrl )
{ {
...@@ -111,6 +122,49 @@ VCDMetaInfo( access_t *p_access, /*const*/ char *psz_mrl ) ...@@ -111,6 +122,49 @@ VCDMetaInfo( access_t *p_access, /*const*/ char *psz_mrl )
addnum(_("Track size (in sectors)"), i_secsize ); addnum(_("Track size (in sectors)"), i_secsize );
} }
{
lid_t i_lid;
for( i_lid = 1 ; i_lid <= p_vcd->i_lids ; i_lid++ ) {
PsdListDescriptor_t pxd;
char psz_cat[20];
snprintf(psz_cat, sizeof(psz_cat), "LID %d", i_lid);
if (vcdinfo_lid_get_pxd(p_vcd->vcd, &pxd, i_lid)) {
switch (pxd.descriptor_type) {
case PSD_TYPE_END_LIST:
addstr(_("type"), _("end"));
break;
case PSD_TYPE_PLAY_LIST:
addstr(_("type"), _("play list"));
addnum("items", vcdinf_pld_get_noi(pxd.pld));
addhex("next", vcdinf_pld_get_next_offset(pxd.pld));
addhex("previous", vcdinf_pld_get_prev_offset(pxd.pld));
addhex("return", vcdinf_pld_get_return_offset(pxd.pld));
addnum("wait time", vcdinf_get_wait_time(pxd.pld));
break;
case PSD_TYPE_SELECTION_LIST:
case PSD_TYPE_EXT_SELECTION_LIST:
addstr(_("type"),
PSD_TYPE_SELECTION_LIST == pxd.descriptor_type
? _("extended selection list")
: _("selection list")
);
addhex("default", vcdinf_psd_get_default_offset(pxd.psd));
addhex("loop count", vcdinf_get_loop_count(pxd.psd));
addhex("next", vcdinf_psd_get_next_offset(pxd.psd));
addhex("previous", vcdinf_psd_get_prev_offset(pxd.psd));
addhex("return", vcdinf_psd_get_return_offset(pxd.psd));
addhex("rejected", vcdinf_psd_get_lid_rejected(pxd.psd));
addhex("time-out offset", vcdinf_get_timeout_offset(pxd.psd));
addnum("time-out time", vcdinf_get_timeout_time(pxd.psd));
break;
default:
addstr(_("type"), _("unknown type"));
break;
}
}
}
}
if ( CDIO_INVALID_TRACK != i_track ) if ( CDIO_INVALID_TRACK != i_track )
{ {
char *psz_name = char *psz_name =
...@@ -310,110 +364,6 @@ VCDFormatStr(const access_t *p_access, vcdplayer_t *p_vcd, ...@@ -310,110 +364,6 @@ VCDFormatStr(const access_t *p_access, vcdplayer_t *p_vcd,
return strdup(temp_str); return strdup(temp_str);
} }
static void
VCDCreatePlayListItem(const access_t *p_access,
vcdplayer_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%3u", 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, vcdplayer_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;
}
void void
VCDUpdateTitle( access_t *p_access ) VCDUpdateTitle( access_t *p_access )
{ {
......
...@@ -26,13 +26,6 @@ ...@@ -26,13 +26,6 @@
#include "vcdplayer.h" #include "vcdplayer.h"
/*
Fills out playlist information.
*/
int VCDFixupPlayList( access_t *p_access, vcdplayer_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. Sets VCD meta information and navigation/playlist entries.
*/ */
......
...@@ -27,10 +27,8 @@ ...@@ -27,10 +27,8 @@
*****************************************************************************/ *****************************************************************************/
#include <vlc/vlc.h> #include <vlc/vlc.h>
#include <vlc/intf.h> #include <vlc/intf.h>
#include <vlc/input.h>
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
#include "vlc_keys.h" #include "vlc_keys.h"
#include "vcd.h" #include "vcd.h"
...@@ -50,7 +48,7 @@ static void RunIntf ( intf_thread_t *p_intf ); ...@@ -50,7 +48,7 @@ static void RunIntf ( intf_thread_t *p_intf );
/***************************************************************************** /*****************************************************************************
* OpenIntf: initialize dummy interface * OpenIntf: initialize dummy interface
*****************************************************************************/ *****************************************************************************/
int E_(OpenIntf) ( vlc_object_t *p_this ) int VCDOpenIntf ( vlc_object_t *p_this )
{ {
intf_thread_t *p_intf = (intf_thread_t *)p_this; intf_thread_t *p_intf = (intf_thread_t *)p_this;
...@@ -60,23 +58,23 @@ int E_(OpenIntf) ( vlc_object_t *p_this ) ...@@ -60,23 +58,23 @@ int E_(OpenIntf) ( vlc_object_t *p_this )
p_intf->p_sys = malloc( sizeof( intf_sys_t ) ); p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
if( p_intf->p_sys == NULL ) if( p_intf->p_sys == NULL )
{ {
return( 1 ); return( VLC_EGENERIC );
}; };
p_intf->pf_run = RunIntf; p_intf->pf_run = RunIntf;
var_AddCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf ); var_AddCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf );
p_intf->p_sys->m_still_time = 0; p_intf->p_sys->m_still_time = 0;
p_intf->p_sys->b_inf_still = 0; p_intf->p_sys->b_infinite_still = 0;
p_intf->p_sys->b_still = 0; p_intf->p_sys->b_still = 0;
return( 0 ); return( VLC_SUCCESS );
} }
/***************************************************************************** /*****************************************************************************
* CloseIntf: destroy dummy interface * CloseIntf: destroy dummy interface
*****************************************************************************/ *****************************************************************************/
void E_(CloseIntf) ( vlc_object_t *p_this ) void VCDCloseIntf ( vlc_object_t *p_this )
{ {
intf_thread_t *p_intf = (intf_thread_t *)p_this; intf_thread_t *p_intf = (intf_thread_t *)p_this;
var_DelCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf ); var_DelCallback( p_intf->p_vlc, "key-pressed", KeyEvent, p_intf );
...@@ -89,13 +87,15 @@ void E_(CloseIntf) ( vlc_object_t *p_this ) ...@@ -89,13 +87,15 @@ void E_(CloseIntf) ( vlc_object_t *p_this )
/***************************************************************************** /*****************************************************************************
* RunIntf: main loop * RunIntf: main loop
*****************************************************************************/ *****************************************************************************/
static void RunIntf( intf_thread_t *p_intf ) static void
RunIntf( intf_thread_t *p_intf )
{ {
vlc_object_t * p_vout = NULL; vlc_object_t * p_vout = NULL;
mtime_t mtime = 0; mtime_t mtime = 0;
mtime_t mlast = 0; mtime_t mlast = 0;
thread_vcd_data_t * p_vcd; vcdplayer_t * p_vcd;
input_thread_t * p_input; input_thread_t * p_input;
access_t * p_access;
/* What you add to the last input number entry. It accumulates all of /* What you add to the last input number entry. It accumulates all of
the 10_ADD keypresses */ the 10_ADD keypresses */
...@@ -108,8 +108,14 @@ static void RunIntf( intf_thread_t *p_intf ) ...@@ -108,8 +108,14 @@ static void RunIntf( intf_thread_t *p_intf )
} }
p_input = p_intf->p_sys->p_input; p_input = p_intf->p_sys->p_input;
p_vcd = p_intf->p_sys->p_vcd =
(thread_vcd_data_t *) p_input->p_access_data; while ( !p_intf->p_sys->p_vcd )
{
msleep( INTF_IDLE_SLEEP );
}
p_vcd = p_intf->p_sys->p_vcd;
p_access = p_vcd->p_access;
dbg_print( INPUT_DBG_CALL, "intf initialized" ); dbg_print( INPUT_DBG_CALL, "intf initialized" );
...@@ -121,7 +127,7 @@ static void RunIntf( intf_thread_t *p_intf ) ...@@ -121,7 +127,7 @@ static void RunIntf( intf_thread_t *p_intf )
/* /*
* Have we timed-out in showing a still frame? * Have we timed-out in showing a still frame?
*/ */
if( p_intf->p_sys->b_still && !p_intf->p_sys->b_inf_still ) if( p_intf->p_sys->b_still && !p_intf->p_sys->b_infinite_still )
{ {
if( p_intf->p_sys->m_still_time > 0 ) if( p_intf->p_sys->m_still_time > 0 )
{ {
...@@ -137,7 +143,7 @@ static void RunIntf( intf_thread_t *p_intf ) ...@@ -137,7 +143,7 @@ static void RunIntf( intf_thread_t *p_intf )
} }
else else
{ {
/* Still time has elasped; set to continue playing. */ /* Still time has elapsed; set to continue playing. */
dbg_print(INPUT_DBG_STILL, "wait time done - setting play"); dbg_print(INPUT_DBG_STILL, "wait time done - setting play");
var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S ); var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S );
p_intf->p_sys->m_still_time = 0; p_intf->p_sys->m_still_time = 0;
...@@ -177,7 +183,7 @@ static void RunIntf( intf_thread_t *p_intf ) ...@@ -177,7 +183,7 @@ static void RunIntf( intf_thread_t *p_intf )
dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_LEFT - prev (%d)", dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_LEFT - prev (%d)",
number_addend ); number_addend );
do { do {
vcdplayer_play_prev( p_input ); vcdplayer_play_prev( p_access );
} while (number_addend-- > 0); } while (number_addend-- > 0);
break; break;
...@@ -185,20 +191,20 @@ static void RunIntf( intf_thread_t *p_intf ) ...@@ -185,20 +191,20 @@ static void RunIntf( intf_thread_t *p_intf )
dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_RIGHT - next (%d)", dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_RIGHT - next (%d)",
number_addend ); number_addend );
do { do {
vcdplayer_play_next( p_input ); vcdplayer_play_next( p_access );
} while (number_addend-- > 0); } while (number_addend-- > 0);
break; break;
case ACTIONID_NAV_UP: case ACTIONID_NAV_UP:
dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_UP - return" ); dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_UP - return" );
do { do {
vcdplayer_play_return( p_input ); vcdplayer_play_return( p_access );
} while (number_addend-- > 0); } while (number_addend-- > 0);
break; break;
case ACTIONID_NAV_DOWN: case ACTIONID_NAV_DOWN:
dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_DOWN - default" ); dbg_print( INPUT_DBG_EVENT, "ACTIONID_NAV_DOWN - default" );
vcdplayer_play_default( p_input ); vcdplayer_play_default( p_access );
break; break;
case ACTIONID_NAV_ACTIVATE: case ACTIONID_NAV_ACTIVATE:
...@@ -210,16 +216,16 @@ static void RunIntf( intf_thread_t *p_intf ) ...@@ -210,16 +216,16 @@ static void RunIntf( intf_thread_t *p_intf )
if ( vcdplayer_pbc_is_on( p_vcd ) && number_addend != 0 ) { if ( vcdplayer_pbc_is_on( p_vcd ) && number_addend != 0 ) {
lid_t next_num=vcdinfo_selection_get_lid(p_vcd->vcd, lid_t next_num=vcdinfo_selection_get_lid(p_vcd->vcd,
p_vcd->cur_lid, p_vcd->i_lid,
number_addend); number_addend);
if (VCDINFO_INVALID_LID != next_num) { if (VCDINFO_INVALID_LID != next_num) {
itemid.num = next_num; itemid.num = next_num;
itemid.type = VCDINFO_ITEM_TYPE_LID; itemid.type = VCDINFO_ITEM_TYPE_LID;
VCDPlay( p_input, itemid ); vcdplayer_play( p_access, itemid );
} }
} else { } else {
itemid.num = number_addend; itemid.num = number_addend;
VCDPlay( p_input, itemid ); vcdplayer_play( p_access, itemid );
} }
break; break;
} }
...@@ -234,7 +240,7 @@ static void RunIntf( intf_thread_t *p_intf ) ...@@ -234,7 +240,7 @@ static void RunIntf( intf_thread_t *p_intf )
dbg_print(INPUT_DBG_STILL, "Playing still after activate"); dbg_print(INPUT_DBG_STILL, "Playing still after activate");
var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S ); var_SetInteger( p_intf->p_sys->p_input, "state", PLAYING_S );
p_intf->p_sys->b_still = 0; p_intf->p_sys->b_still = 0;
p_intf->p_sys->b_inf_still = 0; p_intf->p_sys->b_infinite_still = 0;
p_intf->p_sys->m_still_time = 0; p_intf->p_sys->m_still_time = 0;
} }
...@@ -321,6 +327,7 @@ static int InitThread( intf_thread_t * p_intf ) ...@@ -321,6 +327,7 @@ static int InitThread( intf_thread_t * p_intf )
vlc_mutex_lock( &p_intf->change_lock ); vlc_mutex_lock( &p_intf->change_lock );
p_intf->p_sys->p_input = p_input; p_intf->p_sys->p_input = p_input;
p_intf->p_sys->p_vcd = NULL;
p_intf->p_sys->b_move = VLC_FALSE; p_intf->p_sys->b_move = VLC_FALSE;
p_intf->p_sys->b_click = VLC_FALSE; p_intf->p_sys->b_click = VLC_FALSE;
...@@ -356,19 +363,18 @@ static int KeyEvent( vlc_object_t *p_this, char const *psz_var, ...@@ -356,19 +363,18 @@ static int KeyEvent( vlc_object_t *p_this, char const *psz_var,
* vcdIntfStillTime: function provided to demux plugin to request * vcdIntfStillTime: function provided to demux plugin to request
* still images * still images
*****************************************************************************/ *****************************************************************************/
int vcdIntfStillTime( intf_thread_t *p_intf, int i_sec ) int vcdIntfStillTime( intf_thread_t *p_intf, uint8_t i_sec )
{ {
vlc_mutex_lock( &p_intf->change_lock ); vlc_mutex_lock( &p_intf->change_lock );
if( i_sec == -1 )
{
p_intf->p_sys->b_still = 1; p_intf->p_sys->b_still = 1;
p_intf->p_sys->b_inf_still = 1; if( 255 == i_sec )
{
p_intf->p_sys->b_infinite_still = VLC_TRUE;
} }
else if( i_sec > 0 ) else
{ {
p_intf->p_sys->b_still = 1; p_intf->p_sys->m_still_time = MILLISECONDS_PER_SEC * i_sec;
p_intf->p_sys->m_still_time = 1000000 * i_sec;
} }
vlc_mutex_unlock( &p_intf->change_lock ); vlc_mutex_unlock( &p_intf->change_lock );
......
...@@ -30,7 +30,7 @@ struct intf_sys_t ...@@ -30,7 +30,7 @@ struct intf_sys_t
vcdplayer_t *p_vcd; vcdplayer_t *p_vcd;
vlc_bool_t b_still; /* True if we are in a still frame */ 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 */ vlc_bool_t b_infinite_still; /* True if still wait time is infinite */
mtime_t m_still_time; /* Time in microseconds remaining mtime_t m_still_time; /* Time in microseconds remaining
to wait in still frame. to wait in still frame.
*/ */
...@@ -42,6 +42,6 @@ struct intf_sys_t ...@@ -42,6 +42,6 @@ struct intf_sys_t
vlc_bool_t b_click, b_move, b_key_pressed; vlc_bool_t b_click, b_move, b_key_pressed;
}; };
int vcdIntfStillTime( struct intf_thread_t *, int ); int vcdIntfStillTime( struct intf_thread_t * p_intf, uint8_t wait_time);
int vcdIntfResetStillTime( intf_thread_t *p_intf ); int vcdIntfResetStillTime( intf_thread_t *p_intf );
...@@ -34,10 +34,10 @@ ...@@ -34,10 +34,10 @@
/***************************************************************************** /*****************************************************************************
* Exported prototypes * Exported prototypes
*****************************************************************************/ *****************************************************************************/
int E_(VCDOpen) ( vlc_object_t * ); int VCDOpen ( vlc_object_t * );
void E_(VCDClose) ( vlc_object_t * ); void VCDClose ( vlc_object_t * );
int E_(OpenIntf) ( vlc_object_t * ); int VCDOpenIntf ( vlc_object_t * );
void E_(CloseIntf) ( vlc_object_t * ); void VCDCloseIntf ( vlc_object_t * );
int E_(VCDInit) ( vlc_object_t * ); int E_(VCDInit) ( vlc_object_t * );
void E_(VCDEnd) ( vlc_object_t * ); void E_(VCDEnd) ( vlc_object_t * );
...@@ -96,7 +96,7 @@ vlc_module_begin(); ...@@ -96,7 +96,7 @@ vlc_module_begin();
set_description( _("Video CD (VCD 1.0, 1.1, 2.0, SVCD, HQVCD) input") ); set_description( _("Video CD (VCD 1.0, 1.1, 2.0, SVCD, HQVCD) input") );
set_capability( "access2", 55 /* slightly lower than vcd */ ); set_capability( "access2", 55 /* slightly lower than vcd */ );
set_shortname( N_("(Super) Video CD")); set_shortname( N_("(Super) Video CD"));
set_callbacks( E_(VCDOpen), E_(VCDClose) ); set_callbacks( VCDOpen, VCDClose );
add_shortcut( "vcdx" ); add_shortcut( "vcdx" );
set_category( CAT_INPUT ); set_category( CAT_INPUT );
set_subcategory( SUBCAT_INPUT_ACCESS ); set_subcategory( SUBCAT_INPUT_ACCESS );
...@@ -118,6 +118,12 @@ vlc_module_begin(); ...@@ -118,6 +118,12 @@ vlc_module_begin();
"Otherwise we play by tracks."), "Otherwise we play by tracks."),
VLC_FALSE ); VLC_FALSE );
add_bool( MODULE_STRING "-extended-info", 0, NULL,
N_("Show extended VCD info?"),
N_("Show the maximum about of information under Stream and "
"Media Info. Shows for example playback control navigation."),
VLC_FALSE );
add_string( MODULE_STRING "-author-format", add_string( MODULE_STRING "-author-format",
"%v - %F disc %c of %C", "%v - %F disc %c of %C",
NULL, NULL,
...@@ -131,12 +137,9 @@ vlc_module_begin(); ...@@ -131,12 +137,9 @@ vlc_module_begin();
VCD_TITLE_FMT_LONGTEXT, VLC_FALSE ); VCD_TITLE_FMT_LONGTEXT, VLC_FALSE );
#ifdef FIXED #ifdef FIXED
add_submodule();
set_capability( "demux", 0 );
set_callbacks( E_(VCDInit), E_(VCDEnd) );
add_submodule(); add_submodule();
set_capability( "interface", 0 ); set_capability( "interface", 0 );
set_callbacks( E_(OpenIntf), E_(CloseIntf) ); set_callbacks( VCDOpenIntf, VCDCloseIntf );
#endif #endif
vlc_module_end(); vlc_module_end();
......
...@@ -54,4 +54,3 @@ typedef struct ...@@ -54,4 +54,3 @@ typedef struct
int VCDSetArea ( access_t * ); int VCDSetArea ( access_t * );
int VCDSeek ( access_t *, off_t ); int VCDSeek ( access_t *, off_t );
int VCDPlay ( access_t *, vcdinfo_itemid_t );
...@@ -51,9 +51,9 @@ extern void VCDSetOrigin ( access_t *p_access, lsn_t i_lsn, track_t i_track, ...@@ -51,9 +51,9 @@ extern void VCDSetOrigin ( access_t *p_access, lsn_t i_lsn, track_t i_track,
const vcdinfo_itemid_t * p_itemid ); const vcdinfo_itemid_t * p_itemid );
/*! /*!
Return VLC_TRUE if playback control (PBC) is on Return true if playback control (PBC) is on
*/ */
vlc_bool_t bool
vcdplayer_pbc_is_on( const vcdplayer_t *p_vcd ) vcdplayer_pbc_is_on( const vcdplayer_t *p_vcd )
{ {
return VCDINFO_INVALID_ENTRY != p_vcd->i_lid; return VCDINFO_INVALID_ENTRY != p_vcd->i_lid;
...@@ -111,10 +111,10 @@ vcdplayer_update_entry( access_t * p_access, uint16_t ofs, ...@@ -111,10 +111,10 @@ vcdplayer_update_entry( access_t * p_access, uint16_t ofs,
The navigations rules here may be sort of made up, but the intent The navigations rules here may be sort of made up, but the intent
is to do something that's probably right or helpful. is to do something that's probably right or helpful.
return VLC_TRUE if the caller should return. return true if the caller should return.
*/ */
vcdplayer_read_status_t vcdplayer_read_status_t
vcdplayer_non_pbc_nav ( access_t *p_access ) vcdplayer_non_pbc_nav ( access_t *p_access, uint8_t *wait_time )
{ {
vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys; vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
...@@ -131,9 +131,11 @@ vcdplayer_non_pbc_nav ( access_t *p_access ) ...@@ -131,9 +131,11 @@ vcdplayer_non_pbc_nav ( access_t *p_access )
case VCDINFO_ITEM_TYPE_SPAREID2: case VCDINFO_ITEM_TYPE_SPAREID2:
dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN), dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
"SPAREID2" ); "SPAREID2" );
/* FIXME */
if (p_vcd->in_still) if (p_vcd->in_still)
{ {
dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
"End of still spareid2" );
*wait_time = 255;
return READ_STILL_FRAME ; return READ_STILL_FRAME ;
} }
return READ_END; return READ_END;
...@@ -149,7 +151,8 @@ vcdplayer_non_pbc_nav ( access_t *p_access ) ...@@ -149,7 +151,8 @@ vcdplayer_non_pbc_nav ( access_t *p_access )
if (p_vcd->in_still) if (p_vcd->in_still)
{ {
dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN), dbg_print( (INPUT_DBG_STILL|INPUT_DBG_LSN),
"End of Segment - looping" ); "End of still Segment" );
*wait_time = 10;
return READ_STILL_FRAME; return READ_STILL_FRAME;
} }
return READ_END; return READ_END;
...@@ -242,7 +245,7 @@ _vcdplayer_set_segment(access_t * p_access, unsigned int num) ...@@ -242,7 +245,7 @@ _vcdplayer_set_segment(access_t * p_access, unsigned int num)
/* Play entry. */ /* Play entry. */
/* Play a single item. */ /* Play a single item. */
static void static bool
vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid) vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
{ {
vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys; vcdplayer_t *p_vcd = (vcdplayer_t *)p_access->p_sys;
...@@ -264,7 +267,7 @@ vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid) ...@@ -264,7 +267,7 @@ vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
vcdinfo_video_type2str(p_obj, itemid.num), vcdinfo_video_type2str(p_obj, itemid.num),
(int) segtype, itemid.num); (int) segtype, itemid.num);
if (itemid.num >= num_segs) return; if (itemid.num >= num_segs) return false;
_vcdplayer_set_segment(p_access, itemid.num); _vcdplayer_set_segment(p_access, itemid.num);
switch (segtype) switch (segtype)
...@@ -284,7 +287,7 @@ vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid) ...@@ -284,7 +287,7 @@ vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
case VCDINFO_ITEM_TYPE_TRACK: case VCDINFO_ITEM_TYPE_TRACK:
dbg_print(INPUT_DBG_PBC, "track %d", itemid.num); dbg_print(INPUT_DBG_PBC, "track %d", itemid.num);
if (itemid.num < 1 || itemid.num > p_vcd->i_tracks) return; if (itemid.num < 1 || itemid.num > p_vcd->i_tracks) return false;
_vcdplayer_set_track(p_access, itemid.num); _vcdplayer_set_track(p_access, itemid.num);
break; break;
...@@ -292,23 +295,24 @@ vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid) ...@@ -292,23 +295,24 @@ vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
{ {
unsigned int num_entries = vcdinfo_get_num_entries(p_obj); unsigned int num_entries = vcdinfo_get_num_entries(p_obj);
dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num); dbg_print(INPUT_DBG_PBC, "entry %d", itemid.num);
if (itemid.num >= num_entries) return; if (itemid.num >= num_entries) return false;
_vcdplayer_set_entry(p_access, itemid.num); _vcdplayer_set_entry(p_access, itemid.num);
break; break;
} }
case VCDINFO_ITEM_TYPE_LID: case VCDINFO_ITEM_TYPE_LID:
LOG_ERR("%s", _("Should have converted p_vcd above")); LOG_ERR("%s", _("Should have converted p_vcd above"));
return false;
break; break;
case VCDINFO_ITEM_TYPE_NOTFOUND: case VCDINFO_ITEM_TYPE_NOTFOUND:
dbg_print(INPUT_DBG_PBC, "play nothing"); dbg_print(INPUT_DBG_PBC, "play nothing");
p_vcd->i_lsn = p_vcd->end_lsn; p_vcd->i_lsn = p_vcd->end_lsn;
return; return false;
default: default:
LOG_ERR("item type %d not implemented.", itemid.type); LOG_ERR("item type %d not implemented.", itemid.type);
return; return false;
} }
p_vcd->play_item = itemid; p_vcd->play_item = itemid;
...@@ -317,6 +321,7 @@ vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid) ...@@ -317,6 +321,7 @@ vcdplayer_play_single_item( access_t * p_access, vcdinfo_itemid_t itemid)
that need to be flushed when playing a new selection. */ that need to be flushed when playing a new selection. */
/* if (p_vcd->flush_buffers) /* if (p_vcd->flush_buffers)
p_vcd->flush_buffers(); */ p_vcd->flush_buffers(); */
return true;
} }
/* /*
...@@ -383,8 +388,7 @@ _vcdplayer_inc_play_item(access_t *p_access) ...@@ -383,8 +388,7 @@ _vcdplayer_inc_play_item(access_t *p_access)
vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid); vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s", dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num)); p_vcd->pdi, vcdinfo_pin2str (trans_itemid_num));
vcdplayer_play_single_item(p_access, trans_itemid); return vcdplayer_play_single_item(p_access, trans_itemid);
return true;
} }
} }
...@@ -442,7 +446,7 @@ vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid) ...@@ -442,7 +446,7 @@ vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid)
/* Handles PBC navigation when reaching the end of a play item. */ /* Handles PBC navigation when reaching the end of a play item. */
vcdplayer_read_status_t vcdplayer_read_status_t
vcdplayer_pbc_nav ( access_t * p_access ) vcdplayer_pbc_nav ( access_t * p_access, uint8_t *wait_time )
{ {
vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys; vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
...@@ -468,21 +472,18 @@ vcdplayer_pbc_nav ( access_t * p_access ) ...@@ -468,21 +472,18 @@ vcdplayer_pbc_nav ( access_t * p_access )
return READ_END; return READ_END;
break; break;
case PSD_TYPE_PLAY_LIST: { case PSD_TYPE_PLAY_LIST: {
int wait_time = vcdinf_get_wait_time(p_vcd->pxd.pld);
dbg_print(INPUT_DBG_PBC, "playlist wait_time: %d", wait_time);
if (vcdplayer_inc_play_item(p_access)) if (vcdplayer_inc_play_item(p_access))
return READ_BLOCK; return READ_BLOCK;
/* Handle any wait time given. */ /* Set up for caller process wait time given. */
#if FIXED
if (p_vcd->in_still) { if (p_vcd->in_still) {
vcdIntfStillTime( p_vcd->p_intf, wait_time ); *wait_time = vcdinf_get_wait_time(p_vcd->pxd.pld);
dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
"playlist wait time: %d", *wait_time);
return READ_STILL_FRAME; return READ_STILL_FRAME;
} }
#endif
/* Wait time has been processed; continue with next entry. */
vcdplayer_update_entry( p_access, vcdplayer_update_entry( p_access,
vcdinf_pld_get_next_offset(p_vcd->pxd.pld), vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
&itemid.num, "next" ); &itemid.num, "next" );
...@@ -493,23 +494,23 @@ vcdplayer_pbc_nav ( access_t * p_access ) ...@@ -493,23 +494,23 @@ vcdplayer_pbc_nav ( access_t * p_access )
case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */ case PSD_TYPE_SELECTION_LIST: /* Selection List (+Ext. for SVCD) */
case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */ case PSD_TYPE_EXT_SELECTION_LIST: /* Extended Selection List (VCD2.0) */
{ {
int wait_time = vcdinf_get_timeout_time(p_vcd->pxd.psd);
uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcd->pxd.psd); uint16_t timeout_offs = vcdinf_get_timeout_offset(p_vcd->pxd.psd);
uint16_t max_loop = vcdinf_get_loop_count(p_vcd->pxd.psd); uint16_t max_loop = vcdinf_get_loop_count(p_vcd->pxd.psd);
vcdinfo_offset_t *offset_timeout_LID = vcdinfo_offset_t *offset_timeout_LID =
vcdinfo_get_offset_t(p_vcd->vcd, timeout_offs); vcdinfo_get_offset_t(p_vcd->vcd, timeout_offs);
dbg_print(INPUT_DBG_PBC, "wait_time: %d, looped: %d, max_loop %d", dbg_print(INPUT_DBG_PBC, "looped: %d, max_loop %d",
wait_time, p_vcd->loop_count, max_loop); p_vcd->loop_count, max_loop);
/* Handle any wait time given */ /* Set up for caller process wait time given. */
#if FIXED
if (p_vcd->in_still) { if (p_vcd->in_still) {
vcdIntfStillTime( p_vcd->p_intf, wait_time ); *wait_time = vcdinf_get_timeout_time(p_vcd->pxd.psd);
dbg_print((INPUT_DBG_PBC|INPUT_DBG_STILL),
"playlist wait_time: %d", *wait_time);
return READ_STILL_FRAME; return READ_STILL_FRAME;
} }
#endif
/* Wait time has been processed; continue with next entry. */
/* Handle any looping given. */ /* Handle any looping given. */
if ( max_loop == 0 || p_vcd->loop_count < max_loop ) { if ( max_loop == 0 || p_vcd->loop_count < max_loop ) {
p_vcd->loop_count++; p_vcd->loop_count++;
...@@ -583,9 +584,10 @@ vcdplayer_read (access_t * p_access, uint8_t *p_buf) ...@@ -583,9 +584,10 @@ vcdplayer_read (access_t * p_access, uint8_t *p_buf)
{ {
/* p_access->handle_events (); */ /* p_access->handle_events (); */
uint8_t wait_time;
vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys; vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
if ( p_vcd->i_lsn >= p_vcd->end_lsn ) { if ( p_vcd->i_lsn > p_vcd->end_lsn ) {
vcdplayer_read_status_t read_status; vcdplayer_read_status_t read_status;
/* We've run off of the end of this entry. Do we continue or stop? */ /* We've run off of the end of this entry. Do we continue or stop? */
...@@ -594,8 +596,13 @@ vcdplayer_read (access_t * p_access, uint8_t *p_buf) ...@@ -594,8 +596,13 @@ vcdplayer_read (access_t * p_access, uint8_t *p_buf)
handle_item_continuation: handle_item_continuation:
read_status = vcdplayer_pbc_is_on( p_vcd ) read_status = vcdplayer_pbc_is_on( p_vcd )
? vcdplayer_pbc_nav( p_access ) ? vcdplayer_pbc_nav( p_access, &wait_time )
: vcdplayer_non_pbc_nav( p_access ); : vcdplayer_non_pbc_nav( p_access, &wait_time );
if (READ_STILL_FRAME == read_status) {
*p_buf = wait_time;
return READ_STILL_FRAME;
}
if (READ_BLOCK != read_status) return read_status; if (READ_BLOCK != read_status) return read_status;
} }
...@@ -621,6 +628,7 @@ vcdplayer_read (access_t * p_access, uint8_t *p_buf) ...@@ -621,6 +628,7 @@ vcdplayer_read (access_t * p_access, uint8_t *p_buf)
do { do {
if (cdio_read_mode2_sector(p_img, &vcd_sector, p_vcd->i_lsn, true)!=0) { if (cdio_read_mode2_sector(p_img, &vcd_sector, p_vcd->i_lsn, true)!=0) {
dbg_print(INPUT_DBG_LSN, "read error\n"); dbg_print(INPUT_DBG_LSN, "read error\n");
p_vcd->i_lsn++;
return READ_ERROR; return READ_ERROR;
} }
p_vcd->i_lsn++; p_vcd->i_lsn++;
...@@ -654,7 +662,7 @@ vcdplayer_read (access_t * p_access, uint8_t *p_buf) ...@@ -654,7 +662,7 @@ vcdplayer_read (access_t * p_access, uint8_t *p_buf)
confused with a user's list of favorite things to play or the 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. "next" field of a LID which moves us to a different LID.
*/ */
vlc_bool_t bool
vcdplayer_inc_play_item( access_t *p_access ) vcdplayer_inc_play_item( access_t *p_access )
{ {
vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys; vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
...@@ -663,24 +671,24 @@ vcdplayer_inc_play_item( access_t *p_access ) ...@@ -663,24 +671,24 @@ vcdplayer_inc_play_item( access_t *p_access )
dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcd->pdi); dbg_print(INPUT_DBG_CALL, "called pli: %d", p_vcd->pdi);
if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return VLC_FALSE; if ( NULL == p_vcd || NULL == p_vcd->pxd.pld ) return false;
noi = vcdinf_pld_get_noi(p_vcd->pxd.pld); noi = vcdinf_pld_get_noi(p_vcd->pxd.pld);
if ( noi <= 0 ) return VLC_FALSE; if ( noi <= 0 ) return false;
/* Handle delays like autowait or wait here? */ /* Handle delays like autowait or wait here? */
p_vcd->pdi++; p_vcd->pdi++;
if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return VLC_FALSE; if ( p_vcd->pdi < 0 || p_vcd->pdi >= noi ) return false;
else { else {
uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld, uint16_t trans_itemid_num=vcdinf_pld_get_play_item(p_vcd->pxd.pld,
p_vcd->pdi); p_vcd->pdi);
vcdinfo_itemid_t trans_itemid; vcdinfo_itemid_t trans_itemid;
if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return VLC_FALSE; if (VCDINFO_INVALID_ITEMID == trans_itemid_num) return false;
vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid); vcdinfo_classify_itemid(trans_itemid_num, &trans_itemid);
dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s", dbg_print(INPUT_DBG_PBC, " play-item[%d]: %s",
...@@ -693,9 +701,9 @@ vcdplayer_inc_play_item( access_t *p_access ) ...@@ -693,9 +701,9 @@ vcdplayer_inc_play_item( access_t *p_access )
/*! /*!
Play item assocated with the "default" selection. Play item assocated with the "default" selection.
Return VLC_FALSE if there was some problem. Return false if there was some problem.
*/ */
vlc_bool_t bool
vcdplayer_play_default( access_t * p_access ) vcdplayer_play_default( access_t * p_access )
{ {
vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys; vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
...@@ -734,7 +742,7 @@ vcdplayer_play_default( access_t * p_access ) ...@@ -734,7 +742,7 @@ vcdplayer_play_default( access_t * p_access )
switch (p_vcd->pxd.descriptor_type) { switch (p_vcd->pxd.descriptor_type) {
case PSD_TYPE_SELECTION_LIST: case PSD_TYPE_SELECTION_LIST:
case PSD_TYPE_EXT_SELECTION_LIST: case PSD_TYPE_EXT_SELECTION_LIST:
if (p_vcd->pxd.psd == NULL) return VLC_FALSE; if (p_vcd->pxd.psd == NULL) return false;
vcdplayer_update_entry( p_access, vcdplayer_update_entry( p_access,
vcdinfo_get_default_offset(p_vcd->vcd, vcdinfo_get_default_offset(p_vcd->vcd,
p_vcd->i_lid), p_vcd->i_lid),
...@@ -745,7 +753,7 @@ vcdplayer_play_default( access_t * p_access ) ...@@ -745,7 +753,7 @@ vcdplayer_play_default( access_t * p_access )
case PSD_TYPE_END_LIST: case PSD_TYPE_END_LIST:
case PSD_TYPE_COMMAND_LIST: case PSD_TYPE_COMMAND_LIST:
LOG_WARN( "There is no PBC 'default' selection here" ); LOG_WARN( "There is no PBC 'default' selection here" );
return VLC_FALSE; return false;
} }
#endif /* LIBVCD_VERSION (< 0.7.21) */ #endif /* LIBVCD_VERSION (< 0.7.21) */
...@@ -768,9 +776,9 @@ vcdplayer_play_default( access_t * p_access ) ...@@ -768,9 +776,9 @@ vcdplayer_play_default( access_t * p_access )
/*! /*!
Play item assocated with the "next" selection. Play item assocated with the "next" selection.
Return VLC_FALSE if there was some problem. Return false if there was some problem.
*/ */
vlc_bool_t bool
vcdplayer_play_next( access_t * p_access ) vcdplayer_play_next( access_t * p_access )
{ {
vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys; vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
...@@ -778,7 +786,7 @@ vcdplayer_play_next( access_t * p_access ) ...@@ -778,7 +786,7 @@ vcdplayer_play_next( access_t * p_access )
vcdinfo_obj_t *p_obj; vcdinfo_obj_t *p_obj;
vcdinfo_itemid_t itemid; vcdinfo_itemid_t itemid;
if (!p_vcd) return VLC_FALSE; if (!p_vcd) return false;
dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC), dbg_print( (INPUT_DBG_CALL|INPUT_DBG_PBC),
"current: %d" , p_vcd->play_item.num); "current: %d" , p_vcd->play_item.num);
...@@ -794,7 +802,7 @@ vcdplayer_play_next( access_t * p_access ) ...@@ -794,7 +802,7 @@ vcdplayer_play_next( access_t * p_access )
switch (p_vcd->pxd.descriptor_type) { switch (p_vcd->pxd.descriptor_type) {
case PSD_TYPE_SELECTION_LIST: case PSD_TYPE_SELECTION_LIST:
case PSD_TYPE_EXT_SELECTION_LIST: case PSD_TYPE_EXT_SELECTION_LIST:
if (p_vcd->pxd.psd == NULL) return VLC_FALSE; if (p_vcd->pxd.psd == NULL) return false;
vcdplayer_update_entry( p_access, vcdplayer_update_entry( p_access,
vcdinf_psd_get_next_offset(p_vcd->pxd.psd), vcdinf_psd_get_next_offset(p_vcd->pxd.psd),
&itemid.num, "next"); &itemid.num, "next");
...@@ -802,7 +810,7 @@ vcdplayer_play_next( access_t * p_access ) ...@@ -802,7 +810,7 @@ vcdplayer_play_next( access_t * p_access )
break; break;
case PSD_TYPE_PLAY_LIST: case PSD_TYPE_PLAY_LIST:
if (p_vcd->pxd.pld == NULL) return VLC_FALSE; if (p_vcd->pxd.pld == NULL) return false;
vcdplayer_update_entry( p_access, vcdplayer_update_entry( p_access,
vcdinf_pld_get_next_offset(p_vcd->pxd.pld), vcdinf_pld_get_next_offset(p_vcd->pxd.pld),
&itemid.num, "next"); &itemid.num, "next");
...@@ -812,7 +820,7 @@ vcdplayer_play_next( access_t * p_access ) ...@@ -812,7 +820,7 @@ vcdplayer_play_next( access_t * p_access )
case PSD_TYPE_END_LIST: case PSD_TYPE_END_LIST:
case PSD_TYPE_COMMAND_LIST: case PSD_TYPE_COMMAND_LIST:
LOG_WARN( "There is no PBC 'next' selection here" ); LOG_WARN( "There is no PBC 'next' selection here" );
return VLC_FALSE; return false;
} }
} else { } else {
...@@ -842,7 +850,7 @@ vcdplayer_play_next( access_t * p_access ) ...@@ -842,7 +850,7 @@ vcdplayer_play_next( access_t * p_access )
itemid.num = p_vcd->play_item.num+1; itemid.num = p_vcd->play_item.num+1;
} else { } else {
LOG_WARN( "At the end - non-PBC 'next' not possible here" ); LOG_WARN( "At the end - non-PBC 'next' not possible here" );
return VLC_FALSE; return false;
} }
break; break;
...@@ -851,10 +859,10 @@ vcdplayer_play_next( access_t * p_access ) ...@@ -851,10 +859,10 @@ vcdplayer_play_next( access_t * p_access )
{ {
/* Should have handled above. */ /* Should have handled above. */
LOG_WARN( "Internal inconsistency - should not have gotten here." ); LOG_WARN( "Internal inconsistency - should not have gotten here." );
return VLC_FALSE; return false;
} }
default: default:
return VLC_FALSE; return false;
} }
} }
...@@ -867,9 +875,9 @@ vcdplayer_play_next( access_t * p_access ) ...@@ -867,9 +875,9 @@ vcdplayer_play_next( access_t * p_access )
/*! /*!
Play item assocated with the "prev" selection. Play item assocated with the "prev" selection.
Return VLC_FALSE if there was some problem. Return false if there was some problem.
*/ */
vlc_bool_t bool
vcdplayer_play_prev( access_t * p_access ) vcdplayer_play_prev( access_t * p_access )
{ {
vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys; vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
...@@ -888,7 +896,7 @@ vcdplayer_play_prev( access_t * p_access ) ...@@ -888,7 +896,7 @@ vcdplayer_play_prev( access_t * p_access )
switch (p_vcd->pxd.descriptor_type) { switch (p_vcd->pxd.descriptor_type) {
case PSD_TYPE_SELECTION_LIST: case PSD_TYPE_SELECTION_LIST:
case PSD_TYPE_EXT_SELECTION_LIST: case PSD_TYPE_EXT_SELECTION_LIST:
if (p_vcd->pxd.psd == NULL) return VLC_FALSE; if (p_vcd->pxd.psd == NULL) return false;
vcdplayer_update_entry( p_access, vcdplayer_update_entry( p_access,
vcdinf_psd_get_prev_offset(p_vcd->pxd.psd), vcdinf_psd_get_prev_offset(p_vcd->pxd.psd),
&itemid.num, "prev"); &itemid.num, "prev");
...@@ -896,7 +904,7 @@ vcdplayer_play_prev( access_t * p_access ) ...@@ -896,7 +904,7 @@ vcdplayer_play_prev( access_t * p_access )
break; break;
case PSD_TYPE_PLAY_LIST: case PSD_TYPE_PLAY_LIST:
if (p_vcd->pxd.pld == NULL) return VLC_FALSE; if (p_vcd->pxd.pld == NULL) return false;
vcdplayer_update_entry( p_access, vcdplayer_update_entry( p_access,
vcdinf_pld_get_prev_offset(p_vcd->pxd.pld), vcdinf_pld_get_prev_offset(p_vcd->pxd.pld),
&itemid.num, "prev"); &itemid.num, "prev");
...@@ -906,7 +914,7 @@ vcdplayer_play_prev( access_t * p_access ) ...@@ -906,7 +914,7 @@ vcdplayer_play_prev( access_t * p_access )
case PSD_TYPE_END_LIST: case PSD_TYPE_END_LIST:
case PSD_TYPE_COMMAND_LIST: case PSD_TYPE_COMMAND_LIST:
LOG_WARN( "There is no PBC 'prev' selection here" ); LOG_WARN( "There is no PBC 'prev' selection here" );
return VLC_FALSE; return false;
} }
} else { } else {
...@@ -919,7 +927,7 @@ vcdplayer_play_prev( access_t * p_access ) ...@@ -919,7 +927,7 @@ vcdplayer_play_prev( access_t * p_access )
itemid.num = p_vcd->play_item.num-1; itemid.num = p_vcd->play_item.num-1;
} else { } else {
LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" ); LOG_WARN( "At the beginning - non-PBC 'prev' not possible here" );
return VLC_FALSE; return false;
} }
} }
...@@ -933,9 +941,9 @@ vcdplayer_play_prev( access_t * p_access ) ...@@ -933,9 +941,9 @@ vcdplayer_play_prev( access_t * p_access )
/*! /*!
Play item assocated with the "return" selection. Play item assocated with the "return" selection.
Return VLC_FALSE if there was some problem. Return false if there was some problem.
*/ */
vlc_bool_t bool
vcdplayer_play_return( access_t * p_access ) vcdplayer_play_return( access_t * p_access )
{ {
vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys; vcdplayer_t *p_vcd= (vcdplayer_t *)p_access->p_sys;
...@@ -954,7 +962,7 @@ vcdplayer_play_return( access_t * p_access ) ...@@ -954,7 +962,7 @@ vcdplayer_play_return( access_t * p_access )
switch (p_vcd->pxd.descriptor_type) { switch (p_vcd->pxd.descriptor_type) {
case PSD_TYPE_SELECTION_LIST: case PSD_TYPE_SELECTION_LIST:
case PSD_TYPE_EXT_SELECTION_LIST: case PSD_TYPE_EXT_SELECTION_LIST:
if (p_vcd->pxd.psd == NULL) return VLC_FALSE; if (p_vcd->pxd.psd == NULL) return false;
vcdplayer_update_entry( p_access, vcdplayer_update_entry( p_access,
vcdinf_psd_get_return_offset(p_vcd->pxd.psd), vcdinf_psd_get_return_offset(p_vcd->pxd.psd),
&itemid.num, "return"); &itemid.num, "return");
...@@ -962,7 +970,7 @@ vcdplayer_play_return( access_t * p_access ) ...@@ -962,7 +970,7 @@ vcdplayer_play_return( access_t * p_access )
break; break;
case PSD_TYPE_PLAY_LIST: case PSD_TYPE_PLAY_LIST:
if (p_vcd->pxd.pld == NULL) return VLC_FALSE; if (p_vcd->pxd.pld == NULL) return false;
vcdplayer_update_entry( p_access, vcdplayer_update_entry( p_access,
vcdinf_pld_get_return_offset(p_vcd->pxd.pld), vcdinf_pld_get_return_offset(p_vcd->pxd.pld),
&itemid.num, "return"); &itemid.num, "return");
...@@ -972,7 +980,7 @@ vcdplayer_play_return( access_t * p_access ) ...@@ -972,7 +980,7 @@ vcdplayer_play_return( access_t * p_access )
case PSD_TYPE_END_LIST: case PSD_TYPE_END_LIST:
case PSD_TYPE_COMMAND_LIST: case PSD_TYPE_COMMAND_LIST:
LOG_WARN( "There is no PBC 'return' selection here" ); LOG_WARN( "There is no PBC 'return' selection here" );
return VLC_FALSE; return false;
} }
} else { } else {
......
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/ *****************************************************************************/
/* VCD Player header. More or less media-player independent */ /* VCD Player header. More or less media-player independent. Or at least
that is the goal. So we prefer bool to vlc_bool.
*/
#ifndef _VCDPLAYER_H_ #ifndef _VCDPLAYER_H_
#define _VCDPLAYER_H_ #define _VCDPLAYER_H_
...@@ -83,7 +85,7 @@ typedef struct thread_vcd_data_s ...@@ -83,7 +85,7 @@ typedef struct thread_vcd_data_s
unsigned int i_blocks_per_read; /* number of blocks per read */ unsigned int i_blocks_per_read; /* number of blocks per read */
/* Current State: position */ /* Current State: position */
vlc_bool_t in_still; /* true if in still */ bool in_still; /* true if in still */
int i_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 PBC is on. VCDPLAYER_BAD_ENTRY if
not none or not in PBC */ not none or not in PBC */
...@@ -102,7 +104,10 @@ typedef struct thread_vcd_data_s ...@@ -102,7 +104,10 @@ typedef struct thread_vcd_data_s
track_t i_track; /* Current track number */ track_t i_track; /* Current track number */
lsn_t i_lsn; /* Current logical sector number */ lsn_t i_lsn; /* Current logical sector number */
lsn_t end_lsn; /* LSN of end of current lsn_t end_lsn; /* LSN of end of current
entry/segment/track. */ entry/segment/track. This block
can be read (and is not one after
the "end").
*/
lsn_t origin_lsn; /* LSN of start of seek/slider */ lsn_t origin_lsn; /* LSN of start of seek/slider */
lsn_t track_lsn; /* LSN of start track origin of track lsn_t track_lsn; /* LSN of start track origin of track
we are in. */ we are in. */
...@@ -110,12 +115,12 @@ typedef struct thread_vcd_data_s ...@@ -110,12 +115,12 @@ typedef struct thread_vcd_data_s
entry). */ entry). */
lsn_t * p_entries; /* Entry points */ lsn_t * p_entries; /* Entry points */
lsn_t * p_segments; /* Segments */ lsn_t * p_segments; /* Segments */
vlc_bool_t b_valid_ep; /* Valid entry points flag */ bool b_valid_ep; /* Valid entry points flag */
vlc_bool_t b_end_of_track; /* If the end of track was reached */ bool b_end_of_track; /* If the end of track was reached */
/* Information about (S)VCD */ /* Information about (S)VCD */
char * psz_source; /* (S)VCD drive or image filename */ char * psz_source; /* (S)VCD drive or image filename */
vlc_bool_t b_svd; /* true if we have SVD info */ bool b_svd; /* true if we have SVD info */
vlc_meta_t *p_meta; vlc_meta_t *p_meta;
track_t i_tracks; /* # of playable MPEG tracks. This is track_t i_tracks; /* # of playable MPEG tracks. This is
generally one less than the number generally one less than the number
...@@ -144,8 +149,10 @@ typedef struct thread_vcd_data_s ...@@ -144,8 +149,10 @@ typedef struct thread_vcd_data_s
intf_thread_t *p_intf; intf_thread_t *p_intf;
int i_audio_nb; int i_audio_nb;
int i_still_time; int i_still_time;
vlc_bool_t b_end_of_cell; bool b_end_of_cell;
input_thread_t *p_input; input_thread_t *p_input;
demux_t *p_demux;
access_t *p_access;
} vcdplayer_t; } vcdplayer_t;
...@@ -155,41 +162,40 @@ typedef struct thread_vcd_data_s ...@@ -155,41 +162,40 @@ typedef struct thread_vcd_data_s
confused with a user's list of favorite things to play or the 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. "next" field of a LID which moves us to a different LID.
*/ */
vlc_bool_t vcdplayer_inc_play_item( access_t *p_access ); bool vcdplayer_inc_play_item( access_t *p_access );
/*! /*!
Return true if playback control (PBC) is on Return true if playback control (PBC) is on
*/ */
vlc_bool_t vcdplayer_pbc_is_on(const vcdplayer_t *p_this); bool vcdplayer_pbc_is_on(const vcdplayer_t *p_this);
/*! /*!
Play item assocated with the "default" selection. Play item assocated with the "default" selection.
Return false if there was some problem. Return false if there was some problem.
*/ */
vlc_bool_t vcdplayer_play_default( access_t * p_access ); bool vcdplayer_play_default( access_t * p_access );
/*! /*!
Play item assocated with the "next" selection. Play item assocated with the "next" selection.
Return false if there was some problem. Return false if there was some problem.
*/ */
vlc_bool_t vcdplayer_play_next( access_t * p_access ); bool vcdplayer_play_next( access_t * p_access );
/*! /*!
Play item assocated with the "prev" selection. Play item assocated with the "prev" selection.
Return false if there was some problem. Return false if there was some problem.
*/ */
vlc_bool_t vcdplayer_play_prev( access_t * p_access ); bool vcdplayer_play_prev( access_t * p_access );
/*! /*!
Play item assocated with the "return" selection. Play item assocated with the "return" selection.
Return false if there was some problem. Return false if there was some problem.
*/ */
vlc_bool_t bool vcdplayer_play_return( access_t * p_access );
vcdplayer_play_return( access_t * p_access );
/* /*
Set's start origin and size for subsequent seeks. Set's start origin and size for subsequent seeks.
...@@ -201,11 +207,12 @@ void vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track, ...@@ -201,11 +207,12 @@ void vcdplayer_set_origin(access_t *p_access, lsn_t i_lsn, track_t i_track,
void vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid); void vcdplayer_play(access_t *p_access, vcdinfo_itemid_t itemid);
vcdplayer_read_status_t vcdplayer_pbc_nav ( access_t * p_access ); vcdplayer_read_status_t vcdplayer_pbc_nav ( access_t * p_access,
vcdplayer_read_status_t vcdplayer_non_pbc_nav ( access_t * p_access ); uint8_t *wait_time );
vcdplayer_read_status_t vcdplayer_non_pbc_nav ( access_t * p_access,
uint8_t *wait_time );
vcdplayer_read_status_t vcdplayer_read (access_t * p_access_t, vcdplayer_read_status_t vcdplayer_read (access_t * p_access_t, uint8_t *p_buf);
uint8_t *p_buf);
#endif /* _VCDPLAYER_H_ */ #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