[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