99dcc9e4865b4dfeea8ef1923785d43403a16491
[vlc.git] / modules / demux / mkv.cpp
1 /*****************************************************************************
2  * mkv.cpp : matroska demuxer
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: mkv.cpp,v 1.23 2003/08/25 20:47:41 fenrir Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30
31 #ifdef HAVE_TIME_H
32 #   include <time.h>                                               /* time() */
33 #endif
34
35 #include <vlc/input.h>
36
37 #include <codecs.h>                        /* BITMAPINFOHEADER, WAVEFORMATEX */
38 #include "iso_lang.h"
39
40 #include <iostream>
41 #include <cassert>
42 #include <typeinfo>
43
44 #ifdef HAVE_WCHAR_H
45 #   include <wchar.h>
46 #endif
47
48 /* libebml and matroska */
49 #include "ebml/EbmlHead.h"
50 #include "ebml/EbmlSubHead.h"
51 #include "ebml/EbmlStream.h"
52 #include "ebml/EbmlContexts.h"
53 #include "ebml/EbmlVersion.h"
54 #include "ebml/EbmlVoid.h"
55
56 #include "matroska/FileKax.h"
57 #ifdef HAVE_MATROSKA_KAXATTACHMENTS_H
58 #include "matroska/KaxAttachments.h"
59 #else
60 #include "matroska/KaxAttachements.h"
61 #endif
62 #include "matroska/KaxBlock.h"
63 #include "matroska/KaxBlockData.h"
64 #include "matroska/KaxChapters.h"
65 #include "matroska/KaxCluster.h"
66 #include "matroska/KaxClusterData.h"
67 #include "matroska/KaxContexts.h"
68 #include "matroska/KaxCues.h"
69 #include "matroska/KaxCuesData.h"
70 #include "matroska/KaxInfo.h"
71 #include "matroska/KaxInfoData.h"
72 #include "matroska/KaxSeekHead.h"
73 #include "matroska/KaxSegment.h"
74 #include "matroska/KaxTag.h"
75 #include "matroska/KaxTags.h"
76 #include "matroska/KaxTagMulti.h"
77 #include "matroska/KaxTracks.h"
78 #include "matroska/KaxTrackAudio.h"
79 #include "matroska/KaxTrackVideo.h"
80 #include "matroska/KaxTrackEntryData.h"
81
82 #include "ebml/StdIOCallback.h"
83
84 using namespace LIBMATROSKA_NAMESPACE;
85 using namespace std;
86
87
88 /*****************************************************************************
89  * Local prototypes
90  *****************************************************************************/
91 static int  Activate  ( vlc_object_t * );
92 static void Deactivate( vlc_object_t * );
93 static int  Demux     ( input_thread_t * );
94
95 /*****************************************************************************
96  * Module descriptor
97  *****************************************************************************/
98 vlc_module_begin();
99     add_category_hint( N_("mkv-demuxer"), NULL, VLC_TRUE );
100         add_bool( "mkv-seek-percent", 1, NULL,
101                   N_("Seek based on percent not time"),
102                   N_("Seek based on percent not time"), VLC_TRUE );
103
104     set_description( _("mka/mkv stream demuxer" ) );
105     set_capability( "demux", 50 );
106     set_callbacks( Activate, Deactivate );
107     add_shortcut( "mka" );
108     add_shortcut( "mkv" );
109 vlc_module_end();
110
111
112 /*****************************************************************************
113  * Stream managment
114  *****************************************************************************/
115 class vlc_stream_io_callback: public IOCallback
116 {
117   private:
118     input_thread_t *p_input;
119     vlc_bool_t     mb_eof;
120
121   public:
122     vlc_stream_io_callback( input_thread_t * );
123
124     virtual uint32_t read            ( void *p_buffer, size_t i_size);
125     virtual void     setFilePointer  ( int64_t i_offset, seek_mode mode = seek_beginning );
126     virtual size_t   write           ( const void *p_buffer, size_t i_size);
127     virtual uint64_t getFilePointer  ( void );
128     virtual void     close           ( void );
129 };
130
131 /*****************************************************************************
132  * Ebml Stream parser
133  *****************************************************************************/
134 class EbmlParser
135 {
136   public:
137     EbmlParser( EbmlStream *es, EbmlElement *el_start );
138     ~EbmlParser( void );
139
140     void Up( void );
141     void Down( void );
142     EbmlElement *Get( void );
143     void        Keep( void );
144
145     int GetLevel( void );
146
147   private:
148     EbmlStream  *m_es;
149     int         mi_level;
150     EbmlElement *m_el[6];
151
152     EbmlElement *m_got;
153
154     int         mi_user_level;
155     vlc_bool_t  mb_keep;
156 };
157
158
159 /*****************************************************************************
160  * Some functions to manipulate memory
161  *****************************************************************************/
162 #define GetFOURCC( p )  __GetFOURCC( (uint8_t*)p )
163 static vlc_fourcc_t __GetFOURCC( uint8_t *p )
164 {
165     return VLC_FOURCC( p[0], p[1], p[2], p[3] );
166 }
167
168 /*****************************************************************************
169  * definitions of structures and functions used by this plugins
170  *****************************************************************************/
171 typedef struct
172 {
173     int         i_cat;
174     vlc_bool_t  b_default;
175     vlc_bool_t  b_enabled;
176     int         i_number;
177
178     int         i_extra_data;
179     uint8_t     *p_extra_data;
180
181     char         *psz_language;
182
183     char         *psz_codec;
184     vlc_fourcc_t i_codec;
185
186     uint64_t     i_default_duration;
187     float        f_timecodescale;
188     /* video */
189     int         i_width;
190     int         i_height;
191     int         i_display_width;
192     int         i_display_height;
193     float       f_fps;
194
195
196     /* audio */
197     int         i_channels;
198     int         i_samplerate;
199     int         i_bitspersample;
200
201     es_descriptor_t *p_es;
202
203
204
205     vlc_bool_t      b_inited;
206     /* data to be send first */
207     int             i_data_init;
208     uint8_t         *p_data_init;
209
210     /* hack : it's for seek */
211     vlc_bool_t      b_search_keyframe;
212
213     /* informative */
214     char         *psz_name;
215     char         *psz_codec_name;
216     char         *psz_codec_settings;
217     char         *psz_codec_info_url;
218     char         *psz_codec_download_url;
219
220 } mkv_track_t;
221
222 typedef struct
223 {
224     int     i_track;
225     int     i_block_number;
226
227     int64_t i_position;
228     int64_t i_time;
229
230     vlc_bool_t b_key;
231 } mkv_index_t;
232
233 struct demux_sys_t
234 {
235     vlc_stream_io_callback  *in;
236     EbmlStream              *es;
237     EbmlParser              *ep;
238
239     /* time scale */
240     uint64_t                i_timescale;
241
242     /* duration of the segment */
243     float                   f_duration;
244
245     /* all tracks */
246     int                     i_track;
247     mkv_track_t             *track;
248
249     /* from seekhead */
250     int64_t                 i_cues_position;
251     int64_t                 i_chapters_position;
252     int64_t                 i_tags_position;
253
254     /* current data */
255     KaxSegment              *segment;
256     KaxCluster              *cluster;
257
258     mtime_t                 i_pts;
259
260     vlc_bool_t              b_cues;
261     int                     i_index;
262     int                     i_index_max;
263     mkv_index_t             *index;
264
265     /* info */
266     char                    *psz_muxing_application;
267     char                    *psz_writing_application;
268     char                    *psz_segment_filename;
269     char                    *psz_title;
270     char                    *psz_date_utc;
271 };
272
273 #define MKVD_TIMECODESCALE 1000000
274
275 static void IndexAppendCluster  ( input_thread_t *p_input, KaxCluster *cluster );
276 static char *UTF8ToStr          ( const UTFstring &u );
277 static void LoadCues            ( input_thread_t *);
278 static void InformationsCreate  ( input_thread_t *p_input );
279
280 static char *LanguageGetName    ( const char *psz_code );
281
282 /*****************************************************************************
283  * Activate: initializes matroska demux structures
284  *****************************************************************************/
285 static int Activate( vlc_object_t * p_this )
286 {
287     input_thread_t *p_input = (input_thread_t *)p_this;
288     demux_sys_t    *p_sys;
289     uint8_t        *p_peek;
290
291     int             i_track;
292     vlc_bool_t      b_audio_selected;
293     int             i_spu_channel, i_audio_channel;
294
295     EbmlElement     *el = NULL, *el1 = NULL, *el2 = NULL, *el3 = NULL, *el4 = NULL;
296
297
298     /* Initialize access plug-in structures. */
299     if( p_input->i_mtu == 0 )
300     {
301         /* Improve speed. */
302         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
303     }
304
305     /* Set the demux function */
306     p_input->pf_demux = Demux;
307
308     /* peek the begining */
309     if( input_Peek( p_input, &p_peek, 4 ) < 4 )
310     {
311         msg_Warn( p_input, "cannot peek" );
312         return VLC_EGENERIC;
313     }
314
315     /* is a valid file */
316     if( p_peek[0] != 0x1a || p_peek[1] != 0x45 || p_peek[2] != 0xdf || p_peek[3] != 0xa3 )
317     {
318         msg_Warn( p_input, "matroska module discarded "
319                            "(invalid header 0x%.2x%.2x%.2x%.2x)",
320                            p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
321         return VLC_EGENERIC;
322     }
323
324     p_input->p_demux_data = p_sys = (demux_sys_t*)malloc( sizeof( demux_sys_t ) );
325     memset( p_sys, 0, sizeof( demux_sys_t ) );
326
327     p_sys->in = new vlc_stream_io_callback( p_input );
328     p_sys->es = new EbmlStream( *p_sys->in );
329     p_sys->f_duration   = -1;
330     p_sys->i_timescale     = MKVD_TIMECODESCALE;
331     p_sys->i_track      = 0;
332     p_sys->track        = (mkv_track_t*)malloc( sizeof( mkv_track_t ) );
333     p_sys->i_pts   = 0;
334     p_sys->i_cues_position = -1;
335     p_sys->i_chapters_position = -1;
336     p_sys->i_tags_position = -1;
337
338     p_sys->b_cues       = VLC_FALSE;
339     p_sys->i_index      = 0;
340     p_sys->i_index_max  = 1024;
341     p_sys->index        = (mkv_index_t*)malloc( sizeof( mkv_index_t ) * p_sys->i_index_max );
342
343     p_sys->psz_muxing_application = NULL;
344     p_sys->psz_writing_application = NULL;
345     p_sys->psz_segment_filename = NULL;
346     p_sys->psz_title = NULL;
347     p_sys->psz_date_utc = NULL;;
348
349     if( p_sys->es == NULL )
350     {
351         msg_Err( p_input, "failed to create EbmlStream" );
352         delete p_sys->in;
353         free( p_sys );
354         return VLC_EGENERIC;
355     }
356     /* Find the EbmlHead element */
357     el = p_sys->es->FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL);
358     if( el == NULL )
359     {
360         msg_Err( p_input, "cannot find EbmlHead" );
361         goto error;
362     }
363     msg_Dbg( p_input, "EbmlHead" );
364     /* skip it */
365     el->SkipData( *p_sys->es, el->Generic().Context );
366     delete el;
367
368     /* Find a segment */
369     el = p_sys->es->FindNextID( KaxSegment::ClassInfos, 0xFFFFFFFFL);
370     if( el == NULL )
371     {
372         msg_Err( p_input, "cannot find KaxSegment" );
373         goto error;
374     }
375     msg_Dbg( p_input, "+ Segment" );
376     p_sys->segment = (KaxSegment*)el;
377     p_sys->cluster = NULL;
378
379     p_sys->ep = new EbmlParser( p_sys->es, el );
380
381     while( ( el1 = p_sys->ep->Get() ) != NULL )
382     {
383         if( EbmlId( *el1 ) == KaxInfo::ClassInfos.GlobalId )
384         {
385             msg_Dbg( p_input, "|   + Informations" );
386
387             p_sys->ep->Down();
388             while( ( el2 = p_sys->ep->Get() ) != NULL )
389             {
390                 if( EbmlId( *el2 ) == KaxTimecodeScale::ClassInfos.GlobalId )
391                 {
392                     KaxTimecodeScale &tcs = *(KaxTimecodeScale*)el2;
393
394                     tcs.ReadData( p_sys->es->I_O() );
395                     p_sys->i_timescale = uint64(tcs);
396
397                     msg_Dbg( p_input, "|   |   + TimecodeScale="I64Fd,
398                              p_sys->i_timescale );
399                 }
400                 else if( EbmlId( *el2 ) == KaxDuration::ClassInfos.GlobalId )
401                 {
402                     KaxDuration &dur = *(KaxDuration*)el2;
403
404                     dur.ReadData( p_sys->es->I_O() );
405                     p_sys->f_duration = float(dur);
406
407                     msg_Dbg( p_input, "|   |   + Duration=%f", p_sys->f_duration );
408                 }
409                 else if( EbmlId( *el2 ) == KaxMuxingApp::ClassInfos.GlobalId )
410                 {
411                     KaxMuxingApp &mapp = *(KaxMuxingApp*)el2;
412
413                     mapp.ReadData( p_sys->es->I_O() );
414
415                     p_sys->psz_muxing_application = UTF8ToStr( UTFstring( mapp ) );
416
417                     msg_Dbg( p_input, "|   |   + Muxing Application=%s", p_sys->psz_muxing_application );
418                 }
419                 else if( EbmlId( *el2 ) == KaxWritingApp::ClassInfos.GlobalId )
420                 {
421                     KaxWritingApp &wapp = *(KaxWritingApp*)el2;
422
423                     wapp.ReadData( p_sys->es->I_O() );
424
425                     p_sys->psz_writing_application = UTF8ToStr( UTFstring( wapp ) );
426
427                     msg_Dbg( p_input, "|   |   + Wrinting Application=%s", p_sys->psz_writing_application );
428                 }
429                 else if( EbmlId( *el2 ) == KaxSegmentFilename::ClassInfos.GlobalId )
430                 {
431                     KaxSegmentFilename &sfn = *(KaxSegmentFilename*)el2;
432
433                     sfn.ReadData( p_sys->es->I_O() );
434
435                     p_sys->psz_segment_filename = UTF8ToStr( UTFstring( sfn ) );
436
437                     msg_Dbg( p_input, "|   |   + Segment Filename=%s", p_sys->psz_segment_filename );
438                 }
439                 else if( EbmlId( *el2 ) == KaxTitle::ClassInfos.GlobalId )
440                 {
441                     KaxTitle &title = *(KaxTitle*)el2;
442
443                     title.ReadData( p_sys->es->I_O() );
444
445                     p_sys->psz_title = UTF8ToStr( UTFstring( title ) );
446
447                     msg_Dbg( p_input, "|   |   + Title=%s", p_sys->psz_title );
448                 }
449 #ifdef HAVE_GMTIME_R
450                 else if( EbmlId( *el2 ) == KaxDateUTC::ClassInfos.GlobalId )
451                 {
452                     KaxDateUTC &date = *(KaxDateUTC*)el2;
453                     time_t i_date;
454                     struct tm tmres;
455                     char   buffer[256];
456
457                     date.ReadData( p_sys->es->I_O() );
458
459                     i_date = date.GetEpochDate();
460                     memset( buffer, 0, 256 );
461                     if( gmtime_r( &i_date, &tmres ) &&
462                         asctime_r( &tmres, buffer ) )
463                     {
464                         buffer[strlen( buffer)-1]= '\0';
465                         p_sys->psz_date_utc = strdup( buffer );
466                         msg_Dbg( p_input, "|   |   + Date=%s", p_sys->psz_date_utc );
467                     }
468                 }
469 #endif
470                 else
471                 {
472                     msg_Dbg( p_input, "|   |   + Unknown (%s)", typeid(*el2).name() );
473                 }
474             }
475             p_sys->ep->Up();
476         }
477         else if( EbmlId( *el1 ) == KaxTracks::ClassInfos.GlobalId )
478         {
479             msg_Dbg( p_input, "|   + Tracks" );
480
481             p_sys->ep->Down();
482             while( ( el2 = p_sys->ep->Get() ) != NULL )
483             {
484                 if( EbmlId( *el2 ) == KaxTrackEntry::ClassInfos.GlobalId )
485                 {
486                     msg_Dbg( p_input, "|   |   + Track Entry" );
487
488                     p_sys->i_track++;
489                     p_sys->track = (mkv_track_t*)realloc( p_sys->track, sizeof( mkv_track_t ) * (p_sys->i_track + 1 ) );
490 #define tk  p_sys->track[p_sys->i_track - 1]
491                     memset( &tk, 0, sizeof( mkv_track_t ) );
492                     tk.i_cat = UNKNOWN_ES;
493                     tk.b_default = VLC_TRUE;
494                     tk.b_enabled = VLC_TRUE;
495                     tk.i_number = p_sys->i_track - 1;
496                     tk.i_extra_data = 0;
497                     tk.p_extra_data = NULL;
498                     tk.i_codec = 0;
499                     tk.psz_codec = NULL;
500                     tk.psz_language = NULL;
501                     tk.i_default_duration = 0;
502                     tk.f_timecodescale = 1.0;
503
504                     tk.b_inited = VLC_FALSE;
505                     tk.i_data_init = 0;
506                     tk.p_data_init = NULL;
507
508                     tk.psz_name = NULL;
509                     tk.psz_codec_name = NULL;
510                     tk.psz_codec_settings = NULL;
511                     tk.psz_codec_info_url = NULL;
512                     tk.psz_codec_download_url = NULL;
513
514                     p_sys->ep->Down();
515
516                     while( ( el3 = p_sys->ep->Get() ) != NULL )
517                     {
518                         if( EbmlId( *el3 ) == KaxTrackNumber::ClassInfos.GlobalId )
519                         {
520                             KaxTrackNumber &tnum = *(KaxTrackNumber*)el3;
521                             tnum.ReadData( p_sys->es->I_O() );
522
523                             tk.i_number = uint32( tnum );
524                             msg_Dbg( p_input, "|   |   |   + Track Number=%u", uint32( tnum ) );
525                         }
526                         else  if( EbmlId( *el3 ) == KaxTrackUID::ClassInfos.GlobalId )
527                         {
528                             KaxTrackUID &tuid = *(KaxTrackUID*)el3;
529                             tuid.ReadData( p_sys->es->I_O() );
530
531                             msg_Dbg( p_input, "|   |   |   + Track UID=%u", uint32( tuid ) );
532                         }
533                         else  if( EbmlId( *el3 ) == KaxTrackType::ClassInfos.GlobalId )
534                         {
535                             char *psz_type;
536                             KaxTrackType &ttype = *(KaxTrackType*)el3;
537                             ttype.ReadData( p_sys->es->I_O() );
538                             switch( uint8(ttype) )
539                             {
540                                 case track_audio:
541                                     psz_type = "audio";
542                                     tk.i_cat = AUDIO_ES;
543                                     break;
544                                 case track_video:
545                                     psz_type = "video";
546                                     tk.i_cat = VIDEO_ES;
547                                     break;
548                                 case track_subtitle:
549                                     psz_type = "subtitle";
550                                     tk.i_cat = SPU_ES;
551                                     break;
552                                 default:
553                                     psz_type = "unknown";
554                                     tk.i_cat = UNKNOWN_ES;
555                                     break;
556                             }
557
558                             msg_Dbg( p_input, "|   |   |   + Track Type=%s",
559                                      psz_type );
560                         }
561                         else  if( EbmlId( *el3 ) == KaxTrackFlagEnabled::ClassInfos.GlobalId )
562                         {
563                             KaxTrackFlagEnabled &fenb = *(KaxTrackFlagEnabled*)el3;
564                             fenb.ReadData( p_sys->es->I_O() );
565
566                             tk.b_enabled = uint32( fenb );
567                             msg_Dbg( p_input, "|   |   |   + Track Enabled=%u",
568                                      uint32( fenb )  );
569                         }
570                         else  if( EbmlId( *el3 ) == KaxTrackFlagDefault::ClassInfos.GlobalId )
571                         {
572                             KaxTrackFlagDefault &fdef = *(KaxTrackFlagDefault*)el3;
573                             fdef.ReadData( p_sys->es->I_O() );
574
575                             tk.b_default = uint32( fdef );
576                             msg_Dbg( p_input, "|   |   |   + Track Default=%u",
577                                      uint32( fdef )  );
578                         }
579                         else  if( EbmlId( *el3 ) == KaxTrackFlagLacing::ClassInfos.GlobalId )
580                         {
581                             KaxTrackFlagLacing &lac = *(KaxTrackFlagLacing*)el3;
582                             lac.ReadData( p_sys->es->I_O() );
583
584                             msg_Dbg( p_input, "|   |   |   + Track Lacing=%d",
585                                      uint32( lac ) );
586                         }
587                         else  if( EbmlId( *el3 ) == KaxTrackMinCache::ClassInfos.GlobalId )
588                         {
589                             KaxTrackMinCache &cmin = *(KaxTrackMinCache*)el3;
590                             cmin.ReadData( p_sys->es->I_O() );
591
592                             msg_Dbg( p_input, "|   |   |   + Track MinCache=%d",
593                                      uint32( cmin ) );
594                         }
595                         else  if( EbmlId( *el3 ) == KaxTrackMaxCache::ClassInfos.GlobalId )
596                         {
597                             KaxTrackMaxCache &cmax = *(KaxTrackMaxCache*)el3;
598                             cmax.ReadData( p_sys->es->I_O() );
599
600                             msg_Dbg( p_input, "|   |   |   + Track MaxCache=%d",
601                                      uint32( cmax ) );
602                         }
603                         else  if( EbmlId( *el3 ) == KaxTrackDefaultDuration::ClassInfos.GlobalId )
604                         {
605                             KaxTrackDefaultDuration &defd = *(KaxTrackDefaultDuration*)el3;
606                             defd.ReadData( p_sys->es->I_O() );
607
608                             tk.i_default_duration = uint64(defd);
609                             msg_Dbg( p_input, "|   |   |   + Track Default Duration="I64Fd, uint64(defd) );
610                         }
611                         else  if( EbmlId( *el3 ) == KaxTrackTimecodeScale::ClassInfos.GlobalId )
612                         {
613                             KaxTrackTimecodeScale &ttcs = *(KaxTrackTimecodeScale*)el3;
614                             ttcs.ReadData( p_sys->es->I_O() );
615
616                             tk.f_timecodescale = float( ttcs );
617                             msg_Dbg( p_input, "|   |   |   + Track TimeCodeScale=%f", tk.f_timecodescale );
618                         }
619                         else if( EbmlId( *el3 ) == KaxTrackName::ClassInfos.GlobalId )
620                         {
621                             KaxTrackName &tname = *(KaxTrackName*)el3;
622                             tname.ReadData( p_sys->es->I_O() );
623
624                             tk.psz_name = UTF8ToStr( UTFstring( tname ) );
625                             msg_Dbg( p_input, "|   |   |   + Track Name=%s",
626                                      tk.psz_name );
627                         }
628                         else  if( EbmlId( *el3 ) == KaxTrackLanguage::ClassInfos.GlobalId )
629                         {
630                             KaxTrackLanguage &lang = *(KaxTrackLanguage*)el3;
631                             lang.ReadData( p_sys->es->I_O() );
632
633                             tk.psz_language =
634                                 LanguageGetName( string( lang ).c_str() );
635                             msg_Dbg( p_input,
636                                      "|   |   |   + Track Language=`%s'(%s) ",
637                                      tk.psz_language, string( lang ).c_str() );
638                         }
639                         else  if( EbmlId( *el3 ) == KaxCodecID::ClassInfos.GlobalId )
640                         {
641                             KaxCodecID &codecid = *(KaxCodecID*)el3;
642                             codecid.ReadData( p_sys->es->I_O() );
643
644                             tk.psz_codec = strdup( string( codecid ).c_str() );
645                             msg_Dbg( p_input, "|   |   |   + Track CodecId=%s",
646                                      string( codecid ).c_str() );
647                         }
648                         else  if( EbmlId( *el3 ) == KaxCodecPrivate::ClassInfos.GlobalId )
649                         {
650                             KaxCodecPrivate &cpriv = *(KaxCodecPrivate*)el3;
651                             cpriv.ReadData( p_sys->es->I_O() );
652
653                             tk.i_extra_data = cpriv.GetSize();
654                             if( tk.i_extra_data > 0 )
655                             {
656                                 tk.p_extra_data = (uint8_t*)malloc( tk.i_extra_data );
657                                 memcpy( tk.p_extra_data, cpriv.GetBuffer(), tk.i_extra_data );
658                             }
659                             msg_Dbg( p_input, "|   |   |   + Track CodecPrivate size="I64Fd, cpriv.GetSize() );
660                         }
661                         else if( EbmlId( *el3 ) == KaxCodecName::ClassInfos.GlobalId )
662                         {
663                             KaxCodecName &cname = *(KaxCodecName*)el3;
664                             cname.ReadData( p_sys->es->I_O() );
665
666                             tk.psz_codec_name = UTF8ToStr( UTFstring( cname ) );
667                             msg_Dbg( p_input, "|   |   |   + Track Codec Name=%s", tk.psz_codec_name );
668                         }
669                         else if( EbmlId( *el3 ) == KaxCodecSettings::ClassInfos.GlobalId )
670                         {
671                             KaxCodecSettings &cset = *(KaxCodecSettings*)el3;
672                             cset.ReadData( p_sys->es->I_O() );
673
674                             tk.psz_codec_settings = UTF8ToStr( UTFstring( cset ) );
675                             msg_Dbg( p_input, "|   |   |   + Track Codec Settings=%s", tk.psz_codec_settings );
676                         }
677                         else if( EbmlId( *el3 ) == KaxCodecInfoURL::ClassInfos.GlobalId )
678                         {
679                             KaxCodecInfoURL &ciurl = *(KaxCodecInfoURL*)el3;
680                             ciurl.ReadData( p_sys->es->I_O() );
681
682                             tk.psz_codec_info_url = strdup( string( ciurl ).c_str() );
683                             msg_Dbg( p_input, "|   |   |   + Track Codec Info URL=%s", tk.psz_codec_info_url );
684                         }
685                         else if( EbmlId( *el3 ) == KaxCodecDownloadURL::ClassInfos.GlobalId )
686                         {
687                             KaxCodecDownloadURL &cdurl = *(KaxCodecDownloadURL*)el3;
688                             cdurl.ReadData( p_sys->es->I_O() );
689
690                             tk.psz_codec_download_url = strdup( string( cdurl ).c_str() );
691                             msg_Dbg( p_input, "|   |   |   + Track Codec Info URL=%s", tk.psz_codec_download_url );
692                         }
693                         else if( EbmlId( *el3 ) == KaxCodecDecodeAll::ClassInfos.GlobalId )
694                         {
695                             KaxCodecDecodeAll &cdall = *(KaxCodecDecodeAll*)el3;
696                             cdall.ReadData( p_sys->es->I_O() );
697
698                             msg_Dbg( p_input, "|   |   |   + Track Codec Decode All=%u <== UNUSED", uint8( cdall ) );
699                         }
700                         else if( EbmlId( *el3 ) == KaxTrackOverlay::ClassInfos.GlobalId )
701                         {
702                             KaxTrackOverlay &tovr = *(KaxTrackOverlay*)el3;
703                             tovr.ReadData( p_sys->es->I_O() );
704
705                             msg_Dbg( p_input, "|   |   |   + Track Overlay=%u <== UNUSED", uint32( tovr ) );
706                         }
707                         else  if( EbmlId( *el3 ) == KaxTrackVideo::ClassInfos.GlobalId )
708                         {
709                             msg_Dbg( p_input, "|   |   |   + Track Video" );
710                             tk.i_width  = 0;
711                             tk.i_height = 0;
712                             tk.i_display_width  = 0;
713                             tk.i_display_height = 0;
714                             tk.f_fps = 0.0;
715
716                             p_sys->ep->Down();
717
718                             while( ( el4 = p_sys->ep->Get() ) != NULL )
719                             {
720                                 if( EbmlId( *el4 ) == KaxVideoFlagInterlaced::ClassInfos.GlobalId )
721                                 {
722                                     KaxVideoFlagInterlaced &fint = *(KaxVideoFlagInterlaced*)el4;
723                                     fint.ReadData( p_sys->es->I_O() );
724
725                                     msg_Dbg( p_input, "|   |   |   |   + Track Video Interlaced=%u", uint8( fint ) );
726                                 }
727                                 else if( EbmlId( *el4 ) == KaxVideoStereoMode::ClassInfos.GlobalId )
728                                 {
729                                     KaxVideoStereoMode &stereo = *(KaxVideoStereoMode*)el4;
730                                     stereo.ReadData( p_sys->es->I_O() );
731
732                                     msg_Dbg( p_input, "|   |   |   |   + Track Video Stereo Mode=%u", uint8( stereo ) );
733                                 }
734                                 else if( EbmlId( *el4 ) == KaxVideoPixelWidth::ClassInfos.GlobalId )
735                                 {
736                                     KaxVideoPixelWidth &vwidth = *(KaxVideoPixelWidth*)el4;
737                                     vwidth.ReadData( p_sys->es->I_O() );
738
739                                     tk.i_width = uint16( vwidth );
740                                     msg_Dbg( p_input, "|   |   |   |   + width=%d", uint16( vwidth ) );
741                                 }
742                                 else if( EbmlId( *el4 ) == KaxVideoPixelHeight::ClassInfos.GlobalId )
743                                 {
744                                     KaxVideoPixelWidth &vheight = *(KaxVideoPixelWidth*)el4;
745                                     vheight.ReadData( p_sys->es->I_O() );
746
747                                     tk.i_height = uint16( vheight );
748                                     msg_Dbg( p_input, "|   |   |   |   + height=%d", uint16( vheight ) );
749                                 }
750                                 else if( EbmlId( *el4 ) == KaxVideoDisplayWidth::ClassInfos.GlobalId )
751                                 {
752                                     KaxVideoDisplayWidth &vwidth = *(KaxVideoDisplayWidth*)el4;
753                                     vwidth.ReadData( p_sys->es->I_O() );
754
755                                     tk.i_display_width = uint16( vwidth );
756                                     msg_Dbg( p_input, "|   |   |   |   + display width=%d", uint16( vwidth ) );
757                                 }
758                                 else if( EbmlId( *el4 ) == KaxVideoDisplayHeight::ClassInfos.GlobalId )
759                                 {
760                                     KaxVideoDisplayWidth &vheight = *(KaxVideoDisplayWidth*)el4;
761                                     vheight.ReadData( p_sys->es->I_O() );
762
763                                     tk.i_display_height = uint16( vheight );
764                                     msg_Dbg( p_input, "|   |   |   |   + display height=%d", uint16( vheight ) );
765                                 }
766                                 else if( EbmlId( *el4 ) == KaxVideoFrameRate::ClassInfos.GlobalId )
767                                 {
768                                     KaxVideoFrameRate &vfps = *(KaxVideoFrameRate*)el4;
769                                     vfps.ReadData( p_sys->es->I_O() );
770
771                                     tk.f_fps = float( vfps );
772                                     msg_Dbg( p_input, "   |   |   |   + fps=%f", float( vfps ) );
773                                 }
774                                 else if( EbmlId( *el4 ) == KaxVideoDisplayUnit::ClassInfos.GlobalId )
775                                 {
776                                      KaxVideoDisplayUnit &vdmode = *(KaxVideoDisplayUnit*)el4;
777                                     vdmode.ReadData( p_sys->es->I_O() );
778
779                                     msg_Dbg( p_input, "|   |   |   |   + Track Video Display Unit=%s",
780                                              uint8( vdmode ) == 0 ? "pixels" : ( uint8( vdmode ) == 1 ? "centimeters": "inches" ) );
781                                 }
782                                 else if( EbmlId( *el4 ) == KaxVideoAspectRatio::ClassInfos.GlobalId )
783                                 {
784                                     KaxVideoAspectRatio &ratio = *(KaxVideoAspectRatio*)el4;
785                                     ratio.ReadData( p_sys->es->I_O() );
786
787                                     msg_Dbg( p_input, "   |   |   |   + Track Video Aspect Ratio Type=%u", uint8( ratio ) );
788                                 }
789                                 else if( EbmlId( *el4 ) == KaxVideoGamma::ClassInfos.GlobalId )
790                                 {
791                                     KaxVideoGamma &gamma = *(KaxVideoGamma*)el4;
792                                     gamma.ReadData( p_sys->es->I_O() );
793
794                                     msg_Dbg( p_input, "   |   |   |   + fps=%f", float( gamma ) );
795                                 }
796                                 else
797                                 {
798                                     msg_Dbg( p_input, "|   |   |   |   + Unknown (%s)", typeid(*el4).name() );
799                                 }
800                             }
801                             p_sys->ep->Up();
802                         }
803                         else  if( EbmlId( *el3 ) == KaxTrackAudio::ClassInfos.GlobalId )
804                         {
805                             msg_Dbg( p_input, "|   |   |   + Track Audio" );
806                             tk.i_channels = 0;
807                             tk.i_samplerate = 0;
808                             tk.i_bitspersample = 0;
809
810                             p_sys->ep->Down();
811
812                             while( ( el4 = p_sys->ep->Get() ) != NULL )
813                             {
814                                 if( EbmlId( *el4 ) == KaxAudioSamplingFreq::ClassInfos.GlobalId )
815                                 {
816                                     KaxAudioSamplingFreq &afreq = *(KaxAudioSamplingFreq*)el4;
817                                     afreq.ReadData( p_sys->es->I_O() );
818
819                                     tk.i_samplerate = (int)float( afreq );
820                                     msg_Dbg( p_input, "|   |   |   |   + afreq=%d", tk.i_samplerate );
821                                 }
822                                 else if( EbmlId( *el4 ) == KaxAudioChannels::ClassInfos.GlobalId )
823                                 {
824                                     KaxAudioChannels &achan = *(KaxAudioChannels*)el4;
825                                     achan.ReadData( p_sys->es->I_O() );
826
827                                     tk.i_channels = uint8( achan );
828                                     msg_Dbg( p_input, "|   |   |   |   + achan=%u", uint8( achan ) );
829                                 }
830                                 else if( EbmlId( *el4 ) == KaxAudioBitDepth::ClassInfos.GlobalId )
831                                 {
832                                     KaxAudioBitDepth &abits = *(KaxAudioBitDepth*)el4;
833                                     abits.ReadData( p_sys->es->I_O() );
834
835                                     tk.i_bitspersample = uint8( abits );
836                                     msg_Dbg( p_input, "|   |   |   |   + abits=%u", uint8( abits ) );
837                                 }
838                                 else
839                                 {
840                                     msg_Dbg( p_input, "|   |   |   |   + Unknown (%s)", typeid(*el4).name() );
841                                 }
842                             }
843                             p_sys->ep->Up();
844                         }
845                         else
846                         {
847                             msg_Dbg( p_input, "|   |   |   + Unknown (%s)", typeid(*el3).name() );
848                         }
849                     }
850                     p_sys->ep->Up();
851                 }
852                 else
853                 {
854                     msg_Dbg( p_input, "|   |   + Unknown (%s)", typeid(*el2).name() );
855                 }
856 #undef tk
857             }
858             p_sys->ep->Up();
859         }
860         else if( EbmlId( *el1 ) == KaxSeekHead::ClassInfos.GlobalId )
861         {
862             msg_Dbg( p_input, "|   + Seek head" );
863             p_sys->ep->Down();
864             while( ( el = p_sys->ep->Get() ) != NULL )
865             {
866                 if( EbmlId( *el ) == KaxSeek::ClassInfos.GlobalId )
867                 {
868                     EbmlId id = EbmlVoid::ClassInfos.GlobalId;
869                     int64_t i_pos = -1;
870
871                     //msg_Dbg( p_input, "|   |   + Seek" );
872                     p_sys->ep->Down();
873                     while( ( el = p_sys->ep->Get() ) != NULL )
874                     {
875                         if( EbmlId( *el ) == KaxSeekID::ClassInfos.GlobalId )
876                         {
877                             KaxSeekID &sid = *(KaxSeekID*)el;
878
879                             sid.ReadData( p_sys->es->I_O() );
880
881                             id = EbmlId( sid.GetBuffer(), sid.GetSize() );
882                         }
883                         else  if( EbmlId( *el ) == KaxSeekPosition::ClassInfos.GlobalId )
884                         {
885                             KaxSeekPosition &spos = *(KaxSeekPosition*)el;
886
887                             spos.ReadData( p_sys->es->I_O() );
888
889                             i_pos = uint64( spos );
890                         }
891                         else
892                         {
893                             msg_Dbg( p_input, "|   |   |   + Unknown (%s)", typeid(*el).name() );
894                         }
895                     }
896                     p_sys->ep->Up();
897
898                     if( i_pos >= 0 )
899                     {
900                         if( id == KaxCues::ClassInfos.GlobalId )
901                         {
902                             msg_Dbg( p_input, "|   |   |   = cues at "I64Fd, i_pos );
903                             p_sys->i_cues_position = p_sys->segment->GetGlobalPosition( i_pos );
904                         }
905                         else if( id == KaxChapters::ClassInfos.GlobalId )
906                         {
907                             msg_Dbg( p_input, "|   |   |   = chapters at "I64Fd, i_pos );
908                             p_sys->i_chapters_position = p_sys->segment->GetGlobalPosition( i_pos );
909                         }
910                         else if( id == KaxTags::ClassInfos.GlobalId )
911                         {
912                             msg_Dbg( p_input, "|   |   |   = tags at "I64Fd, i_pos );
913                             p_sys->i_tags_position = p_sys->segment->GetGlobalPosition( i_pos );
914                         }
915
916                     }
917                 }
918                 else
919                 {
920                     msg_Dbg( p_input, "|   |   + Unknown (%s)", typeid(*el).name() );
921                 }
922             }
923             p_sys->ep->Up();
924         }
925         else if( EbmlId( *el1 ) == KaxCues::ClassInfos.GlobalId )
926         {
927             msg_Dbg( p_input, "|   + Cues" );
928         }
929         else if( EbmlId( *el1 ) == KaxCluster::ClassInfos.GlobalId )
930         {
931             msg_Dbg( p_input, "|   + Cluster" );
932
933             p_sys->cluster = (KaxCluster*)el1;
934
935             p_sys->ep->Down();
936             /* stop parsing the stream */
937             break;
938         }
939 #ifdef HAVE_MATROSKA_KAXATTACHMENTS_H
940         else if( EbmlId( *el1 ) == KaxAttachments::ClassInfos.GlobalId )
941 #else
942         else if( EbmlId( *el1 ) == KaxAttachements::ClassInfos.GlobalId )
943 #endif
944         {
945             msg_Dbg( p_input, "|   + Attachments FIXME TODO (but probably never supported)" );
946         }
947         else if( EbmlId( *el1 ) == KaxChapters::ClassInfos.GlobalId )
948         {
949             msg_Dbg( p_input, "|   + Chapters FIXME TODO" );
950         }
951         else if( EbmlId( *el1 ) == KaxTag::ClassInfos.GlobalId )
952         {
953             msg_Dbg( p_input, "|   + Tags FIXME TODO" );
954         }
955         else
956         {
957             msg_Dbg( p_input, "|   + Unknown (%s)", typeid(*el1).name() );
958         }
959     }
960
961     if( p_sys->cluster == NULL )
962     {
963         msg_Err( p_input, "cannot find any cluster, damaged file ?" );
964         goto error;
965     }
966
967     if( p_sys->i_chapters_position >= 0 )
968     {
969         msg_Warn( p_input, "chapters unsupported" );
970     }
971
972     /* *** Load the cue if found *** */
973     if( p_sys->i_cues_position >= 0 && p_input->stream.b_seekable )
974     {
975         LoadCues( p_input );
976     }
977
978     if( !p_sys->b_cues || p_sys->i_index <= 0 )
979     {
980         msg_Warn( p_input, "no cues/empty cues found -> seek won't be precise" );
981
982         IndexAppendCluster( p_input, p_sys->cluster );
983
984         p_sys->b_cues = VLC_FALSE;
985     }
986
987     /* Create one program */
988     vlc_mutex_lock( &p_input->stream.stream_lock );
989     if( input_InitStream( p_input, 0 ) == -1)
990     {
991         vlc_mutex_unlock( &p_input->stream.stream_lock );
992         msg_Err( p_input, "cannot init stream" );
993         goto error;
994     }
995     if( input_AddProgram( p_input, 0, 0) == NULL )
996     {
997         vlc_mutex_unlock( &p_input->stream.stream_lock );
998         msg_Err( p_input, "cannot add program" );
999         goto error;
1000     }
1001     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
1002     if( p_sys->f_duration > 1001.0 )
1003     {
1004         mtime_t i_duration = (mtime_t)( p_sys->f_duration / 1000.0 );
1005         p_input->stream.i_mux_rate = p_input->stream.p_selected_area->i_size / 50 / i_duration;
1006     }
1007     else
1008     {
1009         p_input->stream.i_mux_rate = 0;
1010     }
1011     vlc_mutex_unlock( &p_input->stream.stream_lock );
1012
1013     /* add all es */
1014     msg_Dbg( p_input, "found %d es", p_sys->i_track );
1015     for( i_track = 0; i_track < p_sys->i_track; i_track++ )
1016     {
1017 #define tk  p_sys->track[i_track]
1018         if( tk.i_cat == UNKNOWN_ES )
1019         {
1020             msg_Warn( p_input, "invalid track[%d, n=%d]", i_track, tk.i_number );
1021             tk.p_es = NULL;
1022             continue;
1023         }
1024         tk.p_es = input_AddES( p_input,
1025                                p_input->stream.p_selected_program,
1026                                i_track + 1,
1027                                tk.i_cat,
1028                                tk.psz_language, 0 );
1029         if( !strcmp( tk.psz_codec, "V_MS/VFW/FOURCC" ) )
1030         {
1031             if( tk.i_extra_data < (int)sizeof( BITMAPINFOHEADER ) )
1032             {
1033                 msg_Err( p_input, "missing/invalid BITMAPINFOHEADER" );
1034                 tk.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
1035             }
1036             else
1037             {
1038                 BITMAPINFOHEADER *p_bih = (BITMAPINFOHEADER*)tk.p_extra_data;
1039
1040                 p_bih->biSize           = GetDWLE( &p_bih->biSize );
1041                 p_bih->biWidth          = GetDWLE( &p_bih->biWidth );
1042                 p_bih->biHeight         = GetDWLE( &p_bih->biHeight );
1043                 p_bih->biPlanes         = GetWLE( &p_bih->biPlanes );
1044                 p_bih->biBitCount       = GetWLE( &p_bih->biBitCount );
1045                 p_bih->biCompression    = GetFOURCC( &p_bih->biCompression );
1046                 p_bih->biSizeImage      = GetDWLE( &p_bih->biSizeImage );
1047                 p_bih->biXPelsPerMeter  = GetDWLE( &p_bih->biXPelsPerMeter );
1048                 p_bih->biYPelsPerMeter  = GetDWLE( &p_bih->biYPelsPerMeter );
1049                 p_bih->biClrUsed        = GetDWLE( &p_bih->biClrUsed );
1050                 p_bih->biClrImportant   = GetDWLE( &p_bih->biClrImportant );
1051
1052
1053                 tk.i_codec = p_bih->biCompression;
1054                 tk.p_es->p_bitmapinfoheader = p_bih;
1055             }
1056         }
1057         else if( !strcmp( tk.psz_codec, "V_MPEG1" ) ||
1058                  !strcmp( tk.psz_codec, "V_MPEG2" ) )
1059         {
1060             tk.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'v' );
1061         }
1062         else if( !strncmp( tk.psz_codec, "V_MPEG4", 7 ) )
1063         {
1064             BITMAPINFOHEADER *p_bih;
1065
1066             tk.i_extra_data = sizeof( BITMAPINFOHEADER );
1067             tk.p_extra_data = (uint8_t*)malloc( tk.i_extra_data );
1068
1069             p_bih = (BITMAPINFOHEADER*)tk.p_extra_data;
1070             memset( p_bih, 0, sizeof( BITMAPINFOHEADER ) );
1071             p_bih->biSize  = sizeof( BITMAPINFOHEADER );
1072             p_bih->biWidth = tk.i_width;
1073             p_bih->biHeight= tk.i_height;
1074
1075             if( !strcmp( tk.psz_codec, "V_MPEG4/MS/V3" ) )
1076             {
1077                 tk.i_codec = VLC_FOURCC( 'D', 'I', 'V', '3' );
1078             }
1079             else
1080             {
1081                 tk.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' );
1082             }
1083         }
1084         else if( !strcmp( tk.psz_codec, "A_MS/ACM" ) )
1085         {
1086             if( tk.i_extra_data < (int)sizeof( WAVEFORMATEX ) )
1087             {
1088                 msg_Err( p_input, "missing/invalid WAVEFORMATEX" );
1089                 tk.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
1090             }
1091             else
1092             {
1093                 WAVEFORMATEX *p_wf = (WAVEFORMATEX*)tk.p_extra_data;
1094
1095                 p_wf->wFormatTag        = GetWLE( &p_wf->wFormatTag );
1096                 p_wf->nChannels         = GetWLE( &p_wf->nChannels );
1097                 p_wf->nSamplesPerSec    = GetDWLE( &p_wf->nSamplesPerSec );
1098                 p_wf->nAvgBytesPerSec   = GetDWLE( &p_wf->nAvgBytesPerSec );
1099                 p_wf->nBlockAlign       = GetWLE( &p_wf->nBlockAlign );
1100                 p_wf->wBitsPerSample    = GetWLE( &p_wf->wBitsPerSample );
1101                 p_wf->cbSize            = GetWLE( &p_wf->cbSize );
1102
1103                 wf_tag_to_fourcc( p_wf->wFormatTag, &tk.i_codec, NULL );
1104                 tk.p_es->p_waveformatex = p_wf;
1105             }
1106         }
1107         else if( !strcmp( tk.psz_codec, "A_MPEG/L3" ) ||
1108                  !strcmp( tk.psz_codec, "A_MPEG/L2" ) ||
1109                  !strcmp( tk.psz_codec, "A_MPEG/L1" ) )
1110         {
1111             tk.i_codec = VLC_FOURCC( 'm', 'p', 'g', 'a' );
1112         }
1113         else if( !strcmp( tk.psz_codec, "A_AC3" ) )
1114         {
1115             tk.i_codec = VLC_FOURCC( 'a', '5', '2', ' ' );
1116         }
1117         else if( !strcmp( tk.psz_codec, "A_DTS" ) )
1118         {
1119             tk.i_codec = VLC_FOURCC( 'd', 't', 's', ' ' );
1120         }
1121         else if( !strcmp( tk.psz_codec, "A_VORBIS" ) )
1122         {
1123             tk.i_codec = VLC_FOURCC( 'v', 'o', 'r', 'b' );
1124             tk.i_data_init = tk.i_extra_data;
1125             tk.p_data_init = tk.p_extra_data;
1126         }
1127         else if( !strncmp( tk.psz_codec, "A_AAC/MPEG2/", strlen( "A_AAC/MPEG2/" ) ) ||
1128                  !strncmp( tk.psz_codec, "A_AAC/MPEG4/", strlen( "A_AAC/MPEG4/" ) ) )
1129         {
1130             int i_profile, i_srate;
1131             static int i_sample_rates[] =
1132             {
1133                     96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
1134                         16000, 12000, 11025, 8000,  7350,  0,     0,     0
1135             };
1136             WAVEFORMATEX *p_wf;
1137
1138             tk.i_codec = VLC_FOURCC( 'm', 'p', '4', 'a' );
1139             /* create data for faad (MP4DecSpecificDescrTag)*/
1140
1141             if( !strcmp( &tk.psz_codec[12], "MAIN" ) )
1142             {
1143                 i_profile = 0;
1144             }
1145             else if( !strcmp( &tk.psz_codec[12], "LC" ) )
1146             {
1147                 i_profile = 1;
1148             }
1149             else if( !strcmp( &tk.psz_codec[12], "SSR" ) )
1150             {
1151                 i_profile = 2;
1152             }
1153             else
1154             {
1155                 i_profile = 3;
1156             }
1157
1158             for( i_srate = 0; i_srate < 13; i_srate++ )
1159             {
1160                 if( i_sample_rates[i_srate] == tk.i_samplerate )
1161                 {
1162                     break;
1163                 }
1164             }
1165             msg_Dbg( p_input, "profile=%d srate=%d", i_profile, i_srate );
1166
1167             tk.i_extra_data = sizeof( WAVEFORMATEX ) + 2;
1168             tk.p_extra_data = (uint8_t*)malloc( tk.i_extra_data );
1169             p_wf = (WAVEFORMATEX*)tk.p_extra_data;
1170
1171             p_wf->wFormatTag = WAVE_FORMAT_UNKNOWN;
1172             p_wf->nChannels  = tk.i_channels;
1173             p_wf->nSamplesPerSec = tk.i_samplerate;
1174             p_wf->nAvgBytesPerSec = 0;
1175             p_wf->nBlockAlign = 0;
1176             p_wf->wBitsPerSample = 0;
1177             p_wf->cbSize = 2;
1178
1179             tk.p_extra_data[sizeof( WAVEFORMATEX )+ 0] = ((i_profile + 1) << 3) | ((i_srate&0xe) >> 1);
1180             tk.p_extra_data[sizeof( WAVEFORMATEX )+ 1] = ((i_srate & 0x1) << 7) | (tk.i_channels << 3);
1181
1182             tk.p_es->p_waveformatex = p_wf;
1183         }
1184         else if( !strcmp( tk.psz_codec, "A_PCM/INT/BIG" ) ||
1185                  !strcmp( tk.psz_codec, "A_PCM/INT/LIT" ) ||
1186                  !strcmp( tk.psz_codec, "A_PCM/FLOAT/IEEE" ) )
1187         {
1188             WAVEFORMATEX *p_wf;
1189
1190             tk.i_extra_data = sizeof( WAVEFORMATEX );
1191             tk.p_extra_data = (uint8_t*)malloc( tk.i_extra_data );
1192
1193             p_wf = (WAVEFORMATEX*)tk.p_extra_data;
1194
1195             if( !strncmp( &tk.psz_codec[6], "INT", 3 ) )
1196             {
1197                 p_wf->wFormatTag = WAVE_FORMAT_PCM;
1198             }
1199             else
1200             {
1201                 p_wf->wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
1202             }
1203             p_wf->nChannels  = tk.i_channels;
1204             p_wf->nSamplesPerSec = tk.i_samplerate;
1205             p_wf->nAvgBytesPerSec = 0;
1206             p_wf->nBlockAlign = ( tk.i_bitspersample + 7 ) / 8 * tk.i_channels;
1207             p_wf->wBitsPerSample = tk.i_bitspersample;
1208             p_wf->cbSize = 0;
1209
1210             tk.p_es->p_waveformatex = p_wf;
1211
1212             if( !strcmp( tk.psz_codec, "A_PCM/INT/BIG" ) )
1213             {
1214                 tk.i_codec = VLC_FOURCC( 't', 'w', 'o', 's' );
1215             }
1216             else
1217             {
1218                 tk.i_codec = VLC_FOURCC( 'a', 'r', 'a', 'w' );
1219             }
1220         }
1221         else if( !strcmp( tk.psz_codec, "S_TEXT/UTF8" ) )
1222         {
1223             tk.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
1224         }
1225         else if( !strcmp( tk.psz_codec, "S_TEXT/SSA" ) )
1226         {
1227             tk.i_codec = VLC_FOURCC( 's', 'u', 'b', 't' );
1228         }
1229         else
1230         {
1231             msg_Err( p_input, "unknow codec id=`%s'", tk.psz_codec );
1232             tk.i_codec = VLC_FOURCC( 'u', 'n', 'd', 'f' );
1233         }
1234
1235         tk.p_es->i_fourcc = tk.i_codec;
1236 #undef tk
1237     }
1238
1239     /* select track all video, one audio, no spu TODO : improve */
1240     b_audio_selected = VLC_FALSE;
1241     i_audio_channel = 0;
1242     i_spu_channel = 0;
1243     for( i_track = 0; i_track < p_sys->i_track; i_track++ )
1244     {
1245 #define tk  p_sys->track[i_track]
1246         switch( tk.i_cat )
1247         {
1248             case VIDEO_ES:
1249                 vlc_mutex_lock( &p_input->stream.stream_lock );
1250                 input_SelectES( p_input, tk.p_es );
1251                 vlc_mutex_unlock( &p_input->stream.stream_lock );
1252                 break;
1253
1254             case AUDIO_ES:
1255                 if( ( !b_audio_selected && config_GetInt( p_input, "audio-channel" ) < 0 ) ||
1256                     i_audio_channel == config_GetInt( p_input, "audio-channel" ) )
1257                 {
1258                     vlc_mutex_lock( &p_input->stream.stream_lock );
1259                     input_SelectES( p_input, tk.p_es );
1260                     vlc_mutex_unlock( &p_input->stream.stream_lock );
1261
1262                     b_audio_selected = tk.p_es->p_decoder_fifo ? VLC_TRUE : VLC_FALSE;
1263                 }
1264                 i_audio_channel++;
1265                 break;
1266             case SPU_ES:
1267                 if( i_spu_channel == config_GetInt( p_input, "spu-channel" ) )
1268                 {
1269                     vlc_mutex_lock( &p_input->stream.stream_lock );
1270                     input_SelectES( p_input, tk.p_es );
1271                     vlc_mutex_unlock( &p_input->stream.stream_lock );
1272                 }
1273                 i_spu_channel++;
1274                 break;
1275         }
1276 #undef tk
1277     }
1278
1279     if( !b_audio_selected )
1280     {
1281         msg_Warn( p_input, "cannot find/select audio track" );
1282     }
1283
1284     /* add informations */
1285     InformationsCreate( p_input );
1286
1287     return VLC_SUCCESS;
1288
1289 error:
1290     delete p_sys->es;
1291     delete p_sys->in;
1292     free( p_sys );
1293     return VLC_EGENERIC;
1294 }
1295
1296 /*****************************************************************************
1297  * Deactivate: frees unused data
1298  *****************************************************************************/
1299 static void Deactivate( vlc_object_t *p_this )
1300 {
1301     input_thread_t *p_input = (input_thread_t *)p_this;
1302     demux_sys_t    *p_sys   = p_input->p_demux_data;
1303
1304     int             i_track;
1305
1306     for( i_track = 0; i_track < p_sys->i_track; i_track++ )
1307     {
1308 #define tk  p_sys->track[i_track]
1309         if( tk.psz_codec )
1310         {
1311             free( tk.psz_codec );
1312         }
1313         if( tk.psz_language )
1314         {
1315             free( tk.psz_language );
1316         }
1317 #undef tk
1318     }
1319     free( p_sys->track );
1320
1321     if( p_sys->psz_writing_application  )
1322     {
1323         free( p_sys->psz_writing_application );
1324     }
1325     if( p_sys->psz_muxing_application  )
1326     {
1327         free( p_sys->psz_muxing_application );
1328     }
1329
1330     delete p_sys->segment;
1331
1332     delete p_sys->ep;
1333     delete p_sys->es;
1334     delete p_sys->in;
1335
1336     free( p_sys );
1337 }
1338
1339 static int BlockGet( input_thread_t *p_input, KaxBlock **pp_block, int64_t *pi_ref1, int64_t *pi_ref2, int64_t *pi_duration )
1340 {
1341     demux_sys_t    *p_sys   = p_input->p_demux_data;
1342
1343     *pp_block = NULL;
1344     *pi_ref1  = -1;
1345     *pi_ref2  = -1;
1346
1347     for( ;; )
1348     {
1349         EbmlElement *el;
1350         int         i_level;
1351
1352         if( p_input->b_die )
1353         {
1354             return VLC_EGENERIC;
1355         }
1356
1357         el = p_sys->ep->Get();
1358         i_level = p_sys->ep->GetLevel();
1359
1360         if( el == NULL && *pp_block != NULL )
1361         {
1362             /* update the index */
1363 #define idx p_sys->index[p_sys->i_index - 1]
1364             if( p_sys->i_index > 0 && idx.i_time == -1 )
1365             {
1366                 idx.i_time        = (*pp_block)->GlobalTimecode() * (mtime_t) 1000 / p_sys->i_timescale;
1367                 idx.b_key         = *pi_ref1 == -1 ? VLC_TRUE : VLC_FALSE;
1368             }
1369 #undef idx
1370             return VLC_SUCCESS;
1371         }
1372
1373         if( el == NULL )
1374         {
1375             if( p_sys->ep->GetLevel() > 1 )
1376             {
1377                 p_sys->ep->Up();
1378                 continue;
1379             }
1380             msg_Warn( p_input, "EOF" );
1381             return VLC_EGENERIC;
1382         }
1383
1384         /* do parsing */
1385         if( i_level == 1 )
1386         {
1387             if( EbmlId( *el ) == KaxCluster::ClassInfos.GlobalId )
1388             {
1389                 p_sys->cluster = (KaxCluster*)el;
1390
1391                 /* add it to the index */
1392                 if( p_sys->i_index == 0 ||
1393                     ( p_sys->i_index > 0 && p_sys->index[p_sys->i_index - 1].i_position < (int64_t)p_sys->cluster->GetElementPosition() ) )
1394                 {
1395                     IndexAppendCluster( p_input, p_sys->cluster );
1396                 }
1397
1398                 p_sys->ep->Down();
1399             }
1400             else if( EbmlId( *el ) == KaxCues::ClassInfos.GlobalId )
1401             {
1402                 msg_Warn( p_input, "find KaxCues FIXME" );
1403                 return VLC_EGENERIC;
1404             }
1405             else
1406             {
1407                 msg_Dbg( p_input, "unknown (%s)", typeid( el ).name() );
1408             }
1409         }
1410         else if( i_level == 2 )
1411         {
1412             if( EbmlId( *el ) == KaxClusterTimecode::ClassInfos.GlobalId )
1413             {
1414                 KaxClusterTimecode &ctc = *(KaxClusterTimecode*)el;
1415
1416                 ctc.ReadData( p_sys->es->I_O() );
1417                 p_sys->cluster->InitTimecode( uint64( ctc ), p_sys->i_timescale );
1418             }
1419             else if( EbmlId( *el ) == KaxBlockGroup::ClassInfos.GlobalId )
1420             {
1421                 p_sys->ep->Down();
1422             }
1423         }
1424         else if( i_level == 3 )
1425         {
1426             if( EbmlId( *el ) == KaxBlock::ClassInfos.GlobalId )
1427             {
1428                 *pp_block = (KaxBlock*)el;
1429
1430                 (*pp_block)->ReadData( p_sys->es->I_O() );
1431                 (*pp_block)->SetParent( *p_sys->cluster );
1432
1433                 p_sys->ep->Keep();
1434             }
1435             else if( EbmlId( *el ) == KaxBlockDuration::ClassInfos.GlobalId )
1436             {
1437                 KaxBlockDuration &dur = *(KaxBlockDuration*)el;
1438
1439                 dur.ReadData( p_sys->es->I_O() );
1440                 *pi_duration = uint64( dur );
1441             }
1442             else if( EbmlId( *el ) == KaxReferenceBlock::ClassInfos.GlobalId )
1443             {
1444                 KaxReferenceBlock &ref = *(KaxReferenceBlock*)el;
1445
1446                 ref.ReadData( p_sys->es->I_O() );
1447                 if( *pi_ref1 == -1 )
1448                 {
1449                     *pi_ref1 = int64( ref );
1450                 }
1451                 else
1452                 {
1453                     *pi_ref2 = int64( ref );
1454                 }
1455             }
1456         }
1457         else
1458         {
1459             msg_Err( p_input, "invalid level = %d", i_level );
1460             return VLC_EGENERIC;
1461         }
1462     }
1463 }
1464
1465 static pes_packet_t *MemToPES( input_thread_t *p_input, uint8_t *p_mem, int i_mem )
1466 {
1467     pes_packet_t *p_pes;
1468     data_packet_t *p_data;
1469
1470     if( ( p_pes = input_NewPES( p_input->p_method_data ) ) == NULL )
1471     {
1472         return NULL;
1473     }
1474
1475     p_data = input_NewPacket( p_input->p_method_data, i_mem);
1476
1477     memcpy( p_data->p_payload_start, p_mem, i_mem );
1478     p_data->p_payload_end = p_data->p_payload_start + i_mem;
1479
1480     p_pes->p_first = p_pes->p_last = p_data;
1481     p_pes->i_nb_data = 1;
1482     p_pes->i_pes_size = i_mem;
1483
1484     return p_pes;
1485 }
1486
1487 static void BlockDecode( input_thread_t *p_input, KaxBlock *block, mtime_t i_pts, mtime_t i_duration )
1488 {
1489     demux_sys_t    *p_sys   = p_input->p_demux_data;
1490
1491     int             i_track;
1492     unsigned int    i;
1493
1494 #define tk  p_sys->track[i_track]
1495     for( i_track = 0; i_track < p_sys->i_track; i_track++ )
1496     {
1497         if( tk.i_number == block->TrackNum() )
1498         {
1499             break;
1500         }
1501     }
1502
1503     if( i_track >= p_sys->i_track )
1504     {
1505         msg_Err( p_input, "invalid track number=%d", block->TrackNum() );
1506         return;
1507     }
1508
1509     if( tk.p_es->p_decoder_fifo == NULL )
1510     {
1511         tk.b_inited = VLC_FALSE;
1512         return;
1513     }
1514
1515     if( tk.i_cat == AUDIO_ES && p_input->stream.control.b_mute )
1516     {
1517         return;
1518     }
1519
1520     /* First send init data */
1521     if( !tk.b_inited && tk.i_data_init > 0 )
1522     {
1523         pes_packet_t *p_init;
1524
1525         msg_Dbg( p_input, "sending header (%d bytes)", tk.i_data_init );
1526
1527         if( tk.i_codec == VLC_FOURCC( 'v', 'o', 'r', 'b' ) )
1528         {
1529             int i;
1530             int i_offset = 1;
1531             int i_size[3];
1532
1533             /* XXX hack split the 3 headers */
1534             if( tk.p_data_init[0] != 0x02 )
1535             {
1536                 msg_Err( p_input, "invalid vorbis header" );
1537             }
1538
1539             for( i = 0; i < 2; i++ )
1540             {
1541                 i_size[i] = 0;
1542                 while( i_offset < tk.i_data_init )
1543                 {
1544                     i_size[i] += tk.p_data_init[i_offset];
1545                     if( tk.p_data_init[i_offset++] != 0xff )
1546                     {
1547                         break;
1548                     }
1549                 }
1550             }
1551             i_size[0] = __MIN( i_size[0], tk.i_data_init - i_offset );
1552             i_size[1] = __MIN( i_size[1], tk.i_data_init - i_offset - i_size[0] );
1553             i_size[2] = tk.i_data_init - i_offset - i_size[0] - i_size[1];
1554
1555             p_init = MemToPES( p_input, &tk.p_data_init[i_offset], i_size[0] );
1556             if( p_init )
1557             {
1558                 input_DecodePES( tk.p_es->p_decoder_fifo, p_init );
1559             }
1560             p_init = MemToPES( p_input, &tk.p_data_init[i_offset+i_size[0]], i_size[1] );
1561             if( p_init )
1562             {
1563                 input_DecodePES( tk.p_es->p_decoder_fifo, p_init );
1564             }
1565             p_init = MemToPES( p_input, &tk.p_data_init[i_offset+i_size[0]+i_size[1]], i_size[2] );
1566             if( p_init )
1567             {
1568                 input_DecodePES( tk.p_es->p_decoder_fifo, p_init );
1569             }
1570         }
1571         else
1572         {
1573             p_init = MemToPES( p_input, tk.p_data_init, tk.i_data_init );
1574             if( p_init )
1575             {
1576                 input_DecodePES( tk.p_es->p_decoder_fifo, p_init );
1577             }
1578         }
1579     }
1580     tk.b_inited = VLC_TRUE;
1581
1582
1583     for( i = 0; i < block->NumberFrames(); i++ )
1584     {
1585         pes_packet_t *p_pes;
1586         DataBuffer &data = block->GetBuffer(i);
1587
1588         p_pes = MemToPES( p_input, data.Buffer(), data.Size() );
1589         if( p_pes == NULL )
1590         {
1591             break;
1592         }
1593
1594         p_pes->i_pts = i_pts;
1595         p_pes->i_dts = i_pts;
1596
1597         if( tk.i_cat == SPU_ES )
1598         {
1599             if( i_duration > 0 )
1600             {
1601                 /* FIXME not sure about that */
1602                 p_pes->i_dts += i_duration * 1000;// * (mtime_t) 1000 / p_sys->i_timescale;
1603             }
1604             else
1605             {
1606                 p_pes->i_dts = 0;
1607             }
1608
1609             if( p_pes->p_first && p_pes->i_pes_size > 0 )
1610             {
1611                 p_pes->p_first->p_payload_end[-1] = '\0';
1612             }
1613             if( !strcmp( tk.psz_codec, "S_TEXT/SSA" ) )
1614             {
1615                 /* remove all fields before text for now */
1616                 char *start = (char*)p_pes->p_first->p_payload_start;
1617                 int  i_comma = 0;
1618
1619                 while( *start && i_comma < 8 )
1620                 {
1621                     if( *start++ == ',' )
1622                     {
1623                         i_comma++;
1624                     }
1625                 }
1626                 memmove( p_pes->p_first->p_payload_start, start,
1627                          strlen( start) + 1 );
1628             }
1629         }
1630
1631         input_DecodePES( tk.p_es->p_decoder_fifo, p_pes );
1632
1633         /* use time stamp only for first block */
1634         i_pts = 0;
1635     }
1636
1637 #undef tk
1638 }
1639
1640 static void Seek( input_thread_t *p_input, mtime_t i_date, int i_percent)
1641 {
1642     demux_sys_t    *p_sys   = p_input->p_demux_data;
1643
1644     KaxBlock    *block;
1645     int64_t     i_block_duration;
1646     int64_t     i_block_ref1;
1647     int64_t     i_block_ref2;
1648
1649     int         i_index;
1650     int         i_track_skipping;
1651     int         i_track;
1652
1653     msg_Dbg( p_input, "seek request to "I64Fd" (%d%%)", i_date, i_percent );
1654     if( i_date < 0 && i_percent < 0 )
1655     {
1656         return;
1657     }
1658
1659     delete p_sys->ep;
1660     p_sys->ep = new EbmlParser( p_sys->es, p_sys->segment );
1661     p_sys->cluster = NULL;
1662
1663     /* seek without index or without date */
1664     if( config_GetInt( p_input, "mkv-seek-percent" ) || !p_sys->b_cues || i_date < 0 )
1665     {
1666         int64_t i_pos = i_percent * p_input->stream.p_selected_area->i_size / 100;
1667
1668         msg_Dbg( p_input, "imprecise way of seeking" );
1669         for( i_index = 0; i_index < p_sys->i_index; i_index++ )
1670         {
1671             if( p_sys->index[i_index].i_position >= i_pos)
1672             {
1673                 break;
1674             }
1675         }
1676         if( i_index == p_sys->i_index )
1677         {
1678             i_index--;
1679         }
1680
1681         p_sys->in->setFilePointer( p_sys->index[i_index].i_position, seek_beginning );
1682
1683         if( p_sys->index[i_index].i_position < i_pos )
1684         {
1685             EbmlElement *el;
1686
1687             msg_Warn( p_input, "searching for cluster, could take some time" );
1688
1689             /* search a cluster */
1690             while( ( el = p_sys->ep->Get() ) != NULL )
1691             {
1692                 if( EbmlId( *el ) == KaxCluster::ClassInfos.GlobalId )
1693                 {
1694                     KaxCluster *cluster = (KaxCluster*)el;
1695
1696                     /* add it to the index */
1697                     IndexAppendCluster( p_input, cluster );
1698
1699                     if( (int64_t)cluster->GetElementPosition() >= i_pos )
1700                     {
1701                         p_sys->cluster = cluster;
1702                         p_sys->ep->Down();
1703                         break;
1704                     }
1705                 }
1706             }
1707         }
1708     }
1709     else
1710     {
1711         for( i_index = 0; i_index < p_sys->i_index; i_index++ )
1712         {
1713             if( p_sys->index[i_index].i_time >= i_date )
1714             {
1715                 break;
1716             }
1717         }
1718
1719         if( i_index > 0 )
1720         {
1721             i_index--;
1722         }
1723
1724         msg_Dbg( p_input, "seek got "I64Fd" (%d%%)",
1725                  p_sys->index[i_index].i_time, (int)(100 * p_sys->index[i_index].i_position /p_input->stream.p_selected_area->i_size ) );
1726
1727         p_sys->in->setFilePointer( p_sys->index[i_index].i_position, seek_beginning );
1728     }
1729
1730     /* now parse until key frame */
1731 #define tk  p_sys->track[i_track]
1732     i_track_skipping = 0;
1733     for( i_track = 0; i_track < p_sys->i_track; i_track++ )
1734     {
1735         if( tk.i_cat == VIDEO_ES )
1736         {
1737             tk.b_search_keyframe = VLC_TRUE;
1738             i_track_skipping++;
1739         }
1740     }
1741
1742     while( i_track_skipping > 0 )
1743     {
1744         if( BlockGet( p_input, &block, &i_block_ref1, &i_block_ref2, &i_block_duration ) )
1745         {
1746             msg_Warn( p_input, "cannot get block EOF?" );
1747
1748             return;
1749         }
1750
1751         p_sys->i_pts = block->GlobalTimecode() * (mtime_t) 1000 / p_sys->i_timescale;
1752
1753         for( i_track = 0; i_track < p_sys->i_track; i_track++ )
1754         {
1755             if( tk.i_number == block->TrackNum() )
1756             {
1757                 break;
1758             }
1759         }
1760
1761         if( i_track < p_sys->i_track )
1762         {
1763             if( tk.i_cat == VIDEO_ES && i_block_ref1 == -1 && tk.b_search_keyframe )
1764             {
1765                 tk.b_search_keyframe = VLC_FALSE;
1766                 i_track_skipping--;
1767             }
1768             if( tk.i_cat == VIDEO_ES && !tk.b_search_keyframe )
1769             {
1770                 BlockDecode( p_input, block, 0, 0 );
1771             }
1772         }
1773
1774         delete block;
1775     }
1776 #undef tk
1777 }
1778
1779 /*****************************************************************************
1780  * Demux: reads and demuxes data packets
1781  *****************************************************************************
1782  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
1783  *****************************************************************************/
1784 static int Demux( input_thread_t * p_input )
1785 {
1786     demux_sys_t    *p_sys   = p_input->p_demux_data;
1787     mtime_t        i_start_pts;
1788     int            i_block_count = 0;
1789
1790     KaxBlock *block;
1791     int64_t i_block_duration;
1792     int64_t i_block_ref1;
1793     int64_t i_block_ref2;
1794
1795     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
1796     {
1797         mtime_t i_duration = (mtime_t)( p_sys->f_duration / 1000 );
1798         mtime_t i_date = -1;
1799         int i_percent  = -1;
1800
1801         if( i_duration > 0 )
1802         {
1803             i_date = (mtime_t)1000000 *
1804                      (mtime_t)i_duration*
1805                      (mtime_t)p_sys->in->getFilePointer() /
1806                      (mtime_t)p_input->stream.p_selected_area->i_size;
1807         }
1808         if( p_input->stream.p_selected_area->i_size > 0 )
1809         {
1810             i_percent = 100 * p_sys->in->getFilePointer() /
1811                             p_input->stream.p_selected_area->i_size;
1812         }
1813
1814         Seek( p_input, i_date, i_percent);
1815     }
1816
1817     i_start_pts = -1;
1818
1819     for( ;; )
1820     {
1821         mtime_t i_pts;
1822
1823         if( BlockGet( p_input, &block, &i_block_ref1, &i_block_ref2, &i_block_duration ) )
1824         {
1825             msg_Warn( p_input, "cannot get block EOF?" );
1826
1827             return 0;
1828         }
1829
1830         p_sys->i_pts = block->GlobalTimecode() * (mtime_t) 1000 / p_sys->i_timescale;
1831
1832         if( p_sys->i_pts > 0 )
1833         {
1834             input_ClockManageRef( p_input,
1835                                   p_input->stream.p_selected_program,
1836                                   p_sys->i_pts * 9 / 100 );
1837         }
1838
1839         i_pts = input_ClockGetTS( p_input,
1840                                   p_input->stream.p_selected_program,
1841                                   p_sys->i_pts * 9 / 100 );
1842
1843
1844
1845         BlockDecode( p_input, block, i_pts, i_block_duration );
1846
1847         delete block;
1848         i_block_count++;
1849
1850         if( i_start_pts == -1 )
1851         {
1852             i_start_pts = p_sys->i_pts;
1853         }
1854         else if( p_sys->i_pts > i_start_pts + (mtime_t)100000 || i_block_count > 5 )
1855         {
1856             return 1;
1857         }
1858     }
1859 }
1860
1861
1862
1863 /*****************************************************************************
1864  * Stream managment
1865  *****************************************************************************/
1866 vlc_stream_io_callback::vlc_stream_io_callback( input_thread_t *p_input_ )
1867 {
1868     p_input = p_input_;
1869     mb_eof = VLC_FALSE;
1870 }
1871 uint32_t vlc_stream_io_callback::read( void *p_buffer, size_t i_size )
1872 {
1873     data_packet_t *p_data;
1874
1875     int i_count;
1876     int i_read = 0;
1877
1878
1879     if( !i_size || mb_eof )
1880     {
1881         return 0;
1882     }
1883
1884     do
1885     {
1886         i_count = input_SplitBuffer(p_input, &p_data, __MIN( i_size, 10240 ) );
1887         if( i_count <= 0 )
1888         {
1889             return i_read;
1890         }
1891         memcpy( p_buffer, p_data->p_payload_start, i_count );
1892         input_DeletePacket( p_input->p_method_data, p_data );
1893
1894         (uint8_t*)p_buffer += i_count;
1895         i_size            -= i_count;
1896         i_read            += i_count;
1897
1898     } while( i_size );
1899
1900     return i_read;
1901 }
1902 void vlc_stream_io_callback::setFilePointer(int64_t i_offset, seek_mode mode )
1903 {
1904     int64_t i_pos;
1905     int64_t i_last;
1906
1907     i_last = getFilePointer();
1908
1909     vlc_mutex_lock( &p_input->stream.stream_lock );
1910     switch( mode )
1911     {
1912         case seek_beginning:
1913             i_pos = i_offset;
1914             break;
1915         case seek_end:
1916             i_pos = p_input->stream.p_selected_area->i_size - i_offset;
1917             break;
1918         default:
1919             i_pos= i_last + i_offset;
1920             break;
1921     }
1922
1923     if( i_pos < 0 ||
1924         ( i_pos > p_input->stream.p_selected_area->i_size && p_input->stream.p_selected_area->i_size != 0 ) )
1925     {
1926         msg_Err( p_input, "seeking to wrong place (i_pos="I64Fd")", i_pos );
1927         vlc_mutex_unlock( &p_input->stream.stream_lock );
1928
1929         mb_eof = VLC_TRUE;
1930         return;
1931     }
1932     vlc_mutex_unlock( &p_input->stream.stream_lock );
1933
1934     mb_eof = VLC_FALSE;
1935
1936     if( i_pos == i_last )
1937     {
1938         return;
1939     }
1940
1941     msg_Dbg( p_input, "####################seek new="I64Fd" old="I64Fd,
1942              i_pos, getFilePointer() );
1943
1944     if( p_input->stream.b_seekable &&
1945         ( /*p_input->stream.i_method == INPUT_METHOD_FILE ||*/ i_pos < i_last || i_pos - i_last > p_input->i_bufsize / 4 ) )
1946     {
1947         input_AccessReinit( p_input );
1948         p_input->pf_seek( p_input, i_pos );
1949     }
1950     else if( i_pos > i_last )
1951     {
1952         data_packet_t   *p_data;
1953         int             i_skip = i_pos - i_last;
1954
1955         if( i_skip > 1024 )
1956         {
1957             msg_Warn( p_input, "will skip %d bytes, slow", i_skip );
1958         }
1959
1960         while (i_skip > 0 )
1961         {
1962             int i_read;
1963
1964             i_read = input_SplitBuffer( p_input, &p_data,
1965                                         __MIN( 4096, i_skip ) );
1966             if( i_read <= 0 )
1967             {
1968                 msg_Err( p_input, "seek failed" );
1969                 mb_eof = VLC_TRUE;
1970                 return;
1971             }
1972             i_skip -= i_read;
1973
1974             input_DeletePacket( p_input->p_method_data, p_data );
1975             if( i_read == 0 && i_skip > 0 )
1976             {
1977                 msg_Err( p_input, "seek failed" );
1978                 mb_eof = VLC_TRUE;
1979                 return;
1980             }
1981         }
1982     }
1983     else
1984     {
1985         msg_Err( p_input, "cannot seek or emulate seek to "I64Fd" from "I64Fd,
1986                  i_pos, i_last );
1987         mb_eof = VLC_TRUE;
1988     }
1989 }
1990 size_t vlc_stream_io_callback::write( const void *p_buffer, size_t i_size )
1991 {
1992     return 0;
1993 }
1994 uint64_t vlc_stream_io_callback::getFilePointer( void )
1995 {
1996     uint64_t i_pos;
1997
1998     vlc_mutex_lock( &p_input->stream.stream_lock );
1999     i_pos= p_input->stream.p_selected_area->i_tell;
2000     vlc_mutex_unlock( &p_input->stream.stream_lock );
2001
2002     return i_pos;
2003 }
2004 void vlc_stream_io_callback::close( void )
2005 {
2006     return;
2007 }
2008
2009
2010 /*****************************************************************************
2011  * Ebml Stream parser
2012  *****************************************************************************/
2013 EbmlParser::EbmlParser( EbmlStream *es, EbmlElement *el_start )
2014 {
2015     int i;
2016
2017     m_es = es;
2018     m_got = NULL;
2019     m_el[0] = el_start;
2020
2021     for( i = 1; i < 6; i++ )
2022     {
2023         m_el[i] = NULL;
2024     }
2025     mi_level = 1;
2026     mi_user_level = 1;
2027     mb_keep = VLC_FALSE;
2028 }
2029
2030 EbmlParser::~EbmlParser( void )
2031 {
2032     int i;
2033
2034     for( i = 1; i < mi_level; i++ )
2035     {
2036         if( !mb_keep )
2037         {
2038             delete m_el[i];
2039         }
2040         mb_keep = VLC_FALSE;
2041     }
2042 }
2043
2044 void EbmlParser::Up( void )
2045 {
2046     if( mi_user_level == mi_level )
2047     {
2048         fprintf( stderr," arrrrrrrrrrrrrg Up cannot escape itself\n" );
2049     }
2050
2051     mi_user_level--;
2052 }
2053
2054 void EbmlParser::Down( void )
2055 {
2056     mi_user_level++;
2057     mi_level++;
2058 }
2059
2060 void EbmlParser::Keep( void )
2061 {
2062     mb_keep = VLC_TRUE;
2063 }
2064
2065 int EbmlParser::GetLevel( void )
2066 {
2067     return mi_user_level;
2068 }
2069
2070 EbmlElement *EbmlParser::Get( void )
2071 {
2072     int i_ulev = 0;
2073
2074     if( mi_user_level != mi_level )
2075     {
2076         return NULL;
2077     }
2078     if( m_got )
2079     {
2080         EbmlElement *ret = m_got;
2081         m_got = NULL;
2082
2083         return ret;
2084     }
2085
2086     if( m_el[mi_level] )
2087     {
2088         m_el[mi_level]->SkipData( *m_es, m_el[mi_level]->Generic().Context );
2089         if( !mb_keep )
2090         {
2091             delete m_el[mi_level];
2092         }
2093         mb_keep = VLC_FALSE;
2094     }
2095
2096     m_el[mi_level] = m_es->FindNextElement( m_el[mi_level - 1]->Generic().Context, i_ulev, 0xFFFFFFFFL, true, 1 );
2097     if( i_ulev > 0 )
2098     {
2099         while( i_ulev > 0 )
2100         {
2101             if( mi_level == 1 )
2102             {
2103                 mi_level = 0;
2104                 return NULL;
2105             }
2106
2107             delete m_el[mi_level - 1];
2108             m_got = m_el[mi_level -1] = m_el[mi_level];
2109             m_el[mi_level] = NULL;
2110
2111             mi_level--;
2112             i_ulev--;
2113         }
2114         return NULL;
2115     }
2116     else if( m_el[mi_level] == NULL )
2117     {
2118         fprintf( stderr," m_el[mi_level] == NULL\n" );
2119     }
2120
2121     return m_el[mi_level];
2122 }
2123
2124
2125 /*****************************************************************************
2126  * Tools
2127  *  * LoadCues : load the cues element and update index
2128  *
2129  *  * LoadTags : load ... the tags element
2130  *
2131  *  * InformationsCreate : create all informations, load tags if present
2132  *
2133  *****************************************************************************/
2134 static void LoadCues( input_thread_t *p_input )
2135 {
2136     demux_sys_t *p_sys = p_input->p_demux_data;
2137     int64_t     i_sav_position = p_sys->in->getFilePointer();
2138     EbmlParser  *ep;
2139     EbmlElement *el, *cues;
2140
2141     msg_Dbg( p_input, "loading cues" );
2142     p_sys->in->setFilePointer( p_sys->i_cues_position, seek_beginning );
2143     cues = p_sys->es->FindNextID( KaxCues::ClassInfos, 0xFFFFFFFFL);
2144
2145     if( cues == NULL )
2146     {
2147         msg_Err( p_input, "cannot load cues (broken seekhead or file)" );
2148         return;
2149     }
2150
2151     ep = new EbmlParser( p_sys->es, cues );
2152     while( ( el = ep->Get() ) != NULL )
2153     {
2154         if( EbmlId( *el ) == KaxCuePoint::ClassInfos.GlobalId )
2155         {
2156 #define idx p_sys->index[p_sys->i_index]
2157
2158             idx.i_track       = -1;
2159             idx.i_block_number= -1;
2160             idx.i_position    = -1;
2161             idx.i_time        = -1;
2162             idx.b_key         = VLC_TRUE;
2163
2164             ep->Down();
2165             while( ( el = ep->Get() ) != NULL )
2166             {
2167                 if( EbmlId( *el ) == KaxCueTime::ClassInfos.GlobalId )
2168                 {
2169                     KaxCueTime &ctime = *(KaxCueTime*)el;
2170
2171                     ctime.ReadData( p_sys->es->I_O() );
2172
2173                     idx.i_time = uint64( ctime ) * (mtime_t)1000000000 / p_sys->i_timescale;
2174                 }
2175                 else if( EbmlId( *el ) == KaxCueTrackPositions::ClassInfos.GlobalId )
2176                 {
2177                     ep->Down();
2178                     while( ( el = ep->Get() ) != NULL )
2179                     {
2180                         if( EbmlId( *el ) == KaxCueTrack::ClassInfos.GlobalId )
2181                         {
2182                             KaxCueTrack &ctrack = *(KaxCueTrack*)el;
2183
2184                             ctrack.ReadData( p_sys->es->I_O() );
2185                             idx.i_track = uint16( ctrack );
2186                         }
2187                         else if( EbmlId( *el ) == KaxCueClusterPosition::ClassInfos.GlobalId )
2188                         {
2189                             KaxCueClusterPosition &ccpos = *(KaxCueClusterPosition*)el;
2190
2191                             ccpos.ReadData( p_sys->es->I_O() );
2192                             idx.i_position = p_sys->segment->GetGlobalPosition( uint64( ccpos ) );
2193                         }
2194                         else if( EbmlId( *el ) == KaxCueBlockNumber::ClassInfos.GlobalId )
2195                         {
2196                             KaxCueBlockNumber &cbnum = *(KaxCueBlockNumber*)el;
2197
2198                             cbnum.ReadData( p_sys->es->I_O() );
2199                             idx.i_block_number = uint32( cbnum );
2200                         }
2201                         else
2202                         {
2203                             msg_Dbg( p_input, "         * Unknown (%s)", typeid(*el).name() );
2204                         }
2205                     }
2206                     ep->Up();
2207                 }
2208                 else
2209                 {
2210                     msg_Dbg( p_input, "     * Unknown (%s)", typeid(*el).name() );
2211                 }
2212             }
2213             ep->Up();
2214
2215             msg_Dbg( p_input, " * added time="I64Fd" pos="I64Fd
2216                      " track=%d bnum=%d", idx.i_time, idx.i_position,
2217                      idx.i_track, idx.i_block_number );
2218
2219             p_sys->i_index++;
2220             if( p_sys->i_index >= p_sys->i_index_max )
2221             {
2222                 p_sys->i_index_max += 1024;
2223                 p_sys->index = (mkv_index_t*)realloc( p_sys->index, sizeof( mkv_index_t ) * p_sys->i_index_max );
2224             }
2225 #undef idx
2226         }
2227         else
2228         {
2229             msg_Dbg( p_input, " * Unknown (%s)", typeid(*el).name() );
2230         }
2231     }
2232     delete ep;
2233     delete cues;
2234
2235     p_sys->b_cues = VLC_TRUE;
2236
2237     msg_Dbg( p_input, "loading cues done." );
2238     p_sys->in->setFilePointer( i_sav_position, seek_beginning );
2239 }
2240
2241 static void LoadTags( input_thread_t *p_input )
2242 {
2243     demux_sys_t *p_sys = p_input->p_demux_data;
2244     int64_t     i_sav_position = p_sys->in->getFilePointer();
2245     EbmlParser  *ep;
2246     EbmlElement *el, *tags;
2247
2248     msg_Dbg( p_input, "loading tags" );
2249     p_sys->in->setFilePointer( p_sys->i_tags_position, seek_beginning );
2250     tags = p_sys->es->FindNextID( KaxTags::ClassInfos, 0xFFFFFFFFL);
2251
2252     if( tags == NULL )
2253     {
2254         msg_Err( p_input, "cannot load tags (broken seekhead or file)" );
2255         return;
2256     }
2257
2258     msg_Dbg( p_input, "Tags" );
2259     ep = new EbmlParser( p_sys->es, tags );
2260     while( ( el = ep->Get() ) != NULL )
2261     {
2262         if( EbmlId( *el ) == KaxTag::ClassInfos.GlobalId )
2263         {
2264             msg_Dbg( p_input, "+ Tag" );
2265             ep->Down();
2266             while( ( el = ep->Get() ) != NULL )
2267             {
2268                 if( EbmlId( *el ) == KaxTagTargets::ClassInfos.GlobalId )
2269                 {
2270                     msg_Dbg( p_input, "|   + Targets" );
2271                     ep->Down();
2272                     while( ( el = ep->Get() ) != NULL )
2273                     {
2274                         msg_Dbg( p_input, "|   |   + Unknown (%s)", typeid( *el ).name() );
2275                     }
2276                     ep->Up();
2277                 }
2278                 else if( EbmlId( *el ) == KaxTagGeneral::ClassInfos.GlobalId )
2279                 {
2280                     msg_Dbg( p_input, "|   + General" );
2281                     ep->Down();
2282                     while( ( el = ep->Get() ) != NULL )
2283                     {
2284                         msg_Dbg( p_input, "|   |   + Unknown (%s)", typeid( *el ).name() );
2285                     }
2286                     ep->Up();
2287                 }
2288                 else if( EbmlId( *el ) == KaxTagGenres::ClassInfos.GlobalId )
2289                 {
2290                     msg_Dbg( p_input, "|   + Genres" );
2291                     ep->Down();
2292                     while( ( el = ep->Get() ) != NULL )
2293                     {
2294                         msg_Dbg( p_input, "|   |   + Unknown (%s)", typeid( *el ).name() );
2295                     }
2296                     ep->Up();
2297                 }
2298                 else if( EbmlId( *el ) == KaxTagAudioSpecific::ClassInfos.GlobalId )
2299                 {
2300                     msg_Dbg( p_input, "|   + Audio Specific" );
2301                     ep->Down();
2302                     while( ( el = ep->Get() ) != NULL )
2303                     {
2304                         msg_Dbg( p_input, "|   |   + Unknown (%s)", typeid( *el ).name() );
2305                     }
2306                     ep->Up();
2307                 }
2308                 else if( EbmlId( *el ) == KaxTagImageSpecific::ClassInfos.GlobalId )
2309                 {
2310                     msg_Dbg( p_input, "|   + Images Specific" );
2311                     ep->Down();
2312                     while( ( el = ep->Get() ) != NULL )
2313                     {
2314                         msg_Dbg( p_input, "|   |   + Unknown (%s)", typeid( *el ).name() );
2315                     }
2316                     ep->Up();
2317                 }
2318                 else if( EbmlId( *el ) == KaxTagMultiComment::ClassInfos.GlobalId )
2319                 {
2320                     msg_Dbg( p_input, "|   + Multi Comment" );
2321                 }
2322                 else if( EbmlId( *el ) == KaxTagMultiCommercial::ClassInfos.GlobalId )
2323                 {
2324                     msg_Dbg( p_input, "|   + Multi Commercial" );
2325                 }
2326                 else if( EbmlId( *el ) == KaxTagMultiDate::ClassInfos.GlobalId )
2327                 {
2328                     msg_Dbg( p_input, "|   + Multi Date" );
2329                 }
2330                 else if( EbmlId( *el ) == KaxTagMultiEntity::ClassInfos.GlobalId )
2331                 {
2332                     msg_Dbg( p_input, "|   + Multi Entity" );
2333                 }
2334                 else if( EbmlId( *el ) == KaxTagMultiIdentifier::ClassInfos.GlobalId )
2335                 {
2336                     msg_Dbg( p_input, "|   + Multi Identifier" );
2337                 }
2338                 else if( EbmlId( *el ) == KaxTagMultiLegal::ClassInfos.GlobalId )
2339                 {
2340                     msg_Dbg( p_input, "|   + Multi Legal" );
2341                 }
2342                 else if( EbmlId( *el ) == KaxTagMultiTitle::ClassInfos.GlobalId )
2343                 {
2344                     msg_Dbg( p_input, "|   + Multi Title" );
2345                 }
2346                 else
2347                 {
2348                     msg_Dbg( p_input, "|   + Unknown (%s)", typeid( *el ).name() );
2349                 }
2350             }
2351             ep->Up();
2352         }
2353         else
2354         {
2355             msg_Dbg( p_input, "+ Unknown (%s)", typeid( *el ).name() );
2356         }
2357     }
2358     delete ep;
2359     delete tags;
2360
2361     msg_Dbg( p_input, "loading tags done." );
2362     p_sys->in->setFilePointer( i_sav_position, seek_beginning );
2363 }
2364
2365 static void InformationsCreate( input_thread_t *p_input )
2366 {
2367     demux_sys_t           *p_sys = p_input->p_demux_data;
2368     input_info_category_t *p_cat;
2369     int                   i_track;
2370
2371     p_cat = input_InfoCategory( p_input, "Matroska" );
2372     if( p_sys->f_duration > 1000.1 )
2373     {
2374         int64_t i_sec = (int64_t)p_sys->f_duration / 1000;
2375         int h,m,s;
2376
2377         h = i_sec / 3600;
2378         m = ( i_sec / 60 ) % 60;
2379         s = i_sec % 60;
2380
2381         input_AddInfo( p_cat, _("Duration"), "%d:%2.2d:%2.2d" , h, m, s );
2382     }
2383
2384     if( p_sys->psz_title )
2385     {
2386         input_AddInfo( p_cat, _("Title"), "%s" ,p_sys->psz_title );
2387     }
2388     if( p_sys->psz_date_utc )
2389     {
2390         input_AddInfo( p_cat, _("Date UTC"), "%s" ,p_sys->psz_date_utc );
2391     }
2392     if( p_sys->psz_segment_filename )
2393     {
2394         input_AddInfo( p_cat, _("Segment Filename"), "%s" ,p_sys->psz_segment_filename );
2395     }
2396     if( p_sys->psz_muxing_application )
2397     {
2398         input_AddInfo( p_cat, _("Muxing Application"), "%s" ,p_sys->psz_muxing_application );
2399     }
2400     if( p_sys->psz_writing_application )
2401     {
2402         input_AddInfo( p_cat, _("Writing Application"), "%s" ,p_sys->psz_writing_application );
2403     }
2404     input_AddInfo( p_cat, _("Number of streams"), "%d" , p_sys->i_track );
2405
2406     for( i_track = 0; i_track < p_sys->i_track; i_track++ )
2407     {
2408         char psz_cat[strlen( "Stream " ) + 10];
2409 #define tk  p_sys->track[i_track]
2410
2411         sprintf( psz_cat, "Stream %d", i_track );
2412         p_cat = input_InfoCategory( p_input, psz_cat);
2413         if( tk.psz_name )
2414         {
2415             input_AddInfo( p_cat, _("Name"), "%s", tk.psz_name );
2416         }
2417         if( tk.psz_codec_name )
2418         {
2419             input_AddInfo( p_cat, _("Codec Name"), "%s", tk.psz_codec_name );
2420         }
2421         if( tk.psz_codec_settings )
2422         {
2423             input_AddInfo( p_cat, _("Codec Setting"), "%s", tk.psz_codec_settings );
2424         }
2425         if( tk.psz_codec_info_url )
2426         {
2427             input_AddInfo( p_cat, _("Codec Info"), "%s", tk.psz_codec_info_url );
2428         }
2429         if( tk.psz_codec_download_url )
2430         {
2431             input_AddInfo( p_cat, _("Codec Download"), "%s", tk.psz_codec_download_url );
2432         }
2433
2434         switch( tk.i_cat )
2435         {
2436             case AUDIO_ES:
2437                 input_AddInfo( p_cat, _("Type"), _("Audio") );
2438                 input_AddInfo( p_cat, _("Codec"), "%.4s (%s)", (char*)&tk.i_codec, tk.psz_codec );
2439                 if( tk.i_channels > 0 )
2440                 {
2441                     input_AddInfo( p_cat, _("Channels"), "%d", tk.i_channels );
2442                 }
2443                 if( tk.i_samplerate > 0 )
2444                 {
2445                     input_AddInfo( p_cat, _("Sample Rate"), "%d", tk.i_samplerate );
2446                 }
2447                 if( tk.i_bitspersample )
2448                 {
2449                     input_AddInfo( p_cat, _("Bits Per Sample"), "%d", tk.i_bitspersample );
2450                 }
2451                 break;
2452             case VIDEO_ES:
2453                 input_AddInfo( p_cat, _("Type"), _("Video") );
2454                 input_AddInfo( p_cat, _("Codec"), "%.4s (%s)", (char*)&tk.i_codec, tk.psz_codec );
2455                 if( tk.i_width > 0 && tk.i_height )
2456                 {
2457                     input_AddInfo( p_cat, _("Resolution"), "%dx%d", tk.i_width, tk.i_height );
2458                 }
2459                 if( tk.i_display_width > 0 && tk.i_display_height )
2460                 {
2461                     input_AddInfo( p_cat, _("Display Resolution"), "%dx%d", tk.i_display_width, tk.i_display_height );
2462                 }
2463                 if( tk.f_fps > 0.1 )
2464                 {
2465                     input_AddInfo( p_cat, _("Frame Per Second"), "%.3f", tk.f_fps );
2466                 }
2467                 break;
2468             case SPU_ES:
2469                 input_AddInfo( p_cat, _("Type"), _("Subtitle") );
2470                 input_AddInfo( p_cat, _("Codec"), "%s", tk.psz_codec );
2471                 break;
2472         }
2473
2474 #undef  tk
2475     }
2476     if( p_sys->i_tags_position >= 0 && p_input->stream.b_seekable )
2477     {
2478         LoadTags( p_input );
2479     }
2480 }
2481
2482
2483 /*****************************************************************************
2484  * Divers
2485  *****************************************************************************/
2486
2487 static void IndexAppendCluster( input_thread_t *p_input, KaxCluster *cluster )
2488 {
2489     demux_sys_t    *p_sys   = p_input->p_demux_data;
2490
2491 #define idx p_sys->index[p_sys->i_index]
2492     idx.i_track       = -1;
2493     idx.i_block_number= -1;
2494     idx.i_position    = cluster->GetElementPosition();
2495     idx.i_time        = -1;
2496     idx.b_key         = VLC_TRUE;
2497
2498     p_sys->i_index++;
2499     if( p_sys->i_index >= p_sys->i_index_max )
2500     {
2501         p_sys->i_index_max += 1024;
2502         p_sys->index = (mkv_index_t*)realloc( p_sys->index, sizeof( mkv_index_t ) * p_sys->i_index_max );
2503     }
2504 #undef idx
2505 }
2506
2507 static char * UTF8ToStr( const UTFstring &u )
2508 {
2509     int     i_src;
2510     const wchar_t *src;
2511     char *dst, *p;
2512
2513     i_src = u.length();
2514     src   = u.c_str();
2515
2516     p = dst = (char*)malloc( i_src + 1);
2517     while( i_src > 0 )
2518     {
2519         if( *src < 255 )
2520         {
2521             *p++ = (char)*src;
2522         }
2523         else
2524         {
2525             *p++ = '?';
2526         }
2527         src++;
2528         i_src--;
2529     }
2530     *p++= '\0';
2531
2532     return dst;
2533 }
2534
2535 static char *LanguageGetName    ( const char *psz_code )
2536 {
2537     const iso639_lang_t *pl;
2538
2539     if( strlen( psz_code ) == 2 )
2540     {
2541         pl = GetLang_1( psz_code );
2542     }
2543     else if( strlen( psz_code ) == 3 )
2544     {
2545         pl = GetLang_2B( psz_code );
2546         if( !strcmp( pl->psz_iso639_1, "??" ) )
2547         {
2548             pl = GetLang_2T( psz_code );
2549         }
2550     }
2551     else
2552     {
2553         return strdup( psz_code );
2554     }
2555
2556     if( !strcmp( pl->psz_iso639_1, "??" ) )
2557     {
2558        return strdup( psz_code );
2559     }
2560     else
2561     {
2562         if( *pl->psz_native_name )
2563         {
2564             return strdup( pl->psz_native_name );
2565         }
2566         return strdup( pl->psz_eng_name );
2567     }
2568 }
2569