]> 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 697660d98fe3e7439222cfafb3af2785b587e350..d0bd4edfd04fee490418037aa20fb889a3d97f64 100644 (file)
@@ -30,6 +30,9 @@
 
 extern "C" {
 #include "../vobsub.h"
+#include "../xiph.h"
+#include "../windows_audio_commons.h"
+#include "../mp4/libmp4.h"
 }
 
 #include <vlc_codecs.h>
@@ -86,68 +89,80 @@ void matroska_segment_c::ParseSeekHead( KaxSeekHead *seekhead )
             msg_Dbg( &sys.demuxer, "|   |   + Seek" );
 #endif
             ep->Down();
-            while( ( l = ep->Get() ) != NULL )
+            try
             {
-                if( MKV_IS_ID( l, KaxSeekID ) )
+                while( ( l = ep->Get() ) != NULL )
                 {
-                    KaxSeekID &sid = *(KaxSeekID*)l;
-                    sid.ReadData( es.I_O() );
-                    id = EbmlId( sid.GetBuffer(), sid.GetSize() );
-                }
-                else if( MKV_IS_ID( l, KaxSeekPosition ) )
-                {
-                    KaxSeekPosition &spos = *(KaxSeekPosition*)l;
-                    spos.ReadData( es.I_O() );
-                    i_pos = (int64_t)segment->GetGlobalPosition( uint64( spos ) );
-                }
-                else
-                {
-                    /* Many mkvmerge files hit this case. It seems to be a broken SeekHead */
-                    msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name()  );
+                    if( unlikely( !l->ValidateSize() ) )
+                    {
+                        msg_Err( &sys.demuxer,"%s too big... skipping it",  typeid(*l).name() );
+                        continue;
+                    }
+                    if( MKV_IS_ID( l, KaxSeekID ) )
+                    {
+                        KaxSeekID &sid = *(KaxSeekID*)l;
+                        sid.ReadData( es.I_O() );
+                        id = EbmlId( sid.GetBuffer(), sid.GetSize() );
+                    }
+                    else if( MKV_IS_ID( l, KaxSeekPosition ) )
+                    {
+                        KaxSeekPosition &spos = *(KaxSeekPosition*)l;
+                        spos.ReadData( es.I_O() );
+                        i_pos = (int64_t)segment->GetGlobalPosition( uint64( spos ) );
+                    }
+                    else
+                    {
+                        /* Many mkvmerge files hit this case. It seems to be a broken SeekHead */
+                        msg_Dbg( &sys.demuxer, "|   |   + Unknown (%s)", typeid(*l).name() );
+                    }
                 }
             }
+            catch(...)
+            {
+                msg_Err( &sys.demuxer,"Error while reading %s",  typeid(*l).name() );
+            }
             ep->Up();
 
             if( i_pos >= 0 )
             {
                 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
             }
         }
@@ -176,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 );
 }
@@ -208,6 +223,7 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
     tk->psz_codec              = NULL;
     tk->b_dts_only             = false;
     tk->i_default_duration     = 0;
+    tk->b_no_duration          = false;
     tk->f_timecodescale        = 1.0;
 
     tk->b_inited               = false;
@@ -319,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
@@ -367,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 ) )
         {
@@ -389,6 +406,21 @@ void matroska_segment_c::ParseTrackEntry( KaxTrackEntry *m )
 
             msg_Dbg( &sys.demuxer, "|   |   |   + Track Overlay=%u", uint32( tovr ) );
         }
+#if LIBMATROSKA_VERSION >= 0x010401
+        else if( MKV_IS_ID( l, KaxCodecDelay ) )
+        {
+            KaxCodecDelay &codecdelay = *(KaxCodecDelay*)l;
+            tk->i_codec_delay = uint64_t( codecdelay ) / 1000;
+            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 );
+        }
+#endif
         else if( MKV_IS_ID( l, KaxContentEncodings ) )
         {
             EbmlMaster *cencs = static_cast<EbmlMaster*>(l);
@@ -591,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
@@ -713,7 +745,20 @@ void matroska_segment_c::ParseTracks( KaxTracks *tracks )
     int i_upper_level = 0;
 
     /* Master elements */
-    tracks->Read( es, EBML_CONTEXT(tracks), i_upper_level, el, true );
+    if( unlikely( tracks->IsFiniteSize() && tracks->GetSize() >= SIZE_MAX ) )
+    {
+        msg_Err( &sys.demuxer, "Track too big, aborting" );
+        return;
+    }
+    try
+    {
+        tracks->Read( es, EBML_CONTEXT(tracks), i_upper_level, el, true );
+    }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Couldn't read tracks" );
+        return;
+    }
 
     for( size_t i = 0; i < tracks->ListSize(); i++ )
     {
@@ -741,7 +786,20 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
 
     /* Master elements */
     m = static_cast<EbmlMaster *>(info);
-    m->Read( es, EBML_CONTEXT(info), i_upper_level, el, true );
+    if( unlikely( m->IsFiniteSize() && m->GetSize() >= SIZE_MAX ) )
+    {
+        msg_Err( &sys.demuxer, "Info too big, aborting" );
+        return;
+    }
+    try
+    {
+        m->Read( es, EBML_CONTEXT(info), i_upper_level, el, true );
+    }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Couldn't read info" );
+        return;
+    }   
 
     for( size_t i = 0; i < m->ListSize(); i++ )
     {
@@ -780,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 ) )
@@ -789,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 ) )
@@ -854,28 +912,41 @@ void matroska_segment_c::ParseInfo( KaxInfo *info )
         else if( MKV_IS_ID( l, KaxChapterTranslate ) )
         {
             KaxChapterTranslate *p_trans = static_cast<KaxChapterTranslate*>( l );
-            chapter_translation_c *p_translate = new chapter_translation_c();
-
-            p_trans->Read( es, EBML_CONTEXT(p_trans), i_upper_level, el, true );
-            for( size_t j = 0; j < p_trans->ListSize(); j++ )
+            try
             {
-                EbmlElement *l = (*p_trans)[j];
-
-                if( MKV_IS_ID( l, KaxChapterTranslateEditionUID ) )
-                {
-                    p_translate->editions.push_back( uint64( *static_cast<KaxChapterTranslateEditionUID*>( l ) ) );
-                }
-                else if( MKV_IS_ID( l, KaxChapterTranslateCodec ) )
+                if( unlikely( p_trans->IsFiniteSize() && p_trans->GetSize() >= SIZE_MAX ) )
                 {
-                    p_translate->codec_id = uint32( *static_cast<KaxChapterTranslateCodec*>( l ) );
+                    msg_Err( &sys.demuxer, "Chapter translate too big, aborting" );
+                    continue;
                 }
-                else if( MKV_IS_ID( l, KaxChapterTranslateID ) )
+
+                p_trans->Read( es, EBML_CONTEXT(p_trans), i_upper_level, el, true );
+                chapter_translation_c *p_translate = new chapter_translation_c();
+
+                for( size_t j = 0; j < p_trans->ListSize(); j++ )
                 {
-                    p_translate->p_translated = new KaxChapterTranslateID( *static_cast<KaxChapterTranslateID*>( l ) );
+                    EbmlElement *l = (*p_trans)[j];
+
+                    if( MKV_IS_ID( l, KaxChapterTranslateEditionUID ) )
+                    {
+                        p_translate->editions.push_back( uint64( *static_cast<KaxChapterTranslateEditionUID*>( l ) ) );
+                    }
+                    else if( MKV_IS_ID( l, KaxChapterTranslateCodec ) )
+                    {
+                        p_translate->codec_id = uint32( *static_cast<KaxChapterTranslateCodec*>( l ) );
+                    }
+                    else if( MKV_IS_ID( l, KaxChapterTranslateID ) )
+                    {
+                        p_translate->p_translated = new KaxChapterTranslateID( *static_cast<KaxChapterTranslateID*>( l ) );
+                    }
                 }
-            }
 
-            translations.push_back( p_translate );
+                translations.push_back( p_translate );
+            }
+            catch(...)
+            {
+                msg_Err( &sys.demuxer, "Error while reading Chapter Tranlate");
+            }
         }
         else
         {
@@ -902,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 ) )
         {
@@ -933,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 ) )
         {
@@ -967,16 +1038,14 @@ void matroska_segment_c::ParseChapterAtom( int i_level, KaxChapterAtom *ca, chap
                 else if( MKV_IS_ID( l, KaxChapterLanguage ) )
                 {
                     KaxChapterLanguage &lang =*(KaxChapterLanguage*)l;
-                    const char *psz = string( lang ).c_str();
-
-                    msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterLanguage '%s'", psz );
+                    msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterLanguage '%s'",
+                             string( lang ).c_str() );
                 }
                 else if( MKV_IS_ID( l, KaxChapterCountry ) )
                 {
                     KaxChapterCountry &ct =*(KaxChapterCountry*)l;
-                    const char *psz = string( ct ).c_str();
-
-                    msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterCountry '%s'", psz );
+                    msg_Dbg( &sys.demuxer, "|   |   |   |   |    + ChapterCountry '%s'",
+                             string( ct ).c_str() );
                 }
             }
         }
@@ -1039,7 +1108,20 @@ void matroska_segment_c::ParseAttachments( KaxAttachments *attachments )
     EbmlElement *el;
     int i_upper_level = 0;
 
-    attachments->Read( es, EBML_CONTEXT(attachments), i_upper_level, el, true );
+    if( unlikely( attachments->IsFiniteSize() && attachments->GetSize() >= SIZE_MAX ) )
+    {
+        msg_Err( &sys.demuxer, "Attachments too big, aborting" );
+        return;
+    }
+    try
+    {
+        attachments->Read( es, EBML_CONTEXT(attachments), i_upper_level, el, true );
+    }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Error while reading attachments" );
+        return;
+    }
 
     KaxAttached *attachedFile = FindChild<KaxAttached>( *attachments );
 
@@ -1089,7 +1171,20 @@ void matroska_segment_c::ParseChapters( KaxChapters *chapters )
     int i_upper_level = 0;
 
     /* Master elements */
-    chapters->Read( es, EBML_CONTEXT(chapters), i_upper_level, el, true );
+    if( unlikely( chapters->IsFiniteSize() && chapters->GetSize() >= SIZE_MAX ) )
+    {
+        msg_Err( &sys.demuxer, "Chapters too big, aborting" );
+        return;
+    }
+    try
+    {
+        chapters->Read( es, EBML_CONTEXT(chapters), i_upper_level, el, true );
+    }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Error while reading chapters" );
+        return;
+    }
 
     for( size_t i = 0; i < chapters->ListSize(); i++ )
     {
@@ -1142,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;
@@ -1150,7 +1245,20 @@ void matroska_segment_c::ParseCluster( bool b_update_start_time )
 
     /* Master elements */
     m = static_cast<EbmlMaster *>( cluster );
-    m->Read( es, EBML_CONTEXT(cluster), i_upper_level, el, true );
+    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, read_fully );
+    }
+    catch(...)
+    {
+        msg_Err( &sys.demuxer, "Error while reading cluster" );
+        return;
+    }
 
     for( unsigned int i = 0; i < m->ListSize(); i++ )
     {
@@ -1173,6 +1281,14 @@ void matroska_segment_c::ParseCluster( bool b_update_start_time )
 int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
 {
     es_format_t *p_fmt = &p_tk->fmt;
+
+    if( p_tk->psz_codec == NULL )
+    {
+        msg_Err( &sys.demuxer, "Empty codec id" );
+        p_tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
+        return 0;
+    }
+
     if( !strcmp( p_tk->psz_codec, "V_MS/VFW/FOURCC" ) )
     {
         if( p_tk->i_extra_data < (int)sizeof( VLC_BITMAPINFOHEADER ) )
@@ -1251,6 +1367,11 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
         p_tk->fmt.i_codec = VLC_CODEC_VP8;
         p_tk->b_pts_only = true;
     }
+    else if( !strncmp( p_tk->psz_codec, "V_VP9", 5 ) )
+    {
+        p_tk->fmt.i_codec = VLC_CODEC_VP9;
+        fill_extra_data( p_tk, 0 );
+    }
     else if( !strncmp( p_tk->psz_codec, "V_MPEG4", 7 ) )
     {
         if( !strcmp( p_tk->psz_codec, "V_MPEG4/MS/V3" ) )
@@ -1267,6 +1388,11 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
             fill_extra_data( p_tk, 0 );
         }
     }
+    else if( !strncmp( p_tk->psz_codec, "V_MPEGH/ISO/HEVC", 16) )
+    {
+        p_tk->fmt.i_codec = VLC_CODEC_HEVC;
+        fill_extra_data( p_tk, 0 );
+    } 
     else if( !strcmp( p_tk->psz_codec, "V_QUICKTIME" ) )
     {
         MP4_Box_t *p_box = (MP4_Box_t*)xmalloc( sizeof( MP4_Box_t ) );
@@ -1278,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 );
@@ -1306,10 +1437,6 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
         {
             WAVEFORMATEX *p_wf = (WAVEFORMATEX*)p_tk->p_extra_data;
 
-            wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_tk->fmt.i_codec, NULL );
-
-            if( p_tk->fmt.i_codec == VLC_FOURCC( 'u', 'n', 'd', 'f' ) )
-                msg_Err( &sys.demuxer, "Unrecognized wf tag: 0x%x", GetWLE( &p_wf->wFormatTag ) );
             p_tk->fmt.audio.i_channels   = GetWLE( &p_wf->nChannels );
             p_tk->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
             p_tk->fmt.i_bitrate    = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
@@ -1320,8 +1447,46 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
             if( p_tk->fmt.i_extra > 0 )
             {
                 p_tk->fmt.p_extra = xmalloc( p_tk->fmt.i_extra );
-                memcpy( p_tk->fmt.p_extra, &p_wf[1], p_tk->fmt.i_extra );
+                if( p_tk->fmt.p_extra )
+                    memcpy( p_tk->fmt.p_extra, &p_wf[1], p_tk->fmt.i_extra );
+                else
+                    p_tk->fmt.i_extra = 0;
+            }
+
+            if( p_wf->wFormatTag == WAVE_FORMAT_EXTENSIBLE && 
+                p_tk->i_extra_data >= sizeof(WAVEFORMATEXTENSIBLE) )
+            {
+                WAVEFORMATEXTENSIBLE * p_wext = (WAVEFORMATEXTENSIBLE*) p_wf;
+                sf_tag_to_fourcc( &p_wext->SubFormat,  &p_tk->fmt.i_codec, NULL);
+                /* FIXME should we use Samples */
+
+                if( p_tk->fmt.audio.i_channels > 2 &&
+                    ( p_tk->fmt.i_codec != VLC_FOURCC( 'u', 'n', 'd', 'f' ) ) ) 
+                {
+                    uint32_t wfextcm = GetDWLE( &p_wext->dwChannelMask );
+                    int match;
+                    unsigned i_channel_mask = getChannelMask( &wfextcm,
+                                                              p_tk->fmt.audio.i_channels,
+                                                              &match );
+                    p_tk->fmt.i_codec = vlc_fourcc_GetCodecAudio( p_tk->fmt.i_codec,
+                                                                  p_tk->fmt.audio.i_bitspersample );
+                    if( i_channel_mask )
+                    {
+                        p_tk->i_chans_to_reorder = aout_CheckChannelReorder(
+                            pi_channels_aout, NULL,
+                            i_channel_mask,
+                            p_tk->pi_chan_table );
+
+                        p_tk->fmt.audio.i_physical_channels =
+                        p_tk->fmt.audio.i_original_channels = i_channel_mask;
+                    }
+                }
             }
+            else
+                wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_tk->fmt.i_codec, NULL );
+
+            if( p_tk->fmt.i_codec == VLC_FOURCC( 'u', 'n', 'd', 'f' ) )
+                msg_Err( &sys.demuxer, "Unrecognized wf tag: 0x%x", GetWLE( &p_wf->wFormatTag ) );
         }
     }
     else if( !strcmp( p_tk->psz_codec, "A_MPEG/L3" ) ||
@@ -1332,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" ) )
@@ -1355,13 +1526,33 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
     else if( !strcmp( p_tk->psz_codec, "A_FLAC" ) )
     {
         p_tk->fmt.i_codec = VLC_CODEC_FLAC;
-        fill_extra_data( p_tk, 0 );
+        fill_extra_data( p_tk, 8 );
     }
     else if( !strcmp( p_tk->psz_codec, "A_VORBIS" ) )
     {
         p_tk->fmt.i_codec = VLC_CODEC_VORBIS;
         fill_extra_data( p_tk, 0 );
     }
+    else if( !strncmp( p_tk->psz_codec, "A_OPUS", 6 ) )
+    {
+        p_tk->fmt.i_codec = VLC_CODEC_OPUS;
+        if( !p_tk->fmt.audio.i_rate )
+        {
+            msg_Err( &sys.demuxer,"No sampling rate, defaulting to 48kHz");
+            p_tk->fmt.audio.i_rate = 48000;
+        }
+        const uint8_t tags[16] = {'O','p','u','s','T','a','g','s',
+                                   0, 0, 0, 0, 0, 0, 0, 0};
+        unsigned ps[2] = { p_tk->i_extra_data, 16 };
+        const void *pkt[2] = { (const void *)p_tk->p_extra_data,
+                              (const void *) tags };
+
+        if( xiph_PackHeaders( &p_tk->fmt.i_extra,
+                              &p_tk->fmt.p_extra,
+                              ps, pkt, 2 ) )
+            msg_Err( &sys.demuxer, "Couldn't pack OPUS headers");
+
+    }
     else if( !strncmp( p_tk->psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) ||
              !strncmp( p_tk->psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
     {
@@ -1427,6 +1618,11 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
         p_tk->fmt.i_codec = VLC_CODEC_MP4A;
         fill_extra_data( p_tk, 0 );
     }
+    else if( !strcmp( p_tk->psz_codec, "A_ALAC" ) )
+    {
+        p_tk->fmt.i_codec =  VLC_CODEC_ALAC;
+        fill_extra_data( p_tk, 0 );
+    }
     else if( !strcmp( p_tk->psz_codec, "A_WAVPACK4" ) )
     {
         p_tk->fmt.i_codec = VLC_CODEC_WAVPACK;
@@ -1527,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;
@@ -1564,6 +1774,7 @@ int32_t matroska_segment_c::TrackInit( mkv_track_t * p_tk )
     else if( !strcmp( p_tk->psz_codec, "S_VOBSUB" ) )
     {
         p_tk->fmt.i_codec = VLC_CODEC_SPU;
+        p_tk->b_no_duration = true;
         if( p_tk->i_extra_data )
         {
             char *psz_start;
@@ -1586,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:" );