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