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 }

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