Commit 72be09f0 authored by Steve Lhomme's avatar Steve Lhomme

mkv.cpp: allow seamless transition between segments

parent 77a1a288
...@@ -507,6 +507,8 @@ public: ...@@ -507,6 +507,8 @@ public:
void ParseTrackEntry( EbmlMaster *m ); void ParseTrackEntry( EbmlMaster *m );
void IndexAppendCluster( KaxCluster *cluster ); void IndexAppendCluster( KaxCluster *cluster );
int BlockGet( KaxBlock **pp_block, int64_t *pi_ref1, int64_t *pi_ref2, int64_t *pi_duration ); int BlockGet( KaxBlock **pp_block, int64_t *pi_ref1, int64_t *pi_ref2, int64_t *pi_duration );
bool Select( );
void UnSelect( );
}; };
class matroska_stream_t class matroska_stream_t
...@@ -542,7 +544,7 @@ public: ...@@ -542,7 +544,7 @@ public:
return NULL; return NULL;
} }
matroska_segment_t *FindSegment( EbmlBinary & uid ) const; matroska_segment_t *FindSegment( const EbmlBinary & uid ) const;
void PreloadFamily( const matroska_segment_t & segment ); void PreloadFamily( const matroska_segment_t & segment );
size_t PreloadLinked( const demux_sys_t & of_sys ); size_t PreloadLinked( const demux_sys_t & of_sys );
...@@ -588,7 +590,7 @@ public: ...@@ -588,7 +590,7 @@ public:
return NULL; return NULL;
} }
matroska_segment_t *FindSegment( EbmlBinary & uid ) const; matroska_segment_t *FindSegment( const EbmlBinary & uid ) const;
void PreloadFamily( ); void PreloadFamily( );
void PreloadLinked( ); void PreloadLinked( );
matroska_stream_t *AnalyseAllSegmentsFound( EbmlStream *p_estream ); matroska_stream_t *AnalyseAllSegmentsFound( EbmlStream *p_estream );
...@@ -615,7 +617,6 @@ static int Open( vlc_object_t * p_this ) ...@@ -615,7 +617,6 @@ static int Open( vlc_object_t * p_this )
matroska_segment_t *p_segment; matroska_segment_t *p_segment;
uint8_t *p_peek; uint8_t *p_peek;
std::string s_path, s_filename; std::string s_path, s_filename;
size_t i_track;
vlc_stream_io_callback *p_io_callback; vlc_stream_io_callback *p_io_callback;
EbmlStream *p_io_stream; EbmlStream *p_io_stream;
...@@ -758,758 +759,787 @@ static int Open( vlc_object_t * p_this ) ...@@ -758,758 +759,787 @@ static int Open( vlc_object_t * p_this )
p_segment->b_cues = VLC_FALSE; p_segment->b_cues = VLC_FALSE;
} }
/* add all es */ if ( !p_segment->Select() )
msg_Dbg( p_demux, "found %d es", p_segment->tracks.size() );
for( i_track = 0; i_track < p_segment->tracks.size(); i_track++ )
{
#define tk p_segment->tracks[i_track]
if( tk->fmt.i_cat == UNKNOWN_ES )
{ {
msg_Warn( p_demux, "invalid track[%d, n=%d]", i_track, tk->i_number ); msg_Err( p_demux, "cannot use the segment" );
tk->p_es = NULL; goto error;
continue;
} }
if( !strcmp( tk->psz_codec, "V_MS/VFW/FOURCC" ) ) /* add information */
InformationCreate( p_demux );
return VLC_SUCCESS;
error:
delete p_sys;
return VLC_EGENERIC;
}
/*****************************************************************************
* Close: frees unused data
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
demux_t *p_demux = (demux_t*)p_this;
demux_sys_t *p_sys = p_demux->p_sys;
matroska_stream_t *p_stream = p_sys->Stream();
matroska_segment_t *p_segment = p_stream->Segment();
/* TODO close everything ? */
delete p_segment->segment;
delete p_sys;
}
/*****************************************************************************
* Control:
*****************************************************************************/
static int Control( demux_t *p_demux, int i_query, va_list args )
{
demux_sys_t *p_sys = p_demux->p_sys;
matroska_stream_t *p_stream = p_sys->Stream();
matroska_segment_t *p_segment = p_stream->Segment();
int64_t *pi64;
double *pf, f;
int i_skp;
vlc_meta_t **pp_meta;
switch( i_query )
{ {
if( tk->i_extra_data < (int)sizeof( BITMAPINFOHEADER ) ) case DEMUX_GET_META:
pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
*pp_meta = vlc_meta_Duplicate( p_sys->meta );
return VLC_SUCCESS;
case DEMUX_GET_LENGTH:
pi64 = (int64_t*)va_arg( args, int64_t * );
if( p_segment->f_duration > 0.0 )
{ {
msg_Err( p_demux, "missing/invalid BITMAPINFOHEADER" ); *pi64 = (int64_t)(p_segment->f_duration * 1000);
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' ); return VLC_SUCCESS;
} }
else return VLC_EGENERIC;
case DEMUX_GET_POSITION:
pf = (double*)va_arg( args, double * );
*pf = (double)p_sys->i_pts / (1000.0 * p_segment->f_duration);
return VLC_SUCCESS;
case DEMUX_SET_POSITION:
f = (double)va_arg( args, double );
Seek( p_demux, -1, f, NULL );
return VLC_SUCCESS;
case DEMUX_GET_TIME:
pi64 = (int64_t*)va_arg( args, int64_t * );
*pi64 = p_sys->i_pts;
return VLC_SUCCESS;
case DEMUX_GET_TITLE_INFO:
if( p_sys->title && p_sys->title->i_seekpoint > 0 )
{ {
BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)tk->p_extra_data; input_title_t ***ppp_title = (input_title_t***)va_arg( args, input_title_t*** );
int *pi_int = (int*)va_arg( args, int* );
tk->fmt.video.i_width = GetDWLE( &p_bih->biWidth ); *pi_int = 1;
tk->fmt.video.i_height= GetDWLE( &p_bih->biHeight ); *ppp_title = (input_title_t**)malloc( sizeof( input_title_t**) );
tk->fmt.i_codec = GetFOURCC( &p_bih->biCompression );
tk->fmt.i_extra = GetDWLE( &p_bih->biSize ) - sizeof( BITMAPINFOHEADER ); (*ppp_title)[0] = vlc_input_title_Duplicate( p_sys->title );
if( tk->fmt.i_extra > 0 )
return VLC_SUCCESS;
}
return VLC_EGENERIC;
case DEMUX_SET_TITLE:
/* TODO handle editions as titles & DVD titles as well */
if( p_sys->title && p_sys->title->i_seekpoint > 0 )
{ {
tk->fmt.p_extra = malloc( tk->fmt.i_extra ); return VLC_SUCCESS;
memcpy( tk->fmt.p_extra, &p_bih[1], tk->fmt.i_extra );
} }
return VLC_EGENERIC;
case DEMUX_SET_SEEKPOINT:
/* FIXME do a better implementation */
i_skp = (int)va_arg( args, int );
if( p_sys->title && i_skp < p_sys->title->i_seekpoint)
{
Seek( p_demux, (int64_t)p_sys->title->seekpoint[i_skp]->i_time_offset, -1, NULL);
p_demux->info.i_seekpoint |= INPUT_UPDATE_SEEKPOINT;
p_demux->info.i_seekpoint = i_skp;
return VLC_SUCCESS;
} }
return VLC_EGENERIC;
case DEMUX_SET_TIME:
case DEMUX_GET_FPS:
default:
return VLC_EGENERIC;
} }
else if( !strcmp( tk->psz_codec, "V_MPEG1" ) || }
!strcmp( tk->psz_codec, "V_MPEG2" ) )
int matroska_segment_t::BlockGet( KaxBlock **pp_block, int64_t *pi_ref1, int64_t *pi_ref2, int64_t *pi_duration )
{
*pp_block = NULL;
*pi_ref1 = -1;
*pi_ref2 = -1;
for( ;; )
{ {
tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' ); EbmlElement *el;
int i_level;
if( sys.demuxer.b_die )
{
return VLC_EGENERIC;
} }
else if( !strncmp( tk->psz_codec, "V_MPEG4", 7 ) )
el = ep->Get();
i_level = ep->GetLevel();
if( el == NULL && *pp_block != NULL )
{ {
if( !strcmp( tk->psz_codec, "V_MPEG4/MS/V3" ) ) /* update the index */
#define idx index[i_index - 1]
if( i_index > 0 && idx.i_time == -1 )
{ {
tk->fmt.i_codec = VLC_FOURCC( 'D', 'I', 'V', '3' ); idx.i_time = (*pp_block)->GlobalTimecode() / (mtime_t)1000;
idx.b_key = *pi_ref1 == -1 ? VLC_TRUE : VLC_FALSE;
} }
else if( !strcmp( tk->psz_codec, "V_MPEG4/ISO/AVC" ) ) #undef idx
{ return VLC_SUCCESS;
tk->fmt.i_codec = VLC_FOURCC( 'a', 'v', 'c', '1' );
tk->fmt.b_packetized = VLC_FALSE;
tk->fmt.i_extra = tk->i_extra_data;
tk->fmt.p_extra = malloc( tk->i_extra_data );
memcpy( tk->fmt.p_extra,tk->p_extra_data, tk->i_extra_data );
} }
else
if( el == NULL )
{ {
tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' ); if( ep->GetLevel() > 1 )
{
ep->Up();
continue;
} }
msg_Warn( &sys.demuxer, "EOF" );
return VLC_EGENERIC;
} }
else if( !strcmp( tk->psz_codec, "V_QUICKTIME" ) )
/* do parsing */
if( i_level == 1 )
{ {
MP4_Box_t *p_box = (MP4_Box_t*)malloc( sizeof( MP4_Box_t ) ); if( MKV_IS_ID( el, KaxCluster ) )
stream_t *p_mp4_stream = stream_MemoryNew( VLC_OBJECT(p_demux),
tk->p_extra_data,
tk->i_extra_data );
MP4_ReadBoxCommon( p_mp4_stream, p_box );
MP4_ReadBox_sample_vide( p_mp4_stream, p_box );
tk->fmt.i_codec = p_box->i_type;
tk->fmt.video.i_width = p_box->data.p_sample_vide->i_width;
tk->fmt.video.i_height = p_box->data.p_sample_vide->i_height;
tk->fmt.i_extra = p_box->data.p_sample_vide->i_qt_image_description;
tk->fmt.p_extra = malloc( tk->fmt.i_extra );
memcpy( tk->fmt.p_extra, p_box->data.p_sample_vide->p_qt_image_description, tk->fmt.i_extra );
MP4_FreeBox_sample_vide( p_box );
stream_MemoryDelete( p_mp4_stream, VLC_TRUE );
}
else if( !strcmp( tk->psz_codec, "A_MS/ACM" ) )
{ {
if( tk->i_extra_data < (int)sizeof( WAVEFORMATEX ) ) cluster = (KaxCluster*)el;
/* add it to the index */
if( i_index == 0 ||
( i_index > 0 && index[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
{ {
msg_Err( p_demux, "missing/invalid WAVEFORMATEX" ); IndexAppendCluster( cluster );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
} }
else
{
WAVEFORMATEX *p_wf = (WAVEFORMATEX*)tk->p_extra_data;
wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &tk->fmt.i_codec, NULL );
tk->fmt.audio.i_channels = GetWLE( &p_wf->nChannels );
tk->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
tk->fmt.i_bitrate = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
tk->fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign );;
tk->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );
tk->fmt.i_extra = GetWLE( &p_wf->cbSize ); // reset silent tracks
if( tk->fmt.i_extra > 0 ) for (size_t i=0; i<tracks.size(); i++)
{ {
tk->fmt.p_extra = malloc( tk->fmt.i_extra ); tracks[i]->b_silent = VLC_FALSE;
memcpy( tk->fmt.p_extra, &p_wf[1], tk->fmt.i_extra );
} }
ep->Down();
} }
else if( MKV_IS_ID( el, KaxCues ) )
{
msg_Warn( &sys.demuxer, "find KaxCues FIXME" );
return VLC_EGENERIC;
} }
else if( !strcmp( tk->psz_codec, "A_MPEG/L3" ) || else
!strcmp( tk->psz_codec, "A_MPEG/L2" ) ||
!strcmp( tk->psz_codec, "A_MPEG/L1" ) )
{ {
tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' ); msg_Dbg( &sys.demuxer, "unknown (%s)", typeid( el ).name() );
} }
else if( !strcmp( tk->psz_codec, "A_AC3" ) ) }
else if( i_level == 2 )
{ {
tk->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' ); if( MKV_IS_ID( el, KaxClusterTimecode ) )
{
KaxClusterTimecode &ctc = *(KaxClusterTimecode*)el;
ctc.ReadData( es.I_O(), SCOPE_ALL_DATA );
cluster->InitTimecode( uint64( ctc ), i_timescale );
} }
else if( !strcmp( tk->psz_codec, "A_DTS" ) ) else if( MKV_IS_ID( el, KaxClusterSilentTracks ) )
{ {
tk->fmt.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' ); ep->Down();
} }
else if( !strcmp( tk->psz_codec, "A_FLAC" ) ) else if( MKV_IS_ID( el, KaxBlockGroup ) )
{ {
tk->fmt.i_codec = VLC_FOURCC( 'f', 'l', 'a', 'c' ); ep->Down();
tk->fmt.i_extra = tk->i_extra_data;
tk->fmt.p_extra = malloc( tk->i_extra_data );
memcpy( tk->fmt.p_extra,tk->p_extra_data, tk->i_extra_data );
} }
else if( !strcmp( tk->psz_codec, "A_VORBIS" ) ) }
else if( i_level == 3 )
{ {
int i, i_offset = 1, i_size[3], i_extra; if( MKV_IS_ID( el, KaxBlock ) )
uint8_t *p_extra;
tk->fmt.i_codec = VLC_FOURCC( 'v', 'o', 'r', 'b' );
/* Split the 3 headers */
if( tk->p_extra_data[0] != 0x02 )
msg_Err( p_demux, "invalid vorbis header" );
for( i = 0; i < 2; i++ )
{
i_size[i] = 0;
while( i_offset < tk->i_extra_data )
{ {
i_size[i] += tk->p_extra_data[i_offset]; *pp_block = (KaxBlock*)el;
if( tk->p_extra_data[i_offset++] != 0xff ) break;
}
}
i_size[0] = __MIN(i_size[0], tk->i_extra_data - i_offset); (*pp_block)->ReadData( es.I_O() );
i_size[1] = __MIN(i_size[1], tk->i_extra_data -i_offset -i_size[0]); (*pp_block)->SetParent( *cluster );
i_size[2] = tk->i_extra_data - i_offset - i_size[0] - i_size[1];
tk->fmt.i_extra = 3 * 2 + i_size[0] + i_size[1] + i_size[2]; ep->Keep();
tk->fmt.p_extra = malloc( tk->fmt.i_extra );
p_extra = (uint8_t *)tk->fmt.p_extra; i_extra = 0;
for( i = 0; i < 3; i++ )
{
*(p_extra++) = i_size[i] >> 8;
*(p_extra++) = i_size[i] & 0xFF;
memcpy( p_extra, tk->p_extra_data + i_offset + i_extra,
i_size[i] );
p_extra += i_size[i];
i_extra += i_size[i];
}
} }
else if( !strncmp( tk->psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) || else if( MKV_IS_ID( el, KaxBlockDuration ) )
!strncmp( tk->psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
{
int i_profile, i_srate;
static unsigned int i_sample_rates[] =
{ {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, KaxBlockDuration &dur = *(KaxBlockDuration*)el;
16000, 12000, 11025, 8000, 7350, 0, 0, 0
};
tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
/* create data for faad (MP4DecSpecificDescrTag)*/
if( !strcmp( &tk->psz_codec[12], "MAIN" ) ) dur.ReadData( es.I_O() );
{ *pi_duration = uint64( dur );
i_profile = 0;
}
else if( !strcmp( &tk->psz_codec[12], "LC" ) )
{
i_profile = 1;
}
else if( !strcmp( &tk->psz_codec[12], "SSR" ) )
{
i_profile = 2;
}
else
{
i_profile = 3;
} }
else if( MKV_IS_ID( el, KaxReferenceBlock ) )
for( i_srate = 0; i_srate < 13; i_srate++ )
{
if( i_sample_rates[i_srate] == tk->fmt.audio.i_rate )
{ {
break; KaxReferenceBlock &ref = *(KaxReferenceBlock*)el;
}
}
msg_Dbg( p_demux, "profile=%d srate=%d", i_profile, i_srate );
tk->fmt.i_extra = 2; ref.ReadData( es.I_O() );
tk->fmt.p_extra = malloc( tk->fmt.i_extra ); if( *pi_ref1 == -1 )
((uint8_t*)tk->fmt.p_extra)[0] = ((i_profile + 1) << 3) | ((i_srate&0xe) >> 1);
((uint8_t*)tk->fmt.p_extra)[1] = ((i_srate & 0x1) << 7) | (tk->fmt.audio.i_channels << 3);
}
else if( !strcmp( tk->psz_codec, "A_PCM/INT/BIG" ) ||
!strcmp( tk->psz_codec, "A_PCM/INT/LIT" ) ||
!strcmp( tk->psz_codec, "A_PCM/FLOAT/IEEE" ) )
{
if( !strcmp( tk->psz_codec, "A_PCM/INT/BIG" ) )
{ {
tk->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' ); *pi_ref1 = int64( ref );
} }
else else
{ {
tk->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' ); *pi_ref2 = int64( ref );
}
tk->fmt.audio.i_blockalign = ( tk->fmt.audio.i_bitspersample + 7 ) / 8 * tk->fmt.audio.i_channels;
}
else if( !strcmp( tk->psz_codec, "A_TTA1" ) )
{
/* FIXME: support this codec */
msg_Err( p_demux, "TTA not supported yet[%d, n=%d]", i_track, tk->i_number );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
}
else if( !strcmp( tk->psz_codec, "A_WAVPACK4" ) )
{
/* FIXME: support this codec */
msg_Err( p_demux, "Wavpack not supported yet[%d, n=%d]", i_track, tk->i_number );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
}
else if( !strcmp( tk->psz_codec, "S_TEXT/UTF8" ) )
{
tk->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
} }
else if( !strcmp( tk->psz_codec, "S_TEXT/SSA" ) ||
!strcmp( tk->psz_codec, "S_TEXT/ASS" ) ||
!strcmp( tk->psz_codec, "S_SSA" ) ||
!strcmp( tk->psz_codec, "S_ASS" ))
{
tk->fmt.i_codec = VLC_FOURCC( 's', 's', 'a', ' ' );
tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
} }
else if( !strcmp( tk->psz_codec, "S_VOBSUB" ) ) else if( MKV_IS_ID( el, KaxClusterSilentTrackNumber ) )
{
tk->fmt.i_codec = VLC_FOURCC( 's','p','u',' ' );
if( tk->i_extra_data )
{ {
char *p_start; KaxClusterSilentTrackNumber &track_num = *(KaxClusterSilentTrackNumber*)el;
char *p_buf = (char *)malloc( tk->i_extra_data + 1); track_num.ReadData( es.I_O() );
memcpy( p_buf, tk->p_extra_data , tk->i_extra_data ); // find the track
p_buf[tk->i_extra_data] = '\0'; for (size_t i=0; i<tracks.size(); i++)
p_start = strstr( p_buf, "size:" );
if( sscanf( p_start, "size: %dx%d",
&tk->fmt.subs.spu.i_original_frame_width, &tk->fmt.subs.spu.i_original_frame_height ) == 2 )
{ {
msg_Dbg( p_demux, "original frame size vobsubs: %dx%d", tk->fmt.subs.spu.i_original_frame_width, tk->fmt.subs.spu.i_original_frame_height ); if ( tracks[i]->i_number == uint32(track_num))
}
else
{ {
msg_Warn( p_demux, "reading original frame size for vobsub failed" ); tracks[i]->b_silent = VLC_TRUE;
break;
} }
free( p_buf );
} }
} }
else if( !strcmp( tk->psz_codec, "B_VOBBTN" ) )
{
/* FIXME: support this codec */
msg_Err( p_demux, "Vob Buttons not supported yet[%d, n=%d]", i_track, tk->i_number );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
} }
else else
{ {
msg_Err( p_demux, "unknow codec id=`%s'", tk->psz_codec ); msg_Err( &sys.demuxer, "invalid level = %d", i_level );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' ); return VLC_EGENERIC;
}
if( tk->b_default )
{
tk->fmt.i_priority = 1000;
} }
tk->p_es = es_out_Add( p_demux->out, &tk->fmt );
#undef tk
} }
/* add information */
InformationCreate( p_demux );
return VLC_SUCCESS;
error:
delete p_sys;
return VLC_EGENERIC;
} }
/***************************************************************************** static block_t *MemToBlock( demux_t *p_demux, uint8_t *p_mem, int i_mem)
* Close: frees unused data
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{ {
demux_t *p_demux = (demux_t*)p_this; block_t *p_block;
demux_sys_t *p_sys = p_demux->p_sys; if( !(p_block = block_New( p_demux, i_mem ) ) ) return NULL;
matroska_stream_t *p_stream = p_sys->Stream(); memcpy( p_block->p_buffer, p_mem, i_mem );
matroska_segment_t *p_segment = p_stream->Segment(); //p_block->i_rate = p_input->stream.control.i_rate;
return p_block;
/* TODO close everything ? */
delete p_segment->segment;
delete p_sys;
} }
/***************************************************************************** static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
* Control: mtime_t i_duration )
*****************************************************************************/
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;
matroska_stream_t *p_stream = p_sys->Stream(); matroska_stream_t *p_stream = p_sys->Stream();
matroska_segment_t *p_segment = p_stream->Segment(); matroska_segment_t *p_segment = p_stream->Segment();
int64_t *pi64;
double *pf, f;
int i_skp;
vlc_meta_t **pp_meta; size_t i_track;
unsigned int i;
vlc_bool_t b;
switch( i_query ) #define tk p_segment->tracks[i_track]
for( i_track = 0; i_track < p_segment->tracks.size(); i_track++ )
{ {
case DEMUX_GET_META: if( tk->i_number == block->TrackNum() )
pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** ); {
*pp_meta = vlc_meta_Duplicate( p_sys->meta ); break;
return VLC_SUCCESS; }
}
case DEMUX_GET_LENGTH: if( i_track >= p_segment->tracks.size() )
pi64 = (int64_t*)va_arg( args, int64_t * );
if( p_segment->f_duration > 0.0 )
{ {
*pi64 = (int64_t)(p_segment->f_duration * 1000); msg_Err( p_demux, "invalid track number=%d", block->TrackNum() );
return VLC_SUCCESS; return;
}
if( tk->p_es == NULL )
{
msg_Err( p_demux, "unknown track number=%d", block->TrackNum() );
return;
}
if( i_pts < p_sys->i_start_pts && tk->fmt.i_cat == AUDIO_ES )
{
return; /* discard audio packets that shouldn't be rendered */
} }
return VLC_EGENERIC;
case DEMUX_GET_POSITION: es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
pf = (double*)va_arg( args, double * ); if( !b )
*pf = (double)p_sys->i_pts / (1000.0 * p_segment->f_duration); {
return VLC_SUCCESS; tk->b_inited = VLC_FALSE;
return;
}
case DEMUX_SET_POSITION: /* First send init data */
f = (double)va_arg( args, double ); if( !tk->b_inited && tk->i_data_init > 0 )
Seek( p_demux, -1, f, NULL ); {
return VLC_SUCCESS; block_t *p_init;
case DEMUX_GET_TIME: msg_Dbg( p_demux, "sending header (%d bytes)", tk->i_data_init );
pi64 = (int64_t*)va_arg( args, int64_t * ); p_init = MemToBlock( p_demux, tk->p_data_init, tk->i_data_init );
*pi64 = p_sys->i_pts; if( p_init ) es_out_Send( p_demux->out, tk->p_es, p_init );
return VLC_SUCCESS; }
tk->b_inited = VLC_TRUE;
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; for( i = 0; i < block->NumberFrames(); i++ )
*ppp_title = (input_title_t**)malloc( sizeof( input_title_t**) ); {
block_t *p_block;
DataBuffer &data = block->GetBuffer(i);
(*ppp_title)[0] = vlc_input_title_Duplicate( p_sys->title ); p_block = MemToBlock( p_demux, data.Buffer(), data.Size() );
return VLC_SUCCESS; if( p_block == NULL )
{
break;
} }
return VLC_EGENERIC;
case DEMUX_SET_TITLE: #if defined(HAVE_ZLIB_H)
/* TODO handle editions as titles & DVD titles as well */ if( tk->i_compression_type )
if( p_sys->title && p_sys->title->i_seekpoint > 0 )
{ {
return VLC_SUCCESS; p_block = block_zlib_decompress( VLC_OBJECT(p_demux), p_block );
} }
return VLC_EGENERIC; #endif
case DEMUX_SET_SEEKPOINT: // TODO implement correct timestamping when B frames are used
/* FIXME do a better implementation */ if( tk->fmt.i_cat != VIDEO_ES )
i_skp = (int)va_arg( args, int ); {
p_block->i_dts = p_block->i_pts = i_pts;
}
else
{
p_block->i_dts = i_pts;
p_block->i_pts = 0;
}
if( p_sys->title && i_skp < p_sys->title->i_seekpoint) if( tk->fmt.i_cat == SPU_ES && strcmp( tk->psz_codec, "S_VOBSUB" ) )
{ {
Seek( p_demux, (int64_t)p_sys->title->seekpoint[i_skp]->i_time_offset, -1, NULL); p_block->i_length = i_duration * 1000;
p_demux->info.i_seekpoint |= INPUT_UPDATE_SEEKPOINT;
p_demux->info.i_seekpoint = i_skp;
return VLC_SUCCESS;
} }
return VLC_EGENERIC; es_out_Send( p_demux->out, tk->p_es, p_block );
case DEMUX_SET_TIME: /* use time stamp only for first block */
case DEMUX_GET_FPS: i_pts = 0;
default:
return VLC_EGENERIC;
} }
#undef tk
} }
int matroska_segment_t::BlockGet( KaxBlock **pp_block, int64_t *pi_ref1, int64_t *pi_ref2, int64_t *pi_duration ) matroska_stream_t *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream )
{ {
*pp_block = NULL; int i_upper_lvl = 0;
*pi_ref1 = -1; size_t i;
*pi_ref2 = -1; EbmlElement *p_l0, *p_l1, *p_l2;
bool b_keep_stream = false, b_keep_segment;
for( ;; ) // verify the EBML Header
p_l0 = p_estream->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL);
if (p_l0 == NULL)
{ {
EbmlElement *el; return NULL;
int i_level; }
p_l0->SkipData(*p_estream, EbmlHead_Context);
delete p_l0;
if( sys.demuxer.b_die ) // find all segments in this file
p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
if (p_l0 == NULL)
{ {
return VLC_EGENERIC; return NULL;
} }
el = ep->Get(); matroska_stream_t *p_stream1 = new matroska_stream_t( *this );
i_level = ep->GetLevel();
if( el == NULL && *pp_block != NULL ) while (p_l0 != 0)
{ {
/* update the index */ if (EbmlId(*p_l0) == KaxSegment::ClassInfos.GlobalId)
#define idx index[i_index - 1]
if( i_index > 0 && idx.i_time == -1 )
{ {
idx.i_time = (*pp_block)->GlobalTimecode() / (mtime_t)1000; EbmlParser *ep;
idx.b_key = *pi_ref1 == -1 ? VLC_TRUE : VLC_FALSE; matroska_segment_t *p_segment1 = new matroska_segment_t( *this, *p_estream );
} b_keep_segment = false;
#undef idx
return VLC_SUCCESS;
}
if( el == NULL ) ep = new EbmlParser(p_estream, p_l0);
{ p_segment1->ep = ep;
if( ep->GetLevel() > 1 ) p_segment1->segment = (KaxSegment*)p_l0;
{
ep->Up();
continue;
}
msg_Warn( &sys.demuxer, "EOF" );
return VLC_EGENERIC;
}
/* do parsing */ while ((p_l1 = ep->Get()))
if( i_level == 1 )
{ {
if( MKV_IS_ID( el, KaxCluster ) ) if (MKV_IS_ID(p_l1, KaxInfo))
{ {
cluster = (KaxCluster*)el; // find the families of this segment
KaxInfo *p_info = static_cast<KaxInfo*>(p_l1);
/* add it to the index */ p_info->Read(*p_estream, KaxInfo::ClassInfos.Context, i_upper_lvl, p_l2, true);
if( i_index == 0 || for( i = 0; i < p_info->ListSize(); i++ )
( i_index > 0 && index[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
{ {
IndexAppendCluster( cluster ); EbmlElement *l = (*p_info)[i];
}
// reset silent tracks if( MKV_IS_ID( l, KaxSegmentUID ) )
for (size_t i=0; i<tracks.size(); i++)
{ {
tracks[i]->b_silent = VLC_FALSE; KaxSegmentUID *p_uid = static_cast<KaxSegmentUID*>(l);
b_keep_segment = (FindSegment( *p_uid ) == NULL);
if ( !b_keep_segment )
break; // this segment is already known
p_segment1->segment_uid = *( new KaxSegmentUID(*p_uid) );
} }
else if( MKV_IS_ID( l, KaxPrevUID ) )
ep->Down(); {
p_segment1->prev_segment_uid = *( new KaxPrevUID( *static_cast<KaxPrevUID*>(l) ) );
} }
else if( MKV_IS_ID( el, KaxCues ) ) else if( MKV_IS_ID( l, KaxNextUID ) )
{ {
msg_Warn( &sys.demuxer, "find KaxCues FIXME" ); p_segment1->next_segment_uid = *( new KaxNextUID( *static_cast<KaxNextUID*>(l) ) );
return VLC_EGENERIC;
} }
else else if( MKV_IS_ID( l, KaxSegmentFamily ) )
{ {
msg_Dbg( &sys.demuxer, "unknown (%s)", typeid( el ).name() ); KaxSegmentFamily *p_fam = new KaxSegmentFamily( *static_cast<KaxSegmentFamily*>(l) );
std::vector<KaxSegmentFamily>::iterator iter;
p_segment1->families.push_back( *p_fam );
} }
} }
else if( i_level == 2 ) break;
{
if( MKV_IS_ID( el, KaxClusterTimecode ) )
{
KaxClusterTimecode &ctc = *(KaxClusterTimecode*)el;
ctc.ReadData( es.I_O(), SCOPE_ALL_DATA );
cluster->InitTimecode( uint64( ctc ), i_timescale );
} }
else if( MKV_IS_ID( el, KaxClusterSilentTracks ) )
{
ep->Down();
} }
else if( MKV_IS_ID( el, KaxBlockGroup ) ) if ( b_keep_segment )
{ {
ep->Down(); b_keep_stream = true;
p_stream1->segments.push_back( p_segment1 );
} }
else
delete p_segment1;
} }
else if( i_level == 3 )
{
if( MKV_IS_ID( el, KaxBlock ) )
{
*pp_block = (KaxBlock*)el;
(*pp_block)->ReadData( es.I_O() );
(*pp_block)->SetParent( *cluster );
ep->Keep(); p_l0->SkipData(*p_estream, EbmlHead_Context);
p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
} }
else if( MKV_IS_ID( el, KaxBlockDuration ) )
{
KaxBlockDuration &dur = *(KaxBlockDuration*)el;
dur.ReadData( es.I_O() ); if ( !b_keep_stream )
*pi_duration = uint64( dur ); {
delete p_stream1;
p_stream1 = NULL;
} }
else if( MKV_IS_ID( el, KaxReferenceBlock ) )
return p_stream1;
}
bool matroska_segment_t::Select( )
{
size_t i_track;
/* add all es */
msg_Dbg( &sys.demuxer, "found %d es", tracks.size() );
for( i_track = 0; i_track < tracks.size(); i_track++ )
{ {
KaxReferenceBlock &ref = *(KaxReferenceBlock*)el; #define tk tracks[i_track]
if( tk->fmt.i_cat == UNKNOWN_ES )
{
msg_Warn( &sys.demuxer, "invalid track[%d, n=%d]", i_track, tk->i_number );
tk->p_es = NULL;
continue;
}
ref.ReadData( es.I_O() ); if( !strcmp( tk->psz_codec, "V_MS/VFW/FOURCC" ) )
if( *pi_ref1 == -1 )
{ {
*pi_ref1 = int64( ref ); if( tk->i_extra_data < (int)sizeof( BITMAPINFOHEADER ) )
{
msg_Err( &sys.demuxer, "missing/invalid BITMAPINFOHEADER" );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
} }
else else
{ {
*pi_ref2 = int64( ref ); BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)tk->p_extra_data;
tk->fmt.video.i_width = GetDWLE( &p_bih->biWidth );
tk->fmt.video.i_height= GetDWLE( &p_bih->biHeight );
tk->fmt.i_codec = GetFOURCC( &p_bih->biCompression );
tk->fmt.i_extra = GetDWLE( &p_bih->biSize ) - sizeof( BITMAPINFOHEADER );
if( tk->fmt.i_extra > 0 )
{
tk->fmt.p_extra = malloc( tk->fmt.i_extra );
memcpy( tk->fmt.p_extra, &p_bih[1], tk->fmt.i_extra );
} }
} }
else if( MKV_IS_ID( el, KaxClusterSilentTrackNumber ) ) }
else if( !strcmp( tk->psz_codec, "V_MPEG1" ) ||
!strcmp( tk->psz_codec, "V_MPEG2" ) )
{ {
KaxClusterSilentTrackNumber &track_num = *(KaxClusterSilentTrackNumber*)el; tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
track_num.ReadData( es.I_O() ); }
// find the track else if( !strncmp( tk->psz_codec, "V_MPEG4", 7 ) )
for (size_t i=0; i<tracks.size(); i++)
{ {
if ( tracks[i]->i_number == uint32(track_num)) if( !strcmp( tk->psz_codec, "V_MPEG4/MS/V3" ) )
{ {
tracks[i]->b_silent = VLC_TRUE; tk->fmt.i_codec = VLC_FOURCC( 'D', 'I', 'V', '3' );
break;
} }
else if( !strcmp( tk->psz_codec, "V_MPEG4/ISO/AVC" ) )
{
tk->fmt.i_codec = VLC_FOURCC( 'a', 'v', 'c', '1' );
tk->fmt.b_packetized = VLC_FALSE;
tk->fmt.i_extra = tk->i_extra_data;
tk->fmt.p_extra = malloc( tk->i_extra_data );
memcpy( tk->fmt.p_extra,tk->p_extra_data, tk->i_extra_data );
} }
else
{
tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
} }
} }
else else if( !strcmp( tk->psz_codec, "V_QUICKTIME" ) )
{ {
msg_Err( &sys.demuxer, "invalid level = %d", i_level ); MP4_Box_t *p_box = (MP4_Box_t*)malloc( sizeof( MP4_Box_t ) );
return VLC_EGENERIC; stream_t *p_mp4_stream = stream_MemoryNew( VLC_OBJECT(&sys.demuxer),
tk->p_extra_data,
tk->i_extra_data );
MP4_ReadBoxCommon( p_mp4_stream, p_box );
MP4_ReadBox_sample_vide( p_mp4_stream, p_box );
tk->fmt.i_codec = p_box->i_type;
tk->fmt.video.i_width = p_box->data.p_sample_vide->i_width;
tk->fmt.video.i_height = p_box->data.p_sample_vide->i_height;
tk->fmt.i_extra = p_box->data.p_sample_vide->i_qt_image_description;
tk->fmt.p_extra = malloc( tk->fmt.i_extra );
memcpy( tk->fmt.p_extra, p_box->data.p_sample_vide->p_qt_image_description, tk->fmt.i_extra );
MP4_FreeBox_sample_vide( p_box );
stream_MemoryDelete( p_mp4_stream, VLC_TRUE );
} }
else if( !strcmp( tk->psz_codec, "A_MS/ACM" ) )
{
if( tk->i_extra_data < (int)sizeof( WAVEFORMATEX ) )
{
msg_Err( &sys.demuxer, "missing/invalid WAVEFORMATEX" );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
} }
} else
{
static block_t *MemToBlock( demux_t *p_demux, uint8_t *p_mem, int i_mem) WAVEFORMATEX *p_wf = (WAVEFORMATEX*)tk->p_extra_data;
{
block_t *p_block;
if( !(p_block = block_New( p_demux, i_mem ) ) ) return NULL;
memcpy( p_block->p_buffer, p_mem, i_mem );
//p_block->i_rate = p_input->stream.control.i_rate;
return p_block;
}
static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts, wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &tk->fmt.i_codec, NULL );
mtime_t i_duration )
{
demux_sys_t *p_sys = p_demux->p_sys;
matroska_stream_t *p_stream = p_sys->Stream();
matroska_segment_t *p_segment = p_stream->Segment();
size_t i_track; tk->fmt.audio.i_channels = GetWLE( &p_wf->nChannels );
unsigned int i; tk->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
vlc_bool_t b; tk->fmt.i_bitrate = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
tk->fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign );;
tk->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );
#define tk p_segment->tracks[i_track] tk->fmt.i_extra = GetWLE( &p_wf->cbSize );
for( i_track = 0; i_track < p_segment->tracks.size(); i_track++ ) if( tk->fmt.i_extra > 0 )
{
if( tk->i_number == block->TrackNum() )
{ {
break; tk->fmt.p_extra = malloc( tk->fmt.i_extra );
memcpy( tk->fmt.p_extra, &p_wf[1], tk->fmt.i_extra );
} }
} }
}
if( i_track >= p_segment->tracks.size() ) else if( !strcmp( tk->psz_codec, "A_MPEG/L3" ) ||
!strcmp( tk->psz_codec, "A_MPEG/L2" ) ||
!strcmp( tk->psz_codec, "A_MPEG/L1" ) )
{ {
msg_Err( p_demux, "invalid track number=%d", block->TrackNum() ); tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
return;
} }
if( tk->p_es == NULL ) else if( !strcmp( tk->psz_codec, "A_AC3" ) )
{ {
msg_Err( p_demux, "unknown track number=%d", block->TrackNum() ); tk->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
return;
} }
if( i_pts < p_sys->i_start_pts && tk->fmt.i_cat == AUDIO_ES ) else if( !strcmp( tk->psz_codec, "A_DTS" ) )
{ {
return; /* discard audio packets that shouldn't be rendered */ tk->fmt.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
} }
else if( !strcmp( tk->psz_codec, "A_FLAC" ) )
es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
if( !b )
{ {
tk->b_inited = VLC_FALSE; tk->fmt.i_codec = VLC_FOURCC( 'f', 'l', 'a', 'c' );
return; tk->fmt.i_extra = tk->i_extra_data;
tk->fmt.p_extra = malloc( tk->i_extra_data );
memcpy( tk->fmt.p_extra,tk->p_extra_data, tk->i_extra_data );
} }
else if( !strcmp( tk->psz_codec, "A_VORBIS" ) )
/* First send init data */
if( !tk->b_inited && tk->i_data_init > 0 )
{ {
block_t *p_init; int i, i_offset = 1, i_size[3], i_extra;
uint8_t *p_extra;
msg_Dbg( p_demux, "sending header (%d bytes)", tk->i_data_init ); tk->fmt.i_codec = VLC_FOURCC( 'v', 'o', 'r', 'b' );
p_init = MemToBlock( p_demux, tk->p_data_init, tk->i_data_init );
if( p_init ) es_out_Send( p_demux->out, tk->p_es, p_init );
}
tk->b_inited = VLC_TRUE;
/* Split the 3 headers */
if( tk->p_extra_data[0] != 0x02 )
msg_Err( &sys.demuxer, "invalid vorbis header" );
for( i = 0; i < block->NumberFrames(); i++ ) for( i = 0; i < 2; i++ )
{ {
block_t *p_block; i_size[i] = 0;
DataBuffer &data = block->GetBuffer(i); while( i_offset < tk->i_extra_data )
p_block = MemToBlock( p_demux, data.Buffer(), data.Size() );
if( p_block == NULL )
{ {
break; i_size[i] += tk->p_extra_data[i_offset];
if( tk->p_extra_data[i_offset++] != 0xff ) break;
} }
#if defined(HAVE_ZLIB_H)
if( tk->i_compression_type )
{
p_block = block_zlib_decompress( VLC_OBJECT(p_demux), p_block );
} }
#endif
// TODO implement correct timestamping when B frames are used i_size[0] = __MIN(i_size[0], tk->i_extra_data - i_offset);
if( tk->fmt.i_cat != VIDEO_ES ) i_size[1] = __MIN(i_size[1], tk->i_extra_data -i_offset -i_size[0]);
i_size[2] = tk->i_extra_data - i_offset - i_size[0] - i_size[1];
tk->fmt.i_extra = 3 * 2 + i_size[0] + i_size[1] + i_size[2];
tk->fmt.p_extra = malloc( tk->fmt.i_extra );
p_extra = (uint8_t *)tk->fmt.p_extra; i_extra = 0;
for( i = 0; i < 3; i++ )
{ {
p_block->i_dts = p_block->i_pts = i_pts; *(p_extra++) = i_size[i] >> 8;
*(p_extra++) = i_size[i] & 0xFF;
memcpy( p_extra, tk->p_extra_data + i_offset + i_extra,
i_size[i] );
p_extra += i_size[i];
i_extra += i_size[i];
} }
else
{
p_block->i_dts = i_pts;
p_block->i_pts = 0;
} }
else if( !strncmp( tk->psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) ||
!strncmp( tk->psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
{
int i_profile, i_srate;
static unsigned int i_sample_rates[] =
{
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000, 7350, 0, 0, 0
};
if( tk->fmt.i_cat == SPU_ES && strcmp( tk->psz_codec, "S_VOBSUB" ) ) tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
/* create data for faad (MP4DecSpecificDescrTag)*/
if( !strcmp( &tk->psz_codec[12], "MAIN" ) )
{ {
p_block->i_length = i_duration * 1000; i_profile = 0;
} }
es_out_Send( p_demux->out, tk->p_es, p_block ); else if( !strcmp( &tk->psz_codec[12], "LC" ) )
{
/* use time stamp only for first block */ i_profile = 1;
i_pts = 0;
} }
else if( !strcmp( &tk->psz_codec[12], "SSR" ) )
#undef tk
}
matroska_stream_t *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream )
{
int i_upper_lvl = 0;
size_t i;
EbmlElement *p_l0, *p_l1, *p_l2;
bool b_keep_stream = false, b_keep_segment;
// verify the EBML Header
p_l0 = p_estream->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL);
if (p_l0 == NULL)
{ {
return NULL; i_profile = 2;
} }
p_l0->SkipData(*p_estream, EbmlHead_Context); else
delete p_l0;
// find all segments in this file
p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
if (p_l0 == NULL)
{ {
return NULL; i_profile = 3;
} }
matroska_stream_t *p_stream1 = new matroska_stream_t( *this ); for( i_srate = 0; i_srate < 13; i_srate++ )
while (p_l0 != 0)
{ {
if (EbmlId(*p_l0) == KaxSegment::ClassInfos.GlobalId) if( i_sample_rates[i_srate] == tk->fmt.audio.i_rate )
{ {
EbmlParser *ep; break;
matroska_segment_t *p_segment1 = new matroska_segment_t( *this, *p_estream ); }
b_keep_segment = false; }
msg_Dbg( &sys.demuxer, "profile=%d srate=%d", i_profile, i_srate );
ep = new EbmlParser(p_estream, p_l0);
p_segment1->ep = ep;
p_segment1->segment = (KaxSegment*)p_l0;
while ((p_l1 = ep->Get())) tk->fmt.i_extra = 2;
tk->fmt.p_extra = malloc( tk->fmt.i_extra );
((uint8_t*)tk->fmt.p_extra)[0] = ((i_profile + 1) << 3) | ((i_srate&0xe) >> 1);
((uint8_t*)tk->fmt.p_extra)[1] = ((i_srate & 0x1) << 7) | (tk->fmt.audio.i_channels << 3);
}
else if( !strcmp( tk->psz_codec, "A_PCM/INT/BIG" ) ||
!strcmp( tk->psz_codec, "A_PCM/INT/LIT" ) ||
!strcmp( tk->psz_codec, "A_PCM/FLOAT/IEEE" ) )
{ {
if (MKV_IS_ID(p_l1, KaxInfo)) if( !strcmp( tk->psz_codec, "A_PCM/INT/BIG" ) )
{ {
// find the families of this segment tk->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
KaxInfo *p_info = static_cast<KaxInfo*>(p_l1); }
else
p_info->Read(*p_estream, KaxInfo::ClassInfos.Context, i_upper_lvl, p_l2, true);
for( i = 0; i < p_info->ListSize(); i++ )
{ {
EbmlElement *l = (*p_info)[i]; tk->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
}
if( MKV_IS_ID( l, KaxSegmentUID ) ) tk->fmt.audio.i_blockalign = ( tk->fmt.audio.i_bitspersample + 7 ) / 8 * tk->fmt.audio.i_channels;
}
else if( !strcmp( tk->psz_codec, "A_TTA1" ) )
{ {
KaxSegmentUID *p_uid = static_cast<KaxSegmentUID*>(l); /* FIXME: support this codec */
b_keep_segment = (FindSegment( *p_uid ) == NULL); msg_Err( &sys.demuxer, "TTA not supported yet[%d, n=%d]", i_track, tk->i_number );
if ( !b_keep_segment ) tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
break; // this segment is already known
p_segment1->segment_uid = *( new KaxSegmentUID(*p_uid) );
} }
else if( MKV_IS_ID( l, KaxPrevUID ) ) else if( !strcmp( tk->psz_codec, "A_WAVPACK4" ) )
{ {
p_segment1->prev_segment_uid = *( new KaxPrevUID( *static_cast<KaxPrevUID*>(l) ) ); /* FIXME: support this codec */
msg_Err( &sys.demuxer, "Wavpack not supported yet[%d, n=%d]", i_track, tk->i_number );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
} }
else if( MKV_IS_ID( l, KaxNextUID ) ) else if( !strcmp( tk->psz_codec, "S_TEXT/UTF8" ) )
{ {
p_segment1->next_segment_uid = *( new KaxNextUID( *static_cast<KaxNextUID*>(l) ) ); tk->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
} }
else if( MKV_IS_ID( l, KaxSegmentFamily ) ) else if( !strcmp( tk->psz_codec, "S_TEXT/SSA" ) ||
!strcmp( tk->psz_codec, "S_TEXT/ASS" ) ||
!strcmp( tk->psz_codec, "S_SSA" ) ||
!strcmp( tk->psz_codec, "S_ASS" ))
{ {
KaxSegmentFamily *p_fam = new KaxSegmentFamily( *static_cast<KaxSegmentFamily*>(l) ); tk->fmt.i_codec = VLC_FOURCC( 's', 's', 'a', ' ' );
std::vector<KaxSegmentFamily>::iterator iter; tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
p_segment1->families.push_back( *p_fam ); }
else if( !strcmp( tk->psz_codec, "S_VOBSUB" ) )
{
tk->fmt.i_codec = VLC_FOURCC( 's','p','u',' ' );
if( tk->i_extra_data )
{
char *p_start;
char *p_buf = (char *)malloc( tk->i_extra_data + 1);
memcpy( p_buf, tk->p_extra_data , tk->i_extra_data );
p_buf[tk->i_extra_data] = '\0';
p_start = strstr( p_buf, "size:" );
if( sscanf( p_start, "size: %dx%d",
&tk->fmt.subs.spu.i_original_frame_width, &tk->fmt.subs.spu.i_original_frame_height ) == 2 )
{
msg_Dbg( &sys.demuxer, "original frame size vobsubs: %dx%d", tk->fmt.subs.spu.i_original_frame_width, tk->fmt.subs.spu.i_original_frame_height );
} }
else
{
msg_Warn( &sys.demuxer, "reading original frame size for vobsub failed" );
} }
break; free( p_buf );
} }
} }
if ( b_keep_segment ) else if( !strcmp( tk->psz_codec, "B_VOBBTN" ) )
{ {
b_keep_stream = true; /* FIXME: support this codec */
p_stream1->segments.push_back( p_segment1 ); msg_Err( &sys.demuxer, "Vob Buttons not supported yet[%d, n=%d]", i_track, tk->i_number );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
} }
else else
delete p_segment1; {
msg_Err( &sys.demuxer, "unknow codec id=`%s'", tk->psz_codec );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
}
if( tk->b_default )
{
tk->fmt.i_priority = 1000;
} }
p_l0->SkipData(*p_estream, EbmlHead_Context); tk->p_es = es_out_Add( sys.demuxer.out, &tk->fmt );
p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL); #undef tk
} }
if ( !b_keep_stream ) return true;
}
void matroska_segment_t::UnSelect( )
{
size_t i_track;
for( i_track = 0; i_track < tracks.size(); i_track++ )
{ {
delete p_stream1; #define tk tracks[i_track]
p_stream1 = NULL; if ( tk->p_es != NULL )
{
es_out_Del( sys.demuxer.out, tk->p_es );
tk->p_es = NULL;
}
#undef tk
} }
return p_stream1;
} }
static void UpdateCurrentToChapter( demux_t & demux ) static void UpdateCurrentToChapter( demux_t & demux )
...@@ -1767,8 +1797,13 @@ static int Demux( demux_t *p_demux) ...@@ -1767,8 +1797,13 @@ static int Demux( demux_t *p_demux)
/* nothing left to read in this ordered edition */ /* nothing left to read in this ordered edition */
if ( p_stream->i_current_segment == p_stream->segments.size() - 1) if ( p_stream->i_current_segment == p_stream->segments.size() - 1)
return 0; return 0;
p_segment->UnSelect( );
/* switch to the next segment (TODO update the duration) */ /* switch to the next segment (TODO update the duration) */
p_stream->i_current_segment++; p_stream->i_current_segment++;
p_segment = p_stream->Segment();
if ( !p_segment || !p_segment->Select( ) )
return 0;
continue; continue;
} }
...@@ -3441,7 +3476,7 @@ bool matroska_segment_t::Preload( ) ...@@ -3441,7 +3476,7 @@ bool matroska_segment_t::Preload( )
return true; return true;
} }
matroska_segment_t *demux_sys_t::FindSegment( EbmlBinary & uid ) const matroska_segment_t *demux_sys_t::FindSegment( const EbmlBinary & uid ) const
{ {
matroska_segment_t *p_segment = NULL; matroska_segment_t *p_segment = NULL;
for (size_t i=0; i<streams.size() && p_segment == NULL; i++) for (size_t i=0; i<streams.size() && p_segment == NULL; i++)
...@@ -3451,7 +3486,7 @@ matroska_segment_t *demux_sys_t::FindSegment( EbmlBinary & uid ) const ...@@ -3451,7 +3486,7 @@ matroska_segment_t *demux_sys_t::FindSegment( EbmlBinary & uid ) const
return p_segment; return p_segment;
} }
matroska_segment_t *matroska_stream_t::FindSegment( EbmlBinary & uid ) const matroska_segment_t *matroska_stream_t::FindSegment( const EbmlBinary & uid ) const
{ {
for (size_t i=0; i<segments.size(); i++) for (size_t i=0; i<segments.size(); i++)
{ {
......
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