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 }

Generated on Tue Dec 13 14:47:09 2005 for guliverkli by  doxygen 1.4.5