- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# MatroskaFile.cpp

    00001 /*
    00002  *      Copyright (C) 2003-2005 Gabest
    00003  *      http://www.gabest.org
    00004  *
    00005  *  This Program is free software; you can redistribute it and/or modify
    00006  *  it under the terms of the GNU General Public License as published by
    00007  *  the Free Software Foundation; either version 2, or (at your option)
    00008  *  any later version.
    00009  *
    00010  *  This Program is distributed in the hope that it will be useful,
    00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
    00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    00013  *  GNU General Public License for more details.
    00014  *
    00015  *  You should have received a copy of the GNU General Public License
    00016  *  along with GNU Make; see the file COPYING.  If not, write to
    00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
    00018  *  http://www.gnu.org/copyleft/gpl.html
    00019  *
    00020  */
    00021
    00022 #include "stdafx.h"
    00023 #include "MatroskaFile.h"
    00024 #include "..\..\..\DSUtil\DSUtil.h"
    00025 #include "..\..\..\zlib\zlib.h"
    00026
    00027 #define DOCTYPE _T("matroska")
    00028 #define DOCTYPEVERSION 2
    00029
    00030 static void LOG(LPCTSTR fmt, ...)
    00031 {
    00032         va_list args;
    00033         va_start(args, fmt);
    00034         if(FILE* f = _tfopen(_T("c:\\matroskasplitterlog.txt"), _T("at")))
    00035         {
    00036                 fseek(f, 0, 2);
    00037                 _vftprintf(f, fmt, args);
    00038                 fclose(f);
    00039         }
    00040         va_end(args);
    00041 }
    00042
    00043 using namespace MatroskaReader;
    00044
    00045 #define BeginChunk      \
    00046         CheckPointer(pMN0, E_POINTER); \
    00047 \
    00048         CAutoPtr<CMatroskaNode> pMN = pMN0->Child(); \
    00049         if(!pMN) return S_FALSE; \
    00050 \
    00051         do \
    00052         { \
    00053                 switch(pMN->m_id) \
    00054                 { \
    00055
    00056 #define EndChunk \
    00057                 } \
    00058         } \
    00059         while(pMN->Next()); \
    00060 \
    00061         return S_OK; \
    00062
    00063 static void bswap(BYTE* s, int len)
    00064 {
    00065         for(BYTE* d = s + len-1; s < d; s++, d--)
    00066                 *s ^= *d, *d ^= *s, *s ^= *d;
    00067 }
    00068
    00069 //
    00070 // CMatroskaFile
    00071 //
    00072
    00073 CMatroskaFile::CMatroskaFile(IAsyncReader* pAsyncReader, HRESULT& hr)
    00074         : CBaseSplitterFile(pAsyncReader, hr)
    00075         , m_rtOffset(0)
    00076 {
    00077         if(FAILED(hr)) return;
    00078         hr = Init();
    00079 }
    00080
    00081 HRESULT CMatroskaFile::Init()
    00082 {
    00083         DWORD dw;
    00084         if(FAILED(Read(dw)) || dw != 0x1A45DFA3)
    00085                 return E_FAIL;
    00086
    00087         CMatroskaNode Root(this);
    00088         if(FAILED(Parse(&Root)))
    00089                 return E_FAIL;
    00090
    00091         CAutoPtr<CMatroskaNode> pSegment, pCluster;
    00092         if((pSegment = Root.Child(0x18538067))
    00093         && (pCluster = pSegment->Child(0x1F43B675)))
    00094         {
    00095                 Cluster c0;
    00096                 c0.ParseTimeCode(pCluster);
    00097                 m_rtOffset = m_segment.GetRefTime(c0.TimeCode);
    00098         }
    00099
    00100         return S_OK;
    00101 }
    00102
    00103 template <class T>
    00104 HRESULT CMatroskaFile::Read(T& var)
    00105 {
    00106         HRESULT hr = Read((BYTE*)&var, sizeof(var));
    00107         if(S_OK == hr) bswap((BYTE*)&var, sizeof(var));
    00108         return hr;
    00109 }
    00110
    00111 HRESULT CMatroskaFile::Parse(CMatroskaNode* pMN0)
    00112 {
    00113         BeginChunk
    00114         case 0x1A45DFA3:
    00115                 m_ebml.Parse(pMN);
    00116                 if(m_ebml.DocType != DOCTYPE || m_ebml.DocTypeReadVersion > DOCTYPEVERSION)
    00117                         return E_FAIL;
    00118                 break;
    00119         case 0x18538067: if(m_segment.SegmentInfo.SegmentUID.IsEmpty()) m_segment.ParseMinimal(pMN); break;
    00120         EndChunk
    00121 }
    00122
    00123 //
    00124
    00125 HRESULT EBML::Parse(CMatroskaNode* pMN0)
    00126 {
    00127         BeginChunk
    00128         case 0x4286: EBMLVersion.Parse(pMN); break;
    00129         case 0x42F7: EBMLReadVersion.Parse(pMN); break;
    00130         case 0x42F2: EBMLMaxIDLength.Parse(pMN); break;
    00131         case 0x42F3: EBMLMaxSizeLength.Parse(pMN); break;
    00132         case 0x4282: DocType.Parse(pMN); break;
    00133         case 0x4287: DocTypeVersion.Parse(pMN); break;
    00134         case 0x4285: DocTypeReadVersion.Parse(pMN); break;
    00135         EndChunk
    00136 }
    00137
    00138 HRESULT Segment::Parse(CMatroskaNode* pMN0)
    00139 {
    00140         pos = pMN0->GetPos();
    00141
    00142         BeginChunk
    00143         case 0x1549A966: SegmentInfo.Parse(pMN); break;
    00144         case 0x114D9B74: MetaSeekInfo.Parse(pMN); break;
    00145         case 0x1654AE6B: Tracks.Parse(pMN); break;
    00146         case 0x1F43B675: Clusters.Parse(pMN); break;
    00147         case 0x1C53BB6B: Cues.Parse(pMN); break;
    00148         case 0x1941A469: Attachments.Parse(pMN); break;
    00149         case 0x1043A770: Chapters.Parse(pMN); break;
    00150 //      case 0x1254C367: Tags.Parse(pMN); break;
    00151         EndChunk
    00152 }
    00153
    00154 HRESULT Segment::ParseMinimal(CMatroskaNode* pMN0)
    00155 {
    00156         CheckPointer(pMN0, E_POINTER);
    00157
    00158         pos = pMN0->GetPos();
    00159         len = pMN0->m_len;
    00160
    00161         CAutoPtr<CMatroskaNode> pMN = pMN0->Child();
    00162         if(!pMN) return S_FALSE;
    00163
    00164         int n = 0;
    00165
    00166         do
    00167         {
    00168                 switch(pMN->m_id)
    00169                 {
    00170                 case 0x1549A966: SegmentInfo.Parse(pMN); n++; break;
    00171                 case 0x114D9B74: MetaSeekInfo.Parse(pMN); n++; break;
    00172                 case 0x1654AE6B: Tracks.Parse(pMN); n++; break;
    00173                 case 0x1C53BB6B: Cues.Parse(pMN); break;
    00174                 }
    00175         }
    00176         while(n < 3 && pMN->Next());
    00177
    00178         while(QWORD pos = pMN->FindPos(0x114D9B74, pMN->GetPos()))
    00179         {
    00180                 pMN->SeekTo(pos);
    00181                 pMN->Parse();
    00182                 if(pMN->m_id != 0x114D9B74) {ASSERT(0); break;}
    00183                 MetaSeekInfo.Parse(pMN);
    00184         }
    00185
    00186         if(n == 3)
    00187         {
    00188                 if(Cues.IsEmpty() && (pMN = pMN0->Child(0x1C53BB6B, false)))
    00189                 {
    00190                         do {Cues.Parse(pMN);} while(pMN->Next(true));
    00191                 }
    00192
    00193                 if(Chapters.IsEmpty() && (pMN = pMN0->Child(0x1043A770, false)))
    00194                 {
    00195                         do {Chapters.Parse(pMN); /*BIG UGLY HACK:*/ break;} while(pMN->Next(true));
    00196                 }
    00197
    00198                 if(Attachments.IsEmpty() && (pMN = pMN0->Child(0x1941A469, false)))
    00199                 {
    00200                         do {Attachments.Parse(pMN); /*BIG UGLY HACK:*/ break;} while (pMN->Next(true));
    00201                 }
    00202         }
    00203
    00204         return S_OK;
    00205 }
    00206
    00207 UINT64 Segment::GetMasterTrack()
    00208 {
    00209         UINT64 TrackNumber = 0, AltTrackNumber = 0;
    00210
    00211         POSITION pos1 = Tracks.GetHeadPosition();
    00212         while(pos1 && TrackNumber == 0)
    00213         {
    00214                 Track* pT = Tracks.GetNext(pos1);
    00215
    00216                 POSITION pos2 = pT->TrackEntries.GetHeadPosition();
    00217                 while(pos2 && TrackNumber == 0)
    00218                 {
    00219                         TrackEntry* pTE = pT->TrackEntries.GetNext(pos2);
    00220
    00221                         if(pTE->TrackType == TrackEntry::TypeVideo)
    00222                         {
    00223                                 TrackNumber = pTE->TrackNumber;
    00224                                 break;
    00225                         }
    00226                         else if(pTE->TrackType == TrackEntry::TypeAudio && AltTrackNumber == 0)
    00227                         {
    00228                                 AltTrackNumber = pTE->TrackNumber;
    00229                         }
    00230                 }
    00231         }
    00232
    00233         if(TrackNumber == 0) TrackNumber = AltTrackNumber;
    00234         if(TrackNumber == 0) TrackNumber = 1;
    00235
    00236         return TrackNumber;
    00237 }
    00238
    00239 ChapterAtom* ChapterAtom::FindChapterAtom(UINT64 id)
    00240 {
    00241         if(ChapterUID == id)
    00242                 return(this);
    00243
    00244         POSITION pos = ChapterAtoms.GetHeadPosition();
    00245         while(pos)
    00246         {
    00247                 ChapterAtom* ca = ChapterAtoms.GetNext(pos)->FindChapterAtom(id);
    00248                 if(ca) return ca;
    00249         }
    00250
    00251         return(NULL);
    00252 }
    00253
    00254 ChapterAtom* Segment::FindChapterAtom(UINT64 id, int nEditionEntry)
    00255 {
    00256         POSITION pos1 = Chapters.GetHeadPosition();
    00257         while(pos1)
    00258         {
    00259                 Chapter* c = Chapters.GetNext(pos1);
    00260
    00261                 POSITION pos2 = c->EditionEntries.GetHeadPosition();
    00262                 while(pos2)
    00263                 {
    00264                         EditionEntry* ee = c->EditionEntries.GetNext(pos2);
    00265
    00266                         if(nEditionEntry-- == 0)
    00267                         {
    00268                                 return id == 0 ? ee : ee->FindChapterAtom(id);
    00269                         }
    00270                 }
    00271         }
    00272
    00273         return(NULL);
    00274 }
    00275
    00276 HRESULT Info::Parse(CMatroskaNode* pMN0)
    00277 {
    00278         BeginChunk
    00279         case 0x73A4: SegmentUID.Parse(pMN); break;
    00280         case 0x7384: SegmentFilename.Parse(pMN); break;
    00281         case 0x3CB923: PrevUID.Parse(pMN); break;
    00282         case 0x3C83AB: PrevFilename.Parse(pMN); break;
    00283         case 0x3EB923: NextUID.Parse(pMN); break;
    00284         case 0x3E83BB: NextFilename.Parse(pMN); break;
    00285         case 0x2AD7B1: TimeCodeScale.Parse(pMN); break;
    00286         case 0x4489: Duration.Parse(pMN); break;
    00287         case 0x4461: DateUTC.Parse(pMN); break;
    00288         case 0x7BA9: Title.Parse(pMN); break;
    00289         case 0x4D80: MuxingApp.Parse(pMN); break;
    00290         case 0x5741: WritingApp.Parse(pMN); break;
    00291         EndChunk
    00292 }
    00293
    00294 HRESULT Seek::Parse(CMatroskaNode* pMN0)
    00295 {
    00296         BeginChunk
    00297         case 0x4DBB: SeekHeads.Parse(pMN); break;
    00298         EndChunk
    00299 }
    00300
    00301 HRESULT SeekHead::Parse(CMatroskaNode* pMN0)
    00302 {
    00303         BeginChunk
    00304         case 0x53AB: SeekID.Parse(pMN); break;
    00305         case 0x53AC: SeekPosition.Parse(pMN); break;
    00306         EndChunk
    00307 }
    00308
    00309 HRESULT Track::Parse(CMatroskaNode* pMN0)
    00310 {
    00311         BeginChunk
    00312         case 0xAE: TrackEntries.Parse(pMN); break;
    00313         EndChunk
    00314 }
    00315
    00316 HRESULT TrackEntry::Parse(CMatroskaNode* pMN0)
    00317 {
    00318         BeginChunk
    00319         case 0xD7: TrackNumber.Parse(pMN); break;
    00320         case 0x73C5: TrackUID.Parse(pMN); break;
    00321         case 0x83: TrackType.Parse(pMN); break;
    00322         case 0xB9: FlagEnabled.Parse(pMN); break;
    00323         case 0x88: FlagDefault.Parse(pMN); break;
    00324         case 0x9C: FlagLacing.Parse(pMN); break;
    00325         case 0x6DE7: MinCache.Parse(pMN); break;
    00326         case 0x6DF8: MaxCache.Parse(pMN); break;
    00327         case 0x536E: Name.Parse(pMN); break;
    00328         case 0x22B59C: Language.Parse(pMN); break;
    00329         case 0x86: CodecID.Parse(pMN); break;
    00330         case 0x63A2: CodecPrivate.Parse(pMN); break;
    00331         case 0x258688: CodecName.Parse(pMN); break;
    00332         case 0x3A9697: CodecSettings.Parse(pMN); break;
    00333         case 0x3B4040: CodecInfoURL.Parse(pMN); break;
    00334         case 0x26B240: CodecDownloadURL.Parse(pMN); break;
    00335         case 0xAA: CodecDecodeAll.Parse(pMN); break;
    00336         case 0x6FAB: TrackOverlay.Parse(pMN); break;
    00337         case 0x23E383: case 0x2383E3: DefaultDuration.Parse(pMN); break;
    00338         case 0x23314F: TrackTimecodeScale.Parse(pMN); break;
    00339         case 0xE0: if(S_OK == v.Parse(pMN)) DescType |= DescVideo; break;
    00340         case 0xE1: if(S_OK == a.Parse(pMN)) DescType |= DescAudio; break;
    00341         case 0x6D80: ces.Parse(pMN); break;
    00342         EndChunk
    00343 }
    00344
    00345 static int cesort(const void* a, const void* b)
    00346 {
    00347         UINT64 ce1 = ((ContentEncoding*)a)->ContentEncodingOrder;
    00348         UINT64 ce2 = ((ContentEncoding*)b)->ContentEncodingOrder;
    00349
    00350         return (int)ce1 - (int)ce2;
    00351 }
    00352
    00353 bool TrackEntry::Expand(CBinary& data, UINT64 Scope)
    00354 {
    00355         if(ces.ce.GetCount() == 0) return(true);
    00356
    00357         CArray<ContentEncoding*> cearray;
    00358         POSITION pos = ces.ce.GetHeadPosition();
    00359         while(pos) cearray.Add(ces.ce.GetNext(pos));
    00360         qsort(cearray.GetData(), cearray.GetCount(), sizeof(ContentEncoding*), cesort);
    00361
    00362         for(int i = cearray.GetCount()-1; i >= 0; i--)
    00363         {
    00364                 ContentEncoding* ce = cearray[i];
    00365
    00366                 if(!(ce->ContentEncodingScope & Scope))
    00367                         continue;
    00368
    00369                 if(ce->ContentEncodingType == ContentEncoding::Compression)
    00370                 {
    00371                         if(!data.Decompress(ce->cc))
    00372                                 return(false);
    00373                 }
    00374                 else if(ce->ContentEncodingType == ContentEncoding::Encryption)
    00375                 {
    00376                         // TODO
    00377                         return(false);
    00378                 }
    00379         }
    00380
    00381         return(true);
    00382 }
    00383
    00384 HRESULT Video::Parse(CMatroskaNode* pMN0)
    00385 {
    00386         BeginChunk
    00387         case 0x9A: FlagInterlaced.Parse(pMN); break;
    00388         case 0x53B8: StereoMode.Parse(pMN); break;
    00389         case 0xB0: PixelWidth.Parse(pMN); break;
    00390         case 0xBA: PixelHeight.Parse(pMN); break;
    00391         case 0x54B0: DisplayWidth.Parse(pMN); break;
    00392         case 0x54BA: DisplayHeight.Parse(pMN); break;
    00393         case 0x54B2: DisplayUnit.Parse(pMN); break;
    00394         case 0x54B3: AspectRatioType.Parse(pMN); break;
    00395         case 0x2EB524: ColourSpace.Parse(pMN); break;
    00396         case 0x2FB523: GammaValue.Parse(pMN); break;
    00397         case 0x2383E3: FramePerSec.Parse(pMN); break;
    00398         EndChunk
    00399 }
    00400
    00401 HRESULT Audio::Parse(CMatroskaNode* pMN0)
    00402 {
    00403         BeginChunk
    00404         case 0xB5: SamplingFrequency.Parse(pMN); break;
    00405         case 0x78B5: OutputSamplingFrequency.Parse(pMN); break;
    00406         case 0x9F: Channels.Parse(pMN); break;
    00407         case 0x7D7B: ChannelPositions.Parse(pMN); break;
    00408         case 0x6264: BitDepth.Parse(pMN); break;
    00409         EndChunk
    00410 }
    00411
    00412 HRESULT ContentEncodings::Parse(CMatroskaNode* pMN0)
    00413 {
    00414         BeginChunk
    00415         case 0x6240: ce.Parse(pMN); break;
    00416         EndChunk
    00417 }
    00418
    00419 HRESULT ContentEncoding::Parse(CMatroskaNode* pMN0)
    00420 {
    00421         BeginChunk
    00422         case 0x5031: ContentEncodingOrder.Parse(pMN); break;
    00423         case 0x5032: ContentEncodingScope.Parse(pMN); break;
    00424         case 0x5033: ContentEncodingType.Parse(pMN); break;
    00425         case 0x5034: cc.Parse(pMN); break;
    00426         case 0x5035: ce.Parse(pMN); break;
    00427         EndChunk
    00428 }
    00429
    00430 HRESULT ContentCompression::Parse(CMatroskaNode* pMN0)
    00431 {
    00432         BeginChunk
    00433         case 0x4254: ContentCompAlgo.Parse(pMN); break;
    00434         case 0x4255: ContentCompSettings.Parse(pMN); break;
    00435         EndChunk
    00436 }
    00437
    00438 HRESULT ContentEncryption::Parse(CMatroskaNode* pMN0)
    00439 {
    00440         BeginChunk
    00441         case 0x47e1: ContentEncAlgo.Parse(pMN); break;
    00442         case 0x47e2: ContentEncKeyID.Parse(pMN); break;
    00443         case 0x47e3: ContentSignature.Parse(pMN); break;
    00444         case 0x47e4: ContentSigKeyID.Parse(pMN); break;
    00445         case 0x47e5: ContentSigAlgo.Parse(pMN); break;
    00446         case 0x47e6: ContentSigHashAlgo.Parse(pMN); break;
    00447         EndChunk
    00448 }
    00449
    00450 HRESULT Cluster::Parse(CMatroskaNode* pMN0)
    00451 {
    00452         BeginChunk
    00453         case 0xE7: TimeCode.Parse(pMN); break;
    00454         case 0xA7: Position.Parse(pMN); break;
    00455         case 0xAB: PrevSize.Parse(pMN); break;
    00456         case 0xA0: BlockGroups.Parse(pMN, true); break;
    00457         case 0xA3: SimpleBlocks.Parse(pMN, true); break;
    00458         EndChunk
    00459 }
    00460
    00461 HRESULT Cluster::ParseTimeCode(CMatroskaNode* pMN0)
    00462 {
    00463         BeginChunk
    00464         case 0xE7: TimeCode.Parse(pMN); return S_OK;
    00465         EndChunk
    00466 }
    00467
    00468 HRESULT BlockGroup::Parse(CMatroskaNode* pMN0, bool fFull)
    00469 {
    00470         BeginChunk
    00471         case 0xA1: Block.Parse(pMN, fFull); break;
    00472         case 0xA2: /* TODO: multiple virt blocks? */; break;
    00473         case 0x9B: BlockDuration.Parse(pMN); break;
    00474         case 0xFA: ReferencePriority.Parse(pMN); break;
    00475         case 0xFB: ReferenceBlock.Parse(pMN); break;
    00476         case 0xFD: ReferenceVirtual.Parse(pMN); break;
    00477         case 0xA4: CodecState.Parse(pMN); break;
    00478         case 0xE8: TimeSlices.Parse(pMN); break;
    00479         EndChunk
    00480 }
    00481
    00482 HRESULT SimpleBlock::Parse(CMatroskaNode* pMN, bool fFull)
    00483 {
    00484         pMN->SeekTo(pMN->m_start);
    00485
    00486         TrackNumber.Parse(pMN);
    00487         CShort s; s.Parse(pMN); TimeCode.Set(s);
    00488         Lacing.Parse(pMN);
    00489
    00490         if(!fFull) return S_OK;
    00491
    00492         CList<QWORD> lens;
    00493         QWORD tlen = 0;
    00494         QWORD FrameSize;
    00495         BYTE FramesInLaceLessOne;
    00496
    00497         switch((Lacing & 0x06) >> 1)
    00498         {
    00499         case 0:
    00500                 // No lacing
    00501                 lens.AddTail((pMN->m_start+pMN->m_len) - (pMN->GetPos()+tlen));
    00502                 break;
    00503         case 1:
    00504                 // Xiph lacing
    00505                 BYTE n;
    00506                 pMN->Read(n);
    00507                 while(n-- > 0)
    00508                 {
    00509                         BYTE b;
    00510                         QWORD len = 0;
    00511                         do {pMN->Read(b); len += b;} while(b == 0xff);
    00512                         lens.AddTail(len);
    00513                         tlen += len;
    00514                 }
    00515                 lens.AddTail((pMN->m_start+pMN->m_len) - (pMN->GetPos()+tlen));
    00516                 break;
    00517         case 2:
    00518                 // Fixed-size lacing
    00519                 pMN->Read(FramesInLaceLessOne);
    00520                 FramesInLaceLessOne++;
    00521                 FrameSize = ((pMN->m_start+pMN->m_len) - (pMN->GetPos()+tlen)) / FramesInLaceLessOne;
    00522                 while(FramesInLaceLessOne-- > 0)
    00523                         lens.AddTail(FrameSize);
    00524                 break;
    00525         case 3:
    00526                 // EBML lacing
    00527                 pMN->Read(FramesInLaceLessOne);
    00528
    00529                 CLength FirstFrameSize;
    00530                 FirstFrameSize.Parse(pMN);
    00531                 lens.AddTail(FirstFrameSize);
    00532                 FramesInLaceLessOne--;
    00533                 tlen = FirstFrameSize;
    00534
    00535                 CSignedLength DiffSize;
    00536                 FrameSize = FirstFrameSize;
    00537                 while(FramesInLaceLessOne--)
    00538                 {
    00539                         DiffSize.Parse(pMN);
    00540                         FrameSize += DiffSize;
    00541                         lens.AddTail(FrameSize);
    00542                         tlen += FrameSize;
    00543                 }
    00544                 lens.AddTail((pMN->m_start+pMN->m_len) - (pMN->GetPos()+tlen));
    00545                 break;
    00546         }
    00547
    00548         POSITION pos = lens.GetHeadPosition();
    00549         while(pos)
    00550         {
    00551                 QWORD len = lens.GetNext(pos);
    00552                 CAutoPtr<CBinary> p(new CBinary());
    00553                 p->SetSize((INT_PTR)len);
    00554                 pMN->Read(p->GetData(), len);
    00555                 BlockData.AddTail(p);
    00556         }
    00557
    00558         return S_OK;
    00559 }
    00560
    00561 HRESULT TimeSlice::Parse(CMatroskaNode* pMN0)
    00562 {
    00563         BeginChunk
    00564         case 0xCC: LaceNumber.Parse(pMN); break;
    00565         case 0xCD: FrameNumber.Parse(pMN); break;
    00566         case 0xCE: Delay.Parse(pMN); break;
    00567         case 0xCF: Duration.Parse(pMN); break;
    00568         EndChunk
    00569 }
    00570
    00571 HRESULT Cue::Parse(CMatroskaNode* pMN0)
    00572 {
    00573         BeginChunk
    00574         case 0xBB: CuePoints.Parse(pMN); break;
    00575         EndChunk
    00576 }
    00577
    00578 HRESULT CuePoint::Parse(CMatroskaNode* pMN0)
    00579 {
    00580         BeginChunk
    00581         case 0xB3: CueTime.Parse(pMN); break;
    00582         case 0xB7: CueTrackPositions.Parse(pMN); break;
    00583         EndChunk
    00584 }
    00585
    00586 HRESULT CueTrackPosition::Parse(CMatroskaNode* pMN0)
    00587 {
    00588         BeginChunk
    00589         case 0xF7: CueTrack.Parse(pMN); break;
    00590         case 0xF1: CueClusterPosition.Parse(pMN); break;
    00591         case 0x5387: CueBlockNumber.Parse(pMN); break;
    00592         case 0xEA: CueCodecState.Parse(pMN); break;
    00593         case 0xDB: CueReferences.Parse(pMN); break;
    00594         EndChunk
    00595 }
    00596
    00597 HRESULT CueReference::Parse(CMatroskaNode* pMN0)
    00598 {
    00599         BeginChunk
    00600         case 0x96: CueRefTime.Parse(pMN); break;
    00601         case 0x97: CueRefCluster.Parse(pMN); break;
    00602         case 0x535F: CueRefNumber.Parse(pMN); break;
    00603         case 0xEB: CueRefCodecState.Parse(pMN); break;
    00604         EndChunk
    00605 }
    00606
    00607 HRESULT Attachment::Parse(CMatroskaNode* pMN0)
    00608 {
    00609         BeginChunk
    00610         case 0x61A7: AttachedFiles.Parse(pMN); break;
    00611         EndChunk
    00612 }
    00613
    00614 HRESULT AttachedFile::Parse(CMatroskaNode* pMN0)
    00615 {
    00616         BeginChunk
    00617         case 0x467E: FileDescription.Parse(pMN); break;
    00618         case 0x466E: FileName.Parse(pMN); break;
    00619         case 0x4660: FileMimeType.Parse(pMN); break;
    00620         case 0x465C: // binary
    00621                 FileDataLen = (INT_PTR)pMN->m_len;
    00622                 FileDataPos = pMN->m_start;
    00623                 break;
    00624         case 0x46AE: FileUID.Parse(pMN); break;
    00625         EndChunk
    00626 }
    00627
    00628 HRESULT Chapter::Parse(CMatroskaNode* pMN0)
    00629 {
    00630         BeginChunk
    00631         case 0x45B9: EditionEntries.Parse(pMN); break;
    00632         EndChunk
    00633 }
    00634
    00635 HRESULT EditionEntry::Parse(CMatroskaNode* pMN0)
    00636 {
    00637         BeginChunk
    00638         case 0xB6: ChapterAtoms.Parse(pMN); break;
    00639         EndChunk
    00640 }
    00641
    00642 HRESULT ChapterAtom::Parse(CMatroskaNode* pMN0)
    00643 {
    00644         BeginChunk
    00645         case 0x73C4: ChapterUID.Parse(pMN); break;
    00646         case 0x91: ChapterTimeStart.Parse(pMN); break;
    00647         case 0x92: ChapterTimeEnd.Parse(pMN); break;
    00648 //      case 0x8F: // TODO
    00649         case 0x80: ChapterDisplays.Parse(pMN); break;
    00650         case 0xB6: ChapterAtoms.Parse(pMN); break;
    00651         case 0x98: ChapterFlagHidden.Parse(pMN); break;
    00652         case 0x4598: ChapterFlagEnabled.Parse(pMN); break;
    00653         EndChunk
    00654 }
    00655
    00656 HRESULT ChapterDisplay::Parse(CMatroskaNode* pMN0)
    00657 {
    00658         BeginChunk
    00659         case 0x85: ChapString.Parse(pMN); break;
    00660         case 0x437C: ChapLanguage.Parse(pMN); break;
    00661         case 0x437E: ChapCountry.Parse(pMN); break;
    00662         EndChunk
    00663 }
    00664
    00665 //
    00666
    00667 HRESULT CBinary::Parse(CMatroskaNode* pMN)
    00668 {
    00669         ASSERT(pMN->m_len <= INT_MAX);
    00670         SetSize((INT_PTR)pMN->m_len);
    00671         return pMN->Read(GetData(), pMN->m_len);
    00672 }
    00673
    00674 bool CBinary::Compress(ContentCompression& cc)
    00675 {
    00676         if(cc.ContentCompAlgo == ContentCompression::ZLIB)
    00677         {
    00678                 int res;
    00679                 z_stream c_stream;
    00680
    00681                 c_stream.zalloc = (alloc_func)0;
    00682                 c_stream.zfree = (free_func)0;
    00683                 c_stream.opaque = (voidpf)0;
    00684
    00685                 if(Z_OK != (res = deflateInit(&c_stream, 9)))
    00686                         return(false);
    00687
    00688                 c_stream.next_in = GetData();
    00689                 c_stream.avail_in = GetSize();
    00690
    00691                 BYTE* dst = NULL;
    00692                 int n = 0;
    00693                 do
    00694                 {
    00695                         dst = (BYTE*)realloc(dst, ++n*10);
    00696                         c_stream.next_out = &dst[(n-1)*10];
    00697                         c_stream.avail_out = 10;
    00698                         if(Z_OK != (res = deflate(&c_stream, Z_FINISH)) && Z_STREAM_END != res)
    00699                         {
    00700                                 free(dst);
    00701                                 return(false);
    00702                         }
    00703                 }
    00704                 while(0 == c_stream.avail_out && Z_STREAM_END != res);
    00705
    00706                 deflateEnd(&c_stream);
    00707
    00708                 SetSize(c_stream.total_out);
    00709                 memcpy(GetData(), dst, GetSize());
    00710
    00711                 free(dst);
    00712
    00713                 return(true);
    00714         }
    00715
    00716         return(false);
    00717 }
    00718
    00719 bool CBinary::Decompress(ContentCompression& cc)
    00720 {
    00721         if(cc.ContentCompAlgo == ContentCompression::ZLIB)
    00722         {
    00723                 int res;
    00724                 z_stream d_stream;
    00725
    00726                 d_stream.zalloc = (alloc_func)0;
    00727                 d_stream.zfree = (free_func)0;
    00728                 d_stream.opaque = (voidpf)0;
    00729
    00730                 if(Z_OK != (res = inflateInit(&d_stream)))
    00731                         return(false);
    00732
    00733                 d_stream.next_in = GetData();
    00734                 d_stream.avail_in = GetSize();
    00735
    00736                 BYTE* dst = NULL;
    00737                 int n = 0;
    00738                 do
    00739                 {
    00740                         dst = (unsigned char *)realloc(dst, ++n*1000);
    00741                         d_stream.next_out = &dst[(n-1)*1000];
    00742                         d_stream.avail_out = 1000;
    00743                         if(Z_OK != (res = inflate(&d_stream, Z_NO_FLUSH)) && Z_STREAM_END != res)
    00744                         {
    00745                                 free(dst);
    00746                                 return(false);
    00747                         }
    00748                 }
    00749                 while(0 == d_stream.avail_out && 0 != d_stream.avail_in && Z_STREAM_END != res);
    00750
    00751                 inflateEnd(&d_stream);
    00752
    00753                 SetSize(d_stream.total_out);
    00754                 memcpy(GetData(), dst, GetSize());
    00755
    00756                 free(dst);
    00757
    00758                 return(true);
    00759         }
    00760         else if(cc.ContentCompAlgo == ContentCompression::HDRSTRIP)
    00761         {
    00762                 InsertAt(0, &cc.ContentCompSettings);
    00763         }
    00764
    00765         return(false);
    00766 }
    00767
    00768 HRESULT CANSI::Parse(CMatroskaNode* pMN)
    00769 {
    00770         Empty();
    00771
    00772         QWORD len = pMN->m_len;
    00773         CHAR c;
    00774         while(len-- > 0 && SUCCEEDED(pMN->Read(c)))
    00775                 *this += c;
    00776
    00777         return(len == -1 ? S_OK : E_FAIL);
    00778 }
    00779
    00780 HRESULT CUTF8::Parse(CMatroskaNode* pMN)
    00781 {
    00782         Empty();
    00783         CAutoVectorPtr<BYTE> buff;
    00784         if(!buff.Allocate((UINT)pMN->m_len + 1) || S_OK != pMN->Read(buff, pMN->m_len))
    00785                 return E_FAIL;
    00786         buff[pMN->m_len] = 0;
    00787         CStringW::operator = (UTF8To16((LPCSTR)(BYTE*)buff));
    00788         return S_OK;
    00789 }
    00790
    00791 HRESULT CUInt::Parse(CMatroskaNode* pMN)
    00792 {
    00793         m_val = 0;
    00794         for(int i = 0; i < (int)pMN->m_len; i++)
    00795         {
    00796                 m_val <<= 8;
    00797                 HRESULT hr = pMN->Read(*(BYTE*)&m_val);
    00798                 if(FAILED(hr)) return hr;
    00799         }
    00800         m_fValid = true;
    00801         return S_OK;
    00802 }
    00803
    00804 HRESULT CInt::Parse(CMatroskaNode* pMN)
    00805 {
    00806         m_val = 0;
    00807         for(int i = 0; i < (int)pMN->m_len; i++)
    00808         {
    00809                 HRESULT hr = pMN->Read(*((BYTE*)&m_val+7-i));
    00810                 if(FAILED(hr)) return hr;
    00811         }
    00812         m_val >>= (8-pMN->m_len)*8;
    00813         m_fValid = true;
    00814         return S_OK;
    00815 }
    00816
    00817 HRESULT CFloat::Parse(CMatroskaNode* pMN)
    00818 {
    00819         HRESULT hr = E_FAIL;
    00820         m_val = 0;
    00821
    00822         if(pMN->m_len == 4)
    00823         {
    00824                 float val = 0;
    00825                 hr = pMN->Read(val);
    00826                 m_val = val;
    00827         } else if(pMN->m_len == 8) {
    00828                 hr = pMN->Read(m_val);
    00829         }
    00830         if(SUCCEEDED(hr))
    00831                 m_fValid = true;
    00832         return hr;
    00833 }
    00834
    00835
    00836 template<class T, class BASE>
    00837 HRESULT CSimpleVar<T, BASE>::Parse(CMatroskaNode* pMN)
    00838 {
    00839         m_val = 0;
    00840         m_fValid = true;
    00841         return pMN->Read(m_val);
    00842 }
    00843
    00844 HRESULT CID::Parse(CMatroskaNode* pMN)
    00845 {
    00846         m_val = 0;
    00847
    00848         BYTE b = 0;
    00849         HRESULT hr = pMN->Read(b);
    00850         if(FAILED(hr)) return hr;
    00851
    00852         int nMoreBytes = 0;
    00853
    00854         if((b&0x80) == 0x80) {m_val = b&0xff; nMoreBytes = 0;}
    00855         else if((b&0xc0) == 0x40) {m_val = b&0x7f; nMoreBytes = 1;}
    00856         else if((b&0xe0) == 0x20) {m_val = b&0x3f; nMoreBytes = 2;}
    00857         else if((b&0xf0) == 0x10) {m_val = b&0x1f; nMoreBytes = 3;}
    00858         else return E_FAIL;
    00859
    00860         while(nMoreBytes-- > 0)
    00861         {
    00862                 m_val <<= 8;
    00863                 hr = pMN->Read(*(BYTE*)&m_val);
    00864                 if(FAILED(hr)) return hr;
    00865         }
    00866
    00867         m_fValid = true;
    00868
    00869         return S_OK;
    00870 }
    00871
    00872 HRESULT CLength::Parse(CMatroskaNode* pMN)
    00873 {
    00874         m_val = 0;
    00875
    00876         BYTE b = 0;
    00877         HRESULT hr = pMN->Read(b);
    00878         if(FAILED(hr)) return hr;
    00879
    00880         int nMoreBytes = 0, nMoreBytesTmp = 0;
    00881
    00882         if((b&0x80) == 0x80) {m_val = b&0x7f; nMoreBytes = 0;}
    00883         else if((b&0xc0) == 0x40) {m_val = b&0x3f; nMoreBytes = 1;}
    00884         else if((b&0xe0) == 0x20) {m_val = b&0x1f; nMoreBytes = 2;}
    00885         else if((b&0xf0) == 0x10) {m_val = b&0x0f; nMoreBytes = 3;}
    00886         else if((b&0xf8) == 0x08) {m_val = b&0x07; nMoreBytes = 4;}
    00887         else if((b&0xfc) == 0x04) {m_val = b&0x03; nMoreBytes = 5;}
    00888         else if((b&0xfe) == 0x02) {m_val = b&0x01; nMoreBytes = 6;}
    00889         else if((b&0xff) == 0x01) {m_val = b&0x00; nMoreBytes = 7;}
    00890         else return E_FAIL;
    00891
    00892         nMoreBytesTmp = nMoreBytes;
    00893
    00894         QWORD UnknownSize = (1i64<<(7*(nMoreBytes+1)))-1;
    00895
    00896         while(nMoreBytes-- > 0)
    00897         {
    00898                 m_val <<= 8;
    00899                 hr = pMN->Read(*(BYTE*)&m_val);
    00900                 if(FAILED(hr)) return hr;
    00901         }
    00902
    00903         if(m_val == UnknownSize)
    00904         {
    00905                 m_val = pMN->GetLength() - pMN->GetPos();
    00906                 TRACE(_T("CLength: Unspecified chunk size at %I64d (corrected to %I64d)\n"), pMN->GetPos(), m_val);
    00907         }
    00908
    00909         if(m_fSigned)
    00910                 m_val -= (UnknownSize >> 1);
    00911
    00912         m_fValid = true;
    00913
    00914         return S_OK;
    00915 }
    00916 /*
    00917 HRESULT CSignedLength::Parse(CMatroskaNode* pMN)
    00918 {
    00919 //      HRESULT hr = __super::Parse(pMN);
    00920 //      if(FAILED(hr)) return hr;
    00921
    00922         m_val = 0;
    00923
    00924         BYTE b = 0;
    00925         HRESULT hr = pMN->Read(b);
    00926         if(FAILED(hr)) return hr;
    00927
    00928         int nMoreBytes = 0, nMoreBytesTmp = 0;
    00929
    00930         if((b&0x80) == 0x80) {m_val = b&0x7f; nMoreBytes = 0;}
    00931         else if((b&0xc0) == 0x40) {m_val = b&0x3f; nMoreBytes = 1;}
    00932         else if((b&0xe0) == 0x20) {m_val = b&0x1f; nMoreBytes = 2;}
    00933         else if((b&0xf0) == 0x10) {m_val = b&0x0f; nMoreBytes = 3;}
    00934         else if((b&0xf8) == 0x08) {m_val = b&0x07; nMoreBytes = 4;}
    00935         else if((b&0xfc) == 0x04) {m_val = b&0x03; nMoreBytes = 5;}
    00936         else if((b&0xfe) == 0x02) {m_val = b&0x01; nMoreBytes = 6;}
    00937         else if((b&0xff) == 0x01) {m_val = b&0x00; nMoreBytes = 7;}
    00938         else return E_FAIL;
    00939
    00940         nMoreBytesTmp = nMoreBytes;
    00941
    00942         QWORD UnknownSize = (1i64<<(7*(nMoreBytes+1)))-1;
    00943
    00944         while(nMoreBytes-- > 0)
    00945         {
    00946                 m_val <<= 8;
    00947                 hr = pMN->Read(*(BYTE*)&m_val);
    00948                 if(FAILED(hr)) return hr;
    00949         }
    00950
    00951         if(m_val == UnknownSize)
    00952         {
    00953                 m_val = pMN->GetLength() - pMN->GetPos();
    00954                 TRACE(_T("CLength: Unspecified chunk size at %I64d (corrected to %I64d)\n"), pMN->GetPos(), m_val);
    00955         }
    00956
    00957         m_val -= (UnknownSize >> 1);
    00958
    00959         m_fValid = true;
    00960
    00961         return S_OK;
    00962 }
    00963 */
    00964 template<class T>
    00965 HRESULT CNode<T>::Parse(CMatroskaNode* pMN)
    00966 {
    00967         CAutoPtr<T> p(new T());
    00968         HRESULT hr = E_OUTOFMEMORY;
    00969         if(!p || FAILED(hr = p->Parse(pMN))) return hr;
    00970         AddTail(p);
    00971         return S_OK;
    00972 }
    00973
    00974 HRESULT CBlockGroupNode::Parse(CMatroskaNode* pMN, bool fFull)
    00975 {
    00976         CAutoPtr<BlockGroup> p(new BlockGroup());
    00977         HRESULT hr = E_OUTOFMEMORY;
    00978         if(!p || FAILED(hr = p->Parse(pMN, fFull))) return hr;
    00979         AddTail(p);
    00980         return S_OK;
    00981 }
    00982
    00983 HRESULT CSimpleBlockNode::Parse(CMatroskaNode* pMN, bool fFull)
    00984 {
    00985         CAutoPtr<SimpleBlock> p(new SimpleBlock());
    00986         HRESULT hr = E_OUTOFMEMORY;
    00987         if(!p || FAILED(hr = p->Parse(pMN, fFull))) return hr;
    00988         AddTail(p);
    00989         return S_OK;
    00990 }
    00991
    00993
    00994 CMatroskaNode::CMatroskaNode(CMatroskaFile* pMF)
    00995         : m_pMF(pMF)
    00996         , m_pParent(NULL)
    00997 {
    00998         ASSERT(m_pMF);
    00999         m_start = m_filepos = 0;
    01000         m_len.Set(m_pMF ? m_pMF->GetLength() : 0);
    01001 }
    01002
    01003 CMatroskaNode::CMatroskaNode(CMatroskaNode* pParent)
    01004         : m_pMF(pParent->m_pMF)
    01005         , m_pParent(pParent)
    01006 {
    01007         Parse();
    01008 }
    01009
    01010 HRESULT CMatroskaNode::Parse()
    01011 {
    01012         m_filepos = GetPos();
    01013         if(FAILED(m_id.Parse(this)) || FAILED(m_len.Parse(this)))
    01014                 return E_FAIL;
    01015         m_start = GetPos();
    01016         return S_OK;
    01017 }
    01018
    01019 CAutoPtr<CMatroskaNode> CMatroskaNode::Child(DWORD id, bool fSearch)
    01020 {
    01021         if(m_len == 0) return CAutoPtr<CMatroskaNode>();
    01022         SeekTo(m_start);
    01023         CAutoPtr<CMatroskaNode> pMN(new CMatroskaNode(this));
    01024         if(id && !pMN->Find(id, fSearch)) pMN.Free();
    01025         return pMN;
    01026 }
    01027
    01028 bool CMatroskaNode::Next(bool fSame)
    01029 {
    01030         if(!m_pParent)
    01031                 return(false);
    01032
    01033         CID id = m_id;
    01034
    01035         while(m_start+m_len < m_pParent->m_start+m_pParent->m_len)
    01036         {
    01037                 SeekTo(m_start+m_len);
    01038
    01039                 if(FAILED(Parse()))
    01040                 {
    01041                         if(!Resync())
    01042                                 return(false);
    01043                 }
    01044
    01045                 if(!fSame || m_id == id)
    01046                         return(true);
    01047         }
    01048
    01049         return(false);
    01050 }
    01051
    01052 bool CMatroskaNode::Find(DWORD id, bool fSearch)
    01053 {
    01054         QWORD pos = m_pParent && m_pParent->m_id == 0x18538067 /*segment?*/
    01055                 ? FindPos(id)
    01056                 : 0;
    01057
    01058         if(pos)
    01059         {
    01060                 SeekTo(pos);
    01061                 Parse();
    01062         }
    01063         else if(fSearch)
    01064         {
    01065                 while(m_id != id && Next());
    01066         }
    01067
    01068         return(m_id == id);
    01069 }
    01070
    01071 void CMatroskaNode::SeekTo(QWORD pos) {m_pMF->Seek(pos);}
    01072 QWORD CMatroskaNode::GetPos() {return m_pMF->GetPos();}
    01073 QWORD CMatroskaNode::GetLength() {return m_pMF->GetLength();}
    01074 template <class T>
    01075 HRESULT CMatroskaNode::Read(T& var) {return m_pMF->Read(var);}
    01076 HRESULT CMatroskaNode::Read(BYTE* pData, QWORD len) {return m_pMF->Read(pData, len);}
    01077
    01078 QWORD CMatroskaNode::FindPos(DWORD id, QWORD start)
    01079 {
    01080         Segment& sm = m_pMF->m_segment;
    01081
    01082         POSITION pos = sm.MetaSeekInfo.GetHeadPosition();
    01083         while(pos)
    01084         {
    01085                 Seek* s = sm.MetaSeekInfo.GetNext(pos);
    01086
    01087                 POSITION pos2 = s->SeekHeads.GetHeadPosition();
    01088                 while(pos2)
    01089                 {
    01090                         SeekHead* sh = s->SeekHeads.GetNext(pos2);
    01091                         if(sh->SeekID == id && sh->SeekPosition+sm.pos >= start)
    01092                                 return sh->SeekPosition+sm.pos;
    01093                 }
    01094         }
    01095
    01096         return 0;
    01097 }
    01098
    01099 CAutoPtr<CMatroskaNode> CMatroskaNode::Copy()
    01100 {
    01101         CAutoPtr<CMatroskaNode> pNewNode(new CMatroskaNode(m_pMF));
    01102         pNewNode->m_pParent = m_pParent;
    01103         pNewNode->m_id.Set(m_id);
    01104         pNewNode->m_len.Set(m_len);
    01105         pNewNode->m_filepos = m_filepos;
    01106         pNewNode->m_start = m_start;
    01107         return(pNewNode);
    01108 }
    01109
    01110 CAutoPtr<CMatroskaNode> CMatroskaNode::GetFirstBlock()
    01111 {
    01112         CAutoPtr<CMatroskaNode> pNode = Child();
    01113         do {if(pNode->m_id == 0xA0 || pNode->m_id == 0xA3) return pNode;}
    01114         while(pNode->Next());
    01115         return CAutoPtr<CMatroskaNode>();
    01116 }
    01117
    01118 bool CMatroskaNode::NextBlock()
    01119 {
    01120         if(!m_pParent)
    01121                 return(false);
    01122
    01123         CID id = m_id;
    01124
    01125         while(m_start+m_len < m_pParent->m_start+m_pParent->m_len)
    01126         {
    01127                 SeekTo(m_start+m_len);
    01128
    01129                 if(FAILED(Parse()))
    01130                 {
    01131                         if(!Resync())
    01132                                 return(false);
    01133                 }
    01134
    01135                 if(m_id == 0xA0 || m_id == 0xA3)
    01136                         return(true);
    01137         }
    01138
    01139         return(false);
    01140 }
    01141
    01142 bool CMatroskaNode::Resync()
    01143 {
    01144         if(m_pParent->m_id == 0x18538067) /*segment?*/
    01145         {
    01146                 SeekTo(m_filepos);
    01147
    01148                 for(BYTE b = 0; S_OK == Read(b); b = 0)
    01149                 {
    01150                         if((b&0xf0) != 0x10)
    01151                                 continue;
    01152
    01153             DWORD dw = b;
    01154                         Read((BYTE*)&dw+1, 3);
    01155                         bswap((BYTE*)&dw, 4);
    01156
    01157                         switch(dw)
    01158                         {
    01159                         case 0x1549A966: // SegmentInfo
    01160                         case 0x114D9B74: // MetaSeekInfo
    01161                         case 0x1654AE6B: // Tracks
    01162                         case 0x1F43B675: // Clusters
    01163                         case 0x1C53BB6B: // Cues
    01164                         case 0x1941A469: // Attachments
    01165                         case 0x1043A770: // Chapters
    01166                         case 0x1254C367: // Tags
    01167                                 SeekTo(GetPos()-4);
    01168                                 return(SUCCEEDED(Parse()));
    01169                         default:
    01170                                 SeekTo(GetPos()-3);
    01171                                 break;
    01172                         }
    01173                 }
    01174         }
    01175
    01176         return(false);
    01177 }