[vlc-devel] [PATCH 5/5] mkv: use EbmlTypeDispatcher in matroska_segment_c::BlockGet
Filip Roséen
filip at videolabs.io
Tue Mar 8 15:11:57 CET 2016
---
modules/demux/mkv/matroska_segment.cpp | 305 +++++++++++++++++++--------------
1 file changed, 179 insertions(+), 126 deletions(-)
diff --git a/modules/demux/mkv/matroska_segment.cpp b/modules/demux/mkv/matroska_segment.cpp
index c64fdbf..ca72176 100644
--- a/modules/demux/mkv/matroska_segment.cpp
+++ b/modules/demux/mkv/matroska_segment.cpp
@@ -27,6 +27,7 @@
#include "demux.hpp"
#include "util.hpp"
#include "Ebml_parser.hpp"
+#include "Ebml_dispatcher.hpp"
#include <new>
@@ -1297,6 +1298,154 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s
size_t i_tk;
*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();
+
+ for ( size_t i = 0; i < vars.obj->tracks.size(); ++i)
+ {
+ vars.obj->tracks[i]->b_silent = false;
+ }
+
+ 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 )
+ {
+ kstrackn.ReadData( vars.obj->es.I_O() );
+
+ std::vector<mkv_track_t*> const& tracks = vars.obj->tracks;
+ uint32 i_number = static_cast<uint32> ( kstrackn );
+
+ for (size_t i = 0; i < tracks.size(); ++i )
+ {
+ if( tracks[i]->i_number == i_number )
+ {
+ tracks[i]->b_silent = true;
+ break;
+ }
+ }
+ }
+#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;
@@ -1323,24 +1472,19 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s
/* We have block group let's check if the picture is a keyframe */
else if( *pb_key_picture )
{
- switch(tracks[i_tk]->fmt.i_codec)
+ if( tracks[i_tk]->fmt.i_codec == VLC_CODEC_THEORA )
{
- case VLC_CODEC_THEORA:
- {
- DataBuffer *p_data = &pp_block->GetBuffer(0);
- size_t sz = p_data->Size();
- const uint8_t * p_buff = p_data->Buffer();
- /* if the second bit of a Theora frame is 1
- it's not a keyframe */
- if( sz && p_buff )
- {
- if( p_buff[0] & 0x40 )
- *pb_key_picture = false;
- }
- else
- *pb_key_picture = false;
- break;
- }
+ 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;
}
}
@@ -1388,134 +1532,43 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, KaxSimpleBlock * & pp_s
}
/* do parsing */
- try
- {
- switch ( i_level )
- {
- case 1:
- if( MKV_CHECKED_PTR_DECL ( kc_ptr, KaxCluster, el ) )
- {
- cluster = kc_ptr;
- i_cluster_pos = cluster->GetElementPosition();
-
- // reset silent tracks
- for (size_t i=0; i<tracks.size(); i++)
- {
- tracks[i]->b_silent = false;
- }
- ep->Down();
- }
- else if( MKV_IS_ID( el, KaxCues ) )
- {
- msg_Warn( &sys.demuxer, "find KaxCues FIXME" );
- return VLC_EGENERIC;
- }
- else
- {
- msg_Dbg( &sys.demuxer, "unknown (%s)", typeid( el ).name() );
- }
- break;
+ try {
+ switch( i_level )
+ {
case 2:
- 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();
- break;
- }
- if( MKV_CHECKED_PTR_DECL ( kct_ptr, KaxClusterTimecode, el ) )
- {
- kct_ptr->ReadData( es.I_O(), SCOPE_ALL_DATA );
- cluster->InitTimecode( static_cast<uint64>( *kct_ptr ), i_timescale );
-
- /* add it to the index */
- if( index_idx() == 0 ||
- ( prev_index().i_position < static_cast<int64_t>( cluster->GetElementPosition() ) ) )
- {
- IndexAppendCluster( cluster );
- }
- }
- else if( MKV_IS_ID( el, KaxClusterSilentTracks ) )
- {
- ep->Down();
- }
- else if( MKV_IS_ID( el, KaxBlockGroup ) )
- {
- i_block_pos = el->GetElementPosition();
- ep->Down();
- }
- else if( MKV_CHECKED_PTR_DECL ( ksb_ptr, KaxSimpleBlock, el ) )
- {
- pp_simpleblock = ksb_ptr;
- pp_simpleblock->ReadData( es.I_O() );
- pp_simpleblock->SetParent( *cluster );
- }
- break;
case 3:
- if( unlikely( !el->ValidateSize() ||
- ( el->IsFiniteSize() && el->GetSize() >= SIZE_MAX ) ) )
+ 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;
- }
- if( MKV_CHECKED_PTR_DECL ( kb_ptr, KaxBlock, el ) )
- {
- pp_block = kb_ptr;
-
- pp_block->ReadData( es.I_O() );
- pp_block->SetParent( *cluster );
- ep->Keep();
- }
- else if( MKV_CHECKED_PTR_DECL ( kbd_ptr, KaxBlockDuration, el ) )
- {
- kbd_ptr->ReadData( es.I_O() );
- *pi_duration = static_cast<uint64>( *kbd_ptr );
- }
- else if( MKV_CHECKED_PTR_DECL ( krb_ptr, KaxReferenceBlock, el ) )
- {
- krb_ptr->ReadData( es.I_O() );
-
- if( *pb_key_picture )
- *pb_key_picture = false;
- else if( int64( *krb_ptr ) > 0 )
- *pb_discardable_picture = true;
- }
- else if( MKV_CHECKED_PTR_DECL ( kcstn_ptr, KaxClusterSilentTrackNumber, el ) )
- {
- kcstn_ptr->ReadData( es.I_O() );
- // find the track
- for (size_t i=0; i<tracks.size(); i++)
- {
- if ( tracks[i]->i_number == static_cast<uint32>( *kcstn_ptr ) )
- {
- tracks[i]->b_silent = true;
- break;
- }
- }
+ break;
}
-#if LIBMATROSKA_VERSION >= 0x010401
- else if( MKV_CHECKED_PTR_DECL ( kdp_ptr, KaxDiscardPadding, el ) )
+ case 1:
{
- kdp_ptr->ReadData( es.I_O() );
- if ( *pi_duration < static_cast<int64>( *kdp_ptr ) )
- *pi_duration = 0;
- else
- *pi_duration -= static_cast<int64>( *kdp_ptr );
+ EbmlTypeDispatcher const * dispatcher = dispatchers[i_level - 1];
+ dispatcher->send( el, BlockGetHandler_l1::Payload( payload ) );
}
-#endif
break;
+
default:
msg_Err( &sys.demuxer, "invalid level = %d", i_level );
return VLC_EGENERIC;
}
}
- catch(...)
+ catch (int ret_code)
+ {
+ return ret_code;
+ }
+ catch (...)
{
msg_Err( &sys.demuxer, "Error while reading %s... upping level", typeid(*el).name());
ep->Up();
--
2.7.2
More information about the vlc-devel
mailing list