You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1249 lines
40 KiB
1249 lines
40 KiB
/*****************************************************************************
|
|
* matroska_segment.cpp : matroska demuxer
|
|
*****************************************************************************
|
|
* Copyright (C) 2003-2010 VLC authors and VideoLAN
|
|
* $Id$
|
|
*
|
|
* Authors: Laurent Aimar <fenrir@via.ecp.fr>
|
|
* Steve Lhomme <steve.lhomme@free.fr>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation; either version 2.1 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
|
|
*****************************************************************************/
|
|
|
|
#include "matroska_segment.hpp"
|
|
#include "chapters.hpp"
|
|
#include "demux.hpp"
|
|
#include "util.hpp"
|
|
#include "Ebml_parser.hpp"
|
|
#include "Ebml_dispatcher.hpp"
|
|
|
|
#include <new>
|
|
|
|
matroska_segment_c::matroska_segment_c( demux_sys_t & demuxer, EbmlStream & estream )
|
|
:segment(NULL)
|
|
,es(estream)
|
|
,i_timescale(MKVD_TIMECODESCALE)
|
|
,i_duration(-1)
|
|
,i_mk_start_time(0)
|
|
,i_seekhead_count(0)
|
|
,i_seekhead_position(-1)
|
|
,i_cues_position(-1)
|
|
,i_tracks_position(-1)
|
|
,i_info_position(-1)
|
|
,i_chapters_position(-1)
|
|
,i_attachments_position(-1)
|
|
,cluster(NULL)
|
|
,i_block_pos(0)
|
|
,i_cluster_pos(0)
|
|
,p_segment_uid(NULL)
|
|
,p_prev_segment_uid(NULL)
|
|
,p_next_segment_uid(NULL)
|
|
,b_cues(false)
|
|
,psz_muxing_application(NULL)
|
|
,psz_writing_application(NULL)
|
|
,psz_segment_filename(NULL)
|
|
,psz_title(NULL)
|
|
,psz_date_utc(NULL)
|
|
,i_default_edition(0)
|
|
,sys(demuxer)
|
|
,ep(NULL)
|
|
,b_preloaded(false)
|
|
,b_ref_external_segments(false)
|
|
{
|
|
}
|
|
|
|
matroska_segment_c::~matroska_segment_c()
|
|
{
|
|
for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it)
|
|
{
|
|
tracks_map_t::mapped_type& track = it->second;
|
|
|
|
es_format_Clean( &track.fmt );
|
|
delete track.p_compression_data;
|
|
delete track.p_sys;
|
|
free( track.p_extra_data );
|
|
}
|
|
|
|
free( psz_writing_application );
|
|
free( psz_muxing_application );
|
|
free( psz_segment_filename );
|
|
free( psz_title );
|
|
free( psz_date_utc );
|
|
|
|
delete ep;
|
|
delete segment;
|
|
delete p_segment_uid;
|
|
delete p_prev_segment_uid;
|
|
delete p_next_segment_uid;
|
|
|
|
vlc_delete_all( stored_editions );
|
|
vlc_delete_all( translations );
|
|
vlc_delete_all( families );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* Tools *
|
|
*****************************************************************************
|
|
* * LoadCues : load the cues element and update index
|
|
* * LoadTags : load ... the tags element
|
|
* * InformationCreate : create all information, load tags if present
|
|
*****************************************************************************/
|
|
void matroska_segment_c::LoadCues( KaxCues *cues )
|
|
{
|
|
bool b_invalid_cue;
|
|
EbmlElement *el;
|
|
|
|
if( b_cues )
|
|
{
|
|
msg_Err( &sys.demuxer, "There can be only 1 Cues per section." );
|
|
return;
|
|
}
|
|
|
|
EbmlParser eparser (&es, cues, &sys.demuxer, var_InheritBool( &sys.demuxer, "mkv-use-dummy" ) );
|
|
while( ( el = eparser.Get() ) != NULL )
|
|
{
|
|
if( MKV_IS_ID( el, KaxCuePoint ) )
|
|
{
|
|
b_invalid_cue = false;
|
|
|
|
eparser.Down();
|
|
while( ( el = eparser.Get() ) != NULL )
|
|
{
|
|
if ( MKV_CHECKED_PTR_DECL( kct_ptr, KaxCueTime, el ) )
|
|
{
|
|
try
|
|
{
|
|
if( unlikely( !kct_ptr->ValidateSize() ) )
|
|
{
|
|
msg_Err( &sys.demuxer, "CueTime size too big");
|
|
b_invalid_cue = true;
|
|
break;
|
|
}
|
|
kct_ptr->ReadData( es.I_O() );
|
|
}
|
|
catch(...)
|
|
{
|
|
msg_Err( &sys.demuxer, "Error while reading CueTime" );
|
|
b_invalid_cue = true;
|
|
break;
|
|
}
|
|
}
|
|
else if( MKV_IS_ID( el, KaxCueTrackPositions ) )
|
|
{
|
|
eparser.Down();
|
|
try
|
|
{
|
|
while( ( el = eparser.Get() ) != NULL )
|
|
{
|
|
if( unlikely( !el->ValidateSize() ) )
|
|
{
|
|
eparser.Up();
|
|
msg_Err( &sys.demuxer, "Error %s too big, aborting", typeid(*el).name() );
|
|
b_invalid_cue = true;
|
|
break;
|
|
}
|
|
|
|
if( MKV_CHECKED_PTR_DECL ( kct_ptr, KaxCueTrack, el ) )
|
|
{
|
|
kct_ptr->ReadData( es.I_O() );
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kccp_ptr, KaxCueClusterPosition, el ) )
|
|
{
|
|
kccp_ptr->ReadData( es.I_O() );
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kcbn_ptr, KaxCueBlockNumber, el ) )
|
|
{
|
|
kcbn_ptr->ReadData( es.I_O() );
|
|
}
|
|
#if LIBMATROSKA_VERSION >= 0x010401
|
|
else if( MKV_IS_ID( el, KaxCueRelativePosition ) )
|
|
{
|
|
/* For future use */
|
|
}
|
|
else if( MKV_IS_ID( el, KaxCueDuration ) )
|
|
{
|
|
/* For future use */
|
|
}
|
|
#endif
|
|
else
|
|
{
|
|
msg_Dbg( &sys.demuxer, " * Unknown (%s)", typeid(*el).name() );
|
|
}
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
eparser.Up();
|
|
msg_Err( &sys.demuxer, "Error while reading %s", typeid(*el).name() );
|
|
b_invalid_cue = true;
|
|
break;
|
|
}
|
|
eparser.Up();
|
|
}
|
|
else
|
|
{
|
|
msg_Dbg( &sys.demuxer, " * Unknown (%s)", typeid(*el).name() );
|
|
}
|
|
}
|
|
eparser.Up();
|
|
|
|
}
|
|
else
|
|
{
|
|
msg_Dbg( &sys.demuxer, " * Unknown (%s)", typeid(*el).name() );
|
|
}
|
|
}
|
|
b_cues = true;
|
|
msg_Dbg( &sys.demuxer, "| - loading cues done." );
|
|
}
|
|
|
|
|
|
static const struct {
|
|
vlc_meta_type_t type;
|
|
const char *key;
|
|
int target_type; /* 0 is valid for all target_type */
|
|
} metadata_map[] = {
|
|
{vlc_meta_Album, "TITLE", 50},
|
|
{vlc_meta_Title, "TITLE", 0},
|
|
{vlc_meta_Artist, "ARTIST", 0},
|
|
{vlc_meta_Genre, "GENRE", 0},
|
|
{vlc_meta_Copyright, "COPYRIGHT", 0},
|
|
{vlc_meta_TrackNumber, "PART_NUMBER", 0},
|
|
{vlc_meta_Description, "DESCRIPTION", 0},
|
|
{vlc_meta_Description, "COMMENT", 0},
|
|
{vlc_meta_Rating, "RATING", 0},
|
|
{vlc_meta_Date, "DATE_RELEASED", 0},
|
|
{vlc_meta_Date, "DATE_RELEASE", 0},
|
|
{vlc_meta_Date, "DATE_RECORDED", 0},
|
|
{vlc_meta_URL, "URL", 0},
|
|
{vlc_meta_Publisher, "PUBLISHER", 0},
|
|
{vlc_meta_EncodedBy, "ENCODED_BY", 0},
|
|
{vlc_meta_TrackTotal, "TOTAL_PARTS", 0},
|
|
{vlc_meta_Album, "ALBUM", 0},
|
|
{vlc_meta_Title, NULL, 0},
|
|
};
|
|
|
|
bool matroska_segment_c::ParseSimpleTags( SimpleTag* pout_simple, KaxTagSimple *tag, int target_type )
|
|
{
|
|
EbmlParser eparser ( &es, tag, &sys.demuxer, var_InheritBool( &sys.demuxer, "mkv-use-dummy" ) );
|
|
EbmlElement *el;
|
|
size_t max_size = tag->GetSize();
|
|
size_t size = 0;
|
|
|
|
if( !sys.meta )
|
|
sys.meta = vlc_meta_New();
|
|
|
|
msg_Dbg( &sys.demuxer, "| + Simple Tag ");
|
|
try
|
|
{
|
|
while( ( el = eparser.Get() ) != NULL && size < max_size)
|
|
{
|
|
if( unlikely( !el->ValidateSize() ) )
|
|
{
|
|
msg_Err( &sys.demuxer, "Error %s too big ignoring the tag", typeid(*el).name() );
|
|
delete ep;
|
|
return false;
|
|
}
|
|
if( MKV_CHECKED_PTR_DECL ( ktn_ptr, KaxTagName, el ) )
|
|
{
|
|
ktn_ptr->ReadData( es.I_O(), SCOPE_ALL_DATA );
|
|
pout_simple->tag_name = UTFstring( *ktn_ptr ).GetUTF8().c_str();
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kts_ptr, KaxTagString, el ) )
|
|
{
|
|
kts_ptr->ReadData( es.I_O(), SCOPE_ALL_DATA );
|
|
pout_simple->value = UTFstring( *kts_ptr ).GetUTF8().c_str();
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( ktl_ptr, KaxTagLangue, el ) )
|
|
{
|
|
ktl_ptr->ReadData( es.I_O(), SCOPE_ALL_DATA );
|
|
pout_simple->lang = *ktl_ptr;
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( ktd_ptr, KaxTagDefault, el ) )
|
|
{
|
|
VLC_UNUSED(ktd_ptr); // TODO: we do not care about this value, but maybe we should?
|
|
}
|
|
/*Tags can be nested*/
|
|
else if( MKV_CHECKED_PTR_DECL ( kts_ptr, KaxTagSimple, el) )
|
|
{
|
|
SimpleTag st; // ParseSimpleTags will write to this variable
|
|
// the SimpleTag is valid if ParseSimpleTags returns `true`
|
|
|
|
if (ParseSimpleTags( &st, kts_ptr, target_type )) {
|
|
pout_simple->sub_tags.push_back( st );
|
|
}
|
|
}
|
|
/*TODO Handle binary tags*/
|
|
size += el->HeadSize() + el->GetSize();
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
msg_Err( &sys.demuxer, "Error while reading Tag ");
|
|
delete ep;
|
|
return false;
|
|
}
|
|
|
|
if( pout_simple->tag_name.empty() )
|
|
{
|
|
msg_Warn( &sys.demuxer, "Invalid MKV SimpleTag found.");
|
|
return false;
|
|
}
|
|
for( int i = 0; metadata_map[i].key; i++ )
|
|
{
|
|
if( pout_simple->tag_name == metadata_map[i].key &&
|
|
(metadata_map[i].target_type == 0 || target_type == metadata_map[i].target_type ) )
|
|
{
|
|
vlc_meta_Set( sys.meta, metadata_map[i].type, pout_simple->value.c_str () );
|
|
msg_Dbg( &sys.demuxer, "| | + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
|
|
goto done;
|
|
}
|
|
}
|
|
msg_Dbg( &sys.demuxer, "| | + Meta %s: %s", pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
|
|
vlc_meta_AddExtra( sys.meta, pout_simple->tag_name.c_str (), pout_simple->value.c_str ());
|
|
done:
|
|
return true;
|
|
}
|
|
|
|
void matroska_segment_c::LoadTags( KaxTags *tags )
|
|
{
|
|
/* Master elements */
|
|
EbmlParser eparser = EbmlParser( &es, tags, &sys.demuxer, true );
|
|
EbmlElement *el;
|
|
|
|
while( ( el = eparser.Get() ) != NULL )
|
|
{
|
|
if( MKV_IS_ID( el, KaxTag ) )
|
|
{
|
|
Tag tag;
|
|
|
|
msg_Dbg( &sys.demuxer, "+ Tag" );
|
|
eparser.Down();
|
|
int target_type = 50;
|
|
while( ( el = eparser.Get() ) != NULL )
|
|
{
|
|
if( MKV_IS_ID( el, KaxTagTargets ) )
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + Targets" );
|
|
eparser.Down();
|
|
while( ( el = eparser.Get() ) != NULL )
|
|
{
|
|
try
|
|
{
|
|
if( unlikely( !el->ValidateSize() ) )
|
|
{
|
|
msg_Err( &sys.demuxer, "Invalid size while reading tag");
|
|
break;
|
|
}
|
|
if( MKV_CHECKED_PTR_DECL ( ktttv_ptr, KaxTagTargetTypeValue, el ) )
|
|
{
|
|
ktttv_ptr->ReadData( es.I_O() );
|
|
|
|
msg_Dbg( &sys.demuxer, "| | + TargetTypeValue: %u", uint32(*ktttv_ptr));
|
|
target_type = static_cast<uint32>( *ktttv_ptr );
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kttu_ptr, KaxTagTrackUID, el ) )
|
|
{
|
|
tag.i_tag_type = TRACK_UID;
|
|
kttu_ptr->ReadData( es.I_O() );
|
|
tag.i_uid = static_cast<uint64>( *kttu_ptr );
|
|
msg_Dbg( &sys.demuxer, "| | + TrackUID: %" PRIu64, tag.i_uid);
|
|
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kteu_ptr, KaxTagEditionUID, el ) )
|
|
{
|
|
tag.i_tag_type = EDITION_UID;
|
|
kteu_ptr->ReadData( es.I_O() );
|
|
tag.i_uid = static_cast<uint64>( *kteu_ptr );
|
|
msg_Dbg( &sys.demuxer, "| | + EditionUID: %" PRIu64, tag.i_uid);
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( ktcu_ptr, KaxTagChapterUID, el ) )
|
|
{
|
|
tag.i_tag_type = CHAPTER_UID;
|
|
ktcu_ptr->ReadData( es.I_O() );
|
|
tag.i_uid = static_cast<uint64>( *ktcu_ptr );
|
|
msg_Dbg( &sys.demuxer, "| | + ChapterUID: %" PRIu64, tag.i_uid);
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( ktau_ptr, KaxTagAttachmentUID, el ) )
|
|
{
|
|
tag.i_tag_type = ATTACHMENT_UID;
|
|
ktau_ptr->ReadData( es.I_O() );
|
|
tag.i_uid = static_cast<uint64>( *ktau_ptr );
|
|
msg_Dbg( &sys.demuxer, "| | + AttachmentUID: %" PRIu64, tag.i_uid);
|
|
}
|
|
else
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| | + LoadTag Unknown (%s)", typeid( *el ).name() );
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
msg_Err( &sys.demuxer, "Error while reading tag");
|
|
break;
|
|
}
|
|
}
|
|
eparser.Up();
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kts_ptr, KaxTagSimple, el ) )
|
|
{
|
|
SimpleTag simple;
|
|
|
|
if (ParseSimpleTags(&simple, kts_ptr, target_type )) {
|
|
tag.simple_tags.push_back( simple );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + LoadTag Unknown (%s)", typeid( *el ).name() );
|
|
}
|
|
}
|
|
eparser.Up();
|
|
this->tags.push_back(tag);
|
|
}
|
|
else
|
|
{
|
|
msg_Dbg( &sys.demuxer, "+ Unknown (%s)", typeid( *el ).name() );
|
|
}
|
|
}
|
|
|
|
msg_Dbg( &sys.demuxer, "loading tags done." );
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* InformationCreate:
|
|
*****************************************************************************/
|
|
void matroska_segment_c::InformationCreate( )
|
|
{
|
|
if( !sys.meta )
|
|
sys.meta = vlc_meta_New();
|
|
|
|
if( psz_title )
|
|
{
|
|
vlc_meta_SetTitle( sys.meta, psz_title );
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
* Misc
|
|
*****************************************************************************/
|
|
|
|
void matroska_segment_c::IndexAppendCluster( KaxCluster *cluster )
|
|
{
|
|
|
|
}
|
|
|
|
bool matroska_segment_c::PreloadClusters(uint64 i_cluster_pos)
|
|
{
|
|
struct ClusterHandlerPayload
|
|
{
|
|
matroska_segment_c * const obj;
|
|
bool stop_parsing;
|
|
|
|
} payload = { this, false };
|
|
|
|
MKV_SWITCH_CREATE(EbmlTypeDispatcher, ClusterHandler, ClusterHandlerPayload )
|
|
{
|
|
MKV_SWITCH_INIT();
|
|
|
|
E_CASE( KaxCluster, kcluster )
|
|
{
|
|
vars.obj->ParseCluster( &kcluster, false );
|
|
vars.obj->IndexAppendCluster( &kcluster );
|
|
}
|
|
|
|
E_CASE_DEFAULT( el )
|
|
{
|
|
VLC_UNUSED( el );
|
|
vars.stop_parsing = true;
|
|
}
|
|
};
|
|
|
|
{
|
|
es.I_O().setFilePointer( i_cluster_pos );
|
|
|
|
while (payload.stop_parsing == false)
|
|
{
|
|
EbmlParser parser ( &es, segment, &sys.demuxer, var_InheritBool( &sys.demuxer, "mkv-use-dummy" ) );
|
|
|
|
ClusterHandler::Dispatcher().send( parser.Get(), ClusterHandler::Payload( payload ) );
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool matroska_segment_c::PreloadFamily( const matroska_segment_c & of_segment )
|
|
{
|
|
if ( b_preloaded )
|
|
return false;
|
|
|
|
if ( SameFamily( of_segment ) )
|
|
return Preload( );
|
|
|
|
return false;
|
|
}
|
|
|
|
bool matroska_segment_c::CompareSegmentUIDs( const matroska_segment_c * p_item_a, const matroska_segment_c * p_item_b )
|
|
{
|
|
EbmlBinary *p_tmp;
|
|
|
|
if ( p_item_a == NULL || p_item_b == NULL )
|
|
return false;
|
|
|
|
p_tmp = static_cast<EbmlBinary *>( p_item_a->p_segment_uid );
|
|
if ( p_item_b->p_prev_segment_uid != NULL
|
|
&& *p_tmp == *p_item_b->p_prev_segment_uid )
|
|
return true;
|
|
|
|
p_tmp = static_cast<EbmlBinary *>( p_item_a->p_next_segment_uid );
|
|
if ( !p_tmp )
|
|
return false;
|
|
|
|
if ( p_item_b->p_segment_uid != NULL
|
|
&& *p_tmp == *p_item_b->p_segment_uid )
|
|
return true;
|
|
|
|
if ( p_item_b->p_prev_segment_uid != NULL
|
|
&& *p_tmp == *p_item_b->p_prev_segment_uid )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool matroska_segment_c::SameFamily( const matroska_segment_c & of_segment ) const
|
|
{
|
|
for (size_t i=0; i<families.size(); i++)
|
|
{
|
|
for (size_t j=0; j<of_segment.families.size(); j++)
|
|
{
|
|
if ( *(families[i]) == *(of_segment.families[j]) )
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool matroska_segment_c::Preload( )
|
|
{
|
|
if ( b_preloaded )
|
|
return false;
|
|
|
|
EbmlElement *el = NULL;
|
|
|
|
ep->Reset( &sys.demuxer );
|
|
|
|
while( ( el = ep->Get() ) != NULL )
|
|
{
|
|
if( MKV_IS_ID( el, KaxSeekHead ) )
|
|
{
|
|
/* Multiple allowed */
|
|
/* We bail at 10, to prevent possible recursion */
|
|
msg_Dbg( &sys.demuxer, "| + Seek head" );
|
|
if( i_seekhead_count < 10 )
|
|
{
|
|
i_seekhead_position = el->GetElementPosition();
|
|
ParseSeekHead( static_cast<KaxSeekHead*>( el ) );
|
|
}
|
|
}
|
|
else if( MKV_IS_ID( el, KaxInfo ) )
|
|
{
|
|
/* Multiple allowed, mandatory */
|
|
msg_Dbg( &sys.demuxer, "| + Information" );
|
|
if( i_info_position < 0 )
|
|
{
|
|
ParseInfo( static_cast<KaxInfo*>( el ) );
|
|
i_info_position = el->GetElementPosition();
|
|
}
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTracks, el ) )
|
|
{
|
|
/* Multiple allowed */
|
|
msg_Dbg( &sys.demuxer, "| + Tracks" );
|
|
if( i_tracks_position < 0 )
|
|
{
|
|
ParseTracks( kt_ptr );
|
|
}
|
|
if ( tracks.size() == 0 )
|
|
{
|
|
msg_Err( &sys.demuxer, "No tracks supported" );
|
|
return false;
|
|
}
|
|
i_tracks_position = el->GetElementPosition();
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kc_ptr, KaxCues, el ) )
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + Cues" );
|
|
if( i_cues_position < 0 )
|
|
{
|
|
LoadCues( kc_ptr );
|
|
i_cues_position = el->GetElementPosition();
|
|
}
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kc_ptr, KaxCluster, el ) )
|
|
{
|
|
if( var_InheritBool( &sys.demuxer, "mkv-preload-clusters" ) )
|
|
{
|
|
PreloadClusters ( kc_ptr->GetElementPosition() );
|
|
es.I_O().setFilePointer( kc_ptr->GetElementPosition() );
|
|
}
|
|
msg_Dbg( &sys.demuxer, "| + Cluster" );
|
|
|
|
cluster = kc_ptr;
|
|
|
|
i_cluster_pos = cluster->GetElementPosition();
|
|
ParseCluster( cluster );
|
|
IndexAppendCluster( cluster );
|
|
|
|
ep->Down();
|
|
/* stop pre-parsing the stream */
|
|
break;
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( ka_ptr, KaxAttachments, el ) )
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + Attachments" );
|
|
if( i_attachments_position < 0 )
|
|
{
|
|
ParseAttachments( ka_ptr );
|
|
i_attachments_position = el->GetElementPosition();
|
|
}
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kc_ptr, KaxChapters, el ) )
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + Chapters" );
|
|
if( i_chapters_position < 0 )
|
|
{
|
|
ParseChapters( kc_ptr );
|
|
i_chapters_position = el->GetElementPosition();
|
|
}
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTags, el ) )
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + Tags" );
|
|
if(tags.empty ())
|
|
{
|
|
LoadTags( kt_ptr );
|
|
}
|
|
}
|
|
else if( MKV_IS_ID ( el, EbmlVoid ) )
|
|
msg_Dbg( &sys.demuxer, "| + Void" );
|
|
else
|
|
msg_Dbg( &sys.demuxer, "| + Preload Unknown (%s)", typeid(*el).name() );
|
|
}
|
|
|
|
ComputeTrackPriority();
|
|
|
|
b_preloaded = true;
|
|
|
|
EnsureDuration();
|
|
|
|
return true;
|
|
}
|
|
|
|
/* Here we try to load elements that were found in Seek Heads, but not yet parsed */
|
|
bool matroska_segment_c::LoadSeekHeadItem( const EbmlCallbacks & ClassInfos, int64_t i_element_position )
|
|
{
|
|
int64_t i_sav_position = static_cast<int64_t>( es.I_O().getFilePointer() );
|
|
EbmlElement *el;
|
|
|
|
es.I_O().setFilePointer( i_element_position, seek_beginning );
|
|
el = es.FindNextID( ClassInfos, 0xFFFFFFFFL);
|
|
|
|
if( el == NULL )
|
|
{
|
|
msg_Err( &sys.demuxer, "cannot load some cues/chapters/tags etc. (broken seekhead or file)" );
|
|
es.I_O().setFilePointer( i_sav_position, seek_beginning );
|
|
return false;
|
|
}
|
|
|
|
if( MKV_CHECKED_PTR_DECL ( ksh_ptr, KaxSeekHead, el ) )
|
|
{
|
|
/* Multiple allowed */
|
|
msg_Dbg( &sys.demuxer, "| + Seek head" );
|
|
if( i_seekhead_count < 10 )
|
|
{
|
|
if ( i_seekhead_position != i_element_position )
|
|
{
|
|
i_seekhead_position = i_element_position;
|
|
ParseSeekHead( ksh_ptr );
|
|
}
|
|
}
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( ki_ptr, KaxInfo, el ) ) // FIXME
|
|
{
|
|
/* Multiple allowed, mandatory */
|
|
msg_Dbg( &sys.demuxer, "| + Information" );
|
|
if( i_info_position < 0 )
|
|
{
|
|
ParseInfo( ki_ptr );
|
|
i_info_position = i_element_position;
|
|
}
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTracks, el ) ) // FIXME
|
|
{
|
|
/* Multiple allowed */
|
|
msg_Dbg( &sys.demuxer, "| + Tracks" );
|
|
if( i_tracks_position < 0 )
|
|
ParseTracks( kt_ptr );
|
|
if ( tracks.size() == 0 )
|
|
{
|
|
msg_Err( &sys.demuxer, "No tracks supported" );
|
|
delete el;
|
|
es.I_O().setFilePointer( i_sav_position, seek_beginning );
|
|
return false;
|
|
}
|
|
i_tracks_position = i_element_position;
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kc_ptr, KaxCues, el ) )
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + Cues" );
|
|
if( i_cues_position < 0 )
|
|
{
|
|
LoadCues( kc_ptr );
|
|
i_cues_position = i_element_position;
|
|
}
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( ka_ptr, KaxAttachments, el ) )
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + Attachments" );
|
|
if( i_attachments_position < 0 )
|
|
{
|
|
ParseAttachments( ka_ptr );
|
|
i_attachments_position = i_element_position;
|
|
}
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kc_ptr, KaxChapters, el ) )
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + Chapters" );
|
|
if( i_chapters_position < 0 )
|
|
{
|
|
ParseChapters( kc_ptr );
|
|
i_chapters_position = i_element_position;
|
|
}
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kt_ptr, KaxTags, el ) )
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + Tags" );
|
|
if(tags.empty ())
|
|
{
|
|
LoadTags( kt_ptr );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
msg_Dbg( &sys.demuxer, "| + LoadSeekHeadItem Unknown (%s)", typeid(*el).name() );
|
|
}
|
|
delete el;
|
|
|
|
es.I_O().setFilePointer( i_sav_position, seek_beginning );
|
|
return true;
|
|
}
|
|
|
|
void matroska_segment_c::Seek( mtime_t i_mk_date, mtime_t i_mk_time_offset )
|
|
{
|
|
// TODO: implement
|
|
}
|
|
|
|
|
|
int matroska_segment_c::FindTrackByBlock(tracks_map_t::iterator* p_track_it,
|
|
const KaxBlock *p_block, const KaxSimpleBlock *p_simpleblock )
|
|
{
|
|
*p_track_it = tracks.end();
|
|
|
|
if( p_block == NULL && p_simpleblock == NULL )
|
|
return VLC_EGENERIC;
|
|
|
|
if (p_block != NULL)
|
|
{
|
|
*p_track_it = tracks.find( p_block->TrackNum() );
|
|
}
|
|
else if( p_simpleblock != NULL)
|
|
{
|
|
*p_track_it = tracks.find( p_simpleblock->TrackNum() );
|
|
}
|
|
|
|
return *p_track_it != tracks.end() ? VLC_SUCCESS : VLC_EGENERIC;
|
|
}
|
|
|
|
void matroska_segment_c::ComputeTrackPriority()
|
|
{
|
|
bool b_has_default_video = false;
|
|
bool b_has_default_audio = false;
|
|
/* check for default */
|
|
for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
|
|
{
|
|
tracks_map_t::mapped_type& track = it->second;
|
|
|
|
bool flag = track.b_enabled && ( track.b_default || track.b_forced );
|
|
|
|
switch( track.fmt.i_cat )
|
|
{
|
|
case VIDEO_ES: b_has_default_video |= flag; break;
|
|
case AUDIO_ES: b_has_default_audio |= flag; break;
|
|
}
|
|
}
|
|
|
|
for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
|
|
{
|
|
tracks_map_t::key_type track_id = it->first;
|
|
tracks_map_t::mapped_type track = it->second;
|
|
|
|
if( unlikely( track.fmt.i_cat == UNKNOWN_ES || !track.psz_codec ) )
|
|
{
|
|
msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) );
|
|
track.p_es = NULL;
|
|
continue;
|
|
}
|
|
else if( unlikely( !b_has_default_video && track.fmt.i_cat == VIDEO_ES ) )
|
|
{
|
|
track.b_default = true;
|
|
b_has_default_video = true;
|
|
}
|
|
else if( unlikely( !b_has_default_audio && track.fmt.i_cat == AUDIO_ES ) )
|
|
{
|
|
track.b_default = true;
|
|
b_has_default_audio = true;
|
|
}
|
|
if( unlikely( !track.b_enabled ) )
|
|
track.fmt.i_priority = ES_PRIORITY_NOT_SELECTABLE;
|
|
else if( track.b_forced )
|
|
track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 2;
|
|
else if( track.b_default )
|
|
track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN + 1;
|
|
else
|
|
track.fmt.i_priority = ES_PRIORITY_SELECTABLE_MIN;
|
|
|
|
/* Avoid multivideo tracks when unnecessary */
|
|
if( track.fmt.i_cat == VIDEO_ES )
|
|
track.fmt.i_priority--;
|
|
}
|
|
}
|
|
|
|
void matroska_segment_c::EnsureDuration()
|
|
{
|
|
if ( i_duration > 0 )
|
|
return;
|
|
|
|
i_duration = -1;
|
|
|
|
bool b_seekable;
|
|
|
|
stream_Control( sys.demuxer.s, STREAM_CAN_FASTSEEK, &b_seekable );
|
|
if ( !b_seekable )
|
|
{
|
|
msg_Warn( &sys.demuxer, "could not look for the segment duration" );
|
|
return;
|
|
}
|
|
|
|
uint64 i_current_position = es.I_O().getFilePointer();
|
|
uint64 i_last_cluster_pos = 0;
|
|
|
|
// find the last Cluster from the Cues
|
|
{
|
|
}
|
|
|
|
// find the last Cluster manually
|
|
if ( !i_last_cluster_pos && cluster != NULL )
|
|
{
|
|
es.I_O().setFilePointer( cluster->GetElementPosition(), seek_beginning );
|
|
|
|
EbmlElement* el;
|
|
EbmlParser ep( &es, segment, &sys.demuxer,
|
|
var_InheritBool( &sys.demuxer, "mkv-use-dummy" ) );
|
|
|
|
while( ( el = ep.Get() ) != NULL )
|
|
{
|
|
if ( MKV_IS_ID( el, KaxCluster ) )
|
|
{
|
|
i_last_cluster_pos = el->GetElementPosition();
|
|
}
|
|
}
|
|
}
|
|
|
|
// find the last timecode in the Cluster
|
|
if ( i_last_cluster_pos )
|
|
{
|
|
es.I_O().setFilePointer( i_last_cluster_pos, seek_beginning );
|
|
|
|
EbmlParser eparser (
|
|
&es , segment, &sys.demuxer, var_InheritBool( &sys.demuxer, "mkv-use-dummy" ) );
|
|
|
|
KaxCluster *p_last_cluster = static_cast<KaxCluster*>( eparser.Get() );
|
|
if( p_last_cluster == NULL )
|
|
return;
|
|
ParseCluster( p_last_cluster, false, SCOPE_PARTIAL_DATA );
|
|
|
|
// use the last block + duration
|
|
uint64 i_last_timecode = p_last_cluster->GlobalTimecode();
|
|
for( unsigned int i = 0; i < p_last_cluster->ListSize(); i++ )
|
|
{
|
|
EbmlElement *l = (*p_last_cluster)[i];
|
|
|
|
if( MKV_CHECKED_PTR_DECL ( block, KaxSimpleBlock, l ) )
|
|
{
|
|
block->SetParent( *p_last_cluster );
|
|
i_last_timecode = std::max(i_last_timecode, block->GlobalTimecode());
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( group, KaxBlockGroup, l ) )
|
|
{
|
|
uint64 i_group_timecode = 0;
|
|
for( unsigned int j = 0; j < group->ListSize(); j++ )
|
|
{
|
|
EbmlElement *l = (*group)[j];
|
|
|
|
if( MKV_CHECKED_PTR_DECL ( block, KaxBlock, l ) )
|
|
{
|
|
block->SetParent( *p_last_cluster );
|
|
i_group_timecode += block->GlobalTimecode();
|
|
}
|
|
else if( MKV_CHECKED_PTR_DECL ( kbd_ptr, KaxBlockDuration, l ) )
|
|
{
|
|
i_group_timecode += static_cast<uint64>( *kbd_ptr );
|
|
}
|
|
}
|
|
i_last_timecode = std::max(i_last_timecode, i_group_timecode);
|
|
}
|
|
}
|
|
|
|
i_duration = ( i_last_timecode - cluster->GlobalTimecode() ) / INT64_C(1000000);
|
|
msg_Dbg( &sys.demuxer, " extracted Duration=%" PRId64, i_duration );
|
|
}
|
|
|
|
// get back to the reading position we were at before looking for a duration
|
|
es.I_O().setFilePointer( i_current_position, seek_beginning );
|
|
}
|
|
|
|
bool matroska_segment_c::Select( mtime_t i_mk_start_time )
|
|
{
|
|
/* add all es */
|
|
msg_Dbg( &sys.demuxer, "found %d es", static_cast<int>( tracks.size() ) );
|
|
|
|
for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
|
|
{
|
|
tracks_map_t::key_type track_id = it->first;
|
|
tracks_map_t::mapped_type& track = it->second;
|
|
|
|
if( unlikely( track.fmt.i_cat == UNKNOWN_ES || !track.psz_codec ) )
|
|
{
|
|
msg_Warn( &sys.demuxer, "invalid track[%d]", static_cast<int>( track_id ) );
|
|
track.p_es = NULL;
|
|
continue;
|
|
}
|
|
|
|
if( !track.p_es )
|
|
track.p_es = es_out_Add( sys.demuxer.out, &track.fmt );
|
|
|
|
/* Turn on a subtitles track if it has been flagged as default -
|
|
* but only do this if no subtitles track has already been engaged,
|
|
* either by an earlier 'default track' (??) or by default
|
|
* language choice behaviour.
|
|
*/
|
|
if( track.b_default || track.b_forced )
|
|
{
|
|
es_out_Control( sys.demuxer.out, ES_OUT_SET_ES_DEFAULT, track.p_es );
|
|
}
|
|
}
|
|
es_out_Control( sys.demuxer.out, ES_OUT_SET_NEXT_DISPLAY_TIME, i_mk_start_time );
|
|
|
|
sys.i_start_pts = i_mk_start_time + VLC_TS_0;
|
|
// reset the stream reading to the first cluster of the segment used
|
|
es.I_O().setFilePointer( 0 /* previously i_start_pos */ );
|
|
|
|
ep->reconstruct( &es, segment, &sys.demuxer );
|
|
|
|
return true;
|
|
}
|
|
|
|
void matroska_segment_c::UnSelect( )
|
|
{
|
|
sys.p_ev->ResetPci();
|
|
|
|
for( tracks_map_t::iterator it = tracks.begin(); it != tracks.end(); ++it )
|
|
{
|
|
tracks_map_t::mapped_type& track = it->second;
|
|
|
|
if( track.p_es != NULL )
|
|
{
|
|
es_out_Del( sys.demuxer.out, track.p_es );
|
|
track.p_es = NULL;
|
|
}
|
|
}
|
|
|
|
/* TODO: we will leak, fix this!
|
|
delete ep;
|
|
ep = NULL;
|
|
*/
|
|
}
|
|
|
|
int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_simpleblock, bool *pb_key_picture, bool *pb_discardable_picture, int64_t *pi_duration )
|
|
{
|
|
tracks_map_t::iterator track_it;
|
|
|
|
pp_simpleblock = NULL;
|
|
pp_block = NULL;
|
|
|
|
*pb_key_picture = true;
|
|
*pb_discardable_picture = false;
|
|
*pi_duration = 0;
|
|
|
|
struct BlockPayload {
|
|
matroska_segment_c * const obj;
|
|
EbmlParser * const ep;
|
|
demux_t * const p_demuxer;
|
|
KaxBlock *& block;
|
|
KaxSimpleBlock *& simpleblock;
|
|
|
|
int64_t & i_duration;
|
|
bool & b_key_picture;
|
|
bool & b_discardable_picture;
|
|
} payload = {
|
|
this, ep, &sys.demuxer, pp_block, pp_simpleblock,
|
|
*pi_duration, *pb_key_picture, *pb_discardable_picture
|
|
};
|
|
|
|
MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l1, BlockPayload )
|
|
{
|
|
MKV_SWITCH_INIT();
|
|
|
|
E_CASE( KaxCluster, kcluster )
|
|
{
|
|
vars.obj->cluster = &kcluster;
|
|
vars.obj->i_cluster_pos = vars.obj->cluster->GetElementPosition();
|
|
|
|
vars.ep->Down ();
|
|
}
|
|
E_CASE( KaxCues, kcue )
|
|
{
|
|
VLC_UNUSED( kcue );
|
|
msg_Warn( vars.p_demuxer, "find KaxCues FIXME" );
|
|
throw VLC_EGENERIC;
|
|
}
|
|
E_CASE_DEFAULT(element)
|
|
{
|
|
msg_Dbg( vars.p_demuxer, "Unknown (%s)", typeid (element).name () );
|
|
}
|
|
};
|
|
|
|
MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l2, BlockPayload )
|
|
{
|
|
MKV_SWITCH_INIT();
|
|
|
|
E_CASE( KaxClusterTimecode, ktimecode )
|
|
{
|
|
ktimecode.ReadData( vars.obj->es.I_O(), SCOPE_ALL_DATA );
|
|
vars.obj->cluster->InitTimecode( static_cast<uint64>( ktimecode ), vars.obj->i_timescale );
|
|
}
|
|
|
|
E_CASE( KaxClusterSilentTracks, ksilent )
|
|
{
|
|
vars.obj->ep->Down ();
|
|
|
|
VLC_UNUSED( ksilent );
|
|
}
|
|
|
|
E_CASE( KaxBlockGroup, kbgroup )
|
|
{
|
|
vars.obj->i_block_pos = kbgroup.GetElementPosition();
|
|
vars.obj->ep->Down ();
|
|
}
|
|
|
|
E_CASE( KaxSimpleBlock, ksblock )
|
|
{
|
|
vars.simpleblock = &ksblock;
|
|
vars.simpleblock->ReadData( vars.obj->es.I_O() );
|
|
vars.simpleblock->SetParent( *vars.obj->cluster );
|
|
}
|
|
};
|
|
|
|
MKV_SWITCH_CREATE( EbmlTypeDispatcher, BlockGetHandler_l3, BlockPayload )
|
|
{
|
|
MKV_SWITCH_INIT();
|
|
|
|
E_CASE( KaxBlock, kblock )
|
|
{
|
|
vars.block = &kblock;
|
|
vars.block->ReadData( vars.obj->es.I_O() );
|
|
vars.block->SetParent( *vars.obj->cluster );
|
|
|
|
vars.obj->ep->Keep ();
|
|
}
|
|
|
|
E_CASE( KaxBlockDuration, kduration )
|
|
{
|
|
kduration.ReadData( vars.obj->es.I_O() );
|
|
vars.i_duration = static_cast<uint64>( kduration );
|
|
}
|
|
|
|
E_CASE( KaxReferenceBlock, kreference )
|
|
{
|
|
kreference.ReadData( vars.obj->es.I_O() );
|
|
|
|
if( vars.b_key_picture )
|
|
vars.b_key_picture = false;
|
|
else if( static_cast<int64>( kreference ) )
|
|
vars.b_discardable_picture = true;
|
|
}
|
|
E_CASE( KaxClusterSilentTrackNumber, kstrackn )
|
|
{
|
|
VLC_UNUSED( kstrackn );
|
|
VLC_UNUSED( vars );
|
|
}
|
|
#if LIBMATROSKA_VERSION >= 0x010401
|
|
E_CASE( KaxDiscardPadding, kdiscardp )
|
|
{
|
|
kdiscardp.ReadData( vars.obj->es.I_O() );
|
|
int64 i_duration = static_cast<int64>( kdiscardp );
|
|
|
|
if( vars.i_duration < i_duration )
|
|
vars.i_duration = 0;
|
|
else
|
|
vars.i_duration -= i_duration;
|
|
}
|
|
#endif
|
|
|
|
E_CASE_DEFAULT( element )
|
|
{
|
|
VLC_UNUSED(element);
|
|
msg_Err( vars.p_demuxer, "invalid level = %d", vars.obj->ep->GetLevel() );
|
|
throw VLC_EGENERIC;
|
|
}
|
|
};
|
|
|
|
static EbmlTypeDispatcher const * const dispatchers[] = {
|
|
&BlockGetHandler_l1::Dispatcher(),
|
|
&BlockGetHandler_l2::Dispatcher(),
|
|
&BlockGetHandler_l3::Dispatcher()
|
|
};
|
|
|
|
for( ;; )
|
|
{
|
|
EbmlElement *el = NULL;
|
|
int i_level;
|
|
|
|
if ( ep == NULL )
|
|
return VLC_EGENERIC;
|
|
|
|
if( pp_simpleblock != NULL || ((el = ep->Get()) == NULL && pp_block != NULL) )
|
|
{
|
|
/* Check blocks validity to protect againts broken files */
|
|
if( FindTrackByBlock( &track_it, pp_block , pp_simpleblock ) )
|
|
{
|
|
ep->Unkeep();
|
|
pp_simpleblock = NULL;
|
|
pp_block = NULL;
|
|
continue;
|
|
}
|
|
if( pp_simpleblock != NULL )
|
|
{
|
|
*pb_key_picture = pp_simpleblock->IsKeyframe();
|
|
*pb_discardable_picture = pp_simpleblock->IsDiscardable();
|
|
}
|
|
/* We have block group let's check if the picture is a keyframe */
|
|
else if( *pb_key_picture )
|
|
{
|
|
if( track_it->second.fmt.i_codec == VLC_CODEC_THEORA )
|
|
{
|
|
DataBuffer * p_data = &pp_block->GetBuffer(0);
|
|
const uint8_t * p_buff = p_data->Buffer();
|
|
/* if the second bit of a Theora frame is 1
|
|
it's not a keyframe */
|
|
if( p_data->Size() && p_buff )
|
|
{
|
|
if( p_buff[0] & 0x40 )
|
|
*pb_key_picture = false;
|
|
}
|
|
else
|
|
*pb_key_picture = false;
|
|
}
|
|
}
|
|
|
|
return VLC_SUCCESS;
|
|
}
|
|
|
|
i_level = ep->GetLevel();
|
|
|
|
if( el == NULL )
|
|
{
|
|
if( i_level > 1 )
|
|
{
|
|
ep->Up();
|
|
continue;
|
|
}
|
|
msg_Warn( &sys.demuxer, "EOF" );
|
|
return VLC_EGENERIC;
|
|
}
|
|
|
|
/* Verify that we are still inside our cluster
|
|
* It can happens whith broken files and when seeking
|
|
* without index */
|
|
if( i_level > 1 )
|
|
{
|
|
if( cluster && !ep->IsTopPresent( cluster ) )
|
|
{
|
|
msg_Warn( &sys.demuxer, "Unexpected escape from current cluster" );
|
|
cluster = NULL;
|
|
}
|
|
if( !cluster )
|
|
continue;
|
|
}
|
|
|
|
/* do parsing */
|
|
|
|
try {
|
|
switch( i_level )
|
|
{
|
|
case 2:
|
|
case 3:
|
|
if( unlikely( !el->ValidateSize() || ( el->IsFiniteSize() && el->GetSize() >= SIZE_MAX ) ) )
|
|
{
|
|
msg_Err( &sys.demuxer, "Error while reading %s... upping level", typeid(*el).name());
|
|
ep->Up();
|
|
|
|
if ( i_level == 2 )
|
|
break;
|
|
|
|
ep->Unkeep();
|
|
pp_simpleblock = NULL;
|
|
pp_block = NULL;
|
|
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
EbmlTypeDispatcher const * dispatcher = dispatchers[i_level - 1];
|
|
dispatcher->send( el, BlockGetHandler_l1::Payload( payload ) );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
msg_Err( &sys.demuxer, "invalid level = %d", i_level );
|
|
return VLC_EGENERIC;
|
|
}
|
|
}
|
|
catch (int ret_code)
|
|
{
|
|
return ret_code;
|
|
}
|
|
catch (...)
|
|
{
|
|
msg_Err( &sys.demuxer, "Error while reading %s... upping level", typeid(*el).name());
|
|
ep->Up();
|
|
ep->Unkeep();
|
|
pp_simpleblock = NULL;
|
|
pp_block = NULL;
|
|
}
|
|
}
|
|
}
|
|
|