]> git.sesse.net Git - vlc/commitdiff
mkv.cpp: allow seamless transition between segments
authorSteve Lhomme <robux@videolan.org>
Thu, 17 Mar 2005 12:13:12 +0000 (12:13 +0000)
committerSteve Lhomme <robux@videolan.org>
Thu, 17 Mar 2005 12:13:12 +0000 (12:13 +0000)
modules/demux/mkv.cpp

index 41dff67ac5722ece5918366a3d6bdeeb37c6b12c..db9f739c7c7d3948a1c37e9284de886a105b74f4 100644 (file)
@@ -507,6 +507,8 @@ public:
     void ParseTrackEntry( EbmlMaster *m );
     void IndexAppendCluster( KaxCluster *cluster );
     int BlockGet( KaxBlock **pp_block, int64_t *pi_ref1, int64_t *pi_ref2, int64_t *pi_duration );
+    bool Select( );
+    void UnSelect( );
 };
 
 class matroska_stream_t
@@ -542,7 +544,7 @@ public:
         return NULL;
     }
     
-    matroska_segment_t *FindSegment( EbmlBinary & uid ) const;
+    matroska_segment_t *FindSegment( const EbmlBinary & uid ) const;
 
     void PreloadFamily( const matroska_segment_t & segment );
     size_t PreloadLinked( const demux_sys_t & of_sys );
@@ -588,7 +590,7 @@ public:
         return NULL;
     }
 
-    matroska_segment_t *FindSegment( EbmlBinary & uid ) const;
+    matroska_segment_t *FindSegment( const EbmlBinary & uid ) const;
     void PreloadFamily( );
     void PreloadLinked( );
     matroska_stream_t *AnalyseAllSegmentsFound( EbmlStream *p_estream );
@@ -615,7 +617,6 @@ static int Open( vlc_object_t * p_this )
     matroska_segment_t *p_segment;
     uint8_t            *p_peek;
     std::string        s_path, s_filename;
-    size_t             i_track;
     vlc_stream_io_callback *p_io_callback;
     EbmlStream         *p_io_stream;
 
@@ -758,294 +759,12 @@ static int Open( vlc_object_t * p_this )
         p_segment->b_cues = VLC_FALSE;
     }
 
-    /* add all es */
-    msg_Dbg( p_demux, "found %d es", p_segment->tracks.size() );
-    for( i_track = 0; i_track < p_segment->tracks.size(); i_track++ )
+    if ( !p_segment->Select() )
     {
-#define tk  p_segment->tracks[i_track]
-        if( tk->fmt.i_cat == UNKNOWN_ES )
-        {
-            msg_Warn( p_demux, "invalid track[%d, n=%d]", i_track, tk->i_number );
-            tk->p_es = NULL;
-            continue;
-        }
-
-        if( !strcmp( tk->psz_codec, "V_MS/VFW/FOURCC" ) )
-        {
-            if( tk->i_extra_data < (int)sizeof( BITMAPINFOHEADER ) )
-            {
-                msg_Err( p_demux, "missing/invalid BITMAPINFOHEADER" );
-                tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
-            }
-            else
-            {
-                BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)tk->p_extra_data;
-
-                tk->fmt.video.i_width = GetDWLE( &p_bih->biWidth );
-                tk->fmt.video.i_height= GetDWLE( &p_bih->biHeight );
-                tk->fmt.i_codec       = GetFOURCC( &p_bih->biCompression );
-
-                tk->fmt.i_extra       = GetDWLE( &p_bih->biSize ) - sizeof( BITMAPINFOHEADER );
-                if( tk->fmt.i_extra > 0 )
-                {
-                    tk->fmt.p_extra = malloc( tk->fmt.i_extra );
-                    memcpy( tk->fmt.p_extra, &p_bih[1], tk->fmt.i_extra );
-                }
-            }
-        }
-        else if( !strcmp( tk->psz_codec, "V_MPEG1" ) ||
-                 !strcmp( tk->psz_codec, "V_MPEG2" ) )
-        {
-            tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
-        }
-        else if( !strncmp( tk->psz_codec, "V_MPEG4", 7 ) )
-        {
-            if( !strcmp( tk->psz_codec, "V_MPEG4/MS/V3" ) )
-            {
-                tk->fmt.i_codec = VLC_FOURCC( 'D', 'I', 'V', '3' );
-            }
-            else if( !strcmp( tk->psz_codec, "V_MPEG4/ISO/AVC" ) )
-            {
-                tk->fmt.i_codec = VLC_FOURCC( 'a', 'v', 'c', '1' );
-                tk->fmt.b_packetized = VLC_FALSE;
-                tk->fmt.i_extra = tk->i_extra_data;
-                tk->fmt.p_extra = malloc( tk->i_extra_data );
-                memcpy( tk->fmt.p_extra,tk->p_extra_data, tk->i_extra_data );
-            }
-            else
-            {
-                tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
-            }
-        }
-        else if( !strcmp( tk->psz_codec, "V_QUICKTIME" ) )
-        {
-            MP4_Box_t *p_box = (MP4_Box_t*)malloc( sizeof( MP4_Box_t ) );
-            stream_t *p_mp4_stream = stream_MemoryNew( VLC_OBJECT(p_demux),
-                                                       tk->p_extra_data,
-                                                       tk->i_extra_data );
-            MP4_ReadBoxCommon( p_mp4_stream, p_box );
-            MP4_ReadBox_sample_vide( p_mp4_stream, p_box );
-            tk->fmt.i_codec = p_box->i_type;
-            tk->fmt.video.i_width = p_box->data.p_sample_vide->i_width;
-            tk->fmt.video.i_height = p_box->data.p_sample_vide->i_height;
-            tk->fmt.i_extra = p_box->data.p_sample_vide->i_qt_image_description;
-            tk->fmt.p_extra = malloc( tk->fmt.i_extra );
-            memcpy( tk->fmt.p_extra, p_box->data.p_sample_vide->p_qt_image_description, tk->fmt.i_extra );
-            MP4_FreeBox_sample_vide( p_box );
-            stream_MemoryDelete( p_mp4_stream, VLC_TRUE );
-        }
-        else if( !strcmp( tk->psz_codec, "A_MS/ACM" ) )
-        {
-            if( tk->i_extra_data < (int)sizeof( WAVEFORMATEX ) )
-            {
-                msg_Err( p_demux, "missing/invalid WAVEFORMATEX" );
-                tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
-            }
-            else
-            {
-                WAVEFORMATEX *p_wf = (WAVEFORMATEX*)tk->p_extra_data;
-
-                wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &tk->fmt.i_codec, NULL );
-
-                tk->fmt.audio.i_channels   = GetWLE( &p_wf->nChannels );
-                tk->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
-                tk->fmt.i_bitrate    = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
-                tk->fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign );;
-                tk->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );
-
-                tk->fmt.i_extra            = GetWLE( &p_wf->cbSize );
-                if( tk->fmt.i_extra > 0 )
-                {
-                    tk->fmt.p_extra = malloc( tk->fmt.i_extra );
-                    memcpy( tk->fmt.p_extra, &p_wf[1], tk->fmt.i_extra );
-                }
-            }
-        }
-        else if( !strcmp( tk->psz_codec, "A_MPEG/L3" ) ||
-                 !strcmp( tk->psz_codec, "A_MPEG/L2" ) ||
-                 !strcmp( tk->psz_codec, "A_MPEG/L1" ) )
-        {
-            tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
-        }
-        else if( !strcmp( tk->psz_codec, "A_AC3" ) )
-        {
-            tk->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
-        }
-        else if( !strcmp( tk->psz_codec, "A_DTS" ) )
-        {
-            tk->fmt.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
-        }
-        else if( !strcmp( tk->psz_codec, "A_FLAC" ) )
-        {
-            tk->fmt.i_codec = VLC_FOURCC( 'f', 'l', 'a', 'c' );
-            tk->fmt.i_extra = tk->i_extra_data;
-            tk->fmt.p_extra = malloc( tk->i_extra_data );
-            memcpy( tk->fmt.p_extra,tk->p_extra_data, tk->i_extra_data );
-        }
-        else if( !strcmp( tk->psz_codec, "A_VORBIS" ) )
-        {
-            int i, i_offset = 1, i_size[3], i_extra;
-            uint8_t *p_extra;
-
-            tk->fmt.i_codec = VLC_FOURCC( 'v', 'o', 'r', 'b' );
-
-            /* Split the 3 headers */
-            if( tk->p_extra_data[0] != 0x02 )
-                msg_Err( p_demux, "invalid vorbis header" );
-
-            for( i = 0; i < 2; i++ )
-            {
-                i_size[i] = 0;
-                while( i_offset < tk->i_extra_data )
-                {
-                    i_size[i] += tk->p_extra_data[i_offset];
-                    if( tk->p_extra_data[i_offset++] != 0xff ) break;
-                }
-            }
-
-            i_size[0] = __MIN(i_size[0], tk->i_extra_data - i_offset);
-            i_size[1] = __MIN(i_size[1], tk->i_extra_data -i_offset -i_size[0]);
-            i_size[2] = tk->i_extra_data - i_offset - i_size[0] - i_size[1];
-
-            tk->fmt.i_extra = 3 * 2 + i_size[0] + i_size[1] + i_size[2];
-            tk->fmt.p_extra = malloc( tk->fmt.i_extra );
-            p_extra = (uint8_t *)tk->fmt.p_extra; i_extra = 0;
-            for( i = 0; i < 3; i++ )
-            {
-                *(p_extra++) = i_size[i] >> 8;
-                *(p_extra++) = i_size[i] & 0xFF;
-                memcpy( p_extra, tk->p_extra_data + i_offset + i_extra,
-                        i_size[i] );
-                p_extra += i_size[i];
-                i_extra += i_size[i];
-            }
-        }
-        else if( !strncmp( tk->psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) ||
-                 !strncmp( tk->psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
-        {
-            int i_profile, i_srate;
-            static unsigned int i_sample_rates[] =
-            {
-                    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
-                        16000, 12000, 11025, 8000,  7350,  0,     0,     0
-            };
-
-            tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
-            /* create data for faad (MP4DecSpecificDescrTag)*/
-
-            if( !strcmp( &tk->psz_codec[12], "MAIN" ) )
-            {
-                i_profile = 0;
-            }
-            else if( !strcmp( &tk->psz_codec[12], "LC" ) )
-            {
-                i_profile = 1;
-            }
-            else if( !strcmp( &tk->psz_codec[12], "SSR" ) )
-            {
-                i_profile = 2;
-            }
-            else
-            {
-                i_profile = 3;
-            }
-
-            for( i_srate = 0; i_srate < 13; i_srate++ )
-            {
-                if( i_sample_rates[i_srate] == tk->fmt.audio.i_rate )
-                {
-                    break;
-                }
-            }
-            msg_Dbg( p_demux, "profile=%d srate=%d", i_profile, i_srate );
-
-            tk->fmt.i_extra = 2;
-            tk->fmt.p_extra = malloc( tk->fmt.i_extra );
-            ((uint8_t*)tk->fmt.p_extra)[0] = ((i_profile + 1) << 3) | ((i_srate&0xe) >> 1);
-            ((uint8_t*)tk->fmt.p_extra)[1] = ((i_srate & 0x1) << 7) | (tk->fmt.audio.i_channels << 3);
-        }
-        else if( !strcmp( tk->psz_codec, "A_PCM/INT/BIG" ) ||
-                 !strcmp( tk->psz_codec, "A_PCM/INT/LIT" ) ||
-                 !strcmp( tk->psz_codec, "A_PCM/FLOAT/IEEE" ) )
-        {
-            if( !strcmp( tk->psz_codec, "A_PCM/INT/BIG" ) )
-            {
-                tk->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
-            }
-            else
-            {
-                tk->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
-            }
-            tk->fmt.audio.i_blockalign = ( tk->fmt.audio.i_bitspersample + 7 ) / 8 * tk->fmt.audio.i_channels;
-        }
-        else if( !strcmp( tk->psz_codec, "A_TTA1" ) )
-        {
-            /* FIXME: support this codec */
-            msg_Err( p_demux, "TTA not supported yet[%d, n=%d]", i_track, tk->i_number );
-            tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
-        }
-        else if( !strcmp( tk->psz_codec, "A_WAVPACK4" ) )
-        {
-            /* FIXME: support this codec */
-            msg_Err( p_demux, "Wavpack not supported yet[%d, n=%d]", i_track, tk->i_number );
-            tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
-        }
-        else if( !strcmp( tk->psz_codec, "S_TEXT/UTF8" ) )
-        {
-            tk->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
-            tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
-        }
-        else if( !strcmp( tk->psz_codec, "S_TEXT/SSA" ) ||
-                 !strcmp( tk->psz_codec, "S_TEXT/ASS" ) ||
-                 !strcmp( tk->psz_codec, "S_SSA" ) ||
-                 !strcmp( tk->psz_codec, "S_ASS" ))
-        {
-            tk->fmt.i_codec = VLC_FOURCC( 's', 's', 'a', ' ' );
-            tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
-        }
-        else if( !strcmp( tk->psz_codec, "S_VOBSUB" ) )
-        {
-            tk->fmt.i_codec = VLC_FOURCC( 's','p','u',' ' );
-            if( tk->i_extra_data )
-            {
-                char *p_start;
-                char *p_buf = (char *)malloc( tk->i_extra_data + 1);
-                memcpy( p_buf, tk->p_extra_data , tk->i_extra_data );
-                p_buf[tk->i_extra_data] = '\0';
-                
-                p_start = strstr( p_buf, "size:" );
-                if( sscanf( p_start, "size: %dx%d",
-                        &tk->fmt.subs.spu.i_original_frame_width, &tk->fmt.subs.spu.i_original_frame_height ) == 2 )
-                {
-                    msg_Dbg( p_demux, "original frame size vobsubs: %dx%d", tk->fmt.subs.spu.i_original_frame_width, tk->fmt.subs.spu.i_original_frame_height );
-                }
-                else
-                {
-                    msg_Warn( p_demux, "reading original frame size for vobsub failed" );
-                }
-                free( p_buf );
-            }
-        }
-        else if( !strcmp( tk->psz_codec, "B_VOBBTN" ) )
-        {
-            /* FIXME: support this codec */
-            msg_Err( p_demux, "Vob Buttons not supported yet[%d, n=%d]", i_track, tk->i_number );
-            tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
-        }
-        else
-        {
-            msg_Err( p_demux, "unknow codec id=`%s'", tk->psz_codec );
-            tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
-        }
-        if( tk->b_default )
-        {
-            tk->fmt.i_priority = 1000;
-        }
-
-        tk->p_es = es_out_Add( p_demux->out, &tk->fmt );
-#undef tk
+        msg_Err( p_demux, "cannot use the segment" );
+        goto error;
     }
-
+    
     /* add information */
     InformationCreate( p_demux );
 
@@ -1381,135 +1100,446 @@ static void BlockDecode( demux_t *p_demux, KaxBlock *block, mtime_t i_pts,
 
         if( p_block == NULL )
         {
-            break;
+            break;
+        }
+
+#if defined(HAVE_ZLIB_H)
+        if( tk->i_compression_type )
+        {
+            p_block = block_zlib_decompress( VLC_OBJECT(p_demux), p_block );
+        }
+#endif
+
+        // TODO implement 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_dts = i_pts;
+            p_block->i_pts = 0;
+        }
+
+        if( tk->fmt.i_cat == SPU_ES && strcmp( tk->psz_codec, "S_VOBSUB" ) )
+        {
+            p_block->i_length = i_duration * 1000;
+        }
+        es_out_Send( p_demux->out, tk->p_es, p_block );
+
+        /* use time stamp only for first block */
+        i_pts = 0;
+    }
+
+#undef tk
+}
+
+matroska_stream_t *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream )
+{
+    int i_upper_lvl = 0;
+    size_t i;
+    EbmlElement *p_l0, *p_l1, *p_l2;
+    bool b_keep_stream = false, b_keep_segment;
+
+    // verify the EBML Header
+    p_l0 = p_estream->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL);
+    if (p_l0 == NULL)
+    {
+        return NULL;
+    }
+    p_l0->SkipData(*p_estream, EbmlHead_Context);
+    delete p_l0;
+
+    // find all segments in this file
+    p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
+    if (p_l0 == NULL)
+    {
+        return NULL;
+    }
+
+    matroska_stream_t *p_stream1 = new matroska_stream_t( *this );
+
+    while (p_l0 != 0)
+    {
+        if (EbmlId(*p_l0) == KaxSegment::ClassInfos.GlobalId)
+        {
+            EbmlParser  *ep;
+            matroska_segment_t *p_segment1 = new matroska_segment_t( *this, *p_estream );
+            b_keep_segment = false;
+
+            ep = new EbmlParser(p_estream, p_l0);
+            p_segment1->ep = ep;
+            p_segment1->segment = (KaxSegment*)p_l0;
+
+            while ((p_l1 = ep->Get()))
+            {
+                if (MKV_IS_ID(p_l1, KaxInfo))
+                {
+                    // find the families of this segment
+                    KaxInfo *p_info = static_cast<KaxInfo*>(p_l1);
+
+                    p_info->Read(*p_estream, KaxInfo::ClassInfos.Context, i_upper_lvl, p_l2, true);
+                    for( i = 0; i < p_info->ListSize(); i++ )
+                    {
+                        EbmlElement *l = (*p_info)[i];
+
+                        if( MKV_IS_ID( l, KaxSegmentUID ) )
+                        {
+                            KaxSegmentUID *p_uid = static_cast<KaxSegmentUID*>(l);
+                            b_keep_segment = (FindSegment( *p_uid ) == NULL);
+                            if ( !b_keep_segment )
+                                break; // this segment is already known
+                            p_segment1->segment_uid = *( new KaxSegmentUID(*p_uid) );
+                        }
+                        else if( MKV_IS_ID( l, KaxPrevUID ) )
+                        {
+                            p_segment1->prev_segment_uid = *( new KaxPrevUID( *static_cast<KaxPrevUID*>(l) ) );
+                        }
+                        else if( MKV_IS_ID( l, KaxNextUID ) )
+                        {
+                            p_segment1->next_segment_uid = *( new KaxNextUID( *static_cast<KaxNextUID*>(l) ) );
+                        }
+                        else if( MKV_IS_ID( l, KaxSegmentFamily ) )
+                        {
+                            KaxSegmentFamily *p_fam = new KaxSegmentFamily( *static_cast<KaxSegmentFamily*>(l) );
+                            std::vector<KaxSegmentFamily>::iterator iter;
+                            p_segment1->families.push_back( *p_fam );
+                        }
+                    }
+                    break;
+                }
+            }
+            if ( b_keep_segment )
+            {
+                b_keep_stream = true;
+                p_stream1->segments.push_back( p_segment1 );
+            }
+            else
+                delete p_segment1;
+        }
+
+        p_l0->SkipData(*p_estream, EbmlHead_Context);
+        p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
+    }
+
+    if ( !b_keep_stream )
+    {
+        delete p_stream1;
+        p_stream1 = NULL;
+    }
+
+    return p_stream1;
+}
+
+bool matroska_segment_t::Select( )
+{
+    size_t i_track;
+
+    /* add all es */
+    msg_Dbg( &sys.demuxer, "found %d es", tracks.size() );
+    for( i_track = 0; i_track < tracks.size(); i_track++ )
+    {
+#define tk  tracks[i_track]
+        if( tk->fmt.i_cat == UNKNOWN_ES )
+        {
+            msg_Warn( &sys.demuxer, "invalid track[%d, n=%d]", i_track, tk->i_number );
+            tk->p_es = NULL;
+            continue;
+        }
+
+        if( !strcmp( tk->psz_codec, "V_MS/VFW/FOURCC" ) )
+        {
+            if( tk->i_extra_data < (int)sizeof( BITMAPINFOHEADER ) )
+            {
+                msg_Err( &sys.demuxer, "missing/invalid BITMAPINFOHEADER" );
+                tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
+            }
+            else
+            {
+                BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)tk->p_extra_data;
+
+                tk->fmt.video.i_width = GetDWLE( &p_bih->biWidth );
+                tk->fmt.video.i_height= GetDWLE( &p_bih->biHeight );
+                tk->fmt.i_codec       = GetFOURCC( &p_bih->biCompression );
+
+                tk->fmt.i_extra       = GetDWLE( &p_bih->biSize ) - sizeof( BITMAPINFOHEADER );
+                if( tk->fmt.i_extra > 0 )
+                {
+                    tk->fmt.p_extra = malloc( tk->fmt.i_extra );
+                    memcpy( tk->fmt.p_extra, &p_bih[1], tk->fmt.i_extra );
+                }
+            }
+        }
+        else if( !strcmp( tk->psz_codec, "V_MPEG1" ) ||
+                 !strcmp( tk->psz_codec, "V_MPEG2" ) )
+        {
+            tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
+        }
+        else if( !strncmp( tk->psz_codec, "V_MPEG4", 7 ) )
+        {
+            if( !strcmp( tk->psz_codec, "V_MPEG4/MS/V3" ) )
+            {
+                tk->fmt.i_codec = VLC_FOURCC( 'D', 'I', 'V', '3' );
+            }
+            else if( !strcmp( tk->psz_codec, "V_MPEG4/ISO/AVC" ) )
+            {
+                tk->fmt.i_codec = VLC_FOURCC( 'a', 'v', 'c', '1' );
+                tk->fmt.b_packetized = VLC_FALSE;
+                tk->fmt.i_extra = tk->i_extra_data;
+                tk->fmt.p_extra = malloc( tk->i_extra_data );
+                memcpy( tk->fmt.p_extra,tk->p_extra_data, tk->i_extra_data );
+            }
+            else
+            {
+                tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
+            }
+        }
+        else if( !strcmp( tk->psz_codec, "V_QUICKTIME" ) )
+        {
+            MP4_Box_t *p_box = (MP4_Box_t*)malloc( sizeof( MP4_Box_t ) );
+            stream_t *p_mp4_stream = stream_MemoryNew( VLC_OBJECT(&sys.demuxer),
+                                                       tk->p_extra_data,
+                                                       tk->i_extra_data );
+            MP4_ReadBoxCommon( p_mp4_stream, p_box );
+            MP4_ReadBox_sample_vide( p_mp4_stream, p_box );
+            tk->fmt.i_codec = p_box->i_type;
+            tk->fmt.video.i_width = p_box->data.p_sample_vide->i_width;
+            tk->fmt.video.i_height = p_box->data.p_sample_vide->i_height;
+            tk->fmt.i_extra = p_box->data.p_sample_vide->i_qt_image_description;
+            tk->fmt.p_extra = malloc( tk->fmt.i_extra );
+            memcpy( tk->fmt.p_extra, p_box->data.p_sample_vide->p_qt_image_description, tk->fmt.i_extra );
+            MP4_FreeBox_sample_vide( p_box );
+            stream_MemoryDelete( p_mp4_stream, VLC_TRUE );
+        }
+        else if( !strcmp( tk->psz_codec, "A_MS/ACM" ) )
+        {
+            if( tk->i_extra_data < (int)sizeof( WAVEFORMATEX ) )
+            {
+                msg_Err( &sys.demuxer, "missing/invalid WAVEFORMATEX" );
+                tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
+            }
+            else
+            {
+                WAVEFORMATEX *p_wf = (WAVEFORMATEX*)tk->p_extra_data;
+
+                wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &tk->fmt.i_codec, NULL );
+
+                tk->fmt.audio.i_channels   = GetWLE( &p_wf->nChannels );
+                tk->fmt.audio.i_rate = GetDWLE( &p_wf->nSamplesPerSec );
+                tk->fmt.i_bitrate    = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
+                tk->fmt.audio.i_blockalign = GetWLE( &p_wf->nBlockAlign );;
+                tk->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );
+
+                tk->fmt.i_extra            = GetWLE( &p_wf->cbSize );
+                if( tk->fmt.i_extra > 0 )
+                {
+                    tk->fmt.p_extra = malloc( tk->fmt.i_extra );
+                    memcpy( tk->fmt.p_extra, &p_wf[1], tk->fmt.i_extra );
+                }
+            }
+        }
+        else if( !strcmp( tk->psz_codec, "A_MPEG/L3" ) ||
+                 !strcmp( tk->psz_codec, "A_MPEG/L2" ) ||
+                 !strcmp( tk->psz_codec, "A_MPEG/L1" ) )
+        {
+            tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
         }
-
-#if defined(HAVE_ZLIB_H)
-        if( tk->i_compression_type )
+        else if( !strcmp( tk->psz_codec, "A_AC3" ) )
         {
-            p_block = block_zlib_decompress( VLC_OBJECT(p_demux), p_block );
+            tk->fmt.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
         }
-#endif
-
-        // TODO implement correct timestamping when B frames are used
-        if( tk->fmt.i_cat != VIDEO_ES )
+        else if( !strcmp( tk->psz_codec, "A_DTS" ) )
         {
-            p_block->i_dts = p_block->i_pts = i_pts;
+            tk->fmt.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
         }
-        else
+        else if( !strcmp( tk->psz_codec, "A_FLAC" ) )
         {
-            p_block->i_dts = i_pts;
-            p_block->i_pts = 0;
+            tk->fmt.i_codec = VLC_FOURCC( 'f', 'l', 'a', 'c' );
+            tk->fmt.i_extra = tk->i_extra_data;
+            tk->fmt.p_extra = malloc( tk->i_extra_data );
+            memcpy( tk->fmt.p_extra,tk->p_extra_data, tk->i_extra_data );
         }
-
-        if( tk->fmt.i_cat == SPU_ES && strcmp( tk->psz_codec, "S_VOBSUB" ) )
+        else if( !strcmp( tk->psz_codec, "A_VORBIS" ) )
         {
-            p_block->i_length = i_duration * 1000;
-        }
-        es_out_Send( p_demux->out, tk->p_es, p_block );
-
-        /* use time stamp only for first block */
-        i_pts = 0;
-    }
-
-#undef tk
-}
+            int i, i_offset = 1, i_size[3], i_extra;
+            uint8_t *p_extra;
 
-matroska_stream_t *demux_sys_t::AnalyseAllSegmentsFound( EbmlStream *p_estream )
-{
-    int i_upper_lvl = 0;
-    size_t i;
-    EbmlElement *p_l0, *p_l1, *p_l2;
-    bool b_keep_stream = false, b_keep_segment;
+            tk->fmt.i_codec = VLC_FOURCC( 'v', 'o', 'r', 'b' );
 
-    // verify the EBML Header
-    p_l0 = p_estream->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL);
-    if (p_l0 == NULL)
-    {
-        return NULL;
-    }
-    p_l0->SkipData(*p_estream, EbmlHead_Context);
-    delete p_l0;
+            /* Split the 3 headers */
+            if( tk->p_extra_data[0] != 0x02 )
+                msg_Err( &sys.demuxer, "invalid vorbis header" );
 
-    // find all segments in this file
-    p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
-    if (p_l0 == NULL)
-    {
-        return NULL;
-    }
+            for( i = 0; i < 2; i++ )
+            {
+                i_size[i] = 0;
+                while( i_offset < tk->i_extra_data )
+                {
+                    i_size[i] += tk->p_extra_data[i_offset];
+                    if( tk->p_extra_data[i_offset++] != 0xff ) break;
+                }
+            }
 
-    matroska_stream_t *p_stream1 = new matroska_stream_t( *this );
+            i_size[0] = __MIN(i_size[0], tk->i_extra_data - i_offset);
+            i_size[1] = __MIN(i_size[1], tk->i_extra_data -i_offset -i_size[0]);
+            i_size[2] = tk->i_extra_data - i_offset - i_size[0] - i_size[1];
 
-    while (p_l0 != 0)
-    {
-        if (EbmlId(*p_l0) == KaxSegment::ClassInfos.GlobalId)
+            tk->fmt.i_extra = 3 * 2 + i_size[0] + i_size[1] + i_size[2];
+            tk->fmt.p_extra = malloc( tk->fmt.i_extra );
+            p_extra = (uint8_t *)tk->fmt.p_extra; i_extra = 0;
+            for( i = 0; i < 3; i++ )
+            {
+                *(p_extra++) = i_size[i] >> 8;
+                *(p_extra++) = i_size[i] & 0xFF;
+                memcpy( p_extra, tk->p_extra_data + i_offset + i_extra,
+                        i_size[i] );
+                p_extra += i_size[i];
+                i_extra += i_size[i];
+            }
+        }
+        else if( !strncmp( tk->psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) ||
+                 !strncmp( tk->psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
         {
-            EbmlParser  *ep;
-            matroska_segment_t *p_segment1 = new matroska_segment_t( *this, *p_estream );
-            b_keep_segment = false;
+            int i_profile, i_srate;
+            static unsigned int i_sample_rates[] =
+            {
+                    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+                        16000, 12000, 11025, 8000,  7350,  0,     0,     0
+            };
 
-            ep = new EbmlParser(p_estream, p_l0);
-            p_segment1->ep = ep;
-            p_segment1->segment = (KaxSegment*)p_l0;
+            tk->fmt.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
+            /* create data for faad (MP4DecSpecificDescrTag)*/
 
-            while ((p_l1 = ep->Get()))
+            if( !strcmp( &tk->psz_codec[12], "MAIN" ) )
             {
-                if (MKV_IS_ID(p_l1, KaxInfo))
-                {
-                    // find the families of this segment
-                    KaxInfo *p_info = static_cast<KaxInfo*>(p_l1);
-
-                    p_info->Read(*p_estream, KaxInfo::ClassInfos.Context, i_upper_lvl, p_l2, true);
-                    for( i = 0; i < p_info->ListSize(); i++ )
-                    {
-                        EbmlElement *l = (*p_info)[i];
+                i_profile = 0;
+            }
+            else if( !strcmp( &tk->psz_codec[12], "LC" ) )
+            {
+                i_profile = 1;
+            }
+            else if( !strcmp( &tk->psz_codec[12], "SSR" ) )
+            {
+                i_profile = 2;
+            }
+            else
+            {
+                i_profile = 3;
+            }
 
-                        if( MKV_IS_ID( l, KaxSegmentUID ) )
-                        {
-                            KaxSegmentUID *p_uid = static_cast<KaxSegmentUID*>(l);
-                            b_keep_segment = (FindSegment( *p_uid ) == NULL);
-                            if ( !b_keep_segment )
-                                break; // this segment is already known
-                            p_segment1->segment_uid = *( new KaxSegmentUID(*p_uid) );
-                        }
-                        else if( MKV_IS_ID( l, KaxPrevUID ) )
-                        {
-                            p_segment1->prev_segment_uid = *( new KaxPrevUID( *static_cast<KaxPrevUID*>(l) ) );
-                        }
-                        else if( MKV_IS_ID( l, KaxNextUID ) )
-                        {
-                            p_segment1->next_segment_uid = *( new KaxNextUID( *static_cast<KaxNextUID*>(l) ) );
-                        }
-                        else if( MKV_IS_ID( l, KaxSegmentFamily ) )
-                        {
-                            KaxSegmentFamily *p_fam = new KaxSegmentFamily( *static_cast<KaxSegmentFamily*>(l) );
-                            std::vector<KaxSegmentFamily>::iterator iter;
-                            p_segment1->families.push_back( *p_fam );
-                        }
-                    }
+            for( i_srate = 0; i_srate < 13; i_srate++ )
+            {
+                if( i_sample_rates[i_srate] == tk->fmt.audio.i_rate )
+                {
                     break;
                 }
             }
-            if ( b_keep_segment )
+            msg_Dbg( &sys.demuxer, "profile=%d srate=%d", i_profile, i_srate );
+
+            tk->fmt.i_extra = 2;
+            tk->fmt.p_extra = malloc( tk->fmt.i_extra );
+            ((uint8_t*)tk->fmt.p_extra)[0] = ((i_profile + 1) << 3) | ((i_srate&0xe) >> 1);
+            ((uint8_t*)tk->fmt.p_extra)[1] = ((i_srate & 0x1) << 7) | (tk->fmt.audio.i_channels << 3);
+        }
+        else if( !strcmp( tk->psz_codec, "A_PCM/INT/BIG" ) ||
+                 !strcmp( tk->psz_codec, "A_PCM/INT/LIT" ) ||
+                 !strcmp( tk->psz_codec, "A_PCM/FLOAT/IEEE" ) )
+        {
+            if( !strcmp( tk->psz_codec, "A_PCM/INT/BIG" ) )
             {
-                b_keep_stream = true;
-                p_stream1->segments.push_back( p_segment1 );
+                tk->fmt.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
             }
             else
-                delete p_segment1;
+            {
+                tk->fmt.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
+            }
+            tk->fmt.audio.i_blockalign = ( tk->fmt.audio.i_bitspersample + 7 ) / 8 * tk->fmt.audio.i_channels;
+        }
+        else if( !strcmp( tk->psz_codec, "A_TTA1" ) )
+        {
+            /* FIXME: support this codec */
+            msg_Err( &sys.demuxer, "TTA not supported yet[%d, n=%d]", i_track, tk->i_number );
+            tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
+        }
+        else if( !strcmp( tk->psz_codec, "A_WAVPACK4" ) )
+        {
+            /* FIXME: support this codec */
+            msg_Err( &sys.demuxer, "Wavpack not supported yet[%d, n=%d]", i_track, tk->i_number );
+            tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
+        }
+        else if( !strcmp( tk->psz_codec, "S_TEXT/UTF8" ) )
+        {
+            tk->fmt.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
+            tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
+        }
+        else if( !strcmp( tk->psz_codec, "S_TEXT/SSA" ) ||
+                 !strcmp( tk->psz_codec, "S_TEXT/ASS" ) ||
+                 !strcmp( tk->psz_codec, "S_SSA" ) ||
+                 !strcmp( tk->psz_codec, "S_ASS" ))
+        {
+            tk->fmt.i_codec = VLC_FOURCC( 's', 's', 'a', ' ' );
+            tk->fmt.subs.psz_encoding = strdup( "UTF-8" );
+        }
+        else if( !strcmp( tk->psz_codec, "S_VOBSUB" ) )
+        {
+            tk->fmt.i_codec = VLC_FOURCC( 's','p','u',' ' );
+            if( tk->i_extra_data )
+            {
+                char *p_start;
+                char *p_buf = (char *)malloc( tk->i_extra_data + 1);
+                memcpy( p_buf, tk->p_extra_data , tk->i_extra_data );
+                p_buf[tk->i_extra_data] = '\0';
+                
+                p_start = strstr( p_buf, "size:" );
+                if( sscanf( p_start, "size: %dx%d",
+                        &tk->fmt.subs.spu.i_original_frame_width, &tk->fmt.subs.spu.i_original_frame_height ) == 2 )
+                {
+                    msg_Dbg( &sys.demuxer, "original frame size vobsubs: %dx%d", tk->fmt.subs.spu.i_original_frame_width, tk->fmt.subs.spu.i_original_frame_height );
+                }
+                else
+                {
+                    msg_Warn( &sys.demuxer, "reading original frame size for vobsub failed" );
+                }
+                free( p_buf );
+            }
+        }
+        else if( !strcmp( tk->psz_codec, "B_VOBBTN" ) )
+        {
+            /* FIXME: support this codec */
+            msg_Err( &sys.demuxer, "Vob Buttons not supported yet[%d, n=%d]", i_track, tk->i_number );
+            tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
+        }
+        else
+        {
+            msg_Err( &sys.demuxer, "unknow codec id=`%s'", tk->psz_codec );
+            tk->fmt.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
+        }
+        if( tk->b_default )
+        {
+            tk->fmt.i_priority = 1000;
         }
 
-        p_l0->SkipData(*p_estream, EbmlHead_Context);
-        p_l0 = p_estream->FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
+        tk->p_es = es_out_Add( sys.demuxer.out, &tk->fmt );
+#undef tk
     }
+    
+    return true;
+}
 
-    if ( !b_keep_stream )
+void matroska_segment_t::UnSelect( )
+{
+    size_t i_track;
+
+    for( i_track = 0; i_track < tracks.size(); i_track++ )
     {
-        delete p_stream1;
-        p_stream1 = NULL;
+#define tk  tracks[i_track]
+        if ( tk->p_es != NULL )
+        {
+            es_out_Del( sys.demuxer.out, tk->p_es );
+            tk->p_es = NULL;
+        }
+#undef tk
     }
-
-    return p_stream1;
 }
 
 static void UpdateCurrentToChapter( demux_t & demux )
@@ -1767,8 +1797,13 @@ static int Demux( demux_t *p_demux)
             /* nothing left to read in this ordered edition */
             if ( p_stream->i_current_segment == p_stream->segments.size() - 1)
                 return 0;
+            p_segment->UnSelect( );
+            
             /* switch to the next segment (TODO update the duration) */
             p_stream->i_current_segment++;
+            p_segment = p_stream->Segment();
+            if ( !p_segment || !p_segment->Select( ) )
+                return 0;
             continue;
         }
 
@@ -3441,7 +3476,7 @@ bool matroska_segment_t::Preload( )
     return true;
 }
 
-matroska_segment_t *demux_sys_t::FindSegment( EbmlBinary & uid ) const
+matroska_segment_t *demux_sys_t::FindSegment( const EbmlBinary & uid ) const
 {
     matroska_segment_t *p_segment = NULL;
     for (size_t i=0; i<streams.size() && p_segment == NULL; i++)
@@ -3451,7 +3486,7 @@ matroska_segment_t *demux_sys_t::FindSegment( EbmlBinary & uid ) const
     return p_segment;
 }
 
-matroska_segment_t *matroska_stream_t::FindSegment( EbmlBinary & uid ) const
+matroska_segment_t *matroska_stream_t::FindSegment( const EbmlBinary & uid ) const
 {
     for (size_t i=0; i<segments.size(); i++)
     {