/**************************************************************************** ** libmatroska : parse Matroska files, see http://www.matroska.org/ ** ** ** ** Copyright (C) 2002-2004 Steve Lhomme. All rights reserved. ** ** This library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public ** License as published by the Free Software Foundation; either ** version 2.1 of the License, or (at your option) any later version. ** ** This library is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with this library; if not, write to the Free Software ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ** ** See http://www.gnu.org/licenses/lgpl-2.1.html for LGPL licensing information.** ** Contact license@matroska.org if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ /*! \file \version \$Id$ \brief Test reading of the Header \author Steve Lhomme */ #include #include #if __GNUC__ == 2 #include #endif #include "ebml/EbmlHead.h" #include "ebml/EbmlSubHead.h" #include "ebml/EbmlStream.h" #include "ebml/EbmlContexts.h" #include "ebml/EbmlVoid.h" #include "ebml/EbmlCrc32.h" #include "matroska/FileKax.h" #include "matroska/KaxSegment.h" #include "matroska/KaxContexts.h" #include "matroska/KaxTracks.h" #include "matroska/KaxInfoData.h" #include "matroska/KaxCluster.h" #include "matroska/KaxBlockData.h" #include "matroska/KaxSeekHead.h" #include "matroska/KaxCuesData.h" #include "ebml/StdIOCallback.h" using namespace LIBMATROSKA_NAMESPACE; using namespace std; #define NO_DISPLAY_DATA //#define JUMP_TEST /*! \note you can generate the file used in this example using test6.cpp \todo the blocks with "titi" and "tetetete" don't seem to be read ! */ int main(int argc, char **argv) { try { StdIOCallback Cluster_file((argc>=2 ? argv[1] : "muxed.mkv"), MODE_READ); // create the Matroska file /// FileKax MuxedFile(Cluster_file); // bool bAllowDummy = false; // don't read elements we don't know bool bAllowDummy = true; // even read elements we don't know (needed for CRC checking) // read the EBML head EbmlStream aStream(Cluster_file); EbmlElement * ElementLevel0; EbmlElement * ElementLevel1; EbmlElement * ElementLevel2; EbmlElement * ElementLevel3 = NULL; EbmlElement * ElementLevel4 = NULL; /// MuxedFile.ReadHead(); // find the EBML head in the file ElementLevel0 = aStream.FindNextID(EbmlHead::ClassInfos, 0xFFFFFFFFL); if (ElementLevel0 != NULL) { printf("EBML : "); for (unsigned int i=0; i> (8*(3-i))) & 0xFF); } printf("\n"); ElementLevel0->SkipData(aStream, EbmlHead_Context); if (ElementLevel0 != NULL) delete ElementLevel0; } int UpperElementLevel = 0; KaxSegment * Segment; KaxInfo * SegmentInfo; KaxTrackEntry * TrackAudio; KaxTrackEntry * TrackVideo; KaxCluster *SegmentCluster; KaxCues *CuesEntry; KaxSeekHead *MetaSeek; KaxChapters *Chapters; KaxTags *AllTags; uint64 TimecodeScale = 1000000; // find the segment to read ElementLevel0 = aStream.FindNextID(KaxSegment::ClassInfos, 0xFFFFFFFFL); if (ElementLevel0 != NULL) { if (EbmlId(*ElementLevel0) == KaxSegment::ClassInfos.GlobalId) { Segment = static_cast(ElementLevel0); // MuxedFile.ReadTracks(); // MuxedFile.ReadCodec(); // scan the file for a Tracks element (all previous Level1 elements are discarded) ElementLevel1 = aStream.FindNextElement(ElementLevel0->Generic().Context, UpperElementLevel, 0, bAllowDummy); while (ElementLevel1 != NULL) { if (UpperElementLevel > 0) { break; } if (UpperElementLevel < 0) { UpperElementLevel = 0; } /// \todo switch the type of the element to check if it's one we want to handle, like attachements if (EbmlId(*ElementLevel1) == EbmlVoid::ClassInfos.GlobalId) { printf("\n- Void found\n"); } else if (EbmlId(*ElementLevel1) == KaxTracks::ClassInfos.GlobalId) { // found the Tracks element printf("\n- Segment Tracks found\n"); // handle the data in Tracks here. // poll for new tracks and handle them ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy); while (ElementLevel2 != NULL) { if (UpperElementLevel > 0) { break; } if (UpperElementLevel < 0) { UpperElementLevel = 0; } /// \todo switch the type of the element to check if it's one we want to handle, like attachements if (EbmlId(*ElementLevel2) == KaxTrackEntry::ClassInfos.GlobalId) { printf("* Found a track\n"); ElementLevel3 = aStream.FindNextElement(ElementLevel2->Generic().Context, UpperElementLevel, 0, bAllowDummy); while (ElementLevel3 != NULL) { if (UpperElementLevel > 0) { break; } if (UpperElementLevel < 0) { UpperElementLevel = 0; } // read the data we care about in a track // Track number if (EbmlId(*ElementLevel3) == KaxTrackNumber::ClassInfos.GlobalId) { KaxTrackNumber & TrackNum = *static_cast(ElementLevel3); TrackNum.ReadData(aStream.I_O()); printf("Track # %d\n", uint8(TrackNum)); } // Track type else if (EbmlId(*ElementLevel3) == KaxTrackType::ClassInfos.GlobalId) { KaxTrackType & TrackType = *static_cast(ElementLevel3); TrackType.ReadData(aStream.I_O()); printf("Track type : "); switch(uint8(TrackType)) { case track_audio: printf("Audio"); TrackAudio = static_cast(ElementLevel2); TrackAudio->SetGlobalTimecodeScale(TimecodeScale); break; case track_video: printf("Video"); TrackVideo = static_cast(ElementLevel2); TrackVideo->SetGlobalTimecodeScale(TimecodeScale); break; default: printf("unknown"); } printf("\n"); } else if (EbmlId(*ElementLevel3) == KaxTrackFlagLacing::ClassInfos.GlobalId) { printf("Flag Lacing\n"); } else if (EbmlId(*ElementLevel3) == KaxCodecID::ClassInfos.GlobalId) { KaxCodecID & CodecID = *static_cast(ElementLevel3); CodecID.ReadData(aStream.I_O()); printf("Codec ID : %s\n", string(CodecID).c_str()); } if (UpperElementLevel > 0) { assert(0 == 1); // impossible to be here ? UpperElementLevel--; delete ElementLevel2; ElementLevel2 = ElementLevel3; if (UpperElementLevel > 0) break; } else { ElementLevel3->SkipData(aStream, ElementLevel3->Generic().Context); delete ElementLevel3; ElementLevel3 = aStream.FindNextElement(ElementLevel2->Generic().Context, UpperElementLevel, 0, bAllowDummy); } } } if (UpperElementLevel > 0) { UpperElementLevel--; delete ElementLevel2; ElementLevel2 = ElementLevel3; if (UpperElementLevel > 0) break; } else { ElementLevel2->SkipData(aStream, ElementLevel2->Generic().Context); delete ElementLevel2; ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy); } } } else if (EbmlId(*ElementLevel1) == KaxInfo::ClassInfos.GlobalId) { printf("\n- Segment Informations found\n"); SegmentInfo = static_cast(ElementLevel1); #ifdef JUMP_TEST // test jumping to a random location and find the next Level 0 / Level 1 element aStream.I_O().setFilePointer(79, seek_current); printf("Seeked at position 0x%X in the file", aStream.I_O().getFilePointer()); int LowLevel = 1; ElementLevel2 = aStream.FindNextElement(KaxSegment::ClassInfos.Context, LowLevel, 0, false); // search up to one level lower UpperElementLevel = LowLevel; #else // JUMP_TEST // read the data we care about in matroska /// \todo There should be a way to get the default values of the elements not defined ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy); while (ElementLevel2 != NULL) { if (UpperElementLevel > 0) { break; } if (UpperElementLevel < 0) { UpperElementLevel = 0; } if (EbmlId(*ElementLevel2) == KaxTimecodeScale::ClassInfos.GlobalId) { KaxTimecodeScale *TimeScale = static_cast(ElementLevel2); TimeScale->ReadData(aStream.I_O()); printf("Timecode Scale %d\n", uint32(*TimeScale)); TimecodeScale = uint64(*TimeScale); } else if (EbmlId(*ElementLevel2) == KaxDuration::ClassInfos.GlobalId) { printf("Segment duration\n"); } else if (EbmlId(*ElementLevel2) == KaxDateUTC::ClassInfos.GlobalId) { printf("Date UTC\n"); } else if (EbmlId(*ElementLevel2) == KaxTitle::ClassInfos.GlobalId) { printf("Title\n"); } else if (EbmlId(*ElementLevel2) == KaxMuxingApp::ClassInfos.GlobalId) { KaxMuxingApp *pApp = static_cast(ElementLevel2); pApp->ReadData(aStream.I_O()); #if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__BEOS__) && !defined(__NetBSD__) wprintf(L"Muxing App : %ls\n", UTFstring(*pApp).c_str()); #else printf("Muxing App : %s\n", UTFstring(*pApp).c_str()); #endif } else if (EbmlId(*ElementLevel2) == KaxWritingApp::ClassInfos.GlobalId) { KaxWritingApp *pApp = static_cast(ElementLevel2); pApp->ReadData(aStream.I_O()); #if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__BEOS__) && !defined(__NetBSD__) wprintf(L"Writing App : %ls (יאפן)\n", UTFstring(*pApp).c_str()); #else printf("Writing App : %s (יאפן)\n", UTFstring(*pApp).c_str()); #endif } if (UpperElementLevel > 0) { UpperElementLevel--; delete ElementLevel2; ElementLevel2 = ElementLevel3; if (UpperElementLevel > 0) break; } else { ElementLevel2->SkipData(aStream, ElementLevel2->Generic().Context); delete ElementLevel2; ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy); } } #endif // JUMP_TEST } else if (EbmlId(*ElementLevel1) == KaxCluster::ClassInfos.GlobalId) { printf("\n- Segment Clusters found\n"); SegmentCluster = static_cast(ElementLevel1); // SegmentCluster->ClearElement(); uint32 ClusterTimecode; EbmlCrc32 *pChecksum = NULL; uint32 SizeInCrc; uint64 CrcPositionStart = 0; #ifdef MEMORY_READ // read the Cluster in memory and then extract elements from memory SegmentCluster->Read(aStream, KaxCluster::ClassInfos.Context, UpperElementLevel, ElementLevel2, bAllowDummy); if (SegmentCluster->CheckMandatory()) { printf(" * All mandatory elements found *\n"); } else { printf(" * Some mandatory elements ar missing !!! *\n"); } // display the elements read unsigned int Index0; for (Index0 = 0; Index0ListSize() ;Index0++) { printf(" - found %s\n", (*SegmentCluster)[Index0]->Generic().DebugName); } #else // not MEMORY_READ // read blocks and discard the ones we don't care about ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy); while (ElementLevel2 != NULL) { if (UpperElementLevel > 0) { break; } if (UpperElementLevel < 0) { UpperElementLevel = 0; } if (EbmlId(*ElementLevel2) == KaxClusterTimecode::ClassInfos.GlobalId) { printf("Cluster timecode found\n"); KaxClusterTimecode & ClusterTime = *static_cast(ElementLevel2); ClusterTime.ReadData(aStream.I_O()); ClusterTimecode = uint32(ClusterTime); SegmentCluster->InitTimecode(ClusterTimecode, TimecodeScale); } else if (EbmlId(*ElementLevel2) == KaxBlockGroup::ClassInfos.GlobalId) { printf("Block Group found\n"); #ifdef TEST_BLOCKGROUP_READ KaxBlockGroup & aBlockGroup = *static_cast(ElementLevel2); // aBlockGroup.ClearElement(); // Extract the valuable data from the Block aBlockGroup.Read(aStream, KaxBlockGroup::ClassInfos.Context, UpperElementLevel, ElementLevel3, bAllowDummy); KaxBlock * DataBlock = static_cast(aBlockGroup.FindElt(KaxBlock::ClassInfos)); if (DataBlock != NULL) { // DataBlock->ReadData(aStream.I_O()); DataBlock->SetParent(*SegmentCluster); printf(" Track # %d / %d frame%s / Timecode %I64d\n",DataBlock->TrackNum(), DataBlock->NumberFrames(), (DataBlock->NumberFrames() > 1)?"s":"", DataBlock->GlobalTimecode()); } else { printf(" A BlockGroup without a Block !!!"); } KaxBlockDuration * BlockDuration = static_cast(aBlockGroup.FindElt(KaxBlockDuration::ClassInfos)); if (BlockDuration != NULL) { printf(" Block Duration %d scaled ticks : %ld ns\n", uint32(*BlockDuration), uint32(*BlockDuration) * TimecodeScale); } KaxReferenceBlock * RefTime = static_cast(aBlockGroup.FindElt(KaxReferenceBlock::ClassInfos)); if (RefTime != NULL) { printf(" Reference frame at scaled (%d) timecode %ld\n", int32(*RefTime), int32(int64(*RefTime) * TimecodeScale)); } #else // TEST_BLOCKGROUP_READ // read the data we care about in matroska /// \todo There should be a way to get the default values of the elements not defined ElementLevel3 = aStream.FindNextElement(ElementLevel2->Generic().Context, UpperElementLevel, 0, bAllowDummy); while (ElementLevel3 != NULL) { if (UpperElementLevel > 0) { break; } if (UpperElementLevel < 0) { UpperElementLevel = 0; } if (EbmlId(*ElementLevel3) == KaxBlock::ClassInfos.GlobalId) { printf(" Block Data\n"); KaxBlock & DataBlock = *static_cast(ElementLevel3); #ifdef NO_DISPLAY_DATA DataBlock.ReadData(aStream.I_O(), SCOPE_PARTIAL_DATA); #else // NO_DISPLAY_DATA DataBlock.ReadData(aStream.I_O(), SCOPE_ALL_DATA); #endif // NO_DISPLAY_DATA DataBlock.SetParent(*SegmentCluster); printf(" Track # %d / %d frame%s / Timecode %I64d\n",DataBlock.TrackNum(), DataBlock.NumberFrames(), (DataBlock.NumberFrames() > 1)?"s":"", DataBlock.GlobalTimecode()); #ifndef NO_DISPLAY_DATA for (unsigned int i=0; i< DataBlock.NumberFrames(); i++) { printf(" [%s]\n",DataBlock.GetBuffer(i).Buffer()); // STRING ONLY POSSIBLE WITH THIS PARTICULAR EXAMPLE (the binary data is a string) } #endif // NO_DISPLAY_DATA // printf("Codec ID : %s\n", &binary(CodecID)); // strings for the moment (example) #if MATROSKA_VERSION >= 2 } else if (EbmlId(*ElementLevel3) == KaxBlockVirtual::ClassInfos.GlobalId) { printf(" Virtual Block\n"); } else if (EbmlId(*ElementLevel3) == KaxReferenceVirtual::ClassInfos.GlobalId) { printf(" virtual Reference\n"); #endif // MATROSKA_VERSION } else if (EbmlId(*ElementLevel3) == KaxReferencePriority::ClassInfos.GlobalId) { printf(" Reference priority\n"); } else if (EbmlId(*ElementLevel3) == KaxReferenceBlock::ClassInfos.GlobalId) { KaxReferenceBlock & RefTime = *static_cast(ElementLevel3); RefTime.ReadData(aStream.I_O()); printf(" Reference frame at scaled (%d) timecode %ld\n", int32(RefTime), int32(int64(RefTime) * TimecodeScale)); } else if (EbmlId(*ElementLevel3) == KaxBlockDuration::ClassInfos.GlobalId) { KaxBlockDuration & BlockDuration = *static_cast(ElementLevel3); BlockDuration.ReadData(aStream.I_O()); printf(" Block Duration %d scaled ticks : %ld ns\n", uint32(BlockDuration), uint32(BlockDuration) * TimecodeScale); } if (UpperElementLevel > 0) { UpperElementLevel--; delete ElementLevel3; ElementLevel3 = ElementLevel4; if (UpperElementLevel > 0) break; } else { ElementLevel3->SkipData(aStream, ElementLevel3->Generic().Context); ElementLevel3 = aStream.FindNextElement(ElementLevel2->Generic().Context, UpperElementLevel, 0, bAllowDummy); } } #endif // TEST_BLOCKGROUP_READ } else if (EbmlId(*ElementLevel2) == EbmlCrc32::ClassInfos.GlobalId) { printf("Cluster CheckSum !\n"); pChecksum = static_cast(ElementLevel2); pChecksum->ReadData(aStream.I_O()); SegmentCluster->ForceChecksum( pChecksum->GetCrc32() ); // not use later SizeInCrc = 0; CrcPositionStart = aStream.I_O().getFilePointer(); } if (UpperElementLevel > 0) { UpperElementLevel--; delete ElementLevel2; ElementLevel2 = ElementLevel3; if (UpperElementLevel > 0) break; } else { ElementLevel2->SkipData(aStream, ElementLevel2->Generic().Context); if (ElementLevel2 != pChecksum) delete ElementLevel2; ElementLevel2 = aStream.FindNextElement(ElementLevel1->Generic().Context, UpperElementLevel, 0, bAllowDummy); } } #endif // not MEMORY_READ if (pChecksum != NULL) { EbmlCrc32 ComputedChecksum; uint64 CurrPosition = aStream.I_O().getFilePointer(); uint64 CrcPositionEnd = ElementLevel2->GetElementPosition(); binary *SupposedBufferInCrc = new binary [CrcPositionEnd - CrcPositionStart]; aStream.I_O().setFilePointer(CrcPositionStart); aStream.I_O().readFully(SupposedBufferInCrc, CrcPositionEnd - CrcPositionStart); aStream.I_O().setFilePointer(CurrPosition); ComputedChecksum.FillCRC32(SupposedBufferInCrc, CrcPositionEnd - CrcPositionStart); delete [] SupposedBufferInCrc; if (pChecksum->GetCrc32() == ComputedChecksum.GetCrc32()) { printf(" ++ CheckSum verification succeeded ++"); } else { printf(" ++ CheckSum verification FAILED !!! ++"); } delete pChecksum; pChecksum = NULL; } } else if (EbmlId(*ElementLevel1) == KaxCues::ClassInfos.GlobalId) { printf("\n- Cue entries found\n"); CuesEntry = static_cast(ElementLevel1); CuesEntry->SetGlobalTimecodeScale(TimecodeScale); // read everything in memory CuesEntry->Read(aStream, KaxCues::ClassInfos.Context, UpperElementLevel, ElementLevel2, bAllowDummy); // build the entries in memory if (CuesEntry->CheckMandatory()) { printf(" * All mandatory elements found *\n"); } else { printf(" * Some mandatory elements ar missing !!! *\n"); } CuesEntry->Sort(); // display the elements read unsigned int Index0; for (Index0 = 0; Index0ListSize() ;Index0++) { if ((*CuesEntry)[Index0]->Generic().GlobalId == KaxCuePoint::ClassInfos.GlobalId) { printf(" Cue Point\n"); KaxCuePoint & CuePoint = *static_cast((*CuesEntry)[Index0]); unsigned int Index1; for (Index1 = 0; Index1Generic().GlobalId == KaxCueTime::ClassInfos.GlobalId) { KaxCueTime & CueTime = *static_cast(CuePoint[Index1]); printf(" Time %ld\n", uint64(CueTime) * TimecodeScale); } else if (CuePoint[Index1]->Generic().GlobalId == KaxCueTrackPositions::ClassInfos.GlobalId) { KaxCueTrackPositions & CuePos = *static_cast(CuePoint[Index1]); printf(" Positions\n"); unsigned int Index2; for (Index2 = 0; Index2Generic().GlobalId == KaxCueTrack::ClassInfos.GlobalId) { KaxCueTrack & CueTrack = *static_cast(CuePos[Index2]); printf(" Track %d\n", uint16(CueTrack)); } else if (CuePos[Index2]->Generic().GlobalId == KaxCueClusterPosition::ClassInfos.GlobalId) { KaxCueClusterPosition & CuePoss = *static_cast(CuePos[Index2]); printf(" Cluster position %d\n", uint64(CuePoss)); #if MATROSKA_VERSION >= 2 } else if (CuePos[Index2]->Generic().GlobalId == KaxCueReference::ClassInfos.GlobalId) { KaxCueReference & CueRefs = *static_cast(CuePos[Index2]); printf(" Reference\n"); unsigned int Index3; for (Index3 = 0; Index3Generic().GlobalId == KaxCueRefTime::ClassInfos.GlobalId) { KaxCueRefTime & CueTime = *static_cast(CueRefs[Index3]); printf(" Time %d\n", uint32(CueTime)); } else if (CueRefs[Index3]->Generic().GlobalId == KaxCueRefCluster::ClassInfos.GlobalId) { KaxCueRefCluster & CueClust = *static_cast(CueRefs[Index3]); printf(" Cluster position %d\n", uint64(CueClust)); } else { printf(" - found %s\n", CueRefs[Index3]->Generic().DebugName); } } #endif // MATROSKA_VERSION } else { printf(" - found %s\n", CuePos[Index2]->Generic().DebugName); } } } else { printf(" - found %s\n", CuePoint[Index1]->Generic().DebugName); } } } else { printf(" - found %s\n", (*CuesEntry)[Index0]->Generic().DebugName); } } } else if (EbmlId(*ElementLevel1) == KaxSeekHead::ClassInfos.GlobalId) { printf("\n- Meta Seek found\n"); MetaSeek = static_cast(ElementLevel1); // read it in memory MetaSeek->Read(aStream, KaxSeekHead::ClassInfos.Context, UpperElementLevel, ElementLevel2, bAllowDummy); if (MetaSeek->CheckMandatory()) { printf(" * All mandatory elements found *\n"); } else { printf(" * Some mandatory elements ar missing !!! *\n"); } unsigned int Index0; for (Index0 = 0; Index0ListSize() ;Index0++) { if ((*MetaSeek)[Index0]->Generic().GlobalId == KaxSeek::ClassInfos.GlobalId) { printf(" Seek Point\n"); KaxSeek & SeekPoint = *static_cast((*MetaSeek)[Index0]); unsigned int Index1; for (Index1 = 0; Index1Generic().GlobalId == KaxSeekID::ClassInfos.GlobalId) { KaxSeekID * SeekID = static_cast(SeekPoint[Index1]); printf(" Seek ID ", SeekID->GetBuffer()); for (unsigned int i=0; iGetSize(); i++) { printf("%02X", SeekID->GetBuffer()[i]); } printf("\n"); } else if (SeekPoint[Index1]->Generic().GlobalId == KaxSeekPosition::ClassInfos.GlobalId) { KaxSeekPosition * SeekPos = static_cast(SeekPoint[Index1]); printf(" Seek position %d\n", uint32(*SeekPos)); } } } } } else if (EbmlId(*ElementLevel1) == KaxChapters::ClassInfos.GlobalId) { printf("\n- Chapters found\n"); Chapters = static_cast(ElementLevel1); // read it in memory Chapters->Read(aStream, KaxChapters::ClassInfos.Context, UpperElementLevel, ElementLevel2, bAllowDummy); if (Chapters->CheckMandatory()) { printf(" * All mandatory elements found *\n"); } else { printf(" * Some mandatory elements ar missing !!! *\n"); } unsigned int Index0; for (Index0 = 0; Index0ListSize() ;Index0++) { if ((*Chapters)[Index0]->Generic().GlobalId == KaxEditionEntry::ClassInfos.GlobalId) { printf(" Edition\n"); KaxEditionEntry & Edition = *static_cast((*Chapters)[Index0]); unsigned int Index2; for (Index2 = 0; Index2Generic().GlobalId == KaxChapterAtom::ClassInfos.GlobalId) { printf(" Chapter Atom\n"); KaxChapterAtom & aChapterAtom = *static_cast(Edition[Index2]); unsigned int Index3; for (Index3 = 0; Index3Generic().GlobalId == KaxChapterUID::ClassInfos.GlobalId) { printf(" Chapter UID 0x%08x\n", uint32(*static_cast(aChapterAtom[Index3])) ); } else if (aChapterAtom[Index3]->Generic().GlobalId == KaxChapterTimeStart::ClassInfos.GlobalId) { printf(" Time Start %d\n", uint32(*static_cast(aChapterAtom[Index3])) ); } else if (aChapterAtom[Index3]->Generic().GlobalId == KaxChapterTimeEnd::ClassInfos.GlobalId) { printf(" Time End %d ns\n", uint32(*static_cast(aChapterAtom[Index3])) ); } else if (aChapterAtom[Index3]->Generic().GlobalId == KaxChapterTrack::ClassInfos.GlobalId) { printf(" Track list\n"); } else if (aChapterAtom[Index3]->Generic().GlobalId == KaxChapterDisplay::ClassInfos.GlobalId) { printf(" Display info\n"); KaxChapterDisplay & aDisplay = *static_cast(aChapterAtom[Index3]); unsigned int Index4; for (Index4 = 0; Index4Generic().GlobalId == KaxChapterString::ClassInfos.GlobalId) { #if !defined(__CYGWIN__) && !defined(__APPLE__) && !defined(__BEOS__) && !defined(__NetBSD__) wprintf(L" Display \"%s\"\n", UTFstring(*static_cast(aDisplay[Index4])).c_str() ); #else printf(" Display \"%s\"\n", UTFstring(*static_cast(aDisplay[Index4])).c_str() ); #endif } else if (aDisplay[Index4]->Generic().GlobalId == KaxChapterLanguage::ClassInfos.GlobalId) { printf(" For language \"%s\"\n", std::string(*static_cast(aDisplay[Index4])).c_str() ); } else if (aDisplay[Index4]->Generic().GlobalId == KaxChapterCountry::ClassInfos.GlobalId) { printf(" For country \"%s\"\n", std::string(*static_cast(aDisplay[Index4])).c_str() ); } else if (aDisplay[Index4]->IsDummy()) { printf(" Dummy !!!\n"); } } } } } } } } } else if (EbmlId(*ElementLevel1) == KaxTags::ClassInfos.GlobalId) { printf("\n- Tags found\n"); AllTags = static_cast(ElementLevel1); // read it in memory AllTags->Read(aStream, KaxTags::ClassInfos.Context, UpperElementLevel, ElementLevel2, bAllowDummy); if (AllTags->CheckMandatory()) { printf(" * All mandatory elements found *\n"); } else { printf(" * Some mandatory elements ar missing !!! *\n"); } unsigned int Index0; for (Index0 = 0; Index0ListSize() ;Index0++) { if ((*AllTags)[Index0]->Generic().GlobalId == KaxTag::ClassInfos.GlobalId) { printf(" Tag\n"); KaxTag & TagElt = *static_cast((*AllTags)[Index0]); unsigned int Index1; for (Index1 = 0; Index1Generic().GlobalId == KaxTagTargets::ClassInfos.GlobalId) { printf(" Targets\n"); KaxTagTargets & Targets = *static_cast(TagElt[Index1]); unsigned int Index2; for (Index2 = 0; Index2Generic().GlobalId == KaxTagTrackUID::ClassInfos.GlobalId) { #ifndef TEST_REMOVE printf(" Track UID\n"); #else // TEST_REMOVE printf(" Track UID (will be removed)\n"); /*************** Test to remove an element ***************/ Targets.Remove(Index2); bRemoved = true; bRemovedDone = false; Index2--; Index1--; #endif // TEST_REMOVE } else if (Targets[Index2]->Generic().GlobalId == KaxTagChapterUID::ClassInfos.GlobalId) { printf(" Chapter UID\n"); #if 0 } else if (Targets[Index2]->Generic().GlobalId == KaxTagMultiComment::ClassInfos.GlobalId) { printf(" Comment\n"); KaxTagMultiComment & Comment = *static_cast(Targets[Index2]); unsigned int Index3; for (Index3 = 0; Index3Generic().GlobalId == KaxTagMultiCommentName::ClassInfos.GlobalId) { KaxTagMultiCommentName & CommentName = *static_cast(Comment[Index3]); printf(" Comment Name \"%s\"\n", std::string(CommentName).c_str()); } } // } else if (Targets[Index2]->Generic().GlobalId == DummyRawElement::ClassInfos.GlobalId) { #endif } } #ifdef TEST_REMOVE if (bRemoved) { printf(" -- Again After Deletion --\n"); bRemoved = false; } else if (bRemovedDone) { printf(" -- Done --\n"); } #endif // TEST_REMOVE #if 0 } else if (TagElt[Index1]->Generic().GlobalId == KaxTagGeneral::ClassInfos.GlobalId) { printf(" General\n"); KaxTagGeneral & General = *static_cast(TagElt[Index1]); unsigned int Index2; for (Index2 = 0; Index2Generic().GlobalId == KaxTagSubject::ClassInfos.GlobalId) { printf(" Subject\n"); } else if (General[Index2]->Generic().GlobalId == KaxTagBibliography::ClassInfos.GlobalId) { printf(" Bibliography\n"); } else if (General[Index2]->Generic().GlobalId == KaxTagLanguage::ClassInfos.GlobalId) { printf(" Language\n"); } } } else if (TagElt[Index1]->Generic().GlobalId == KaxTagMultiCommercial::ClassInfos.GlobalId) { printf(" MultiCommercial\n"); KaxTagMultiCommercial & Commercials = *static_cast(TagElt[Index1]); unsigned int Index2; for (Index2 = 0; Index2Generic().GlobalId == KaxTagCommercial::ClassInfos.GlobalId) { printf(" Commercial\n"); KaxTagCommercial & Commercial = *static_cast(Commercials[Index2]); unsigned int Index3; for (Index3 = 0; Index3Generic().GlobalId == KaxTagMultiCommercialType::ClassInfos.GlobalId) { printf(" Type\n"); } else if (Commercial[Index3]->Generic().GlobalId == KaxTagMultiPrice::ClassInfos.GlobalId) { printf(" Prices\n"); KaxTagMultiPrice & Prices = *static_cast(Commercial[Index3]); unsigned int Index4; for (Index4 = 0; Index4Generic().GlobalId == KaxTagMultiPriceCurrency::ClassInfos.GlobalId) { printf(" Currency\n"); } else if (Prices[Index4]->Generic().GlobalId == KaxTagMultiPriceAmount::ClassInfos.GlobalId) { printf(" Amount\n"); } } } } } } } else if (TagElt[Index1]->Generic().GlobalId == KaxTagMultiDate::ClassInfos.GlobalId) { printf(" MultiDate\n"); } else if (TagElt[Index1]->Generic().GlobalId == KaxTagMultiComment::ClassInfos.GlobalId) { printf(" Comment\n"); KaxTagMultiComment & Comment = *static_cast(TagElt[Index1]); unsigned int Index2; for (Index2 = 0; Index2Generic().GlobalId == KaxTagMultiCommentName::ClassInfos.GlobalId) { KaxTagMultiCommentName & CommentName = *static_cast(Comment[Index2]); printf(" Comment Name \"%s\"\n", std::string(CommentName).c_str()); } } #endif } } } } if (AllTags->HasChecksum()) { if (AllTags->VerifyChecksum()) { printf(" ++ CheckSum verification succeeded ++\n"); } else { printf(" ++ CheckSum verification FAILED !!! ++\n"); } } } if (UpperElementLevel > 0) { UpperElementLevel--; delete ElementLevel1; ElementLevel1 = ElementLevel2; if (UpperElementLevel > 0) break; } else { ElementLevel1->SkipData(aStream, ElementLevel1->Generic().Context); delete ElementLevel1; ElementLevel1 = aStream.FindNextElement(ElementLevel0->Generic().Context, UpperElementLevel, 0, bAllowDummy); } } } } #ifdef OLD uint8 TrackNumber = MuxedFile.GetTrackNumber(); TrackInfo *Tracks = new TrackInfo[TrackNumber]; TrackInfoAudio aAudioTrack; TrackInfoVideo aVideoTrack; Track * track1 = MuxedFile.GetTrack(1); Track * track2 = MuxedFile.GetTrack(2); Track * track3 = MuxedFile.GetTrack(3); // should be 0 // get information about the 1st track MuxedFile.Track_GetInfo(track1, Tracks[0]); displayTrackInfo(Tracks[0]); if (Tracks[0].TrackType == track_audio) { MuxedFile.Track_GetInfo_Audio(track1, aAudioTrack); displayAudioInfo(aAudioTrack); } else cout << "the expected audio track is not an audio one :(" << endl; MuxedFile.Track_GetInfo(track3, Tracks[2]); displayTrackInfo(Tracks[2]); if (Tracks[2].TrackType == track_video) { MuxedFile.Track_GetInfo_Video(track3, aVideoTrack); displayVideoInfo(aVideoTrack); } else cout << "the expected video track is not an video one :(" << endl; // let's read only track1 (audio) MuxedFile.SelectReadingTrack(track1); MuxedFile.SelectReadingTrack(track2); MuxedFile.SelectReadingTrack(track1,false); MuxedFile.SelectReadingTrack(track1); MuxedFile.SelectReadingTrack(track2,false); MuxedFile.SelectReadingTrack(track2); MuxedFile.SelectReadingTrack(track3); // read the frames from the selected tracks and put them in an output file StdIOCallback Output_file1("out-binr.bin", MODE_CREATE); StdIOCallback Output_file2("out-text.bin", MODE_CREATE); StdIOCallback Output_file3("out-vide.bin", MODE_CREATE); Track * TrackRead; uint32 timecode; // not used yet binary *aFrame; uint32 aFrameSize; while (MuxedFile.ReadFrame(TrackRead, timecode, aFrame, aFrameSize)) { if (TrackRead == track1) { Output_file1.write(aFrame, aFrameSize); } else if (TrackRead == track2) { Output_file2.write(aFrame, aFrameSize); } else if (TrackRead == track3) { Output_file3.write(aFrame, aFrameSize); } else cout << "received a frame from an unwanted track" << endl; } delete[] Tracks; #endif // OLD } catch (exception & Ex) { cout << Ex.what() << endl; return -1; } return 0; }