Commit d82e9eb7 authored by Laurent Aimar's avatar Laurent Aimar

* all: rework of the input.

parent 3d331406
...@@ -44,27 +44,17 @@ ...@@ -44,27 +44,17 @@
"Allows you to modify the default caching value for DVDnav streams. This "\ "Allows you to modify the default caching value for DVDnav streams. This "\
"value should be set in millisecond units." ) "value should be set in millisecond units." )
static int AccessOpen ( vlc_object_t * ); static int Open ( vlc_object_t * );
static void AccessClose( vlc_object_t * ); static void Close( vlc_object_t * );
static int DemuxOpen ( vlc_object_t * );
static void DemuxClose( vlc_object_t * );
vlc_module_begin(); vlc_module_begin();
set_description( _("DVDnav Input") ); set_description( _("DVDnav Input") );
add_integer( "dvdnav-caching", DEFAULT_PTS_DELAY / 1000, NULL, add_integer( "dvdnav-caching", DEFAULT_PTS_DELAY / 1000, NULL,
CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE ); CACHING_TEXT, CACHING_LONGTEXT, VLC_TRUE );
set_capability( "access", 0 ); set_capability( "access_demux", 0 );
add_shortcut( "dvdnav" ); add_shortcut( "dvdnav" );
add_shortcut( "dvdnavsimple" ); add_shortcut( "dvdnavsimple" );
set_callbacks( AccessOpen, AccessClose ); set_callbacks( Open, Close );
add_submodule();
set_description( _("DVDnav Input (demux)") );
set_capability( "demux2", 0 );
add_shortcut( "dvdnav" );
add_shortcut( "dvdnavsimple" );
set_callbacks( DemuxOpen, DemuxClose );
vlc_module_end(); vlc_module_end();
/* TODO /* TODO
...@@ -80,7 +70,6 @@ vlc_module_end(); ...@@ -80,7 +70,6 @@ vlc_module_end();
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
static ssize_t AccessRead( input_thread_t *, byte_t *, size_t ); /* dummy */
static char *ParseCL( vlc_object_t *, char *, vlc_bool_t, int *, int *, int *); static char *ParseCL( vlc_object_t *, char *, vlc_bool_t, int *, int *, int *);
typedef struct typedef struct
...@@ -124,10 +113,13 @@ struct demux_sys_t ...@@ -124,10 +113,13 @@ struct demux_sys_t
/* */ /* */
vlc_bool_t b_es_out_ok; vlc_bool_t b_es_out_ok;
vlc_bool_t b_simple; vlc_bool_t b_simple;
int i_title;
input_title_t **title;
}; };
static int DemuxControl( demux_t *, int, va_list ); static int Control( demux_t *, int, va_list );
static int DemuxDemux ( demux_t * ); static int Demux ( demux_t * );
static int DemuxBlock ( demux_t *, uint8_t *pkt, int i_pkt ); static int DemuxBlock ( demux_t *, uint8_t *pkt, int i_pkt );
enum enum
...@@ -138,186 +130,26 @@ enum ...@@ -138,186 +130,26 @@ enum
AR_221_1_PICTURE = 4, /* 2.21:1 picture (movie) */ AR_221_1_PICTURE = 4, /* 2.21:1 picture (movie) */
}; };
#if 0
static int MenusCallback( vlc_object_t *, char const *, static int MenusCallback( vlc_object_t *, char const *,
vlc_value_t, vlc_value_t, void * ); vlc_value_t, vlc_value_t, void * );
#endif
static void DemuxTitles( demux_t *p_demux );
static void ESSubtitleUpdate( demux_t * ); static void ESSubtitleUpdate( demux_t * );
static void ButtonUpdate( demux_t * ); static void ButtonUpdate( demux_t * );
/*****************************************************************************
* Open: see if dvdnav can handle the input and if so force dvdnav demux
*****************************************************************************
* For now it has to be like that (ie open dvdnav twice) but will be fixed
* when a demux can work without an access module.
*****************************************************************************/
static int AccessOpen( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
dvdnav_t *dvdnav;
int i_title, i_chapter, i_angle;
char *psz_name;
vlc_value_t val;
vlc_bool_t b_force;
/* We try only if we are forced */
if( p_input->psz_demux && *p_input->psz_demux &&
strncmp( p_input->psz_demux, "dvdnav", 6 ) )
{
msg_Warn( p_input, "dvdnav access discarded (demuxer forced)" );
return VLC_EGENERIC;
}
b_force = p_input->psz_access &&
!strncmp( p_input->psz_access, "dvdnav", 6 );
psz_name = ParseCL( VLC_OBJECT(p_input), p_input->psz_name, b_force,
&i_title, &i_chapter, &i_angle );
if( !psz_name )
{
return VLC_EGENERIC;
}
/* Test dvdnav */
if( dvdnav_open( &dvdnav, psz_name ) != DVDNAV_STATUS_OK )
{
msg_Warn( p_input, "cannot open dvdnav" );
free( psz_name );
return VLC_EGENERIC;
}
dvdnav_close( dvdnav );
free( psz_name );
/* Fill p_input fields */
p_input->pf_read = AccessRead;
p_input->pf_set_program = input_SetProgram;
p_input->pf_set_area = NULL;
p_input->pf_seek = NULL;
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_pace_control = VLC_TRUE;
p_input->stream.b_seekable = VLC_TRUE;
p_input->stream.p_selected_area->i_tell = 0;
/* Bogus for demux1 compatibility */
p_input->stream.p_selected_area->i_size = 10000;
p_input->stream.i_method = INPUT_METHOD_DVD;
vlc_mutex_unlock( &p_input->stream.stream_lock );
p_input->i_mtu = 0;
/* Force dvdnav demux */
if( p_input->psz_access && !strncmp(p_input->psz_access, "dvdnav", 6 ) )
p_input->psz_demux = strdup( p_input->psz_access );
else
p_input->psz_demux = strdup( "dvdnav" );
/* Update default_pts to a suitable value for udp access */
var_Create( p_input, "dvdnav-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
var_Get( p_input, "dvdnav-caching", &val );
p_input->i_pts_delay = val.i_int * 1000;
return VLC_SUCCESS;
}
/*****************************************************************************
* Close: free unused data structures
*****************************************************************************/
static void AccessClose( vlc_object_t *p_this )
{
}
/*****************************************************************************
* Read: Should not be called (ie not used by the dvdnav demuxer)
*****************************************************************************/
static ssize_t AccessRead( input_thread_t *p_input, byte_t *p_buffer,
size_t i_len )
{
memset( p_buffer, 0, i_len );
return i_len;
}
/*****************************************************************************
* ParseCL: parse command line
*****************************************************************************/
static char *ParseCL( vlc_object_t *p_this, char *psz_name, vlc_bool_t b_force,
int *i_title, int *i_chapter, int *i_angle )
{
char *psz_parser, *psz_source, *psz_next;
psz_source = strdup( psz_name );
if( psz_source == NULL ) return NULL;
*i_title = 0;
*i_chapter = 1;
*i_angle = 1;
/* Start with the end, because you could have :
* dvdnav:/Volumes/my@toto/VIDEO_TS@1,1
* (yes, this is kludgy). */
for( psz_parser = psz_source + strlen(psz_source) - 1;
psz_parser >= psz_source && *psz_parser != '@';
psz_parser-- );
if( psz_parser >= psz_source && *psz_parser == '@' )
{
/* Found options */
*psz_parser = '\0';
++psz_parser;
*i_title = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
psz_parser = psz_next + 1;
*i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
*i_angle = (int)strtol( psz_next + 1, NULL, 10 );
}
}
}
*i_title = *i_title >= 0 ? *i_title : 0;
*i_chapter = *i_chapter ? *i_chapter : 1;
*i_angle = *i_angle ? *i_angle : 1;
if( !*psz_source )
{
free( psz_source );
if( !b_force )
{
return NULL;
}
psz_source = config_GetPsz( p_this, "dvd" );
if( !psz_source ) return NULL;
}
#ifdef WIN32
if( psz_source[0] && psz_source[1] == ':' &&
psz_source[2] == '\\' && psz_source[3] == '\0' )
{
psz_source[2] = '\0';
}
#endif
msg_Dbg( p_this, "dvdroot=%s title=%d chapter=%d angle=%d",
psz_source, *i_title, *i_chapter, *i_angle );
return psz_source;
}
/***************************************************************************** /*****************************************************************************
* DemuxOpen: * DemuxOpen:
*****************************************************************************/ *****************************************************************************/
static int DemuxOpen( vlc_object_t *p_this ) static int Open( vlc_object_t *p_this )
{ {
demux_t *p_demux = (demux_t*)p_this; demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys; demux_sys_t *p_sys;
vlc_value_t val, text; int i_title, i_chapter, i_angle;
int i_title, i_titles, i_chapter, i_chapters, i_angle, i;
char *psz_name; char *psz_name;
if( strncmp( p_demux->psz_access, "dvdnav", 6 ) || if( strncmp( p_demux->psz_access, "dvdnav", 6 ) )
strncmp( p_demux->psz_demux, "dvdnav", 6 ) )
{ {
msg_Warn( p_demux, "dvdnav module discarded" ); msg_Warn( p_demux, "dvdnav module discarded" );
return VLC_EGENERIC; return VLC_EGENERIC;
...@@ -330,7 +162,9 @@ static int DemuxOpen( vlc_object_t *p_this ) ...@@ -330,7 +162,9 @@ static int DemuxOpen( vlc_object_t *p_this )
return VLC_EGENERIC; return VLC_EGENERIC;
} }
/* Init p_sys */ /* fill p_demux field */
p_demux->pf_demux = Demux;
p_demux->pf_control = Control;
p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) ); p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
memset( p_sys, 0, sizeof( demux_sys_t ) ); memset( p_sys, 0, sizeof( demux_sys_t ) );
...@@ -376,29 +210,46 @@ static int DemuxOpen( vlc_object_t *p_this ) ...@@ -376,29 +210,46 @@ static int DemuxOpen( vlc_object_t *p_this )
dvdnav_err_to_string( p_sys->dvdnav ) ); dvdnav_err_to_string( p_sys->dvdnav ) );
} }
#if 0 // FIXME: Doesn't work with libdvdnav CVS! // FIXME: Doesn't work with libdvdnav CVS!
/* Find out number of titles/chapters */ // Bah don't use CVS ;) --fenrir (anyway it's needed now)
dvdnav_get_number_of_titles( p_sys->dvdnav, &i_titles ); DemuxTitles( p_demux );
for( i = 1; i <= i_titles; i++ )
/* Set forced title/chapter */
if( i_title != 0 )
{ {
i_chapters = 0; if( dvdnav_title_play( p_sys->dvdnav, i_title ) != DVDNAV_STATUS_OK )
dvdnav_get_number_of_parts( p_sys->dvdnav, i, &i_chapters ); {
msg_Warn( p_demux, "cannot set title" );
i_title = 0;
}
else
{
p_demux->info.i_update |= INPUT_UPDATE_TITLE;
p_demux->info.i_title = i_title;
}
} }
#endif
if( dvdnav_title_play( p_sys->dvdnav, i_title ) != if( i_chapter != 0 && i_title != 0 )
DVDNAV_STATUS_OK )
{ {
msg_Warn( p_demux, "cannot set title/chapter" ); if( dvdnav_part_play( p_sys->dvdnav, i_title, i_chapter ) != DVDNAV_STATUS_OK )
{
msg_Warn( p_demux, "cannot set chapter" );
i_chapter = 0;
}
else
{
p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
p_demux->info.i_seekpoint = i_chapter;
}
} }
/* fill p_demux field */ /* Update default_pts to a suitable value for dvdnav access */
p_demux->pf_control = DemuxControl; var_Create( p_demux, "dvdnav-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
p_demux->pf_demux = DemuxDemux;
/* For simple mode (no menus), we're done */ /* For simple mode (no menus), we're done */
if( p_sys->b_simple ) return VLC_SUCCESS; if( p_sys->b_simple ) return VLC_SUCCESS;
/* FIXME hack hack hack hachk FIXME */
/* Get p_input and create variable */ /* Get p_input and create variable */
p_sys->p_input = vlc_object_find( p_demux, VLC_OBJECT_INPUT, FIND_PARENT ); p_sys->p_input = vlc_object_find( p_demux, VLC_OBJECT_INPUT, FIND_PARENT );
var_Create( p_sys->p_input, "x-start", VLC_VAR_INTEGER ); var_Create( p_sys->p_input, "x-start", VLC_VAR_INTEGER );
...@@ -410,27 +261,6 @@ static int DemuxOpen( vlc_object_t *p_this ) ...@@ -410,27 +261,6 @@ static int DemuxOpen( vlc_object_t *p_this )
var_Create( p_sys->p_input, "highlight", VLC_VAR_BOOL ); var_Create( p_sys->p_input, "highlight", VLC_VAR_BOOL );
var_Create( p_sys->p_input, "highlight-mutex", VLC_VAR_MUTEX ); var_Create( p_sys->p_input, "highlight-mutex", VLC_VAR_MUTEX );
/* Create a few object variables used for navigation in the interfaces */
var_Create( p_sys->p_input, "dvd_menus",
VLC_VAR_INTEGER | VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
text.psz_string = _("DVD menus");
var_Change( p_sys->p_input, "dvd_menus", VLC_VAR_SETTEXT, &text, NULL );
var_AddCallback( p_sys->p_input, "dvd_menus", MenusCallback, p_demux );
val.i_int = DVD_MENU_Escape; text.psz_string = _("Resume");
var_Change( p_sys->p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = DVD_MENU_Root; text.psz_string = _("Root");
var_Change( p_sys->p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = DVD_MENU_Title; text.psz_string = _("Title");
var_Change( p_sys->p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = DVD_MENU_Part; text.psz_string = _("Chapter");
var_Change( p_sys->p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = DVD_MENU_Subpicture; text.psz_string = _("Subtitle");
var_Change( p_sys->p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = DVD_MENU_Audio; text.psz_string = _("Audio");
var_Change( p_sys->p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
val.i_int = DVD_MENU_Angle; text.psz_string = _("Angle");
var_Change( p_sys->p_input, "dvd_menus", VLC_VAR_ADDCHOICE, &val, &text );
/* Now create our event thread catcher */ /* Now create our event thread catcher */
p_sys->p_ev = vlc_object_create( p_demux, sizeof( event_thread_t ) ); p_sys->p_ev = vlc_object_create( p_demux, sizeof( event_thread_t ) );
p_sys->p_ev->p_demux = p_demux; p_sys->p_ev->p_demux = p_demux;
...@@ -441,9 +271,9 @@ static int DemuxOpen( vlc_object_t *p_this ) ...@@ -441,9 +271,9 @@ static int DemuxOpen( vlc_object_t *p_this )
} }
/***************************************************************************** /*****************************************************************************
* DemuxClose: * Close:
*****************************************************************************/ *****************************************************************************/
static void DemuxClose( vlc_object_t *p_this ) static void Close( vlc_object_t *p_this )
{ {
demux_t *p_demux = (demux_t*)p_this; demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
...@@ -483,12 +313,17 @@ static void DemuxClose( vlc_object_t *p_this ) ...@@ -483,12 +313,17 @@ static void DemuxClose( vlc_object_t *p_this )
} }
/***************************************************************************** /*****************************************************************************
* DemuxControl: * Control:
*****************************************************************************/ *****************************************************************************/
static int DemuxControl( demux_t *p_demux, int i_query, va_list args ) static int Control( demux_t *p_demux, int i_query, va_list args )
{ {
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
double f, *pf; double f, *pf;
vlc_bool_t *pb;
int64_t *pi64;
input_title_t ***ppp_title;
int *pi_int;
int i;
switch( i_query ) switch( i_query )
{ {
...@@ -525,6 +360,92 @@ static int DemuxControl( demux_t *p_demux, int i_query, va_list args ) ...@@ -525,6 +360,92 @@ static int DemuxControl( demux_t *p_demux, int i_query, va_list args )
return VLC_EGENERIC; return VLC_EGENERIC;
} }
/* Special for access_demux */
case DEMUX_CAN_PAUSE:
case DEMUX_CAN_CONTROL_PACE:
/* TODO */
pb = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
*pb = VLC_TRUE;
return VLC_SUCCESS;
case DEMUX_SET_PAUSE_STATE:
return VLC_SUCCESS;
case DEMUX_GET_TITLE_INFO:
ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
pi_int = (int*)va_arg( args, int* );
/* Duplicate title infos */
*pi_int = p_sys->i_title;
*ppp_title = malloc( sizeof( input_title_t ** ) * p_sys->i_title );
for( i = 0; i < p_sys->i_title; i++ )
{
(*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->title[i] );
}
return VLC_SUCCESS;
case DEMUX_SET_TITLE:
i = (int)va_arg( args, int );
if( ( i == 0 && dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root ) != DVDNAV_STATUS_OK ) ||
( i != 0 && dvdnav_title_play( p_sys->dvdnav, i ) != DVDNAV_STATUS_OK ) )
{
msg_Warn( p_demux, "cannot set title/chapter" );
return VLC_EGENERIC;
}
p_demux->info.i_update |= INPUT_UPDATE_TITLE|INPUT_UPDATE_SEEKPOINT;
p_demux->info.i_title = i;
p_demux->info.i_seekpoint = 0;
return VLC_SUCCESS;
case DEMUX_SET_SEEKPOINT:
i = (int)va_arg( args, int );
if( p_demux->info.i_title == 0 )
{
int i_ret;
/* Special case */
switch( i )
{
case 0:
i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Escape );
break;
case 1:
i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Root );
break;
case 2:
i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Title );
break;
case 3:
i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Part );
break;
case 4:
i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Subpicture );
break;
case 5:
i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Audio );
break;
case 6:
i_ret = dvdnav_menu_call( p_sys->dvdnav, DVD_MENU_Angle );
break;
default:
return VLC_EGENERIC;
}
if( i_ret != DVDNAV_STATUS_OK )
return VLC_EGENERIC;
}
else if( dvdnav_part_play( p_sys->dvdnav, p_demux->info.i_title, i ) != DVDNAV_STATUS_OK )
{
msg_Warn( p_demux, "cannot set title/chapter" );
return VLC_EGENERIC;
}
p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
p_demux->info.i_seekpoint = i;
return VLC_SUCCESS;
case DEMUX_GET_PTS_DELAY:
pi64 = (int64_t*)va_arg( args, int64_t * );
*pi64 = (int64_t)var_GetInteger( p_demux, "dvdnav-caching" ) * I64C(1000);
return VLC_SUCCESS;
/* TODO implement others */ /* TODO implement others */
default: default:
return VLC_EGENERIC; return VLC_EGENERIC;
...@@ -532,9 +453,9 @@ static int DemuxControl( demux_t *p_demux, int i_query, va_list args ) ...@@ -532,9 +453,9 @@ static int DemuxControl( demux_t *p_demux, int i_query, va_list args )
} }
/***************************************************************************** /*****************************************************************************
* DemuxDemux: * Demux:
*****************************************************************************/ *****************************************************************************/
static int DemuxDemux( demux_t *p_demux ) static int Demux( demux_t *p_demux )
{ {
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
...@@ -558,11 +479,10 @@ static int DemuxDemux( demux_t *p_demux ) ...@@ -558,11 +479,10 @@ static int DemuxDemux( demux_t *p_demux )
} }
#if DVD_READ_CACHE #if DVD_READ_CACHE
if( dvdnav_get_next_cache_block( p_sys->dvdnav, &packet, &i_event, &i_len ) if( dvdnav_get_next_cache_block( p_sys->dvdnav, &packet, &i_event, &i_len ) == DVDNAV_STATUS_ERR )
#else #else
if( dvdnav_get_next_block( p_sys->dvdnav, packet, &i_event, &i_len ) if( dvdnav_get_next_block( p_sys->dvdnav, packet, &i_event, &i_len ) == DVDNAV_STATUS_ERR )
#endif #endif
== DVDNAV_STATUS_ERR )
{ {
msg_Warn( p_demux, "cannot get next block (%s)", msg_Warn( p_demux, "cannot get next block (%s)",
dvdnav_err_to_string( p_sys->dvdnav ) ); dvdnav_err_to_string( p_sys->dvdnav ) );
...@@ -638,7 +558,10 @@ static int DemuxDemux( demux_t *p_demux ) ...@@ -638,7 +558,10 @@ static int DemuxDemux( demux_t *p_demux )
} }
case DVDNAV_VTS_CHANGE: case DVDNAV_VTS_CHANGE:
{ {
int32_t i_title = 0;
int32_t i_part = 0;
int i; int i;
dvdnav_vts_change_event_t *event = (dvdnav_vts_change_event_t*)packet; dvdnav_vts_change_event_t *event = (dvdnav_vts_change_event_t*)packet;
msg_Dbg( p_demux, "DVDNAV_VTS_CHANGE" ); msg_Dbg( p_demux, "DVDNAV_VTS_CHANGE" );
msg_Dbg( p_demux, " - vtsN=%d", event->new_vtsN ); msg_Dbg( p_demux, " - vtsN=%d", event->new_vtsN );
...@@ -662,25 +585,29 @@ static int DemuxDemux( demux_t *p_demux ) ...@@ -662,25 +585,29 @@ static int DemuxDemux( demux_t *p_demux )
tk->b_seen = VLC_FALSE; tk->b_seen = VLC_FALSE;
} }
if( p_sys->b_simple ) if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
&i_part ) == DVDNAV_STATUS_OK )
{ {
int32_t i_title = 0; if( p_sys->b_simple && i_title == 0 )
int32_t i_part = 0;
if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
&i_part ) == DVDNAV_STATUS_OK )
{ {
if( i_title == 0 ) /* we have returned in menu, stop dvd */
{ /* FIXME is it the right way ? */
/* we have returned in menu, stop dvd */ return 0;
/* FIXME is it the right way ? */ }
return 0; if( i_title >= 0 && i_title < p_sys->i_title &&
} p_demux->info.i_title != i_title )
{
p_demux->info.i_update |= INPUT_UPDATE_TITLE;
p_demux->info.i_title = i_title;
} }
} }
break; break;
} }
case DVDNAV_CELL_CHANGE: case DVDNAV_CELL_CHANGE:
{ {
int32_t i_title = 0;
int32_t i_part = 0;
dvdnav_cell_change_event_t *event = dvdnav_cell_change_event_t *event =
(dvdnav_cell_change_event_t*)packet; (dvdnav_cell_change_event_t*)packet;
msg_Dbg( p_demux, "DVDNAV_CELL_CHANGE" ); msg_Dbg( p_demux, "DVDNAV_CELL_CHANGE" );
...@@ -691,8 +618,22 @@ static int DemuxDemux( demux_t *p_demux ) ...@@ -691,8 +618,22 @@ static int DemuxDemux( demux_t *p_demux )
msg_Dbg( p_demux, " - pgc_length=%lld", event->pgc_length ); msg_Dbg( p_demux, " - pgc_length=%lld", event->pgc_length );
msg_Dbg( p_demux, " - cell_start=%lld", event->cell_start ); msg_Dbg( p_demux, " - cell_start=%lld", event->cell_start );
msg_Dbg( p_demux, " - pg_start=%lld", event->pg_start ); msg_Dbg( p_demux, " - pg_start=%lld", event->pg_start );
/* FIXME is it correct or there is better way to know chapter change */
if( dvdnav_current_title_info( p_sys->dvdnav, &i_title,
&i_part ) == DVDNAV_STATUS_OK )
{
if( i_title >= 0 && i_title < p_sys->i_title &&
i_part >= 0 && i_part < p_sys->title[i_title]->i_seekpoint &&
p_demux->info.i_seekpoint != i_part )
{
p_demux->info.i_update |= INPUT_UPDATE_SEEKPOINT;
p_demux->info.i_seekpoint = i_part;
}
}
break; break;
} }
case DVDNAV_NAV_PACKET: case DVDNAV_NAV_PACKET:
{ {
#ifdef DVDNAV_DEBUG #ifdef DVDNAV_DEBUG
...@@ -751,6 +692,139 @@ static int DemuxDemux( demux_t *p_demux ) ...@@ -751,6 +692,139 @@ static int DemuxDemux( demux_t *p_demux )
return 1; return 1;
} }
/*****************************************************************************
* ParseCL: parse command line
*****************************************************************************/
static char *ParseCL( vlc_object_t *p_this, char *psz_name, vlc_bool_t b_force,
int *i_title, int *i_chapter, int *i_angle )
{
char *psz_parser, *psz_source, *psz_next;
psz_source = strdup( psz_name );
if( psz_source == NULL ) return NULL;
*i_title = 0;
*i_chapter = 0;
*i_angle = 1;
/* Start with the end, because you could have :
* dvdnav:/Volumes/my@toto/VIDEO_TS@1,1
* (yes, this is kludgy). */
for( psz_parser = psz_source + strlen(psz_source) - 1;
psz_parser >= psz_source && *psz_parser != '@';
psz_parser-- );
if( psz_parser >= psz_source && *psz_parser == '@' )
{
/* Found options */
*psz_parser = '\0';
++psz_parser;
*i_title = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
psz_parser = psz_next + 1;
*i_chapter = (int)strtol( psz_parser, &psz_next, 10 );
if( *psz_next )
{
*i_angle = (int)strtol( psz_next + 1, NULL, 10 );
}
}
}
*i_title = *i_title >= 0 ? *i_title : 0;
*i_chapter = *i_chapter ? *i_chapter : 0;
*i_angle = *i_angle ? *i_angle : 1;
if( !*psz_source )
{
free( psz_source );
if( !b_force )
{
return NULL;
}
psz_source = config_GetPsz( p_this, "dvd" );
if( !psz_source ) return NULL;
}
#ifdef WIN32
if( psz_source[0] && psz_source[1] == ':' &&
psz_source[2] == '\\' && psz_source[3] == '\0' )
{
psz_source[2] = '\0';
}
#endif
msg_Dbg( p_this, "dvdroot=%s title=%d chapter=%d angle=%d",
psz_source, *i_title, *i_chapter, *i_angle );
return psz_source;
}
static void DemuxTitles( demux_t *p_demux )
{
demux_sys_t *p_sys = p_demux->p_sys;
input_title_t *t;
seekpoint_t *s;
int32_t i_titles;
int i;
/* Menu */
t = vlc_input_title_New();
t->b_menu = VLC_TRUE;
t->psz_name = strdup( "DVD Menu" );
s = vlc_seekpoint_New();
s->psz_name = strdup( "Resume" );
TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
s = vlc_seekpoint_New();
s->psz_name = strdup( "Root" );
TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
s = vlc_seekpoint_New();
s->psz_name = strdup( "Title" );
TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
s = vlc_seekpoint_New();
s->psz_name = strdup( "Chapter" );
TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
s = vlc_seekpoint_New();
s->psz_name = strdup( "Subtitle" );
TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
s = vlc_seekpoint_New();
s->psz_name = strdup( "Audio" );
TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
s = vlc_seekpoint_New();
s->psz_name = strdup( "Angle" );
TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
TAB_APPEND( p_sys->i_title, p_sys->title, t );
/* Find out number of titles/chapters */
dvdnav_get_number_of_titles( p_sys->dvdnav, &i_titles );
for( i = 1; i < i_titles; i++ )
{
int32_t i_chapters = 0;
int j;
dvdnav_get_number_of_parts( p_sys->dvdnav, i, &i_chapters );
t = vlc_input_title_New();
for( j = 0; j < __MAX( i_chapters, 1 ); j++ )
{
s = vlc_seekpoint_New();
TAB_APPEND( t->i_seekpoint, t->seekpoint, s );
}
TAB_APPEND( p_sys->i_title, p_sys->title, t );
}
}
/***************************************************************************** /*****************************************************************************
* Update functions: * Update functions:
*****************************************************************************/ *****************************************************************************/
...@@ -1220,6 +1294,7 @@ static int EventKey( vlc_object_t *p_this, char const *psz_var, ...@@ -1220,6 +1294,7 @@ static int EventKey( vlc_object_t *p_this, char const *psz_var,
return VLC_SUCCESS; return VLC_SUCCESS;
} }
#if 0
static int MenusCallback( vlc_object_t *p_this, char const *psz_name, static int MenusCallback( vlc_object_t *p_this, char const *psz_name,
vlc_value_t oldval, vlc_value_t newval, void *p_arg ) vlc_value_t oldval, vlc_value_t newval, void *p_arg )
{ {
...@@ -1230,3 +1305,4 @@ static int MenusCallback( vlc_object_t *p_this, char const *psz_name, ...@@ -1230,3 +1305,4 @@ static int MenusCallback( vlc_object_t *p_this, char const *psz_name,
return VLC_SUCCESS; return VLC_SUCCESS;
} }
#endif
...@@ -44,11 +44,8 @@ using namespace std; ...@@ -44,11 +44,8 @@ using namespace std;
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
*****************************************************************************/ *****************************************************************************/
static int DemuxOpen ( vlc_object_t * ); static int Open ( vlc_object_t * );
static void DemuxClose( vlc_object_t * ); static void Close( vlc_object_t * );
static int AccessOpen ( vlc_object_t * );
static void AccessClose( vlc_object_t * );
#define CACHING_TEXT N_("Caching value (ms)") #define CACHING_TEXT N_("Caching value (ms)")
#define CACHING_LONGTEXT N_( \ #define CACHING_LONGTEXT N_( \
...@@ -58,15 +55,15 @@ static void AccessClose( vlc_object_t * ); ...@@ -58,15 +55,15 @@ static void AccessClose( vlc_object_t * );
vlc_module_begin(); vlc_module_begin();
set_description( _("live.com (RTSP/RTP/SDP) demuxer" ) ); set_description( _("live.com (RTSP/RTP/SDP) demuxer" ) );
set_capability( "demux2", 50 ); set_capability( "demux2", 50 );
set_callbacks( DemuxOpen, DemuxClose ); set_callbacks( Open, Close );
add_shortcut( "live" ); add_shortcut( "live" );
add_submodule(); add_submodule();
set_description( _("RTSP/RTP describe") ); set_description( _("RTSP/RTP access and demux") );
add_shortcut( "rtsp" ); add_shortcut( "rtsp" );
add_shortcut( "sdp" ); add_shortcut( "sdp" );
set_capability( "access", 0 ); set_capability( "access_demux", 0 );
set_callbacks( AccessOpen, AccessClose ); set_callbacks( Open, Close );
add_bool( "rtsp-tcp", 0, NULL, add_bool( "rtsp-tcp", 0, NULL,
N_("Use RTP over RTSP (TCP)"), N_("Use RTP over RTSP (TCP)"),
N_("Use RTP over RTSP (TCP)"), VLC_TRUE ); N_("Use RTP over RTSP (TCP)"), VLC_TRUE );
...@@ -84,187 +81,7 @@ vlc_module_end(); ...@@ -84,187 +81,7 @@ vlc_module_end();
*/ */
/***************************************************************************** /*****************************************************************************
* Local prototypes for access * Local prototypes
*****************************************************************************/
struct access_sys_t
{
int i_sdp;
char *p_sdp;
int i_pos;
};
static ssize_t Read ( input_thread_t *, byte_t *, size_t );
static ssize_t MRLRead( input_thread_t *, byte_t *, size_t );
/*****************************************************************************
* AccessOpen:
*****************************************************************************/
static int AccessOpen( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
access_sys_t *p_sys;
TaskScheduler *scheduler = NULL;
UsageEnvironment *env = NULL;
RTSPClient *rtsp = NULL;
vlc_value_t val;
char *psz_url;
if( p_input->psz_access == NULL || ( strcasecmp( p_input->psz_access, "rtsp" ) && strcasecmp( p_input->psz_access, "sdp" ) ) )
{
msg_Warn( p_input, "RTSP access discarded" );
return VLC_EGENERIC;
}
if( !strcasecmp( p_input->psz_access, "rtsp" ) )
{
if( ( scheduler = BasicTaskScheduler::createNew() ) == NULL )
{
msg_Err( p_input, "BasicTaskScheduler::createNew failed" );
return VLC_EGENERIC;
}
if( ( env = BasicUsageEnvironment::createNew(*scheduler) ) == NULL )
{
delete scheduler;
msg_Err( p_input, "BasicUsageEnvironment::createNew failed" );
return VLC_EGENERIC;
}
if( ( rtsp = RTSPClient::createNew(*env, 1/*verbose*/, "VLC Media Player" ) ) == NULL )
{
delete env;
delete scheduler;
msg_Err( p_input, "RTSPClient::createNew failed" );
return VLC_EGENERIC;
}
psz_url = (char*)malloc( strlen( p_input->psz_name ) + 8 );
sprintf( psz_url, "rtsp://%s", p_input->psz_name );
p_sys = (access_sys_t*)malloc( sizeof( access_sys_t ) );
p_sys->p_sdp = rtsp->describeURL( psz_url );
if( p_sys->p_sdp == NULL )
{
msg_Err( p_input, "describeURL failed (%s)", env->getResultMsg() );
free( psz_url );
delete env;
delete scheduler;
free( p_sys );
return VLC_EGENERIC;
}
free( psz_url );
p_sys->i_sdp = strlen( p_sys->p_sdp );
p_sys->i_pos = 0;
delete env;
delete scheduler;
var_Create( p_input, "rtsp-tcp", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
var_Get( p_input, "rtsp-tcp", &val );
p_input->p_access_data = p_sys;
p_input->i_mtu = 0;
/* Set exported functions */
p_input->pf_read = Read;
p_input->pf_seek = NULL;
p_input->pf_set_program = input_SetProgram;
p_input->pf_set_area = NULL;
p_input->p_private = NULL;
p_input->psz_demux = "live";
/* Finished to set some variable */
vlc_mutex_lock( &p_input->stream.stream_lock );
/* FIXME that's not true but eg over tcp, server send data too fast */
p_input->stream.b_pace_control = val.b_bool;
p_input->stream.p_selected_area->i_tell = 0;
p_input->stream.b_seekable = 1; /* Hack to display time */
p_input->stream.p_selected_area->i_size = p_sys->i_sdp;
p_input->stream.i_method = INPUT_METHOD_NETWORK;
vlc_mutex_unlock( &p_input->stream.stream_lock );
/* Update default_pts to a suitable value for RTSP access */
var_Create( p_input, "rtsp-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
var_Get( p_input, "rtsp-caching", &val );
p_input->i_pts_delay = val.i_int * 1000;
return VLC_SUCCESS;
}
else
{
p_input->p_access_data = (access_sys_t*)0;
p_input->i_mtu = 0;
p_input->pf_read = MRLRead;
p_input->pf_seek = NULL;
p_input->pf_set_program = input_SetProgram;
p_input->pf_set_area = NULL;
p_input->p_private = NULL;
p_input->psz_demux = "live";
/* Finished to set some variable */
vlc_mutex_lock( &p_input->stream.stream_lock );
p_input->stream.b_pace_control = VLC_TRUE;
p_input->stream.p_selected_area->i_tell = 0;
p_input->stream.b_seekable = VLC_FALSE;
p_input->stream.p_selected_area->i_size = strlen(p_input->psz_name);
p_input->stream.i_method = INPUT_METHOD_NETWORK;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return VLC_SUCCESS;
}
}
/*****************************************************************************
* AccessClose:
*****************************************************************************/
static void AccessClose( vlc_object_t *p_this )
{
input_thread_t *p_input = (input_thread_t *)p_this;
access_sys_t *p_sys = p_input->p_access_data;
if( !strcasecmp( p_input->psz_access, "rtsp" ) )
{
delete[] p_sys->p_sdp;
free( p_sys );
}
}
/*****************************************************************************
* Read:
*****************************************************************************/
static ssize_t Read ( input_thread_t *p_input, byte_t *p_buffer, size_t i_len )
{
access_sys_t *p_sys = p_input->p_access_data;
int i_copy = __MIN( (int)i_len, p_sys->i_sdp - p_sys->i_pos );
if( i_copy > 0 )
{
memcpy( p_buffer, &p_sys->p_sdp[p_sys->i_pos], i_copy );
p_sys->i_pos += i_copy;
}
return i_copy;
}
/*****************************************************************************
* MRLRead: read data from the mrl
*****************************************************************************/
static ssize_t MRLRead ( input_thread_t *p_input, byte_t *p_buffer, size_t i_len )
{
int i_done = (int)p_input->p_access_data;
int i_copy = __MIN( (int)i_len, (int)strlen(p_input->psz_name) - i_done );
if( i_copy > 0 )
{
memcpy( p_buffer, &p_input->psz_name[i_done], i_copy );
i_done += i_copy;
p_input->p_access_data = (access_sys_t*)i_done;
}
return i_copy;
}
/*****************************************************************************
* Local prototypes for demux2
*****************************************************************************/ *****************************************************************************/
typedef struct typedef struct
{ {
...@@ -315,7 +132,7 @@ static int Control( demux_t *, int, va_list ); ...@@ -315,7 +132,7 @@ static int Control( demux_t *, int, va_list );
/***************************************************************************** /*****************************************************************************
* DemuxOpen: * DemuxOpen:
*****************************************************************************/ *****************************************************************************/
static int DemuxOpen ( vlc_object_t *p_this ) static int Open ( vlc_object_t *p_this )
{ {
demux_t *p_demux = (demux_t*)p_this; demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys; demux_sys_t *p_sys;
...@@ -323,26 +140,32 @@ static int DemuxOpen ( vlc_object_t *p_this ) ...@@ -323,26 +140,32 @@ static int DemuxOpen ( vlc_object_t *p_this )
MediaSubsessionIterator *iter; MediaSubsessionIterator *iter;
MediaSubsession *sub; MediaSubsession *sub;
vlc_value_t val; vlc_bool_t b_rtsp_tcp;
uint8_t *p_peek; uint8_t *p_peek;
int i_sdp; int i_sdp;
int i_sdp_max; int i_sdp_max;
uint8_t *p_sdp; uint8_t *p_sdp;
/* See if it looks like a SDP if( p_demux->s )
v, o, s fields are mandatory and in this order */
if( stream_Peek( p_demux->s, &p_peek, 7 ) < 7 )
{ {
msg_Err( p_demux, "cannot peek" ); /* See if it looks like a SDP
return VLC_EGENERIC; v, o, s fields are mandatory and in this order */
if( stream_Peek( p_demux->s, &p_peek, 7 ) < 7 )
{
msg_Err( p_demux, "cannot peek" );
return VLC_EGENERIC;
}
if( strncmp( (char*)p_peek, "v=0\r\n", 5 ) && strncmp( (char*)p_peek, "v=0\n", 4 ) &&
( p_peek[0] < 'a' || p_peek[0] > 'z' || p_peek[1] != '=' ) )
{
msg_Warn( p_demux, "SDP module discarded" );
return VLC_EGENERIC;
}
} }
if( strncmp( (char*)p_peek, "v=0\r\n", 5 ) && strncmp( (char*)p_peek, "v=0\n", 4 ) && else
( strcasecmp( p_demux->psz_access, "rtsp" ) || p_peek[0] < 'a' || p_peek[0] > 'z' || p_peek[1] != '=' ) )
{ {
msg_Warn( p_demux, "SDP module discarded" ); var_Create( p_demux, "rtsp-caching", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
return VLC_EGENERIC;
} }
p_demux->pf_demux = Demux; p_demux->pf_demux = Demux;
...@@ -360,35 +183,6 @@ static int DemuxOpen ( vlc_object_t *p_this ) ...@@ -360,35 +183,6 @@ static int DemuxOpen ( vlc_object_t *p_this )
p_sys->i_length = 0; p_sys->i_length = 0;
p_sys->i_start = 0; p_sys->i_start = 0;
/* Gather the complete sdp file */
i_sdp = 0;
i_sdp_max = 1000;
p_sdp = (uint8_t*)malloc( i_sdp_max );
for( ;; )
{
int i_read = stream_Read( p_demux->s, &p_sdp[i_sdp], i_sdp_max - i_sdp - 1 );
if( i_read < 0 )
{
msg_Err( p_demux, "failed to read SDP" );
free( p_sys );
return VLC_EGENERIC;
}
i_sdp += i_read;
if( i_read < i_sdp_max - i_sdp - 1 )
{
p_sdp[i_sdp] = '\0';
break;
}
i_sdp_max += 1000;
p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max );
}
p_sys->p_sdp = (char*)p_sdp;
fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
if( ( p_sys->scheduler = BasicTaskScheduler::createNew() ) == NULL ) if( ( p_sys->scheduler = BasicTaskScheduler::createNew() ) == NULL )
{ {
...@@ -400,7 +194,8 @@ static int DemuxOpen ( vlc_object_t *p_this ) ...@@ -400,7 +194,8 @@ static int DemuxOpen ( vlc_object_t *p_this )
msg_Err( p_demux, "BasicUsageEnvironment::createNew failed" ); msg_Err( p_demux, "BasicUsageEnvironment::createNew failed" );
goto error; goto error;
} }
if( !strcasecmp( p_demux->psz_access, "rtsp" ) )
if( p_demux->s == NULL && !strcasecmp( p_demux->psz_access, "rtsp" ) )
{ {
char *psz_url; char *psz_url;
char *psz_options; char *psz_options;
...@@ -417,7 +212,56 @@ static int DemuxOpen ( vlc_object_t *p_this ) ...@@ -417,7 +212,56 @@ static int DemuxOpen ( vlc_object_t *p_this )
if( psz_options ) if( psz_options )
delete [] psz_options; delete [] psz_options;
p_sdp = (uint8_t*)p_sys->rtsp->describeURL( psz_url );
if( p_sdp == NULL )
{
msg_Err( p_demux, "describeURL failed (%s)", p_sys->env->getResultMsg() );
free( psz_url );
goto error;
}
free( psz_url ); free( psz_url );
/* malloc-ated copy */
p_sys->p_sdp = strdup( (char*)p_sdp );
delete[] p_sdp;
fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
}
else if( p_demux->s == NULL && !strcasecmp( p_demux->psz_access, "sdp" ) )
{
p_sys->p_sdp = strdup( p_demux->psz_path );
}
else
{
/* Gather the complete sdp file */
i_sdp = 0;
i_sdp_max = 1000;
p_sdp = (uint8_t*)malloc( i_sdp_max );
for( ;; )
{
int i_read = stream_Read( p_demux->s, &p_sdp[i_sdp], i_sdp_max - i_sdp - 1 );
if( i_read < 0 )
{
msg_Err( p_demux, "failed to read SDP" );
free( p_sys );
return VLC_EGENERIC;
}
i_sdp += i_read;
if( i_read < i_sdp_max - i_sdp - 1 )
{
p_sdp[i_sdp] = '\0';
break;
}
i_sdp_max += 1000;
p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max );
}
p_sys->p_sdp = (char*)p_sdp;
fprintf( stderr, "sdp=%s\n", p_sys->p_sdp );
} }
if( ( p_sys->ms = MediaSession::createNew(*p_sys->env, p_sys->p_sdp ) ) == NULL ) if( ( p_sys->ms = MediaSession::createNew(*p_sys->env, p_sys->p_sdp ) ) == NULL )
{ {
...@@ -425,8 +269,7 @@ static int DemuxOpen ( vlc_object_t *p_this ) ...@@ -425,8 +269,7 @@ static int DemuxOpen ( vlc_object_t *p_this )
goto error; goto error;
} }
var_Create( p_demux, "rtsp-tcp", VLC_VAR_BOOL|VLC_VAR_DOINHERIT ); b_rtsp_tcp = var_CreateGetBool( p_demux, "rtsp-tcp" );
var_Get( p_demux, "rtsp-tcp", &val );
/* Initialise each media subsession */ /* Initialise each media subsession */
iter = new MediaSubsessionIterator( *p_sys->ms ); iter = new MediaSubsessionIterator( *p_sys->ms );
...@@ -466,7 +309,7 @@ static int DemuxOpen ( vlc_object_t *p_this ) ...@@ -466,7 +309,7 @@ static int DemuxOpen ( vlc_object_t *p_this )
/* Issue the SETUP */ /* Issue the SETUP */
if( p_sys->rtsp ) if( p_sys->rtsp )
{ {
p_sys->rtsp->setupMediaSubsession( *sub, False, val.b_bool ? True : False ); p_sys->rtsp->setupMediaSubsession( *sub, False, b_rtsp_tcp ? True : False );
} }
} }
} }
...@@ -693,7 +536,7 @@ error: ...@@ -693,7 +536,7 @@ error:
/***************************************************************************** /*****************************************************************************
* DemuxClose: * DemuxClose:
*****************************************************************************/ *****************************************************************************/
static void DemuxClose( vlc_object_t *p_this ) static void Close( vlc_object_t *p_this )
{ {
demux_t *p_demux = (demux_t*)p_this; demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
...@@ -775,7 +618,8 @@ static int Demux( demux_t *p_demux ) ...@@ -775,7 +618,8 @@ static int Demux( demux_t *p_demux )
p_sys->i_pcr = i_pcr; p_sys->i_pcr = i_pcr;
es_out_Control( p_demux->out, ES_OUT_SET_PCR, i_pcr ); es_out_Control( p_demux->out, ES_OUT_SET_PCR, i_pcr );
if( p_sys->i_pcr_start <= 0 || p_sys->i_pcr_start > i_pcr ) if( p_sys->i_pcr_start <= 0 || p_sys->i_pcr_start > i_pcr ||
( p_sys->i_length > 0 && i_pcr - p_sys->i_pcr_start > p_sys->i_length ) )
{ {
p_sys->i_pcr_start = i_pcr; p_sys->i_pcr_start = i_pcr;
} }
...@@ -835,6 +679,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) ...@@ -835,6 +679,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
int64_t *pi64; int64_t *pi64;
double *pf, f; double *pf, f;
vlc_bool_t *pb;
switch( i_query ) switch( i_query )
{ {
...@@ -891,6 +736,25 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) ...@@ -891,6 +736,25 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
return VLC_EGENERIC; return VLC_EGENERIC;
} }
/* Special for access_demux */
case DEMUX_CAN_PAUSE:
case DEMUX_CAN_CONTROL_PACE:
/* TODO */
pb = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
*pb = VLC_FALSE;
return VLC_SUCCESS;
case DEMUX_SET_PAUSE_STATE:
case DEMUX_GET_TITLE_INFO:
case DEMUX_SET_TITLE:
case DEMUX_SET_SEEKPOINT:
return VLC_EGENERIC;
case DEMUX_GET_PTS_DELAY:
pi64 = (int64_t*)va_arg( args, int64_t * );
*pi64 = (int64_t)var_GetInteger( p_demux, "rtsp-caching" ) * I64C(1000);
return VLC_SUCCESS;
default: default:
return VLC_EGENERIC; return VLC_EGENERIC;
} }
......
...@@ -51,11 +51,7 @@ ...@@ -51,11 +51,7 @@
#include "ebml/EbmlVoid.h" #include "ebml/EbmlVoid.h"
#include "matroska/FileKax.h" #include "matroska/FileKax.h"
#ifdef HAVE_MATROSKA_KAXATTACHMENTS_H
#include "matroska/KaxAttachments.h" #include "matroska/KaxAttachments.h"
#else
#include "matroska/KaxAttachements.h"
#endif
#include "matroska/KaxBlock.h" #include "matroska/KaxBlock.h"
#include "matroska/KaxBlockData.h" #include "matroska/KaxBlockData.h"
#include "matroska/KaxChapters.h" #include "matroska/KaxChapters.h"
...@@ -146,7 +142,7 @@ class EbmlParser ...@@ -146,7 +142,7 @@ class EbmlParser
private: private:
EbmlStream *m_es; EbmlStream *m_es;
int mi_level; int mi_level;
EbmlElement *m_el[6]; EbmlElement *m_el[10];
EbmlElement *m_got; EbmlElement *m_got;
...@@ -253,15 +249,24 @@ struct demux_sys_t ...@@ -253,15 +249,24 @@ struct demux_sys_t
char *psz_date_utc; char *psz_date_utc;
vlc_meta_t *meta; vlc_meta_t *meta;
input_title_t *title;
}; };
#define MKVD_TIMECODESCALE 1000000 #define MKVD_TIMECODESCALE 1000000
#define MKV_IS_ID( el, C ) ( EbmlId( (*el) ) == C::ClassInfos.GlobalId )
static void IndexAppendCluster ( demux_t *p_demux, KaxCluster *cluster ); static void IndexAppendCluster ( demux_t *p_demux, KaxCluster *cluster );
static char *UTF8ToStr ( const UTFstring &u ); static char *UTF8ToStr ( const UTFstring &u );
static void LoadCues ( demux_t * ); static void LoadCues ( demux_t * );
static void InformationsCreate ( demux_t * ); static void InformationsCreate ( demux_t * );
static void ParseInfo( demux_t *, EbmlElement *info );
static void ParseTracks( demux_t *, EbmlElement *tracks );
static void ParseSeekHead( demux_t *, EbmlElement *seekhead );
static void ParseChapters( demux_t *, EbmlElement *chapters );
/***************************************************************************** /*****************************************************************************
* Open: initializes matroska demux structures * Open: initializes matroska demux structures
*****************************************************************************/ *****************************************************************************/
...@@ -273,7 +278,7 @@ static int Open( vlc_object_t * p_this ) ...@@ -273,7 +278,7 @@ static int Open( vlc_object_t * p_this )
int i_track; int i_track;
EbmlElement *el = NULL, *el1 = NULL, *el2 = NULL, *el3 = NULL, *el4 = NULL; EbmlElement *el = NULL, *el1 = NULL;
/* peek the begining */ /* peek the begining */
if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 ) if( stream_Peek( p_demux->s, &p_peek, 4 ) < 4 )
...@@ -321,6 +326,7 @@ static int Open( vlc_object_t * p_this ) ...@@ -321,6 +326,7 @@ static int Open( vlc_object_t * p_this )
p_sys->psz_title = NULL; p_sys->psz_title = NULL;
p_sys->psz_date_utc = NULL;; p_sys->psz_date_utc = NULL;;
p_sys->meta = NULL; p_sys->meta = NULL;
p_sys->title = NULL;
if( p_sys->es == NULL ) if( p_sys->es == NULL )
{ {
...@@ -356,560 +362,23 @@ static int Open( vlc_object_t * p_this ) ...@@ -356,560 +362,23 @@ static int Open( vlc_object_t * p_this )
while( ( el1 = p_sys->ep->Get() ) != NULL ) while( ( el1 = p_sys->ep->Get() ) != NULL )
{ {
if( EbmlId( *el1 ) == KaxInfo::ClassInfos.GlobalId ) if( MKV_IS_ID( el1, KaxInfo ) )
{ {
msg_Dbg( p_demux, "| + Informations" ); ParseInfo( p_demux, el1 );
p_sys->ep->Down();
while( ( el2 = p_sys->ep->Get() ) != NULL )
{
if( EbmlId( *el2 ) == KaxTimecodeScale::ClassInfos.GlobalId )
{
KaxTimecodeScale &tcs = *(KaxTimecodeScale*)el2;
tcs.ReadData( p_sys->es->I_O() );
p_sys->i_timescale = uint64(tcs);
msg_Dbg( p_demux, "| | + TimecodeScale="I64Fd,
p_sys->i_timescale );
}
else if( EbmlId( *el2 ) == KaxDuration::ClassInfos.GlobalId )
{
KaxDuration &dur = *(KaxDuration*)el2;
dur.ReadData( p_sys->es->I_O() );
p_sys->f_duration = float(dur);
msg_Dbg( p_demux, "| | + Duration=%f",
p_sys->f_duration );
}
else if( EbmlId( *el2 ) == KaxMuxingApp::ClassInfos.GlobalId )
{
KaxMuxingApp &mapp = *(KaxMuxingApp*)el2;
mapp.ReadData( p_sys->es->I_O() );
p_sys->psz_muxing_application = UTF8ToStr( UTFstring( mapp ) );
msg_Dbg( p_demux, "| | + Muxing Application=%s",
p_sys->psz_muxing_application );
}
else if( EbmlId( *el2 ) == KaxWritingApp::ClassInfos.GlobalId )
{
KaxWritingApp &wapp = *(KaxWritingApp*)el2;
wapp.ReadData( p_sys->es->I_O() );
p_sys->psz_writing_application = UTF8ToStr( UTFstring( wapp ) );
msg_Dbg( p_demux, "| | + Writing Application=%s",
p_sys->psz_writing_application );
}
else if( EbmlId( *el2 ) == KaxSegmentFilename::ClassInfos.GlobalId )
{
KaxSegmentFilename &sfn = *(KaxSegmentFilename*)el2;
sfn.ReadData( p_sys->es->I_O() );
p_sys->psz_segment_filename = UTF8ToStr( UTFstring( sfn ) );
msg_Dbg( p_demux, "| | + Segment Filename=%s",
p_sys->psz_segment_filename );
}
else if( EbmlId( *el2 ) == KaxTitle::ClassInfos.GlobalId )
{
KaxTitle &title = *(KaxTitle*)el2;
title.ReadData( p_sys->es->I_O() );
p_sys->psz_title = UTF8ToStr( UTFstring( title ) );
msg_Dbg( p_demux, "| | + Title=%s", p_sys->psz_title );
}
#if defined( HAVE_GMTIME_R ) && !defined( SYS_DARWIN )
else if( EbmlId( *el2 ) == KaxDateUTC::ClassInfos.GlobalId )
{
KaxDateUTC &date = *(KaxDateUTC*)el2;
time_t i_date;
struct tm tmres;
char buffer[256];
date.ReadData( p_sys->es->I_O() );
i_date = date.GetEpochDate();
memset( buffer, 0, 256 );
if( gmtime_r( &i_date, &tmres ) &&
asctime_r( &tmres, buffer ) )
{
buffer[strlen( buffer)-1]= '\0';
p_sys->psz_date_utc = strdup( buffer );
msg_Dbg( p_demux, "| | + Date=%s", p_sys->psz_date_utc );
}
}
#endif
else
{
msg_Dbg( p_demux, "| | + Unknown (%s)", typeid(*el2).name() );
}
}
p_sys->ep->Up();
} }
else if( EbmlId( *el1 ) == KaxTracks::ClassInfos.GlobalId ) else if( MKV_IS_ID( el1, KaxTracks ) )
{ {
msg_Dbg( p_demux, "| + Tracks" ); ParseTracks( p_demux, el1 );
p_sys->ep->Down();
while( ( el2 = p_sys->ep->Get() ) != NULL )
{
if( EbmlId( *el2 ) == KaxTrackEntry::ClassInfos.GlobalId )
{
msg_Dbg( p_demux, "| | + Track Entry" );
p_sys->i_track++;
p_sys->track = (mkv_track_t*)realloc( p_sys->track, sizeof( mkv_track_t ) * (p_sys->i_track + 1 ) );
#define tk p_sys->track[p_sys->i_track - 1]
memset( &tk, 0, sizeof( mkv_track_t ) );
es_format_Init( &tk.fmt, UNKNOWN_ES, 0 );
tk.fmt.psz_language = strdup("English");
tk.fmt.psz_description = NULL;
tk.b_default = VLC_TRUE;
tk.b_enabled = VLC_TRUE;
tk.i_number = p_sys->i_track - 1;
tk.i_extra_data = 0;
tk.p_extra_data = NULL;
tk.psz_codec = NULL;
tk.i_default_duration = 0;
tk.f_timecodescale = 1.0;
tk.b_inited = VLC_FALSE;
tk.i_data_init = 0;
tk.p_data_init = NULL;
tk.psz_codec_name = NULL;
tk.psz_codec_settings = NULL;
tk.psz_codec_info_url = NULL;
tk.psz_codec_download_url = NULL;
p_sys->ep->Down();
while( ( el3 = p_sys->ep->Get() ) != NULL )
{
if( EbmlId( *el3 ) == KaxTrackNumber::ClassInfos.GlobalId )
{
KaxTrackNumber &tnum = *(KaxTrackNumber*)el3;
tnum.ReadData( p_sys->es->I_O() );
tk.i_number = uint32( tnum );
msg_Dbg( p_demux, "| | | + Track Number=%u",
uint32( tnum ) );
}
else if( EbmlId( *el3 ) == KaxTrackUID::ClassInfos.GlobalId )
{
KaxTrackUID &tuid = *(KaxTrackUID*)el3;
tuid.ReadData( p_sys->es->I_O() );
msg_Dbg( p_demux, "| | | + Track UID=%u",
uint32( tuid ) );
}
else if( EbmlId( *el3 ) == KaxTrackType::ClassInfos.GlobalId )
{
char *psz_type;
KaxTrackType &ttype = *(KaxTrackType*)el3;
ttype.ReadData( p_sys->es->I_O() );
switch( uint8(ttype) )
{
case track_audio:
psz_type = "audio";
tk.fmt.i_cat = AUDIO_ES;
break;
case track_video:
psz_type = "video";
tk.fmt.i_cat = VIDEO_ES;
break;
case track_subtitle:
psz_type = "subtitle";
tk.fmt.i_cat = SPU_ES;
break;
default:
psz_type = "unknown";
tk.fmt.i_cat = UNKNOWN_ES;
break;
}
msg_Dbg( p_demux, "| | | + Track Type=%s",
psz_type );
}
// else if( EbmlId( *el3 ) == KaxTrackFlagEnabled::ClassInfos.GlobalId )
// {
// KaxTrackFlagEnabled &fenb = *(KaxTrackFlagEnabled*)el3;
// fenb.ReadData( p_sys->es->I_O() );
// tk.b_enabled = uint32( fenb );
// msg_Dbg( p_demux, "| | | + Track Enabled=%u",
// uint32( fenb ) );
// }
else if( EbmlId( *el3 ) == KaxTrackFlagDefault::ClassInfos.GlobalId )
{
KaxTrackFlagDefault &fdef = *(KaxTrackFlagDefault*)el3;
fdef.ReadData( p_sys->es->I_O() );
tk.b_default = uint32( fdef );
msg_Dbg( p_demux, "| | | + Track Default=%u",
uint32( fdef ) );
}
else if( EbmlId( *el3 ) == KaxTrackFlagLacing::ClassInfos.GlobalId )
{
KaxTrackFlagLacing &lac = *(KaxTrackFlagLacing*)el3;
lac.ReadData( p_sys->es->I_O() );
msg_Dbg( p_demux, "| | | + Track Lacing=%d",
uint32( lac ) );
}
else if( EbmlId( *el3 ) == KaxTrackMinCache::ClassInfos.GlobalId )
{
KaxTrackMinCache &cmin = *(KaxTrackMinCache*)el3;
cmin.ReadData( p_sys->es->I_O() );
msg_Dbg( p_demux, "| | | + Track MinCache=%d",
uint32( cmin ) );
}
else if( EbmlId( *el3 ) == KaxTrackMaxCache::ClassInfos.GlobalId )
{
KaxTrackMaxCache &cmax = *(KaxTrackMaxCache*)el3;
cmax.ReadData( p_sys->es->I_O() );
msg_Dbg( p_demux, "| | | + Track MaxCache=%d",
uint32( cmax ) );
}
else if( EbmlId( *el3 ) == KaxTrackDefaultDuration::ClassInfos.GlobalId )
{
KaxTrackDefaultDuration &defd = *(KaxTrackDefaultDuration*)el3;
defd.ReadData( p_sys->es->I_O() );
tk.i_default_duration = uint64(defd);
msg_Dbg( p_demux, "| | | + Track Default Duration="I64Fd, uint64(defd) );
}
else if( EbmlId( *el3 ) == KaxTrackTimecodeScale::ClassInfos.GlobalId )
{
KaxTrackTimecodeScale &ttcs = *(KaxTrackTimecodeScale*)el3;
ttcs.ReadData( p_sys->es->I_O() );
tk.f_timecodescale = float( ttcs );
msg_Dbg( p_demux, "| | | + Track TimeCodeScale=%f", tk.f_timecodescale );
}
else if( EbmlId( *el3 ) == KaxTrackName::ClassInfos.GlobalId )
{
KaxTrackName &tname = *(KaxTrackName*)el3;
tname.ReadData( p_sys->es->I_O() );
tk.fmt.psz_description = UTF8ToStr( UTFstring( tname ) );
msg_Dbg( p_demux, "| | | + Track Name=%s",
tk.fmt.psz_description );
}
else if( EbmlId( *el3 ) == KaxTrackLanguage::ClassInfos.GlobalId )
{
KaxTrackLanguage &lang = *(KaxTrackLanguage*)el3;
lang.ReadData( p_sys->es->I_O() );
tk.fmt.psz_language = strdup( string( lang ).c_str() );
msg_Dbg( p_demux,
"| | | + Track Language=`%s'",
tk.fmt.psz_language );
}
else if( EbmlId( *el3 ) == KaxCodecID::ClassInfos.GlobalId )
{
KaxCodecID &codecid = *(KaxCodecID*)el3;
codecid.ReadData( p_sys->es->I_O() );
tk.psz_codec = strdup( string( codecid ).c_str() );
msg_Dbg( p_demux, "| | | + Track CodecId=%s",
string( codecid ).c_str() );
}
else if( EbmlId( *el3 ) == KaxCodecPrivate::ClassInfos.GlobalId )
{
KaxCodecPrivate &cpriv = *(KaxCodecPrivate*)el3;
cpriv.ReadData( p_sys->es->I_O(), SCOPE_ALL_DATA );
tk.i_extra_data = cpriv.GetSize();
if( tk.i_extra_data > 0 )
{
tk.p_extra_data = (uint8_t*)malloc( tk.i_extra_data );
memcpy( tk.p_extra_data, cpriv.GetBuffer(), tk.i_extra_data );
}
msg_Dbg( p_demux, "| | | + Track CodecPrivate size="I64Fd, cpriv.GetSize() );
}
else if( EbmlId( *el3 ) == KaxCodecName::ClassInfos.GlobalId )
{
KaxCodecName &cname = *(KaxCodecName*)el3;
cname.ReadData( p_sys->es->I_O() );
tk.psz_codec_name = UTF8ToStr( UTFstring( cname ) );
msg_Dbg( p_demux, "| | | + Track Codec Name=%s", tk.psz_codec_name );
}
// else if( EbmlId( *el3 ) == KaxCodecSettings::ClassInfos.GlobalId )
// {
// KaxCodecSettings &cset = *(KaxCodecSettings*)el3;
// cset.ReadData( p_sys->es->I_O() );
// tk.psz_codec_settings = UTF8ToStr( UTFstring( cset ) );
// msg_Dbg( p_demux, "| | | + Track Codec Settings=%s", tk.psz_codec_settings );
// }
// else if( EbmlId( *el3 ) == KaxCodecInfoURL::ClassInfos.GlobalId )
// {
// KaxCodecInfoURL &ciurl = *(KaxCodecInfoURL*)el3;
// ciurl.ReadData( p_sys->es->I_O() );
// tk.psz_codec_info_url = strdup( string( ciurl ).c_str() );
// msg_Dbg( p_demux, "| | | + Track Codec Info URL=%s", tk.psz_codec_info_url );
// }
// else if( EbmlId( *el3 ) == KaxCodecDownloadURL::ClassInfos.GlobalId )
// {
// KaxCodecDownloadURL &cdurl = *(KaxCodecDownloadURL*)el3;
// cdurl.ReadData( p_sys->es->I_O() );
// tk.psz_codec_download_url = strdup( string( cdurl ).c_str() );
// msg_Dbg( p_demux, "| | | + Track Codec Info URL=%s", tk.psz_codec_download_url );
// }
// else if( EbmlId( *el3 ) == KaxCodecDecodeAll::ClassInfos.GlobalId )
// {
// KaxCodecDecodeAll &cdall = *(KaxCodecDecodeAll*)el3;
// cdall.ReadData( p_sys->es->I_O() );
// msg_Dbg( p_demux, "| | | + Track Codec Decode All=%u <== UNUSED", uint8( cdall ) );
// }
// else if( EbmlId( *el3 ) == KaxTrackOverlay::ClassInfos.GlobalId )
// {
// KaxTrackOverlay &tovr = *(KaxTrackOverlay*)el3;
// tovr.ReadData( p_sys->es->I_O() );
// msg_Dbg( p_demux, "| | | + Track Overlay=%u <== UNUSED", uint32( tovr ) );
// }
else if( EbmlId( *el3 ) == KaxTrackVideo::ClassInfos.GlobalId )
{
msg_Dbg( p_demux, "| | | + Track Video" );
tk.f_fps = 0.0;
p_sys->ep->Down();
while( ( el4 = p_sys->ep->Get() ) != NULL )
{
// if( EbmlId( *el4 ) == KaxVideoFlagInterlaced::ClassInfos.GlobalId )
// {
// KaxVideoFlagInterlaced &fint = *(KaxVideoFlagInterlaced*)el4;
// fint.ReadData( p_sys->es->I_O() );
// msg_Dbg( p_demux, "| | | | + Track Video Interlaced=%u", uint8( fint ) );
// }
// else if( EbmlId( *el4 ) == KaxVideoStereoMode::ClassInfos.GlobalId )
// {
// KaxVideoStereoMode &stereo = *(KaxVideoStereoMode*)el4;
// stereo.ReadData( p_sys->es->I_O() );
// msg_Dbg( p_demux, "| | | | + Track Video Stereo Mode=%u", uint8( stereo ) );
// }
// else
if( EbmlId( *el4 ) == KaxVideoPixelWidth::ClassInfos.GlobalId )
{
KaxVideoPixelWidth &vwidth = *(KaxVideoPixelWidth*)el4;
vwidth.ReadData( p_sys->es->I_O() );
tk.fmt.video.i_width = uint16( vwidth );
msg_Dbg( p_demux, "| | | | + width=%d", uint16( vwidth ) );
}
else if( EbmlId( *el4 ) == KaxVideoPixelHeight::ClassInfos.GlobalId )
{
KaxVideoPixelWidth &vheight = *(KaxVideoPixelWidth*)el4;
vheight.ReadData( p_sys->es->I_O() );
tk.fmt.video.i_height = uint16( vheight );
msg_Dbg( p_demux, "| | | | + height=%d", uint16( vheight ) );
}
else if( EbmlId( *el4 ) == KaxVideoDisplayWidth::ClassInfos.GlobalId )
{
KaxVideoDisplayWidth &vwidth = *(KaxVideoDisplayWidth*)el4;
vwidth.ReadData( p_sys->es->I_O() );
tk.fmt.video.i_visible_width = uint16( vwidth );
msg_Dbg( p_demux, "| | | | + display width=%d", uint16( vwidth ) );
}
else if( EbmlId( *el4 ) == KaxVideoDisplayHeight::ClassInfos.GlobalId )
{
KaxVideoDisplayWidth &vheight = *(KaxVideoDisplayWidth*)el4;
vheight.ReadData( p_sys->es->I_O() );
tk.fmt.video.i_visible_height = uint16( vheight );
msg_Dbg( p_demux, "| | | | + display height=%d", uint16( vheight ) );
}
else if( EbmlId( *el4 ) == KaxVideoFrameRate::ClassInfos.GlobalId )
{
KaxVideoFrameRate &vfps = *(KaxVideoFrameRate*)el4;
vfps.ReadData( p_sys->es->I_O() );
tk.f_fps = float( vfps );
msg_Dbg( p_demux, " | | | + fps=%f", float( vfps ) );
}
// else if( EbmlId( *el4 ) == KaxVideoDisplayUnit::ClassInfos.GlobalId )
// {
// KaxVideoDisplayUnit &vdmode = *(KaxVideoDisplayUnit*)el4;
// vdmode.ReadData( p_sys->es->I_O() );
// msg_Dbg( p_demux, "| | | | + Track Video Display Unit=%s",
// uint8( vdmode ) == 0 ? "pixels" : ( uint8( vdmode ) == 1 ? "centimeters": "inches" ) );
// }
// else if( EbmlId( *el4 ) == KaxVideoAspectRatio::ClassInfos.GlobalId )
// {
// KaxVideoAspectRatio &ratio = *(KaxVideoAspectRatio*)el4;
// ratio.ReadData( p_sys->es->I_O() );
// msg_Dbg( p_demux, " | | | + Track Video Aspect Ratio Type=%u", uint8( ratio ) );
// }
// else if( EbmlId( *el4 ) == KaxVideoGamma::ClassInfos.GlobalId )
// {
// KaxVideoGamma &gamma = *(KaxVideoGamma*)el4;
// gamma.ReadData( p_sys->es->I_O() );
// msg_Dbg( p_demux, " | | | + fps=%f", float( gamma ) );
// }
else
{
msg_Dbg( p_demux, "| | | | + Unknown (%s)", typeid(*el4).name() );
}
}
p_sys->ep->Up();
}
else if( EbmlId( *el3 ) == KaxTrackAudio::ClassInfos.GlobalId )
{
msg_Dbg( p_demux, "| | | + Track Audio" );
p_sys->ep->Down();
while( ( el4 = p_sys->ep->Get() ) != NULL )
{
if( EbmlId( *el4 ) == KaxAudioSamplingFreq::ClassInfos.GlobalId )
{
KaxAudioSamplingFreq &afreq = *(KaxAudioSamplingFreq*)el4;
afreq.ReadData( p_sys->es->I_O() );
tk.fmt.audio.i_rate = (int)float( afreq );
msg_Dbg( p_demux, "| | | | + afreq=%d", tk.fmt.audio.i_rate );
}
else if( EbmlId( *el4 ) == KaxAudioChannels::ClassInfos.GlobalId )
{
KaxAudioChannels &achan = *(KaxAudioChannels*)el4;
achan.ReadData( p_sys->es->I_O() );
tk.fmt.audio.i_channels = uint8( achan );
msg_Dbg( p_demux, "| | | | + achan=%u", uint8( achan ) );
}
else if( EbmlId( *el4 ) == KaxAudioBitDepth::ClassInfos.GlobalId )
{
KaxAudioBitDepth &abits = *(KaxAudioBitDepth*)el4;
abits.ReadData( p_sys->es->I_O() );
tk.fmt.audio.i_bitspersample = uint8( abits );
msg_Dbg( p_demux, "| | | | + abits=%u", uint8( abits ) );
}
else
{
msg_Dbg( p_demux, "| | | | + Unknown (%s)", typeid(*el4).name() );
}
}
p_sys->ep->Up();
}
else
{
msg_Dbg( p_demux, "| | | + Unknown (%s)",
typeid(*el3).name() );
}
}
p_sys->ep->Up();
}
else
{
msg_Dbg( p_demux, "| | + Unknown (%s)",
typeid(*el2).name() );
}
#undef tk
}
p_sys->ep->Up();
} }
else if( EbmlId( *el1 ) == KaxSeekHead::ClassInfos.GlobalId ) else if( MKV_IS_ID( el1, KaxSeekHead ) )
{ {
msg_Dbg( p_demux, "| + Seek head" ); ParseSeekHead( p_demux, el1 );
p_sys->ep->Down();
while( ( el = p_sys->ep->Get() ) != NULL )
{
if( EbmlId( *el ) == KaxSeek::ClassInfos.GlobalId )
{
EbmlId id = EbmlVoid::ClassInfos.GlobalId;
int64_t i_pos = -1;
//msg_Dbg( p_demux, "| | + Seek" );
p_sys->ep->Down();
while( ( el = p_sys->ep->Get() ) != NULL )
{
if( EbmlId( *el ) == KaxSeekID::ClassInfos.GlobalId )
{
KaxSeekID &sid = *(KaxSeekID*)el;
sid.ReadData( p_sys->es->I_O(), SCOPE_ALL_DATA );
id = EbmlId( sid.GetBuffer(), sid.GetSize() );
}
else if( EbmlId( *el ) == KaxSeekPosition::ClassInfos.GlobalId )
{
KaxSeekPosition &spos = *(KaxSeekPosition*)el;
spos.ReadData( p_sys->es->I_O(), SCOPE_ALL_DATA );
i_pos = uint64( spos );
}
else
{
msg_Dbg( p_demux, "| | | + Unknown (%s)",
typeid(*el).name() );
}
}
p_sys->ep->Up();
if( i_pos >= 0 )
{
if( id == KaxCues::ClassInfos.GlobalId )
{
msg_Dbg( p_demux, "| | | = cues at "I64Fd,
i_pos );
p_sys->i_cues_position = p_sys->segment->GetGlobalPosition( i_pos );
}
else if( id == KaxChapters::ClassInfos.GlobalId )
{
msg_Dbg( p_demux, "| | | = chapters at "I64Fd,
i_pos );
p_sys->i_chapters_position = p_sys->segment->GetGlobalPosition( i_pos );
}
else if( id == KaxTags::ClassInfos.GlobalId )
{
msg_Dbg( p_demux, "| | | = tags at "I64Fd,
i_pos );
p_sys->i_tags_position = p_sys->segment->GetGlobalPosition( i_pos );
}
}
}
else
{
msg_Dbg( p_demux, "| | + Unknown (%s)",
typeid(*el).name() );
}
}
p_sys->ep->Up();
} }
else if( EbmlId( *el1 ) == KaxCues::ClassInfos.GlobalId ) else if( MKV_IS_ID( el1, KaxCues ) )
{ {
msg_Dbg( p_demux, "| + Cues" ); msg_Dbg( p_demux, "| + Cues" );
} }
else if( EbmlId( *el1 ) == KaxCluster::ClassInfos.GlobalId ) else if( MKV_IS_ID( el1, KaxCluster ) )
{ {
msg_Dbg( p_demux, "| + Cluster" ); msg_Dbg( p_demux, "| + Cluster" );
...@@ -919,19 +388,16 @@ static int Open( vlc_object_t * p_this ) ...@@ -919,19 +388,16 @@ static int Open( vlc_object_t * p_this )
/* stop parsing the stream */ /* stop parsing the stream */
break; break;
} }
#ifdef HAVE_MATROSKA_KAXATTACHMENTS_H else if( MKV_IS_ID( el1, KaxAttachments ) )
else if( EbmlId( *el1 ) == KaxAttachments::ClassInfos.GlobalId )
#else
else if( EbmlId( *el1 ) == KaxAttachements::ClassInfos.GlobalId )
#endif
{ {
msg_Dbg( p_demux, "| + Attachments FIXME TODO (but probably never supported)" ); msg_Dbg( p_demux, "| + Attachments FIXME TODO (but probably never supported)" );
} }
else if( EbmlId( *el1 ) == KaxChapters::ClassInfos.GlobalId ) else if( MKV_IS_ID( el1, KaxChapters ) )
{ {
msg_Dbg( p_demux, "| + Chapters FIXME TODO" ); msg_Dbg( p_demux, "| + Chapters" );
ParseChapters( p_demux, el1 );
} }
else if( EbmlId( *el1 ) == KaxTag::ClassInfos.GlobalId ) else if( MKV_IS_ID( el1, KaxTag ) )
{ {
msg_Dbg( p_demux, "| + Tags FIXME TODO" ); msg_Dbg( p_demux, "| + Tags FIXME TODO" );
} }
...@@ -947,11 +413,6 @@ static int Open( vlc_object_t * p_this ) ...@@ -947,11 +413,6 @@ static int Open( vlc_object_t * p_this )
goto error; goto error;
} }
if( p_sys->i_chapters_position >= 0 )
{
msg_Warn( p_demux, "chapters unsupported" );
}
/* *** Load the cue if found *** */ /* *** Load the cue if found *** */
if( p_sys->i_cues_position >= 0 ) if( p_sys->i_cues_position >= 0 )
{ {
...@@ -1256,7 +717,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) ...@@ -1256,7 +717,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
case DEMUX_SET_POSITION: case DEMUX_SET_POSITION:
f = (double)va_arg( args, double ); f = (double)va_arg( args, double );
Seek( p_demux, -1, (int)(100.0 * f) ); Seek( p_demux, -1, (int)(100.0 * f) );
return VLC_EGENERIC; return VLC_SUCCESS;
case DEMUX_GET_TIME: case DEMUX_GET_TIME:
pi64 = (int64_t*)va_arg( args, int64_t * ); pi64 = (int64_t*)va_arg( args, int64_t * );
...@@ -1273,6 +734,45 @@ static int Control( demux_t *p_demux, int i_query, va_list args ) ...@@ -1273,6 +734,45 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
} }
return VLC_EGENERIC; return VLC_EGENERIC;
case DEMUX_GET_TITLE_INFO:
if( p_sys->title && p_sys->title->i_seekpoint > 0 )
{
input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
int *pi_int = (int*)va_arg( args, int* );
*pi_int = 1;
*ppp_title = (input_title_t**)malloc( sizeof( input_title_t**) );
(*ppp_title)[0] = vlc_input_title_Duplicate( p_sys->title );
return VLC_SUCCESS;
}
return VLC_EGENERIC;
case DEMUX_SET_TITLE:
if( p_sys->title && p_sys->title->i_seekpoint > 0 )
{
return VLC_SUCCESS;
}
return VLC_EGENERIC;
case DEMUX_SET_SEEKPOINT:
/* FIXME do a better implementation */
if( p_sys->title && p_sys->title->i_seekpoint > 0 )
{
int i_skp = (int)va_arg( args, int );
int64_t i_start = (int64_t)p_sys->title->seekpoint[i_skp]->i_time_offset;
if( p_sys->f_duration > 0.0 )
{
double f_pos = (double)i_start / (double)(1000.0 * p_sys->f_duration );
Seek( p_demux, -1, (int)(100 * f_pos+0.5));
return VLC_SUCCESS;
}
}
return VLC_EGENERIC;
case DEMUX_SET_TIME: case DEMUX_SET_TIME:
case DEMUX_GET_FPS: case DEMUX_GET_FPS:
default: default:
...@@ -1328,7 +828,7 @@ static int BlockGet( demux_t *p_demux, KaxBlock **pp_block, int64_t *pi_ref1, in ...@@ -1328,7 +828,7 @@ static int BlockGet( demux_t *p_demux, KaxBlock **pp_block, int64_t *pi_ref1, in
/* do parsing */ /* do parsing */
if( i_level == 1 ) if( i_level == 1 )
{ {
if( EbmlId( *el ) == KaxCluster::ClassInfos.GlobalId ) if( MKV_IS_ID( el, KaxCluster ) )
{ {
p_sys->cluster = (KaxCluster*)el; p_sys->cluster = (KaxCluster*)el;
...@@ -1341,7 +841,7 @@ static int BlockGet( demux_t *p_demux, KaxBlock **pp_block, int64_t *pi_ref1, in ...@@ -1341,7 +841,7 @@ static int BlockGet( demux_t *p_demux, KaxBlock **pp_block, int64_t *pi_ref1, in
p_sys->ep->Down(); p_sys->ep->Down();
} }
else if( EbmlId( *el ) == KaxCues::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxCues ) )
{ {
msg_Warn( p_demux, "find KaxCues FIXME" ); msg_Warn( p_demux, "find KaxCues FIXME" );
return VLC_EGENERIC; return VLC_EGENERIC;
...@@ -1353,21 +853,21 @@ static int BlockGet( demux_t *p_demux, KaxBlock **pp_block, int64_t *pi_ref1, in ...@@ -1353,21 +853,21 @@ static int BlockGet( demux_t *p_demux, KaxBlock **pp_block, int64_t *pi_ref1, in
} }
else if( i_level == 2 ) else if( i_level == 2 )
{ {
if( EbmlId( *el ) == KaxClusterTimecode::ClassInfos.GlobalId ) if( MKV_IS_ID( el, KaxClusterTimecode ) )
{ {
KaxClusterTimecode &ctc = *(KaxClusterTimecode*)el; KaxClusterTimecode &ctc = *(KaxClusterTimecode*)el;
ctc.ReadData( p_sys->es->I_O(), SCOPE_ALL_DATA ); ctc.ReadData( p_sys->es->I_O(), SCOPE_ALL_DATA );
p_sys->cluster->InitTimecode( uint64( ctc ), p_sys->i_timescale ); p_sys->cluster->InitTimecode( uint64( ctc ), p_sys->i_timescale );
} }
else if( EbmlId( *el ) == KaxBlockGroup::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxBlockGroup ) )
{ {
p_sys->ep->Down(); p_sys->ep->Down();
} }
} }
else if( i_level == 3 ) else if( i_level == 3 )
{ {
if( EbmlId( *el ) == KaxBlock::ClassInfos.GlobalId ) if( MKV_IS_ID( el, KaxBlock ) )
{ {
*pp_block = (KaxBlock*)el; *pp_block = (KaxBlock*)el;
...@@ -1376,14 +876,14 @@ static int BlockGet( demux_t *p_demux, KaxBlock **pp_block, int64_t *pi_ref1, in ...@@ -1376,14 +876,14 @@ static int BlockGet( demux_t *p_demux, KaxBlock **pp_block, int64_t *pi_ref1, in
p_sys->ep->Keep(); p_sys->ep->Keep();
} }
else if( EbmlId( *el ) == KaxBlockDuration::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxBlockDuration ) )
{ {
KaxBlockDuration &dur = *(KaxBlockDuration*)el; KaxBlockDuration &dur = *(KaxBlockDuration*)el;
dur.ReadData( p_sys->es->I_O() ); dur.ReadData( p_sys->es->I_O() );
*pi_duration = uint64( dur ); *pi_duration = uint64( dur );
} }
else if( EbmlId( *el ) == KaxReferenceBlock::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxReferenceBlock ) )
{ {
KaxReferenceBlock &ref = *(KaxReferenceBlock*)el; KaxReferenceBlock &ref = *(KaxReferenceBlock*)el;
...@@ -1558,6 +1058,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent) ...@@ -1558,6 +1058,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent)
{ {
return; return;
} }
if( i_percent > 100 ) i_percent = 100;
delete p_sys->ep; delete p_sys->ep;
p_sys->ep = new EbmlParser( p_sys->es, p_sys->segment ); p_sys->ep = new EbmlParser( p_sys->es, p_sys->segment );
...@@ -1593,7 +1094,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent) ...@@ -1593,7 +1094,7 @@ static void Seek( demux_t *p_demux, mtime_t i_date, int i_percent)
/* search a cluster */ /* search a cluster */
while( ( el = p_sys->ep->Get() ) != NULL ) while( ( el = p_sys->ep->Get() ) != NULL )
{ {
if( EbmlId( *el ) == KaxCluster::ClassInfos.GlobalId ) if( MKV_IS_ID( el, KaxCluster ) )
{ {
KaxCluster *cluster = (KaxCluster*)el; KaxCluster *cluster = (KaxCluster*)el;
...@@ -1942,7 +1443,7 @@ static void LoadCues( demux_t *p_demux ) ...@@ -1942,7 +1443,7 @@ static void LoadCues( demux_t *p_demux )
ep = new EbmlParser( p_sys->es, cues ); ep = new EbmlParser( p_sys->es, cues );
while( ( el = ep->Get() ) != NULL ) while( ( el = ep->Get() ) != NULL )
{ {
if( EbmlId( *el ) == KaxCuePoint::ClassInfos.GlobalId ) if( MKV_IS_ID( el, KaxCuePoint ) )
{ {
#define idx p_sys->index[p_sys->i_index] #define idx p_sys->index[p_sys->i_index]
...@@ -1955,7 +1456,7 @@ static void LoadCues( demux_t *p_demux ) ...@@ -1955,7 +1456,7 @@ static void LoadCues( demux_t *p_demux )
ep->Down(); ep->Down();
while( ( el = ep->Get() ) != NULL ) while( ( el = ep->Get() ) != NULL )
{ {
if( EbmlId( *el ) == KaxCueTime::ClassInfos.GlobalId ) if( MKV_IS_ID( el, KaxCueTime ) )
{ {
KaxCueTime &ctime = *(KaxCueTime*)el; KaxCueTime &ctime = *(KaxCueTime*)el;
...@@ -1963,26 +1464,26 @@ static void LoadCues( demux_t *p_demux ) ...@@ -1963,26 +1464,26 @@ static void LoadCues( demux_t *p_demux )
idx.i_time = uint64( ctime ) * (mtime_t)1000000000 / p_sys->i_timescale; idx.i_time = uint64( ctime ) * (mtime_t)1000000000 / p_sys->i_timescale;
} }
else if( EbmlId( *el ) == KaxCueTrackPositions::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxCueTrackPositions ) )
{ {
ep->Down(); ep->Down();
while( ( el = ep->Get() ) != NULL ) while( ( el = ep->Get() ) != NULL )
{ {
if( EbmlId( *el ) == KaxCueTrack::ClassInfos.GlobalId ) if( MKV_IS_ID( el, KaxCueTrack ) )
{ {
KaxCueTrack &ctrack = *(KaxCueTrack*)el; KaxCueTrack &ctrack = *(KaxCueTrack*)el;
ctrack.ReadData( p_sys->es->I_O() ); ctrack.ReadData( p_sys->es->I_O() );
idx.i_track = uint16( ctrack ); idx.i_track = uint16( ctrack );
} }
else if( EbmlId( *el ) == KaxCueClusterPosition::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxCueClusterPosition ) )
{ {
KaxCueClusterPosition &ccpos = *(KaxCueClusterPosition*)el; KaxCueClusterPosition &ccpos = *(KaxCueClusterPosition*)el;
ccpos.ReadData( p_sys->es->I_O() ); ccpos.ReadData( p_sys->es->I_O() );
idx.i_position = p_sys->segment->GetGlobalPosition( uint64( ccpos ) ); idx.i_position = p_sys->segment->GetGlobalPosition( uint64( ccpos ) );
} }
else if( EbmlId( *el ) == KaxCueBlockNumber::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxCueBlockNumber ) )
{ {
KaxCueBlockNumber &cbnum = *(KaxCueBlockNumber*)el; KaxCueBlockNumber &cbnum = *(KaxCueBlockNumber*)el;
...@@ -2053,13 +1554,13 @@ static void LoadTags( demux_t *p_demux ) ...@@ -2053,13 +1554,13 @@ static void LoadTags( demux_t *p_demux )
ep = new EbmlParser( p_sys->es, tags ); ep = new EbmlParser( p_sys->es, tags );
while( ( el = ep->Get() ) != NULL ) while( ( el = ep->Get() ) != NULL )
{ {
if( EbmlId( *el ) == KaxTag::ClassInfos.GlobalId ) if( MKV_IS_ID( el, KaxTag ) )
{ {
msg_Dbg( p_demux, "+ Tag" ); msg_Dbg( p_demux, "+ Tag" );
ep->Down(); ep->Down();
while( ( el = ep->Get() ) != NULL ) while( ( el = ep->Get() ) != NULL )
{ {
if( EbmlId( *el ) == KaxTagTargets::ClassInfos.GlobalId ) if( MKV_IS_ID( el, KaxTagTargets ) )
{ {
msg_Dbg( p_demux, "| + Targets" ); msg_Dbg( p_demux, "| + Targets" );
ep->Down(); ep->Down();
...@@ -2069,7 +1570,7 @@ static void LoadTags( demux_t *p_demux ) ...@@ -2069,7 +1570,7 @@ static void LoadTags( demux_t *p_demux )
} }
ep->Up(); ep->Up();
} }
else if( EbmlId( *el ) == KaxTagGeneral::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagGeneral ) )
{ {
msg_Dbg( p_demux, "| + General" ); msg_Dbg( p_demux, "| + General" );
ep->Down(); ep->Down();
...@@ -2079,7 +1580,7 @@ static void LoadTags( demux_t *p_demux ) ...@@ -2079,7 +1580,7 @@ static void LoadTags( demux_t *p_demux )
} }
ep->Up(); ep->Up();
} }
else if( EbmlId( *el ) == KaxTagGenres::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagGenres ) )
{ {
msg_Dbg( p_demux, "| + Genres" ); msg_Dbg( p_demux, "| + Genres" );
ep->Down(); ep->Down();
...@@ -2089,7 +1590,7 @@ static void LoadTags( demux_t *p_demux ) ...@@ -2089,7 +1590,7 @@ static void LoadTags( demux_t *p_demux )
} }
ep->Up(); ep->Up();
} }
else if( EbmlId( *el ) == KaxTagAudioSpecific::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagAudioSpecific ) )
{ {
msg_Dbg( p_demux, "| + Audio Specific" ); msg_Dbg( p_demux, "| + Audio Specific" );
ep->Down(); ep->Down();
...@@ -2099,7 +1600,7 @@ static void LoadTags( demux_t *p_demux ) ...@@ -2099,7 +1600,7 @@ static void LoadTags( demux_t *p_demux )
} }
ep->Up(); ep->Up();
} }
else if( EbmlId( *el ) == KaxTagImageSpecific::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagImageSpecific ) )
{ {
msg_Dbg( p_demux, "| + Images Specific" ); msg_Dbg( p_demux, "| + Images Specific" );
ep->Down(); ep->Down();
...@@ -2109,31 +1610,31 @@ static void LoadTags( demux_t *p_demux ) ...@@ -2109,31 +1610,31 @@ static void LoadTags( demux_t *p_demux )
} }
ep->Up(); ep->Up();
} }
else if( EbmlId( *el ) == KaxTagMultiComment::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagMultiComment ) )
{ {
msg_Dbg( p_demux, "| + Multi Comment" ); msg_Dbg( p_demux, "| + Multi Comment" );
} }
else if( EbmlId( *el ) == KaxTagMultiCommercial::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagMultiCommercial ) )
{ {
msg_Dbg( p_demux, "| + Multi Commercial" ); msg_Dbg( p_demux, "| + Multi Commercial" );
} }
else if( EbmlId( *el ) == KaxTagMultiDate::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagMultiDate ) )
{ {
msg_Dbg( p_demux, "| + Multi Date" ); msg_Dbg( p_demux, "| + Multi Date" );
} }
else if( EbmlId( *el ) == KaxTagMultiEntity::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagMultiEntity ) )
{ {
msg_Dbg( p_demux, "| + Multi Entity" ); msg_Dbg( p_demux, "| + Multi Entity" );
} }
else if( EbmlId( *el ) == KaxTagMultiIdentifier::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagMultiIdentifier ) )
{ {
msg_Dbg( p_demux, "| + Multi Identifier" ); msg_Dbg( p_demux, "| + Multi Identifier" );
} }
else if( EbmlId( *el ) == KaxTagMultiLegal::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagMultiLegal ) )
{ {
msg_Dbg( p_demux, "| + Multi Legal" ); msg_Dbg( p_demux, "| + Multi Legal" );
} }
else if( EbmlId( *el ) == KaxTagMultiTitle::ClassInfos.GlobalId ) else if( MKV_IS_ID( el, KaxTagMultiTitle ) )
{ {
msg_Dbg( p_demux, "| + Multi Title" ); msg_Dbg( p_demux, "| + Multi Title" );
} }
...@@ -2156,6 +1657,693 @@ static void LoadTags( demux_t *p_demux ) ...@@ -2156,6 +1657,693 @@ static void LoadTags( demux_t *p_demux )
p_sys->in->setFilePointer( i_sav_position, seek_beginning ); p_sys->in->setFilePointer( i_sav_position, seek_beginning );
} }
/*****************************************************************************
* ParseInfo:
*****************************************************************************/
static void ParseSeekHead( demux_t *p_demux, EbmlElement *seekhead )
{
demux_sys_t *p_sys = p_demux->p_sys;
EbmlElement *el;
EbmlMaster *m;
unsigned int i;
int i_upper_level = 0;
msg_Dbg( p_demux, "| + Seek head" );
/* Master elements */
m = static_cast<EbmlMaster *>(seekhead);
m->Read( *p_sys->es, seekhead->Generic().Context, i_upper_level, el, true );
for( i = 0; i < m->ListSize(); i++ )
{
EbmlElement *l = (*m)[i];
if( MKV_IS_ID( l, KaxSeek ) )
{
EbmlMaster *sk = static_cast<EbmlMaster *>(l);
EbmlId id = EbmlVoid::ClassInfos.GlobalId;
int64_t i_pos = -1;
unsigned int j;
for( j = 0; j < sk->ListSize(); j++ )
{
EbmlElement *l = (*sk)[j];
if( MKV_IS_ID( l, KaxSeekID ) )
{
KaxSeekID &sid = *(KaxSeekID*)l;
id = EbmlId( sid.GetBuffer(), sid.GetSize() );
}
else if( MKV_IS_ID( l, KaxSeekPosition ) )
{
KaxSeekPosition &spos = *(KaxSeekPosition*)l;
i_pos = uint64( spos );
}
else
{
msg_Dbg( p_demux, "| | | + Unknown (%s)", typeid(*l).name() );
}
}
if( i_pos >= 0 )
{
if( id == KaxCues::ClassInfos.GlobalId )
{
msg_Dbg( p_demux, "| | | = cues at "I64Fd, i_pos );
p_sys->i_cues_position = p_sys->segment->GetGlobalPosition( i_pos );
}
else if( id == KaxChapters::ClassInfos.GlobalId )
{
msg_Dbg( p_demux, "| | | = chapters at "I64Fd, i_pos );
p_sys->i_chapters_position = p_sys->segment->GetGlobalPosition( i_pos );
}
else if( id == KaxTags::ClassInfos.GlobalId )
{
msg_Dbg( p_demux, "| | | = tags at "I64Fd, i_pos );
p_sys->i_tags_position = p_sys->segment->GetGlobalPosition( i_pos );
}
}
}
else
{
msg_Dbg( p_demux, "| | + Unknown (%s)", typeid(*l).name() );
}
}
}
/*****************************************************************************
* ParseTracks:
*****************************************************************************/
static void ParseTrackEntry( demux_t *p_demux, EbmlMaster *m )
{
demux_sys_t *p_sys = p_demux->p_sys;
unsigned int i;
mkv_track_t *tk;
msg_Dbg( p_demux, "| | + Track Entry" );
p_sys->i_track++;
p_sys->track = (mkv_track_t*)realloc( p_sys->track, sizeof( mkv_track_t ) * (p_sys->i_track + 1 ) );
/* Init the track */
tk = &p_sys->track[p_sys->i_track - 1];
memset( tk, 0, sizeof( mkv_track_t ) );
es_format_Init( &tk->fmt, UNKNOWN_ES, 0 );
tk->fmt.psz_language = strdup("English");
tk->fmt.psz_description = NULL;
tk->b_default = VLC_TRUE;
tk->b_enabled = VLC_TRUE;
tk->i_number = p_sys->i_track - 1;
tk->i_extra_data = 0;
tk->p_extra_data = NULL;
tk->psz_codec = NULL;
tk->i_default_duration = 0;
tk->f_timecodescale = 1.0;
tk->b_inited = VLC_FALSE;
tk->i_data_init = 0;
tk->p_data_init = NULL;
tk->psz_codec_name = NULL;
tk->psz_codec_settings = NULL;
tk->psz_codec_info_url = NULL;
tk->psz_codec_download_url = NULL;
for( i = 0; i < m->ListSize(); i++ )
{
EbmlElement *l = (*m)[i];
if( MKV_IS_ID( l, KaxTrackNumber ) )
{
KaxTrackNumber &tnum = *(KaxTrackNumber*)l;
tk->i_number = uint32( tnum );
msg_Dbg( p_demux, "| | | + Track Number=%u", uint32( tnum ) );
}
else if( MKV_IS_ID( l, KaxTrackUID ) )
{
KaxTrackUID &tuid = *(KaxTrackUID*)l;
msg_Dbg( p_demux, "| | | + Track UID=%u", uint32( tuid ) );
}
else if( MKV_IS_ID( l, KaxTrackType ) )
{
char *psz_type;
KaxTrackType &ttype = *(KaxTrackType*)l;
switch( uint8(ttype) )
{
case track_audio:
psz_type = "audio";
tk->fmt.i_cat = AUDIO_ES;
break;
case track_video:
psz_type = "video";
tk->fmt.i_cat = VIDEO_ES;
break;
case track_subtitle:
psz_type = "subtitle";
tk->fmt.i_cat = SPU_ES;
break;
default:
psz_type = "unknown";
tk->fmt.i_cat = UNKNOWN_ES;
break;
}
msg_Dbg( p_demux, "| | | + Track Type=%s", psz_type );
}
// else if( EbmlId( *l ) == KaxTrackFlagEnabled::ClassInfos.GlobalId )
// {
// KaxTrackFlagEnabled &fenb = *(KaxTrackFlagEnabled*)l;
// tk->b_enabled = uint32( fenb );
// msg_Dbg( p_demux, "| | | + Track Enabled=%u",
// uint32( fenb ) );
// }
else if( MKV_IS_ID( l, KaxTrackFlagDefault ) )
{
KaxTrackFlagDefault &fdef = *(KaxTrackFlagDefault*)l;
tk->b_default = uint32( fdef );
msg_Dbg( p_demux, "| | | + Track Default=%u", uint32( fdef ) );
}
else if( MKV_IS_ID( l, KaxTrackFlagLacing ) )
{
KaxTrackFlagLacing &lac = *(KaxTrackFlagLacing*)l;
msg_Dbg( p_demux, "| | | + Track Lacing=%d", uint32( lac ) );
}
else if( MKV_IS_ID( l, KaxTrackMinCache ) )
{
KaxTrackMinCache &cmin = *(KaxTrackMinCache*)l;
msg_Dbg( p_demux, "| | | + Track MinCache=%d", uint32( cmin ) );
}
else if( MKV_IS_ID( l, KaxTrackMaxCache ) )
{
KaxTrackMaxCache &cmax = *(KaxTrackMaxCache*)l;
msg_Dbg( p_demux, "| | | + Track MaxCache=%d", uint32( cmax ) );
}
else if( MKV_IS_ID( l, KaxTrackDefaultDuration ) )
{
KaxTrackDefaultDuration &defd = *(KaxTrackDefaultDuration*)l;
tk->i_default_duration = uint64(defd);
msg_Dbg( p_demux, "| | | + Track Default Duration="I64Fd, uint64(defd) );
}
else if( MKV_IS_ID( l, KaxTrackTimecodeScale ) )
{
KaxTrackTimecodeScale &ttcs = *(KaxTrackTimecodeScale*)l;
tk->f_timecodescale = float( ttcs );
msg_Dbg( p_demux, "| | | + Track TimeCodeScale=%f", tk->f_timecodescale );
}
else if( MKV_IS_ID( l, KaxTrackName ) )
{
KaxTrackName &tname = *(KaxTrackName*)l;
tk->fmt.psz_description = UTF8ToStr( UTFstring( tname ) );
msg_Dbg( p_demux, "| | | + Track Name=%s", tk->fmt.psz_description );
}
else if( MKV_IS_ID( l, KaxTrackLanguage ) )
{
KaxTrackLanguage &lang = *(KaxTrackLanguage*)l;
tk->fmt.psz_language = strdup( string( lang ).c_str() );
msg_Dbg( p_demux,
"| | | + Track Language=`%s'", tk->fmt.psz_language );
}
else if( MKV_IS_ID( l, KaxCodecID ) )
{
KaxCodecID &codecid = *(KaxCodecID*)l;
tk->psz_codec = strdup( string( codecid ).c_str() );
msg_Dbg( p_demux, "| | | + Track CodecId=%s", string( codecid ).c_str() );
}
else if( MKV_IS_ID( l, KaxCodecPrivate ) )
{
KaxCodecPrivate &cpriv = *(KaxCodecPrivate*)l;
tk->i_extra_data = cpriv.GetSize();
if( tk->i_extra_data > 0 )
{
tk->p_extra_data = (uint8_t*)malloc( tk->i_extra_data );
memcpy( tk->p_extra_data, cpriv.GetBuffer(), tk->i_extra_data );
}
msg_Dbg( p_demux, "| | | + Track CodecPrivate size="I64Fd, cpriv.GetSize() );
}
else if( MKV_IS_ID( l, KaxCodecName ) )
{
KaxCodecName &cname = *(KaxCodecName*)l;
tk->psz_codec_name = UTF8ToStr( UTFstring( cname ) );
msg_Dbg( p_demux, "| | | + Track Codec Name=%s", tk->psz_codec_name );
}
// else if( EbmlId( *l ) == KaxCodecSettings::ClassInfos.GlobalId )
// {
// KaxCodecSettings &cset = *(KaxCodecSettings*)l;
// tk->psz_codec_settings = UTF8ToStr( UTFstring( cset ) );
// msg_Dbg( p_demux, "| | | + Track Codec Settings=%s", tk->psz_codec_settings );
// }
// else if( EbmlId( *l ) == KaxCodecInfoURL::ClassInfos.GlobalId )
// {
// KaxCodecInfoURL &ciurl = *(KaxCodecInfoURL*)l;
// tk->psz_codec_info_url = strdup( string( ciurl ).c_str() );
// msg_Dbg( p_demux, "| | | + Track Codec Info URL=%s", tk->psz_codec_info_url );
// }
// else if( EbmlId( *l ) == KaxCodecDownloadURL::ClassInfos.GlobalId )
// {
// KaxCodecDownloadURL &cdurl = *(KaxCodecDownloadURL*)l;
// tk->psz_codec_download_url = strdup( string( cdurl ).c_str() );
// msg_Dbg( p_demux, "| | | + Track Codec Info URL=%s", tk->psz_codec_download_url );
// }
// else if( EbmlId( *l ) == KaxCodecDecodeAll::ClassInfos.GlobalId )
// {
// KaxCodecDecodeAll &cdall = *(KaxCodecDecodeAll*)l;
// msg_Dbg( p_demux, "| | | + Track Codec Decode All=%u <== UNUSED", uint8( cdall ) );
// }
// else if( EbmlId( *l ) == KaxTrackOverlay::ClassInfos.GlobalId )
// {
// KaxTrackOverlay &tovr = *(KaxTrackOverlay*)l;
// msg_Dbg( p_demux, "| | | + Track Overlay=%u <== UNUSED", uint32( tovr ) );
// }
else if( MKV_IS_ID( l, KaxTrackVideo ) )
{
EbmlMaster *tkv = static_cast<EbmlMaster*>(l);
unsigned int j;
msg_Dbg( p_demux, "| | | + Track Video" );
tk->f_fps = 0.0;
for( j = 0; j < tkv->ListSize(); j++ )
{
EbmlElement *l = (*tkv)[j];
// if( EbmlId( *el4 ) == KaxVideoFlagInterlaced::ClassInfos.GlobalId )
// {
// KaxVideoFlagInterlaced &fint = *(KaxVideoFlagInterlaced*)el4;
// msg_Dbg( p_demux, "| | | | + Track Video Interlaced=%u", uint8( fint ) );
// }
// else if( EbmlId( *el4 ) == KaxVideoStereoMode::ClassInfos.GlobalId )
// {
// KaxVideoStereoMode &stereo = *(KaxVideoStereoMode*)el4;
// msg_Dbg( p_demux, "| | | | + Track Video Stereo Mode=%u", uint8( stereo ) );
// }
// else
if( MKV_IS_ID( l, KaxVideoPixelWidth ) )
{
KaxVideoPixelWidth &vwidth = *(KaxVideoPixelWidth*)l;
tk->fmt.video.i_width = uint16( vwidth );
msg_Dbg( p_demux, "| | | | + width=%d", uint16( vwidth ) );
}
else if( MKV_IS_ID( l, KaxVideoPixelHeight ) )
{
KaxVideoPixelWidth &vheight = *(KaxVideoPixelWidth*)l;
tk->fmt.video.i_height = uint16( vheight );
msg_Dbg( p_demux, "| | | | + height=%d", uint16( vheight ) );
}
else if( MKV_IS_ID( l, KaxVideoDisplayWidth ) )
{
KaxVideoDisplayWidth &vwidth = *(KaxVideoDisplayWidth*)l;
tk->fmt.video.i_visible_width = uint16( vwidth );
msg_Dbg( p_demux, "| | | | + display width=%d", uint16( vwidth ) );
}
else if( MKV_IS_ID( l, KaxVideoDisplayHeight ) )
{
KaxVideoDisplayWidth &vheight = *(KaxVideoDisplayWidth*)l;
tk->fmt.video.i_visible_height = uint16( vheight );
msg_Dbg( p_demux, "| | | | + display height=%d", uint16( vheight ) );
}
else if( MKV_IS_ID( l, KaxVideoFrameRate ) )
{
KaxVideoFrameRate &vfps = *(KaxVideoFrameRate*)l;
tk->f_fps = float( vfps );
msg_Dbg( p_demux, " | | | + fps=%f", float( vfps ) );
}
// else if( EbmlId( *l ) == KaxVideoDisplayUnit::ClassInfos.GlobalId )
// {
// KaxVideoDisplayUnit &vdmode = *(KaxVideoDisplayUnit*)l;
// msg_Dbg( p_demux, "| | | | + Track Video Display Unit=%s",
// uint8( vdmode ) == 0 ? "pixels" : ( uint8( vdmode ) == 1 ? "centimeters": "inches" ) );
// }
// else if( EbmlId( *l ) == KaxVideoAspectRatio::ClassInfos.GlobalId )
// {
// KaxVideoAspectRatio &ratio = *(KaxVideoAspectRatio*)l;
// msg_Dbg( p_demux, " | | | + Track Video Aspect Ratio Type=%u", uint8( ratio ) );
// }
// else if( EbmlId( *l ) == KaxVideoGamma::ClassInfos.GlobalId )
// {
// KaxVideoGamma &gamma = *(KaxVideoGamma*)l;
// msg_Dbg( p_demux, " | | | + fps=%f", float( gamma ) );
// }
else
{
msg_Dbg( p_demux, "| | | | + Unknown (%s)", typeid(*l).name() );
}
}
}
else if( MKV_IS_ID( l, KaxTrackAudio ) )
{
EbmlMaster *tka = static_cast<EbmlMaster*>(l);
unsigned int j;
msg_Dbg( p_demux, "| | | + Track Audio" );
for( j = 0; j < tka->ListSize(); j++ )
{
EbmlElement *l = (*tka)[j];
if( MKV_IS_ID( l, KaxAudioSamplingFreq ) )
{
KaxAudioSamplingFreq &afreq = *(KaxAudioSamplingFreq*)l;
tk->fmt.audio.i_rate = (int)float( afreq );
msg_Dbg( p_demux, "| | | | + afreq=%d", tk->fmt.audio.i_rate );
}
else if( MKV_IS_ID( l, KaxAudioChannels ) )
{
KaxAudioChannels &achan = *(KaxAudioChannels*)l;
tk->fmt.audio.i_channels = uint8( achan );
msg_Dbg( p_demux, "| | | | + achan=%u", uint8( achan ) );
}
else if( MKV_IS_ID( l, KaxAudioBitDepth ) )
{
KaxAudioBitDepth &abits = *(KaxAudioBitDepth*)l;
tk->fmt.audio.i_bitspersample = uint8( abits );
msg_Dbg( p_demux, "| | | | + abits=%u", uint8( abits ) );
}
else
{
msg_Dbg( p_demux, "| | | | + Unknown (%s)", typeid(*l).name() );
}
}
}
else
{
msg_Dbg( p_demux, "| | | + Unknown (%s)",
typeid(*l).name() );
}
}
}
static void ParseTracks( demux_t *p_demux, EbmlElement *tracks )
{
demux_sys_t *p_sys = p_demux->p_sys;
EbmlElement *el;
EbmlMaster *m;
unsigned int i;
int i_upper_level = 0;
msg_Dbg( p_demux, "| + Tracks" );
/* Master elements */
m = static_cast<EbmlMaster *>(tracks);
m->Read( *p_sys->es, tracks->Generic().Context, i_upper_level, el, true );
for( i = 0; i < m->ListSize(); i++ )
{
EbmlElement *l = (*m)[i];
if( MKV_IS_ID( l, KaxTrackEntry ) )
{
ParseTrackEntry( p_demux, static_cast<EbmlMaster *>(l) );
}
else
{
msg_Dbg( p_demux, "| | + Unknown (%s)", typeid(*l).name() );
}
}
}
/*****************************************************************************
* ParseInfo:
*****************************************************************************/
static void ParseInfo( demux_t *p_demux, EbmlElement *info )
{
demux_sys_t *p_sys = p_demux->p_sys;
EbmlElement *el;
EbmlMaster *m;
unsigned int i;
int i_upper_level = 0;
msg_Dbg( p_demux, "| + Informations" );
/* Master elements */
m = static_cast<EbmlMaster *>(info);
m->Read( *p_sys->es, info->Generic().Context, i_upper_level, el, true );
for( i = 0; i < m->ListSize(); i++ )
{
EbmlElement *l = (*m)[i];
if( MKV_IS_ID( l, KaxSegmentUID ) )
{
KaxSegmentUID &uid = *(KaxSegmentUID*)l;
msg_Dbg( p_demux, "| | + UID=%d", uint32(uid) );
}
else if( MKV_IS_ID( l, KaxTimecodeScale ) )
{
KaxTimecodeScale &tcs = *(KaxTimecodeScale*)l;
p_sys->i_timescale = uint64(tcs);
msg_Dbg( p_demux, "| | + TimecodeScale="I64Fd,
p_sys->i_timescale );
}
else if( MKV_IS_ID( l, KaxDuration ) )
{
KaxDuration &dur = *(KaxDuration*)l;
p_sys->f_duration = float(dur);
msg_Dbg( p_demux, "| | + Duration=%f",
p_sys->f_duration );
}
else if( MKV_IS_ID( l, KaxMuxingApp ) )
{
KaxMuxingApp &mapp = *(KaxMuxingApp*)l;
p_sys->psz_muxing_application = UTF8ToStr( UTFstring( mapp ) );
msg_Dbg( p_demux, "| | + Muxing Application=%s",
p_sys->psz_muxing_application );
}
else if( MKV_IS_ID( l, KaxWritingApp ) )
{
KaxWritingApp &wapp = *(KaxWritingApp*)l;
p_sys->psz_writing_application = UTF8ToStr( UTFstring( wapp ) );
msg_Dbg( p_demux, "| | + Writing Application=%s",
p_sys->psz_writing_application );
}
else if( MKV_IS_ID( l, KaxSegmentFilename ) )
{
KaxSegmentFilename &sfn = *(KaxSegmentFilename*)l;
p_sys->psz_segment_filename = UTF8ToStr( UTFstring( sfn ) );
msg_Dbg( p_demux, "| | + Segment Filename=%s",
p_sys->psz_segment_filename );
}
else if( MKV_IS_ID( l, KaxTitle ) )
{
KaxTitle &title = *(KaxTitle*)l;
p_sys->psz_title = UTF8ToStr( UTFstring( title ) );
msg_Dbg( p_demux, "| | + Title=%s", p_sys->psz_title );
}
#if defined( HAVE_GMTIME_R ) && !defined( SYS_DARWIN )
else if( MKV_IS_ID( l, KaxDateUTC ) )
{
KaxDateUTC &date = *(KaxDateUTC*)l;
time_t i_date;
struct tm tmres;
char buffer[256];
i_date = date.GetEpochDate();
memset( buffer, 0, 256 );
if( gmtime_r( &i_date, &tmres ) &&
asctime_r( &tmres, buffer ) )
{
buffer[strlen( buffer)-1]= '\0';
p_sys->psz_date_utc = strdup( buffer );
msg_Dbg( p_demux, "| | + Date=%s", p_sys->psz_date_utc );
}
}
#endif
else
{
msg_Dbg( p_demux, "| | + Unknown (%s)", typeid(*l).name() );
}
}
}
/*****************************************************************************
* ParseChapterAtom
*****************************************************************************/
static void ParseChapterAtom( demux_t *p_demux, int i_level, EbmlMaster *ca )
{
demux_sys_t *p_sys = p_demux->p_sys;
unsigned int i;
seekpoint_t *sk;
if( p_sys->title == NULL )
{
p_sys->title = vlc_input_title_New();
}
sk = vlc_seekpoint_New();
msg_Dbg( p_demux, "| | | + ChapterAtom (level=%d)", i_level );
for( i = 0; i < ca->ListSize(); i++ )
{
EbmlElement *l = (*ca)[i];
if( MKV_IS_ID( l, KaxChapterUID ) )
{
KaxChapterUID &uid = *(KaxChapterUID*)l;
uint32_t i_uid = uint32( uid );
msg_Dbg( p_demux, "| | | | + ChapterUID: 0x%x", i_uid );
}
else if( MKV_IS_ID( l, KaxChapterTimeStart ) )
{
KaxChapterTimeStart &start =*(KaxChapterTimeStart*)l;
sk->i_time_offset = uint64( start ) / I64C(1000);
msg_Dbg( p_demux, "| | | | + ChapterTimeStart: %lld", sk->i_time_offset );
}
else if( MKV_IS_ID( l, KaxChapterTimeEnd ) )
{
KaxChapterTimeEnd &end =*(KaxChapterTimeEnd*)l;
int64_t i_end = uint64( end );
msg_Dbg( p_demux, "| | | | + ChapterTimeEnd: %lld", i_end );
}
else if( MKV_IS_ID( l, KaxChapterDisplay ) )
{
EbmlMaster *cd = static_cast<EbmlMaster *>(l);
unsigned int j;
msg_Dbg( p_demux, "| | | | + ChapterDisplay" );
for( j = 0; j < cd->ListSize(); j++ )
{
EbmlElement *l= (*cd)[j];
if( MKV_IS_ID( l, KaxChapterString ) )
{
KaxChapterString &name =*(KaxChapterString*)l;
char *psz = UTF8ToStr( UTFstring( name ) );
sk->psz_name = strdup( psz );
msg_Dbg( p_demux, "| | | | | + ChapterString '%s'", psz );
}
else if( MKV_IS_ID( l, KaxChapterLanguage ) )
{
KaxChapterLanguage &lang =*(KaxChapterLanguage*)l;
const char *psz = string( lang ).c_str();
msg_Dbg( p_demux, "| | | | | + ChapterLanguage '%s'", psz );
}
else if( MKV_IS_ID( l, KaxChapterCountry ) )
{
KaxChapterCountry &ct =*(KaxChapterCountry*)l;
const char *psz = string( ct ).c_str();
msg_Dbg( p_demux, "| | | | | + ChapterCountry '%s'", psz );
}
}
}
else if( MKV_IS_ID( l, KaxChapterAtom ) )
{
ParseChapterAtom( p_demux, i_level+1, static_cast<EbmlMaster *>(l) );
}
}
if( sk->i_time_offset > 0 )
{
p_sys->title->i_seekpoint++;
p_sys->title->seekpoint = (seekpoint_t**)realloc( p_sys->title->seekpoint, p_sys->title->i_seekpoint * sizeof( seekpoint_t* ) );
p_sys->title->seekpoint[p_sys->title->i_seekpoint-1] = sk;
}
else
{
vlc_seekpoint_Delete( sk );
}
}
/*****************************************************************************
* ParseChapters:
*****************************************************************************/
static void ParseChapters( demux_t *p_demux, EbmlElement *chapters )
{
demux_sys_t *p_sys = p_demux->p_sys;
EbmlElement *el;
EbmlMaster *m;
unsigned int i;
int i_upper_level = 0;
/* Master elements */
m = static_cast<EbmlMaster *>(chapters);
m->Read( *p_sys->es, chapters->Generic().Context, i_upper_level, el, true );
for( i = 0; i < m->ListSize(); i++ )
{
EbmlElement *l = (*m)[i];
if( MKV_IS_ID( l, KaxEditionEntry ) )
{
EbmlMaster *E = static_cast<EbmlMaster *>(l );
unsigned int j;
msg_Dbg( p_demux, "| | + EditionEntry" );
for( j = 0; j < E->ListSize(); j++ )
{
EbmlElement *l = (*E)[j];
if( MKV_IS_ID( l, KaxChapterAtom ) )
{
ParseChapterAtom( p_demux, 0, static_cast<EbmlMaster *>(l) );
}
else
{
msg_Dbg( p_demux, "| | | + Unknown (%s)", typeid(*l).name() );
}
}
}
else
{
msg_Dbg( p_demux, "| | + Unknown (%s)", typeid(*l).name() );
}
}
}
/*****************************************************************************
* InformationsCreate:
*****************************************************************************/
static void InformationsCreate( demux_t *p_demux ) static void InformationsCreate( demux_t *p_demux )
{ {
demux_sys_t *p_sys = p_demux->p_sys; demux_sys_t *p_sys = p_demux->p_sys;
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* id3.c: simple id3 tag skipper * id3.c: simple id3 tag skipper
***************************************************************************** *****************************************************************************
* Copyright (C) 2001 VideoLAN * Copyright (C) 2001 VideoLAN
* $Id: id3.c,v 1.8 2004/03/03 11:38:14 fenrir Exp $ * $Id$
* *
* Authors: Sigmund Augdal <sigmunau@idi.ntnu.no> * Authors: Sigmund Augdal <sigmunau@idi.ntnu.no>
* *
...@@ -30,10 +30,6 @@ ...@@ -30,10 +30,6 @@
#include <vlc/vlc.h> #include <vlc/vlc.h>
#include <vlc/input.h> #include <vlc/input.h>
#include "ninput.h"
#include <sys/types.h>
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
......
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