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

多媒体编程

开发平台:

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 <math.h>
  23. #include <time.h>
  24. #include "DirectVobSubFilter.h"
  25. #include "TextInputPin.h"
  26. #include "DirectVobSubPropPage.h"
  27. #include "VSFilter.h"
  28. #include "systray.h"
  29. #include "......DSUtilMediaTypes.h"
  30. #include "......SubPicMemSubPic.h"
  31. #include <initguid.h>
  32. #include "........includemoreuuids.h"
  33. #include "........includeOggOggDS.h"
  34. ///////////////////////////////////////////////////////////////////////////
  35. /*removeme*/
  36. bool g_RegOK = true;//false; // doesn't work with the dvd graph builder
  37. #include "valami.cpp"
  38. ////////////////////////////////////////////////////////////////////////////
  39. //
  40. // Constructor
  41. //
  42. CDirectVobSubFilter::CDirectVobSubFilter(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid)
  43. : CBaseVideoFilter(NAME("CDirectVobSubFilter"), punk, phr, clsid)
  44. , m_nSubtitleId(-1)
  45. , m_fMSMpeg4Fix(false)
  46. , m_fDivxPlusFix(false)
  47. , m_fps(25)
  48. {
  49. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  50. m_hdc = 0;
  51. m_hbm = 0;
  52. m_hfont = 0;
  53. {
  54. LOGFONT lf;
  55. memset(&lf, 0, sizeof(lf));
  56. lf.lfCharSet = DEFAULT_CHARSET;
  57. lf.lfOutPrecision = OUT_CHARACTER_PRECIS;
  58. lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  59. lf.lfQuality = ANTIALIASED_QUALITY;
  60. HDC hdc = GetDC(NULL);
  61. lf.lfHeight = -MulDiv(10, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  62. ReleaseDC(NULL, hdc);
  63. lf.lfWeight = FW_BOLD;
  64. _tcscpy(lf.lfFaceName, _T("Arial"));
  65. m_hfont = CreateFontIndirect(&lf);
  66. }
  67. theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Hint"), _T("The first three are fixed, but you can add more up to ten entries."));
  68. theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path0"), _T("."));
  69. theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path1"), _T("c:\subtitles"));
  70. theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path2"), _T(".\subtitles"));
  71. m_fLoading = true;
  72. m_hSystrayThread = 0;
  73. m_tbid.hSystrayWnd = NULL;
  74. m_tbid.graph = NULL;
  75. m_tbid.fRunOnce = false;
  76. m_tbid.fShowIcon = (theApp.m_AppName.Find(_T("zplayer"), 0) < 0 || !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_ENABLEZPICON), 0));
  77. HRESULT hr = S_OK;
  78. m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
  79. ASSERT(SUCCEEDED(hr));
  80. CAMThread::Create();
  81. m_frd.EndThreadEvent.Create(0, FALSE, FALSE, 0);
  82. m_frd.RefreshEvent.Create(0, FALSE, FALSE, 0);
  83. }
  84. CDirectVobSubFilter::~CDirectVobSubFilter()
  85. {
  86. CAutoLock cAutoLock(&m_csQueueLock);
  87. if(m_pSubPicQueue) m_pSubPicQueue->Invalidate();
  88. m_pSubPicQueue = NULL;
  89. if(m_hfont) {DeleteObject(m_hfont); m_hfont = 0;}
  90. if(m_hbm) {DeleteObject(m_hbm); m_hbm = 0;}
  91. if(m_hdc) {DeleteObject(m_hdc); m_hdc = 0;}
  92. for(int i = 0; i < m_pTextInput.GetSize(); i++) 
  93. delete m_pTextInput[i];
  94. m_frd.EndThreadEvent.Set();
  95. CAMThread::Close();
  96. }
  97. STDMETHODIMP CDirectVobSubFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  98. {
  99.     CheckPointer(ppv, E_POINTER);
  100.     return 
  101. QI(IDirectVobSub)
  102. QI(IDirectVobSub2)
  103. QI(IFilterVersion)
  104. QI(ISpecifyPropertyPages)
  105. QI(IAMStreamSelect)
  106. __super::NonDelegatingQueryInterface(riid, ppv);
  107. }
  108. // CBaseVideoFilter
  109. void CDirectVobSubFilter::GetOutputSize(int& w, int& h, int& arx, int& ary)
  110. {
  111. CSize s(w, h), os = s;
  112. AdjustFrameSize(s);
  113. w = s.cx;
  114. h = s.cy;
  115. if(w != os.cx)
  116. {
  117. while(arx < 100) arx *= 10, ary *= 10;
  118. arx = arx * w / os.cx;
  119. }
  120. if(h != os.cy)
  121. {
  122. while(ary < 100) arx *= 10, ary *= 10;
  123. ary = ary * h / os.cy;
  124. }
  125. }
  126. HRESULT CDirectVobSubFilter::Transform(IMediaSample* pIn)
  127. {
  128. HRESULT hr;
  129. REFERENCE_TIME rtStart, rtStop;
  130. if(SUCCEEDED(pIn->GetTime(&rtStart, &rtStop)))
  131. {
  132. double dRate = m_pInput->CurrentRate();
  133. m_tPrev = m_pInput->CurrentStartTime() + dRate*rtStart;
  134. REFERENCE_TIME rtAvgTimePerFrame = rtStop - rtStart;
  135. if(CComQIPtr<ISubClock2> pSC2 = m_pSubClock)
  136. {
  137. REFERENCE_TIME rt;
  138.  if(S_OK == pSC2->GetAvgTimePerFrame(&rt))
  139.  rtAvgTimePerFrame = rt;
  140. }
  141. m_fps = 10000000.0/rtAvgTimePerFrame / dRate;
  142. }
  143. //
  144. {
  145. CAutoLock cAutoLock(&m_csQueueLock);
  146. if(m_pSubPicQueue)
  147. {
  148. m_pSubPicQueue->SetTime(CalcCurrentTime());
  149. m_pSubPicQueue->SetFPS(m_fps);
  150. }
  151. }
  152. //
  153. BYTE* pDataIn = NULL;
  154. if(FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn)
  155. return S_FALSE;
  156. const CMediaType& mt = m_pInput->CurrentMediaType();
  157. BITMAPINFOHEADER bihIn;
  158. ExtractBIH(&mt, &bihIn);
  159. bool fYV12 = (mt.subtype == MEDIASUBTYPE_YV12 || mt.subtype == MEDIASUBTYPE_I420 || mt.subtype == MEDIASUBTYPE_IYUV);
  160. int bpp = fYV12 ? 8 : bihIn.biBitCount;
  161. DWORD black = fYV12 ? 0x10101010 : (bihIn.biCompression == '2YUY') ? 0x80108010 : 0;
  162. CSize sub(m_w, m_h);
  163. CSize in(bihIn.biWidth, bihIn.biHeight);
  164. if(FAILED(Copy((BYTE*)m_pTempPicBuff, pDataIn, sub, in, bpp, mt.subtype, black))) 
  165. return E_FAIL;
  166. if(fYV12)
  167. {
  168. BYTE* pSubV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
  169. BYTE* pInV = pDataIn + (in.cx*bpp>>3)*in.cy;
  170. sub.cx >>= 1; sub.cy >>= 1; in.cx >>= 1; in.cy >>= 1;
  171. BYTE* pSubU = pSubV + (sub.cx*bpp>>3)*sub.cy;
  172. BYTE* pInU = pInV + (in.cx*bpp>>3)*in.cy;
  173. if(FAILED(Copy(pSubV, pInV, sub, in, bpp, mt.subtype, 0x80808080)))
  174. return E_FAIL;
  175. if(FAILED(Copy(pSubU, pInU, sub, in, bpp, mt.subtype, 0x80808080)))
  176. return E_FAIL;
  177. }
  178. //
  179. SubPicDesc spd = m_spd;
  180. CComPtr<IMediaSample> pOut;
  181. BYTE* pDataOut = NULL;
  182. if(FAILED(hr = GetDeliveryBuffer(spd.w, spd.h, &pOut))
  183. || FAILED(hr = pOut->GetPointer(&pDataOut)))
  184. return hr;
  185. pOut->SetTime(&rtStart, &rtStop);
  186. pOut->SetMediaTime(NULL, NULL);
  187. // 
  188. BITMAPINFOHEADER bihOut;
  189. ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
  190. bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3;
  191. bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3;
  192. bool fFlip = fInputFlipped != fOutputFlipped;
  193. if(m_fFlipPicture) fFlip = !fFlip;
  194. if(m_fMSMpeg4Fix) fFlip = !fFlip;
  195. // if(m_fDivxPlusFix) fFlip = !fFlip;
  196. bool fFlipSub = fOutputFlipped;
  197. if(m_fFlipSubtitles) fFlipSub = !fFlipSub;
  198. // if(m_fDivxPlusFix) fFlipSub = !fFlipSub;
  199. //
  200. {
  201. CAutoLock cAutoLock(&m_csQueueLock);
  202. if(m_pSubPicQueue)
  203. {
  204. CComPtr<ISubPic> pSubPic;
  205. if(SUCCEEDED(m_pSubPicQueue->LookupSubPic(CalcCurrentTime(), &pSubPic)) && pSubPic)
  206. {
  207. CRect r;
  208. pSubPic->GetDirtyRect(r);
  209. if(fFlip ^ fFlipSub)
  210. spd.h = -spd.h;
  211. pSubPic->AlphaBlt(r, r, &spd);
  212. }
  213. }
  214. }
  215. CopyBuffer(pDataOut, (BYTE*)spd.bits, spd.w, abs(spd.h)*(fFlip?-1:1), spd.pitch, mt.subtype);
  216. PrintMessages(pDataOut);
  217. return m_pOutput->Deliver(pOut);
  218. }
  219. // CBaseFilter
  220. CBasePin* CDirectVobSubFilter::GetPin(int n)
  221. {
  222. if(n < __super::GetPinCount())
  223. return __super::GetPin(n);
  224. n -= __super::GetPinCount();
  225. if(n >= 0 && n < m_pTextInput.GetSize())
  226. return m_pTextInput[n]; 
  227. n -= m_pTextInput.GetSize();
  228. return NULL;
  229. }
  230. int CDirectVobSubFilter::GetPinCount()
  231. {
  232. return __super::GetPinCount() + m_pTextInput.GetSize();
  233. }
  234. HRESULT CDirectVobSubFilter::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
  235. {
  236. if(pGraph)
  237. {
  238. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  239. if(!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 0))
  240. {
  241. unsigned __int64 ver = GetFileVersion(_T("divx_c32.ax"));
  242. if(((ver >> 48)&0xffff) == 4 && ((ver >> 32)&0xffff) == 2)
  243. {
  244. DWORD dwVersion = GetVersion();
  245. DWORD dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
  246. DWORD dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
  247. if(dwVersion < 0x80000000 && dwWindowsMajorVersion >= 5)
  248. {
  249. AfxMessageBox(IDS_DIVX_WARNING);
  250. theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 1);
  251. }
  252. }
  253. }
  254. /*removeme*/
  255. if(!g_RegOK)
  256. {
  257. DllRegisterServer();
  258. g_RegOK = true;
  259. }
  260. }
  261. else
  262. {
  263. if(m_hSystrayThread)
  264. {
  265. SendMessage(m_tbid.hSystrayWnd, WM_CLOSE, 0, 0);
  266. if(WaitForSingleObject(m_hSystrayThread, 10000) != WAIT_OBJECT_0)
  267. {
  268. DbgLog((LOG_TRACE, 0, _T("CALL THE AMBULANCE!!!")));
  269. TerminateThread(m_hSystrayThread, (DWORD)-1);
  270. }
  271. m_hSystrayThread = 0;
  272. }
  273. }
  274. return __super::JoinFilterGraph(pGraph, pName);
  275. }
  276. STDMETHODIMP CDirectVobSubFilter::QueryFilterInfo(FILTER_INFO* pInfo)
  277. {
  278.     CheckPointer(pInfo, E_POINTER);
  279.     ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO));
  280. if(!get_Forced())
  281. return __super::QueryFilterInfo(pInfo);
  282. wcscpy(pInfo->achName, L"DirectVobSub (forced auto-loading version)");
  283. if(pInfo->pGraph = m_pGraph) m_pGraph->AddRef();
  284. return S_OK;
  285. }
  286. // CTransformFilter
  287. HRESULT CDirectVobSubFilter::SetMediaType(PIN_DIRECTION dir, const CMediaType* pmt)
  288. {
  289. HRESULT hr = __super::SetMediaType(dir, pmt);
  290. if(FAILED(hr)) return hr;
  291. if(dir == PINDIR_INPUT)
  292. {
  293. CAutoLock cAutoLock(&m_csReceive);
  294. REFERENCE_TIME atpf = 
  295. pmt->formattype == FORMAT_VideoInfo ? ((VIDEOINFOHEADER*)pmt->Format())->AvgTimePerFrame :
  296. pmt->formattype == FORMAT_VideoInfo2 ? ((VIDEOINFOHEADER2*)pmt->Format())->AvgTimePerFrame :
  297. 0;
  298. m_fps = atpf ? 10000000.0 / atpf : 25;
  299.         InitSubPicQueue();
  300. }
  301. else if(dir == PINDIR_OUTPUT)
  302. {
  303. }
  304. return hr;
  305. }
  306. HRESULT CDirectVobSubFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
  307. {
  308. if(dir == PINDIR_INPUT)
  309. {
  310. }
  311. else if(dir == PINDIR_OUTPUT)
  312. {
  313. /*removeme*/
  314. if(HmGyanusVagyTeNekem(pPin)) return(E_FAIL);
  315. }
  316. return __super::CheckConnect(dir, pPin);
  317. }
  318. HRESULT CDirectVobSubFilter::CompleteConnect(PIN_DIRECTION dir, IPin* pReceivePin)
  319. {
  320. if(dir == PINDIR_INPUT)
  321. {
  322. CComPtr<IBaseFilter> pFilter;
  323. // needed when we have a decoder with a version number of 3.x
  324. if(SUCCEEDED(m_pGraph->FindFilterByName(L"DivX MPEG-4 DVD Video Decompressor ", &pFilter))
  325. && (GetFileVersion(_T("divx_c32.ax")) >> 48) <= 4
  326. || SUCCEEDED(m_pGraph->FindFilterByName(L"Microcrap MPEG-4 Video Decompressor", &pFilter))
  327. || SUCCEEDED(m_pGraph->FindFilterByName(L"Microsoft MPEG-4 Video Decompressor", &pFilter)) 
  328. && (GetFileVersion(_T("mpg4ds32.ax")) >> 48) <= 3)
  329. {
  330. m_fMSMpeg4Fix = true;
  331. }
  332. }
  333. else if(dir == PINDIR_OUTPUT)
  334. {
  335. if(!m_hSystrayThread)
  336. {
  337. m_tbid.graph = m_pGraph;
  338. m_tbid.dvs = static_cast<IDirectVobSub*>(this);
  339. DWORD tid;
  340. m_hSystrayThread = CreateThread(0, 0, SystrayThreadProc, &m_tbid, 0, &tid);
  341. }
  342. // HACK: triggers CBaseVideoFilter::SetMediaType to adjust m_w/m_h/.. and InitSubPicQueue() to realloc buffers
  343. m_pInput->SetMediaType(&m_pInput->CurrentMediaType());
  344. }
  345. return __super::CompleteConnect(dir, pReceivePin);
  346. }
  347. HRESULT CDirectVobSubFilter::BreakConnect(PIN_DIRECTION dir)
  348. {
  349. if(dir == PINDIR_INPUT)
  350. {
  351. if(m_pOutput->IsConnected())
  352. {
  353. m_pOutput->GetConnected()->Disconnect();
  354. m_pOutput->Disconnect();
  355. }
  356. }
  357. else if(dir == PINDIR_OUTPUT)
  358. {
  359. // not really needed, but may free up a little memory
  360. CAutoLock cAutoLock(&m_csQueueLock);
  361. m_pSubPicQueue = NULL;
  362. }
  363. return __super::BreakConnect(dir);
  364. }
  365. HRESULT CDirectVobSubFilter::StartStreaming()
  366. {
  367. m_fLoading = false;
  368. InitSubPicQueue();
  369. m_tbid.fRunOnce = true;
  370. CComPtr<IBaseFilter> pFilter;
  371. m_fDivxPlusFix = SUCCEEDED(m_pGraph->FindFilterByName(L"HPlus YUV Video Renderer", &pFilter));
  372. put_MediaFPS(m_fMediaFPSEnabled, m_MediaFPS);
  373. return __super::StartStreaming();
  374. }
  375. HRESULT CDirectVobSubFilter::StopStreaming()
  376. {
  377. InvalidateSubtitle();
  378. return __super::StopStreaming();
  379. }
  380. HRESULT CDirectVobSubFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
  381. {
  382. m_tPrev = tStart;
  383.     return __super::NewSegment(tStart, tStop, dRate);
  384. }
  385. //
  386. REFERENCE_TIME CDirectVobSubFilter::CalcCurrentTime()
  387. {
  388. REFERENCE_TIME rt = m_pSubClock ? m_pSubClock->GetTime() : m_tPrev;
  389. return (rt - 10000i64*m_SubtitleDelay) * m_SubtitleSpeedMul / m_SubtitleSpeedDiv; // no, it won't overflow if we use normal parameters (__int64 is enough for about 2000 hours if we multiply it by the max: 65536 as m_SubtitleSpeedMul)
  390. }
  391. void CDirectVobSubFilter::InitSubPicQueue()
  392. {
  393. CAutoLock cAutoLock(&m_csQueueLock);
  394. m_pSubPicQueue = NULL;
  395. m_pTempPicBuff.Free();
  396. m_pTempPicBuff.Allocate(4*m_w*m_h);
  397. const GUID& subtype = m_pInput->CurrentMediaType().subtype;
  398. BITMAPINFOHEADER bihIn;
  399. ExtractBIH(&m_pInput->CurrentMediaType(), &bihIn);
  400. m_spd.type = -1;
  401. if(subtype == MEDIASUBTYPE_YV12) m_spd.type = MSP_YV12;
  402. else if(subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV) m_spd.type = MSP_IYUV;
  403. else if(subtype == MEDIASUBTYPE_YUY2) m_spd.type = MSP_YUY2;
  404. else if(subtype == MEDIASUBTYPE_RGB32) m_spd.type = MSP_RGB32;
  405. else if(subtype == MEDIASUBTYPE_RGB24) m_spd.type = MSP_RGB24;
  406. else if(subtype == MEDIASUBTYPE_RGB565) m_spd.type = MSP_RGB16;
  407. else if(subtype == MEDIASUBTYPE_RGB555) m_spd.type = MSP_RGB15;
  408. m_spd.w = m_w;
  409. m_spd.h = m_h;
  410. m_spd.bpp = (m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV) ? 8 : bihIn.biBitCount;
  411. m_spd.pitch = m_spd.w*m_spd.bpp>>3;
  412. m_spd.bits = (void*)m_pTempPicBuff;
  413. CComPtr<ISubPicAllocator> pSubPicAllocator = new CMemSubPicAllocator(m_spd.type, CSize(m_w, m_h));
  414. CSize video(bihIn.biWidth, bihIn.biHeight);
  415. CSize window(m_w, m_h);
  416. if(AdjustFrameSize(window)) video += video;
  417. pSubPicAllocator->SetCurSize(window);
  418. pSubPicAllocator->SetCurVidRect(CRect(CPoint((window.cx - video.cx)/2, (window.cy - video.cy)/2), video));
  419. HRESULT hr = S_OK;
  420. m_pSubPicQueue = m_fDoPreBuffering 
  421. ? (ISubPicQueue*)new CSubPicQueue(10, pSubPicAllocator, &hr)
  422. : (ISubPicQueue*)new CSubPicQueueNoThread(pSubPicAllocator, &hr);
  423. if(FAILED(hr)) m_pSubPicQueue = NULL;
  424. UpdateSubtitle(false);
  425. if(m_hbm) {DeleteObject(m_hbm); m_hbm = NULL;}
  426. if(m_hdc) {DeleteDC(m_hdc); m_hdc = NULL;}
  427. struct {BITMAPINFOHEADER bih; DWORD mask[3];} b = {{sizeof(BITMAPINFOHEADER), m_w, -(int)m_h, 1, 32, BI_BITFIELDS, 0, 0, 0, 0, 0}, 0xFF0000, 0x00FF00, 0x0000FF};
  428. m_hdc = CreateCompatibleDC(NULL);
  429. m_hbm = CreateDIBSection(m_hdc, (BITMAPINFO*)&b, DIB_RGB_COLORS, NULL, NULL, 0);
  430. BITMAP bm;
  431. GetObject(m_hbm, sizeof(bm), &bm);
  432. memsetd(bm.bmBits, 0xFF000000, bm.bmHeight*bm.bmWidthBytes);
  433. }
  434. bool CDirectVobSubFilter::AdjustFrameSize(CSize& s)
  435. {
  436. int horizontal, vertical, resx2, resx2minw, resx2minh;
  437. get_ExtendPicture(&horizontal, &vertical, &resx2, &resx2minw, &resx2minh);
  438. bool fRet;
  439. if(fRet = (resx2 == 1) || (resx2 == 2 && s.cx*s.cy <= resx2minw*resx2minh))
  440. {
  441. s.cx <<= 1; 
  442. s.cy <<= 1;
  443. }
  444. int h;
  445. switch(vertical&0x7f)
  446. {
  447. case 1:
  448. h = s.cx * 9 / 16;
  449. if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
  450. break;
  451. case 2:
  452. h = s.cx * 3 / 4;
  453. if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
  454. break;
  455. case 3:
  456. h = 480;
  457. if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
  458. break;
  459. case 4:
  460. h = 576;
  461. if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
  462. break;
  463. }
  464. if(horizontal == 1)
  465. {
  466. s.cx = (s.cx + 31) & ~31;
  467. s.cy = (s.cy + 1) & ~1;
  468. }
  469. return(fRet);
  470. }
  471. STDMETHODIMP CDirectVobSubFilter::Count(DWORD* pcStreams)
  472. {
  473. if(!pcStreams) return E_POINTER;
  474. *pcStreams = 0;
  475. int nLangs = 0;
  476. if(SUCCEEDED(get_LanguageCount(&nLangs)))
  477. (*pcStreams) += nLangs;
  478. (*pcStreams) += 2; // enable ... disable
  479. (*pcStreams) += 2; // normal flipped
  480. return S_OK;
  481. }
  482. #define MAXPREFLANGS 5
  483. int CDirectVobSubFilter::FindPreferedLanguage(bool fHideToo)
  484. {
  485. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  486. int nLangs;
  487. get_LanguageCount(&nLangs);
  488. if(nLangs <= 0) return(0);
  489. for(int i = 0; i < MAXPREFLANGS; i++)
  490. {
  491. CString tmp;
  492. tmp.Format(IDS_RL_LANG, i);
  493. CString lang = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
  494. if(!lang.IsEmpty())
  495. {
  496. for(int ret = 0; ret < nLangs; ret++)
  497. {
  498. CString l;
  499. WCHAR* pName = NULL;
  500. get_LanguageName(ret, &pName);
  501. l = pName;
  502. CoTaskMemFree(pName);
  503. if(!l.CompareNoCase(lang)) return(ret);
  504. }
  505. }
  506. }
  507. return(0);
  508. }
  509. void CDirectVobSubFilter::UpdatePreferedLanguages(CString l)
  510. {
  511. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  512. CString langs[MAXPREFLANGS+1];
  513. int i = 0, j = 0, k = -1;
  514. for(; i < MAXPREFLANGS; i++)
  515. {
  516. CString tmp;
  517. tmp.Format(IDS_RL_LANG, i);
  518. langs[j] = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
  519. if(!langs[j].IsEmpty()) 
  520. {
  521. if(!langs[j].CompareNoCase(l)) k = j;
  522. j++;
  523. }
  524. }
  525. if(k == -1)
  526. {
  527. langs[k = j] = l;
  528. j++;
  529. }
  530. // move the selected to the top of the list
  531. while(k > 0)
  532. {
  533. CString tmp = langs[k]; langs[k] = langs[k-1]; langs[k-1] = tmp;
  534. k--;
  535. }
  536. // move "Hide subtitles" to the last position if it wasn't our selection
  537. CString hidesubs;
  538. hidesubs.LoadString(IDS_M_HIDESUBTITLES);
  539. for(k = 1; k < j; k++)
  540. {
  541. if(!langs[k].CompareNoCase(hidesubs)) break;
  542. }
  543. while(k < j-1)
  544. {
  545. CString tmp = langs[k]; langs[k] = langs[k+1]; langs[k+1] = tmp;
  546. k++;
  547. }
  548. for(i = 0; i < j; i++)
  549. {
  550. CString tmp;
  551. tmp.Format(IDS_RL_LANG, i);
  552. theApp.WriteProfileString(ResStr(IDS_R_PREFLANGS), tmp, langs[i]);
  553. }
  554. }
  555. STDMETHODIMP CDirectVobSubFilter::Enable(long lIndex, DWORD dwFlags)
  556. {
  557. if(!(dwFlags & AMSTREAMSELECTENABLE_ENABLE))
  558. return E_NOTIMPL;
  559. int nLangs = 0;
  560. get_LanguageCount(&nLangs);
  561. if(!(lIndex >= 0 && lIndex < nLangs+2+2)) 
  562. return E_INVALIDARG;
  563. int i = lIndex-1;
  564. if(i == -1 && !m_fLoading) // we need this because when loading something stupid media player pushes the first stream it founds, which is "enable" in our case
  565. {
  566. put_HideSubtitles(false);
  567. }
  568. else if(i >= 0 && i < nLangs)
  569. {
  570. put_HideSubtitles(false);
  571. put_SelectedLanguage(i);
  572. WCHAR* pName = NULL;
  573. if(SUCCEEDED(get_LanguageName(i, &pName)))
  574. {
  575. UpdatePreferedLanguages(CString(pName));
  576. if(pName) CoTaskMemFree(pName);
  577. }
  578. }
  579. else if(i == nLangs && !m_fLoading)
  580. {
  581. put_HideSubtitles(true);
  582. }
  583. else if((i == nLangs+1 || i == nLangs+2) && !m_fLoading)
  584. {
  585. put_Flip(i == nLangs+2, m_fFlipSubtitles);
  586. }
  587. return S_OK;
  588. }
  589. STDMETHODIMP CDirectVobSubFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk)
  590. {
  591. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  592. int nLangs = 0;
  593. get_LanguageCount(&nLangs);
  594. if(!(lIndex >= 0 && lIndex < nLangs+2+2)) 
  595. return E_INVALIDARG;
  596. int i = lIndex-1;
  597. if(ppmt) *ppmt = CreateMediaType(&m_pInput->CurrentMediaType());
  598. if(pdwFlags)
  599. {
  600. *pdwFlags = 0;
  601. if(i == -1 && !m_fHideSubtitles
  602. || i >= 0 && i < nLangs && i == m_iSelectedLanguage
  603. || i == nLangs && m_fHideSubtitles
  604. || i == nLangs+1 && !m_fFlipPicture
  605. || i == nLangs+2 && m_fFlipPicture)
  606. {
  607. *pdwFlags |= AMSTREAMSELECTINFO_ENABLED;
  608. }
  609. }
  610. if(plcid) *plcid = 0;
  611. if(pdwGroup) *pdwGroup = 0x648E51;
  612. if(ppszName)
  613. {
  614. *ppszName = NULL;
  615. CStringW str;
  616. if(i == -1) str = ResStr(IDS_M_SHOWSUBTITLES);
  617. else if(i >= 0 && i < nLangs) get_LanguageName(i, ppszName);
  618. else if(i == nLangs) str = ResStr(IDS_M_HIDESUBTITLES);
  619. else if(i == nLangs+1) {str = ResStr(IDS_M_ORIGINALPICTURE); if(pdwGroup) (*pdwGroup)++;}
  620. else if(i == nLangs+2) {str = ResStr(IDS_M_FLIPPEDPICTURE); if(pdwGroup) (*pdwGroup)++;}
  621. if(!str.IsEmpty())
  622. {
  623. *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength()+1)*sizeof(WCHAR));
  624. if(*ppszName == NULL) return S_FALSE;
  625. wcscpy(*ppszName, str);
  626. }
  627. }
  628. if(ppObject) *ppObject = NULL;
  629. if(ppUnk) *ppUnk = NULL;
  630. return S_OK;
  631. }
  632. STDMETHODIMP CDirectVobSubFilter::GetClassID(CLSID* pClsid)
  633. {
  634.     if(pClsid == NULL) return E_POINTER;
  635. *pClsid = m_clsid;
  636.     return NOERROR;
  637. }
  638. STDMETHODIMP CDirectVobSubFilter::GetPages(CAUUID* pPages)
  639. {
  640.     CheckPointer(pPages, E_POINTER);
  641. pPages->cElems = 7;
  642.     pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID)*pPages->cElems);
  643. if(pPages->pElems == NULL) return E_OUTOFMEMORY;
  644. int i = 0;
  645.     pPages->pElems[i++] = __uuidof(CDVSMainPPage);
  646.     pPages->pElems[i++] = __uuidof(CDVSGeneralPPage);
  647.     pPages->pElems[i++] = __uuidof(CDVSMiscPPage);
  648.     pPages->pElems[i++] = __uuidof(CDVSTimingPPage);
  649.     pPages->pElems[i++] = __uuidof(CDVSColorPPage);
  650.     pPages->pElems[i++] = __uuidof(CDVSPathsPPage);
  651.     pPages->pElems[i++] = __uuidof(CDVSAboutPPage);
  652.     return NOERROR;
  653. }
  654. // IDirectVobSub
  655. STDMETHODIMP CDirectVobSubFilter::put_FileName(WCHAR* fn)
  656. {
  657. HRESULT hr = CDirectVobSub::put_FileName(fn);
  658. if(hr == S_OK && !Open()) 
  659. {
  660. m_FileName.Empty();
  661. hr = E_FAIL;
  662. }
  663. return hr;
  664. }
  665. STDMETHODIMP CDirectVobSubFilter::get_LanguageCount(int* nLangs)
  666. {
  667. HRESULT hr = CDirectVobSub::get_LanguageCount(nLangs);
  668. if(hr == NOERROR && nLangs)
  669. {
  670.         CAutoLock cAutolock(&m_csQueueLock);
  671. *nLangs = 0;
  672. POSITION pos = m_pSubStreams.GetHeadPosition();
  673. while(pos) (*nLangs) += m_pSubStreams.GetNext(pos)->GetStreamCount();
  674. }
  675. return hr;
  676. }
  677. STDMETHODIMP CDirectVobSubFilter::get_LanguageName(int iLanguage, WCHAR** ppName)
  678. {
  679. HRESULT hr = CDirectVobSub::get_LanguageName(iLanguage, ppName);
  680. if(!ppName) return E_POINTER;
  681. if(hr == NOERROR)
  682. {
  683.         CAutoLock cAutolock(&m_csQueueLock);
  684. hr = E_INVALIDARG;
  685. int i = iLanguage;
  686. POSITION pos = m_pSubStreams.GetHeadPosition();
  687. while(i >= 0 && pos)
  688. {
  689. CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
  690. if(i < pSubStream->GetStreamCount())
  691. {
  692. pSubStream->GetStreamInfo(i, ppName, NULL);
  693. hr = NOERROR;
  694. break;
  695. }
  696. i -= pSubStream->GetStreamCount();
  697. }
  698. }
  699. return hr;
  700. }
  701. STDMETHODIMP CDirectVobSubFilter::put_SelectedLanguage(int iSelected)
  702. {
  703. HRESULT hr = CDirectVobSub::put_SelectedLanguage(iSelected);
  704. if(hr == NOERROR)
  705. {
  706. UpdateSubtitle(false);
  707. }
  708. return hr;
  709. }
  710. STDMETHODIMP CDirectVobSubFilter::put_HideSubtitles(bool fHideSubtitles)
  711. {
  712. HRESULT hr = CDirectVobSub::put_HideSubtitles(fHideSubtitles);
  713. if(hr == NOERROR)
  714. {
  715. UpdateSubtitle(false);
  716. }
  717. return hr;
  718. }
  719. STDMETHODIMP CDirectVobSubFilter::put_PreBuffering(bool fDoPreBuffering)
  720. {
  721. HRESULT hr = CDirectVobSub::put_PreBuffering(fDoPreBuffering);
  722. if(hr == NOERROR)
  723. {
  724. InitSubPicQueue();
  725. }
  726. return hr;
  727. }
  728. STDMETHODIMP CDirectVobSubFilter::put_Placement(bool fOverridePlacement, int xperc, int yperc)
  729. {
  730. HRESULT hr = CDirectVobSub::put_Placement(fOverridePlacement, xperc, yperc);
  731. if(hr == NOERROR)
  732. {
  733. UpdateSubtitle(true);
  734. }
  735. return hr;
  736. }
  737. STDMETHODIMP CDirectVobSubFilter::put_VobSubSettings(bool fBuffer, bool fOnlyShowForcedSubs, bool fReserved)
  738. {
  739. HRESULT hr = CDirectVobSub::put_VobSubSettings(fBuffer, fOnlyShowForcedSubs, fReserved);
  740. if(hr == NOERROR)
  741. {
  742. // UpdateSubtitle(false);
  743. InvalidateSubtitle();
  744. }
  745. return hr;
  746. }
  747. STDMETHODIMP CDirectVobSubFilter::put_TextSettings(void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer)
  748. {
  749. HRESULT hr = CDirectVobSub::put_TextSettings(lf, lflen, color, fShadow, fOutline, fAdvancedRenderer);
  750. if(hr == NOERROR)
  751. {
  752. // UpdateSubtitle(true);
  753. InvalidateSubtitle();
  754. }
  755. return hr;
  756. }
  757. STDMETHODIMP CDirectVobSubFilter::put_SubtitleTiming(int delay, int speedmul, int speeddiv)
  758. {
  759. HRESULT hr = CDirectVobSub::put_SubtitleTiming(delay, speedmul, speeddiv);
  760. if(hr == NOERROR)
  761. {
  762. InvalidateSubtitle();
  763. }
  764. return hr;
  765. }
  766. STDMETHODIMP CDirectVobSubFilter::get_MediaFPS(bool* fEnabled, double* fps)
  767. {
  768. HRESULT hr = CDirectVobSub::get_MediaFPS(fEnabled, fps);
  769. CComQIPtr<IMediaSeeking> pMS = m_pGraph;
  770. double rate;
  771. if(pMS && SUCCEEDED(pMS->GetRate(&rate)))
  772. {
  773. m_MediaFPS = rate * m_fps;
  774. if(fps) *fps = m_MediaFPS;
  775. }
  776. return hr;
  777. }
  778. STDMETHODIMP CDirectVobSubFilter::put_MediaFPS(bool fEnabled, double fps)
  779. {
  780. HRESULT hr = CDirectVobSub::put_MediaFPS(fEnabled, fps);
  781. CComQIPtr<IMediaSeeking> pMS = m_pGraph;
  782. if(pMS)
  783. {
  784. if(hr == NOERROR)
  785. {
  786. hr = pMS->SetRate(m_fMediaFPSEnabled ? m_MediaFPS / m_fps : 1.0);
  787. }
  788. double dRate;
  789. if(SUCCEEDED(pMS->GetRate(&dRate)))
  790. m_MediaFPS = dRate * m_fps;
  791. }
  792. return hr;
  793. }
  794. STDMETHODIMP CDirectVobSubFilter::get_ZoomRect(NORMALIZEDRECT* rect)
  795. {
  796. return E_NOTIMPL;
  797. }
  798. STDMETHODIMP CDirectVobSubFilter::put_ZoomRect(NORMALIZEDRECT* rect)
  799. {
  800. return E_NOTIMPL;
  801. }
  802. // IDirectVobSub2
  803. STDMETHODIMP CDirectVobSubFilter::put_TextSettings(STSStyle* pDefStyle)
  804. {
  805. HRESULT hr = CDirectVobSub::put_TextSettings(pDefStyle);
  806. if(hr == NOERROR)
  807. {
  808. UpdateSubtitle(true);
  809. }
  810. return hr;
  811. }
  812. // IDirectVobSubFilterColor
  813. STDMETHODIMP CDirectVobSubFilter::HasConfigDialog(int iSelected)
  814. {
  815. int nLangs;
  816. if(FAILED(get_LanguageCount(&nLangs))) return E_FAIL;
  817. return E_FAIL;
  818. // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
  819. // return(nLangs >= 0 && iSelected < nLangs ? S_OK : E_FAIL);
  820. }
  821. STDMETHODIMP CDirectVobSubFilter::ShowConfigDialog(int iSelected, HWND hWndParent)
  822. {
  823. // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
  824. return(E_FAIL);
  825. }
  826. ///////////////////////////////////////////////////////////////////////////
  827. CDirectVobSubFilter2::CDirectVobSubFilter2(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid) :
  828. CDirectVobSubFilter(punk, phr, clsid)
  829. {
  830. }
  831. HRESULT CDirectVobSubFilter2::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
  832. {
  833. CPinInfo pi;
  834. if(FAILED(pPin->QueryPinInfo(&pi))) return E_FAIL;
  835. if(CComQIPtr<IDirectVobSub>(pi.pFilter)) return E_FAIL;
  836. if(dir == PINDIR_INPUT)
  837. {
  838. CFilterInfo fi;
  839. if(SUCCEEDED(pi.pFilter->QueryFilterInfo(&fi))
  840. && !wcsnicmp(fi.achName, L"Overlay Mixer", 13))
  841. return(E_FAIL);
  842. }
  843. else
  844. {
  845. }
  846. return __super::CheckConnect(dir, pPin);
  847. }
  848. HRESULT CDirectVobSubFilter2::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
  849. {
  850. if(pGraph)
  851. {
  852. BeginEnumFilters(pGraph, pEF, pBF)
  853. {
  854. if(pBF != (IBaseFilter*)this && CComQIPtr<IDirectVobSub>(pBF))
  855. return E_FAIL;
  856. }
  857. EndEnumFilters
  858. // don't look... we will do some serious graph hacking again...
  859. //
  860. // we will add dvs2 to the filter graph cache
  861. // - if the main app has already added some kind of renderer or overlay mixer (anything which accepts video on its input)
  862. // and 
  863. // - if we have a reason to auto-load (we don't want to make any trouble when there is no need :)
  864. //
  865. // This whole workaround is needed because the video stream will always be connected 
  866. // to the pre-added filters first, no matter how high merit we have.
  867. if(!get_Forced())
  868. {
  869. BeginEnumFilters(pGraph, pEF, pBF)
  870. {
  871. if(CComQIPtr<IDirectVobSub>(pBF))
  872. continue;
  873. CComPtr<IPin> pInPin = GetFirstPin(pBF, PINDIR_INPUT);
  874. CComPtr<IPin> pOutPin = GetFirstPin(pBF, PINDIR_OUTPUT);
  875. if(!pInPin)
  876. continue;
  877. CComPtr<IPin> pPin;
  878. if(pInPin && SUCCEEDED(pInPin->ConnectedTo(&pPin))
  879. || pOutPin && SUCCEEDED(pOutPin->ConnectedTo(&pPin)))
  880. continue;
  881. if(pOutPin && GetFilterName(pBF) == _T("Overlay Mixer")) 
  882. continue;
  883. bool fVideoInputPin = false;
  884. do
  885. {
  886. BITMAPINFOHEADER bih = {sizeof(BITMAPINFOHEADER), 384, 288, 1, 16, '2YUY', 384*288*2, 0, 0, 0, 0};
  887. CMediaType cmt;
  888. cmt.majortype = MEDIATYPE_Video;
  889. cmt.subtype = MEDIASUBTYPE_YUY2;
  890. cmt.formattype = FORMAT_VideoInfo;
  891. cmt.pUnk = NULL;
  892. cmt.bFixedSizeSamples = TRUE;
  893. cmt.bTemporalCompression = TRUE;
  894. cmt.lSampleSize = 384*288*2;
  895. VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
  896. memset(vih, 0, sizeof(VIDEOINFOHEADER));
  897. memcpy(&vih->bmiHeader, &bih, sizeof(bih));
  898. vih->AvgTimePerFrame = 400000;
  899. if(SUCCEEDED(pInPin->QueryAccept(&cmt))) 
  900. {
  901. fVideoInputPin = true;
  902. break;
  903. }
  904. VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER2));
  905. memset(vih2, 0, sizeof(VIDEOINFOHEADER2));
  906. memcpy(&vih2->bmiHeader, &bih, sizeof(bih));
  907. vih2->AvgTimePerFrame = 400000;
  908. vih2->dwPictAspectRatioX = 384;
  909. vih2->dwPictAspectRatioY = 288;
  910. if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
  911. {
  912. fVideoInputPin = true;
  913. break;
  914. }
  915. }
  916. while(false);
  917. if(fVideoInputPin)
  918. {
  919. CComPtr<IBaseFilter> pDVS;
  920. if(ShouldWeAutoload(pGraph) && SUCCEEDED(pDVS.CoCreateInstance(__uuidof(CDirectVobSubFilter2))))
  921. {
  922. CComQIPtr<IDirectVobSub2>(pDVS)->put_Forced(true);
  923. CComQIPtr<IGraphConfig>(pGraph)->AddFilterToCache(pDVS);
  924. }
  925. break;
  926. }
  927. }
  928. EndEnumFilters
  929. }
  930. }
  931. else
  932. {
  933. }
  934. return __super::JoinFilterGraph(pGraph, pName);
  935. }
  936. HRESULT CDirectVobSubFilter2::CheckInputType(const CMediaType* mtIn)
  937. {
  938.     HRESULT hr = __super::CheckInputType(mtIn);
  939. if(FAILED(hr) || m_pInput->IsConnected()) return hr;
  940. if(!ShouldWeAutoload(m_pGraph)) return VFW_E_TYPE_NOT_ACCEPTED;
  941. GetRidOfInternalScriptRenderer();
  942. return NOERROR;
  943. }
  944. bool CDirectVobSubFilter2::ShouldWeAutoload(IFilterGraph* pGraph)
  945. {
  946. TCHAR blacklistedapps[][32] = 
  947. {
  948. _T("WM8EUTIL."), // wmp8 encoder's dummy renderer releases the outputted media sample after calling Receive on its input pin (yes, even when dvobsub isn't registered at all)
  949. _T("explorer."), // as some users reported thumbnail preview loads dvobsub, I've never experienced this yet...
  950. _T("producer."), // this is real's producer
  951. };
  952. for(int i = 0; i < countof(blacklistedapps); i++)
  953. {
  954. if(theApp.m_AppName.Find(blacklistedapps[i]) >= 0) 
  955. return(false);
  956. }
  957. int level;
  958. bool m_fExternalLoad, m_fWebLoad, m_fEmbeddedLoad;
  959. get_LoadSettings(&level, &m_fExternalLoad, &m_fWebLoad, &m_fEmbeddedLoad);
  960. if(level < 0 || level >= 2) return(false);
  961. bool fRet = false;
  962. if(level == 1)
  963. fRet = m_fExternalLoad = m_fWebLoad = m_fEmbeddedLoad = true;
  964. // find text stream on known splitters
  965. if(!fRet && m_fEmbeddedLoad)
  966. {
  967. CComPtr<IBaseFilter> pBF;
  968. if((pBF = FindFilter(CLSID_OggSplitter, pGraph)) || (pBF = FindFilter(CLSID_AviSplitter, pGraph))
  969. || (pBF = FindFilter(L"{34293064-02F2-41D5-9D75-CC5967ACA1AB}", pGraph)) // matroska demux
  970. || (pBF = FindFilter(L"{0A68C3B5-9164-4a54-AFAF-995B2FF0E0D4}", pGraph)) // matroska source
  971. || (pBF = FindFilter(L"{149D2E01-C32E-4939-80F6-C07B81015A7A}", pGraph)) // matroska splitter
  972. || (pBF = FindFilter(L"{9AB95E90-1F37-427e-9B3D-257FB0CB25F7}", pGraph)) // Haali's matroska splitter (?)
  973. || (pBF = FindFilter(L"{55DA30FC-F16B-49fc-BAA5-AE59FC65F82D}", pGraph)) // Haali's matroska splitter
  974. || (pBF = FindFilter(L"{52B63861-DC93-11CE-A099-00AA00479A58}", pGraph)) // 3ivx splitter
  975. || (pBF = FindFilter(L"{6D3688CE-3E9D-42F4-92CA-8A11119D25CD}", pGraph)) // our ogg source
  976. || (pBF = FindFilter(L"{9FF48807-E133-40AA-826F-9B2959E5232D}", pGraph)) // our ogg splitter
  977. || (pBF = FindFilter(L"{803E8280-F3CE-4201-982C-8CD8FB512004}", pGraph)) // dsm source
  978. || (pBF = FindFilter(L"{0912B4DD-A30A-4568-B590-7179EBB420EC}", pGraph))) // dsm splitter
  979. {
  980. BeginEnumPins(pBF, pEP, pPin)
  981. {
  982. BeginEnumMediaTypes(pPin, pEM, pmt)
  983. {
  984. if(pmt->majortype == MEDIATYPE_Text || pmt->majortype == MEDIATYPE_Subtitle)
  985. {
  986. fRet = true;
  987. break;
  988. }
  989. }
  990. EndEnumMediaTypes(pmt)
  991. if(fRet) break;
  992. }
  993. EndEnumFilters
  994. }
  995. }
  996. // find file name
  997. CStringW fn;
  998. BeginEnumFilters(pGraph, pEF, pBF)
  999. {
  1000. if(CComQIPtr<IFileSourceFilter> pFSF = pBF)
  1001. {
  1002. LPOLESTR fnw = NULL;
  1003. if(!pFSF || FAILED(pFSF->GetCurFile(&fnw, NULL)) || !fnw)
  1004. continue;
  1005. fn = CString(fnw);
  1006. CoTaskMemFree(fnw);
  1007. break;
  1008. }
  1009. }
  1010. EndEnumFilters
  1011. if((m_fExternalLoad || m_fWebLoad) && (m_fWebLoad || !(wcsstr(fn, L"http://") || wcsstr(fn, L"mms://"))))
  1012. {
  1013. bool fTemp = m_fHideSubtitles;
  1014. fRet = !fn.IsEmpty() && SUCCEEDED(put_FileName((LPWSTR)(LPCWSTR)fn))
  1015. || SUCCEEDED(put_FileName(L"c:\tmp.srt")) 
  1016. || fRet;
  1017. if(fTemp) m_fHideSubtitles = true;
  1018. }
  1019. return(fRet);
  1020. }
  1021. void CDirectVobSubFilter2::GetRidOfInternalScriptRenderer()
  1022. {
  1023. while(CComPtr<IBaseFilter> pBF = FindFilter(L"{48025243-2D39-11CE-875D-00608CB78066}", m_pGraph))
  1024. {
  1025. BeginEnumPins(pBF, pEP, pPin)
  1026. {
  1027. PIN_DIRECTION dir;
  1028. CComPtr<IPin> pPinTo;
  1029. if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT 
  1030. && SUCCEEDED(pPin->ConnectedTo(&pPinTo)))
  1031. {
  1032. m_pGraph->Disconnect(pPinTo);
  1033. m_pGraph->Disconnect(pPin);
  1034. m_pGraph->ConnectDirect(pPinTo, GetPin(2 + m_pTextInput.GetSize()-1), NULL);
  1035. }
  1036. }
  1037. EndEnumPins
  1038. if(FAILED(m_pGraph->RemoveFilter(pBF)))
  1039. break;
  1040. }
  1041. }
  1042. ///////////////////////////////////////////////////////////////////////////////
  1043. bool CDirectVobSubFilter::Open()
  1044. {
  1045. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1046. CAutoLock cAutolock(&m_csQueueLock);
  1047. m_pSubStreams.RemoveAll();
  1048. m_frd.files.RemoveAll();
  1049. CStringArray paths;
  1050. for(int i = 0; i < 10; i++)
  1051. {
  1052. CString tmp;
  1053. tmp.Format(IDS_RP_PATH, i);
  1054. CString path = theApp.GetProfileString(ResStr(IDS_R_DEFTEXTPATHES), tmp);
  1055. if(!path.IsEmpty()) paths.Add(path);
  1056. }
  1057. SubFiles ret;
  1058. GetSubFileNames(m_FileName, paths, ret);
  1059. for(int i = 0; i < ret.GetSize(); i++)
  1060. {
  1061. if(m_frd.files.Find(ret[i].fn))
  1062. continue;
  1063. CComPtr<ISubStream> pSubStream;
  1064. if(!pSubStream)
  1065. {
  1066. CAutoPtr<CVobSubFile> pVSF(new CVobSubFile(&m_csSubLock));
  1067. if(pVSF && pVSF->Open(ret[i].fn) && pVSF->GetStreamCount() > 0)
  1068. {
  1069. pSubStream = pVSF.Detach();
  1070. m_frd.files.AddTail(ret[i].fn.Left(ret[i].fn.GetLength()-4) + _T(".sub"));
  1071. }
  1072. }
  1073. if(!pSubStream)
  1074. {
  1075. CAutoPtr<CRenderedTextSubtitle> pRTS(new CRenderedTextSubtitle(&m_csSubLock));
  1076. if(pRTS && pRTS->Open(ret[i].fn, DEFAULT_CHARSET) && pRTS->GetStreamCount() > 0)
  1077. {
  1078. pSubStream = pRTS.Detach();
  1079. m_frd.files.AddTail(ret[i].fn + _T(".style"));
  1080. }
  1081. }
  1082.     
  1083. if(pSubStream)
  1084. {
  1085. m_pSubStreams.AddTail(pSubStream);
  1086. m_frd.files.AddTail(ret[i].fn);
  1087. }
  1088. }
  1089. for(int i = 0; i < m_pTextInput.GetSize(); i++)
  1090. {
  1091. if(m_pTextInput[i]->IsConnected())
  1092. m_pSubStreams.AddTail(m_pTextInput[i]->GetSubStream());
  1093. }
  1094. if(S_FALSE == put_SelectedLanguage(FindPreferedLanguage()))
  1095.         UpdateSubtitle(false); // make sure pSubPicProvider of our queue gets updated even if the stream number hasn't changed
  1096. m_frd.RefreshEvent.Set();
  1097. return(m_pSubStreams.GetCount() > 0);
  1098. }
  1099. void CDirectVobSubFilter::UpdateSubtitle(bool fApplyDefStyle)
  1100. {
  1101. CAutoLock cAutolock(&m_csQueueLock);
  1102. if(!m_pSubPicQueue) return;
  1103. InvalidateSubtitle();
  1104. CComPtr<ISubStream> pSubStream;
  1105. if(!m_fHideSubtitles)
  1106. {
  1107. int i = m_iSelectedLanguage;
  1108. for(POSITION pos = m_pSubStreams.GetHeadPosition(); i >= 0 && pos; pSubStream = NULL)
  1109. {
  1110. pSubStream = m_pSubStreams.GetNext(pos);
  1111. if(i < pSubStream->GetStreamCount()) 
  1112. {
  1113. CAutoLock cAutoLock(&m_csSubLock);
  1114. pSubStream->SetStream(i);
  1115. break;
  1116. }
  1117. i -= pSubStream->GetStreamCount();
  1118. }
  1119. }
  1120. SetSubtitle(pSubStream, fApplyDefStyle);
  1121. }
  1122. void CDirectVobSubFilter::SetSubtitle(ISubStream* pSubStream, bool fApplyDefStyle)
  1123. {
  1124.     CAutoLock cAutolock(&m_csQueueLock);
  1125. if(pSubStream)
  1126. {
  1127. CAutoLock cAutolock(&m_csSubLock);
  1128. CLSID clsid;
  1129. pSubStream->GetClassID(&clsid);
  1130. if(clsid == __uuidof(CVobSubFile))
  1131. {
  1132. CVobSubSettings* pVSS = (CVobSubFile*)(ISubStream*)pSubStream;
  1133. if(fApplyDefStyle)
  1134. {
  1135. pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
  1136. pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
  1137. }
  1138. }
  1139. else if(clsid == __uuidof(CVobSubStream))
  1140. {
  1141. CVobSubSettings* pVSS = (CVobSubStream*)(ISubStream*)pSubStream;
  1142. if(fApplyDefStyle)
  1143. {
  1144. pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
  1145. pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
  1146. }
  1147. }
  1148. else if(clsid == __uuidof(CRenderedTextSubtitle))
  1149. {
  1150. CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubStream;
  1151. if(fApplyDefStyle || pRTS->m_fUsingAutoGeneratedDefaultStyle)
  1152. {
  1153. STSStyle s = m_defStyle;
  1154. if(m_fOverridePlacement)
  1155. {
  1156. s.scrAlignment = 2;
  1157. int w = pRTS->m_dstScreenSize.cx;
  1158. int h = pRTS->m_dstScreenSize.cy;
  1159. int mw = w - s.marginRect.left - s.marginRect.right;
  1160. s.marginRect.bottom = h - MulDiv(h, m_PlacementYperc, 100);
  1161. s.marginRect.left = MulDiv(w, m_PlacementXperc, 100) - mw/2;
  1162. s.marginRect.right = w - (s.marginRect.left + mw);
  1163. }
  1164. pRTS->SetDefaultStyle(s);
  1165. }
  1166. pRTS->Deinit();
  1167. }
  1168. }
  1169. if(!fApplyDefStyle)
  1170. {
  1171. int i = 0;
  1172. POSITION pos = m_pSubStreams.GetHeadPosition();
  1173. while(pos)
  1174. {
  1175. CComPtr<ISubStream> pSubStream2 = m_pSubStreams.GetNext(pos);
  1176. if(pSubStream == pSubStream2)
  1177. {
  1178. m_iSelectedLanguage = i + pSubStream2->GetStream();
  1179. break;
  1180. }
  1181. i += pSubStream2->GetStreamCount();
  1182. }
  1183. }
  1184. m_nSubtitleId = (DWORD_PTR)pSubStream;
  1185. if(m_pSubPicQueue)
  1186. m_pSubPicQueue->SetSubPicProvider(CComQIPtr<ISubPicProvider>(pSubStream));
  1187. }
  1188. void CDirectVobSubFilter::InvalidateSubtitle(REFERENCE_TIME rtInvalidate, DWORD_PTR nSubtitleId)
  1189. {
  1190.     CAutoLock cAutolock(&m_csQueueLock);
  1191. if(m_pSubPicQueue)
  1192. {
  1193. if(nSubtitleId == -1 || nSubtitleId == m_nSubtitleId)
  1194. m_pSubPicQueue->Invalidate(rtInvalidate);
  1195. }
  1196. }
  1197. //////////////////////////////////////////////////////////////////////////////////////////
  1198. void CDirectVobSubFilter::AddSubStream(ISubStream* pSubStream)
  1199. {
  1200. CAutoLock cAutoLock(&m_csQueueLock);
  1201. POSITION pos = m_pSubStreams.Find(pSubStream);
  1202. if(!pos) m_pSubStreams.AddTail(pSubStream);
  1203. int len = m_pTextInput.GetSize();
  1204. for(int i = 0; i < m_pTextInput.GetSize(); i++)
  1205. if(m_pTextInput[i]->IsConnected()) len--;
  1206. if(len == 0)
  1207. {
  1208. HRESULT hr = S_OK;
  1209. m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
  1210. }
  1211. }
  1212. void CDirectVobSubFilter::RemoveSubStream(ISubStream* pSubStream)
  1213. {
  1214. CAutoLock cAutoLock(&m_csQueueLock);
  1215. POSITION pos = m_pSubStreams.Find(pSubStream);
  1216. if(pos) m_pSubStreams.RemoveAt(pos);
  1217. }
  1218. void CDirectVobSubFilter::Post_EC_OLE_EVENT(CString str, DWORD_PTR nSubtitleId)
  1219. {
  1220. if(nSubtitleId != -1 && nSubtitleId != m_nSubtitleId)
  1221. return;
  1222. CComQIPtr<IMediaEventSink> pMES = m_pGraph;
  1223. if(!pMES) return;
  1224. CComBSTR bstr1("Text"), bstr2(" ");
  1225. str.Trim();
  1226. if(!str.IsEmpty()) bstr2 = CStringA(str);
  1227. pMES->Notify(EC_OLE_EVENT, (LONG_PTR)bstr1.Detach(), (LONG_PTR)bstr2.Detach());
  1228. }
  1229. ////////////////////////////////////////////////////////////////
  1230. void CDirectVobSubFilter::SetupFRD(CStringArray& paths, CArray<HANDLE>& handles)
  1231. {
  1232.     CAutoLock cAutolock(&m_csSubLock);
  1233. for(int i = 2; i < handles.GetSize(); i++)
  1234. {
  1235. FindCloseChangeNotification(handles[i]);
  1236. }
  1237. paths.RemoveAll();
  1238. handles.RemoveAll();
  1239. handles.Add(m_frd.EndThreadEvent);
  1240. handles.Add(m_frd.RefreshEvent);
  1241. m_frd.mtime.SetSize(m_frd.files.GetSize());
  1242. POSITION pos = m_frd.files.GetHeadPosition();
  1243. for(int i = 0; pos; i++)
  1244. {
  1245. CString fn = m_frd.files.GetNext(pos);
  1246. CFileStatus status;
  1247. if(CFileGetStatus(fn, status)) 
  1248. m_frd.mtime[i] = status.m_mtime;
  1249. fn.Replace('\', '/');
  1250. fn = fn.Left(fn.ReverseFind('/')+1);
  1251. bool fFound = false;
  1252. for(int j = 0; !fFound && j < paths.GetSize(); j++)
  1253. {
  1254. if(paths[j] == fn) fFound = true;
  1255. }
  1256. if(!fFound)
  1257. {
  1258. paths.Add(fn);
  1259. HANDLE h = FindFirstChangeNotification(fn, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE); 
  1260. if(h != INVALID_HANDLE_VALUE) handles.Add(h);
  1261. }
  1262. }
  1263. }
  1264. DWORD CDirectVobSubFilter::ThreadProc()
  1265. {
  1266. SetThreadPriority(m_hThread, THREAD_PRIORITY_LOWEST/*THREAD_PRIORITY_BELOW_NORMAL*/);
  1267. CStringArray paths;
  1268. CArray<HANDLE> handles;
  1269. SetupFRD(paths, handles);
  1270. while(1)
  1271. DWORD idx = WaitForMultipleObjects(handles.GetSize(), handles.GetData(), FALSE, INFINITE);
  1272. if(idx == (WAIT_OBJECT_0 + 0)) // m_frd.hEndThreadEvent
  1273. {
  1274. break;
  1275. }
  1276. if(idx == (WAIT_OBJECT_0 + 1)) // m_frd.hRefreshEvent
  1277. {
  1278. SetupFRD(paths, handles);
  1279. }
  1280. else if(idx >= (WAIT_OBJECT_0 + 2) && idx < (WAIT_OBJECT_0 + handles.GetSize()))
  1281. {
  1282. bool fLocked = true;
  1283. IsSubtitleReloaderLocked(&fLocked);
  1284. if(fLocked) continue;
  1285. if(FindNextChangeNotification(handles[idx - WAIT_OBJECT_0]) == FALSE) 
  1286. break;
  1287. int j = 0;
  1288. POSITION pos = m_frd.files.GetHeadPosition();
  1289. for(int i = 0; pos && j == 0; i++)
  1290. {
  1291. CString fn = m_frd.files.GetNext(pos);
  1292. CFileStatus status;
  1293. if(CFileGetStatus(fn, status) && m_frd.mtime[i] != status.m_mtime) 
  1294. {
  1295. for(j = 0; j < 10; j++)
  1296. {
  1297. if(FILE* f = _tfopen(fn, _T("rb+"))) 
  1298. {
  1299. fclose(f);
  1300. j = 0;
  1301. break;
  1302. }
  1303. else
  1304. {
  1305. Sleep(100);
  1306. j++;
  1307. }
  1308. }
  1309. }
  1310. }
  1311. if(j > 0)
  1312. {
  1313. SetupFRD(paths, handles);
  1314. }
  1315. else
  1316. {
  1317. Sleep(500);
  1318. POSITION pos = m_frd.files.GetHeadPosition();
  1319. for(int i = 0; pos; i++)
  1320. {
  1321. CFileStatus status;
  1322. if(CFileGetStatus(m_frd.files.GetNext(pos), status) 
  1323. && m_frd.mtime[i] != status.m_mtime) 
  1324. {
  1325. Open();
  1326. SetupFRD(paths, handles);
  1327. break;
  1328. }
  1329. }
  1330. }
  1331. }
  1332. else 
  1333. {
  1334. break;
  1335. }
  1336. }
  1337. for(int i = 2; i < handles.GetSize(); i++)
  1338. {
  1339. FindCloseChangeNotification(handles[i]);
  1340. }
  1341. return 0;
  1342. }