]> git.sesse.net Git - vlc/blobdiff - modules/demux/mkv.cpp
Fix seeking with broken file or without index (close #1687)
[vlc] / modules / demux / mkv.cpp
index c4d399e05ad91589e9bac9b034a8e5499d6abf90..fbb975979162e9c6d563766a91fd6c5ae96ab577 100644 (file)
  * Preamble
  *****************************************************************************/
 
+/* config.h may include inttypes.h, so make sure we define that option
+ * early enough. */
+#define __STDC_FORMAT_MACROS 1
+#define __STDC_CONSTANT_MACROS 1
+
 #ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 
-#define __STDC_FORMAT_MACROS 1
-#define __STDC_CONSTANT_MACROS 1
 #include <inttypes.h>
 
-#include <vlc/vlc.h>
+#include <vlc_common.h>
 #include <vlc_plugin.h>
 
 #ifdef HAVE_TIME_H
@@ -43,7 +46,7 @@
 
 
 #include <vlc_codecs.h>               /* BITMAPINFOHEADER, WAVEFORMATEX */
-#include "iso_lang.h"
+#include <vlc_iso_lang.h>
 #include "vlc_meta.h"
 #include <vlc_charset.h>
 #include <vlc_input.h>
@@ -110,6 +113,46 @@ extern "C" {
 #   include <zlib.h>
 #endif
 
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int  Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+vlc_module_begin();
+    set_shortname( "Matroska" );
+    set_description( N_("Matroska stream demuxer" ) );
+    set_capability( "demux", 50 );
+    set_callbacks( Open, Close );
+    set_category( CAT_INPUT );
+    set_subcategory( SUBCAT_INPUT_DEMUX );
+
+    add_bool( "mkv-use-ordered-chapters", 1, NULL,
+            N_("Ordered chapters"),
+            N_("Play ordered chapters as specified in the segment."), true );
+
+    add_bool( "mkv-use-chapter-codec", 1, NULL,
+            N_("Chapter codecs"),
+            N_("Use chapter codecs found in the segment."), true );
+
+    add_bool( "mkv-preload-local-dir", 1, NULL,
+            N_("Preload Directory"),
+            N_("Preload matroska files from the same family in the same directory (not good for broken files)."), true );
+
+    add_bool( "mkv-seek-percent", 0, NULL,
+            N_("Seek based on percent not time"),
+            N_("Seek based on percent not time."), true );
+
+    add_bool( "mkv-use-dummy", 0, NULL,
+            N_("Dummy Elements"),
+            N_("Read and discard unknown EBML elements (not good for broken files)."), true );
+
+    add_shortcut( "mka" );
+    add_shortcut( "mkv" );
+vlc_module_end();
+
+
+
 #define MATROSKA_COMPRESSION_NONE  -1
 #define MATROSKA_COMPRESSION_ZLIB   0
 #define MATROSKA_COMPRESSION_BLIB   1
@@ -394,44 +437,6 @@ typedef struct {
 using namespace LIBMATROSKA_NAMESPACE;
 using namespace std;
 
-/*****************************************************************************
- * Module descriptor
- *****************************************************************************/
-static int  Open ( vlc_object_t * );
-static void Close( vlc_object_t * );
-
-vlc_module_begin();
-    set_shortname( "Matroska" );
-    set_description( N_("Matroska stream demuxer" ) );
-    set_capability( "demux", 50 );
-    set_callbacks( Open, Close );
-    set_category( CAT_INPUT );
-    set_subcategory( SUBCAT_INPUT_DEMUX );
-
-    add_bool( "mkv-use-ordered-chapters", 1, NULL,
-            N_("Ordered chapters"),
-            N_("Play ordered chapters as specified in the segment."), true );
-
-    add_bool( "mkv-use-chapter-codec", 1, NULL,
-            N_("Chapter codecs"),
-            N_("Use chapter codecs found in the segment."), true );
-
-    add_bool( "mkv-preload-local-dir", 1, NULL,
-            N_("Preload Directory"),
-            N_("Preload matroska files from the same family in the same directory (not good for broken files)."), true );
-
-    add_bool( "mkv-seek-percent", 0, NULL,
-            N_("Seek based on percent not time"),
-            N_("Seek based on percent not time."), true );
-
-    add_bool( "mkv-use-dummy", 0, NULL,
-            N_("Dummy Elements"),
-            N_("Read and discard unknown EBML elements (not good for broken files)."), true );
-
-    add_shortcut( "mka" );
-    add_shortcut( "mkv" );
-vlc_module_end();
-
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -550,7 +555,10 @@ class EbmlParser
     void        Keep( void );
     EbmlElement *UnGet( uint64 i_block_pos, uint64 i_cluster_pos );
 
-    int GetLevel( void );
+    int  GetLevel( void );
+
+    /* Is the provided element presents in our upper elements */
+    bool IsTopPresent( EbmlElement * );
 
   private:
     EbmlStream  *m_es;
@@ -1048,10 +1056,7 @@ public:
     {
         for( size_t i_track = 0; i_track < tracks.size(); i_track++ )
         {
-            if ( tracks[i_track]->p_compression_data )
-            {
-                delete tracks[i_track]->p_compression_data;
-            }
+            delete tracks[i_track]->p_compression_data;
             es_format_Clean( &tracks[i_track]->fmt );
             free( tracks[i_track]->p_extra_data );
             free( tracks[i_track]->psz_codec );
@@ -1683,7 +1688,7 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
             return VLC_SUCCESS;
 
         case DEMUX_GET_TITLE_INFO:
-            if( p_sys->titles.size() )
+            if( p_sys->titles.size() > 1 || ( p_sys->titles.size() == 1 && p_sys->titles[0]->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* );
@@ -1695,7 +1700,6 @@ static int Control( demux_t *p_demux, int i_query, va_list args )
                 {
                     (*ppp_title)[i] = vlc_input_title_Duplicate( p_sys->titles[i] );
                 }
-
                 return VLC_SUCCESS;
             }
             return VLC_EGENERIC;
@@ -1786,6 +1790,20 @@ int matroska_segment_c::BlockGet( KaxBlock * & pp_block, int64_t *pi_ref1, int64
             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 */
         switch ( i_level )
         {
@@ -2551,7 +2569,6 @@ bool matroska_segment_c::Select( mtime_t i_start_time )
             }
             tracks[i_track]->fmt.audio.i_blockalign = ( tracks[i_track]->fmt.audio.i_bitspersample + 7 ) / 8 * tracks[i_track]->fmt.audio.i_channels;
         }
-#if 0
         /* disabled due to the potential "S_KATE" namespace issue */
         else if( !strcmp( tracks[i_track]->psz_codec, "S_KATE" ) )
         {
@@ -2602,7 +2619,6 @@ bool matroska_segment_c::Select( mtime_t i_start_time )
                 i_extra += i_size[i];
             }
         }
-#endif
         else if( !strcmp( tracks[i_track]->psz_codec, "S_TEXT/UTF8" ) )
         {
             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
@@ -2795,7 +2811,7 @@ int demux_sys_t::EventThread( vlc_object_t *p_this )
     var_AddCallback( p_ev->p_libvlc, "key-action", EventKey, p_ev );
 
     /* main loop */
-    while( !p_ev->b_die )
+    while( vlc_object_alive (p_ev) )
     {
         if ( !p_sys->b_pci_packet_set )
         {
@@ -3053,7 +3069,7 @@ int demux_sys_t::EventThread( vlc_object_t *p_this )
         }
 
         /* VOUT part */
-        if( p_vout && p_vout->b_die )
+        if( p_vout && !vlc_object_alive (p_vout) )
         {
             var_DelCallback( p_vout, "mouse-moved", EventMouse, p_ev );
             var_DelCallback( p_vout, "mouse-clicked", EventMouse, p_ev );
@@ -3895,6 +3911,15 @@ EbmlElement *EbmlParser::Get( void )
     return m_el[mi_level];
 }
 
+bool EbmlParser::IsTopPresent( EbmlElement *el )
+{
+    for( int i = 0; i < mi_level; i++ )
+    {
+        if( m_el[i] && m_el[i] == el )
+            return true;
+    }
+    return false;
+}
 
 /*****************************************************************************
  * Tools
@@ -5217,7 +5242,7 @@ void matroska_segment_c::InformationCreate( )
 
 
 /*****************************************************************************
- * Divers
+ * Misc
  *****************************************************************************/
 
 void matroska_segment_c::IndexAppendCluster( KaxCluster *cluster )