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

mkv.cpp: allow seamless transition between segments

parent 77a1a288
......@@ -507,6 +507,8 @@ public:
void ParseTrackEntry( EbmlMaster *m );
void IndexAppendCluster( KaxCluster *cluster );
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
......@@ -542,7 +544,7 @@ public:
return NULL;
}
matroska_segment_t *FindSegment( EbmlBinary & uid ) const;
matroska_segment_t *FindSegment( const EbmlBinary & uid ) const;
void PreloadFamily( const matroska_segment_t & segment );
size_t PreloadLinked( const demux_sys_t & of_sys );
......@@ -588,7 +590,7 @@ public:
return NULL;
}
matroska_segment_t *FindSegment( EbmlBinary & uid ) const;
matroska_segment_t *FindSegment( const EbmlBinary & uid ) const;
void PreloadFamily( );
void PreloadLinked( );
matroska_stream_t *AnalyseAllSegmentsFound( EbmlStream *p_estream );
......@@ -615,7 +617,6 @@ static int Open( vlc_object_t * p_this )
matroska_segment_t *p_segment;
uint8_t *p_peek;
std::string s_path, s_filename;
size_t i_track;
vlc_stream_io_callback *p_io_callback;
EbmlStream *p_io_stream;
......@@ -758,758 +759,787 @@ static int Open( vlc_object_t * p_this )
p_segment->b_cues = VLC_FALSE;
}
/* add all es */
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 )
if ( !p_segment->Select() )
{
msg_Warn( p_demux, "invalid track[%d, n=%d]", i_track, tk->i_number );
tk->p_es = NULL;
continue;
msg_Err( p_demux, "cannot use the segment" );
goto error;
}
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" );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
*pi64 = (int64_t)(p_segment->f_duration * 1000);
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 );
tk->fmt.video.i_height= GetDWLE( &p_bih->biHeight );
tk->fmt.i_codec = GetFOURCC( &p_bih->biCompression );
*pi_int = 1;
*ppp_title = (input_title_t**)malloc( sizeof( input_title_t**) );
tk->fmt.i_extra = GetDWLE( &p_bih->biSize ) - sizeof( BITMAPINFOHEADER );
if( tk->fmt.i_extra > 0 )
(*ppp_title)[0] = vlc_input_title_Duplicate( p_sys->title );
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 );
memcpy( tk->fmt.p_extra, &p_bih[1], tk->fmt.i_extra );
return VLC_SUCCESS;
}
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" ) )
{
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 );
#undef idx
return VLC_SUCCESS;
}
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 ) );
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( MKV_IS_ID( el, KaxCluster ) )
{
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" );
tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
IndexAppendCluster( cluster );
}
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 );
if( tk->fmt.i_extra > 0 )
// reset silent tracks
for (size_t i=0; i<tracks.size(); i++)
{
tk->fmt.p_extra = malloc( tk->fmt.i_extra );
memcpy( tk->fmt.p_extra, &p_wf[1], tk->fmt.i_extra );
tracks[i]->b_silent = VLC_FALSE;
}
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" ) ||
!strcmp( tk->psz_codec, "A_MPEG/L2" ) ||
!strcmp( tk->psz_codec, "A_MPEG/L1" ) )
else
{
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' );
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 );
ep->Down();
}
else if( !strcmp( tk->psz_codec, "A_VORBIS" ) )
}
else if( i_level == 3 )
{
int i, i_offset = 1, i_size[3], i_extra;
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 )
if( MKV_IS_ID( el, KaxBlock ) )
{
i_size[i] += tk->p_extra_data[i_offset];
if( tk->p_extra_data[i_offset++] != 0xff ) break;
}
}
*pp_block = (KaxBlock*)el;
i_size[0] = __MIN(i_size[0], tk->i_extra_data - i_offset);
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];
(*pp_block)->ReadData( es.I_O() );
(*pp_block)->SetParent( *cluster );
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_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];
}
ep->Keep();
}
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[] =
else if( MKV_IS_ID( el, KaxBlockDuration ) )
{
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000, 7350, 0, 0, 0
};
tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
/* create data for faad (MP4DecSpecificDescrTag)*/
KaxBlockDuration &dur = *(KaxBlockDuration*)el;
if( !strcmp( &tk->psz_codec[12], "MAIN" ) )
{
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;
dur.ReadData( es.I_O() );
*pi_duration = uint64( dur );
}
for( i_srate = 0; i_srate < 13; i_srate++ )
{
if( i_sample_rates[i_srate] == tk->fmt.audio.i_rate )
else if( MKV_IS_ID( el, KaxReferenceBlock ) )
{
break;
}
}
msg_Dbg( p_demux, "profile=%d srate=%d", i_profile, i_srate );
KaxReferenceBlock &ref = *(KaxReferenceBlock*)el;
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( !strcmp( tk->psz_codec, "A_PCM/INT/BIG" ) )
ref.ReadData( es.I_O() );
if( *pi_ref1 == -1 )
{
tk->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
*pi_ref1 = int64( ref );
}
else
{
tk->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
}
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" );
*pi_ref2 = int64( ref );
}
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" ) )
{
tk->fmt.i_codec = VLC_FOURCC( 's','p','u',' ' );
if( tk->i_extra_data )
else if( MKV_IS_ID( el, KaxClusterSilentTrackNumber ) )
{
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 )
KaxClusterSilentTrackNumber &track_num = *(KaxClusterSilentTrackNumber*)el;
track_num.ReadData( es.I_O() );
// find the track
for (size_t i=0; i<tracks.size(); i++)
{
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 );
}
else
if ( tracks[i]->i_number == uint32(track_num))
{
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
{
msg_Err( p_demux, "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;
msg_Err( &sys.demuxer, "invalid level = %d", i_level );
return VLC_EGENERIC;
}
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;
}
/*****************************************************************************
* Close: frees unused data
*****************************************************************************/
static void Close( vlc_object_t *p_this )
static block_t *MemToBlock( demux_t *p_demux, uint8_t *p_mem, int i_mem)
{
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;
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;
}
/*****************************************************************************
* Control:
*****************************************************************************/
static int Control( demux_t *p_demux, int i_query, va_list args )
static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
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();
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:
pp_meta = (vlc_meta_t**)va_arg( args, vlc_meta_t** );
*pp_meta = vlc_meta_Duplicate( p_sys->meta );
return VLC_SUCCESS;
if( tk->i_number == block->TrackNum() )
{
break;
}
}
case DEMUX_GET_LENGTH:
pi64 = (int64_t*)va_arg( args, int64_t * );
if( p_segment->f_duration > 0.0 )
if( i_track >= p_segment->tracks.size() )
{
*pi64 = (int64_t)(p_segment->f_duration * 1000);
return VLC_SUCCESS;
msg_Err( p_demux, "invalid track number=%d", block->TrackNum() );
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:
pf = (double*)va_arg( args, double * );
*pf = (double)p_sys->i_pts / (1000.0 * p_segment->f_duration);
return VLC_SUCCESS;
es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
if( !b )
{
tk->b_inited = VLC_FALSE;
return;
}
case DEMUX_SET_POSITION:
f = (double)va_arg( args, double );
Seek( p_demux, -1, f, NULL );
return VLC_SUCCESS;
/* First send init data */
if( !tk->b_inited && tk->i_data_init > 0 )
{
block_t *p_init;
case DEMUX_GET_TIME:
pi64 = (int64_t*)va_arg( args, int64_t * );
*pi64 = p_sys->i_pts;
return VLC_SUCCESS;
msg_Dbg( p_demux, "sending header (%d bytes)", tk->i_data_init );
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;
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**) );
for( i = 0; i < block->NumberFrames(); i++ )
{
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:
/* TODO handle editions as titles & DVD titles as well */
if( p_sys->title && p_sys->title->i_seekpoint > 0 )
#if defined(HAVE_ZLIB_H)
if( tk->i_compression_type )
{
return VLC_SUCCESS;
p_block = block_zlib_decompress( VLC_OBJECT(p_demux), p_block );
}
return VLC_EGENERIC;
#endif
case DEMUX_SET_SEEKPOINT:
/* FIXME do a better implementation */
i_skp = (int)va_arg( args, int );
// TODO implement correct timestamping when B frames are used
if( tk->fmt.i_cat != VIDEO_ES )
{
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_demux->info.i_seekpoint |= INPUT_UPDATE_SEEKPOINT;
p_demux->info.i_seekpoint = i_skp;
return VLC_SUCCESS;
p_block->i_length = i_duration * 1000;
}
return VLC_EGENERIC;
es_out_Send( p_demux->out, tk->p_es, p_block );
case DEMUX_SET_TIME:
case DEMUX_GET_FPS:
default:
return VLC_EGENERIC;
/* use time stamp only for first block */
i_pts = 0;
}
#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;
*pi_ref1 = -1;
*pi_ref2 = -1;
int i_upper_lvl = 0;
size_t i;
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;
int i_level;
return NULL;
}
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();
i_level = ep->GetLevel();
matroska_stream_t *p_stream1 = new matroska_stream_t( *this );
if( el == NULL && *pp_block != NULL )
while (p_l0 != 0)
{
/* update the index */
#define idx index[i_index - 1]
if( i_index > 0 && idx.i_time == -1 )
if (EbmlId(*p_l0) == KaxSegment::ClassInfos.GlobalId)
{
idx.i_time = (*pp_block)->GlobalTimecode() / (mtime_t)1000;
idx.b_key = *pi_ref1 == -1 ? VLC_TRUE : VLC_FALSE;
}
#undef idx
return VLC_SUCCESS;
}
EbmlParser *ep;
matroska_segment_t *p_segment1 = new matroska_segment_t( *this, *p_estream );
b_keep_segment = false;
if( el == NULL )
{
if( ep->GetLevel() > 1 )
{
ep->Up();
continue;
}
msg_Warn( &sys.demuxer, "EOF" );
return VLC_EGENERIC;
}
ep = new EbmlParser(p_estream, p_l0);
p_segment1->ep = ep;
p_segment1->segment = (KaxSegment*)p_l0;
/* do parsing */
if( i_level == 1 )
while ((p_l1 = ep->Get()))
{
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 */
if( i_index == 0 ||
( i_index > 0 && index[i_index - 1].i_position < (int64_t)cluster->GetElementPosition() ) )
p_info->Read(*p_estream, KaxInfo::ClassInfos.Context, i_upper_lvl, p_l2, true);
for( i = 0; i < p_info->ListSize(); i++ )
{
IndexAppendCluster( cluster );
}
EbmlElement *l = (*p_info)[i];
// reset silent tracks
for (size_t i=0; i<tracks.size(); i++)
if( MKV_IS_ID( l, KaxSegmentUID ) )
{
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) );
}
ep->Down();
else if( MKV_IS_ID( l, KaxPrevUID ) )
{
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" );
return VLC_EGENERIC;
p_segment1->next_segment_uid = *( new KaxNextUID( *static_cast<KaxNextUID*>(l) ) );
}
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 )
{
if( MKV_IS_ID( el, KaxClusterTimecode ) )
{
KaxClusterTimecode &ctc = *(KaxClusterTimecode*)el;
ctc.ReadData( es.I_O(), SCOPE_ALL_DATA );
cluster->InitTimecode( uint64( ctc ), i_timescale );
break;
}
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() );
*pi_duration = uint64( dur );
if ( !b_keep_stream )
{
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( *pi_ref1 == -1 )
if( !strcmp( tk->psz_codec, "V_MS/VFW/FOURCC" ) )
{
*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
{
*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;
track_num.ReadData( es.I_O() );
// find the track
for (size_t i=0; i<tracks.size(); i++)
tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
}
else if( !strncmp( tk->psz_codec, "V_MPEG4", 7 ) )
{
if ( tracks[i]->i_number == uint32(track_num))
if( !strcmp( tk->psz_codec, "V_MPEG4/MS/V3" ) )
{
tracks[i]->b_silent = VLC_TRUE;
break;
tk->fmt.i_codec = VLC_FOURCC( 'D', 'I', 'V', '3' );
}
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 );
return VLC_EGENERIC;
MP4_Box_t *p_box = (MP4_Box_t*)malloc( sizeof( MP4_Box_t ) );
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' );
}
}
static block_t *MemToBlock( demux_t *p_demux, uint8_t *p_mem, int i_mem)
{
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;
}
else
{
WAVEFORMATEX *p_wf = (WAVEFORMATEX*)tk->p_extra_data;
static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
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();
wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &tk->fmt.i_codec, NULL );
size_t i_track;
unsigned int i;
vlc_bool_t b;
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 );
#define tk p_segment->tracks[i_track]
for( i_track = 0; i_track < p_segment->tracks.size(); i_track++ )
{
if( tk->i_number == block->TrackNum() )
tk->fmt.i_extra = GetWLE( &p_wf->cbSize );
if( tk->fmt.i_extra > 0 )
{
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() );
return;
tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
}
if( tk->p_es == NULL )
else if( !strcmp( tk->psz_codec, "A_AC3" ) )
{
msg_Err( p_demux, "unknown track number=%d", block->TrackNum() );
return;
tk->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
}
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', ' ' );
}
es_out_Control( p_demux->out, ES_OUT_GET_ES_STATE, tk->p_es, &b );
if( !b )
else if( !strcmp( tk->psz_codec, "A_FLAC" ) )
{
tk->b_inited = VLC_FALSE;
return;
tk->fmt.i_codec = VLC_FOURCC( 'f', 'l', 'a', 'c' );
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 );
}
/* First send init data */
if( !tk->b_inited && tk->i_data_init > 0 )
else if( !strcmp( tk->psz_codec, "A_VORBIS" ) )
{
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 );
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;
tk->fmt.i_codec = VLC_FOURCC( 'v', 'o', 'r', 'b' );
/* 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;
DataBuffer &data = block->GetBuffer(i);
p_block = MemToBlock( p_demux, data.Buffer(), data.Size() );
if( p_block == NULL )
i_size[i] = 0;
while( i_offset < tk->i_extra_data )
{
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
if( tk->fmt.i_cat != VIDEO_ES )
i_size[0] = __MIN(i_size[0], tk->i_extra_data - i_offset);
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 );
/* use time stamp only for first block */
i_pts = 0;
else if( !strcmp( &tk->psz_codec[12], "LC" ) )
{
i_profile = 1;
}
#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)
else if( !strcmp( &tk->psz_codec[12], "SSR" ) )
{
return NULL;
i_profile = 2;
}
p_l0->SkipData(*p_estream, EbmlHead_Context);
delete p_l0;
// find all segments in this file
p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
if (p_l0 == NULL)
else
{
return NULL;
i_profile = 3;
}
matroska_stream_t *p_stream1 = new matroska_stream_t( *this );
while (p_l0 != 0)
for( i_srate = 0; i_srate < 13; i_srate++ )
{
if (EbmlId(*p_l0) == KaxSegment::ClassInfos.GlobalId)
if( i_sample_rates[i_srate] == tk->fmt.audio.i_rate )
{
EbmlParser *ep;
matroska_segment_t *p_segment1 = new matroska_segment_t( *this, *p_estream );
b_keep_segment = false;
ep = new EbmlParser(p_estream, p_l0);
p_segment1->ep = ep;
p_segment1->segment = (KaxSegment*)p_l0;
break;
}
}
msg_Dbg( &sys.demuxer, "profile=%d srate=%d", i_profile, i_srate );
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
KaxInfo *p_info = static_cast<KaxInfo*>(p_l1);
p_info->Read(*p_estream, KaxInfo::ClassInfos.Context, i_upper_lvl, p_l2, true);
for( i = 0; i < p_info->ListSize(); i++ )
tk->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
}
else
{
EbmlElement *l = (*p_info)[i];
if( MKV_IS_ID( l, KaxSegmentUID ) )
tk->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
}
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);
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) );
/* FIXME: support this codec */
msg_Err( &sys.demuxer, "TTA 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, 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) );
std::vector<KaxSegmentFamily>::iterator iter;
p_segment1->families.push_back( *p_fam );
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" ) )
{
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;
p_stream1->segments.push_back( p_segment1 );
/* FIXME: support this codec */
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
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);
p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
tk->p_es = es_out_Add( sys.demuxer.out, &tk->fmt );
#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;
p_stream1 = NULL;
#define tk tracks[i_track]
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 )
......@@ -1767,8 +1797,13 @@ static int Demux( demux_t *p_demux)
/* nothing left to read in this ordered edition */
if ( p_stream->i_current_segment == p_stream->segments.size() - 1)
return 0;
p_segment->UnSelect( );
/* switch to the next segment (TODO update the duration) */
p_stream->i_current_segment++;
p_segment = p_stream->Segment();
if ( !p_segment || !p_segment->Select( ) )
return 0;
continue;
}
......@@ -3441,7 +3476,7 @@ bool matroska_segment_t::Preload( )
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;
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
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++)
{
......
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