MP4Splitter.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:25k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2005 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. #include "StdAfx.h"
  22. #include "MP4Splitter.h"
  23. #include "......DSUtilDSUtil.h"
  24. #include <initguid.h>
  25. #include "........includemoreuuids.h"
  26. #include "Ap4.h"
  27. #include "Ap4File.h"
  28. #include "Ap4StssAtom.h"
  29. #include "Ap4IsmaCryp.h"
  30. #include "Ap4AvcCAtom.h"
  31. #include "Ap4ChplAtom.h"
  32. #include "Ap4DataAtom.h"
  33. #ifdef REGISTER_FILTER
  34. const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
  35. {
  36. {&MEDIATYPE_Stream, &MEDIASUBTYPE_MP4},
  37. {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL},
  38. };
  39. const AMOVIESETUP_PIN sudpPins[] =
  40. {
  41. {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
  42. {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, 0, NULL}
  43. };
  44. const AMOVIESETUP_FILTER sudFilter[] =
  45. {
  46. {&__uuidof(CMP4SplitterFilter), L"MP4 Splitter", MERIT_NORMAL, countof(sudpPins), sudpPins},
  47. {&__uuidof(CMP4SourceFilter), L"MP4 Source", MERIT_NORMAL, 0, NULL},
  48. };
  49. CFactoryTemplate g_Templates[] =
  50. {
  51. {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CMP4SplitterFilter>, NULL, &sudFilter[0]},
  52. {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance<CMP4SourceFilter>, NULL, &sudFilter[1]},
  53. };
  54. int g_cTemplates = countof(g_Templates);
  55. STDAPI DllRegisterServer()
  56. {
  57. DeleteRegKey(_T("Media Type\Extensions\"), _T(".mp4"));
  58. CList<CString> chkbytes;
  59. chkbytes.AddTail(_T("4,4,,66747970")); // ftyp
  60. chkbytes.AddTail(_T("4,4,,6d6f6f76")); // moov
  61. chkbytes.AddTail(_T("4,4,,6d646174")); // mdat
  62. chkbytes.AddTail(_T("4,4,,736b6970")); // skip
  63. RegisterSourceFilter(CLSID_AsyncReader, MEDIASUBTYPE_MP4, chkbytes, NULL);
  64. return AMovieDllRegisterServer2(TRUE);
  65. }
  66. STDAPI DllUnregisterServer()
  67. {
  68. UnRegisterSourceFilter(MEDIASUBTYPE_MP4);
  69. return AMovieDllRegisterServer2(FALSE);
  70. }
  71. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
  72. BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
  73. {
  74.     return DllEntryPoint((HINSTANCE)hModule, dwReason, 0); // "DllMain" of the dshow baseclasses;
  75. }
  76. #endif
  77. //
  78. // CMP4SplitterFilter
  79. //
  80. CMP4SplitterFilter::CMP4SplitterFilter(LPUNKNOWN pUnk, HRESULT* phr)
  81. : CBaseSplitterFilter(NAME("CMP4SplitterFilter"), pUnk, phr, __uuidof(this))
  82. {
  83. }
  84. CMP4SplitterFilter::~CMP4SplitterFilter()
  85. {
  86. }
  87. HRESULT CMP4SplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader)
  88. {
  89. CheckPointer(pAsyncReader, E_POINTER);
  90. HRESULT hr = E_FAIL;
  91. m_trackpos.RemoveAll();
  92. m_pFile.Free();
  93. m_pFile.Attach(new CMP4SplitterFile(pAsyncReader, hr));
  94. if(!m_pFile) return E_OUTOFMEMORY;
  95. if(FAILED(hr)) {m_pFile.Free(); return hr;}
  96. m_rtNewStart = m_rtCurrent = 0;
  97. m_rtNewStop = m_rtStop = m_rtDuration = 0;
  98. if(AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie())
  99. {
  100. for(AP4_List<AP4_Track>::Item* item = movie->GetTracks().FirstItem();
  101. item;
  102. item = item->GetNext())
  103. {
  104. AP4_Track* track = item->GetData();
  105. if(track->GetType() != AP4_Track::TYPE_VIDEO 
  106. && track->GetType() != AP4_Track::TYPE_AUDIO
  107. && track->GetType() != AP4_Track::TYPE_TEXT)
  108. continue;
  109. AP4_Sample sample;
  110. if(!AP4_SUCCEEDED(track->GetSample(0, sample)) || sample.GetDescriptionIndex() == 0xFFFFFFFF)
  111. continue;
  112. CArray<CMediaType> mts;
  113. CMediaType mt;
  114. mt.SetSampleSize(1);
  115. VIDEOINFOHEADER* vih = NULL;
  116. WAVEFORMATEX* wfe = NULL;
  117. AP4_DataBuffer empty;
  118. if(AP4_SampleDescription* desc = track->GetSampleDescription(sample.GetDescriptionIndex()))
  119. {
  120. AP4_MpegSampleDescription* mpeg_desc = NULL;
  121. if(desc->GetType() == AP4_SampleDescription::TYPE_MPEG)
  122. {
  123. mpeg_desc = dynamic_cast<AP4_MpegSampleDescription*>(desc);
  124. }
  125. else if(desc->GetType() == AP4_SampleDescription::TYPE_ISMACRYP)
  126. {
  127. AP4_IsmaCrypSampleDescription* isma_desc = dynamic_cast<AP4_IsmaCrypSampleDescription*>(desc);
  128. mpeg_desc = isma_desc->GetOriginalSampleDescription();
  129. }
  130. if(AP4_MpegVideoSampleDescription* video_desc = 
  131. dynamic_cast<AP4_MpegVideoSampleDescription*>(mpeg_desc))
  132. {
  133. const AP4_DataBuffer* di = video_desc->GetDecoderInfo();
  134. if(!di) di = &empty;
  135. mt.majortype = MEDIATYPE_Video;
  136. mt.formattype = FORMAT_VideoInfo;
  137. vih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER) + di->GetDataSize());
  138. memset(vih, 0, mt.FormatLength());
  139. vih->dwBitRate = video_desc->GetAvgBitrate()/8;
  140. vih->bmiHeader.biSize = sizeof(vih->bmiHeader);
  141. vih->bmiHeader.biWidth = (LONG)video_desc->GetWidth();
  142. vih->bmiHeader.biHeight = (LONG)video_desc->GetHeight();
  143. memcpy(vih + 1, di->GetData(), di->GetDataSize());
  144. switch(video_desc->GetObjectTypeId())
  145. {
  146. case AP4_MPEG4_VISUAL_OTI:
  147. mt.subtype = FOURCCMap('v4pm');
  148. mt.formattype = FORMAT_MPEG2Video;
  149. {
  150. MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.AllocFormatBuffer(FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader) + di->GetDataSize());
  151. memset(vih, 0, mt.FormatLength());
  152. vih->hdr.bmiHeader.biSize = sizeof(vih->hdr.bmiHeader);
  153. vih->hdr.bmiHeader.biWidth = (LONG)video_desc->GetWidth();
  154. vih->hdr.bmiHeader.biHeight = (LONG)video_desc->GetHeight();
  155. vih->hdr.bmiHeader.biCompression = 'v4pm';
  156. vih->hdr.bmiHeader.biPlanes = 1;
  157. vih->hdr.bmiHeader.biBitCount = 24;
  158. vih->hdr.dwPictAspectRatioX = vih->hdr.bmiHeader.biWidth;
  159. vih->hdr.dwPictAspectRatioY = vih->hdr.bmiHeader.biHeight;
  160. vih->cbSequenceHeader = di->GetDataSize();
  161. memcpy(vih->dwSequenceHeader, di->GetData(), di->GetDataSize());
  162. mts.Add(mt);
  163. mt.subtype = FOURCCMap(vih->hdr.bmiHeader.biCompression = 'V4PM');
  164. mts.Add(mt);
  165. }
  166. break;
  167. case AP4_MPEG2_VISUAL_SIMPLE_OTI:
  168. case AP4_MPEG2_VISUAL_MAIN_OTI:
  169. case AP4_MPEG2_VISUAL_SNR_OTI:
  170. case AP4_MPEG2_VISUAL_SPATIAL_OTI:
  171. case AP4_MPEG2_VISUAL_HIGH_OTI:
  172. case AP4_MPEG2_VISUAL_422_OTI:
  173. mt.subtype = MEDIASUBTYPE_MPEG2_VIDEO;
  174. {
  175. m_pFile->Seek(sample.GetOffset());
  176. CBaseSplitterFileEx::seqhdr h;
  177. CMediaType mt2;
  178. if(m_pFile->Read(h, sample.GetSize(), &mt2))
  179. mt = mt2;
  180. }
  181. mts.Add(mt);
  182. break;
  183. case AP4_MPEG1_VISUAL_OTI: // ???
  184. mt.subtype = MEDIASUBTYPE_MPEG1Payload;
  185. {
  186. m_pFile->Seek(sample.GetOffset());
  187. CBaseSplitterFileEx::seqhdr h;
  188. CMediaType mt2;
  189. if(m_pFile->Read(h, sample.GetSize(), &mt2))
  190. mt = mt2;
  191. }
  192. mts.Add(mt);
  193. break;
  194. }
  195. if(mt.subtype == GUID_NULL)
  196. {
  197. TRACE(_T("Unknown video OBI: %02xn"), video_desc->GetObjectTypeId());
  198. }
  199. }
  200. else if(AP4_MpegAudioSampleDescription* audio_desc = 
  201. dynamic_cast<AP4_MpegAudioSampleDescription*>(mpeg_desc))
  202. {
  203. const AP4_DataBuffer* di = audio_desc->GetDecoderInfo();
  204. if(!di) di = &empty;
  205. mt.majortype = MEDIATYPE_Audio;
  206. mt.formattype = FORMAT_WaveFormatEx;
  207. wfe = (WAVEFORMATEX*)mt.AllocFormatBuffer(sizeof(WAVEFORMATEX) + di->GetDataSize());
  208. memset(wfe, 0, mt.FormatLength());
  209. wfe->nSamplesPerSec = audio_desc->GetSampleRate();
  210. wfe->nAvgBytesPerSec = audio_desc->GetAvgBitrate()/8;
  211. wfe->nChannels = audio_desc->GetChannelCount();
  212. wfe->wBitsPerSample = audio_desc->GetSampleSize();
  213. wfe->cbSize = (WORD)di->GetDataSize();
  214. memcpy(wfe + 1, di->GetData(), di->GetDataSize());
  215. switch(audio_desc->GetObjectTypeId())
  216. {
  217. case AP4_MPEG4_AUDIO_OTI:
  218. case AP4_MPEG2_AAC_AUDIO_MAIN_OTI: // ???
  219. case AP4_MPEG2_AAC_AUDIO_LC_OTI: // ???
  220. case AP4_MPEG2_AAC_AUDIO_SSRP_OTI: // ???
  221. mt.subtype = FOURCCMap(wfe->wFormatTag = WAVE_FORMAT_AAC);
  222. mts.Add(mt);
  223. break;
  224. case AP4_MPEG2_PART3_AUDIO_OTI: // ???
  225. break;
  226. case AP4_MPEG1_AUDIO_OTI:
  227. mt.subtype = FOURCCMap(wfe->wFormatTag = WAVE_FORMAT_MP3);
  228. {
  229. m_pFile->Seek(sample.GetOffset());
  230. CBaseSplitterFileEx::mpahdr h;
  231. CMediaType mt2;
  232. if(m_pFile->Read(h, sample.GetSize(), false, &mt2))
  233. mt = mt2;
  234. }
  235. mts.Add(mt);
  236. break;
  237. }
  238. if(mt.subtype == GUID_NULL)
  239. {
  240. TRACE(_T("Unknown audio OBI: %02xn"), audio_desc->GetObjectTypeId());
  241. }
  242. }
  243. else if(AP4_UnknownSampleDescription* unknown_desc = 
  244. dynamic_cast<AP4_UnknownSampleDescription*>(desc)) // TEMP
  245. {
  246. AP4_SampleEntry* sample_entry = unknown_desc->GetSampleEntry();
  247. if(dynamic_cast<AP4_TextSampleEntry*>(sample_entry)
  248. || dynamic_cast<AP4_Tx3gSampleEntry*>(sample_entry))
  249. {
  250. mt.majortype = MEDIATYPE_Subtitle;
  251. mt.subtype = MEDIASUBTYPE_ASS;
  252. mt.formattype = FORMAT_SubtitleInfo;
  253. CStringA hdr = "[Script Info]nScriptType: v4.00+n";
  254. SUBTITLEINFO* si = (SUBTITLEINFO*)mt.AllocFormatBuffer(sizeof(SUBTITLEINFO) + hdr.GetLength());
  255. memset(si, 0, mt.FormatLength());
  256. si->dwOffset = sizeof(SUBTITLEINFO);
  257. /* dong
  258. strcpy_s(si->IsoLang, countof(si->IsoLang), track->GetTrackLanguage().c_str());
  259. wcscpy_s(si->TrackName, countof(si->TrackName), CStringW(track->GetTrackName().c_str()));
  260. */
  261. strcpy(si->IsoLang, track->GetTrackLanguage().c_str());
  262. wcscpy(si->TrackName,CStringW(track->GetTrackName().c_str()));
  263. memcpy(si + 1, (LPCSTR)hdr, hdr.GetLength());
  264. // mts.Add(mt); // TODO
  265. mt.subtype = MEDIASUBTYPE_UTF8;
  266. si = (SUBTITLEINFO*)mt.ReallocFormatBuffer(sizeof(SUBTITLEINFO));
  267. mts.Add(mt);
  268. }
  269. }
  270. }
  271. else if(AP4_Avc1SampleEntry* avc1 = dynamic_cast<AP4_Avc1SampleEntry*>(
  272. track->GetTrakAtom()->FindChild("mdia/minf/stbl/stsd/avc1")))
  273. {
  274. if(AP4_AvcCAtom* avcC = dynamic_cast<AP4_AvcCAtom*>(avc1->GetChild(AP4_ATOM_TYPE_AVCC)))
  275. {
  276. const AP4_DataBuffer* di = avcC->GetDecoderInfo();
  277. if(!di) di = &empty;
  278. const AP4_Byte* data = di->GetData();
  279. AP4_Size size = di->GetDataSize();
  280. mt.majortype = MEDIATYPE_Video;
  281. mt.subtype = FOURCCMap('1cva');
  282. mt.formattype = FORMAT_MPEG2Video;
  283. MPEG2VIDEOINFO* vih = (MPEG2VIDEOINFO*)mt.AllocFormatBuffer(FIELD_OFFSET(MPEG2VIDEOINFO, dwSequenceHeader) + size - 7);
  284. memset(vih, 0, mt.FormatLength());
  285. vih->hdr.bmiHeader.biSize = sizeof(vih->hdr.bmiHeader);
  286. vih->hdr.bmiHeader.biWidth = (LONG)avc1->GetWidth();
  287. vih->hdr.bmiHeader.biHeight = (LONG)avc1->GetHeight();
  288. vih->hdr.bmiHeader.biCompression = '1cva';
  289. vih->hdr.bmiHeader.biPlanes = 1;
  290. vih->hdr.bmiHeader.biBitCount = 24;
  291. vih->hdr.dwPictAspectRatioX = vih->hdr.bmiHeader.biWidth;
  292. vih->hdr.dwPictAspectRatioY = vih->hdr.bmiHeader.biHeight;
  293. vih->dwProfile = data[1];
  294. vih->dwLevel = data[3];
  295. vih->dwFlags = (data[4] & 3) + 1;
  296. vih->cbSequenceHeader = 0;
  297. BYTE* src = (BYTE*)data + 5;
  298. BYTE* dst = (BYTE*)vih->dwSequenceHeader;
  299. BYTE* src_end = (BYTE*)data + size;
  300. BYTE* dst_end = (BYTE*)vih->dwSequenceHeader + size;
  301. for(int i = 0; i < 2; i++)
  302. {
  303. for(int n = *src++ & 0x1f; n > 0; n--)
  304. {
  305. int len = ((src[0] << 8) | src[1]) + 2;
  306. if(src + len > src_end || dst + len > dst_end) {ASSERT(0); break;}
  307. memcpy(dst, src, len);
  308. src += len; 
  309. dst += len;
  310. vih->cbSequenceHeader += len;
  311. }
  312. }
  313. mts.Add(mt);
  314. mt.subtype = FOURCCMap(vih->hdr.bmiHeader.biCompression = '1CVA');
  315. mts.Add(mt);
  316. }
  317. }
  318. else if(AP4_VisualSampleEntry* s263 = dynamic_cast<AP4_VisualSampleEntry*>(
  319. track->GetTrakAtom()->FindChild("mdia/minf/stbl/stsd/s263")))
  320. {
  321. mt.majortype = MEDIATYPE_Video;
  322. mt.subtype = FOURCCMap('362s');
  323. mt.formattype = FORMAT_VideoInfo;
  324. vih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
  325. memset(vih, 0, mt.FormatLength());
  326. vih->bmiHeader.biSize = sizeof(vih->bmiHeader);
  327. vih->bmiHeader.biWidth = (LONG)s263->GetWidth();
  328. vih->bmiHeader.biHeight = (LONG)s263->GetHeight();
  329. vih->bmiHeader.biCompression = '362s';
  330. mts.Add(mt);
  331. mt.subtype = FOURCCMap(vih->bmiHeader.biCompression = '362S');
  332. mts.Add(mt);
  333. }
  334. else if(AP4_AudioSampleEntry* samr = dynamic_cast<AP4_AudioSampleEntry*>(
  335. track->GetTrakAtom()->FindChild("mdia/minf/stbl/stsd/samr")))
  336. {
  337. mt.majortype = MEDIATYPE_Audio;
  338. mt.subtype = FOURCCMap('rmas');
  339. mt.formattype = FORMAT_WaveFormatEx;
  340. wfe = (WAVEFORMATEX*)mt.AllocFormatBuffer(sizeof(WAVEFORMATEX));
  341. memset(wfe, 0, mt.FormatLength());
  342. wfe->nSamplesPerSec = samr->GetSampleRate();
  343. wfe->nChannels = samr->GetChannelCount();
  344. mts.Add(mt);
  345. mt.subtype = FOURCCMap('RMAS');
  346. mts.Add(mt);
  347. }
  348. REFERENCE_TIME rtDuration = 10000i64 * track->GetDurationMs();
  349. if(m_rtDuration < rtDuration) m_rtDuration = rtDuration;
  350. DWORD id = track->GetId();
  351. CStringW name, lang;
  352. name.Format(L"Output %d", id);
  353. AP4_String TrackName = track->GetTrackName();
  354. AP4_String TrackLanguage = track->GetTrackLanguage();
  355. if(!TrackName.empty())
  356. {
  357. name.Format(L"%s", CStringW(TrackName.c_str()));
  358. SetProperty(L"NAME", CStringW(TrackName.c_str()));
  359. }
  360. if(!TrackLanguage.empty())
  361. {
  362. if(TrackLanguage != "und") name += L" (" + CStringW(TrackLanguage.c_str()) + L")";
  363. SetProperty(L"LANG", CStringW(TrackLanguage.c_str()));
  364. }
  365. CAutoPtr<CBaseSplitterOutputPin> pPinOut(new CBaseSplitterOutputPin(mts, name, this, this, &hr));
  366. EXECUTE_ASSERT(SUCCEEDED(AddOutputPin(id, pPinOut)));
  367. m_trackpos[id] = trackpos();
  368. }
  369. if(AP4_ChplAtom* chpl = dynamic_cast<AP4_ChplAtom*>(movie->GetMoovAtom()->FindChild("udta/chpl")))
  370. {
  371. AP4_Array<AP4_ChplAtom::AP4_Chapter>& chapters = chpl->GetChapters();
  372. for(AP4_Cardinal i = 0; i < chapters.ItemCount(); i++)
  373. {
  374. AP4_ChplAtom::AP4_Chapter& chapter = chapters[i];
  375. ChapAppend(chapter.Time, UTF8To16(ConvertMBCS(chapter.Name.c_str(), ANSI_CHARSET, CP_UTF8)));
  376. }
  377. ChapSort();
  378. }
  379. if(AP4_ContainerAtom* ilst = dynamic_cast<AP4_ContainerAtom*>(movie->GetMoovAtom()->FindChild("udta/meta/ilst")))
  380. {
  381. CStringW title, artist, writer, album, year, appl, desc, track;
  382. for(AP4_List<AP4_Atom>::Item* item = ilst->GetChildren().FirstItem();
  383. item;
  384. item = item->GetNext())
  385. {
  386. if(AP4_ContainerAtom* atom = dynamic_cast<AP4_ContainerAtom*>(item->GetData()))
  387. {
  388. if(AP4_DataAtom* data = dynamic_cast<AP4_DataAtom*>(atom->GetChild(AP4_ATOM_TYPE_DATA)))
  389. {
  390. const AP4_DataBuffer* db = data->GetData();
  391. if(atom->GetType() == AP4_ATOM_TYPE_TRKN)
  392. {
  393. if(db->GetDataSize() >= 4)
  394. {
  395. unsigned short n = (db->GetData()[2] << 8) | db->GetData()[3];
  396. if(n > 0 && n < 100) track.Format(L"%02d", n);
  397. else if(n >= 100) track.Format(L"%d", n);
  398. }
  399. }
  400. else
  401. {
  402. CStringW str = UTF8To16(CStringA((LPCSTR)db->GetData(), db->GetDataSize()));
  403. switch(atom->GetType())
  404. {
  405. case AP4_ATOM_TYPE_NAM: title = str; break;
  406. case AP4_ATOM_TYPE_ART: artist = str; break;
  407. case AP4_ATOM_TYPE_WRT: writer = str; break;
  408. case AP4_ATOM_TYPE_ALB: album = str; break;
  409. case AP4_ATOM_TYPE_DAY: year = str; break;
  410. case AP4_ATOM_TYPE_TOO: appl = str; break;
  411. case AP4_ATOM_TYPE_CMT: desc = str; break;
  412. }
  413. }
  414. }
  415. }
  416. }
  417. if(!title.IsEmpty())
  418. {
  419. if(!track.IsEmpty()) title = track + L" - " + title;
  420. if(!album.IsEmpty()) title = album + L" - " + title;
  421. if(!year.IsEmpty()) title += L" - " +  year;
  422. SetProperty(L"TITL", title);
  423. }
  424. if(!artist.IsEmpty()) SetProperty(L"AUTH", artist);
  425. else if(!writer.IsEmpty()) SetProperty(L"AUTH", writer);
  426. if(!appl.IsEmpty()) SetProperty(L"APPL", appl);
  427. if(!desc.IsEmpty()) SetProperty(L"DESC", desc);
  428. }
  429. }
  430. m_rtNewStop = m_rtStop = m_rtDuration;
  431. return m_pOutputs.GetCount() > 0 ? S_OK : E_FAIL;
  432. }
  433. bool CMP4SplitterFilter::DemuxInit()
  434. {
  435. AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie();
  436. POSITION pos = m_trackpos.GetStartPosition();
  437. while(pos)
  438. {
  439. CAtlMap<DWORD, trackpos>::CPair* pPair = m_trackpos.GetNext(pos);
  440. pPair->m_value.index = 0;
  441. pPair->m_value.ts = 0;
  442. AP4_Track* track = movie->GetTrack(pPair->m_key);
  443. AP4_Sample sample;
  444. if(AP4_SUCCEEDED(track->GetSample(0, sample)))
  445. pPair->m_value.ts = sample.GetCts();
  446. }
  447. return true;
  448. }
  449. void CMP4SplitterFilter::DemuxSeek(REFERENCE_TIME rt)
  450. {
  451. AP4_TimeStamp ts = (AP4_TimeStamp)(rt / 10000);
  452. AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie();
  453. POSITION pos = m_trackpos.GetStartPosition();
  454. while(pos)
  455. {
  456. CAtlMap<DWORD, trackpos>::CPair* pPair = m_trackpos.GetNext(pos);
  457. AP4_Track* track = movie->GetTrack(pPair->m_key);
  458. if(AP4_FAILED(track->GetSampleIndexForTimeStampMs(ts, pPair->m_value.index)))
  459. pPair->m_value.index = 0;
  460. AP4_Sample sample;
  461. if(AP4_SUCCEEDED(track->GetSample(pPair->m_value.index, sample)))
  462. pPair->m_value.ts = sample.GetCts();
  463. // FIXME: slow search & stss->m_Entries is private
  464. if(AP4_StssAtom* stss = dynamic_cast<AP4_StssAtom*>(track->GetTrakAtom()->FindChild("mdia/minf/stbl/stss")))
  465. {
  466. if(stss->m_Entries.ItemCount() > 0)
  467. {
  468. AP4_Cardinal i = -1;
  469. while(++i < stss->m_Entries.ItemCount() && stss->m_Entries[i]-1 <= pPair->m_value.index);
  470. if(i > 0) i--;
  471. pPair->m_value.index = stss->m_Entries[i]-1;
  472. }
  473. }
  474. }
  475. }
  476. bool CMP4SplitterFilter::DemuxLoop()
  477. {
  478. HRESULT hr = S_OK;
  479. AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie();
  480. while(SUCCEEDED(hr) && !CheckRequest(NULL))
  481. {
  482. CAtlMap<DWORD, trackpos>::CPair* pPairNext = NULL;
  483. REFERENCE_TIME rtNext = 0;
  484. POSITION pos = m_trackpos.GetStartPosition();
  485. while(pos)
  486. {
  487. CAtlMap<DWORD, trackpos>::CPair* pPair = m_trackpos.GetNext(pos);
  488. AP4_Track* track = movie->GetTrack(pPair->m_key);
  489. REFERENCE_TIME rt = (REFERENCE_TIME)(10000000.0 / track->GetMediaTimeScale() * pPair->m_value.ts);
  490. if(pPair->m_value.index < track->GetSampleCount() && (!pPairNext || rt < rtNext))
  491. {
  492. pPairNext = pPair;
  493. rtNext = rt;
  494. }
  495. }
  496. if(!pPairNext) break;
  497. AP4_Track* track = movie->GetTrack(pPairNext->m_key);
  498. AP4_Sample sample;
  499. AP4_DataBuffer data;
  500. if(AP4_SUCCEEDED(track->ReadSample(pPairNext->m_value.index, sample, data)))
  501. {
  502. CAutoPtr<Packet> p(new Packet());
  503. p->TrackNumber = (DWORD)track->GetId();
  504. p->rtStart = (REFERENCE_TIME)(10000000.0 / track->GetMediaTimeScale() * sample.GetCts());
  505. p->rtStop = p->rtStart + 1;
  506. p->bSyncPoint = TRUE;
  507. if(track->GetType() == AP4_Track::TYPE_TEXT)
  508. {
  509. const AP4_Byte* ptr = data.GetData();
  510. AP4_Size avail = data.GetDataSize();
  511. if(avail > 2)
  512. {
  513. AP4_UI16 size = (ptr[0] << 8) | ptr[1];
  514. if(size <= avail-2)
  515. {
  516. CStringA str;
  517. if(size >= 2 && ptr[2] == 0xfe && ptr[3] == 0xff)
  518. {
  519. CStringW wstr = CStringW((LPCWSTR)&ptr[2], size/2);
  520. for(int i = 0; i < wstr.GetLength(); i++) wstr.SetAt(i, ((WORD)wstr[i] >> 8) | ((WORD)wstr[i] << 8));
  521. str = UTF16To8(wstr);
  522. }
  523. else
  524. {
  525. str = CStringA((LPCSTR)&ptr[2], size);
  526. }
  527. // TODO: still very incomplete
  528. if(CBaseSplitterOutputPin* pPin = GetOutputPin(p->TrackNumber))
  529. if(pPin->CurrentMediaType().subtype == MEDIASUBTYPE_ASS)
  530. {
  531. CStringW wstr = UTF8To16(str);
  532. AP4_SampleDescription* desc = track->GetSampleDescription(sample.GetDescriptionIndex());
  533. if(AP4_UnknownSampleDescription* unknown_desc = dynamic_cast<AP4_UnknownSampleDescription*>(desc)) // TEMP
  534. {
  535. AP4_SampleEntry* sample_entry = unknown_desc->GetSampleEntry();
  536. if(AP4_TextSampleEntry* text = dynamic_cast<AP4_TextSampleEntry*>(sample_entry))
  537. {
  538. const AP4_TextSampleEntry::AP4_TextDescription& d = text->GetDescription();
  539. }
  540. else if(AP4_Tx3gSampleEntry* tx3g = dynamic_cast<AP4_Tx3gSampleEntry*>(sample_entry))
  541. {
  542. const AP4_Tx3gSampleEntry::AP4_Tx3gDescription& d = tx3g->GetDescription();
  543. int align = 2;
  544. signed char h = (signed char)d.HorizontalJustification;
  545. signed char v = (signed char)d.VerticalJustification;
  546. if(h == 0 && v < 0) align = 1;
  547. else if(h > 0 && v < 0) align = 2;
  548. else if(h < 0 && v < 0) align = 3;
  549. else if(h == 0 && v > 0) align = 4;
  550. else if(h > 0 && v > 0) align = 5;
  551. else if(h < 0 && v > 0) align = 6;
  552. else if(h == 0 && v == 0) align = 7;
  553. else if(h > 0 && v == 0) align = 8;
  554. else if(h < 0 && v == 0) align = 9;
  555. wstr.Format(L"{\an%d}%s", align, CStringW(wstr));
  556. if(d.BackgroundColor)
  557. {
  558. DWORD c = d.BackgroundColor;
  559. wstr.Format(L"{\3c%02x%02x%02x}%s", (c>>8)&0xff, (c>>16)&0xff, (c>>24)&0xff, CStringW(wstr));
  560. if(c&0xff) wstr.Format(L"{\3a%02x}%s", 255 - (c&0xff), CStringW(wstr));
  561. }
  562. if(d.Style.Font.Color)
  563. {
  564. DWORD c = d.Style.Font.Color;
  565. wstr.Format(L"{\1c%02x%02x%02x}%s", (c>>8)&0xff, (c>>16)&0xff, (c>>24)&0xff, CStringW(wstr));
  566. if(c&0xff) wstr.Format(L"{\1a%02x}%s", 255 - (c&0xff), CStringW(wstr));
  567. }
  568. if(d.Style.Font.Size) wstr.Format(L"{\fs%d}%s", d.Style.Font.Size, CStringW(wstr));
  569. if(d.Style.Font.Face&1) wstr = L"{\b1}" + wstr;
  570. if(d.Style.Font.Face&2) wstr = L"{\i1}" + wstr;
  571. if(d.Style.Font.Face&4) wstr = L"{\u1}" + wstr;
  572. }
  573. }
  574. str = "0,0,Default,,0000,0000,0000,," + UTF16To8(wstr);
  575. }
  576. p->pData.SetSize(str.GetLength());
  577. memcpy(p->pData.GetData(), (LPCSTR)str, str.GetLength());
  578. AP4_Sample sample;
  579. if(AP4_SUCCEEDED(track->GetSample(pPairNext->m_value.index+1, sample)))
  580. p->rtStop = (REFERENCE_TIME)(10000000.0 / track->GetMediaTimeScale() * sample.GetCts());
  581. }
  582. }
  583. }
  584. else
  585. {
  586. p->pData.SetSize(data.GetDataSize());
  587. memcpy(p->pData.GetData(), data.GetData(), data.GetDataSize());
  588. }
  589. // FIXME: slow search & stss->m_Entries is private
  590. if(AP4_StssAtom* stss = dynamic_cast<AP4_StssAtom*>(track->GetTrakAtom()->FindChild("mdia/minf/stbl/stss")))
  591. {
  592. if(stss->m_Entries.ItemCount() > 0)
  593. {
  594. p->bSyncPoint = FALSE;
  595. AP4_Cardinal i = -1;
  596. while(++i < stss->m_Entries.ItemCount())
  597. if(stss->m_Entries[i]-1 == pPairNext->m_value.index)
  598. p->bSyncPoint = TRUE;
  599. }
  600. }
  601. hr = DeliverPacket(p);
  602. }
  603. {
  604. AP4_Sample sample;
  605. if(AP4_SUCCEEDED(track->GetSample(++pPairNext->m_value.index, sample)))
  606. pPairNext->m_value.ts = sample.GetCts();
  607. }
  608. }
  609. return true;
  610. }
  611. // IKeyFrameInfo
  612. STDMETHODIMP CMP4SplitterFilter::GetKeyFrameCount(UINT& nKFs)
  613. {
  614. CheckPointer(m_pFile, E_UNEXPECTED);
  615. if(!m_pFile) return E_UNEXPECTED;
  616. AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie();
  617. POSITION pos = m_trackpos.GetStartPosition();
  618. while(pos)
  619. {
  620. CAtlMap<DWORD, trackpos>::CPair* pPair = m_trackpos.GetNext(pos);
  621. AP4_Track* track = movie->GetTrack(pPair->m_key);
  622. if(track->GetType() != AP4_Track::TYPE_VIDEO)
  623. continue;
  624. if(AP4_StssAtom* stss = dynamic_cast<AP4_StssAtom*>(track->GetTrakAtom()->FindChild("mdia/minf/stbl/stss")))
  625. {
  626. nKFs = stss->m_Entries.ItemCount();
  627. return S_OK;
  628. }
  629. }
  630. return E_FAIL;
  631. }
  632. STDMETHODIMP CMP4SplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs)
  633. {
  634. CheckPointer(pFormat, E_POINTER);
  635. CheckPointer(pKFs, E_POINTER);
  636. CheckPointer(m_pFile, E_UNEXPECTED);
  637. if(*pFormat != TIME_FORMAT_MEDIA_TIME) return E_INVALIDARG;
  638. if(!m_pFile) return E_UNEXPECTED;
  639. AP4_Movie* movie = (AP4_Movie*)m_pFile->GetMovie();
  640. POSITION pos = m_trackpos.GetStartPosition();
  641. while(pos)
  642. {
  643. CAtlMap<DWORD, trackpos>::CPair* pPair = m_trackpos.GetNext(pos);
  644. AP4_Track* track = movie->GetTrack(pPair->m_key);
  645. if(track->GetType() != AP4_Track::TYPE_VIDEO)
  646. continue;
  647. if(AP4_StssAtom* stss = dynamic_cast<AP4_StssAtom*>(track->GetTrakAtom()->FindChild("mdia/minf/stbl/stss")))
  648. {
  649. nKFs = 0;
  650. for(AP4_Cardinal i = 0; i < stss->m_Entries.ItemCount(); i++)
  651. {
  652. AP4_Sample sample;
  653. if(AP4_SUCCEEDED(track->GetSample(stss->m_Entries[i]-1, sample)))
  654. pKFs[nKFs++] = 10000000i64 * sample.GetCts() / track->GetMediaTimeScale();
  655. }
  656. return S_OK;
  657. }
  658. }
  659. return E_FAIL;
  660. }
  661. //
  662. // CMP4SourceFilter
  663. //
  664. CMP4SourceFilter::CMP4SourceFilter(LPUNKNOWN pUnk, HRESULT* phr)
  665. : CMP4SplitterFilter(pUnk, phr)
  666. {
  667. m_clsid = __uuidof(this);
  668. m_pInput.Free();
  669. }