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

多媒体编程

开发平台:

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 <mmreg.h>
  23. #include "AviFile.h"
  24. #include "AviReportWnd.h"
  25. #include "AviSplitter.h"
  26. #ifdef REGISTER_FILTER
  27. const AMOVIESETUP_MEDIATYPE sudPinTypesIn[] =
  28. {
  29. {&MEDIATYPE_Stream, &MEDIASUBTYPE_Avi},
  30. {&MEDIATYPE_Stream, &MEDIASUBTYPE_NULL},
  31. };
  32. const AMOVIESETUP_PIN sudpPins[] =
  33. {
  34.     {L"Input", FALSE, FALSE, FALSE, FALSE, &CLSID_NULL, NULL, countof(sudPinTypesIn), sudPinTypesIn},
  35.     {L"Output", FALSE, TRUE, FALSE, FALSE, &CLSID_NULL, NULL, 0, NULL}
  36. };
  37. const AMOVIESETUP_FILTER sudFilter[] =
  38. {
  39. {&__uuidof(CAviSplitterFilter), L"Avi Splitter", MERIT_NORMAL+1, countof(sudpPins), sudpPins},
  40. {&__uuidof(CAviSourceFilter), L"Avi Source", MERIT_NORMAL+1, 0, NULL},
  41. };
  42. CFactoryTemplate g_Templates[] =
  43. {
  44. {sudFilter[0].strName, sudFilter[0].clsID, CreateInstance<CAviSplitterFilter>, NULL, &sudFilter[0]},
  45. {sudFilter[1].strName, sudFilter[1].clsID, CreateInstance<CAviSourceFilter>, NULL, &sudFilter[1]},
  46. };
  47. int g_cTemplates = countof(g_Templates);
  48. STDAPI DllRegisterServer()
  49. {
  50. RegisterSourceFilter(
  51. CLSID_AsyncReader, 
  52. MEDIASUBTYPE_Avi, 
  53. _T("0,4,,52494646,8,4,41564920"), 
  54. _T(".avi"), _T(".divx"), _T(".vp6"), NULL);
  55. return AMovieDllRegisterServer2(TRUE);
  56. }
  57. STDAPI DllUnregisterServer()
  58. {
  59. // UnRegisterSourceFilter(MEDIASUBTYPE_Avi);
  60. return AMovieDllRegisterServer2(FALSE);
  61. }
  62. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
  63. class CAviSplitterApp : public CWinApp
  64. {
  65. public:
  66. CAviSplitterApp() {}
  67. BOOL InitInstance()
  68. {
  69. if(!__super::InitInstance()) return FALSE;
  70. DllEntryPoint(m_hInstance, DLL_PROCESS_ATTACH, 0);
  71. return TRUE;
  72. }
  73. BOOL ExitInstance()
  74. {
  75. DllEntryPoint(m_hInstance, DLL_PROCESS_DETACH, 0);
  76. return __super::ExitInstance();
  77. }
  78. void SetDefaultRegistryKey()
  79. {
  80. SetRegistryKey(_T("Gabest"));
  81. }
  82. DECLARE_MESSAGE_MAP()
  83. };
  84. BEGIN_MESSAGE_MAP(CAviSplitterApp, CWinApp)
  85. END_MESSAGE_MAP()
  86. CAviSplitterApp theApp;
  87. #endif
  88. //
  89. // CAviSplitterFilter
  90. //
  91. CAviSplitterFilter::CAviSplitterFilter(LPUNKNOWN pUnk, HRESULT* phr)
  92. : CBaseSplitterFilter(NAME("CAviSplitterFilter"), pUnk, phr, __uuidof(this))
  93. , m_timeformat(TIME_FORMAT_MEDIA_TIME)
  94. {
  95. }
  96. STDMETHODIMP CAviSplitterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  97. {
  98. CheckPointer(ppv, E_POINTER);
  99. *ppv = NULL;
  100. return 
  101. __super::NonDelegatingQueryInterface(riid, ppv);
  102. }
  103. HRESULT CAviSplitterFilter::CreateOutputs(IAsyncReader* pAsyncReader)
  104. {
  105. CheckPointer(pAsyncReader, E_POINTER);
  106. HRESULT hr = E_FAIL;
  107. m_pFile.Free();
  108. m_tFrame.Free();
  109. m_pFile.Attach(new CAviFile(pAsyncReader, hr));
  110. if(!m_pFile) return E_OUTOFMEMORY;
  111. bool fShiftDown = !!(::GetKeyState(VK_SHIFT)&0x8000);
  112. bool fShowWarningText = !m_pFile->IsInterleaved(fShiftDown);
  113. if(SUCCEEDED(hr) && (fShowWarningText || fShiftDown))
  114. {
  115. #ifdef REGISTER_FILTER
  116. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  117. #endif
  118. bool fHideWarning = !!AfxGetApp()->GetProfileInt(_T("Settings"), _T("HideAviSplitterWarning"), 0);
  119. if(!fHideWarning && !dynamic_cast<CAviSourceFilter*>(this) || fShiftDown)
  120. {
  121. CAviReportWnd wnd;
  122. fHideWarning = wnd.DoModal(m_pFile, fHideWarning, fShowWarningText);
  123. AfxGetApp()->WriteProfileInt(_T("Settings"), _T("HideAviSplitterWarning"), fHideWarning);
  124. }
  125. if(fShowWarningText) hr = E_FAIL;
  126. }
  127. if(FAILED(hr)) {m_pFile.Free(); return hr;}
  128. m_rtNewStart = m_rtCurrent = 0;
  129. m_rtNewStop = m_rtStop = m_rtDuration = m_pFile->GetTotalTime();
  130. bool fHasIndex = false;
  131. for(DWORD i = 0; !fHasIndex && i < m_pFile->m_strms.GetCount(); i++)
  132. if(m_pFile->m_strms[i]->cs.GetCount() > 0) 
  133. fHasIndex = true;
  134. for(DWORD i = 0; i < m_pFile->m_strms.GetCount(); i++)
  135. {
  136. CAviFile::strm_t* s = m_pFile->m_strms[i];
  137. if(fHasIndex && s->cs.GetCount() == 0) continue;
  138. CMediaType mt;
  139. CArray<CMediaType> mts;
  140. CStringW name, label;
  141. if(s->strh.fccType == FCC('vids'))
  142. {
  143. label = L"Video";
  144. ASSERT(s->strf.GetSize() >= sizeof(BITMAPINFOHEADER));
  145. BITMAPINFOHEADER* pbmi = &((BITMAPINFO*)s->strf.GetData())->bmiHeader;
  146. mt.majortype = MEDIATYPE_Video;
  147. mt.subtype = FOURCCMap(pbmi->biCompression);
  148. mt.formattype = FORMAT_VideoInfo;
  149. VIDEOINFOHEADER* pvih = (VIDEOINFOHEADER*)mt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER) + s->strf.GetSize() - sizeof(BITMAPINFOHEADER));
  150. memset(mt.Format(), 0, mt.FormatLength());
  151. memcpy(&pvih->bmiHeader, s->strf.GetData(), s->strf.GetSize());
  152. if(s->strh.dwRate > 0) pvih->AvgTimePerFrame = 10000000i64 * s->strh.dwScale / s->strh.dwRate;
  153. switch(pbmi->biCompression)
  154. {
  155. case BI_RGB: case BI_BITFIELDS: mt.subtype = 
  156. pbmi->biBitCount == 1 ? MEDIASUBTYPE_RGB1 :
  157. pbmi->biBitCount == 4 ? MEDIASUBTYPE_RGB4 :
  158. pbmi->biBitCount == 8 ? MEDIASUBTYPE_RGB8 :
  159. pbmi->biBitCount == 16 ? MEDIASUBTYPE_RGB565 :
  160. pbmi->biBitCount == 24 ? MEDIASUBTYPE_RGB24 :
  161. pbmi->biBitCount == 32 ? MEDIASUBTYPE_ARGB32 :
  162. MEDIASUBTYPE_NULL;
  163. break;
  164. // case BI_RLE8: mt.subtype = MEDIASUBTYPE_RGB8; break;
  165. // case BI_RLE4: mt.subtype = MEDIASUBTYPE_RGB4; break;
  166. }
  167. if(s->cs.GetCount() && pvih->AvgTimePerFrame > 0)
  168. {
  169. __int64 size = 0;
  170. for(int i = 0; i < s->cs.GetCount(); i++)
  171. size += s->cs[i].orgsize;
  172. pvih->dwBitRate = size*8 / s->cs.GetCount() * 10000000i64 / pvih->AvgTimePerFrame;
  173. }
  174. mt.SetSampleSize(s->strh.dwSuggestedBufferSize > 0 
  175. ? s->strh.dwSuggestedBufferSize*3/2
  176. : (pvih->bmiHeader.biWidth*pvih->bmiHeader.biHeight*4));
  177. mts.Add(mt);
  178. }
  179. else if(s->strh.fccType == FCC('auds'))
  180. {
  181. label = L"Audio";
  182. ASSERT(s->strf.GetSize() >= sizeof(WAVEFORMATEX)
  183. || s->strf.GetSize() == sizeof(PCMWAVEFORMAT));
  184.             WAVEFORMATEX* pwfe = (WAVEFORMATEX*)s->strf.GetData();
  185. if(pwfe->nBlockAlign == 0) continue;
  186. mt.majortype = MEDIATYPE_Audio;
  187. mt.subtype = FOURCCMap(pwfe->wFormatTag);
  188. mt.formattype = FORMAT_WaveFormatEx;
  189. mt.SetFormat(s->strf.GetData(), max(s->strf.GetSize(), sizeof(WAVEFORMATEX)));
  190. pwfe = (WAVEFORMATEX*)mt.Format();
  191. if(s->strf.GetSize() == sizeof(PCMWAVEFORMAT)) pwfe->cbSize = 0;
  192. if(pwfe->wFormatTag == WAVE_FORMAT_PCM) pwfe->nBlockAlign = pwfe->nChannels*pwfe->wBitsPerSample>>3;
  193. mt.SetSampleSize(s->strh.dwSuggestedBufferSize > 0 
  194. ? s->strh.dwSuggestedBufferSize*3/2
  195. : (pwfe->nChannels*pwfe->nSamplesPerSec*32>>3));
  196. mts.Add(mt);
  197. }
  198. else if(s->strh.fccType == FCC('mids'))
  199. {
  200. label = L"Midi";
  201. mt.majortype = MEDIATYPE_Midi;
  202. mt.subtype = MEDIASUBTYPE_NULL;
  203. mt.formattype = FORMAT_None;
  204. mt.SetSampleSize(s->strh.dwSuggestedBufferSize > 0 
  205. ? s->strh.dwSuggestedBufferSize*3/2
  206. : (1024*1024));
  207. mts.Add(mt);
  208. }
  209. else if(s->strh.fccType == FCC('txts'))
  210. {
  211. label = L"Text";
  212. mt.majortype = MEDIATYPE_Text;
  213. mt.subtype = MEDIASUBTYPE_NULL;
  214. mt.formattype = FORMAT_None;
  215. mt.SetSampleSize(s->strh.dwSuggestedBufferSize > 0 
  216. ? s->strh.dwSuggestedBufferSize*3/2
  217. : (1024*1024));
  218. mts.Add(mt);
  219. }
  220. else if(s->strh.fccType == FCC('iavs'))
  221. {
  222. label = L"Interleaved";
  223. ASSERT(s->strh.fccHandler == FCC('dvsd'));
  224. mt.majortype = MEDIATYPE_Interleaved;
  225. mt.subtype = FOURCCMap(s->strh.fccHandler);
  226. mt.formattype = FORMAT_DvInfo;
  227. mt.SetFormat(s->strf.GetData(), max(s->strf.GetSize(), sizeof(DVINFO)));
  228. mt.SetSampleSize(s->strh.dwSuggestedBufferSize > 0 
  229. ? s->strh.dwSuggestedBufferSize*3/2
  230. : (1024*1024));
  231. mts.Add(mt);
  232. }
  233. if(mts.IsEmpty())
  234. {
  235. TRACE(_T("CAviSourceFilter: Unsupported stream (%d)n"), i);
  236. continue;
  237. }
  238. name.Format(L"%s %d", !s->strn.IsEmpty() ? CStringW(s->strn) : label, i);
  239. HRESULT hr;
  240. CAutoPtr<CBaseSplitterOutputPin> pPinOut(new CAviSplitterOutputPin(mts, name, this, this, &hr));
  241. AddOutputPin(i, pPinOut);
  242. }
  243. POSITION pos = m_pFile->m_info.GetStartPosition();
  244. while(pos)
  245. {
  246. DWORD fcc;
  247. CStringA value;
  248. m_pFile->m_info.GetNextAssoc(pos, fcc, value);
  249.         switch(fcc)
  250. {
  251. case FCC('INAM'): SetProperty(L"TITL", CStringW(value)); break;
  252. case FCC('IART'): SetProperty(L"AUTH", CStringW(value)); break;
  253. case FCC('ICOP'): SetProperty(L"CPYR", CStringW(value)); break;
  254. case FCC('ISBJ'): SetProperty(L"DESC", CStringW(value)); break;
  255. }
  256. }
  257. m_tFrame.Attach(new DWORD[m_pFile->m_avih.dwStreams]);
  258. return m_pOutputs.GetCount() > 0 ? S_OK : E_FAIL;
  259. }
  260. bool CAviSplitterFilter::DemuxInit()
  261. {
  262. if(!m_pFile) return(false);
  263. // reindex if needed
  264. bool fReIndex = false;
  265. for(int i = 0; i < (int)m_pFile->m_avih.dwStreams && !fReIndex; i++)
  266. {
  267. if(m_pFile->m_strms[i]->cs.GetCount() == 0 && GetOutputPin(i)) 
  268. fReIndex = true;
  269. }
  270. if(fReIndex)
  271. {
  272. m_pFile->EmptyIndex();
  273. m_fAbort = false;
  274. m_nOpenProgress = 0;
  275. m_rtDuration = 0;
  276. CAutoVectorPtr<UINT64> pSize;
  277. pSize.Allocate(m_pFile->m_avih.dwStreams);
  278. memset((UINT64*)pSize, 0, sizeof(UINT64)*m_pFile->m_avih.dwStreams);
  279. m_pFile->Seek(0);
  280.         ReIndex(m_pFile->GetLength(), pSize);
  281. if(m_fAbort) m_pFile->EmptyIndex();
  282. m_fAbort = false;
  283. m_nOpenProgress = 100;
  284. }
  285. return(true);
  286. }
  287. HRESULT CAviSplitterFilter::ReIndex(__int64 end, UINT64* pSize)
  288. {
  289. HRESULT hr = S_OK;
  290. while(S_OK == hr && m_pFile->GetPos() < end && SUCCEEDED(hr) && !m_fAbort)
  291. {
  292. __int64 pos = m_pFile->GetPos();
  293. DWORD id = 0, size;
  294. if(S_OK != m_pFile->Read(id) || id == 0)
  295. return E_FAIL;
  296. if(id == FCC('RIFF') || id == FCC('LIST'))
  297. {
  298. if(S_OK != m_pFile->Read(size) || S_OK != m_pFile->Read(id))
  299. return E_FAIL;
  300. size += (size&1) + 8;
  301. if(id == FCC('AVI ') || id == FCC('AVIX') || id == FCC('movi') || id == FCC('rec '))
  302. hr = ReIndex(pos + size, pSize);
  303. }
  304. else
  305. {
  306. if(S_OK != m_pFile->Read(size))
  307. return E_FAIL;
  308. DWORD TrackNumber = TRACKNUM(id);
  309. if(TrackNumber < m_pFile->m_strms.GetCount())
  310. {
  311. CAviFile::strm_t* s = m_pFile->m_strms[TrackNumber];
  312. WORD type = TRACKTYPE(id);
  313. if(type == 'db' || type == 'dc' || /*type == 'pc' ||*/ type == 'wb'
  314. || type == 'iv' || type == '__' || type == 'xx')
  315. {
  316. CAviFile::strm_t::chunk c;
  317. c.filepos = pos;
  318. c.size = pSize[TrackNumber];
  319. c.orgsize = size;
  320. c.fKeyFrame = size > 0; // TODO: find a better way...
  321. c.fChunkHdr = true;
  322. s->cs.Add(c);
  323. pSize[TrackNumber] += s->GetChunkSize(size);
  324. REFERENCE_TIME rt = s->GetRefTime(s->cs.GetCount()-1, pSize[TrackNumber]);
  325. m_rtDuration = max(rt, m_rtDuration);
  326. }
  327. }
  328. size += (size&1) + 8;
  329. }
  330. m_pFile->Seek(pos + size);
  331. m_nOpenProgress = m_pFile->GetPos()*100/m_pFile->GetLength();
  332. DWORD cmd;
  333. if(CheckRequest(&cmd))
  334. {
  335. if(cmd == CMD_EXIT) m_fAbort = true;
  336. else Reply(S_OK);
  337. }
  338. }
  339. return hr;
  340. }
  341. void CAviSplitterFilter::DemuxSeek(REFERENCE_TIME rt)
  342. {
  343. memset((DWORD*)m_tFrame, 0, sizeof(DWORD)*m_pFile->m_avih.dwStreams);
  344. m_pFile->Seek(0);
  345. DbgLog((LOG_TRACE, 0, _T("Seek: %I64d"), rt/10000));
  346. if(rt > 0)
  347. {
  348. UINT64 minfp = _I64_MAX;
  349. for(int j = 0; j < (int)m_pFile->m_strms.GetCount(); j++)
  350. {
  351. CAviFile::strm_t* s = m_pFile->m_strms[j];
  352. int f = s->GetKeyFrame(rt);
  353. UINT64 fp = f >= 0 ? s->cs[f].filepos : m_pFile->GetLength();
  354. if(!s->IsRawSubtitleStream())
  355. minfp = min(minfp, fp);
  356. }
  357. for(int j = 0; j < (int)m_pFile->m_strms.GetCount(); j++)
  358. {
  359. CAviFile::strm_t* s = m_pFile->m_strms[j];
  360. for(int i = 0; i < s->cs.GetCount(); i++)
  361. {
  362. CAviFile::strm_t::chunk& c = s->cs[i];
  363. if(c.filepos >= minfp)
  364. {
  365. m_tFrame[j] = i;
  366. break;
  367. }
  368. }
  369. }
  370. DbgLog((LOG_TRACE, 0, _T("minfp: %I64d"), minfp));
  371. }
  372. }
  373. bool CAviSplitterFilter::DemuxLoop()
  374. {
  375. HRESULT hr = S_OK;
  376. int nTracks = (int)m_pFile->m_strms.GetCount();
  377. CArray<BOOL> fDiscontinuity;
  378. fDiscontinuity.SetSize(nTracks);
  379. memset(fDiscontinuity.GetData(), 0, nTracks*sizeof(bool));
  380. while(SUCCEEDED(hr) && !CheckRequest(NULL))
  381. {
  382. int minTrack = nTracks;
  383. UINT64 minFilePos = _I64_MAX;
  384. for(int i = 0; i < nTracks; i++)
  385. {
  386. CAviFile::strm_t* s = m_pFile->m_strms[i];
  387. DWORD f = m_tFrame[i];
  388. if(f >= (DWORD)s->cs.GetCount()) continue;
  389. bool fUrgent = s->IsRawSubtitleStream();
  390. if(fUrgent || s->cs[f].filepos < minFilePos)
  391. {
  392. minTrack = i;
  393. minFilePos = s->cs[f].filepos;
  394. }
  395. if(fUrgent) break;
  396. }
  397. if(minTrack == nTracks)
  398. break;
  399. DWORD& f = m_tFrame[minTrack];
  400. do
  401. {
  402. CAviFile::strm_t* s = m_pFile->m_strms[minTrack];
  403. m_pFile->Seek(s->cs[f].filepos);
  404. DWORD size = 0;
  405. if(s->cs[f].fChunkHdr)
  406. {
  407. DWORD id = 0;
  408. if(S_OK != m_pFile->Read(id) || id == 0 || minTrack != TRACKNUM(id)
  409. || S_OK != m_pFile->Read(size))
  410. {
  411. fDiscontinuity[minTrack] = true;
  412. break;
  413. }
  414. UINT64 expectedsize = -1;
  415. expectedsize = f < (DWORD)s->cs.GetCount()-1
  416. ? s->cs[f+1].size - s->cs[f].size
  417. : s->totalsize - s->cs[f].size;
  418. if(expectedsize != s->GetChunkSize(size))
  419. {
  420. fDiscontinuity[minTrack] = true;
  421. // ASSERT(0);
  422. break;
  423. }
  424. }
  425. else
  426. {
  427. size = s->cs[f].orgsize;
  428. }
  429. CAutoPtr<Packet> p(new Packet());
  430. p->TrackNumber = minTrack;
  431. p->bSyncPoint = (BOOL)s->cs[f].fKeyFrame;
  432. p->bDiscontinuity = fDiscontinuity[minTrack];
  433. p->rtStart = s->GetRefTime(f, s->cs[f].size);
  434. p->rtStop = s->GetRefTime(f+1, f+1 < (DWORD)s->cs.GetCount() ? s->cs[f+1].size : s->totalsize);
  435. p->pData.SetSize(size);
  436. if(S_OK != (hr = m_pFile->Read(p->pData.GetData(), p->pData.GetSize()))) 
  437. return(true); // break;
  438. /*
  439. DbgLog((LOG_TRACE, 0, _T("%d (%d): %I64d - %I64d, %I64d - %I64d (size = %d)"), 
  440. minTrack, (int)p->bSyncPoint,
  441. (p->rtStart)/10000, (p->rtStop)/10000, 
  442. (p->rtStart-m_rtStart)/10000, (p->rtStop-m_rtStart)/10000,
  443. size));
  444. */
  445. hr = DeliverPacket(p);
  446. fDiscontinuity[minTrack] = false;
  447. }
  448. while(0);
  449. f++;
  450. }
  451. return(true);
  452. }
  453. // IMediaSeeking
  454. STDMETHODIMP CAviSplitterFilter::GetDuration(LONGLONG* pDuration)
  455. {
  456. CheckPointer(pDuration, E_POINTER);
  457. CheckPointer(m_pFile, VFW_E_NOT_CONNECTED);
  458. if(m_timeformat == TIME_FORMAT_FRAME)
  459. {
  460. for(int i = 0; i < (int)m_pFile->m_strms.GetCount(); i++)
  461. {
  462. CAviFile::strm_t* s = m_pFile->m_strms[i];
  463. if(s->strh.fccType == FCC('vids'))
  464. {
  465. *pDuration = s->cs.GetCount();
  466. return S_OK;
  467. }
  468. }
  469. return E_UNEXPECTED;
  470. }
  471. return __super::GetDuration(pDuration);
  472. }
  473. //
  474. STDMETHODIMP CAviSplitterFilter::IsFormatSupported(const GUID* pFormat)
  475. {
  476. CheckPointer(pFormat, E_POINTER);
  477. HRESULT hr = __super::IsFormatSupported(pFormat);
  478. if(S_OK == hr) return hr;
  479. return *pFormat == TIME_FORMAT_FRAME ? S_OK : S_FALSE;
  480. }
  481. STDMETHODIMP CAviSplitterFilter::GetTimeFormat(GUID* pFormat)
  482. {
  483. CheckPointer(pFormat, E_POINTER);
  484. *pFormat = m_timeformat;
  485. return S_OK;
  486. }
  487. STDMETHODIMP CAviSplitterFilter::IsUsingTimeFormat(const GUID* pFormat)
  488. {
  489. CheckPointer(pFormat, E_POINTER);
  490. return *pFormat == m_timeformat ? S_OK : S_FALSE;
  491. }
  492. STDMETHODIMP CAviSplitterFilter::SetTimeFormat(const GUID* pFormat)
  493. {
  494. CheckPointer(pFormat, E_POINTER);
  495. if(S_OK != IsFormatSupported(pFormat)) return E_FAIL;
  496. m_timeformat = *pFormat;
  497. return S_OK;
  498. }
  499. STDMETHODIMP CAviSplitterFilter::GetStopPosition(LONGLONG* pStop)
  500. {
  501. CheckPointer(pStop, E_POINTER);
  502. if(FAILED(__super::GetStopPosition(pStop))) return E_FAIL;
  503. if(m_timeformat == TIME_FORMAT_MEDIA_TIME) return S_OK;
  504. LONGLONG rt = *pStop;
  505. if(FAILED(ConvertTimeFormat(pStop, &TIME_FORMAT_FRAME, rt, &TIME_FORMAT_MEDIA_TIME))) return E_FAIL;
  506. return S_OK;
  507. }
  508. STDMETHODIMP CAviSplitterFilter::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat)
  509. {
  510. CheckPointer(pTarget, E_POINTER);
  511. const GUID& SourceFormat = pSourceFormat ? *pSourceFormat : m_timeformat;
  512. const GUID& TargetFormat = pTargetFormat ? *pTargetFormat : m_timeformat;
  513. if(TargetFormat == SourceFormat)
  514. {
  515. *pTarget = Source; 
  516. return S_OK;
  517. }
  518. else if(TargetFormat == TIME_FORMAT_FRAME && SourceFormat == TIME_FORMAT_MEDIA_TIME)
  519. {
  520. for(int i = 0; i < (int)m_pFile->m_strms.GetCount(); i++)
  521. {
  522. CAviFile::strm_t* s = m_pFile->m_strms[i];
  523. if(s->strh.fccType == FCC('vids'))
  524. {
  525. *pTarget = s->GetFrame(Source);
  526. return S_OK;
  527. }
  528. }
  529. }
  530. else if(TargetFormat == TIME_FORMAT_MEDIA_TIME && SourceFormat == TIME_FORMAT_FRAME)
  531. {
  532. for(int i = 0; i < (int)m_pFile->m_strms.GetCount(); i++)
  533. {
  534. CAviFile::strm_t* s = m_pFile->m_strms[i];
  535. if(s->strh.fccType == FCC('vids'))
  536. {
  537. if(Source < 0 || Source >= s->cs.GetCount()) return E_FAIL;
  538. CAviFile::strm_t::chunk& c = s->cs[(int)Source];
  539. *pTarget = s->GetRefTime((DWORD)Source, c.size);
  540. return S_OK;
  541. }
  542. }
  543. }
  544. return E_FAIL;
  545. }
  546. STDMETHODIMP CAviSplitterFilter::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop)
  547. {
  548. HRESULT hr;
  549. if(FAILED(hr = __super::GetPositions(pCurrent, pStop)) || m_timeformat != TIME_FORMAT_FRAME)
  550. return hr;
  551. if(pCurrent)
  552. if(FAILED(ConvertTimeFormat(pCurrent, &TIME_FORMAT_FRAME, *pCurrent, &TIME_FORMAT_MEDIA_TIME))) return E_FAIL;
  553. if(pStop)
  554. if(FAILED(ConvertTimeFormat(pStop, &TIME_FORMAT_FRAME, *pStop, &TIME_FORMAT_MEDIA_TIME))) return E_FAIL;
  555. return S_OK;
  556. }
  557. HRESULT CAviSplitterFilter::SetPositionsInternal(void* id, LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
  558. {
  559. if(m_timeformat != TIME_FORMAT_FRAME)
  560. return __super::SetPositionsInternal(id, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
  561. if(!pCurrent && !pStop
  562. || (dwCurrentFlags&AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning 
  563. && (dwStopFlags&AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
  564. return S_OK;
  565. REFERENCE_TIME 
  566. rtCurrent = m_rtCurrent,
  567. rtStop = m_rtStop;
  568. if((dwCurrentFlags&AM_SEEKING_PositioningBitsMask)
  569. && FAILED(ConvertTimeFormat(&rtCurrent, &TIME_FORMAT_FRAME, rtCurrent, &TIME_FORMAT_MEDIA_TIME))) 
  570. return E_FAIL;
  571. if((dwStopFlags&AM_SEEKING_PositioningBitsMask)
  572. && FAILED(ConvertTimeFormat(&rtStop, &TIME_FORMAT_FRAME, rtStop, &TIME_FORMAT_MEDIA_TIME)))
  573. return E_FAIL;
  574. if(pCurrent)
  575. switch(dwCurrentFlags&AM_SEEKING_PositioningBitsMask)
  576. {
  577. case AM_SEEKING_NoPositioning: break;
  578. case AM_SEEKING_AbsolutePositioning: rtCurrent = *pCurrent; break;
  579. case AM_SEEKING_RelativePositioning: rtCurrent = rtCurrent + *pCurrent; break;
  580. case AM_SEEKING_IncrementalPositioning: rtCurrent = rtCurrent + *pCurrent; break;
  581. }
  582. if(pStop)
  583. switch(dwStopFlags&AM_SEEKING_PositioningBitsMask)
  584. {
  585. case AM_SEEKING_NoPositioning: break;
  586. case AM_SEEKING_AbsolutePositioning: rtStop = *pStop; break;
  587. case AM_SEEKING_RelativePositioning: rtStop += *pStop; break;
  588. case AM_SEEKING_IncrementalPositioning: rtStop = rtCurrent + *pStop; break;
  589. }
  590. if((dwCurrentFlags&AM_SEEKING_PositioningBitsMask)
  591. && pCurrent)
  592. if(FAILED(ConvertTimeFormat(pCurrent, &TIME_FORMAT_MEDIA_TIME, rtCurrent, &TIME_FORMAT_FRAME))) return E_FAIL;
  593. if((dwStopFlags&AM_SEEKING_PositioningBitsMask)
  594. && pStop)
  595. if(FAILED(ConvertTimeFormat(pStop, &TIME_FORMAT_MEDIA_TIME, rtStop, &TIME_FORMAT_FRAME))) return E_FAIL;
  596. return __super::SetPositionsInternal(id, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
  597. }
  598. // IKeyFrameInfo
  599. STDMETHODIMP CAviSplitterFilter::GetKeyFrameCount(UINT& nKFs)
  600. {
  601. if(!m_pFile) return E_UNEXPECTED;
  602. HRESULT hr = S_OK;
  603. nKFs = 0;
  604. for(int i = 0; i < (int)m_pFile->m_strms.GetCount(); i++)
  605. {
  606. CAviFile::strm_t* s = m_pFile->m_strms[i];
  607. if(s->strh.fccType != FCC('vids')) continue;
  608. for(int j = 0; j < s->cs.GetCount(); j++)
  609. {
  610. CAviFile::strm_t::chunk& c = s->cs[j];
  611. if(c.fKeyFrame) nKFs++;
  612. }
  613. if(nKFs == s->cs.GetCount())
  614. hr = S_FALSE;
  615. break;
  616. }
  617. return hr;
  618. }
  619. STDMETHODIMP CAviSplitterFilter::GetKeyFrames(const GUID* pFormat, REFERENCE_TIME* pKFs, UINT& nKFs)
  620. {
  621. CheckPointer(pFormat, E_POINTER);
  622. CheckPointer(pKFs, E_POINTER);
  623. if(!m_pFile) return E_UNEXPECTED;
  624. if(*pFormat != TIME_FORMAT_MEDIA_TIME && *pFormat != TIME_FORMAT_FRAME) return E_INVALIDARG;
  625. UINT nKFsTmp = 0;
  626. for(int i = 0; i < (int)m_pFile->m_strms.GetCount(); i++)
  627. {
  628. CAviFile::strm_t* s = m_pFile->m_strms[i];
  629. if(s->strh.fccType != FCC('vids')) continue;
  630. bool fConvertToRefTime = !!(*pFormat == TIME_FORMAT_MEDIA_TIME);
  631. for(int j = 0; j < s->cs.GetCount() && nKFsTmp < nKFs; j++)
  632. {
  633. if(s->cs[j].fKeyFrame)
  634. pKFs[nKFsTmp++] = fConvertToRefTime ? s->GetRefTime(j, s->cs[j].size) : j;
  635. }
  636. break;
  637. }
  638. nKFs = nKFsTmp;
  639. return S_OK;
  640. }
  641. //
  642. // CAviSourceFilter
  643. //
  644. CAviSourceFilter::CAviSourceFilter(LPUNKNOWN pUnk, HRESULT* phr)
  645. : CAviSplitterFilter(pUnk, phr)
  646. {
  647. m_clsid = __uuidof(this);
  648. m_pInput.Free();
  649. }
  650. //
  651. // CAviSplitterOutputPin
  652. //
  653. CAviSplitterOutputPin::CAviSplitterOutputPin(CArray<CMediaType>& mts, LPCWSTR pName, CBaseFilter* pFilter, CCritSec* pLock, HRESULT* phr)
  654. : CBaseSplitterOutputPin(mts, pName, pFilter, pLock, phr)
  655. {
  656. }
  657. HRESULT CAviSplitterOutputPin::CheckConnect(IPin* pPin)
  658. {
  659. int iPosition = 0;
  660. CMediaType mt;
  661. while(S_OK == GetMediaType(iPosition++, &mt))
  662. {
  663. if(mt.majortype == MEDIATYPE_Video 
  664. && (mt.subtype == FOURCCMap(FCC('IV32'))
  665. || mt.subtype == FOURCCMap(FCC('IV31'))
  666. || mt.subtype == FOURCCMap(FCC('IF09'))))
  667. {
  668. CLSID clsid = GetCLSID(GetFilterFromPin(pPin));
  669. if(clsid == CLSID_VideoMixingRenderer || clsid == CLSID_OverlayMixer)
  670. return E_FAIL;
  671. }
  672. mt.InitMediaType();
  673. }
  674. return __super::CheckConnect(pPin);
  675. }