- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# DSMSplitterFile.cpp

    00001 #include "StdAfx.h"
    00002 #include "DSMSplitterFile.h"
    00003 #include "..\..\..\DSUtil\DSUtil.h"
    00004 #include "..\..\..\..\include\matroska\matroska.h"
    00005
    00006 CDSMSplitterFile::CDSMSplitterFile(IAsyncReader* pReader, HRESULT& hr, IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap)
    00007         : CBaseSplitterFile(pReader, hr)
    00008         , m_rtFirst(0)
    00009         , m_rtDuration(0)
    00010 {
    00011         if(FAILED(hr)) return;
    00012
    00013         hr = Init(res, chap);
    00014 }
    00015
    00016 HRESULT CDSMSplitterFile::Init(IDSMResourceBagImpl& res, IDSMChapterBagImpl& chap)
    00017 {
    00018         Seek(0);
    00019
    00020         if(BitRead(DSMSW_SIZE<<3) != DSMSW || BitRead(5) != DSMP_FILEINFO)
    00021                 return E_FAIL;
    00022
    00023         Seek(0);
    00024
    00025         m_mts.RemoveAll();
    00026         m_rtFirst = m_rtDuration = 0;
    00027         m_fim.RemoveAll();
    00028         m_sim.RemoveAll();
    00029         res.ResRemoveAll();
    00030         chap.ChapRemoveAll();
    00031
    00032         dsmp_t type;
    00033         UINT64 len;
    00034         int limit = 65536;
    00035
    00036         // examine the beginning of the file ...
    00037
    00038         while(Sync(type, len, 0))
    00039         {
    00040                 __int64 pos = GetPos();
    00041
    00042                 if(type == DSMP_MEDIATYPE)
    00043                 {
    00044                         BYTE id;
    00045                         CMediaType mt;
    00046                         if(Read(len, id, mt)) m_mts[id] = mt;
    00047                 }
    00048                 else if(type == DSMP_SAMPLE)
    00049                 {
    00050                         Packet p;
    00051                         if(Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME)
    00052                         {
    00053                                 m_rtFirst = p.rtStart;
    00054                                 break;
    00055                         }
    00056                 }
    00057                 else if(type == DSMP_FILEINFO) {if((BYTE)BitRead(8) > DSMF_VERSION) return E_FAIL; Read(len-1, m_fim);}
    00058                 else if(type == DSMP_STREAMINFO) {Read(len-1, m_sim[(BYTE)BitRead(8)]);}
    00059                 else if(type == DSMP_SYNCPOINTS) {Read(len, m_sps);}
    00060                 else if(type == DSMP_RESOURCE) {Read(len, res);}
    00061                 else if(type == DSMP_CHAPTERS) {Read(len, chap);}
    00062
    00063                 Seek(pos + len);
    00064         }
    00065
    00066         if(type != DSMP_SAMPLE)
    00067                 return E_FAIL;
    00068
    00069         // ... and the end
    00070
    00071         for(int i = 1, j = (int)((GetLength()+limit/2)/limit); i <= j; i++)
    00072         {
    00073                 __int64 seekpos = max(0, (__int64)GetLength()-i*limit);
    00074                 Seek(seekpos);
    00075
    00076                 while(Sync(type, len, limit) && GetPos() < seekpos+limit)
    00077                 {
    00078                         __int64 pos = GetPos();
    00079
    00080                         if(type == DSMP_SAMPLE)
    00081                         {
    00082                                 Packet p;
    00083                                 if(Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME)
    00084                                 {
    00085                                         m_rtDuration = max(m_rtDuration, p.rtStop - m_rtFirst); // max isn't really needed, only for safety
    00086                                         i = j;
    00087                                 }
    00088                         }
    00089                         else if(type == DSMP_FILEINFO) {if((BYTE)BitRead(8) > DSMF_VERSION) return E_FAIL; Read(len-1, m_fim);}
    00090                         else if(type == DSMP_STREAMINFO) {Read(len-1, m_sim[(BYTE)BitRead(8)]);}
    00091                         else if(type == DSMP_SYNCPOINTS) {Read(len, m_sps);}
    00092                         else if(type == DSMP_RESOURCE) {Read(len, res);}
    00093                         else if(type == DSMP_CHAPTERS) {Read(len, chap);}
    00094
    00095                         Seek(pos + len);
    00096                 }
    00097         }
    00098
    00099         if(m_rtFirst < 0)
    00100         {
    00101                 m_rtDuration += m_rtFirst;
    00102                 m_rtFirst = 0;
    00103         }
    00104
    00105         return m_mts.GetCount() > 0 ? S_OK : E_FAIL;
    00106 }
    00107
    00108 bool CDSMSplitterFile::Sync(dsmp_t& type, UINT64& len, __int64 limit)
    00109 {
    00110         UINT64 pos;
    00111         return Sync(pos, type, len, limit);
    00112 }
    00113
    00114 bool CDSMSplitterFile::Sync(UINT64& syncpos, dsmp_t& type, UINT64& len, __int64 limit)
    00115 {
    00116         BitByteAlign();
    00117
    00118         limit += DSMSW_SIZE;
    00119
    00120         for(UINT64 id = 0; (id&((1ui64<<(DSMSW_SIZE<<3))-1)) != DSMSW; id = (id << 8) | (BYTE)BitRead(8))
    00121         {
    00122                 if(limit-- <= 0 || GetPos() >= GetLength()-2)
    00123                         return(false);
    00124         }
    00125
    00126         syncpos = GetPos() - (DSMSW_SIZE<<3);
    00127         type = (dsmp_t)BitRead(5);
    00128         len = BitRead(((int)BitRead(3)+1)<<3);
    00129
    00130         return(true);
    00131 }
    00132
    00133 bool CDSMSplitterFile::Read(__int64 len, BYTE& id, CMediaType& mt)
    00134 {
    00135         id = (BYTE)BitRead(8);
    00136         ByteRead((BYTE*)&mt.majortype, sizeof(mt.majortype));
    00137         ByteRead((BYTE*)&mt.subtype, sizeof(mt.subtype));
    00138         mt.bFixedSizeSamples = (BOOL)BitRead(1);
    00139         mt.bTemporalCompression = (BOOL)BitRead(1);
    00140         mt.lSampleSize = (ULONG)BitRead(30);
    00141         ByteRead((BYTE*)&mt.formattype, sizeof(mt.formattype));
    00142         len -= 5 + sizeof(GUID)*3;
    00143         ASSERT(len >= 0);
    00144         if(len > 0) {mt.AllocFormatBuffer((LONG)len); ByteRead(mt.Format(), mt.FormatLength());}
    00145         else mt.ResetFormatBuffer();
    00146         return true;
    00147 }
    00148
    00149 bool CDSMSplitterFile::Read(__int64 len, Packet* p, bool fData)
    00150 {
    00151         if(!p) return false;
    00152
    00153         p->TrackNumber = (DWORD)BitRead(8);
    00154         p->bSyncPoint = (BOOL)BitRead(1);
    00155         bool fSign = !!BitRead(1);
    00156         int iTimeStamp = (int)BitRead(3);
    00157         int iDuration = (int)BitRead(3);
    00158
    00159         if(fSign && !iTimeStamp)
    00160         {
    00161                 ASSERT(!iDuration);
    00162                 p->rtStart = Packet::INVALID_TIME;
    00163                 p->rtStop = Packet::INVALID_TIME + 1;
    00164         }
    00165         else
    00166         {
    00167                 p->rtStart = (REFERENCE_TIME)BitRead(iTimeStamp<<3) * (fSign ? -1 : 1);
    00168                 p->rtStop = p->rtStart + BitRead(iDuration<<3);
    00169         }
    00170
    00171         if(fData)
    00172         {
    00173         p->pData.SetSize((INT_PTR)len - (2 + iTimeStamp + iDuration));
    00174                 ByteRead(p->pData.GetData(), p->pData.GetSize());
    00175         }
    00176
    00177         return true;
    00178 }
    00179
    00180 bool CDSMSplitterFile::Read(__int64 len, CArray<SyncPoint>& sps)
    00181 {
    00182         SyncPoint sp = {0, 0};
    00183         sps.RemoveAll();
    00184
    00185         while(len > 0)
    00186         {
    00187                 bool fSign = !!BitRead(1);
    00188                 int iTimeStamp = (int)BitRead(3);
    00189                 int iFilePos = (int)BitRead(3);
    00190                 BitRead(1); // reserved
    00191
    00192                 sp.rt += (REFERENCE_TIME)BitRead(iTimeStamp<<3) * (fSign ? -1 : 1);
    00193                 sp.fp += BitRead(iFilePos<<3);
    00194                 sps.Add(sp);
    00195
    00196                 len -= 1 + iTimeStamp + iFilePos;
    00197         }
    00198
    00199         if(len != 0)
    00200         {
    00201                 sps.RemoveAll();
    00202                 return false;
    00203         }
    00204
    00205         // TODO: sort sps
    00206
    00207         return true;
    00208 }
    00209
    00210 bool CDSMSplitterFile::Read(__int64 len, CStreamInfoMap& im)
    00211 {
    00212         while(len >= 5)
    00213         {
    00214                 CStringA key;
    00215                 ByteRead((BYTE*)key.GetBufferSetLength(4), 4);
    00216                 len -= 4;
    00217                 len -= Read(len, im[key]);
    00218         }
    00219
    00220         return len == 0;
    00221 }
    00222
    00223 bool CDSMSplitterFile::Read(__int64 len, IDSMResourceBagImpl& res)
    00224 {
    00225         BYTE compression = (BYTE)BitRead(2);
    00226         BYTE reserved = (BYTE)BitRead(6);
    00227         len--;
    00228
    00229         CDSMResource r;
    00230         len -= Read(len, r.name);
    00231         len -= Read(len, r.desc);
    00232         len -= Read(len, r.mime);
    00233
    00234         if(compression != 0) return false; // TODO
    00235
    00236         r.data.SetSize(len);
    00237         ByteRead(r.data.GetData(), r.data.GetSize());
    00238
    00239         res += r;
    00240
    00241         return true;
    00242 }
    00243
    00244 bool CDSMSplitterFile::Read(__int64 len, IDSMChapterBagImpl& chap)
    00245 {
    00246         CDSMChapter c(0, L"");
    00247
    00248         while(len > 0)
    00249         {
    00250                 bool fSign = !!BitRead(1);
    00251                 int iTimeStamp = (int)BitRead(3);
    00252                 BitRead(4); // reserved
    00253                 len--;
    00254
    00255                 c.rt += (REFERENCE_TIME)BitRead(iTimeStamp<<3) * (fSign ? -1 : 1);
    00256                 len -= iTimeStamp;
    00257                 len -= Read(len, c.name);
    00258
    00259                 chap += c;
    00260         }
    00261
    00262         chap.ChapSort();
    00263
    00264         return len == 0;
    00265 }
    00266
    00267 __int64 CDSMSplitterFile::Read(__int64 len, CStringW& str)
    00268 {
    00269         char c;
    00270         CStringA s;
    00271         __int64 i = 0;
    00272         while(i++ < len && (c = (char)BitRead(8)) != 0) s += c;
    00273         str = UTF8To16(s);
    00274         return i;
    00275 }
    00276
    00277 __int64 CDSMSplitterFile::FindSyncPoint(REFERENCE_TIME rt)
    00278 {
    00279         if( m_sps.GetCount() > 1)
    00280         {
    00281                 int i = range_bsearch(m_sps, m_rtFirst + rt);
    00282                 return i >= 0 ? m_sps[i].fp : 0;
    00283         }
    00284
    00285         if(m_rtDuration <= 0 || rt <= m_rtFirst)
    00286                 return 0;
    00287
    00288         // ok, do the hard way then
    00289
    00290         dsmp_t type;
    00291         UINT64 syncpos, len;
    00292
    00293         // 1. find some boundaries close to rt's position (minpos, maxpos)
    00294
    00295         __int64 minpos = 0, maxpos = GetLength();
    00296
    00297         for(int i = 0; i < 10 && (maxpos - minpos) >= 1024*1024; i++)
    00298         {
    00299                 Seek((minpos + maxpos) / 2);
    00300
    00301                 while(GetPos() < maxpos)
    00302                 {
    00303                         if(!Sync(syncpos, type, len))
    00304                                 continue;
    00305
    00306                         __int64 pos = GetPos();
    00307
    00308                         if(type == DSMP_SAMPLE)
    00309                         {
    00310                                 Packet p;
    00311                                 if(Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME)
    00312                                 {
    00313                                         REFERENCE_TIME dt = (p.rtStart -= m_rtFirst) - rt;
    00314                                         if(dt >= 0) maxpos = max((__int64)syncpos - 65536, minpos);
    00315                                         else minpos = syncpos;
    00316                                         break;
    00317                                 }
    00318                         }
    00319
    00320                         Seek(pos + len);
    00321                 }
    00322         }
    00323
    00324         // 2. find the first packet just after rt (maxpos)
    00325
    00326         Seek(minpos);
    00327
    00328         while(GetPos() < GetLength())
    00329         {
    00330                 if(!Sync(syncpos, type, len))
    00331                         continue;
    00332
    00333                 __int64 pos = GetPos();
    00334
    00335                 if(type == DSMP_SAMPLE)
    00336                 {
    00337                         Packet p;
    00338                         if(Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME)
    00339                         {
    00340                                 REFERENCE_TIME dt = (p.rtStart -= m_rtFirst) - rt;
    00341                                 if(dt >= 0) {maxpos = (__int64)syncpos; break;}
    00342                         }
    00343                 }
    00344
    00345                 Seek(pos + len);
    00346         }
    00347
    00348         // 3. iterate backwards from maxpos and find at least one syncpoint for every stream, except for subtitle streams
    00349
    00350         CAtlMap<BYTE,BYTE> ids;
    00351
    00352         {
    00353                 POSITION pos = m_mts.GetStartPosition();
    00354                 while(pos)
    00355                 {
    00356                         BYTE id;
    00357                         CMediaType mt;
    00358                         m_mts.GetNextAssoc(pos, id, mt);
    00359                         if(mt.majortype != MEDIATYPE_Text && mt.majortype != MEDIATYPE_Subtitle)
    00360                                 ids[id] = 0;
    00361                 }
    00362         }
    00363
    00364         __int64 ret = maxpos;
    00365
    00366         while(maxpos > 0 && !ids.IsEmpty())
    00367         {
    00368                 minpos = max(0, maxpos - 65536);
    00369
    00370                 Seek(minpos);
    00371
    00372                 while(Sync(syncpos, type, len) && GetPos() < maxpos)
    00373                 {
    00374                         UINT64 pos = GetPos();
    00375
    00376                         if(type == DSMP_SAMPLE)
    00377                         {
    00378                                 Packet p;
    00379                                 if(Read(len, &p, false) && p.rtStart != Packet::INVALID_TIME && p.bSyncPoint)
    00380                                 {
    00381                                         BYTE id = (BYTE)p.TrackNumber, tmp;
    00382                                         if(ids.Lookup(id, tmp))
    00383                                         {
    00384                                                 ids.RemoveKey((BYTE)p.TrackNumber);
    00385                                                 ret = min(ret, (__int64)syncpos);
    00386                                         }
    00387                                 }
    00388                         }
    00389
    00390                         Seek(pos + len);
    00391                 }
    00392
    00393                 maxpos = minpos;
    00394         }
    00395
    00396         return ret;
    00397 }