Add colour space auto guess option to UI.
[xy_vsfilter.git] / src / filters / transform / vsfilter / DirectVobSubFilter.cpp
blob302007e863c72a3cf43c9b4f5c6d8ad079a6be7d
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
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.
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.
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
22 #include "stdafx.h"
23 #include <math.h>
24 #include <time.h>
25 #include "DirectVobSubFilter.h"
26 #include "TextInputPin.h"
27 #include "DirectVobSubPropPage.h"
28 #include "VSFilter.h"
29 #include "systray.h"
30 #include "../../../DSUtil/MediaTypes.h"
31 #include "../../../SubPic/SubPicQueueImpl.h"
32 #include "../../../SubPic/PooledSubPic.h"
33 #include "../../../subpic/color_conv_table.h"
35 #include <initguid.h>
36 #include "..\..\..\..\include\moreuuids.h"
38 #include "CAutoTiming.h"
39 #include "xy_logger.h"
41 #define MAX_SUBPIC_QUEUE_LENGTH 1
43 ///////////////////////////////////////////////////////////////////////////
45 /*removeme*/
46 bool g_RegOK = true;//false; // doesn't work with the dvd graph builder
47 #include "valami.cpp"
49 #ifdef __DO_LOG
50 EXTERN_C IMAGE_DOS_HEADER __ImageBase;
51 #endif
53 ////////////////////////////////////////////////////////////////////////////
55 // Constructor
58 CDirectVobSubFilter::CDirectVobSubFilter(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid)
59 : CBaseVideoFilter(NAME("CDirectVobSubFilter"), punk, phr, clsid)
60 , m_nSubtitleId(-1)
61 , m_fMSMpeg4Fix(false)
62 , m_fps(25)
64 DbgLog((LOG_TRACE, 3, _T("CDirectVobSubFilter::CDirectVobSubFilter")));
66 // and then, anywhere you need it:
68 #ifdef __DO_LOG
69 LPTSTR strDLLPath = new TCHAR[_MAX_PATH];
70 ::GetModuleFileName( reinterpret_cast<HINSTANCE>(&__ImageBase), strDLLPath, _MAX_PATH);
71 CString dllPath = strDLLPath;
72 dllPath += ".properties";
73 xy_logger::doConfigure( dllPath.GetString() );
74 #endif
76 AFX_MANAGE_STATE(AfxGetStaticModuleState());
78 m_hdc = 0;
79 m_hbm = 0;
80 m_hfont = 0;
83 LOGFONT lf;
84 memset(&lf, 0, sizeof(lf));
85 lf.lfCharSet = DEFAULT_CHARSET;
86 lf.lfOutPrecision = OUT_CHARACTER_PRECIS;
87 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
88 lf.lfQuality = ANTIALIASED_QUALITY;
89 HDC hdc = GetDC(NULL);
90 lf.lfHeight = 28;
91 //MulDiv(20, GetDeviceCaps(hdc, LOGPIXELSY), 54);
92 ReleaseDC(NULL, hdc);
93 lf.lfWeight = FW_BOLD;
94 _tcscpy(lf.lfFaceName, _T("Arial"));
95 m_hfont = CreateFontIndirect(&lf);
98 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Hint"), _T("The first three are fixed, but you can add more up to ten entries."));
99 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path0"), _T("."));
100 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path1"), _T("c:\\subtitles"));
101 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path2"), _T(".\\subtitles"));
103 m_fLoading = true;
105 m_hSystrayThread = 0;
106 m_tbid.hSystrayWnd = NULL;
107 m_tbid.graph = NULL;
108 m_tbid.fRunOnce = false;
109 m_tbid.fShowIcon = (theApp.m_AppName.Find(_T("zplayer"), 0) < 0 || !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_ENABLEZPICON), 0));
111 HRESULT hr = S_OK;
112 m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
113 ASSERT(SUCCEEDED(hr));
115 CAMThread::Create();
116 m_frd.EndThreadEvent.Create(0, FALSE, FALSE, 0);
117 m_frd.RefreshEvent.Create(0, FALSE, FALSE, 0);
119 memset(&m_CurrentVIH2, 0, sizeof(VIDEOINFOHEADER2));
121 m_time_alphablt = m_time_rasterization = 0;
124 CDirectVobSubFilter::~CDirectVobSubFilter()
126 CAutoLock cAutoLock(&m_csQueueLock);
127 if(m_pSubPicQueue)
129 DbgLog((LOG_TRACE, 3, "~CDirectVobSubFilter::Invalidate"));
130 m_pSubPicQueue->Invalidate();
132 m_pSubPicQueue = NULL;
134 if(m_hfont) {DeleteObject(m_hfont); m_hfont = 0;}
135 if(m_hbm) {DeleteObject(m_hbm); m_hbm = 0;}
136 if(m_hdc) {DeleteObject(m_hdc); m_hdc = 0;}
138 for(int i = 0; i < m_pTextInput.GetCount(); i++)
139 delete m_pTextInput[i];
141 m_frd.EndThreadEvent.Set();
142 CAMThread::Close();
144 DbgLog((LOG_TRACE, 3, _T("CDirectVobSubFilter::~CDirectVobSubFilter")));
146 //Trace(_T("CDirectVobSubFilter::~CDirectVobSubFilter"));
147 //ReleaseTracer;
150 STDMETHODIMP CDirectVobSubFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
152 CheckPointer(ppv, E_POINTER);
154 return
155 QI(IDirectVobSub)
156 QI(IDirectVobSub2)
157 QI(IFilterVersion)
158 QI(ISpecifyPropertyPages)
159 QI(IAMStreamSelect)
160 __super::NonDelegatingQueryInterface(riid, ppv);
163 // CBaseVideoFilter
165 void CDirectVobSubFilter::GetOutputSize(int& w, int& h, int& arx, int& ary)
167 CSize s(w, h), os = s;
168 AdjustFrameSize(s);
169 w = s.cx;
170 h = s.cy;
172 if(w != os.cx)
174 while(arx < 100) arx *= 10, ary *= 10;
175 arx = arx * w / os.cx;
178 if(h != os.cy)
180 while(ary < 100) arx *= 10, ary *= 10;
181 ary = ary * h / os.cy;
185 HRESULT CDirectVobSubFilter::TryNotCopy(IMediaSample* pIn, const CMediaType& mt, const BITMAPINFOHEADER& bihIn )
187 CSize sub(m_w, m_h);
188 CSize in(bihIn.biWidth, bihIn.biHeight);
189 BYTE* pDataIn = NULL;
190 if(FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn)
191 return S_FALSE;
192 if( sub==in )
194 m_spd.bits = pDataIn;
196 else
198 m_spd.bits = static_cast<BYTE*>(m_pTempPicBuff);
199 bool fYV12 = (mt.subtype == MEDIASUBTYPE_YV12 || mt.subtype == MEDIASUBTYPE_I420 || mt.subtype == MEDIASUBTYPE_IYUV);
200 bool fP010 = (mt.subtype == MEDIASUBTYPE_P010 || mt.subtype == MEDIASUBTYPE_P016);
202 int bpp = fP010 ? 16 : fYV12 ? 8 : bihIn.biBitCount;
203 DWORD black = fP010 ? 0x10001000 : fYV12 ? 0x10101010 : (bihIn.biCompression == '2YUY') ? 0x80108010 : 0;
206 if(FAILED(Copy((BYTE*)m_pTempPicBuff, pDataIn, sub, in, bpp, mt.subtype, black)))
207 return E_FAIL;
209 if(fYV12)
211 BYTE* pSubV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
212 BYTE* pInV = pDataIn + (in.cx*bpp>>3)*in.cy;
213 sub.cx >>= 1; sub.cy >>= 1; in.cx >>= 1; in.cy >>= 1;
214 BYTE* pSubU = pSubV + (sub.cx*bpp>>3)*sub.cy;
215 BYTE* pInU = pInV + (in.cx*bpp>>3)*in.cy;
216 if(FAILED(Copy(pSubV, pInV, sub, in, bpp, mt.subtype, 0x80808080)))
217 return E_FAIL;
218 if(FAILED(Copy(pSubU, pInU, sub, in, bpp, mt.subtype, 0x80808080)))
219 return E_FAIL;
221 else if (fP010)
223 BYTE* pSubUV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
224 BYTE* pInUV = pDataIn + (in.cx*bpp>>3)*in.cy;
225 sub.cy >>= 1; in.cy >>= 1;
226 if(FAILED(Copy(pSubUV, pInUV, sub, in, bpp, mt.subtype, 0x80008000)))
227 return E_FAIL;
230 return S_OK;
233 HRESULT CDirectVobSubFilter::Transform(IMediaSample* pIn)
235 XY_LOG_ONCE(0, _T("CDirectVobSubFilter::Transform"));
236 HRESULT hr;
239 REFERENCE_TIME rtStart, rtStop;
240 if(SUCCEEDED(pIn->GetTime(&rtStart, &rtStop)))
242 double dRate = m_pInput->CurrentRate();
244 m_tPrev = m_pInput->CurrentStartTime() + dRate*rtStart;
246 REFERENCE_TIME rtAvgTimePerFrame = rtStop - rtStart;
247 if(CComQIPtr<ISubClock2> pSC2 = m_pSubClock)
249 REFERENCE_TIME rt;
250 if(S_OK == pSC2->GetAvgTimePerFrame(&rt))
251 rtAvgTimePerFrame = rt;
254 m_fps = 10000000.0/rtAvgTimePerFrame / dRate;
260 CAutoLock cAutoLock(&m_csQueueLock);
262 if(m_pSubPicQueue)
264 m_pSubPicQueue->SetTime(CalcCurrentTime());
265 m_pSubPicQueue->SetFPS(m_fps);
270 const CMediaType& mt = m_pInput->CurrentMediaType();
272 BITMAPINFOHEADER bihIn;
273 ExtractBIH(&mt, &bihIn);
275 hr = TryNotCopy(pIn, mt, bihIn);
276 if( hr!=S_OK )
278 //fix me: log error
279 return hr;
283 SubPicDesc spd = m_spd;
285 CComPtr<IMediaSample> pOut;
286 BYTE* pDataOut = NULL;
287 if(FAILED(hr = GetDeliveryBuffer(spd.w, spd.h, &pOut))
288 || FAILED(hr = pOut->GetPointer(&pDataOut)))
289 return hr;
290 pOut->SetTime(&rtStart, &rtStop);
291 pOut->SetMediaTime(NULL, NULL);
292 pOut->SetDiscontinuity(pIn->IsDiscontinuity() == S_OK);
293 pOut->SetSyncPoint(pIn->IsSyncPoint() == S_OK);
294 pOut->SetPreroll(pIn->IsPreroll() == S_OK);
297 BITMAPINFOHEADER bihOut;
298 ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
300 bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3;
301 bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3;
303 bool fFlip = fInputFlipped != fOutputFlipped;
304 if(m_fFlipPicture) fFlip = !fFlip;
305 if(m_fMSMpeg4Fix) fFlip = !fFlip;
307 bool fFlipSub = fOutputFlipped;
308 if(m_fFlipSubtitles) fFlipSub = !fFlipSub;
313 CAutoLock cAutoLock(&m_csQueueLock);
315 if(m_pSubPicQueue)
317 CComPtr<ISubPicEx> pSubPic;
319 //int timeStamp1 = GetTickCount();
320 bool lookupResult = SUCCEEDED(m_pSubPicQueue->LookupSubPicEx(CalcCurrentTime(), &pSubPic));
321 //int timeStamp2 = GetTickCount();
322 //m_time_rasterization += timeStamp2-timeStamp1;
324 if(lookupResult && pSubPic)
326 //CRect r;
327 //pSubPic->GetDirtyRect(r);
328 CAtlList<const CRect> rectList;
329 pSubPic->GetDirtyRects(rectList);
331 if(fFlip ^ fFlipSub)
332 spd.h = -spd.h;
334 POSITION pos = rectList.GetHeadPosition();
335 while(pos!=NULL)
337 const CRect& cRect = rectList.GetNext(pos);
338 pSubPic->AlphaBlt(cRect, cRect, &spd);
339 //pSubPic->AlphaBlt(r, r, &spd);
342 //m_time_alphablt += GetTickCount() - timeStamp2;
344 DbgLog((LOG_TRACE,3,"AlphaBlt time:%lu", (ULONG)(CalcCurrentTime()/10000)));
350 CopyBuffer(pDataOut, (BYTE*)spd.bits, spd.w, abs(spd.h)*(fFlip?-1:1), spd.pitch, mt.subtype);
352 PrintMessages(pDataOut);
353 return m_pOutput->Deliver(pOut);
356 // CBaseFilter
358 CBasePin* CDirectVobSubFilter::GetPin(int n)
360 if(n < __super::GetPinCount())
361 return __super::GetPin(n);
363 n -= __super::GetPinCount();
365 if(n >= 0 && n < m_pTextInput.GetCount())
366 return m_pTextInput[n];
368 n -= m_pTextInput.GetCount();
370 return NULL;
373 int CDirectVobSubFilter::GetPinCount()
375 return __super::GetPinCount() + m_pTextInput.GetCount();
378 HRESULT CDirectVobSubFilter::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
380 if(pGraph)
382 AFX_MANAGE_STATE(AfxGetStaticModuleState());
384 if(!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 0))
386 unsigned __int64 ver = GetFileVersion(_T("divx_c32.ax"));
387 if(((ver >> 48)&0xffff) == 4 && ((ver >> 32)&0xffff) == 2)
389 DWORD dwVersion = GetVersion();
390 DWORD dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
391 DWORD dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
393 if(dwVersion < 0x80000000 && dwWindowsMajorVersion >= 5)
395 AfxMessageBox(IDS_DIVX_WARNING);
396 theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 1);
401 /*removeme*/
402 if(!g_RegOK)
404 DllRegisterServer();
405 g_RegOK = true;
408 else
410 if(m_hSystrayThread)
412 SendMessage(m_tbid.hSystrayWnd, WM_CLOSE, 0, 0);
414 if(WaitForSingleObject(m_hSystrayThread, 10000) != WAIT_OBJECT_0)
416 DbgLog((LOG_TRACE, 0, _T("CALL THE AMBULANCE!!!")));
417 TerminateThread(m_hSystrayThread, (DWORD)-1);
420 m_hSystrayThread = 0;
424 return __super::JoinFilterGraph(pGraph, pName);
427 STDMETHODIMP CDirectVobSubFilter::QueryFilterInfo(FILTER_INFO* pInfo)
429 CheckPointer(pInfo, E_POINTER);
430 ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO));
432 if(!get_Forced())
433 return __super::QueryFilterInfo(pInfo);
435 wcscpy(pInfo->achName, L"DirectVobSub (forced auto-loading version)");
436 if(pInfo->pGraph = m_pGraph) m_pGraph->AddRef();
438 return S_OK;
441 // CTransformFilter
443 HRESULT CDirectVobSubFilter::SetMediaType(PIN_DIRECTION dir, const CMediaType* pmt)
445 HRESULT hr = __super::SetMediaType(dir, pmt);
446 if(FAILED(hr)) return hr;
448 if(dir == PINDIR_INPUT)
450 CAutoLock cAutoLock(&m_csReceive);
452 REFERENCE_TIME atpf =
453 pmt->formattype == FORMAT_VideoInfo ? ((VIDEOINFOHEADER*)pmt->Format())->AvgTimePerFrame :
454 pmt->formattype == FORMAT_VideoInfo2 ? ((VIDEOINFOHEADER2*)pmt->Format())->AvgTimePerFrame :
457 m_fps = atpf ? 10000000.0 / atpf : 25;
459 if (pmt->formattype == FORMAT_VideoInfo2)
460 m_CurrentVIH2 = *(VIDEOINFOHEADER2*)pmt->Format();
462 DbgLog((LOG_TRACE, 3, "SetMediaType => InitSubPicQueue"));
463 InitSubPicQueue();
465 else if(dir == PINDIR_OUTPUT)
470 return hr;
473 HRESULT CDirectVobSubFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
475 if(dir == PINDIR_INPUT)
478 else if(dir == PINDIR_OUTPUT)
480 /*removeme*/
481 if(HmGyanusVagyTeNekem(pPin)) return(E_FAIL);
484 return __super::CheckConnect(dir, pPin);
487 HRESULT CDirectVobSubFilter::CompleteConnect(PIN_DIRECTION dir, IPin* pReceivePin)
489 bool reconnected = false;
490 if(dir == PINDIR_INPUT)
492 DbgLog((LOG_TRACE, 3, TEXT("connect input")));
493 DumpGraph(m_pGraph,0);
494 CComPtr<IBaseFilter> pFilter;
496 // needed when we have a decoder with a version number of 3.x
497 if(SUCCEEDED(m_pGraph->FindFilterByName(L"DivX MPEG-4 DVD Video Decompressor ", &pFilter))
498 && (GetFileVersion(_T("divx_c32.ax")) >> 48) <= 4
499 || SUCCEEDED(m_pGraph->FindFilterByName(L"Microcrap MPEG-4 Video Decompressor", &pFilter))
500 || SUCCEEDED(m_pGraph->FindFilterByName(L"Microsoft MPEG-4 Video Decompressor", &pFilter))
501 && (GetFileVersion(_T("mpg4ds32.ax")) >> 48) <= 3)
503 m_fMSMpeg4Fix = true;
506 else if(dir == PINDIR_OUTPUT)
508 DbgLog((LOG_TRACE, 3, TEXT("connect output")));
509 DumpGraph(m_pGraph,0);
510 const CMediaType* mtIn = &(m_pInput->CurrentMediaType());
511 const CMediaType* mtOut = &(m_pOutput->CurrentMediaType());
512 CMediaType desiredMt;
514 if( (mtIn->subtype == MEDIASUBTYPE_P010 || mtIn->subtype == MEDIASUBTYPE_P016)
515 && (mtOut->subtype != mtIn->subtype ) )
517 DbgLog((LOG_TRACE, 3, TEXT("Try reconnect!")));
518 DbgLog((LOG_TRACE, 3, TEXT("Trying media type:")));
519 DbgLog((LOG_TRACE, 3, TEXT(" major type: %hs"),
520 GuidNames[*mtOut->Type()]));
521 DbgLog((LOG_TRACE, 3, TEXT(" sub type : %hs"),
522 GuidNames[*mtOut->Subtype()]));
524 int position = 0;
525 HRESULT hr;
528 hr = GetMediaType(position, &desiredMt);
529 ++position;
530 //if( FAILED(hr) )
531 if( hr!=S_OK )
532 break;
534 DbgLog((LOG_TRACE, 3, TEXT("Trying reconnect with media type:")));
535 DbgLog((LOG_TRACE, 3, TEXT(" in major type: %hs"),
536 GuidNames[*(desiredMt.Type())]));
537 DbgLog((LOG_TRACE, 3, TEXT(" in sub type : %hs"),
538 GuidNames[*(desiredMt.Subtype())]));
539 DbgLog((LOG_TRACE, 3, TEXT(" out major type: %hs"),
540 GuidNames[*mtOut->Type()]));
541 DbgLog((LOG_TRACE, 3, TEXT(" out sub type : %hs"),
542 GuidNames[*mtOut->Subtype()]));
544 if( desiredMt.subtype==MEDIASUBTYPE_P010 ||
545 desiredMt.subtype==MEDIASUBTYPE_P016 ||
546 FAILED( DoCheckTransform(&desiredMt, mtOut, true) ) )
548 continue;
550 else
552 break;
554 } while ( true );
555 if (hr==S_OK && //SUCCEEDED(hr) &&
556 SUCCEEDED(m_pInput->GetConnected()->QueryAccept(&desiredMt)))
558 if (SUCCEEDED(ReconnectPin(m_pInput, &desiredMt)))
560 reconnected = true;
561 DumpGraph(m_pGraph,0);
562 //m_pInput->SetMediaType(&desiredMt);
563 DbgLog((LOG_TRACE, 3, TEXT("reconnected succeed!")));
565 else
567 DbgLog((LOG_TRACE, 3, TEXT("Failed to reconnect!")));
568 return VFW_E_TYPE_NOT_ACCEPTED;
571 else
573 DbgLog((LOG_TRACE, 3, TEXT("Failed to agree reconnect type!")));
574 return VFW_E_TYPE_NOT_ACCEPTED;
578 if (!reconnected && m_pOutput->IsConnected())
580 if(!m_hSystrayThread)
582 m_tbid.graph = m_pGraph;
583 m_tbid.dvs = static_cast<IDirectVobSub*>(this);
585 DWORD tid;
586 m_hSystrayThread = CreateThread(0, 0, SystrayThreadProc, &m_tbid, 0, &tid);
588 m_pInput->SetMediaType( &m_pInput->CurrentMediaType() );
591 HRESULT hr = __super::CompleteConnect(dir, pReceivePin);
592 DbgLog((LOG_TRACE, 3, TEXT("connect fininshed!")));
593 DumpGraph(m_pGraph,0);
594 return hr;
597 HRESULT CDirectVobSubFilter::BreakConnect(PIN_DIRECTION dir)
599 if(dir == PINDIR_INPUT)
601 //if(m_pOutput->IsConnected())
603 // m_pOutput->GetConnected()->Disconnect();
604 // m_pOutput->Disconnect();
607 else if(dir == PINDIR_OUTPUT)
609 // not really needed, but may free up a little memory
610 CAutoLock cAutoLock(&m_csQueueLock);
611 m_pSubPicQueue = NULL;
614 return __super::BreakConnect(dir);
617 HRESULT CDirectVobSubFilter::StartStreaming()
619 /* WARNING: calls to m_pGraph member functions from within this function will generate deadlock with Haali
620 * Video Renderer in MPC. Reason is that CAutoLock's variables in IFilterGraph functions are overriden by
621 * CFGManager class.
624 m_fLoading = false;
626 DbgLog((LOG_TRACE, 3, "StartStreaming => InitSubPicQueue"));
627 InitSubPicQueue();
629 m_tbid.fRunOnce = true;
631 put_MediaFPS(m_fMediaFPSEnabled, m_MediaFPS);
633 return __super::StartStreaming();
636 HRESULT CDirectVobSubFilter::StopStreaming()
638 InvalidateSubtitle();
640 //xy Timing
641 //FILE * timingFile = fopen("C:\\vsfilter_timing.txt", "at");
642 //fprintf(timingFile, "%s:%ld %s:%ld\n", "m_time_alphablt", m_time_alphablt, "m_time_rasterization", m_time_rasterization);
643 //fclose(timingFile);
645 return __super::StopStreaming();
648 HRESULT CDirectVobSubFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
650 m_tPrev = tStart;
651 return __super::NewSegment(tStart, tStop, dRate);
656 REFERENCE_TIME CDirectVobSubFilter::CalcCurrentTime()
658 REFERENCE_TIME rt = m_pSubClock ? m_pSubClock->GetTime() : m_tPrev;
659 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)
662 void CDirectVobSubFilter::InitSubPicQueue()
664 CAutoLock cAutoLock(&m_csQueueLock);
666 switch(m_colourSpace)
668 case CDirectVobSub::BT_601:
669 ColorConvTable::SetDefaultYUVType(ColorConvTable::BT601);
670 break;
671 case CDirectVobSub::BT_709:
672 ColorConvTable::SetDefaultYUVType(ColorConvTable::BT709);
673 break;
674 case CDirectVobSub::AUTO_GUESS:
675 ColorConvTable::SetDefaultYUVType( (m_w > m_bt601Width || m_h > m_bt601Height) ?
676 ColorConvTable::BT709 : ColorConvTable::BT601 );
677 break;
679 CacheManager::GetPathDataMruCache()->SetMaxItemNum(m_path_data_cache_max_item_num);
680 CacheManager::GetScanLineDataMruCache()->SetMaxItemNum(m_scan_line_data_cache_max_item_num);
681 CacheManager::GetOverlayNoBlurMruCache()->SetMaxItemNum(m_overlay_no_blur_cache_max_item_num);
682 CacheManager::GetOverlayMruCache()->SetMaxItemNum(m_overlay_cache_max_item_num);
683 SubpixelPositionControler::GetGlobalControler().SetSubpixelLevel( static_cast<SubpixelPositionControler::SUBPIXEL_LEVEL>(m_subpixel_pos_level) );
685 m_pSubPicQueue = NULL;
687 const GUID& subtype = m_pInput->CurrentMediaType().subtype;
689 BITMAPINFOHEADER bihIn;
690 ExtractBIH(&m_pInput->CurrentMediaType(), &bihIn);
692 m_spd.type = -1;
694 if(subtype == MEDIASUBTYPE_YV12) m_spd.type = MSP_YV12;
695 else if(subtype == MEDIASUBTYPE_P010) m_spd.type = MSP_P010;
696 else if(subtype == MEDIASUBTYPE_P016) m_spd.type = MSP_P016;
697 else if(subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV) m_spd.type = MSP_IYUV;
698 else if(subtype == MEDIASUBTYPE_YUY2) m_spd.type = MSP_YUY2;
699 else if(subtype == MEDIASUBTYPE_RGB32) m_spd.type = MSP_RGB32;
700 else if(subtype == MEDIASUBTYPE_RGB24) m_spd.type = MSP_RGB24;
701 else if(subtype == MEDIASUBTYPE_RGB565) m_spd.type = MSP_RGB16;
702 else if(subtype == MEDIASUBTYPE_RGB555) m_spd.type = MSP_RGB15;
704 m_spd.w = m_w;
705 m_spd.h = m_h;
706 m_spd.bpp = (m_spd.type == MSP_P010 || m_spd.type == MSP_P016) ? 16 : (m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV) ? 8 : bihIn.biBitCount;
707 m_spd.pitch = m_spd.w*m_spd.bpp>>3;
709 m_pTempPicBuff.Free();
710 if(m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV)
711 m_pTempPicBuff.Allocate(4*m_spd.pitch*m_spd.h);
712 else if(m_spd.type == MSP_P010 || m_spd.type == MSP_P016)
713 m_pTempPicBuff.Allocate(m_spd.pitch*m_spd.h+m_spd.pitch*m_spd.h/2);
714 else
715 m_pTempPicBuff.Allocate(m_spd.pitch*m_spd.h);
716 m_spd.bits = (void*)m_pTempPicBuff;
718 //CComPtr<ISubPicExAllocator> pSubPicAllocator = new CMemSubPicAllocator(m_spd.type, CSize(m_w, m_h));
719 CComPtr<ISubPicExAllocator> pSubPicAllocator = new CPooledSubPicAllocator(m_spd.type, CSize(m_w, m_h), MAX_SUBPIC_QUEUE_LENGTH + 1);
720 if(pSubPicAllocator==NULL)
722 //fix me: log error
725 CSize video(bihIn.biWidth, bihIn.biHeight), window = video;
726 if(AdjustFrameSize(window)) video += video;
727 ASSERT(window == CSize(m_w, m_h));
729 pSubPicAllocator->SetCurSize(window);
730 pSubPicAllocator->SetCurVidRect(CRect(CPoint((window.cx - video.cx)/2, (window.cy - video.cy)/2), video));
732 HRESULT hr = S_OK;
733 //m_pSubPicQueue = m_fDoPreBuffering
734 // ? (ISubPicQueue*)new CSubPicQueue(MAX_SUBPIC_QUEUE_LENGTH, pSubPicAllocator, &hr)
735 // : (ISubPicQueue*)new CSubPicQueueNoThread(pSubPicAllocator, &hr);
736 m_pSubPicQueue = new CSubPicQueueNoThread(pSubPicAllocator, &hr);
738 if(FAILED(hr)) m_pSubPicQueue = NULL;
740 UpdateSubtitle(false);
742 if(m_hbm) {DeleteObject(m_hbm); m_hbm = NULL;}
743 if(m_hdc) {DeleteDC(m_hdc); m_hdc = NULL;}
745 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};
746 m_hdc = CreateCompatibleDC(NULL);
747 m_hbm = CreateDIBSection(m_hdc, (BITMAPINFO*)&b, DIB_RGB_COLORS, NULL, NULL, 0);
749 BITMAP bm;
750 GetObject(m_hbm, sizeof(bm), &bm);
751 memsetd(bm.bmBits, 0xFF000000, bm.bmHeight*bm.bmWidthBytes);
754 bool CDirectVobSubFilter::AdjustFrameSize(CSize& s)
756 int horizontal, vertical, resx2, resx2minw, resx2minh;
757 get_ExtendPicture(&horizontal, &vertical, &resx2, &resx2minw, &resx2minh);
759 bool fRet = (resx2 == 1) || (resx2 == 2 && s.cx*s.cy <= resx2minw*resx2minh);
761 if(fRet)
763 s.cx <<= 1;
764 s.cy <<= 1;
767 int h;
768 switch(vertical&0x7f)
770 case 1:
771 h = s.cx * 9 / 16;
772 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
773 break;
774 case 2:
775 h = s.cx * 3 / 4;
776 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
777 break;
778 case 3:
779 h = 480;
780 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
781 break;
782 case 4:
783 h = 576;
784 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
785 break;
788 if(horizontal == 1)
790 s.cx = (s.cx + 31) & ~31;
791 s.cy = (s.cy + 1) & ~1;
794 return(fRet);
797 STDMETHODIMP CDirectVobSubFilter::Count(DWORD* pcStreams)
799 if(!pcStreams) return E_POINTER;
801 *pcStreams = 0;
803 int nLangs = 0;
804 if(SUCCEEDED(get_LanguageCount(&nLangs)))
805 (*pcStreams) += nLangs;
807 (*pcStreams) += 2; // enable ... disable
809 (*pcStreams) += 2; // normal flipped
811 return S_OK;
814 #define MAXPREFLANGS 5
816 int CDirectVobSubFilter::FindPreferedLanguage(bool fHideToo)
818 AFX_MANAGE_STATE(AfxGetStaticModuleState());
820 int nLangs;
821 get_LanguageCount(&nLangs);
823 if(nLangs <= 0) return(0);
825 for(int i = 0; i < MAXPREFLANGS; i++)
827 CString tmp;
828 tmp.Format(IDS_RL_LANG, i);
830 CString lang = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
832 if(!lang.IsEmpty())
834 for(int ret = 0; ret < nLangs; ret++)
836 CString l;
837 WCHAR* pName = NULL;
838 get_LanguageName(ret, &pName);
839 l = pName;
840 CoTaskMemFree(pName);
842 if(!l.CompareNoCase(lang)) return(ret);
847 return(0);
850 void CDirectVobSubFilter::UpdatePreferedLanguages(CString l)
852 AFX_MANAGE_STATE(AfxGetStaticModuleState());
854 CString langs[MAXPREFLANGS+1];
856 int i = 0, j = 0, k = -1;
857 for(; i < MAXPREFLANGS; i++)
859 CString tmp;
860 tmp.Format(IDS_RL_LANG, i);
862 langs[j] = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
864 if(!langs[j].IsEmpty())
866 if(!langs[j].CompareNoCase(l)) k = j;
867 j++;
871 if(k == -1)
873 langs[k = j] = l;
874 j++;
877 // move the selected to the top of the list
879 while(k > 0)
881 CString tmp = langs[k]; langs[k] = langs[k-1]; langs[k-1] = tmp;
882 k--;
885 // move "Hide subtitles" to the last position if it wasn't our selection
887 CString hidesubs;
888 hidesubs.LoadString(IDS_M_HIDESUBTITLES);
890 for(k = 1; k < j; k++)
892 if(!langs[k].CompareNoCase(hidesubs)) break;
895 while(k < j-1)
897 CString tmp = langs[k]; langs[k] = langs[k+1]; langs[k+1] = tmp;
898 k++;
901 for(i = 0; i < j; i++)
903 CString tmp;
904 tmp.Format(IDS_RL_LANG, i);
906 theApp.WriteProfileString(ResStr(IDS_R_PREFLANGS), tmp, langs[i]);
910 STDMETHODIMP CDirectVobSubFilter::Enable(long lIndex, DWORD dwFlags)
912 if(!(dwFlags & AMSTREAMSELECTENABLE_ENABLE))
913 return E_NOTIMPL;
915 int nLangs = 0;
916 get_LanguageCount(&nLangs);
918 if(!(lIndex >= 0 && lIndex < nLangs+2+2))
919 return E_INVALIDARG;
921 int i = lIndex-1;
923 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
925 put_HideSubtitles(false);
927 else if(i >= 0 && i < nLangs)
929 put_HideSubtitles(false);
930 put_SelectedLanguage(i);
932 WCHAR* pName = NULL;
933 if(SUCCEEDED(get_LanguageName(i, &pName)))
935 UpdatePreferedLanguages(CString(pName));
936 if(pName) CoTaskMemFree(pName);
939 else if(i == nLangs && !m_fLoading)
941 put_HideSubtitles(true);
943 else if((i == nLangs+1 || i == nLangs+2) && !m_fLoading)
945 put_Flip(i == nLangs+2, m_fFlipSubtitles);
948 return S_OK;
951 STDMETHODIMP CDirectVobSubFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk)
953 AFX_MANAGE_STATE(AfxGetStaticModuleState());
955 int nLangs = 0;
956 get_LanguageCount(&nLangs);
958 if(!(lIndex >= 0 && lIndex < nLangs+2+2))
959 return E_INVALIDARG;
961 int i = lIndex-1;
963 if(ppmt) *ppmt = CreateMediaType(&m_pInput->CurrentMediaType());
965 if(pdwFlags)
967 *pdwFlags = 0;
969 if(i == -1 && !m_fHideSubtitles
970 || i >= 0 && i < nLangs && i == m_iSelectedLanguage
971 || i == nLangs && m_fHideSubtitles
972 || i == nLangs+1 && !m_fFlipPicture
973 || i == nLangs+2 && m_fFlipPicture)
975 *pdwFlags |= AMSTREAMSELECTINFO_ENABLED;
979 if(plcid) *plcid = 0;
981 if(pdwGroup) *pdwGroup = 0x648E51;
983 if(ppszName)
985 *ppszName = NULL;
987 CStringW str;
988 if(i == -1) str = ResStr(IDS_M_SHOWSUBTITLES);
989 else if(i >= 0 && i < nLangs) get_LanguageName(i, ppszName);
990 else if(i == nLangs) str = ResStr(IDS_M_HIDESUBTITLES);
991 else if(i == nLangs+1) {str = ResStr(IDS_M_ORIGINALPICTURE); if(pdwGroup) (*pdwGroup)++;}
992 else if(i == nLangs+2) {str = ResStr(IDS_M_FLIPPEDPICTURE); if(pdwGroup) (*pdwGroup)++;}
994 if(!str.IsEmpty())
996 *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength()+1)*sizeof(WCHAR));
997 if(*ppszName == NULL) return S_FALSE;
998 wcscpy(*ppszName, str);
1002 if(ppObject) *ppObject = NULL;
1004 if(ppUnk) *ppUnk = NULL;
1006 return S_OK;
1009 STDMETHODIMP CDirectVobSubFilter::GetClassID(CLSID* pClsid)
1011 if(pClsid == NULL) return E_POINTER;
1012 *pClsid = m_clsid;
1013 return NOERROR;
1016 STDMETHODIMP CDirectVobSubFilter::GetPages(CAUUID* pPages)
1018 CheckPointer(pPages, E_POINTER);
1020 pPages->cElems = 8;
1021 pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID)*pPages->cElems);
1023 if(pPages->pElems == NULL) return E_OUTOFMEMORY;
1025 int i = 0;
1026 pPages->pElems[i++] = __uuidof(CDVSMainPPage);
1027 pPages->pElems[i++] = __uuidof(CDVSGeneralPPage);
1028 pPages->pElems[i++] = __uuidof(CDVSMiscPPage);
1029 pPages->pElems[i++] = __uuidof(CDVSMorePPage);
1030 pPages->pElems[i++] = __uuidof(CDVSTimingPPage);
1031 pPages->pElems[i++] = __uuidof(CDVSColorPPage);
1032 pPages->pElems[i++] = __uuidof(CDVSPathsPPage);
1033 pPages->pElems[i++] = __uuidof(CDVSAboutPPage);
1035 return NOERROR;
1038 // IDirectVobSub
1040 STDMETHODIMP CDirectVobSubFilter::put_FileName(WCHAR* fn)
1042 AMTRACE((TEXT(__FUNCTION__),0));
1043 HRESULT hr = CDirectVobSub::put_FileName(fn);
1045 if(hr == S_OK && !Open())
1047 m_FileName.Empty();
1048 hr = E_FAIL;
1051 return hr;
1054 STDMETHODIMP CDirectVobSubFilter::get_LanguageCount(int* nLangs)
1056 HRESULT hr = CDirectVobSub::get_LanguageCount(nLangs);
1058 if(hr == NOERROR && nLangs)
1060 CAutoLock cAutolock(&m_csQueueLock);
1062 *nLangs = 0;
1063 POSITION pos = m_pSubStreams.GetHeadPosition();
1064 while(pos) (*nLangs) += m_pSubStreams.GetNext(pos)->GetStreamCount();
1067 return hr;
1070 STDMETHODIMP CDirectVobSubFilter::get_LanguageName(int iLanguage, WCHAR** ppName)
1072 HRESULT hr = CDirectVobSub::get_LanguageName(iLanguage, ppName);
1074 if(!ppName) return E_POINTER;
1076 if(hr == NOERROR)
1078 CAutoLock cAutolock(&m_csQueueLock);
1080 hr = E_INVALIDARG;
1082 int i = iLanguage;
1084 POSITION pos = m_pSubStreams.GetHeadPosition();
1085 while(i >= 0 && pos)
1087 CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
1089 if(i < pSubStream->GetStreamCount())
1091 pSubStream->GetStreamInfo(i, ppName, NULL);
1092 hr = NOERROR;
1093 break;
1096 i -= pSubStream->GetStreamCount();
1100 return hr;
1103 STDMETHODIMP CDirectVobSubFilter::put_SelectedLanguage(int iSelected)
1105 HRESULT hr = CDirectVobSub::put_SelectedLanguage(iSelected);
1107 if(hr == NOERROR)
1109 UpdateSubtitle(false);
1112 return hr;
1115 STDMETHODIMP CDirectVobSubFilter::put_HideSubtitles(bool fHideSubtitles)
1117 HRESULT hr = CDirectVobSub::put_HideSubtitles(fHideSubtitles);
1119 if(hr == NOERROR)
1121 UpdateSubtitle(false);
1124 return hr;
1127 STDMETHODIMP CDirectVobSubFilter::put_PreBuffering(bool fDoPreBuffering)
1129 HRESULT hr = CDirectVobSub::put_PreBuffering(fDoPreBuffering);
1131 if(hr == NOERROR)
1133 DbgLog((LOG_TRACE, 3, "put_PreBuffering => InitSubPicQueue"));
1134 InitSubPicQueue();
1137 return hr;
1140 STDMETHODIMP CDirectVobSubFilter::put_ColourSpace(int colourSpace)
1142 CAutoLock cAutolock(&m_csQueueLock);
1143 HRESULT hr = CDirectVobSub::put_ColourSpace(colourSpace);
1145 if(hr == NOERROR)
1147 switch(m_colourSpace)
1149 case ColourSpaceOption::BT_601:
1150 ColorConvTable::SetDefaultYUVType(ColorConvTable::BT601);
1151 break;
1152 case ColourSpaceOption::BT_709:
1153 ColorConvTable::SetDefaultYUVType(ColorConvTable::BT709);
1154 break;
1155 case ColourSpaceOption::AUTO_GUESS:
1156 ColorConvTable::SetDefaultYUVType( (m_w > m_bt601Width || m_h > m_bt601Height) ?
1157 ColorConvTable::BT709 : ColorConvTable::BT601 );
1158 break;
1162 return hr;
1165 STDMETHODIMP CDirectVobSubFilter::put_Placement(bool fOverridePlacement, int xperc, int yperc)
1167 DbgLog((LOG_TRACE, 3, "%s(%d) %s", __FILE__, __LINE__, __FUNCTION__));
1168 HRESULT hr = CDirectVobSub::put_Placement(fOverridePlacement, xperc, yperc);
1170 if(hr == NOERROR)
1172 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1173 //UpdateSubtitle(true);
1174 UpdateSubtitle(false);
1177 return hr;
1180 STDMETHODIMP CDirectVobSubFilter::put_VobSubSettings(bool fBuffer, bool fOnlyShowForcedSubs, bool fReserved)
1182 HRESULT hr = CDirectVobSub::put_VobSubSettings(fBuffer, fOnlyShowForcedSubs, fReserved);
1184 if(hr == NOERROR)
1186 // UpdateSubtitle(false);
1187 InvalidateSubtitle();
1190 return hr;
1193 STDMETHODIMP CDirectVobSubFilter::put_TextSettings(void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer)
1195 HRESULT hr = CDirectVobSub::put_TextSettings(lf, lflen, color, fShadow, fOutline, fAdvancedRenderer);
1197 if(hr == NOERROR)
1199 // UpdateSubtitle(true);
1200 InvalidateSubtitle();
1203 return hr;
1206 STDMETHODIMP CDirectVobSubFilter::put_SubtitleTiming(int delay, int speedmul, int speeddiv)
1208 HRESULT hr = CDirectVobSub::put_SubtitleTiming(delay, speedmul, speeddiv);
1210 if(hr == NOERROR)
1212 InvalidateSubtitle();
1215 return hr;
1218 STDMETHODIMP CDirectVobSubFilter::put_OverlayCacheMaxItemNum( int overlay_cache_max_item_num )
1220 CAutoLock cAutolock(&m_csQueueLock);
1221 HRESULT hr = CDirectVobSub::put_OverlayCacheMaxItemNum(overlay_cache_max_item_num);
1223 if(hr == NOERROR)
1225 CacheManager::GetOverlayMruCache()->SetMaxItemNum(m_overlay_cache_max_item_num);
1228 return hr;
1231 STDMETHODIMP CDirectVobSubFilter::put_ScanLineDataCacheMaxItemNum( int scan_line_data_cache_max_item_num )
1233 CAutoLock cAutolock(&m_csQueueLock);
1234 HRESULT hr = CDirectVobSub::put_ScanLineDataCacheMaxItemNum(scan_line_data_cache_max_item_num);
1236 if(hr == NOERROR)
1238 CacheManager::GetScanLineDataMruCache()->SetMaxItemNum(m_scan_line_data_cache_max_item_num);
1241 return hr;
1244 STDMETHODIMP CDirectVobSubFilter::put_PathDataCacheMaxItemNum(int path_data_cache_max_item_num)
1246 CAutoLock cAutolock(&m_csQueueLock);
1247 HRESULT hr = CDirectVobSub::put_PathDataCacheMaxItemNum(path_data_cache_max_item_num);
1249 if(hr == NOERROR)
1251 CacheManager::GetPathDataMruCache()->SetMaxItemNum(m_path_data_cache_max_item_num);
1254 return hr;
1257 STDMETHODIMP CDirectVobSubFilter::put_OverlayNoBlurCacheMaxItemNum(int overlay_no_blur_cache_max_item_num)
1259 CAutoLock cAutolock(&m_csQueueLock);
1260 HRESULT hr = CDirectVobSub::put_OverlayNoBlurCacheMaxItemNum(overlay_no_blur_cache_max_item_num);
1262 if(hr == NOERROR)
1264 CacheManager::GetOverlayNoBlurMruCache()->SetMaxItemNum(m_overlay_no_blur_cache_max_item_num);
1267 return hr;
1270 STDMETHODIMP CDirectVobSubFilter::get_CachesInfo(CachesInfo* caches_info)
1272 CAutoLock cAutoLock(&m_csQueueLock);
1273 HRESULT hr = CDirectVobSub::get_CachesInfo(caches_info);
1275 caches_info->path_cache_cur_item_num = CacheManager::GetPathDataMruCache()->GetCurItemNum();
1276 caches_info->path_cache_hit_count = CacheManager::GetPathDataMruCache()->GetCacheHitCount();
1277 caches_info->path_cache_query_count = CacheManager::GetPathDataMruCache()->GetQueryCount();
1278 caches_info->scanline_cache_cur_item_num= CacheManager::GetScanLineDataMruCache()->GetCurItemNum();
1279 caches_info->scanline_cache_hit_count = CacheManager::GetScanLineDataMruCache()->GetCacheHitCount();
1280 caches_info->scanline_cache_query_count = CacheManager::GetScanLineDataMruCache()->GetQueryCount();
1281 caches_info->non_blur_cache_cur_item_num= CacheManager::GetOverlayNoBlurMruCache()->GetCurItemNum();
1282 caches_info->non_blur_cache_hit_count = CacheManager::GetOverlayNoBlurMruCache()->GetCacheHitCount();
1283 caches_info->non_blur_cache_query_count = CacheManager::GetOverlayNoBlurMruCache()->GetQueryCount();
1284 caches_info->overlay_cache_cur_item_num = CacheManager::GetOverlayMruCache()->GetCurItemNum();
1285 caches_info->overlay_cache_hit_count = CacheManager::GetOverlayMruCache()->GetCacheHitCount();
1286 caches_info->overlay_cache_query_count = CacheManager::GetOverlayMruCache()->GetQueryCount();
1288 caches_info->interpolate_cache_cur_item_num = CacheManager::GetSubpixelVarianceCache()->GetCurItemNum();
1289 caches_info->interpolate_cache_hit_count = CacheManager::GetSubpixelVarianceCache()->GetCacheHitCount();
1290 caches_info->interpolate_cache_query_count = CacheManager::GetSubpixelVarianceCache()->GetQueryCount();
1291 caches_info->text_info_cache_cur_item_num = CacheManager::GetTextInfoCache()->GetCurItemNum();
1292 caches_info->text_info_cache_hit_count = CacheManager::GetTextInfoCache()->GetCacheHitCount();
1293 caches_info->text_info_cache_query_count = CacheManager::GetTextInfoCache()->GetQueryCount();
1295 caches_info->word_info_cache_cur_item_num = CacheManager::GetAssTagListMruCache()->GetCurItemNum();
1296 caches_info->word_info_cache_hit_count = CacheManager::GetAssTagListMruCache()->GetCacheHitCount();
1297 caches_info->word_info_cache_query_count = CacheManager::GetAssTagListMruCache()->GetQueryCount();
1299 return hr;
1302 STDMETHODIMP CDirectVobSubFilter::put_SubpixelPositionLevel(int subpixel_pos_level)
1304 CAutoLock cAutolock(&m_csQueueLock);
1305 HRESULT hr = CDirectVobSub::put_SubpixelPositionLevel(subpixel_pos_level);
1307 if(hr == NOERROR)
1309 SubpixelPositionControler::GetGlobalControler().SetSubpixelLevel( static_cast<SubpixelPositionControler::SUBPIXEL_LEVEL>(subpixel_pos_level) );
1312 return hr;
1315 STDMETHODIMP CDirectVobSubFilter::get_MediaFPS(bool* fEnabled, double* fps)
1317 HRESULT hr = CDirectVobSub::get_MediaFPS(fEnabled, fps);
1319 CComQIPtr<IMediaSeeking> pMS = m_pGraph;
1320 double rate;
1321 if(pMS && SUCCEEDED(pMS->GetRate(&rate)))
1323 m_MediaFPS = rate * m_fps;
1324 if(fps) *fps = m_MediaFPS;
1327 return hr;
1330 STDMETHODIMP CDirectVobSubFilter::put_MediaFPS(bool fEnabled, double fps)
1332 HRESULT hr = CDirectVobSub::put_MediaFPS(fEnabled, fps);
1334 CComQIPtr<IMediaSeeking> pMS = m_pGraph;
1335 if(pMS)
1337 if(hr == NOERROR)
1339 hr = pMS->SetRate(m_fMediaFPSEnabled ? m_MediaFPS / m_fps : 1.0);
1342 double dRate;
1343 if(SUCCEEDED(pMS->GetRate(&dRate)))
1344 m_MediaFPS = dRate * m_fps;
1347 return hr;
1350 STDMETHODIMP CDirectVobSubFilter::get_ZoomRect(NORMALIZEDRECT* rect)
1352 return E_NOTIMPL;
1355 STDMETHODIMP CDirectVobSubFilter::put_ZoomRect(NORMALIZEDRECT* rect)
1357 return E_NOTIMPL;
1360 // IDirectVobSub2
1362 STDMETHODIMP CDirectVobSubFilter::put_TextSettings(STSStyle* pDefStyle)
1364 HRESULT hr = CDirectVobSub::put_TextSettings(pDefStyle);
1366 if(hr == NOERROR)
1368 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1369 //UpdateSubtitle(true);
1370 UpdateSubtitle(false);
1373 return hr;
1376 STDMETHODIMP CDirectVobSubFilter::put_AspectRatioSettings(CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType)
1378 HRESULT hr = CDirectVobSub::put_AspectRatioSettings(ePARCompensationType);
1380 if(hr == NOERROR)
1382 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1383 //UpdateSubtitle(true);
1384 UpdateSubtitle(false);
1387 return hr;
1390 // IDirectVobSubFilterColor
1392 STDMETHODIMP CDirectVobSubFilter::HasConfigDialog(int iSelected)
1394 int nLangs;
1395 if(FAILED(get_LanguageCount(&nLangs))) return E_FAIL;
1396 return E_FAIL;
1397 // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
1398 // return(nLangs >= 0 && iSelected < nLangs ? S_OK : E_FAIL);
1401 STDMETHODIMP CDirectVobSubFilter::ShowConfigDialog(int iSelected, HWND hWndParent)
1403 // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
1404 return(E_FAIL);
1407 ///////////////////////////////////////////////////////////////////////////
1409 CDirectVobSubFilter2::CDirectVobSubFilter2(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid) :
1410 CDirectVobSubFilter(punk, phr, clsid)
1414 HRESULT CDirectVobSubFilter2::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
1416 CPinInfo pi;
1417 if(FAILED(pPin->QueryPinInfo(&pi))) return E_FAIL;
1419 if(CComQIPtr<IDirectVobSub>(pi.pFilter)) return E_FAIL;
1421 if(dir == PINDIR_INPUT)
1423 CFilterInfo fi;
1424 if(SUCCEEDED(pi.pFilter->QueryFilterInfo(&fi))
1425 && !wcsnicmp(fi.achName, L"Overlay Mixer", 13))
1426 return(E_FAIL);
1428 else
1432 return __super::CheckConnect(dir, pPin);
1435 HRESULT CDirectVobSubFilter2::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
1437 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::JoinFilterGraph"));
1438 if(pGraph)
1440 BeginEnumFilters(pGraph, pEF, pBF)
1442 if(pBF != (IBaseFilter*)this && CComQIPtr<IDirectVobSub>(pBF))
1443 return E_FAIL;
1445 EndEnumFilters
1447 // don't look... we will do some serious graph hacking again...
1449 // we will add dvs2 to the filter graph cache
1450 // - if the main app has already added some kind of renderer or overlay mixer (anything which accepts video on its input)
1451 // and
1452 // - if we have a reason to auto-load (we don't want to make any trouble when there is no need :)
1454 // This whole workaround is needed because the video stream will always be connected
1455 // to the pre-added filters first, no matter how high merit we have.
1457 if(!get_Forced())
1459 BeginEnumFilters(pGraph, pEF, pBF)
1461 if(CComQIPtr<IDirectVobSub>(pBF))
1462 continue;
1464 CComPtr<IPin> pInPin = GetFirstPin(pBF, PINDIR_INPUT);
1465 CComPtr<IPin> pOutPin = GetFirstPin(pBF, PINDIR_OUTPUT);
1467 if(!pInPin)
1468 continue;
1470 CComPtr<IPin> pPin;
1471 if(pInPin && SUCCEEDED(pInPin->ConnectedTo(&pPin))
1472 || pOutPin && SUCCEEDED(pOutPin->ConnectedTo(&pPin)))
1473 continue;
1475 if(pOutPin && GetFilterName(pBF) == _T("Overlay Mixer"))
1476 continue;
1478 bool fVideoInputPin = false;
1482 BITMAPINFOHEADER bih = {sizeof(BITMAPINFOHEADER), 384, 288, 1, 16, '2YUY', 384*288*2, 0, 0, 0, 0};
1484 CMediaType cmt;
1485 cmt.majortype = MEDIATYPE_Video;
1486 cmt.subtype = MEDIASUBTYPE_YUY2;
1487 cmt.formattype = FORMAT_VideoInfo;
1488 cmt.pUnk = NULL;
1489 cmt.bFixedSizeSamples = TRUE;
1490 cmt.bTemporalCompression = TRUE;
1491 cmt.lSampleSize = 384*288*2;
1492 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
1493 memset(vih, 0, sizeof(VIDEOINFOHEADER));
1494 memcpy(&vih->bmiHeader, &bih, sizeof(bih));
1495 vih->AvgTimePerFrame = 400000;
1497 if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
1499 fVideoInputPin = true;
1500 break;
1503 VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER2));
1504 memset(vih2, 0, sizeof(VIDEOINFOHEADER2));
1505 memcpy(&vih2->bmiHeader, &bih, sizeof(bih));
1506 vih2->AvgTimePerFrame = 400000;
1507 vih2->dwPictAspectRatioX = 384;
1508 vih2->dwPictAspectRatioY = 288;
1510 if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
1512 fVideoInputPin = true;
1513 break;
1516 while(false);
1518 if(fVideoInputPin)
1520 CComPtr<IBaseFilter> pDVS;
1521 if(ShouldWeAutoload(pGraph) && SUCCEEDED(pDVS.CoCreateInstance(__uuidof(CDirectVobSubFilter2))))
1523 CComQIPtr<IDirectVobSub2>(pDVS)->put_Forced(true);
1524 CComQIPtr<IGraphConfig>(pGraph)->AddFilterToCache(pDVS);
1527 break;
1530 EndEnumFilters
1533 else
1537 return __super::JoinFilterGraph(pGraph, pName);
1540 HRESULT CDirectVobSubFilter2::CheckInputType(const CMediaType* mtIn)
1542 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::CheckInputType"));
1543 HRESULT hr = __super::CheckInputType(mtIn);
1545 if(FAILED(hr) || m_pInput->IsConnected()) return hr;
1547 if(!ShouldWeAutoload(m_pGraph)) return VFW_E_TYPE_NOT_ACCEPTED;
1549 GetRidOfInternalScriptRenderer();
1551 return NOERROR;
1554 bool CDirectVobSubFilter2::ShouldWeAutoload(IFilterGraph* pGraph)
1556 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::ShouldWeAutoload"));
1557 TCHAR blacklistedapps[][32] =
1559 _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)
1560 _T("explorer."), // as some users reported thumbnail preview loads dvobsub, I've never experienced this yet...
1561 _T("producer."), // this is real's producer
1562 _T("GoogleDesktopIndex."), // Google Desktop
1563 _T("GoogleDesktopDisplay."), // Google Desktop
1564 _T("GoogleDesktopCrawl."), // Google Desktop
1567 for(int i = 0; i < countof(blacklistedapps); i++)
1569 if(theApp.m_AppName.Find(blacklistedapps[i]) >= 0)
1570 return(false);
1573 int level;
1574 bool m_fExternalLoad, m_fWebLoad, m_fEmbeddedLoad;
1575 get_LoadSettings(&level, &m_fExternalLoad, &m_fWebLoad, &m_fEmbeddedLoad);
1577 if(level < 0 || level >= 2) return(false);
1579 bool fRet = false;
1581 if(level == 1)
1582 fRet = m_fExternalLoad = m_fWebLoad = m_fEmbeddedLoad = true;
1584 // find text stream on known splitters
1586 if(!fRet && m_fEmbeddedLoad)
1588 CComPtr<IBaseFilter> pBF;
1589 if((pBF = FindFilter(CLSID_OggSplitter, pGraph)) || (pBF = FindFilter(CLSID_AviSplitter, pGraph))
1590 || (pBF = FindFilter(L"{34293064-02F2-41D5-9D75-CC5967ACA1AB}", pGraph)) // matroska demux
1591 || (pBF = FindFilter(L"{0A68C3B5-9164-4a54-AFAF-995B2FF0E0D4}", pGraph)) // matroska source
1592 || (pBF = FindFilter(L"{149D2E01-C32E-4939-80F6-C07B81015A7A}", pGraph)) // matroska splitter
1593 || (pBF = FindFilter(L"{55DA30FC-F16B-49fc-BAA5-AE59FC65F82D}", pGraph)) // Haali Media Splitter
1594 || (pBF = FindFilter(L"{564FD788-86C9-4444-971E-CC4A243DA150}", pGraph)) // Haali Media Splitter (AR)
1595 || (pBF = FindFilter(L"{8F43B7D9-9D6B-4F48-BE18-4D787C795EEA}", pGraph)) // Haali Simple Media Splitter
1596 || (pBF = FindFilter(L"{52B63861-DC93-11CE-A099-00AA00479A58}", pGraph)) // 3ivx splitter
1597 || (pBF = FindFilter(L"{6D3688CE-3E9D-42F4-92CA-8A11119D25CD}", pGraph)) // our ogg source
1598 || (pBF = FindFilter(L"{9FF48807-E133-40AA-826F-9B2959E5232D}", pGraph)) // our ogg splitter
1599 || (pBF = FindFilter(L"{803E8280-F3CE-4201-982C-8CD8FB512004}", pGraph)) // dsm source
1600 || (pBF = FindFilter(L"{0912B4DD-A30A-4568-B590-7179EBB420EC}", pGraph)) // dsm splitter
1601 || (pBF = FindFilter(L"{3CCC052E-BDEE-408a-BEA7-90914EF2964B}", pGraph)) // mp4 source
1602 || (pBF = FindFilter(L"{61F47056-E400-43d3-AF1E-AB7DFFD4C4AD}", pGraph))) // mp4 splitter
1604 BeginEnumPins(pBF, pEP, pPin)
1606 BeginEnumMediaTypes(pPin, pEM, pmt)
1608 if(pmt->majortype == MEDIATYPE_Text || pmt->majortype == MEDIATYPE_Subtitle)
1610 fRet = true;
1611 break;
1614 EndEnumMediaTypes(pmt)
1615 if(fRet) break;
1617 EndEnumFilters
1621 // find file name
1623 CStringW fn;
1625 BeginEnumFilters(pGraph, pEF, pBF)
1627 if(CComQIPtr<IFileSourceFilter> pFSF = pBF)
1629 LPOLESTR fnw = NULL;
1630 if(!pFSF || FAILED(pFSF->GetCurFile(&fnw, NULL)) || !fnw)
1631 continue;
1632 fn = CString(fnw);
1633 CoTaskMemFree(fnw);
1634 break;
1637 EndEnumFilters
1639 if((m_fExternalLoad || m_fWebLoad) && (m_fWebLoad || !(wcsstr(fn, L"http://") || wcsstr(fn, L"mms://"))))
1641 bool fTemp = m_fHideSubtitles;
1642 fRet = !fn.IsEmpty() && SUCCEEDED(put_FileName((LPWSTR)(LPCWSTR)fn))
1643 || SUCCEEDED(put_FileName(L"c:\\tmp.srt"))
1644 || fRet;
1645 if(fTemp) m_fHideSubtitles = true;
1648 return(fRet);
1651 void CDirectVobSubFilter2::GetRidOfInternalScriptRenderer()
1653 while(CComPtr<IBaseFilter> pBF = FindFilter(L"{48025243-2D39-11CE-875D-00608CB78066}", m_pGraph))
1655 BeginEnumPins(pBF, pEP, pPin)
1657 PIN_DIRECTION dir;
1658 CComPtr<IPin> pPinTo;
1660 if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT
1661 && SUCCEEDED(pPin->ConnectedTo(&pPinTo)))
1663 m_pGraph->Disconnect(pPinTo);
1664 m_pGraph->Disconnect(pPin);
1665 m_pGraph->ConnectDirect(pPinTo, GetPin(2 + m_pTextInput.GetCount()-1), NULL);
1668 EndEnumPins
1670 if(FAILED(m_pGraph->RemoveFilter(pBF)))
1671 break;
1675 ///////////////////////////////////////////////////////////////////////////////
1677 bool CDirectVobSubFilter::Open()
1679 AMTRACE((TEXT(__FUNCTION__),0));
1680 XY_AUTO_TIMING(TEXT("CDirectVobSubFilter::Open"));
1682 AFX_MANAGE_STATE(AfxGetStaticModuleState());
1684 CAutoLock cAutolock(&m_csQueueLock);
1686 m_pSubStreams.RemoveAll();
1688 m_frd.files.RemoveAll();
1690 CAtlArray<CString> paths;
1692 for(int i = 0; i < 10; i++)
1694 CString tmp;
1695 tmp.Format(IDS_RP_PATH, i);
1696 CString path = theApp.GetProfileString(ResStr(IDS_R_DEFTEXTPATHES), tmp);
1697 if(!path.IsEmpty()) paths.Add(path);
1700 CAtlArray<SubFile> ret;
1701 GetSubFileNames(m_FileName, paths, ret);
1703 for(int i = 0; i < ret.GetCount(); i++)
1705 if(m_frd.files.Find(ret[i].fn))
1706 continue;
1708 CComPtr<ISubStream> pSubStream;
1710 if(!pSubStream)
1712 // CAutoTiming t(TEXT("CRenderedTextSubtitle::Open"), 0);
1713 XY_AUTO_TIMING(TEXT("CRenderedTextSubtitle::Open"));
1714 CAutoPtr<CRenderedTextSubtitle> pRTS(new CRenderedTextSubtitle(&m_csSubLock));
1715 if(pRTS && pRTS->Open(ret[i].fn, DEFAULT_CHARSET) && pRTS->GetStreamCount() > 0)
1717 pSubStream = pRTS.Detach();
1718 m_frd.files.AddTail(ret[i].fn + _T(".style"));
1722 if(!pSubStream)
1724 CAutoTiming t(TEXT("CVobSubFile::Open"), 0);
1725 CAutoPtr<CVobSubFile> pVSF(new CVobSubFile(&m_csSubLock));
1726 if(pVSF && pVSF->Open(ret[i].fn) && pVSF->GetStreamCount() > 0)
1728 pSubStream = pVSF.Detach();
1729 m_frd.files.AddTail(ret[i].fn.Left(ret[i].fn.GetLength()-4) + _T(".sub"));
1733 if(!pSubStream)
1735 CAutoTiming t(TEXT("ssf::CRenderer::Open"), 0);
1736 CAutoPtr<ssf::CRenderer> pSSF(new ssf::CRenderer(&m_csSubLock));
1737 if(pSSF && pSSF->Open(ret[i].fn) && pSSF->GetStreamCount() > 0)
1739 pSubStream = pSSF.Detach();
1743 if(pSubStream)
1745 m_pSubStreams.AddTail(pSubStream);
1746 m_frd.files.AddTail(ret[i].fn);
1750 for(int i = 0; i < m_pTextInput.GetCount(); i++)
1752 if(m_pTextInput[i]->IsConnected())
1753 m_pSubStreams.AddTail(m_pTextInput[i]->GetSubStream());
1756 if(S_FALSE == put_SelectedLanguage(FindPreferedLanguage()))
1757 UpdateSubtitle(false); // make sure pSubPicProvider of our queue gets updated even if the stream number hasn't changed
1759 m_frd.RefreshEvent.Set();
1761 return(m_pSubStreams.GetCount() > 0);
1764 void CDirectVobSubFilter::UpdateSubtitle(bool fApplyDefStyle)
1766 CAutoLock cAutolock(&m_csQueueLock);
1768 if(!m_pSubPicQueue) return;
1770 InvalidateSubtitle();
1772 CComPtr<ISubStream> pSubStream;
1774 if(!m_fHideSubtitles)
1776 int i = m_iSelectedLanguage;
1778 for(POSITION pos = m_pSubStreams.GetHeadPosition(); i >= 0 && pos; pSubStream = NULL)
1780 pSubStream = m_pSubStreams.GetNext(pos);
1782 if(i < pSubStream->GetStreamCount())
1784 CAutoLock cAutoLock(&m_csSubLock);
1785 pSubStream->SetStream(i);
1786 break;
1789 i -= pSubStream->GetStreamCount();
1793 SetSubtitle(pSubStream, fApplyDefStyle);
1796 void CDirectVobSubFilter::SetSubtitle(ISubStream* pSubStream, bool fApplyDefStyle)
1798 DbgLog((LOG_TRACE, 3, "%s(%d): %s", __FILE__, __LINE__, __FUNCTION__));
1799 DbgLog((LOG_TRACE, 3, "\tpSubStream:%x fApplyDefStyle:%d", pSubStream, (int)fApplyDefStyle));
1800 CAutoLock cAutolock(&m_csQueueLock);
1802 if(pSubStream)
1804 CAutoLock cAutolock(&m_csSubLock);
1806 CLSID clsid;
1807 pSubStream->GetClassID(&clsid);
1809 if(clsid == __uuidof(CVobSubFile))
1811 CVobSubSettings* pVSS = dynamic_cast<CVobSubFile*>(pSubStream);
1813 if(fApplyDefStyle)
1815 pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
1816 pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
1819 else if(clsid == __uuidof(CVobSubStream))
1821 CVobSubSettings* pVSS = dynamic_cast<CVobSubStream*>(pSubStream);
1823 if(fApplyDefStyle)
1825 pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
1826 pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
1829 else if(clsid == __uuidof(CRenderedTextSubtitle))
1831 CRenderedTextSubtitle* pRTS = dynamic_cast<CRenderedTextSubtitle*>(pSubStream);
1833 if(fApplyDefStyle || pRTS->m_fUsingAutoGeneratedDefaultStyle)
1835 STSStyle s = m_defStyle;
1837 if(m_fOverridePlacement)
1839 s.scrAlignment = 2;
1840 int w = pRTS->m_dstScreenSize.cx;
1841 int h = pRTS->m_dstScreenSize.cy;
1842 CRect tmp_rect = s.marginRect.get();
1843 int mw = w - tmp_rect.left - tmp_rect.right;
1844 tmp_rect.bottom = h - MulDiv(h, m_PlacementYperc, 100);
1845 tmp_rect.left = MulDiv(w, m_PlacementXperc, 100) - mw/2;
1846 tmp_rect.right = w - (tmp_rect.left + mw);
1847 s.marginRect = tmp_rect;
1850 pRTS->SetDefaultStyle(s);
1853 pRTS->m_ePARCompensationType = m_ePARCompensationType;
1854 if (m_CurrentVIH2.dwPictAspectRatioX != 0 && m_CurrentVIH2.dwPictAspectRatioY != 0&& m_CurrentVIH2.bmiHeader.biWidth != 0 && m_CurrentVIH2.bmiHeader.biHeight != 0)
1856 pRTS->m_dPARCompensation = ((double)abs(m_CurrentVIH2.bmiHeader.biWidth) / (double)abs(m_CurrentVIH2.bmiHeader.biHeight)) /
1857 ((double)abs((long)m_CurrentVIH2.dwPictAspectRatioX) / (double)abs((long)m_CurrentVIH2.dwPictAspectRatioY));
1860 else
1862 pRTS->m_dPARCompensation = 1.00;
1865 pRTS->Deinit();
1869 if(!fApplyDefStyle)
1871 int i = 0;
1873 POSITION pos = m_pSubStreams.GetHeadPosition();
1874 while(pos)
1876 CComPtr<ISubStream> pSubStream2 = m_pSubStreams.GetNext(pos);
1878 if(pSubStream == pSubStream2)
1880 m_iSelectedLanguage = i + pSubStream2->GetStream();
1881 break;
1884 i += pSubStream2->GetStreamCount();
1888 m_nSubtitleId = reinterpret_cast<DWORD_PTR>(pSubStream);
1890 if(m_pSubPicQueue)
1891 m_pSubPicQueue->SetSubPicProviderEx(CComQIPtr<ISubPicProviderEx>(pSubStream));
1894 void CDirectVobSubFilter::InvalidateSubtitle(REFERENCE_TIME rtInvalidate, DWORD_PTR nSubtitleId)
1896 CAutoLock cAutolock(&m_csQueueLock);
1898 if(m_pSubPicQueue)
1900 if(nSubtitleId == -1 || nSubtitleId == m_nSubtitleId)
1902 DbgLog((LOG_TRACE, 3, "InvalidateSubtitle::Invalidate"));
1903 m_pSubPicQueue->Invalidate(rtInvalidate);
1908 //////////////////////////////////////////////////////////////////////////////////////////
1910 void CDirectVobSubFilter::AddSubStream(ISubStream* pSubStream)
1912 CAutoLock cAutoLock(&m_csQueueLock);
1914 POSITION pos = m_pSubStreams.Find(pSubStream);
1915 if(!pos) m_pSubStreams.AddTail(pSubStream);
1917 int len = m_pTextInput.GetCount();
1918 for(int i = 0; i < m_pTextInput.GetCount(); i++)
1919 if(m_pTextInput[i]->IsConnected()) len--;
1921 if(len == 0)
1923 HRESULT hr = S_OK;
1924 m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
1928 void CDirectVobSubFilter::RemoveSubStream(ISubStream* pSubStream)
1930 CAutoLock cAutoLock(&m_csQueueLock);
1932 POSITION pos = m_pSubStreams.Find(pSubStream);
1933 if(pos) m_pSubStreams.RemoveAt(pos);
1936 void CDirectVobSubFilter::Post_EC_OLE_EVENT(CString str, DWORD_PTR nSubtitleId)
1938 if(nSubtitleId != -1 && nSubtitleId != m_nSubtitleId)
1939 return;
1941 CComQIPtr<IMediaEventSink> pMES = m_pGraph;
1942 if(!pMES) return;
1944 CComBSTR bstr1("Text"), bstr2(" ");
1946 str.Trim();
1947 if(!str.IsEmpty()) bstr2 = CStringA(str);
1949 pMES->Notify(EC_OLE_EVENT, (LONG_PTR)bstr1.Detach(), (LONG_PTR)bstr2.Detach());
1952 ////////////////////////////////////////////////////////////////
1954 void CDirectVobSubFilter::SetupFRD(CStringArray& paths, CAtlArray<HANDLE>& handles)
1956 CAutoLock cAutolock(&m_csSubLock);
1958 for(int i = 2; i < handles.GetCount(); i++)
1960 FindCloseChangeNotification(handles[i]);
1963 paths.RemoveAll();
1964 handles.RemoveAll();
1966 handles.Add(m_frd.EndThreadEvent);
1967 handles.Add(m_frd.RefreshEvent);
1969 m_frd.mtime.SetCount(m_frd.files.GetCount());
1971 POSITION pos = m_frd.files.GetHeadPosition();
1972 for(int i = 0; pos; i++)
1974 CString fn = m_frd.files.GetNext(pos);
1976 CFileStatus status;
1977 if(CFileGetStatus(fn, status))
1978 m_frd.mtime[i] = status.m_mtime;
1980 fn.Replace('\\', '/');
1981 fn = fn.Left(fn.ReverseFind('/')+1);
1983 bool fFound = false;
1985 for(int j = 0; !fFound && j < paths.GetCount(); j++)
1987 if(paths[j] == fn) fFound = true;
1990 if(!fFound)
1992 paths.Add(fn);
1994 HANDLE h = FindFirstChangeNotification(fn, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
1995 if(h != INVALID_HANDLE_VALUE) handles.Add(h);
2000 DWORD CDirectVobSubFilter::ThreadProc()
2002 SetThreadPriority(m_hThread, THREAD_PRIORITY_LOWEST/*THREAD_PRIORITY_BELOW_NORMAL*/);
2004 CStringArray paths;
2005 CAtlArray<HANDLE> handles;
2007 SetupFRD(paths, handles);
2009 while(1)
2011 DWORD idx = WaitForMultipleObjects(handles.GetCount(), handles.GetData(), FALSE, INFINITE);
2013 if(idx == (WAIT_OBJECT_0 + 0)) // m_frd.hEndThreadEvent
2015 break;
2017 if(idx == (WAIT_OBJECT_0 + 1)) // m_frd.hRefreshEvent
2019 SetupFRD(paths, handles);
2021 else if(idx >= (WAIT_OBJECT_0 + 2) && idx < (WAIT_OBJECT_0 + handles.GetCount()))
2023 bool fLocked = true;
2024 IsSubtitleReloaderLocked(&fLocked);
2025 if(fLocked) continue;
2027 if(FindNextChangeNotification(handles[idx - WAIT_OBJECT_0]) == FALSE)
2028 break;
2030 int j = 0;
2032 POSITION pos = m_frd.files.GetHeadPosition();
2033 for(int i = 0; pos && j == 0; i++)
2035 CString fn = m_frd.files.GetNext(pos);
2037 CFileStatus status;
2038 if(CFileGetStatus(fn, status) && m_frd.mtime[i] != status.m_mtime)
2040 for(j = 0; j < 10; j++)
2042 if(FILE* f = _tfopen(fn, _T("rb+")))
2044 fclose(f);
2045 j = 0;
2046 break;
2048 else
2050 Sleep(100);
2051 j++;
2057 if(j > 0)
2059 SetupFRD(paths, handles);
2061 else
2063 Sleep(500);
2065 POSITION pos = m_frd.files.GetHeadPosition();
2066 for(int i = 0; pos; i++)
2068 CFileStatus status;
2069 if(CFileGetStatus(m_frd.files.GetNext(pos), status)
2070 && m_frd.mtime[i] != status.m_mtime)
2072 Open();
2073 SetupFRD(paths, handles);
2074 break;
2079 else
2081 break;
2085 for(int i = 2; i < handles.GetCount(); i++)
2087 FindCloseChangeNotification(handles[i]);
2090 return 0;