]> git.sesse.net Git - vlc/blobdiff - modules/demux/mkv/matroska_segment_parse.cpp
MKV: fix playback of AC-3 with bogus default duration
[vlc] / modules / demux / mkv / matroska_segment_parse.cpp
index 9d1aa971aae59faef9ba43ac5648b9b21f2cbb59..d0bd4edfd04fee490418037aa20fb889a3d97f64 100644 (file)
@@ -32,6 +32,7 @@ extern "C" {
 #include "../vobsub.h"
 #include "../xiph.h"
 #include "../windows_audio_commons.h"
+#include "../mp4/libmp4.h"
 }
 
 #include <vlc_codecs.h>
@@ -92,7 +93,7 @@ void matroska_segment_c::ParseSeekHead( KaxSeekHead *seekhead )
             {
                 while( ( l = ep->Get() ) != NULL )
                 {
-                    if( unlikely( l->GetSize() >= SIZE_MAX ) )
+                    if( unlikely( !l->ValidateSize() ) )
                     {
                         msg_Err( &sys.demuxer,"%s too big... skipping it",  typeid(*l).name() );
                         continue;
@@ -126,42 +127,42 @@ void matroska_segment_c::ParseSeekHead( KaxSeekHead *seekhead )
             {
                 if( id == EBML_ID(KaxCues) )
                 {
-                    msg_Dbg( &sys.demuxer, "|   - cues at %"PRId64, i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - cues at %" PRId64, i_pos );
                     LoadSeekHeadItem( EBML_INFO(KaxCues), i_pos );
                 }
                 else if( id == EBML_ID(KaxInfo) )
                 {
-                    msg_Dbg( &sys.demuxer, "|   - info at %"PRId64, i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - info at %" PRId64, i_pos );
                     LoadSeekHeadItem( EBML_INFO(KaxInfo), i_pos );
                 }
                 else if( id == EBML_ID(KaxChapters) )
                 {
-                    msg_Dbg( &sys.demuxer, "|   - chapters at %"PRId64, i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - chapters at %" PRId64, i_pos );
                     LoadSeekHeadItem( EBML_INFO(KaxChapters), i_pos );
                 }
                 else if( id == EBML_ID(KaxTags) )
                 {
-                    msg_Dbg( &sys.demuxer, "|   - tags at %"PRId64, i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - tags at %" PRId64, i_pos );
                     LoadSeekHeadItem( EBML_INFO(KaxTags), i_pos );
                 }
                 else if( id == EBML_ID(KaxSeekHead) )
                 {
-                    msg_Dbg( &sys.demuxer, "|   - chained seekhead at %"PRId64, i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - chained seekhead at %" PRId64, i_pos );
                     LoadSeekHeadItem( EBML_INFO(KaxSeekHead), i_pos );
                 }
                 else if( id == EBML_ID(KaxTracks) )
                 {
-                    msg_Dbg( &sys.demuxer, "|   - tracks at %"PRId64, i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - tracks at %" PRId64, i_pos );
                     LoadSeekHeadItem( EBML_INFO(KaxTracks), i_pos );
                 }
                 else if( id == EBML_ID(KaxAttachments) )
                 {
-                    msg_Dbg( &sys.demuxer, "|   - attachments at %"PRId64, i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - attachments at %" PRId64, i_pos );
                     LoadSeekHeadItem( EBML_INFO(KaxAttachments), i_pos );
                 }
 #ifdef MKV_DEBUG
                 else
-                    msg_Dbg( &sys.demuxer, "|   - unknown seekhead reference at %"PRId64, i_pos );
+                    msg_Dbg( &sys.demuxer, "|   - unknown seekhead reference at %" PRId64, i_pos );
 #endif
             }
         }
@@ -190,7 +191,7 @@ static void MkvTree( demux_t & demuxer, int i_level, const char *psz_format, ...
     psz_foo2[ 4 * i_level ] = '+';
     psz_foo2[ 4 * i_level + 1 ] = ' ';
     strcpy( &psz_foo2[ 4 * i_level + 2 ], psz_format );
-    msg_GenericVa( &demuxer,VLC_MSG_DBG, "mkv", psz_foo2, args );
+    msg_GenericVa( &demuxer,VLC_MSG_DBG, psz_foo2, args );
     free( psz_foo2 );
     va_end( args );
 }
@@ -334,13 +335,14 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
             KaxTrackDefaultDuration &defd = *(KaxTrackDefaultDuration*)l;
 
             tk->i_default_duration = uint64(defd);
-            msg_Dbg( &sys.demuxer, "|   |   |   + Track Default Duration=%"PRId64, uint64(defd) );
+            msg_Dbg( &sys.demuxer, "|   |   |   + Track Default Duration=%" PRId64, uint64(defd) );
         }
         else  if( MKV_IS_ID( l, KaxTrackTimecodeScale ) )
         {
             KaxTrackTimecodeScale &ttcs = *(KaxTrackTimecodeScale*)l;
 
             tk->f_timecodescale = float( ttcs );
+            if ( tk->f_timecodescale <= 0 ) tk->f_timecodescale = 1.0;
             msg_Dbg( &sys.demuxer, "|   |   |   + Track TimeCodeScale=%f", tk->f_timecodescale );
         }
         else  if( MKV_IS_ID( l, KaxMaxBlockAdditionID ) ) // UNUSED
@@ -382,7 +384,7 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
                 tk->p_extra_data = (uint8_t*)malloc( tk->i_extra_data );
                 memcpy( tk->p_extra_data, cpriv.GetBuffer(), tk->i_extra_data );
             }
-            msg_Dbg( &sys.demuxer, "|   |   |   + Track CodecPrivate size=%"PRId64, cpriv.GetSize() );
+            msg_Dbg( &sys.demuxer, "|   |   |   + Track CodecPrivate size=%" PRId64, cpriv.GetSize() );
         }
         else if( MKV_IS_ID( l, KaxCodecName ) )
         {
@@ -409,14 +411,14 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
         {
             KaxCodecDelay &codecdelay = *(KaxCodecDelay*)l;
             tk->i_codec_delay = uint64_t( codecdelay ) / 1000;
-            msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Delay =%"PRIu64,
+            msg_Dbg( &sys.demuxer, "|   |   |   + Track Codec Delay =%" PRIu64,
                      tk->i_codec_delay );
         }
         else if( MKV_IS_ID( l, KaxSeekPreRoll ) )
         {
             KaxSeekPreRoll &spr = *(KaxSeekPreRoll*)l;
             tk->i_seek_preroll = uint64_t(spr) / 1000;
-            msg_Dbg( &sys.demuxer, "|   |   |   + Track Seek Preroll =%"PRIu64, tk->i_seek_preroll );
+            msg_Dbg( &sys.demuxer, "|   |   |   + Track Seek Preroll =%" PRIu64, tk->i_seek_preroll );
         }
 #endif
         else if( MKV_IS_ID( l, KaxContentEncodings ) )
@@ -621,7 +623,7 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
                 {
                     KaxVideoFrameRate &vfps = *(KaxVideoFrameRate*)l;
 
-                    tk->f_fps = float( vfps );
+                    tk->f_fps = __MAX( float( vfps ), 1 );
                     msg_Dbg( &sys.demuxer, "   |   |   |   + fps=%f", float( vfps ) );
                 }
 //                else if( MKV_IS_ID( l, KaxVideoGamma) ) //DEPRECATED by Matroska
@@ -743,7 +745,7 @@ void matroska_segment_c::ParseTracks( KaxTracks *tracks )
     int i_upper_level = 0;
 
     /* Master elements */
-    if( unlikely( tracks->GetSize() >= SIZE_MAX ) )
+    if( unlikely( tracks->IsFiniteSize() && tracks->GetSize() >= SIZE_MAX ) )
     {
         msg_Err( &sys.demuxer, "Track too big, aborting" );
         return;
@@ -784,7 +786,7 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
 
     /* Master elements */
     m = static_cast<EbmlMaster *>(info);
-    if( unlikely( m->GetSize() >= SIZE_MAX ) )
+    if( unlikely( m->IsFiniteSize() && m->GetSize() >= SIZE_MAX ) )
     {
         msg_Err( &sys.demuxer, "Info too big, aborting" );
         return;
@@ -836,7 +838,7 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
 
             i_timescale = uint64(tcs);
 
-            msg_Dbg( &sys.demuxer, "|   |   + TimecodeScale=%"PRId64,
+            msg_Dbg( &sys.demuxer, "|   |   + TimecodeScale=%" PRId64,
                      i_timescale );
         }
         else if( MKV_IS_ID( l, KaxDuration ) )
@@ -845,7 +847,7 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
 
             i_duration = mtime_t( double( dur ) );
 
-            msg_Dbg( &sys.demuxer, "|   |   + Duration=%"PRId64,
+            msg_Dbg( &sys.demuxer, "|   |   + Duration=%" PRId64,
                      i_duration );
         }
         else if( MKV_IS_ID( l, KaxMuxingApp ) )
@@ -912,7 +914,7 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
             KaxChapterTranslate *p_trans = static_cast<KaxChapterTranslate*>( l );
             try
             {
-                if( unlikely( p_trans->GetSize() >= SIZE_MAX ) )
+                if( unlikely( p_trans->IsFiniteSize() && p_trans->GetSize() >= SIZE_MAX ) )
                 {
                     msg_Err( &sys.demuxer, "Chapter translate too big, aborting" );
                     continue;
@@ -971,7 +973,7 @@ void matroska_segment_c::ParseChapterAtom( int i_level, KaxChapterAtom *ca, chap
         if( MKV_IS_ID( l, KaxChapterUID ) )
         {
             chapters.i_uid = uint64_t(*(KaxChapterUID*)l);
-            msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterUID: %"PRIu64"", chapters.i_uid );
+            msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterUID: %" PRIu64, chapters.i_uid );
         }
         else if( MKV_IS_ID( l, KaxChapterFlagHidden ) )
         {
@@ -1002,14 +1004,14 @@ void matroska_segment_c::ParseChapterAtom( int i_level, KaxChapterAtom *ca, chap
             KaxChapterTimeStart &start =*(KaxChapterTimeStart*)l;
             chapters.i_start_time = uint64( start ) / INT64_C(1000);
 
-            msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterTimeStart: %"PRId64"", chapters.i_start_time );
+            msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterTimeStart: %" PRId64, chapters.i_start_time );
         }
         else if( MKV_IS_ID( l, KaxChapterTimeEnd ) )
         {
             KaxChapterTimeEnd &end =*(KaxChapterTimeEnd*)l;
             chapters.i_end_time = uint64( end ) / INT64_C(1000);
 
-            msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterTimeEnd: %"PRId64"", chapters.i_end_time );
+            msg_Dbg( &sys.demuxer, "|   |   |   |   + ChapterTimeEnd: %" PRId64, chapters.i_end_time );
         }
         else if( MKV_IS_ID( l, KaxChapterDisplay ) )
         {
@@ -1106,7 +1108,7 @@ void matroska_segment_c::ParseAttachments( KaxAttachments *attachments )
     EbmlElement *el;
     int i_upper_level = 0;
 
-    if( unlikely( attachments->GetSize() >= SIZE_MAX ) )
+    if( unlikely( attachments->IsFiniteSize() && attachments->GetSize() >= SIZE_MAX ) )
     {
         msg_Err( &sys.demuxer, "Attachments too big, aborting" );
         return;
@@ -1169,7 +1171,7 @@ void matroska_segment_c::ParseChapters( KaxChapters *chapters )
     int i_upper_level = 0;
 
     /* Master elements */
-    if( unlikely( chapters->GetSize() >= SIZE_MAX ) )
+    if( unlikely( chapters->IsFiniteSize() && chapters->GetSize() >= SIZE_MAX ) )
     {
         msg_Err( &sys.demuxer, "Chapters too big, aborting" );
         return;
@@ -1235,7 +1237,7 @@ void matroska_segment_c::ParseChapters( KaxChapters *chapters )
     }
 }
 
-void matroska_segment_c::ParseCluster( bool b_update_start_time )
+void matroska_segment_c::ParseCluster( KaxCluster *cluster, bool b_update_start_time, ScopeMode read_fully )
 {
     EbmlElement *el;
     EbmlMaster  *m;
@@ -1243,14 +1245,14 @@ void matroska_segment_c::ParseCluster( bool b_update_start_time )
 
     /* Master elements */
     m = static_cast<EbmlMaster *>( cluster );
-    if( unlikely( m->GetSize() >= SIZE_MAX ) )
+    if( unlikely( m->IsFiniteSize() && m->GetSize() >= SIZE_MAX ) )
     {
         msg_Err( &sys.demuxer, "Cluster too big, aborting" );
         return;
     }
     try
     {
-        m->Read( es, EBML_CONTEXT(cluster), i_upper_level, el, true );
+        m->Read( es, EBML_CONTEXT(cluster), i_upper_level, el, true, read_fully );
     }
     catch(...)
     {
@@ -1402,8 +1404,13 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
             MP4_ReadBox_sample_vide( p_mp4_stream, p_box ) )
         {
             p_tk->fmt.i_codec = p_box->i_type;
-            p_tk->fmt.video.i_width = p_box->data.p_sample_vide->i_width;
-            p_tk->fmt.video.i_height = p_box->data.p_sample_vide->i_height;
+            uint32_t i_width = p_box->data.p_sample_vide->i_width;
+            uint32_t i_height = p_box->data.p_sample_vide->i_height;
+            if( i_width && i_height )
+            {
+                p_tk->fmt.video.i_width = i_width;
+                p_tk->fmt.video.i_height = i_height;
+            }
             p_tk->fmt.i_extra = p_box->data.p_sample_vide->i_qt_image_description;
             p_tk->fmt.p_extra = xmalloc( p_tk->fmt.i_extra );
             memcpy( p_tk->fmt.p_extra, p_box->data.p_sample_vide->p_qt_image_description, p_tk->fmt.i_extra );
@@ -1490,6 +1497,12 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
     }
     else if( !strcmp( p_tk->psz_codec, "A_AC3" ) )
     {
+        // the AC-3 default duration cannot be trusted, see #8512
+        if ( p_tk->fmt.audio.i_rate == 8000 )
+        {
+            p_tk->b_no_duration = true;
+            p_tk->i_default_duration = 0;
+        }
         p_tk->fmt.i_codec = VLC_CODEC_A52;
     }
     else if( !strcmp( p_tk->psz_codec, "A_EAC3" ) )
@@ -1710,6 +1723,20 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
             }
         }
     }
+    else if( !strncmp( p_tk->psz_codec, "A_QUICKTIME", 11 ) )
+    {
+        p_tk->fmt.i_cat = AUDIO_ES;
+        if ( !strncmp( p_tk->psz_codec+11, "/QDM2", 5 ) )
+            p_tk->fmt.i_codec = VLC_CODEC_QDM2;
+        else if( !strncmp( p_tk->psz_codec+11, "/QDMC", 5 ) )
+            p_tk->fmt.i_codec = VLC_FOURCC('Q','D','M','C');
+        else if( p_tk->i_extra_data >= 8)
+            p_tk->fmt.i_codec = VLC_FOURCC(p_tk->p_extra_data[4],
+                                           p_tk->p_extra_data[5],
+                                           p_tk->p_extra_data[6],
+                                           p_tk->p_extra_data[7]);
+        fill_extra_data( p_tk, 0 );
+    }
     else if( !strcmp( p_tk->psz_codec, "S_KATE" ) )
     {
         p_tk->fmt.i_codec = VLC_CODEC_KATE;
@@ -1770,7 +1797,6 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
                 else
                 {
                     msg_Warn( &sys.demuxer, "reading original frame size for vobsub failed" );
-                    return 1;
                 }
 
                 psz_start = strstr( psz_buf, "palette:" );