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
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
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);
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);
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
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;
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);
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
00289
00290 dsmp_t type;
00291 UINT64 syncpos, len;
00292
00293
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
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
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 }