1 /****************************************************************************
2 ** libmatroska : parse Matroska files, see http://www.matroska.org/
3 **
4 ** <file/class description>
5 **
6 ** Copyright (C) 2002-2004 Steve Lhomme.  All rights reserved.
7 **
8 ** This library is free software; you can redistribute it and/or
9 ** modify it under the terms of the GNU Lesser General Public
10 ** License as published by the Free Software Foundation; either
11 ** version 2.1 of the License, or (at your option) any later version.
12 **
13 ** This library is distributed in the hope that it will be useful,
14 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 ** Lesser General Public License for more details.
17 **
18 ** You should have received a copy of the GNU Lesser General Public
19 ** License along with this library; if not, write to the Free Software
20 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21 **
22 ** See http://www.gnu.org/licenses/lgpl-2.1.html for LGPL licensing information.**
23 ** Contact license@matroska.org if any conditions of this licensing are
24 ** not clear to you.
25 **
26 **********************************************************************/
27 
28 /*!
29     \file
30     \version \$Id$
31     \brief Test reading of the Header
32     \author Steve Lhomme     <robux4 @ users.sf.net>
33 */
34 
35 #include <iostream>
36 #include <cassert>
37 
38 #if __GNUC__ == 2
39 #include <wchar.h>
40 #endif
41 
42 #include "ebml/EbmlHead.h"
43 #include "ebml/EbmlSubHead.h"
44 #include "ebml/EbmlStream.h"
45 #include "ebml/EbmlContexts.h"
46 #include "ebml/EbmlVoid.h"
47 #include "ebml/EbmlCrc32.h"
48 #include "matroska/FileKax.h"
49 #include "matroska/KaxSegment.h"
50 #include "matroska/KaxContexts.h"
51 #include "matroska/KaxTracks.h"
52 #include "matroska/KaxInfoData.h"
53 #include "matroska/KaxCluster.h"
54 #include "matroska/KaxBlockData.h"
55 #include "matroska/KaxSeekHead.h"
56 #include "matroska/KaxCuesData.h"
57 #include "ebml/StdIOCallback.h"
58 
59 using namespace LIBMATROSKA_NAMESPACE;
60 using namespace std;
61 
62 #define NO_DISPLAY_DATA
63 //#define JUMP_TEST
64 
65 /*!
66     \note you can generate the file used in this example using test6.cpp
67   \todo the blocks with "titi" and "tetetete" don't seem to be read !
68 */
main(int argc,char ** argv)69 int main(int argc, char **argv)
70 {
71     try {
72   StdIOCallback Cluster_file((argc>=2 ? argv[1] : "muxed.mkv"), MODE_READ);
73 
74   // create the Matroska file
75 ///  FileKax MuxedFile(Cluster_file);
76 //  bool bAllowDummy = false; // don't read elements we don't know
77   bool bAllowDummy = true; // even read elements we don't know (needed for CRC checking)
78 
79   // read the EBML head
80   EbmlStream aStream(Cluster_file);
81   EbmlElement * ElementLevel0;
82   EbmlElement * ElementLevel1;
83   EbmlElement * ElementLevel2;
84   EbmlElement * ElementLevel3 = NULL;
85   EbmlElement * ElementLevel4 = NULL;
86 
87 ///  MuxedFile.ReadHead();
88   // find the EBML head in the file
89   ElementLevel0 = aStream.FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL);
90   if (ElementLevel0 != NULL)
91   {
92     printf("EBML : ");
93     for (unsigned int i=0; i<EbmlId(*ElementLevel0).Length; i++)
94     {
95       printf("[%02X]", (EbmlId(*ElementLevel0).Value >> (8*(3-i))) & 0xFF);
96     }
97     printf("\n");
98 
99     ElementLevel0->SkipData(aStream, EbmlHead_Context);
100     if (ElementLevel0 != NULL)
101       delete ElementLevel0;
102   }
103 
104   int UpperElementLevel = 0;
105   KaxSegment * Segment;
106   KaxInfo * SegmentInfo;
107   KaxTrackEntry * TrackAudio;
108   KaxTrackEntry * TrackVideo;
109   KaxCluster *SegmentCluster;
110   KaxCues *CuesEntry;
111   KaxSeekHead *MetaSeek;
112   KaxChapters *Chapters;
113   KaxTags *AllTags;
114   uint64 TimecodeScale = 1000000;
115 
116   // find the segment to read
117   ElementLevel0 = aStream.FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL);
118   if (ElementLevel0 != NULL)
119   {
120     if (EbmlId(*ElementLevel0) == KaxSegment::ClassInfos.GlobalId) {
121       Segment = static_cast<KaxSegment*>(ElementLevel0);
122 //      MuxedFile.ReadTracks();
123 //      MuxedFile.ReadCodec();
124       // scan the file for a Tracks element (all previous Level1 elements are discarded)
125       ElementLevel1 = aStream.FindNextElement(ElementLevel0->Generic().Context, UpperElementLevel, 0, bAllowDummy);
126 
127       while (ElementLevel1 != NULL) {
128         if (UpperElementLevel > 0) {
129           break;
130         }
131         if (UpperElementLevel < 0) {
132           UpperElementLevel = 0;
133         }
134 
135         /// \todo switch the type of the element to check if it's one we want to handle, like attachements
136         if (EbmlId(*ElementLevel1) == EbmlVoid::ClassInfos.GlobalId) {
137           printf("\n- Void found\n");
138         } else if (EbmlId(*ElementLevel1) == KaxTracks::ClassInfos.GlobalId) {
139           // found the Tracks element
140           printf("\n- Segment Tracks found\n");
141           // handle the data in Tracks here.
142           // poll for new tracks and handle them
143           ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy);
144 
145           while (ElementLevel2 != NULL) {
146             if (UpperElementLevel > 0) {
147               break;
148             }
149             if (UpperElementLevel < 0) {
150               UpperElementLevel = 0;
151             }
152             /// \todo switch the type of the element to check if it's one we want to handle, like attachements
153             if (EbmlId(*ElementLevel2) == KaxTrackEntry::ClassInfos.GlobalId) {
154               printf("* Found a track\n");
155 
156               ElementLevel3 = aStream.FindNextElement(ElementLevel2->Generic().Context, UpperElementLevel, 0, bAllowDummy);
157               while (ElementLevel3 != NULL) {
158                 if (UpperElementLevel > 0) {
159                   break;
160                 }
161                 if (UpperElementLevel < 0) {
162                   UpperElementLevel = 0;
163                 }
164                 // read the data we care about in a track
165                 // Track number
166                 if (EbmlId(*ElementLevel3) == KaxTrackNumber::ClassInfos.GlobalId) {
167                   KaxTrackNumber & TrackNum = *static_cast<KaxTrackNumber*>(ElementLevel3);
168                   TrackNum.ReadData(aStream.I_O());
169                   printf("Track # %d\n", uint8(TrackNum));
170                 }
171 
172                 // Track type
173                 else if (EbmlId(*ElementLevel3) == KaxTrackType::ClassInfos.GlobalId) {
174                   KaxTrackType & TrackType = *static_cast<KaxTrackType*>(ElementLevel3);
175                   TrackType.ReadData(aStream.I_O());
176                   printf("Track type : ");
177                   switch(uint8(TrackType))
178                   {
179                   case track_audio:
180                     printf("Audio");
181                     TrackAudio = static_cast<KaxTrackEntry *>(ElementLevel2);
182                     TrackAudio->SetGlobalTimecodeScale(TimecodeScale);
183                     break;
184                   case track_video:
185                     printf("Video");
186                     TrackVideo = static_cast<KaxTrackEntry *>(ElementLevel2);
187                     TrackVideo->SetGlobalTimecodeScale(TimecodeScale);
188                     break;
189                   default:
190                     printf("unknown");
191                   }
192                   printf("\n");
193                 }
194 
195                 else if (EbmlId(*ElementLevel3) == KaxTrackFlagLacing::ClassInfos.GlobalId) {
196                   printf("Flag Lacing\n");
197                 }
198                 else if (EbmlId(*ElementLevel3) == KaxCodecID::ClassInfos.GlobalId) {
199                   KaxCodecID & CodecID = *static_cast<KaxCodecID*>(ElementLevel3);
200                   CodecID.ReadData(aStream.I_O());
201                   printf("Codec ID   : %s\n", string(CodecID).c_str());
202                 }
203 
204                 if (UpperElementLevel > 0) {
205                   assert(0 == 1); // impossible to be here ?
206                   UpperElementLevel--;
207                   delete ElementLevel2;
208                   ElementLevel2 = ElementLevel3;
209                   if (UpperElementLevel > 0)
210                     break;
211                 } else {
212                   ElementLevel3->SkipData(aStream, ElementLevel3->Generic().Context);
213                   delete ElementLevel3;
214 
215                   ElementLevel3 = aStream.FindNextElement(ElementLevel2->Generic().Context, UpperElementLevel, 0, bAllowDummy);
216                 }
217               }
218             }
219             if (UpperElementLevel > 0) {
220               UpperElementLevel--;
221               delete ElementLevel2;
222               ElementLevel2 = ElementLevel3;
223               if (UpperElementLevel > 0)
224                 break;
225             } else {
226               ElementLevel2->SkipData(aStream, ElementLevel2->Generic().Context);
227               delete ElementLevel2;
228 
229               ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy);
230             }
231           }
232         }
233 
234         else if (EbmlId(*ElementLevel1) == KaxInfo::ClassInfos.GlobalId) {
235           printf("\n- Segment Informations found\n");
236           SegmentInfo = static_cast<KaxInfo *>(ElementLevel1);
237 
238 #ifdef JUMP_TEST
239           // test jumping to a random location and find the next Level 0 / Level 1 element
240           aStream.I_O().setFilePointer(79, seek_current);
241           printf("Seeked at position 0x%X in the file", aStream.I_O().getFilePointer());
242           int LowLevel = 1;
243           ElementLevel2 = aStream.FindNextElement(KaxSegment::ClassInfos.Context, LowLevel, 0, false); // search up to one level lower
244           UpperElementLevel = LowLevel;
245 #else // JUMP_TEST
246           // read the data we care about in matroska
247           /// \todo There should be a way to get the default values of the elements not defined
248           ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy);
249           while (ElementLevel2 != NULL) {
250             if (UpperElementLevel > 0) {
251               break;
252             }
253             if (UpperElementLevel < 0) {
254               UpperElementLevel = 0;
255             }
256             if (EbmlId(*ElementLevel2) == KaxTimecodeScale::ClassInfos.GlobalId) {
257               KaxTimecodeScale *TimeScale = static_cast<KaxTimecodeScale*>(ElementLevel2);
258               TimeScale->ReadData(aStream.I_O());
259               printf("Timecode Scale %d\n", uint32(*TimeScale));
260               TimecodeScale = uint64(*TimeScale);
261             } else if (EbmlId(*ElementLevel2) == KaxDuration::ClassInfos.GlobalId) {
262               printf("Segment duration\n");
263             } else if (EbmlId(*ElementLevel2) == KaxDateUTC::ClassInfos.GlobalId) {
264               printf("Date UTC\n");
265             } else if (EbmlId(*ElementLevel2) == KaxTitle::ClassInfos.GlobalId) {
266               printf("Title\n");
267             } else if (EbmlId(*ElementLevel2) == KaxMuxingApp::ClassInfos.GlobalId) {
268               KaxMuxingApp *pApp = static_cast<KaxMuxingApp*>(ElementLevel2);
269               pApp->ReadData(aStream.I_O());
270 #if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__BEOS__) && !defined(__NetBSD__)
271               wprintf(L"Muxing App : %ls\n", UTFstring(*pApp).c_str());
272 #else
273               printf("Muxing App : %s\n", UTFstring(*pApp).c_str());
274 #endif
275             } else if (EbmlId(*ElementLevel2) == KaxWritingApp::ClassInfos.GlobalId) {
276               KaxWritingApp *pApp = static_cast<KaxWritingApp*>(ElementLevel2);
277               pApp->ReadData(aStream.I_O());
278 #if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__BEOS__) && !defined(__NetBSD__)
279               wprintf(L"Writing App : %ls (����)\n", UTFstring(*pApp).c_str());
280 #else
281               printf("Writing App : %s (����)\n", UTFstring(*pApp).c_str());
282 #endif
283             }
284 
285             if (UpperElementLevel > 0) {
286               UpperElementLevel--;
287               delete ElementLevel2;
288               ElementLevel2 = ElementLevel3;
289               if (UpperElementLevel > 0)
290                 break;
291             } else {
292               ElementLevel2->SkipData(aStream, ElementLevel2->Generic().Context);
293               delete ElementLevel2;
294 
295               ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy);
296             }
297           }
298 #endif // JUMP_TEST
299         }
300 
301         else if (EbmlId(*ElementLevel1) == KaxCluster::ClassInfos.GlobalId) {
302           printf("\n- Segment Clusters found\n");
303           SegmentCluster = static_cast<KaxCluster *>(ElementLevel1);
304 //          SegmentCluster->ClearElement();
305           uint32 ClusterTimecode;
306           EbmlCrc32 *pChecksum = NULL;
307           uint32 SizeInCrc;
308           uint64 CrcPositionStart = 0;
309 
310 #ifdef MEMORY_READ // read the Cluster in memory and then extract elements from memory
311           SegmentCluster->Read(aStream, KaxCluster::ClassInfos.Context, UpperElementLevel, ElementLevel2, bAllowDummy);
312           if (SegmentCluster->CheckMandatory()) {
313             printf("  * All mandatory elements found *\n");
314           } else {
315             printf("  * Some mandatory elements ar missing !!! *\n");
316           }
317 
318           // display the elements read
319           unsigned int Index0;
320           for (Index0 = 0; Index0<SegmentCluster->ListSize() ;Index0++) {
321             printf(" - found %s\n", (*SegmentCluster)[Index0]->Generic().DebugName);
322           }
323 #else // not MEMORY_READ
324           // read blocks and discard the ones we don't care about
325           ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy);
326           while (ElementLevel2 != NULL) {
327             if (UpperElementLevel > 0) {
328               break;
329             }
330             if (UpperElementLevel < 0) {
331               UpperElementLevel = 0;
332             }
333             if (EbmlId(*ElementLevel2) == KaxClusterTimecode::ClassInfos.GlobalId) {
334               printf("Cluster timecode found\n");
335               KaxClusterTimecode & ClusterTime = *static_cast<KaxClusterTimecode*>(ElementLevel2);
336               ClusterTime.ReadData(aStream.I_O());
337               ClusterTimecode = uint32(ClusterTime);
338               SegmentCluster->InitTimecode(ClusterTimecode, TimecodeScale);
339             } else  if (EbmlId(*ElementLevel2) == KaxBlockGroup::ClassInfos.GlobalId) {
340               printf("Block Group found\n");
341 #ifdef TEST_BLOCKGROUP_READ
342               KaxBlockGroup & aBlockGroup = *static_cast<KaxBlockGroup*>(ElementLevel2);
343 //              aBlockGroup.ClearElement();
344               // Extract the valuable data from the Block
345 
346               aBlockGroup.Read(aStream, KaxBlockGroup::ClassInfos.Context, UpperElementLevel, ElementLevel3, bAllowDummy);
347               KaxBlock * DataBlock = static_cast<KaxBlock *>(aBlockGroup.FindElt(KaxBlock::ClassInfos));
348               if (DataBlock != NULL) {
349 //                DataBlock->ReadData(aStream.I_O());
350                 DataBlock->SetParent(*SegmentCluster);
351                 printf("   Track # %d / %d frame%s / Timecode %I64d\n",DataBlock->TrackNum(), DataBlock->NumberFrames(), (DataBlock->NumberFrames() > 1)?"s":"", DataBlock->GlobalTimecode());
352               } else {
353                 printf("   A BlockGroup without a Block !!!");
354               }
355               KaxBlockDuration * BlockDuration = static_cast<KaxBlockDuration *>(aBlockGroup.FindElt(KaxBlockDuration::ClassInfos));
356               if (BlockDuration != NULL) {
357                 printf("  Block Duration %d scaled ticks : %ld ns\n", uint32(*BlockDuration), uint32(*BlockDuration) * TimecodeScale);
358               }
359               KaxReferenceBlock * RefTime = static_cast<KaxReferenceBlock *>(aBlockGroup.FindElt(KaxReferenceBlock::ClassInfos));
360               if (RefTime != NULL) {
361                 printf("  Reference frame at scaled (%d) timecode %ld\n", int32(*RefTime), int32(int64(*RefTime) * TimecodeScale));
362               }
363 #else // TEST_BLOCKGROUP_READ
364               // read the data we care about in matroska
365               /// \todo There should be a way to get the default values of the elements not defined
366               ElementLevel3 = aStream.FindNextElement(ElementLevel2->Generic().Context, UpperElementLevel, 0, bAllowDummy);
367               while (ElementLevel3 != NULL) {
368                 if (UpperElementLevel > 0) {
369                   break;
370                 }
371                 if (UpperElementLevel < 0) {
372                   UpperElementLevel = 0;
373                 }
374                 if (EbmlId(*ElementLevel3) == KaxBlock::ClassInfos.GlobalId) {
375                   printf(" Block Data\n");
376                   KaxBlock & DataBlock = *static_cast<KaxBlock*>(ElementLevel3);
377 #ifdef NO_DISPLAY_DATA
378                   DataBlock.ReadData(aStream.I_O(), SCOPE_PARTIAL_DATA);
379 #else // NO_DISPLAY_DATA
380                   DataBlock.ReadData(aStream.I_O(), SCOPE_ALL_DATA);
381 #endif // NO_DISPLAY_DATA
382                   DataBlock.SetParent(*SegmentCluster);
383                   printf("   Track # %d / %d frame%s / Timecode %I64d\n",DataBlock.TrackNum(), DataBlock.NumberFrames(), (DataBlock.NumberFrames() > 1)?"s":"", DataBlock.GlobalTimecode());
384 #ifndef NO_DISPLAY_DATA
385                   for (unsigned int i=0; i< DataBlock.NumberFrames(); i++) {
386                     printf("   [%s]\n",DataBlock.GetBuffer(i).Buffer()); // STRING ONLY POSSIBLE WITH THIS PARTICULAR EXAMPLE (the binary data is a string)
387                   }
388 #endif // NO_DISPLAY_DATA
389 //                  printf("Codec ID   : %s\n", &binary(CodecID)); // strings for the moment (example)
390                 } else if (EbmlId(*ElementLevel3) == KaxBlockVirtual::ClassInfos.GlobalId) {
391                   printf(" Virtual Block\n");
392                 } else if (EbmlId(*ElementLevel3) == KaxReferenceVirtual::ClassInfos.GlobalId) {
393                   printf("  virtual Reference\n");
394                 } else if (EbmlId(*ElementLevel3) == KaxReferencePriority::ClassInfos.GlobalId) {
395                   printf("  Reference priority\n");
396                 } else if (EbmlId(*ElementLevel3) == KaxReferenceBlock::ClassInfos.GlobalId) {
397                   KaxReferenceBlock & RefTime = *static_cast<KaxReferenceBlock*>(ElementLevel3);
398                   RefTime.ReadData(aStream.I_O());
399                   printf("  Reference frame at scaled (%d) timecode %ld\n", int32(RefTime), int32(int64(RefTime) * TimecodeScale));
400                 } else if (EbmlId(*ElementLevel3) == KaxBlockDuration::ClassInfos.GlobalId) {
401                   KaxBlockDuration & BlockDuration = *static_cast<KaxBlockDuration*>(ElementLevel3);
402                   BlockDuration.ReadData(aStream.I_O());
403                   printf("  Block Duration %d scaled ticks : %ld ns\n", uint32(BlockDuration), uint32(BlockDuration) * TimecodeScale);
404                 }
405                 if (UpperElementLevel > 0) {
406                   UpperElementLevel--;
407                   delete ElementLevel3;
408                   ElementLevel3 = ElementLevel4;
409                   if (UpperElementLevel > 0)
410                     break;
411                 } else {
412                   ElementLevel3->SkipData(aStream, ElementLevel3->Generic().Context);
413 
414                   ElementLevel3 = aStream.FindNextElement(ElementLevel2->Generic().Context, UpperElementLevel, 0, bAllowDummy);
415                 }
416               }
417 #endif // TEST_BLOCKGROUP_READ
418             } else if (EbmlId(*ElementLevel2) == EbmlCrc32::ClassInfos.GlobalId) {
419               printf("Cluster CheckSum !\n");
420               pChecksum = static_cast<EbmlCrc32*>(ElementLevel2);
421               pChecksum->ReadData(aStream.I_O());
422               SegmentCluster->ForceChecksum( pChecksum->GetCrc32() ); // not use later
423               SizeInCrc = 0;
424               CrcPositionStart = aStream.I_O().getFilePointer();
425             }
426 
427             if (UpperElementLevel > 0) {
428               UpperElementLevel--;
429               delete ElementLevel2;
430               ElementLevel2 = ElementLevel3;
431               if (UpperElementLevel > 0)
432                 break;
433             } else {
434               ElementLevel2->SkipData(aStream, ElementLevel2->Generic().Context);
435               if (ElementLevel2 != pChecksum)
436                 delete ElementLevel2;
437 
438               ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy);
439             }
440           }
441 #endif // not MEMORY_READ
442           if (pChecksum != NULL) {
443             EbmlCrc32 ComputedChecksum;
444             uint64 CurrPosition = aStream.I_O().getFilePointer();
445             uint64 CrcPositionEnd = ElementLevel2->GetElementPosition();
446             binary *SupposedBufferInCrc = new binary [CrcPositionEnd - CrcPositionStart];
447             aStream.I_O().setFilePointer(CrcPositionStart);
448             aStream.I_O().readFully(SupposedBufferInCrc, CrcPositionEnd - CrcPositionStart);
449             aStream.I_O().setFilePointer(CurrPosition);
450             ComputedChecksum.FillCRC32(SupposedBufferInCrc, CrcPositionEnd - CrcPositionStart);
451             delete [] SupposedBufferInCrc;
452             if (pChecksum->GetCrc32() == ComputedChecksum.GetCrc32()) {
453               printf(" ++ CheckSum verification succeeded ++");
454             } else {
455               printf(" ++ CheckSum verification FAILED !!! ++");
456             }
457             delete pChecksum;
458             pChecksum = NULL;
459           }
460         }
461         else if (EbmlId(*ElementLevel1) == KaxCues::ClassInfos.GlobalId) {
462           printf("\n- Cue entries found\n");
463           CuesEntry = static_cast<KaxCues *>(ElementLevel1);
464           CuesEntry->SetGlobalTimecodeScale(TimecodeScale);
465           // read everything in memory
466           CuesEntry->Read(aStream, KaxCues::ClassInfos.Context, UpperElementLevel, ElementLevel2, bAllowDummy); // build the entries in memory
467           if (CuesEntry->CheckMandatory()) {
468             printf("  * All mandatory elements found *\n");
469           } else {
470             printf("  * Some mandatory elements ar missing !!! *\n");
471           }
472           CuesEntry->Sort();
473           // display the elements read
474           unsigned int Index0;
475           for (Index0 = 0; Index0<CuesEntry->ListSize() ;Index0++) {
476             if ((*CuesEntry)[Index0]->Generic().GlobalId == KaxCuePoint::ClassInfos.GlobalId) {
477               printf(" Cue Point\n");
478 
479               KaxCuePoint & CuePoint = *static_cast<KaxCuePoint *>((*CuesEntry)[Index0]);
480               unsigned int Index1;
481               for (Index1 = 0; Index1<CuePoint.ListSize() ;Index1++) {
482                 if (CuePoint[Index1]->Generic().GlobalId == KaxCueTime::ClassInfos.GlobalId) {
483                   KaxCueTime & CueTime = *static_cast<KaxCueTime *>(CuePoint[Index1]);
484                   printf("  Time %ld\n", uint64(CueTime) * TimecodeScale);
485                 } else if (CuePoint[Index1]->Generic().GlobalId == KaxCueTrackPositions::ClassInfos.GlobalId) {
486                   KaxCueTrackPositions & CuePos = *static_cast<KaxCueTrackPositions *>(CuePoint[Index1]);
487                   printf("  Positions\n");
488 
489                   unsigned int Index2;
490                   for (Index2 = 0; Index2<CuePos.ListSize() ;Index2++) {
491                     if (CuePos[Index2]->Generic().GlobalId == KaxCueTrack::ClassInfos.GlobalId) {
492                       KaxCueTrack & CueTrack = *static_cast<KaxCueTrack *>(CuePos[Index2]);
493                       printf("   Track %d\n", uint16(CueTrack));
494                     } else if (CuePos[Index2]->Generic().GlobalId == KaxCueClusterPosition::ClassInfos.GlobalId) {
495                       KaxCueClusterPosition & CuePoss = *static_cast<KaxCueClusterPosition *>(CuePos[Index2]);
496                       printf("   Cluster position %d\n", uint64(CuePoss));
497                     } else if (CuePos[Index2]->Generic().GlobalId == KaxCueReference::ClassInfos.GlobalId) {
498                       KaxCueReference & CueRefs = *static_cast<KaxCueReference *>(CuePos[Index2]);
499                       printf("   Reference\n");
500 
501                       unsigned int Index3;
502                       for (Index3 = 0; Index3<CueRefs.ListSize() ;Index3++) {
503                         if (CueRefs[Index3]->Generic().GlobalId == KaxCueRefTime::ClassInfos.GlobalId) {
504                           KaxCueRefTime & CueTime = *static_cast<KaxCueRefTime *>(CueRefs[Index3]);
505                           printf("    Time %d\n", uint32(CueTime));
506                         } else if (CueRefs[Index3]->Generic().GlobalId == KaxCueRefCluster::ClassInfos.GlobalId) {
507                           KaxCueRefCluster & CueClust = *static_cast<KaxCueRefCluster *>(CueRefs[Index3]);
508                           printf("    Cluster position %d\n", uint64(CueClust));
509                         } else {
510                           printf("    - found %s\n", CueRefs[Index3]->Generic().DebugName);
511                         }
512                       }
513                     } else {
514                       printf("   - found %s\n", CuePos[Index2]->Generic().DebugName);
515                     }
516                   }
517                 } else {
518                   printf("  - found %s\n", CuePoint[Index1]->Generic().DebugName);
519                 }
520               }
521             } else {
522               printf(" - found %s\n", (*CuesEntry)[Index0]->Generic().DebugName);
523             }
524           }
525         }
526         else if (EbmlId(*ElementLevel1) == KaxSeekHead::ClassInfos.GlobalId) {
527           printf("\n- Meta Seek found\n");
528           MetaSeek = static_cast<KaxSeekHead *>(ElementLevel1);
529           // read it in memory
530           MetaSeek->Read(aStream, KaxSeekHead::ClassInfos.Context, UpperElementLevel, ElementLevel2, bAllowDummy);
531           if (MetaSeek->CheckMandatory()) {
532             printf("  * All mandatory elements found *\n");
533           } else {
534             printf("  * Some mandatory elements ar missing !!! *\n");
535           }
536           unsigned int Index0;
537           for (Index0 = 0; Index0<MetaSeek->ListSize() ;Index0++) {
538             if ((*MetaSeek)[Index0]->Generic().GlobalId == KaxSeek::ClassInfos.GlobalId) {
539               printf("   Seek Point\n");
540               KaxSeek & SeekPoint = *static_cast<KaxSeek *>((*MetaSeek)[Index0]);
541               unsigned int Index1;
542               for (Index1 = 0; Index1<SeekPoint.ListSize() ;Index1++) {
543                 if (SeekPoint[Index1]->Generic().GlobalId == KaxSeekID::ClassInfos.GlobalId) {
544                   KaxSeekID * SeekID = static_cast<KaxSeekID *>(SeekPoint[Index1]);
545                   printf("    Seek ID ", SeekID->GetBuffer());
546                   for (unsigned int i=0; i<SeekID->GetSize(); i++) {
547                     printf("%02X", SeekID->GetBuffer()[i]);
548                   }
549                   printf("\n");
550                 } else if (SeekPoint[Index1]->Generic().GlobalId == KaxSeekPosition::ClassInfos.GlobalId) {
551                   KaxSeekPosition * SeekPos = static_cast<KaxSeekPosition *>(SeekPoint[Index1]);
552                   printf("    Seek position %d\n", uint32(*SeekPos));
553                 }
554               }
555             }
556           }
557         } else if (EbmlId(*ElementLevel1) == KaxChapters::ClassInfos.GlobalId) {
558           printf("\n- Chapters found\n");
559           Chapters = static_cast<KaxChapters *>(ElementLevel1);
560           // read it in memory
561           Chapters->Read(aStream, KaxChapters::ClassInfos.Context, UpperElementLevel, ElementLevel2, bAllowDummy);
562           if (Chapters->CheckMandatory()) {
563             printf("  * All mandatory elements found *\n");
564           } else {
565             printf("  * Some mandatory elements ar missing !!! *\n");
566           }
567           unsigned int Index0;
568           for (Index0 = 0; Index0<Chapters->ListSize() ;Index0++) {
569             if ((*Chapters)[Index0]->Generic().GlobalId == KaxEditionEntry::ClassInfos.GlobalId) {
570               printf("   Edition\n");
571               KaxEditionEntry & Edition = *static_cast<KaxEditionEntry *>((*Chapters)[Index0]);
572               unsigned int Index2;
573               for (Index2 = 0; Index2<Edition.ListSize() ;Index2++) {
574                 if (Edition[Index2]->Generic().GlobalId == KaxChapterAtom::ClassInfos.GlobalId) {
575                   printf("     Chapter Atom\n");
576                   KaxChapterAtom & aChapterAtom = *static_cast<KaxChapterAtom *>(Edition[Index2]);
577                   unsigned int Index3;
578                   for (Index3 = 0; Index3<aChapterAtom.ListSize() ;Index3++) {
579                     if (aChapterAtom[Index3]->Generic().GlobalId == KaxChapterUID::ClassInfos.GlobalId) {
580                       printf("      Chapter UID 0x%08x\n", uint32(*static_cast<EbmlUInteger *>(aChapterAtom[Index3])) );
581                     } else if (aChapterAtom[Index3]->Generic().GlobalId == KaxChapterTimeStart::ClassInfos.GlobalId) {
582                       printf("      Time Start %d\n", uint32(*static_cast<EbmlUInteger *>(aChapterAtom[Index3])) );
583                     } else if (aChapterAtom[Index3]->Generic().GlobalId == KaxChapterTimeEnd::ClassInfos.GlobalId) {
584                       printf("      Time End %d ns\n", uint32(*static_cast<EbmlUInteger *>(aChapterAtom[Index3])) );
585                     } else if (aChapterAtom[Index3]->Generic().GlobalId == KaxChapterTrack::ClassInfos.GlobalId) {
586                       printf("      Track list\n");
587                     } else if (aChapterAtom[Index3]->Generic().GlobalId == KaxChapterDisplay::ClassInfos.GlobalId) {
588                       printf("      Display info\n");
589                       KaxChapterDisplay & aDisplay = *static_cast<KaxChapterDisplay *>(aChapterAtom[Index3]);
590                       unsigned int Index4;
591                       for (Index4 = 0; Index4<aDisplay.ListSize() ;Index4++) {
592                         if (aDisplay[Index4]->Generic().GlobalId == KaxChapterString::ClassInfos.GlobalId) {
593 #if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__BEOS__) && !defined(__NetBSD__)
594                           wprintf(L"       Display \"%s\"\n", UTFstring(*static_cast<EbmlUnicodeString *>(aDisplay[Index4])).c_str() );
595 #else
596                           printf("       Display \"%s\"\n", UTFstring(*static_cast<EbmlUnicodeString *>(aDisplay[Index4])).c_str() );
597 #endif
598                         } else if (aDisplay[Index4]->Generic().GlobalId == KaxChapterLanguage::ClassInfos.GlobalId) {
599                           printf("       For language \"%s\"\n", std::string(*static_cast<EbmlString *>(aDisplay[Index4])).c_str() );
600                         } else if (aDisplay[Index4]->Generic().GlobalId == KaxChapterCountry::ClassInfos.GlobalId) {
601                           printf("       For country \"%s\"\n", std::string(*static_cast<EbmlString *>(aDisplay[Index4])).c_str() );
602                         } else if (aDisplay[Index4]->IsDummy()) {
603                           printf("       Dummy !!!\n");
604                         }
605                       }
606                     }
607                   }
608                 }
609               }
610             }
611           }
612         } else if (EbmlId(*ElementLevel1) == KaxTags::ClassInfos.GlobalId) {
613           printf("\n- Tags found\n");
614           AllTags = static_cast<KaxTags *>(ElementLevel1);
615           // read it in memory
616           AllTags->Read(aStream, KaxTags::ClassInfos.Context, UpperElementLevel, ElementLevel2, bAllowDummy);
617           if (AllTags->CheckMandatory()) {
618             printf("  * All mandatory elements found *\n");
619           } else {
620             printf("  * Some mandatory elements ar missing !!! *\n");
621           }
622           unsigned int Index0;
623           for (Index0 = 0; Index0<AllTags->ListSize() ;Index0++) {
624             if ((*AllTags)[Index0]->Generic().GlobalId == KaxTag::ClassInfos.GlobalId) {
625               printf("   Tag\n");
626               KaxTag & TagElt = *static_cast<KaxTag *>((*AllTags)[Index0]);
627               unsigned int Index1;
628               for (Index1 = 0; Index1<TagElt.ListSize() ;Index1++) {
629 //                 bool bRemoved = false, bRemovedDone = true;
630                 if (TagElt[Index1]->Generic().GlobalId == KaxTagTargets::ClassInfos.GlobalId) {
631                   printf("    Targets\n");
632                   KaxTagTargets & Targets = *static_cast<KaxTagTargets *>(TagElt[Index1]);
633                   unsigned int Index2;
634                   for (Index2 = 0; Index2<Targets.ListSize() ;Index2++) {
635                     if (Targets[Index2]->Generic().GlobalId == KaxTagTrackUID::ClassInfos.GlobalId) {
636 #ifndef TEST_REMOVE
637                       printf("     Track UID\n");
638 #else // TEST_REMOVE
639                       printf("     Track UID (will be removed)\n");
640                       /*************** Test to remove an element ***************/
641                       Targets.Remove(Index2);
642                       bRemoved = true;
643                       bRemovedDone = false;
644                       Index2--;
645                       Index1--;
646 #endif // TEST_REMOVE
647                     } else if (Targets[Index2]->Generic().GlobalId == KaxTagChapterUID::ClassInfos.GlobalId) {
648                       printf("     Chapter UID\n");
649 #if 0
650                     } else if (Targets[Index2]->Generic().GlobalId == KaxTagMultiComment::ClassInfos.GlobalId) {
651                       printf("     Comment\n");
652                       KaxTagMultiComment & Comment = *static_cast<KaxTagMultiComment *>(Targets[Index2]);
653                       unsigned int Index3;
654                       for (Index3 = 0; Index3<Comment.ListSize() ;Index3++) {
655                         if (Comment[Index3]->Generic().GlobalId == KaxTagMultiCommentName::ClassInfos.GlobalId) {
656                           KaxTagMultiCommentName & CommentName = *static_cast<KaxTagMultiCommentName *>(Comment[Index3]);
657                           printf("      Comment Name \"%s\"\n", std::string(CommentName).c_str());
658                         }
659                       }
660 //                    } else if (Targets[Index2]->Generic().GlobalId == DummyRawElement::ClassInfos.GlobalId) {
661 #endif
662                     }
663                   }
664 #ifdef TEST_REMOVE
665                   if (bRemoved) {
666                     printf("    -- Again After Deletion --\n");
667                     bRemoved = false;
668                   } else if (bRemovedDone) {
669                     printf("    -- Done --\n");
670                   }
671 #endif // TEST_REMOVE
672 #if 0
673                 } else if (TagElt[Index1]->Generic().GlobalId == KaxTagGeneral::ClassInfos.GlobalId) {
674                   printf("    General\n");
675                   KaxTagGeneral & General = *static_cast<KaxTagGeneral *>(TagElt[Index1]);
676                   unsigned int Index2;
677                   for (Index2 = 0; Index2<General.ListSize() ;Index2++) {
678                     if (General[Index2]->Generic().GlobalId == KaxTagSubject::ClassInfos.GlobalId) {
679                       printf("     Subject\n");
680                     } else if (General[Index2]->Generic().GlobalId == KaxTagBibliography::ClassInfos.GlobalId) {
681                       printf("     Bibliography\n");
682                     } else if (General[Index2]->Generic().GlobalId == KaxTagLanguage::ClassInfos.GlobalId) {
683                       printf("     Language\n");
684                     }
685                   }
686                 } else if (TagElt[Index1]->Generic().GlobalId == KaxTagMultiCommercial::ClassInfos.GlobalId) {
687                   printf("    MultiCommercial\n");
688                   KaxTagMultiCommercial & Commercials = *static_cast<KaxTagMultiCommercial *>(TagElt[Index1]);
689                   unsigned int Index2;
690                   for (Index2 = 0; Index2<Commercials.ListSize() ;Index2++) {
691                     if (Commercials[Index2]->Generic().GlobalId == KaxTagCommercial::ClassInfos.GlobalId) {
692                       printf("     Commercial\n");
693                       KaxTagCommercial & Commercial = *static_cast<KaxTagCommercial *>(Commercials[Index2]);
694                       unsigned int Index3;
695                       for (Index3 = 0; Index3<Commercial.ListSize() ;Index3++) {
696                         if (Commercial[Index3]->Generic().GlobalId == KaxTagMultiCommercialType::ClassInfos.GlobalId) {
697                           printf("      Type\n");
698                         } else if (Commercial[Index3]->Generic().GlobalId == KaxTagMultiPrice::ClassInfos.GlobalId) {
699                           printf("      Prices\n");
700                           KaxTagMultiPrice & Prices = *static_cast<KaxTagMultiPrice *>(Commercial[Index3]);
701                           unsigned int Index4;
702                           for (Index4 = 0; Index4<Prices.ListSize(); Index4++) {
703                             if (Prices[Index4]->Generic().GlobalId == KaxTagMultiPriceCurrency::ClassInfos.GlobalId) {
704                               printf("       Currency\n");
705                             } else if (Prices[Index4]->Generic().GlobalId == KaxTagMultiPriceAmount::ClassInfos.GlobalId) {
706                               printf("       Amount\n");
707                             }
708                           }
709                         }
710                       }
711                     }
712                   }
713                 } else if (TagElt[Index1]->Generic().GlobalId == KaxTagMultiDate::ClassInfos.GlobalId) {
714                   printf("    MultiDate\n");
715                 } else if (TagElt[Index1]->Generic().GlobalId == KaxTagMultiComment::ClassInfos.GlobalId) {
716                   printf("    Comment\n");
717                   KaxTagMultiComment & Comment = *static_cast<KaxTagMultiComment *>(TagElt[Index1]);
718                   unsigned int Index2;
719                   for (Index2 = 0; Index2<Comment.ListSize() ;Index2++) {
720                     if (Comment[Index2]->Generic().GlobalId == KaxTagMultiCommentName::ClassInfos.GlobalId) {
721                       KaxTagMultiCommentName & CommentName = *static_cast<KaxTagMultiCommentName *>(Comment[Index2]);
722                       printf("     Comment Name \"%s\"\n", std::string(CommentName).c_str());
723                     }
724                   }
725 #endif
726                 }
727               }
728             }
729           }
730           if (AllTags->HasChecksum()) {
731             if (AllTags->VerifyChecksum()) {
732               printf(" ++ CheckSum verification succeeded ++\n");
733             } else {
734               printf(" ++ CheckSum verification FAILED !!! ++\n");
735             }
736           }
737         }
738 
739         if (UpperElementLevel > 0) {
740           UpperElementLevel--;
741           delete ElementLevel1;
742           ElementLevel1 = ElementLevel2;
743           if (UpperElementLevel > 0)
744             break;
745         } else {
746           ElementLevel1->SkipData(aStream, ElementLevel1->Generic().Context);
747           delete ElementLevel1;
748 
749           ElementLevel1 = aStream.FindNextElement(ElementLevel0->Generic().Context, UpperElementLevel, 0, bAllowDummy);
750         }
751       }
752     }
753   }
754 
755 #ifdef OLD
756   uint8 TrackNumber = MuxedFile.GetTrackNumber();
757 
758   TrackInfo *Tracks = new TrackInfo[TrackNumber];
759   TrackInfoAudio aAudioTrack;
760   TrackInfoVideo aVideoTrack;
761 
762   Track * track1 = MuxedFile.GetTrack(1);
763   Track * track2 = MuxedFile.GetTrack(2);
764   Track * track3 = MuxedFile.GetTrack(3); // should be 0
765   // get information about the 1st track
766 
767   MuxedFile.Track_GetInfo(track1, Tracks[0]);
768   displayTrackInfo(Tracks[0]);
769 
770   if (Tracks[0].TrackType == track_audio) {
771       MuxedFile.Track_GetInfo_Audio(track1, aAudioTrack);
772       displayAudioInfo(aAudioTrack);
773   }
774   else
775       cout << "the expected audio track is not an audio one :(" << endl;
776 
777   MuxedFile.Track_GetInfo(track3, Tracks[2]);
778   displayTrackInfo(Tracks[2]);
779 
780   if (Tracks[2].TrackType == track_video) {
781       MuxedFile.Track_GetInfo_Video(track3, aVideoTrack);
782       displayVideoInfo(aVideoTrack);
783   }
784   else
785       cout << "the expected video track is not an video one :(" << endl;
786 
787   // let's read only track1 (audio)
788   MuxedFile.SelectReadingTrack(track1);
789   MuxedFile.SelectReadingTrack(track2);
790   MuxedFile.SelectReadingTrack(track1,false);
791   MuxedFile.SelectReadingTrack(track1);
792   MuxedFile.SelectReadingTrack(track2,false);
793   MuxedFile.SelectReadingTrack(track2);
794   MuxedFile.SelectReadingTrack(track3);
795 
796   // read the frames from the selected tracks and put them in an output file
797   StdIOCallback Output_file1("out-binr.bin", MODE_CREATE);
798   StdIOCallback Output_file2("out-text.bin", MODE_CREATE);
799   StdIOCallback Output_file3("out-vide.bin", MODE_CREATE);
800 
801   Track * TrackRead;
802   uint32 timecode; // not used yet
803   binary *aFrame;
804   uint32 aFrameSize;
805   while (MuxedFile.ReadFrame(TrackRead, timecode, aFrame, aFrameSize))
806   {
807       if (TrackRead == track1)
808       {
809     Output_file1.write(aFrame, aFrameSize);
810       }
811       else if (TrackRead == track2)
812       {
813     Output_file2.write(aFrame, aFrameSize);
814       }
815       else if (TrackRead == track3)
816       {
817     Output_file3.write(aFrame, aFrameSize);
818       }
819       else cout << "received a frame from an unwanted track" << endl;
820   }
821   delete[] Tracks;
822 #endif // OLD
823     }
824     catch (exception & Ex)
825     {
826     cout << Ex.what() << endl;
827     return -1;
828     }
829 
830     return 0;
831 }
832