]> git.sesse.net Git - vlc/blobdiff - modules/demux/mkv.cpp
mkv.cpp: fix some memory leaks
[vlc] / modules / demux / mkv.cpp
index 22e532f877a84633b8dc5d52dded477733b5dade..dd474570b95a8eefaaa52164bb6f4d9f78b4c511 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * mkv.cpp : matroska demuxer
  *****************************************************************************
- * Copyright (C) 2003-2004 VideoLAN
+ * Copyright (C) 2003-2004 the VideoLAN team
  * $Id$
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
@@ -397,7 +397,7 @@ vlc_module_begin();
             N_("Use chapter codecs found in the segment."), VLC_TRUE );
 
     add_bool( "mkv-seek-percent", 0, NULL,
-            N_("Seek based on percent not time."),
+            N_("Seek based on percent not time"),
             N_("Seek based on percent not time."), VLC_TRUE );
 
     add_bool( "mkv-use-dummy", 0, NULL,
@@ -953,9 +953,9 @@ public:
     
     std::vector<chapter_codec_cmds_c*> codecs;
 
-    bool operator<( const chapter_item_c & item ) const
+    static bool CompareTimecode( const chapter_item_c * itemA, const chapter_item_c * itemB )
     {
-        return ( i_user_start_time < item.i_user_start_time || (i_user_start_time == item.i_user_start_time && i_user_end_time < item.i_user_end_time) );
+        return ( itemA->i_user_start_time < itemB->i_user_start_time || (itemA->i_user_start_time == itemB->i_user_start_time && itemA->i_user_end_time < itemB->i_user_end_time) );
     }
 
     bool Enter( bool b_do_subchapters );
@@ -1021,14 +1021,14 @@ public:
             {
                 free( tracks[i_track]->fmt.psz_description );
             }
-/*            if( tracks[i_track]->psz_codec )
+            if( tracks[i_track]->psz_codec )
             {
                 free( tracks[i_track]->psz_codec );
             }
             if( tracks[i_track]->fmt.psz_language )
             {
                 free( tracks[i_track]->fmt.psz_language );
-            }*/
+            }
             delete tracks[i_track];
         }
         
@@ -1337,7 +1337,7 @@ public:
     void PreloadFamily( const matroska_segment_c & of_segment );
     void PreloadLinked( matroska_segment_c *p_segment );
     bool PreparePlayback( virtual_segment_c *p_new_segment );
-    matroska_stream_c *AnalyseAllSegmentsFound( EbmlStream *p_estream );
+    matroska_stream_c *AnalyseAllSegmentsFound( EbmlStream *p_estream, bool b_initial = false );
     void JumpTo( virtual_segment_c & p_segment, chapter_item_c * p_chapter );
 
     void StartUiThread();
@@ -1373,7 +1373,10 @@ static void Seek   ( demux_t *, mtime_t i_date, double f_percent, chapter_item_c
 
 #define MKV_IS_ID( el, C ) ( EbmlId( (*el) ) == C::ClassInfos.GlobalId )
 
-static char *UTF8ToStr          ( const UTFstring &u );
+static inline char * ToUTF8( const UTFstring &u )
+{
+    return strdup( u.GetUTF8().c_str() );
+}
 
 /*****************************************************************************
  * Open: initializes matroska demux structures
@@ -1412,7 +1415,7 @@ static int Open( vlc_object_t * p_this )
         return VLC_EGENERIC;
     }
 
-    p_stream = p_sys->AnalyseAllSegmentsFound( p_io_stream );
+    p_stream = p_sys->AnalyseAllSegmentsFound( p_io_stream, true );
     if( p_stream == NULL )
     {
         msg_Err( p_demux, "cannot find KaxSegment" );
@@ -1478,21 +1481,30 @@ static int Open( vlc_object_t * p_this )
 #endif
                     {
                         // test wether this file belongs to our family
-                        vlc_stream_io_callback *p_file_io = new vlc_stream_io_callback( stream_UrlNew( p_demux, s_filename.c_str()), VLC_TRUE );
-                        EbmlStream *p_estream = new EbmlStream(*p_file_io);
-
-                        p_stream = p_sys->AnalyseAllSegmentsFound( p_estream );
-                        if ( p_stream == NULL )
+                        stream_t *p_file_stream = stream_UrlNew( p_demux, s_filename.c_str());
+                        if ( p_file_stream != NULL )
                         {
-                            msg_Dbg( p_demux, "the file '%s' will not be used", s_filename.c_str() );
-                            delete p_estream;
-                            delete p_file_io;
+                            vlc_stream_io_callback *p_file_io = new vlc_stream_io_callback( p_file_stream, VLC_TRUE );
+                            EbmlStream *p_estream = new EbmlStream(*p_file_io);
+
+                            p_stream = p_sys->AnalyseAllSegmentsFound( p_estream );
+
+                            if ( p_stream == NULL )
+                            {
+                                msg_Dbg( p_demux, "the file '%s' will not be used", s_filename.c_str() );
+                                delete p_estream;
+                                delete p_file_io;
+                            }
+                            else
+                            {
+                                p_stream->p_in = p_file_io;
+                                p_stream->p_es = p_estream;
+                                p_sys->streams.push_back( p_stream );
+                            }
                         }
                         else
                         {
-                            p_stream->p_in = p_file_io;
-                            p_stream->p_es = p_estream;
-                            p_sys->streams.push_back( p_stream );
+                            msg_Dbg( p_demux, "the file '%s' cannot be opened", s_filename.c_str() );
                         }
                     }
                 }
@@ -1868,21 +1880,23 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
             }
             return;
         }
-        // TODO implement correct timestamping when B frames are used
-#if 0
+        // 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_pts = i_pts;
+            if( !strcmp( tk->psz_codec, "V_MS/VFW/FOURCC" ) )
+            {
+                p_block->i_pts = 0;
+            }
+            else
+            {
+                p_block->i_pts = i_pts;
+            }
             p_block->i_dts = p_sys->i_pts;
         }
-#else
-        p_block->i_pts = i_pts;
-        p_block->i_dts = p_sys->i_last_dts;
-#endif
 
 #if 0
 msg_Dbg( p_demux, "block i_dts: "I64Fd" / i_pts: "I64Fd, p_block->i_dts, p_block->i_pts);
@@ -1901,7 +1915,7 @@ msg_Dbg( p_demux, "block i_dts: "I64Fd" / i_pts: "I64Fd, p_block->i_dts, p_block
 #undef tk
 }
 
-matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream )
+matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream, bool b_initial )
 {
     int i_upper_lvl = 0;
     size_t i;
@@ -1914,7 +1928,7 @@ matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream )
     {
         return NULL;
     }
-    p_l0->SkipData(*p_estream, EbmlHead_Context);
+    p_l0->SkipData(*p_estream, KaxMatroska_Context);
     delete p_l0;
 
     // find all segments in this file
@@ -1932,7 +1946,7 @@ matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream )
         {
             EbmlParser  *ep;
             matroska_segment_c *p_segment1 = new matroska_segment_c( *this, *p_estream );
-            b_keep_segment = false;
+            b_keep_segment = b_initial;
 
             ep = new EbmlParser(p_estream, p_l0, &demuxer );
             p_segment1->ep = ep;
@@ -1985,9 +1999,13 @@ matroska_stream_c *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream )
             else
                 delete p_segment1;
         }
-
-        p_l0->SkipData(*p_estream, EbmlHead_Context);
-        p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
+        if (p_l0->IsFiniteSize() )
+        {
+            p_l0->SkipData(*p_estream, KaxMatroska_Context);
+            p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
+        }
+        else
+            p_l0 = p_l0->SkipData(*p_estream, KaxSegment_Context);
     }
 
     if ( !b_keep_stream )
@@ -2004,14 +2022,14 @@ bool matroska_segment_c::Select( mtime_t i_start_time )
     size_t i_track;
 
     /* add all es */
-    msg_Dbg( &sys.demuxer, "found %d es", tracks.size() );
+    msg_Dbg( &sys.demuxer, "found %d es", (int)tracks.size() );
     sys.b_pci_packet_set = false;
 
     for( i_track = 0; i_track < tracks.size(); i_track++ )
     {
         if( tracks[i_track]->fmt.i_cat == UNKNOWN_ES )
         {
-            msg_Warn( &sys.demuxer, "invalid track[%d, n=%d]", i_track, tracks[i_track]->i_number );
+            msg_Warn( &sys.demuxer, "invalid track[%d, n=%d]", (int)i_track, tracks[i_track]->i_number );
             tracks[i_track]->p_es = NULL;
             continue;
         }
@@ -2053,7 +2071,6 @@ bool matroska_segment_c::Select( mtime_t i_start_time )
             else if( !strcmp( tracks[i_track]->psz_codec, "V_MPEG4/ISO/AVC" ) )
             {
                 tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'a', 'v', 'c', '1' );
-                tracks[i_track]->fmt.b_packetized = VLC_FALSE;
                 tracks[i_track]->fmt.i_extra = tracks[i_track]->i_extra_data;
                 tracks[i_track]->fmt.p_extra = malloc( tracks[i_track]->i_extra_data );
                 memcpy( tracks[i_track]->fmt.p_extra,tracks[i_track]->p_extra_data, tracks[i_track]->i_extra_data );
@@ -2228,13 +2245,13 @@ bool matroska_segment_c::Select( mtime_t i_start_time )
         else if( !strcmp( tracks[i_track]->psz_codec, "A_TTA1" ) )
         {
             /* FIXME: support this codec */
-            msg_Err( &sys.demuxer, "TTA not supported yet[%d, n=%d]", i_track, tracks[i_track]->i_number );
+            msg_Err( &sys.demuxer, "TTA not supported yet[%d, n=%d]", (int)i_track, tracks[i_track]->i_number );
             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
         }
         else if( !strcmp( tracks[i_track]->psz_codec, "A_WAVPACK4" ) )
         {
             /* FIXME: support this codec */
-            msg_Err( &sys.demuxer, "Wavpack not supported yet[%d, n=%d]", i_track, tracks[i_track]->i_number );
+            msg_Err( &sys.demuxer, "Wavpack not supported yet[%d, n=%d]", (int)i_track, tracks[i_track]->i_number );
             tracks[i_track]->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
         }
         else if( !strcmp( tracks[i_track]->psz_codec, "S_TEXT/UTF8" ) )
@@ -3321,6 +3338,8 @@ size_t vlc_stream_io_callback::write( const void *p_buffer, size_t i_size )
 }
 uint64 vlc_stream_io_callback::getFilePointer( void )
 {
+    if ( s == NULL )
+        return 0;
     return stream_Tell( s );
 }
 void vlc_stream_io_callback::close( void )
@@ -3962,13 +3981,15 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
         {
             KaxTrackName &tname = *(KaxTrackName*)l;
 
-            tk->fmt.psz_description = UTF8ToStr( UTFstring( tname ) );
+            tk->fmt.psz_description = ToUTF8( UTFstring( tname ) );
             msg_Dbg( &sys.demuxer, "|   |   |   + Track Name=%s", tk->fmt.psz_description );
         }
         else  if( MKV_IS_ID( l, KaxTrackLanguage ) )
         {
             KaxTrackLanguage &lang = *(KaxTrackLanguage*)l;
 
+            if ( tk->fmt.psz_language != NULL )
+                free( tk->fmt.psz_language );
             tk->fmt.psz_language = strdup( string( lang ).c_str() );
             msg_Dbg( &sys.demuxer,
                      "|   |   |   + Track Language=`%s'", tk->fmt.psz_language );
@@ -3996,7 +4017,7 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
         {
             KaxCodecName &cname = *(KaxCodecName*)l;
 
-            tk->psz_codec_name = UTF8ToStr( UTFstring( cname ) );
+            tk->psz_codec_name = ToUTF8( UTFstring( cname ) );
             msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Name=%s", tk->psz_codec_name );
         }
         else if( MKV_IS_ID( l, KaxContentEncodings ) )
@@ -4069,7 +4090,7 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
 //        {
 //            KaxCodecSettings &cset = *(KaxCodecSettings*)l;
 
-//            tk->psz_codec_settings = UTF8ToStr( UTFstring( cset ) );
+//            tk->psz_codec_settings = ToUTF8( UTFstring( cset ) );
 //            msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Settings=%s", tk->psz_codec_settings );
 //        }
 //        else if( EbmlId( *l ) == KaxCodecInfoURL::ClassInfos.GlobalId )
@@ -4284,19 +4305,22 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
 
         if( MKV_IS_ID( l, KaxSegmentUID ) )
         {
-            p_segment_uid = new KaxSegmentUID(*static_cast<KaxSegmentUID*>(l));
+            if ( p_segment_uid == NULL )
+                p_segment_uid = new KaxSegmentUID(*static_cast<KaxSegmentUID*>(l));
 
             msg_Dbg( &sys.demuxer, "|   |   + UID=%d", *(uint32*)p_segment_uid->GetBuffer() );
         }
         else if( MKV_IS_ID( l, KaxPrevUID ) )
         {
-            p_prev_segment_uid = new KaxPrevUID(*static_cast<KaxPrevUID*>(l));
+            if ( p_prev_segment_uid == NULL )
+                p_prev_segment_uid = new KaxPrevUID(*static_cast<KaxPrevUID*>(l));
 
             msg_Dbg( &sys.demuxer, "|   |   + PrevUID=%d", *(uint32*)p_prev_segment_uid->GetBuffer() );
         }
         else if( MKV_IS_ID( l, KaxNextUID ) )
         {
-            p_next_segment_uid = new KaxNextUID(*static_cast<KaxNextUID*>(l));
+            if ( p_next_segment_uid == NULL )
+                p_next_segment_uid = new KaxNextUID(*static_cast<KaxNextUID*>(l));
 
             msg_Dbg( &sys.demuxer, "|   |   + NextUID=%d", *(uint32*)p_next_segment_uid->GetBuffer() );
         }
@@ -4322,7 +4346,7 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
         {
             KaxMuxingApp &mapp = *(KaxMuxingApp*)l;
 
-            psz_muxing_application = UTF8ToStr( UTFstring( mapp ) );
+            psz_muxing_application = ToUTF8( UTFstring( mapp ) );
 
             msg_Dbg( &sys.demuxer, "|   |   + Muxing Application=%s",
                      psz_muxing_application );
@@ -4331,7 +4355,7 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
         {
             KaxWritingApp &wapp = *(KaxWritingApp*)l;
 
-            psz_writing_application = UTF8ToStr( UTFstring( wapp ) );
+            psz_writing_application = ToUTF8( UTFstring( wapp ) );
 
             msg_Dbg( &sys.demuxer, "|   |   + Writing Application=%s",
                      psz_writing_application );
@@ -4340,7 +4364,7 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
         {
             KaxSegmentFilename &sfn = *(KaxSegmentFilename*)l;
 
-            psz_segment_filename = UTF8ToStr( UTFstring( sfn ) );
+            psz_segment_filename = ToUTF8( UTFstring( sfn ) );
 
             msg_Dbg( &sys.demuxer, "|   |   + Segment Filename=%s",
                      psz_segment_filename );
@@ -4349,7 +4373,7 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
         {
             KaxTitle &title = *(KaxTitle*)l;
 
-            psz_title = UTF8ToStr( UTFstring( title ) );
+            psz_title = ToUTF8( UTFstring( title ) );
 
             msg_Dbg( &sys.demuxer, "|   |   + Title=%s", psz_title );
         }
@@ -4474,10 +4498,10 @@ void matroska_segment_c::ParseChapterAtom( int i_level, KaxChapterAtom *ca, chap
                     for (k = 0; k < i_level; k++)
                         chapters.psz_name += '+';
                     chapters.psz_name += ' ';
-                    chapters.psz_name += UTF8ToStr( UTFstring( name ) );
+                    chapters.psz_name += ToUTF8( UTFstring( name ) );
                     chapters.b_user_display = true;
 
-                    msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterString '%s'", UTF8ToStr(UTFstring(name)) );
+                    msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterString '%s'", ToUTF8(UTFstring(name)) );
                 }
                 else if( MKV_IS_ID( l, KaxChapterLanguage ) )
                 {
@@ -4743,34 +4767,6 @@ void matroska_segment_c::IndexAppendCluster( KaxCluster *cluster )
 #undef idx
 }
 
-static char * UTF8ToStr( const UTFstring &u )
-{
-    int     i_src;
-    const wchar_t *src;
-    char *dst, *p;
-
-    i_src = u.length();
-    src   = u.c_str();
-
-    p = dst = (char*)malloc( i_src + 1);
-    while( i_src > 0 )
-    {
-        if( *src < 255 )
-        {
-            *p++ = (char)*src;
-        }
-        else
-        {
-            *p++ = '?';
-        }
-        src++;
-        i_src--;
-    }
-    *p++= '\0';
-
-    return dst;
-}
-
 void chapter_edition_c::RefreshChapters( )
 {
     chapter_item_c::RefreshChapters( b_ordered, -1 );
@@ -4811,7 +4807,8 @@ int64_t chapter_item_c::RefreshChapters( bool b_ordered, int64_t i_prev_user_tim
     }
     else
     {
-        std::sort( sub_chapters.begin(), sub_chapters.end() );
+        if ( sub_chapters.begin() != sub_chapters.end() )
+            std::sort( sub_chapters.begin(), sub_chapters.end(), chapter_item_c::CompareTimecode );
         i_user_start_time = i_start_time;
         if ( i_end_time != -1 )
             i_user_end_time = i_end_time;
@@ -4967,7 +4964,7 @@ void demux_sys_t::PreloadLinked( matroska_segment_c *p_segment )
             {
                 sz_name = N_("Segment ");
                 char psz_str[6];
-                sprintf( psz_str, "%d", i );
+                sprintf( psz_str, "%d", (int)i );
                 sz_name += psz_str;
                 p_title->psz_name = strdup( sz_name.c_str() );
             }
@@ -5056,15 +5053,18 @@ void demux_sys_t::JumpTo( virtual_segment_c & vsegment, chapter_item_c * p_chapt
 
 bool matroska_segment_c::CompareSegmentUIDs( const matroska_segment_c * p_item_a, const matroska_segment_c * p_item_b )
 {
+    if ( p_item_a == NULL || p_item_b == NULL )
+        return false;
+
     EbmlBinary * p_itema = (EbmlBinary *)(p_item_a->p_segment_uid);
-    if ( *p_itema == *p_item_b->p_prev_segment_uid )
+    if ( p_item_b->p_prev_segment_uid != NULL && *p_itema == *p_item_b->p_prev_segment_uid )
         return true;
 
     p_itema = (EbmlBinary *)(&p_item_a->p_next_segment_uid);
-    if ( *p_itema == *p_item_b->p_segment_uid )
+    if ( p_item_b->p_segment_uid != NULL && *p_itema == *p_item_b->p_segment_uid )
         return true;
 
-    if ( *p_itema == *p_item_b->p_prev_segment_uid )
+    if ( p_item_b->p_prev_segment_uid != NULL && *p_itema == *p_item_b->p_prev_segment_uid )
         return true;
 
     return false;
@@ -5596,8 +5596,8 @@ bool dvd_command_interpretor_c::Interpret( const binary * p_command, size_t i_si
     if ( i_size != 8 )
         return false;
 
-    virtual_segment_c *p_segment;
-    chapter_item_c *p_chapter;
+    virtual_segment_c *p_segment = NULL;
+    chapter_item_c *p_chapter = NULL;
     bool f_result = false;
     uint16 i_command = ( p_command[0] << 8 ) + p_command[1];