MPC-HC 78f4dc6180ff69bf1ad59960ff51bef80655ce65 Fix: VSFilter might not load when...
[xy_vsfilter.git] / src / filters / transform / vsfilter / DirectVobSubFilter.cpp
blobe508175ecff8a259b7064c469daf06287a8eee3d
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/SimpleSubPicProviderImpl.h"
32 #include "../../../SubPic/PooledSubPic.h"
33 #include "../../../subpic/color_conv_table.h"
34 #include "../../../subpic/SimpleSubPicWrapper.h"
36 #include <initguid.h>
37 #include "..\..\..\..\include\moreuuids.h"
39 #include "CAutoTiming.h"
40 #include "xy_logger.h"
43 #define MAX_SUBPIC_QUEUE_LENGTH 1
45 ///////////////////////////////////////////////////////////////////////////
47 /*removeme*/
48 bool g_RegOK = true;//false; // doesn't work with the dvd graph builder
49 #include "valami.cpp"
51 #ifdef __DO_LOG
52 EXTERN_C IMAGE_DOS_HEADER __ImageBase;
53 #endif
55 using namespace DirectVobSubXyOptions;
57 ////////////////////////////////////////////////////////////////////////////
59 // Constructor
62 CDirectVobSubFilter::CDirectVobSubFilter(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid)
63 : CBaseVideoFilter(NAME("CDirectVobSubFilter"), punk, phr, clsid)
64 , m_nSubtitleId(-1)
65 , m_fMSMpeg4Fix(false)
66 , m_fps(25)
68 DbgLog((LOG_TRACE, 3, _T("CDirectVobSubFilter::CDirectVobSubFilter")));
70 // and then, anywhere you need it:
72 #ifdef __DO_LOG
73 LPTSTR strDLLPath = new TCHAR[_MAX_PATH];
74 ::GetModuleFileName( reinterpret_cast<HINSTANCE>(&__ImageBase), strDLLPath, _MAX_PATH);
75 CString dllPath = strDLLPath;
76 dllPath += ".properties";
77 xy_logger::doConfigure( dllPath.GetString() );
78 #endif
80 AFX_MANAGE_STATE(AfxGetStaticModuleState());
82 m_hdc = 0;
83 m_hbm = 0;
84 m_hfont = 0;
87 LOGFONT lf;
88 memset(&lf, 0, sizeof(lf));
89 lf.lfCharSet = DEFAULT_CHARSET;
90 lf.lfOutPrecision = OUT_CHARACTER_PRECIS;
91 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
92 lf.lfQuality = ANTIALIASED_QUALITY;
93 HDC hdc = GetDC(NULL);
94 lf.lfHeight = 28;
95 //MulDiv(20, GetDeviceCaps(hdc, LOGPIXELSY), 54);
96 ReleaseDC(NULL, hdc);
97 lf.lfWeight = FW_BOLD;
98 _tcscpy(lf.lfFaceName, _T("Arial"));
99 m_hfont = CreateFontIndirect(&lf);
102 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Hint"), _T("The first three are fixed, but you can add more up to ten entries."));
103 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path0"), _T("."));
104 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path1"), _T("c:\\subtitles"));
105 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path2"), _T(".\\subtitles"));
107 m_fLoading = true;
109 m_hSystrayThread = 0;
110 m_tbid.hSystrayWnd = NULL;
111 m_tbid.graph = NULL;
112 m_tbid.fRunOnce = false;
113 m_tbid.fShowIcon = (theApp.m_AppName.Find(_T("zplayer"), 0) < 0 || !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_ENABLEZPICON), 0));
115 HRESULT hr = S_OK;
116 m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
117 ASSERT(SUCCEEDED(hr));
119 CAMThread::Create();
120 m_frd.EndThreadEvent.Create(0, FALSE, FALSE, 0);
121 m_frd.RefreshEvent.Create(0, FALSE, FALSE, 0);
123 memset(&m_CurrentVIH2, 0, sizeof(VIDEOINFOHEADER2));
125 m_donot_follow_upstream_preferred_order = !m_xy_bool_opt[BOOL_FOLLOW_UPSTREAM_PREFERRED_ORDER];
127 m_time_alphablt = m_time_rasterization = 0;
129 m_script_selected_yuv = CSimpleTextSubtitle::YCbCrMatrix_AUTO;
130 m_script_selected_range = CSimpleTextSubtitle::YCbCrRange_AUTO;
133 CDirectVobSubFilter::~CDirectVobSubFilter()
135 CAutoLock cAutoLock(&m_csQueueLock);
136 if(m_simple_provider)
138 DbgLog((LOG_TRACE, 3, "~CDirectVobSubFilter::Invalidate"));
139 m_simple_provider->Invalidate();
141 m_simple_provider = NULL;
143 if(m_hfont) {DeleteObject(m_hfont); m_hfont = 0;}
144 if(m_hbm) {DeleteObject(m_hbm); m_hbm = 0;}
145 if(m_hdc) {DeleteObject(m_hdc); m_hdc = 0;}
147 for(size_t i = 0; i < m_pTextInput.GetCount(); i++)
148 delete m_pTextInput[i];
150 m_frd.EndThreadEvent.Set();
151 CAMThread::Close();
153 DbgLog((LOG_TRACE, 3, _T("CDirectVobSubFilter::~CDirectVobSubFilter")));
155 //Trace(_T("CDirectVobSubFilter::~CDirectVobSubFilter"));
156 //ReleaseTracer;
159 STDMETHODIMP CDirectVobSubFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
161 CheckPointer(ppv, E_POINTER);
163 return
164 QI(IDirectVobSub)
165 QI(IDirectVobSub2)
166 QI(IDirectVobSubXy)
167 QI(IFilterVersion)
168 QI(ISpecifyPropertyPages)
169 QI(IAMStreamSelect)
170 __super::NonDelegatingQueryInterface(riid, ppv);
173 // CBaseVideoFilter
175 void CDirectVobSubFilter::GetOutputSize(int& w, int& h, int& arx, int& ary)
177 CSize s(w, h), os = s;
178 AdjustFrameSize(s);
179 w = s.cx;
180 h = s.cy;
182 if(w != os.cx)
184 while(arx < 100) arx *= 10, ary *= 10;
185 arx = arx * w / os.cx;
188 if(h != os.cy)
190 while(ary < 100) arx *= 10, ary *= 10;
191 ary = ary * h / os.cy;
195 HRESULT CDirectVobSubFilter::TryNotCopy(IMediaSample* pIn, const CMediaType& mt, const BITMAPINFOHEADER& bihIn )
197 CSize sub(m_w, m_h);
198 CSize in(bihIn.biWidth, bihIn.biHeight);
199 BYTE* pDataIn = NULL;
200 if(FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn)
201 return S_FALSE;
202 if( sub==in )
204 m_spd.bits = pDataIn;
206 else
208 m_spd.bits = static_cast<BYTE*>(m_pTempPicBuff);
209 bool fYV12 = (mt.subtype == MEDIASUBTYPE_YV12 || mt.subtype == MEDIASUBTYPE_I420 || mt.subtype == MEDIASUBTYPE_IYUV);
210 bool fNV12 = (mt.subtype == MEDIASUBTYPE_NV12 || mt.subtype == MEDIASUBTYPE_NV21);
211 bool fP010 = (mt.subtype == MEDIASUBTYPE_P010 || mt.subtype == MEDIASUBTYPE_P016);
213 int bpp = fP010 ? 16 : (fYV12||fNV12) ? 8 : bihIn.biBitCount;
214 DWORD black = fP010 ? 0x10001000 : (fYV12||fNV12) ? 0x10101010 : (bihIn.biCompression == '2YUY') ? 0x80108010 : 0;
217 if(FAILED(Copy((BYTE*)m_pTempPicBuff, pDataIn, sub, in, bpp, mt.subtype, black)))
218 return E_FAIL;
220 if(fYV12)
222 BYTE* pSubV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
223 BYTE* pInV = pDataIn + (in.cx*bpp>>3)*in.cy;
224 sub.cx >>= 1; sub.cy >>= 1; in.cx >>= 1; in.cy >>= 1;
225 BYTE* pSubU = pSubV + (sub.cx*bpp>>3)*sub.cy;
226 BYTE* pInU = pInV + (in.cx*bpp>>3)*in.cy;
227 if(FAILED(Copy(pSubV, pInV, sub, in, bpp, mt.subtype, 0x80808080)))
228 return E_FAIL;
229 if(FAILED(Copy(pSubU, pInU, sub, in, bpp, mt.subtype, 0x80808080)))
230 return E_FAIL;
232 else if (fP010)
234 BYTE* pSubUV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
235 BYTE* pInUV = pDataIn + (in.cx*bpp>>3)*in.cy;
236 sub.cy >>= 1; in.cy >>= 1;
237 if(FAILED(Copy(pSubUV, pInUV, sub, in, bpp, mt.subtype, 0x80008000)))
238 return E_FAIL;
240 else if(fNV12) {
241 BYTE* pSubUV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
242 BYTE* pInUV = pDataIn + (in.cx*bpp>>3)*in.cy;
243 sub.cy >>= 1;
244 in.cy >>= 1;
245 if(FAILED(Copy(pSubUV, pInUV, sub, in, bpp, mt.subtype, 0x80808080)))
246 return E_FAIL;
249 return S_OK;
252 HRESULT CDirectVobSubFilter::Transform(IMediaSample* pIn)
254 XY_LOG_ONCE(0, _T("CDirectVobSubFilter::Transform"));
255 HRESULT hr;
258 REFERENCE_TIME rtStart, rtStop;
259 if(SUCCEEDED(pIn->GetTime(&rtStart, &rtStop)))
261 double dRate = m_pInput->CurrentRate();
263 m_tPrev = m_pInput->CurrentStartTime() + dRate*rtStart;
265 REFERENCE_TIME rtAvgTimePerFrame = rtStop - rtStart;
266 if(CComQIPtr<ISubClock2> pSC2 = m_pSubClock)
268 REFERENCE_TIME rt;
269 if(S_OK == pSC2->GetAvgTimePerFrame(&rt))
270 rtAvgTimePerFrame = rt;
273 m_fps = 10000000.0/rtAvgTimePerFrame / dRate;
279 CAutoLock cAutoLock(&m_csQueueLock);
281 if(m_simple_provider)
283 m_simple_provider->SetTime(CalcCurrentTime());
284 m_simple_provider->SetFPS(m_fps);
291 const CMediaType& mt = m_pInput->CurrentMediaType();
293 BITMAPINFOHEADER bihIn;
294 ExtractBIH(&mt, &bihIn);
296 hr = TryNotCopy(pIn, mt, bihIn);
297 if( hr!=S_OK )
299 //fix me: log error
300 return hr;
304 SubPicDesc spd = m_spd;
306 CComPtr<IMediaSample> pOut;
307 BYTE* pDataOut = NULL;
308 if(FAILED(hr = GetDeliveryBuffer(spd.w, spd.h, &pOut))
309 || FAILED(hr = pOut->GetPointer(&pDataOut)))
310 return hr;
311 pOut->SetTime(&rtStart, &rtStop);
312 pOut->SetMediaTime(NULL, NULL);
313 pOut->SetDiscontinuity(pIn->IsDiscontinuity() == S_OK);
314 pOut->SetSyncPoint(pIn->IsSyncPoint() == S_OK);
315 pOut->SetPreroll(pIn->IsPreroll() == S_OK);
318 BITMAPINFOHEADER bihOut;
319 ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
321 bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3;
322 bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3;
324 bool fFlip = fInputFlipped != fOutputFlipped;
325 if(m_fFlipPicture) fFlip = !fFlip;
326 if(m_fMSMpeg4Fix) fFlip = !fFlip;
328 bool fFlipSub = fOutputFlipped;
329 if(m_fFlipSubtitles) fFlipSub = !fFlipSub;
334 CAutoLock cAutoLock(&m_csQueueLock);
336 if(m_simple_provider)
338 CComPtr<ISimpleSubPic> pSubPic;
339 //int timeStamp1 = GetTickCount();
340 bool lookupResult = m_simple_provider->LookupSubPic(CalcCurrentTime(), &pSubPic);
341 //int timeStamp2 = GetTickCount();
342 //m_time_rasterization += timeStamp2-timeStamp1;
344 if(lookupResult && pSubPic)
346 if(fFlip ^ fFlipSub)
347 spd.h = -spd.h;
348 pSubPic->AlphaBlt(&spd);
349 DbgLog((LOG_TRACE,3,"AlphaBlt time:%lu", (ULONG)(CalcCurrentTime()/10000)));
353 CopyBuffer(pDataOut, (BYTE*)spd.bits, spd.w, abs(spd.h)*(fFlip?-1:1), spd.pitch, mt.subtype);
355 PrintMessages(pDataOut);
356 return m_pOutput->Deliver(pOut);
359 // CBaseFilter
361 CBasePin* CDirectVobSubFilter::GetPin(int n)
363 if(n < __super::GetPinCount())
364 return __super::GetPin(n);
366 n -= __super::GetPinCount();
368 if(n >= 0 && n < m_pTextInput.GetCount())
369 return m_pTextInput[n];
371 n -= m_pTextInput.GetCount();
373 return NULL;
376 int CDirectVobSubFilter::GetPinCount()
378 return __super::GetPinCount() + m_pTextInput.GetCount();
381 HRESULT CDirectVobSubFilter::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
383 if(pGraph)
385 AFX_MANAGE_STATE(AfxGetStaticModuleState());
387 if(!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 0))
389 unsigned __int64 ver = GetFileVersion(_T("divx_c32.ax"));
390 if(((ver >> 48)&0xffff) == 4 && ((ver >> 32)&0xffff) == 2)
392 DWORD dwVersion = GetVersion();
393 DWORD dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
394 DWORD dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
396 if(dwVersion < 0x80000000 && dwWindowsMajorVersion >= 5)
398 AfxMessageBox(IDS_DIVX_WARNING);
399 theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 1);
404 /*removeme*/
405 if(!g_RegOK)
407 DllRegisterServer();
408 g_RegOK = true;
411 else
413 if(m_hSystrayThread)
415 SendMessage(m_tbid.hSystrayWnd, WM_CLOSE, 0, 0);
417 if(WaitForSingleObject(m_hSystrayThread, 10000) != WAIT_OBJECT_0)
419 DbgLog((LOG_TRACE, 0, _T("CALL THE AMBULANCE!!!")));
420 TerminateThread(m_hSystrayThread, (DWORD)-1);
423 m_hSystrayThread = 0;
427 return __super::JoinFilterGraph(pGraph, pName);
430 STDMETHODIMP CDirectVobSubFilter::QueryFilterInfo(FILTER_INFO* pInfo)
432 CheckPointer(pInfo, E_POINTER);
433 ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO));
435 if(!get_Forced())
436 return __super::QueryFilterInfo(pInfo);
438 wcscpy(pInfo->achName, L"DirectVobSub (forced auto-loading version)");
439 if(pInfo->pGraph = m_pGraph) m_pGraph->AddRef();
441 return S_OK;
444 // CTransformFilter
446 HRESULT CDirectVobSubFilter::SetMediaType(PIN_DIRECTION dir, const CMediaType* pmt)
448 HRESULT hr = __super::SetMediaType(dir, pmt);
449 if(FAILED(hr)) return hr;
451 if(dir == PINDIR_INPUT)
453 CAutoLock cAutoLock(&m_csReceive);
455 REFERENCE_TIME atpf =
456 pmt->formattype == FORMAT_VideoInfo ? ((VIDEOINFOHEADER*)pmt->Format())->AvgTimePerFrame :
457 pmt->formattype == FORMAT_VideoInfo2 ? ((VIDEOINFOHEADER2*)pmt->Format())->AvgTimePerFrame :
460 m_fps = atpf ? 10000000.0 / atpf : 25;
462 if (pmt->formattype == FORMAT_VideoInfo2)
463 m_CurrentVIH2 = *(VIDEOINFOHEADER2*)pmt->Format();
465 DbgLog((LOG_TRACE, 3, "SetMediaType => InitSubPicQueue"));
466 InitSubPicQueue();
468 else if(dir == PINDIR_OUTPUT)
473 return hr;
476 HRESULT CDirectVobSubFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
478 if(dir == PINDIR_INPUT)
481 else if(dir == PINDIR_OUTPUT)
483 /*removeme*/
484 if(HmGyanusVagyTeNekem(pPin)) return(E_FAIL);
487 return __super::CheckConnect(dir, pPin);
490 HRESULT CDirectVobSubFilter::CompleteConnect(PIN_DIRECTION dir, IPin* pReceivePin)
492 bool reconnected = false;
493 if(dir == PINDIR_INPUT)
495 DbgLog((LOG_TRACE, 3, TEXT("connect input")));
496 DumpGraph(m_pGraph,0);
497 CComPtr<IBaseFilter> pFilter;
499 // needed when we have a decoder with a version number of 3.x
500 if(SUCCEEDED(m_pGraph->FindFilterByName(L"DivX MPEG-4 DVD Video Decompressor ", &pFilter))
501 && (GetFileVersion(_T("divx_c32.ax")) >> 48) <= 4
502 || SUCCEEDED(m_pGraph->FindFilterByName(L"Microcrap MPEG-4 Video Decompressor", &pFilter))
503 || SUCCEEDED(m_pGraph->FindFilterByName(L"Microsoft MPEG-4 Video Decompressor", &pFilter))
504 && (GetFileVersion(_T("mpg4ds32.ax")) >> 48) <= 3)
506 m_fMSMpeg4Fix = true;
509 else if(dir == PINDIR_OUTPUT)
511 DbgLog((LOG_TRACE, 3, TEXT("connect output")));
512 DumpGraph(m_pGraph,0);
513 const CMediaType* mtIn = &(m_pInput->CurrentMediaType());
514 const CMediaType* mtOut = &(m_pOutput->CurrentMediaType());
515 CMediaType desiredMt;
516 int position = 0;
517 HRESULT hr;
519 bool can_reconnect = false;
520 bool can_transform = (DoCheckTransform(mtIn, mtOut, true)==S_OK);
521 if( mtIn->subtype!=mtOut->subtype )
523 position = GetOutputSubtypePosition(mtOut->subtype);
524 if(position>=0)
526 hr = GetMediaType(position, &desiredMt);
527 if (hr!=S_OK)
529 DbgLog((LOG_ERROR, 3, TEXT("Unexpected error when GetMediaType, position:%d"), position));
531 else
533 hr = DoCheckTransform(&desiredMt, mtOut, true);
534 if (hr!=S_OK)
536 DbgLog((LOG_TRACE, 3, TEXT("Transform not accept:")));
537 DisplayType(0,&desiredMt);
538 DisplayType(0,mtOut);
540 else
542 hr = m_pInput->GetConnected()->QueryAccept(&desiredMt);
543 if(hr!=S_OK)
545 DbgLog((LOG_TRACE, 3, TEXT("Upstream not accept:")));
546 DisplayType(0, &desiredMt);
548 else
550 can_reconnect = true;
551 DbgLog((LOG_ERROR, 3, TEXT("Can use the same subtype!")));
556 else
558 DbgLog((LOG_ERROR, 3, TEXT("Cannot use the same subtype!")));
561 if(!can_reconnect && !can_transform)
563 position = 0;
566 hr = GetMediaType(position, &desiredMt);
567 ++position;
568 //if( FAILED(hr) )
569 if( hr!=S_OK )
570 break;
572 DbgLog((LOG_TRACE, 3, TEXT("Checking reconnect with media type:")));
573 DisplayType(0, &desiredMt);
575 if( DoCheckTransform(&desiredMt, mtOut, true)!=S_OK ||
576 m_pInput->GetConnected()->QueryAccept(&desiredMt)!=S_OK )
578 continue;
580 else
582 can_reconnect = true;
583 break;
585 } while ( true );
587 if ( can_reconnect )
589 if (SUCCEEDED(ReconnectPin(m_pInput, &desiredMt)))
591 reconnected = true;
592 DumpGraph(m_pGraph,0);
593 //m_pInput->SetMediaType(&desiredMt);
594 DbgLog((LOG_TRACE, 3, TEXT("reconnected succeed!")));
597 else if(!can_transform)
599 DbgLog((LOG_TRACE, 3, TEXT("Failed to agree reconnect type!")));
600 if(m_pInput->IsConnected())
602 m_pInput->GetConnected()->Disconnect();
603 m_pInput->Disconnect();
605 if(m_pOutput->IsConnected())
607 m_pOutput->GetConnected()->Disconnect();
608 m_pOutput->Disconnect();
610 return VFW_E_TYPE_NOT_ACCEPTED;
613 if (!reconnected && m_pOutput->IsConnected())
615 if(!m_hSystrayThread && !m_xy_bool_opt[BOOL_HIDE_TRAY_ICON])
617 m_tbid.graph = m_pGraph;
618 m_tbid.dvs = static_cast<IDirectVobSub*>(this);
620 DWORD tid;
621 m_hSystrayThread = CreateThread(0, 0, SystrayThreadProc, &m_tbid, 0, &tid);
623 m_pInput->SetMediaType( &m_pInput->CurrentMediaType() );
626 HRESULT hr = __super::CompleteConnect(dir, pReceivePin);
627 DbgLog((LOG_TRACE, 3, TEXT("connect fininshed!")));
628 DumpGraph(m_pGraph,0);
629 return hr;
632 HRESULT CDirectVobSubFilter::BreakConnect(PIN_DIRECTION dir)
634 if(dir == PINDIR_INPUT)
636 //if(m_pOutput->IsConnected())
638 // m_pOutput->GetConnected()->Disconnect();
639 // m_pOutput->Disconnect();
642 else if(dir == PINDIR_OUTPUT)
644 // not really needed, but may free up a little memory
645 CAutoLock cAutoLock(&m_csQueueLock);
646 m_simple_provider = NULL;
649 return __super::BreakConnect(dir);
652 HRESULT CDirectVobSubFilter::StartStreaming()
654 /* WARNING: calls to m_pGraph member functions from within this function will generate deadlock with Haali
655 * Video Renderer in MPC. Reason is that CAutoLock's variables in IFilterGraph functions are overriden by
656 * CFGManager class.
659 m_fLoading = false;
661 DbgLog((LOG_TRACE, 3, "StartStreaming => InitSubPicQueue"));
662 InitSubPicQueue();
664 m_tbid.fRunOnce = true;
666 put_MediaFPS(m_fMediaFPSEnabled, m_MediaFPS);
668 return __super::StartStreaming();
671 HRESULT CDirectVobSubFilter::StopStreaming()
673 InvalidateSubtitle();
675 //xy Timing
676 //FILE * timingFile = fopen("C:\\vsfilter_timing.txt", "at");
677 //fprintf(timingFile, "%s:%ld %s:%ld\n", "m_time_alphablt", m_time_alphablt, "m_time_rasterization", m_time_rasterization);
678 //fclose(timingFile);
680 return __super::StopStreaming();
683 HRESULT CDirectVobSubFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
685 m_tPrev = tStart;
686 return __super::NewSegment(tStart, tStop, dRate);
691 REFERENCE_TIME CDirectVobSubFilter::CalcCurrentTime()
693 REFERENCE_TIME rt = m_pSubClock ? m_pSubClock->GetTime() : m_tPrev;
694 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)
697 void CDirectVobSubFilter::InitSubPicQueue()
699 CAutoLock cAutoLock(&m_csQueueLock);
701 CacheManager::GetPathDataMruCache()->SetMaxItemNum(m_xy_int_opt[INT_PATH_DATA_CACHE_MAX_ITEM_NUM]);
702 CacheManager::GetScanLineData2MruCache()->SetMaxItemNum(m_xy_int_opt[INT_SCAN_LINE_DATA_CACHE_MAX_ITEM_NUM]);
703 CacheManager::GetOverlayNoBlurMruCache()->SetMaxItemNum(m_xy_int_opt[INT_OVERLAY_NO_BLUR_CACHE_MAX_ITEM_NUM]);
704 CacheManager::GetOverlayMruCache()->SetMaxItemNum(m_xy_int_opt[INT_OVERLAY_CACHE_MAX_ITEM_NUM]);
706 XyFwGroupedDrawItemsHashKey::GetCacher()->SetMaxItemNum(m_xy_int_opt[INT_BITMAP_MRU_CACHE_ITEM_NUM]);
707 CacheManager::GetBitmapMruCache()->SetMaxItemNum(m_xy_int_opt[INT_BITMAP_MRU_CACHE_ITEM_NUM]);
709 CacheManager::GetClipperAlphaMaskMruCache()->SetMaxItemNum(m_xy_int_opt[INT_CLIPPER_MRU_CACHE_ITEM_NUM]);
710 CacheManager::GetTextInfoCache()->SetMaxItemNum(m_xy_int_opt[INT_TEXT_INFO_CACHE_ITEM_NUM]);
711 CacheManager::GetAssTagListMruCache()->SetMaxItemNum(m_xy_int_opt[INT_ASS_TAG_LIST_CACHE_ITEM_NUM]);
713 SubpixelPositionControler::GetGlobalControler().SetSubpixelLevel( static_cast<SubpixelPositionControler::SUBPIXEL_LEVEL>(m_xy_int_opt[INT_SUBPIXEL_POS_LEVEL]) );
715 m_simple_provider = NULL;
717 const GUID& subtype = m_pInput->CurrentMediaType().subtype;
719 BITMAPINFOHEADER bihIn;
720 ExtractBIH(&m_pInput->CurrentMediaType(), &bihIn);
722 m_spd.type = -1;
724 if(subtype == MEDIASUBTYPE_YV12) m_spd.type = MSP_YV12;
725 else if(subtype == MEDIASUBTYPE_P010) m_spd.type = MSP_P010;
726 else if(subtype == MEDIASUBTYPE_P016) m_spd.type = MSP_P016;
727 else if(subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV) m_spd.type = MSP_IYUV;
728 else if(subtype == MEDIASUBTYPE_YUY2) m_spd.type = MSP_YUY2;
729 else if(subtype == MEDIASUBTYPE_RGB32) m_spd.type = MSP_RGB32;
730 else if(subtype == MEDIASUBTYPE_RGB24) m_spd.type = MSP_RGB24;
731 else if(subtype == MEDIASUBTYPE_RGB565) m_spd.type = MSP_RGB16;
732 else if(subtype == MEDIASUBTYPE_RGB555) m_spd.type = MSP_RGB15;
733 else if(subtype == MEDIASUBTYPE_NV12) m_spd.type = MSP_NV12;
734 else if(subtype == MEDIASUBTYPE_NV21) m_spd.type = MSP_NV21;
735 else if(subtype == MEDIASUBTYPE_AYUV) m_spd.type = MSP_AYUV;
737 m_spd.w = m_w;
738 m_spd.h = m_h;
739 m_spd.bpp = (m_spd.type == MSP_P010 || m_spd.type == MSP_P016) ? 16 :
740 (m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV || m_spd.type == MSP_NV12 || m_spd.type == MSP_NV21) ? 8 : bihIn.biBitCount;
741 m_spd.pitch = m_spd.w*m_spd.bpp>>3;
743 m_pTempPicBuff.Free();
744 if(m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV || m_spd.type == MSP_NV12 || m_spd.type == MSP_NV21)
745 m_pTempPicBuff.Allocate(4*m_spd.pitch*m_spd.h);//fix me: can be smaller
746 else if(m_spd.type == MSP_P010 || m_spd.type == MSP_P016)
747 m_pTempPicBuff.Allocate(m_spd.pitch*m_spd.h+m_spd.pitch*m_spd.h/2);
748 else
749 m_pTempPicBuff.Allocate(m_spd.pitch*m_spd.h);
750 m_spd.bits = (void*)m_pTempPicBuff;
752 CSize video(bihIn.biWidth, bihIn.biHeight), window = video;
753 if(AdjustFrameSize(window)) video += video;
754 ASSERT(window == CSize(m_w, m_h));
755 CRect video_rect(CPoint((window.cx - video.cx)/2, (window.cy - video.cy)/2), video);
757 HRESULT hr = S_OK;
758 //m_pSubPicQueue = m_fDoPreBuffering
759 // ? (ISubPicQueue*)new CSubPicQueue(MAX_SUBPIC_QUEUE_LENGTH, pSubPicAllocator, &hr)
760 // : (ISubPicQueue*)new CSubPicQueueNoThread(pSubPicAllocator, &hr);
761 m_simple_provider = new SimpleSubPicProvider2(m_spd.type, CSize(m_w, m_h), window, video_rect, this, &hr);
763 if(FAILED(hr)) m_simple_provider = NULL;
765 XySetSize(DirectVobSubXyOptions::SIZE_ORIGINAL_VIDEO, CSize(m_w, m_h));
766 UpdateSubtitle(false);
768 if(m_hbm) {DeleteObject(m_hbm); m_hbm = NULL;}
769 if(m_hdc) {DeleteDC(m_hdc); m_hdc = NULL;}
771 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};
772 m_hdc = CreateCompatibleDC(NULL);
773 m_hbm = CreateDIBSection(m_hdc, (BITMAPINFO*)&b, DIB_RGB_COLORS, NULL, NULL, 0);
775 BITMAP bm;
776 GetObject(m_hbm, sizeof(bm), &bm);
777 memsetd(bm.bmBits, 0xFF000000, bm.bmHeight*bm.bmWidthBytes);
780 bool CDirectVobSubFilter::AdjustFrameSize(CSize& s)
782 int horizontal, vertical, resx2, resx2minw, resx2minh;
783 get_ExtendPicture(&horizontal, &vertical, &resx2, &resx2minw, &resx2minh);
785 bool fRet = (resx2 == 1) || (resx2 == 2 && s.cx*s.cy <= resx2minw*resx2minh);
787 if(fRet)
789 s.cx <<= 1;
790 s.cy <<= 1;
793 int h;
794 switch(vertical&0x7f)
796 case 1:
797 h = s.cx * 9 / 16;
798 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
799 break;
800 case 2:
801 h = s.cx * 3 / 4;
802 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
803 break;
804 case 3:
805 h = 480;
806 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
807 break;
808 case 4:
809 h = 576;
810 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
811 break;
814 if(horizontal == 1)
816 s.cx = (s.cx + 31) & ~31;
817 s.cy = (s.cy + 1) & ~1;
820 return(fRet);
823 STDMETHODIMP CDirectVobSubFilter::Count(DWORD* pcStreams)
825 if(!pcStreams) return E_POINTER;
827 *pcStreams = 0;
829 int nLangs = 0;
830 if(SUCCEEDED(get_LanguageCount(&nLangs)))
831 (*pcStreams) += nLangs;
833 (*pcStreams) += 2; // enable ... disable
835 (*pcStreams) += 2; // normal flipped
837 return S_OK;
840 #define MAXPREFLANGS 5
842 int CDirectVobSubFilter::FindPreferedLanguage(bool fHideToo)
844 AFX_MANAGE_STATE(AfxGetStaticModuleState());
846 int nLangs;
847 get_LanguageCount(&nLangs);
849 if(nLangs <= 0) return(0);
851 for(int i = 0; i < MAXPREFLANGS; i++)
853 CString tmp;
854 tmp.Format(IDS_RL_LANG, i);
856 CString lang = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
858 if(!lang.IsEmpty())
860 for(int ret = 0; ret < nLangs; ret++)
862 CString l;
863 WCHAR* pName = NULL;
864 get_LanguageName(ret, &pName);
865 l = pName;
866 CoTaskMemFree(pName);
868 if(!l.CompareNoCase(lang)) return(ret);
873 return(0);
876 void CDirectVobSubFilter::UpdatePreferedLanguages(CString l)
878 AFX_MANAGE_STATE(AfxGetStaticModuleState());
880 CString langs[MAXPREFLANGS+1];
882 int i = 0, j = 0, k = -1;
883 for(; i < MAXPREFLANGS; i++)
885 CString tmp;
886 tmp.Format(IDS_RL_LANG, i);
888 langs[j] = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
890 if(!langs[j].IsEmpty())
892 if(!langs[j].CompareNoCase(l)) k = j;
893 j++;
897 if(k == -1)
899 langs[k = j] = l;
900 j++;
903 // move the selected to the top of the list
905 while(k > 0)
907 CString tmp = langs[k]; langs[k] = langs[k-1]; langs[k-1] = tmp;
908 k--;
911 // move "Hide subtitles" to the last position if it wasn't our selection
913 CString hidesubs;
914 hidesubs.LoadString(IDS_M_HIDESUBTITLES);
916 for(k = 1; k < j; k++)
918 if(!langs[k].CompareNoCase(hidesubs)) break;
921 while(k < j-1)
923 CString tmp = langs[k]; langs[k] = langs[k+1]; langs[k+1] = tmp;
924 k++;
927 for(i = 0; i < j; i++)
929 CString tmp;
930 tmp.Format(IDS_RL_LANG, i);
932 theApp.WriteProfileString(ResStr(IDS_R_PREFLANGS), tmp, langs[i]);
936 STDMETHODIMP CDirectVobSubFilter::Enable(long lIndex, DWORD dwFlags)
938 if(!(dwFlags & AMSTREAMSELECTENABLE_ENABLE))
939 return E_NOTIMPL;
941 int nLangs = 0;
942 get_LanguageCount(&nLangs);
944 if(!(lIndex >= 0 && lIndex < nLangs+2+2))
945 return E_INVALIDARG;
947 int i = lIndex-1;
949 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
951 put_HideSubtitles(false);
953 else if(i >= 0 && i < nLangs)
955 put_HideSubtitles(false);
956 put_SelectedLanguage(i);
958 WCHAR* pName = NULL;
959 if(SUCCEEDED(get_LanguageName(i, &pName)))
961 UpdatePreferedLanguages(CString(pName));
962 if(pName) CoTaskMemFree(pName);
965 else if(i == nLangs && !m_fLoading)
967 put_HideSubtitles(true);
969 else if((i == nLangs+1 || i == nLangs+2) && !m_fLoading)
971 put_Flip(i == nLangs+2, m_fFlipSubtitles);
974 return S_OK;
977 STDMETHODIMP CDirectVobSubFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk)
979 AFX_MANAGE_STATE(AfxGetStaticModuleState());
980 const int FLAG_CMD = 1;
981 const int FLAG_EXTERNAL_SUB = 2;
982 const int FLAG_PICTURE_CMD = 4;
983 const int FLAG_VISIBILITY_CMD = 8;
985 const int GROUP_NUM_BASE = 0x648E40;//random number
987 int nLangs = 0;
988 get_LanguageCount(&nLangs);
990 if(!(lIndex >= 0 && lIndex < nLangs+2+2))
991 return E_INVALIDARG;
993 int i = lIndex-1;
995 if(ppmt) *ppmt = CreateMediaType(&m_pInput->CurrentMediaType());
997 if(pdwFlags)
999 *pdwFlags = 0;
1001 if(i == -1 && !m_fHideSubtitles
1002 || i >= 0 && i < nLangs && i == m_iSelectedLanguage
1003 || i == nLangs && m_fHideSubtitles
1004 || i == nLangs+1 && !m_fFlipPicture
1005 || i == nLangs+2 && m_fFlipPicture)
1007 *pdwFlags |= AMSTREAMSELECTINFO_ENABLED;
1011 if(plcid) *plcid = 0;
1013 if(pdwGroup)
1015 *pdwGroup = GROUP_NUM_BASE;
1016 if(i == -1)
1018 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_VISIBILITY_CMD;
1020 else if(i >= 0 && i < nLangs)
1022 bool isEmbedded = false;
1023 if( SUCCEEDED(GetIsEmbeddedSubStream(i, &isEmbedded)) )
1025 if(isEmbedded)
1027 *pdwGroup = GROUP_NUM_BASE & ~(FLAG_CMD | FLAG_EXTERNAL_SUB);
1029 else
1031 *pdwGroup = (GROUP_NUM_BASE & ~FLAG_CMD) | FLAG_EXTERNAL_SUB;
1035 else if(i == nLangs)
1037 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_VISIBILITY_CMD;
1039 else if(i == nLangs+1)
1041 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_PICTURE_CMD;
1043 else if(i == nLangs+2)
1045 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_PICTURE_CMD;
1049 if(ppszName)
1051 *ppszName = NULL;
1053 CStringW str;
1054 if(i == -1) str = ResStr(IDS_M_SHOWSUBTITLES);
1055 else if(i >= 0 && i < nLangs)
1057 get_LanguageName(i, ppszName);
1059 else if(i == nLangs)
1061 str = ResStr(IDS_M_HIDESUBTITLES);
1063 else if(i == nLangs+1)
1065 str = ResStr(IDS_M_ORIGINALPICTURE);
1067 else if(i == nLangs+2)
1069 str = ResStr(IDS_M_FLIPPEDPICTURE);
1072 if(!str.IsEmpty())
1074 *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength()+1)*sizeof(WCHAR));
1075 if(*ppszName == NULL) return S_FALSE;
1076 wcscpy(*ppszName, str);
1080 if(ppObject) *ppObject = NULL;
1082 if(ppUnk) *ppUnk = NULL;
1084 return S_OK;
1087 STDMETHODIMP CDirectVobSubFilter::GetClassID(CLSID* pClsid)
1089 if(pClsid == NULL) return E_POINTER;
1090 *pClsid = m_clsid;
1091 return NOERROR;
1094 STDMETHODIMP CDirectVobSubFilter::GetPages(CAUUID* pPages)
1096 CheckPointer(pPages, E_POINTER);
1098 pPages->cElems = 8;
1099 pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID)*pPages->cElems);
1101 if(pPages->pElems == NULL) return E_OUTOFMEMORY;
1103 int i = 0;
1104 pPages->pElems[i++] = __uuidof(CDVSMainPPage);
1105 pPages->pElems[i++] = __uuidof(CDVSGeneralPPage);
1106 pPages->pElems[i++] = __uuidof(CDVSMiscPPage);
1107 pPages->pElems[i++] = __uuidof(CDVSMorePPage);
1108 pPages->pElems[i++] = __uuidof(CDVSTimingPPage);
1109 pPages->pElems[i++] = __uuidof(CDVSColorPPage);
1110 pPages->pElems[i++] = __uuidof(CDVSPathsPPage);
1111 pPages->pElems[i++] = __uuidof(CDVSAboutPPage);
1113 return NOERROR;
1116 // IDirectVobSub
1118 STDMETHODIMP CDirectVobSubFilter::put_FileName(WCHAR* fn)
1120 AMTRACE((TEXT(__FUNCTION__),0));
1121 HRESULT hr = CDirectVobSub::put_FileName(fn);
1123 if(hr == S_OK && !Open())
1125 m_FileName.Empty();
1126 hr = E_FAIL;
1129 return hr;
1132 STDMETHODIMP CDirectVobSubFilter::get_LanguageCount(int* nLangs)
1134 HRESULT hr = CDirectVobSub::get_LanguageCount(nLangs);
1136 if(hr == NOERROR && nLangs)
1138 CAutoLock cAutolock(&m_csQueueLock);
1140 *nLangs = 0;
1141 POSITION pos = m_pSubStreams.GetHeadPosition();
1142 while(pos) (*nLangs) += m_pSubStreams.GetNext(pos)->GetStreamCount();
1145 return hr;
1148 STDMETHODIMP CDirectVobSubFilter::get_LanguageName(int iLanguage, WCHAR** ppName)
1150 HRESULT hr = CDirectVobSub::get_LanguageName(iLanguage, ppName);
1152 if(!ppName) return E_POINTER;
1154 if(hr == NOERROR)
1156 CAutoLock cAutolock(&m_csQueueLock);
1158 hr = E_INVALIDARG;
1160 int i = iLanguage;
1162 POSITION pos = m_pSubStreams.GetHeadPosition();
1163 while(i >= 0 && pos)
1165 CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
1167 if(i < pSubStream->GetStreamCount())
1169 pSubStream->GetStreamInfo(i, ppName, NULL);
1170 hr = NOERROR;
1171 break;
1174 i -= pSubStream->GetStreamCount();
1178 return hr;
1181 STDMETHODIMP CDirectVobSubFilter::put_SelectedLanguage(int iSelected)
1183 HRESULT hr = CDirectVobSub::put_SelectedLanguage(iSelected);
1185 if(hr == NOERROR)
1187 UpdateSubtitle(false);
1190 return hr;
1193 STDMETHODIMP CDirectVobSubFilter::put_HideSubtitles(bool fHideSubtitles)
1195 HRESULT hr = CDirectVobSub::put_HideSubtitles(fHideSubtitles);
1197 if(hr == NOERROR)
1199 UpdateSubtitle(false);
1202 return hr;
1205 STDMETHODIMP CDirectVobSubFilter::put_PreBuffering(bool fDoPreBuffering)
1207 HRESULT hr = CDirectVobSub::put_PreBuffering(fDoPreBuffering);
1209 if(hr == NOERROR)
1211 DbgLog((LOG_TRACE, 3, "put_PreBuffering => InitSubPicQueue"));
1212 InitSubPicQueue();
1215 return hr;
1218 STDMETHODIMP CDirectVobSubFilter::put_Placement(bool fOverridePlacement, int xperc, int yperc)
1220 DbgLog((LOG_TRACE, 3, "%s(%d) %s", __FILE__, __LINE__, __FUNCTION__));
1221 HRESULT hr = CDirectVobSub::put_Placement(fOverridePlacement, xperc, yperc);
1223 if(hr == NOERROR)
1225 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1226 //UpdateSubtitle(true);
1227 UpdateSubtitle(false);
1230 return hr;
1233 STDMETHODIMP CDirectVobSubFilter::put_VobSubSettings(bool fBuffer, bool fOnlyShowForcedSubs, bool fReserved)
1235 HRESULT hr = CDirectVobSub::put_VobSubSettings(fBuffer, fOnlyShowForcedSubs, fReserved);
1237 if(hr == NOERROR)
1239 // UpdateSubtitle(false);
1240 InvalidateSubtitle();
1243 return hr;
1246 STDMETHODIMP CDirectVobSubFilter::put_TextSettings(void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer)
1248 HRESULT hr = CDirectVobSub::put_TextSettings(lf, lflen, color, fShadow, fOutline, fAdvancedRenderer);
1250 if(hr == NOERROR)
1252 // UpdateSubtitle(true);
1253 InvalidateSubtitle();
1256 return hr;
1259 STDMETHODIMP CDirectVobSubFilter::put_SubtitleTiming(int delay, int speedmul, int speeddiv)
1261 HRESULT hr = CDirectVobSub::put_SubtitleTiming(delay, speedmul, speeddiv);
1263 if(hr == NOERROR)
1265 InvalidateSubtitle();
1268 return hr;
1271 STDMETHODIMP CDirectVobSubFilter::get_CachesInfo(CachesInfo* caches_info)
1273 CAutoLock cAutoLock(&m_csQueueLock);
1274 HRESULT hr = CDirectVobSub::get_CachesInfo(caches_info);
1276 caches_info->path_cache_cur_item_num = CacheManager::GetPathDataMruCache()->GetCurItemNum();
1277 caches_info->path_cache_hit_count = CacheManager::GetPathDataMruCache()->GetCacheHitCount();
1278 caches_info->path_cache_query_count = CacheManager::GetPathDataMruCache()->GetQueryCount();
1279 caches_info->scanline_cache2_cur_item_num= CacheManager::GetScanLineData2MruCache()->GetCurItemNum();
1280 caches_info->scanline_cache2_hit_count = CacheManager::GetScanLineData2MruCache()->GetCacheHitCount();
1281 caches_info->scanline_cache2_query_count = CacheManager::GetScanLineData2MruCache()->GetQueryCount();
1282 caches_info->non_blur_cache_cur_item_num= CacheManager::GetOverlayNoBlurMruCache()->GetCurItemNum();
1283 caches_info->non_blur_cache_hit_count = CacheManager::GetOverlayNoBlurMruCache()->GetCacheHitCount();
1284 caches_info->non_blur_cache_query_count = CacheManager::GetOverlayNoBlurMruCache()->GetQueryCount();
1285 caches_info->overlay_cache_cur_item_num = CacheManager::GetOverlayMruCache()->GetCurItemNum();
1286 caches_info->overlay_cache_hit_count = CacheManager::GetOverlayMruCache()->GetCacheHitCount();
1287 caches_info->overlay_cache_query_count = CacheManager::GetOverlayMruCache()->GetQueryCount();
1289 caches_info->bitmap_cache_cur_item_num = CacheManager::GetBitmapMruCache()->GetCurItemNum();
1290 caches_info->bitmap_cache_hit_count = CacheManager::GetBitmapMruCache()->GetCacheHitCount();
1291 caches_info->bitmap_cache_query_count = CacheManager::GetBitmapMruCache()->GetQueryCount();
1293 caches_info->interpolate_cache_cur_item_num = CacheManager::GetSubpixelVarianceCache()->GetCurItemNum();
1294 caches_info->interpolate_cache_hit_count = CacheManager::GetSubpixelVarianceCache()->GetCacheHitCount();
1295 caches_info->interpolate_cache_query_count = CacheManager::GetSubpixelVarianceCache()->GetQueryCount();
1296 caches_info->text_info_cache_cur_item_num = CacheManager::GetTextInfoCache()->GetCurItemNum();
1297 caches_info->text_info_cache_hit_count = CacheManager::GetTextInfoCache()->GetCacheHitCount();
1298 caches_info->text_info_cache_query_count = CacheManager::GetTextInfoCache()->GetQueryCount();
1300 caches_info->word_info_cache_cur_item_num = CacheManager::GetAssTagListMruCache()->GetCurItemNum();
1301 caches_info->word_info_cache_hit_count = CacheManager::GetAssTagListMruCache()->GetCacheHitCount();
1302 caches_info->word_info_cache_query_count = CacheManager::GetAssTagListMruCache()->GetQueryCount();
1304 caches_info->scanline_cache_cur_item_num = CacheManager::GetScanLineDataMruCache()->GetCurItemNum();
1305 caches_info->scanline_cache_hit_count = CacheManager::GetScanLineDataMruCache()->GetCacheHitCount();
1306 caches_info->scanline_cache_query_count = CacheManager::GetScanLineDataMruCache()->GetQueryCount();
1308 caches_info->overlay_key_cache_cur_item_num = CacheManager::GetOverlayNoOffsetMruCache()->GetCurItemNum();
1309 caches_info->overlay_key_cache_hit_count = CacheManager::GetOverlayNoOffsetMruCache()->GetCacheHitCount();
1310 caches_info->overlay_key_cache_query_count = CacheManager::GetOverlayNoOffsetMruCache()->GetQueryCount();
1312 caches_info->clipper_cache_cur_item_num = CacheManager::GetClipperAlphaMaskMruCache()->GetCurItemNum();
1313 caches_info->clipper_cache_hit_count = CacheManager::GetClipperAlphaMaskMruCache()->GetCacheHitCount();
1314 caches_info->clipper_cache_query_count = CacheManager::GetClipperAlphaMaskMruCache()->GetQueryCount();
1316 return hr;
1319 STDMETHODIMP CDirectVobSubFilter::get_XyFlyWeightInfo( XyFlyWeightInfo* xy_fw_info )
1321 CAutoLock cAutoLock(&m_csQueueLock);
1322 HRESULT hr = CDirectVobSub::get_XyFlyWeightInfo(xy_fw_info);
1324 xy_fw_info->xy_fw_string_w.cur_item_num = XyFwStringW::GetCacher()->GetCurItemNum();
1325 xy_fw_info->xy_fw_string_w.hit_count = XyFwStringW::GetCacher()->GetCacheHitCount();
1326 xy_fw_info->xy_fw_string_w.query_count = XyFwStringW::GetCacher()->GetQueryCount();
1328 xy_fw_info->xy_fw_grouped_draw_items_hash_key.cur_item_num = XyFwGroupedDrawItemsHashKey::GetCacher()->GetCurItemNum();
1329 xy_fw_info->xy_fw_grouped_draw_items_hash_key.hit_count = XyFwGroupedDrawItemsHashKey::GetCacher()->GetCacheHitCount();
1330 xy_fw_info->xy_fw_grouped_draw_items_hash_key.query_count = XyFwGroupedDrawItemsHashKey::GetCacher()->GetQueryCount();
1332 return hr;
1335 STDMETHODIMP CDirectVobSubFilter::get_MediaFPS(bool* fEnabled, double* fps)
1337 HRESULT hr = CDirectVobSub::get_MediaFPS(fEnabled, fps);
1339 CComQIPtr<IMediaSeeking> pMS = m_pGraph;
1340 double rate;
1341 if(pMS && SUCCEEDED(pMS->GetRate(&rate)))
1343 m_MediaFPS = rate * m_fps;
1344 if(fps) *fps = m_MediaFPS;
1347 return hr;
1350 STDMETHODIMP CDirectVobSubFilter::put_MediaFPS(bool fEnabled, double fps)
1352 HRESULT hr = CDirectVobSub::put_MediaFPS(fEnabled, fps);
1354 CComQIPtr<IMediaSeeking> pMS = m_pGraph;
1355 if(pMS)
1357 if(hr == NOERROR)
1359 hr = pMS->SetRate(m_fMediaFPSEnabled ? m_MediaFPS / m_fps : 1.0);
1362 double dRate;
1363 if(SUCCEEDED(pMS->GetRate(&dRate)))
1364 m_MediaFPS = dRate * m_fps;
1367 return hr;
1370 STDMETHODIMP CDirectVobSubFilter::get_ZoomRect(NORMALIZEDRECT* rect)
1372 return E_NOTIMPL;
1375 STDMETHODIMP CDirectVobSubFilter::put_ZoomRect(NORMALIZEDRECT* rect)
1377 return E_NOTIMPL;
1380 // IDirectVobSub2
1382 STDMETHODIMP CDirectVobSubFilter::put_TextSettings(STSStyle* pDefStyle)
1384 HRESULT hr = CDirectVobSub::put_TextSettings(pDefStyle);
1386 if(hr == NOERROR)
1388 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1389 //UpdateSubtitle(true);
1390 UpdateSubtitle(false);
1393 return hr;
1396 STDMETHODIMP CDirectVobSubFilter::put_AspectRatioSettings(CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType)
1398 HRESULT hr = CDirectVobSub::put_AspectRatioSettings(ePARCompensationType);
1400 if(hr == NOERROR)
1402 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1403 //UpdateSubtitle(true);
1404 UpdateSubtitle(false);
1407 return hr;
1410 // IDirectVobSubFilterColor
1412 STDMETHODIMP CDirectVobSubFilter::HasConfigDialog(int iSelected)
1414 int nLangs;
1415 if(FAILED(get_LanguageCount(&nLangs))) return E_FAIL;
1416 return E_FAIL;
1417 // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
1418 // return(nLangs >= 0 && iSelected < nLangs ? S_OK : E_FAIL);
1421 STDMETHODIMP CDirectVobSubFilter::ShowConfigDialog(int iSelected, HWND hWndParent)
1423 // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
1424 return(E_FAIL);
1427 ///////////////////////////////////////////////////////////////////////////
1429 CDirectVobSubFilter2::CDirectVobSubFilter2(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid) :
1430 CDirectVobSubFilter(punk, phr, clsid)
1434 HRESULT CDirectVobSubFilter2::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
1436 CPinInfo pi;
1437 if(FAILED(pPin->QueryPinInfo(&pi))) return E_FAIL;
1439 if(CComQIPtr<IDirectVobSub>(pi.pFilter)) return E_FAIL;
1441 if(dir == PINDIR_INPUT)
1443 CFilterInfo fi;
1444 if(SUCCEEDED(pi.pFilter->QueryFilterInfo(&fi))
1445 && !wcsnicmp(fi.achName, L"Overlay Mixer", 13))
1446 return(E_FAIL);
1448 else
1452 return __super::CheckConnect(dir, pPin);
1455 HRESULT CDirectVobSubFilter2::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
1457 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::JoinFilterGraph"));
1458 if(pGraph)
1460 BeginEnumFilters(pGraph, pEF, pBF)
1462 if(pBF != (IBaseFilter*)this && CComQIPtr<IDirectVobSub>(pBF))
1463 return E_FAIL;
1465 EndEnumFilters
1467 // don't look... we will do some serious graph hacking again...
1469 // we will add dvs2 to the filter graph cache
1470 // - if the main app has already added some kind of renderer or overlay mixer (anything which accepts video on its input)
1471 // and
1472 // - if we have a reason to auto-load (we don't want to make any trouble when there is no need :)
1474 // This whole workaround is needed because the video stream will always be connected
1475 // to the pre-added filters first, no matter how high merit we have.
1477 if(!get_Forced())
1479 BeginEnumFilters(pGraph, pEF, pBF)
1481 if(CComQIPtr<IDirectVobSub>(pBF))
1482 continue;
1484 CComPtr<IPin> pInPin = GetFirstPin(pBF, PINDIR_INPUT);
1485 CComPtr<IPin> pOutPin = GetFirstPin(pBF, PINDIR_OUTPUT);
1487 if(!pInPin)
1488 continue;
1490 CComPtr<IPin> pPin;
1491 if(pInPin && SUCCEEDED(pInPin->ConnectedTo(&pPin))
1492 || pOutPin && SUCCEEDED(pOutPin->ConnectedTo(&pPin)))
1493 continue;
1495 if(pOutPin && GetFilterName(pBF) != _T("Overlay Mixer"))
1496 continue;
1498 bool fVideoInputPin = false;
1502 BITMAPINFOHEADER bih = {sizeof(BITMAPINFOHEADER), 384, 288, 1, 16, '2YUY', 384*288*2, 0, 0, 0, 0};
1504 CMediaType cmt;
1505 cmt.majortype = MEDIATYPE_Video;
1506 cmt.subtype = MEDIASUBTYPE_YUY2;
1507 cmt.formattype = FORMAT_VideoInfo;
1508 cmt.pUnk = NULL;
1509 cmt.bFixedSizeSamples = TRUE;
1510 cmt.bTemporalCompression = TRUE;
1511 cmt.lSampleSize = 384*288*2;
1512 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
1513 memset(vih, 0, sizeof(VIDEOINFOHEADER));
1514 memcpy(&vih->bmiHeader, &bih, sizeof(bih));
1515 vih->AvgTimePerFrame = 400000;
1517 if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
1519 fVideoInputPin = true;
1520 break;
1523 VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER2));
1524 memset(vih2, 0, sizeof(VIDEOINFOHEADER2));
1525 memcpy(&vih2->bmiHeader, &bih, sizeof(bih));
1526 vih2->AvgTimePerFrame = 400000;
1527 vih2->dwPictAspectRatioX = 384;
1528 vih2->dwPictAspectRatioY = 288;
1530 if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
1532 fVideoInputPin = true;
1533 break;
1536 while(false);
1538 if(fVideoInputPin)
1540 CComPtr<IBaseFilter> pDVS;
1541 if(ShouldWeAutoload(pGraph) && SUCCEEDED(pDVS.CoCreateInstance(__uuidof(CDirectVobSubFilter2))))
1543 CComQIPtr<IDirectVobSub2>(pDVS)->put_Forced(true);
1544 CComQIPtr<IGraphConfig>(pGraph)->AddFilterToCache(pDVS);
1547 break;
1550 EndEnumFilters
1553 else
1557 return __super::JoinFilterGraph(pGraph, pName);
1560 HRESULT CDirectVobSubFilter2::CheckInputType(const CMediaType* mtIn)
1562 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::CheckInputType"));
1563 HRESULT hr = __super::CheckInputType(mtIn);
1565 if(FAILED(hr) || m_pInput->IsConnected()) return hr;
1567 if(!ShouldWeAutoload(m_pGraph)) return VFW_E_TYPE_NOT_ACCEPTED;
1569 GetRidOfInternalScriptRenderer();
1571 return NOERROR;
1574 bool CDirectVobSubFilter2::ShouldWeAutoload(IFilterGraph* pGraph)
1576 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::ShouldWeAutoload"));
1577 TCHAR blacklistedapps[][32] =
1579 _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)
1580 _T("explorer."), // as some users reported thumbnail preview loads dvobsub, I've never experienced this yet...
1581 _T("producer."), // this is real's producer
1582 _T("GoogleDesktopIndex."), // Google Desktop
1583 _T("GoogleDesktopDisplay."), // Google Desktop
1584 _T("GoogleDesktopCrawl."), // Google Desktop
1587 for(int i = 0; i < countof(blacklistedapps); i++)
1589 if(theApp.m_AppName.Find(blacklistedapps[i]) >= 0)
1590 return(false);
1593 int level;
1594 bool m_fExternalLoad, m_fWebLoad, m_fEmbeddedLoad;
1595 get_LoadSettings(&level, &m_fExternalLoad, &m_fWebLoad, &m_fEmbeddedLoad);
1597 if(level < 0 || level >= 2) return(false);
1599 bool fRet = false;
1601 if(level == 1)
1602 fRet = m_fExternalLoad = m_fWebLoad = m_fEmbeddedLoad = true;
1604 // find text stream on known splitters
1606 if(!fRet && m_fEmbeddedLoad)
1608 CComPtr<IBaseFilter> pBF;
1609 if((pBF = FindFilter(CLSID_OggSplitter, pGraph)) || (pBF = FindFilter(CLSID_AviSplitter, pGraph))
1610 || (pBF = FindFilter(L"{34293064-02F2-41D5-9D75-CC5967ACA1AB}", pGraph)) // matroska demux
1611 || (pBF = FindFilter(L"{0A68C3B5-9164-4a54-AFAF-995B2FF0E0D4}", pGraph)) // matroska source
1612 || (pBF = FindFilter(L"{149D2E01-C32E-4939-80F6-C07B81015A7A}", pGraph)) // matroska splitter
1613 || (pBF = FindFilter(L"{55DA30FC-F16B-49fc-BAA5-AE59FC65F82D}", pGraph)) // Haali Media Splitter
1614 || (pBF = FindFilter(L"{564FD788-86C9-4444-971E-CC4A243DA150}", pGraph)) // Haali Media Splitter (AR)
1615 || (pBF = FindFilter(L"{8F43B7D9-9D6B-4F48-BE18-4D787C795EEA}", pGraph)) // Haali Simple Media Splitter
1616 || (pBF = FindFilter(L"{52B63861-DC93-11CE-A099-00AA00479A58}", pGraph)) // 3ivx splitter
1617 || (pBF = FindFilter(L"{6D3688CE-3E9D-42F4-92CA-8A11119D25CD}", pGraph)) // our ogg source
1618 || (pBF = FindFilter(L"{9FF48807-E133-40AA-826F-9B2959E5232D}", pGraph)) // our ogg splitter
1619 || (pBF = FindFilter(L"{803E8280-F3CE-4201-982C-8CD8FB512004}", pGraph)) // dsm source
1620 || (pBF = FindFilter(L"{0912B4DD-A30A-4568-B590-7179EBB420EC}", pGraph)) // dsm splitter
1621 || (pBF = FindFilter(L"{3CCC052E-BDEE-408a-BEA7-90914EF2964B}", pGraph)) // mp4 source
1622 || (pBF = FindFilter(L"{61F47056-E400-43d3-AF1E-AB7DFFD4C4AD}", pGraph)) // mp4 splitter
1623 || (pBF = FindFilter(L"{171252A0-8820-4AFE-9DF8-5C92B2D66B04}", pGraph)) // LAV splitter
1624 || (pBF = FindFilter(L"{B98D13E7-55DB-4385-A33D-09FD1BA26338}", pGraph)) // LAV Splitter Source
1625 || (pBF = FindFilter(L"{E436EBB5-524F-11CE-9F53-0020AF0BA770}", pGraph)) // Solveig matroska splitter
1626 || (pBF = FindFilter(L"{1365BE7A-C86A-473C-9A41-C0A6E82C9FA3}", pGraph)) // MPC-HC MPEG PS/TS/PVA source
1627 || (pBF = FindFilter(L"{DC257063-045F-4BE2-BD5B-E12279C464F0}", pGraph)) // MPC-HC MPEG splitter
1628 || (pBF = FindFilter(L"{529A00DB-0C43-4f5b-8EF2-05004CBE0C6F}", pGraph)) // AV splitter
1629 || (pBF = FindFilter(L"{D8980E15-E1F6-4916-A10F-D7EB4E9E10B8}", pGraph)) // AV source
1632 BeginEnumPins(pBF, pEP, pPin)
1634 BeginEnumMediaTypes(pPin, pEM, pmt)
1636 if(pmt->majortype == MEDIATYPE_Text || pmt->majortype == MEDIATYPE_Subtitle)
1638 fRet = true;
1639 break;
1642 EndEnumMediaTypes(pmt)
1643 if(fRet) break;
1645 EndEnumFilters
1649 // find file name
1651 CStringW fn;
1653 BeginEnumFilters(pGraph, pEF, pBF)
1655 if(CComQIPtr<IFileSourceFilter> pFSF = pBF)
1657 LPOLESTR fnw = NULL;
1658 if(!pFSF || FAILED(pFSF->GetCurFile(&fnw, NULL)) || !fnw)
1659 continue;
1660 fn = CString(fnw);
1661 CoTaskMemFree(fnw);
1662 break;
1665 EndEnumFilters
1667 if((m_fExternalLoad || m_fWebLoad) && (m_fWebLoad || !(wcsstr(fn, L"http://") || wcsstr(fn, L"mms://"))))
1669 bool fTemp = m_fHideSubtitles;
1670 fRet = !fn.IsEmpty() && SUCCEEDED(put_FileName((LPWSTR)(LPCWSTR)fn))
1671 || SUCCEEDED(put_FileName(L"c:\\tmp.srt"))
1672 || fRet;
1673 if(fTemp) m_fHideSubtitles = true;
1676 return(fRet);
1679 void CDirectVobSubFilter2::GetRidOfInternalScriptRenderer()
1681 while(CComPtr<IBaseFilter> pBF = FindFilter(L"{48025243-2D39-11CE-875D-00608CB78066}", m_pGraph))
1683 BeginEnumPins(pBF, pEP, pPin)
1685 PIN_DIRECTION dir;
1686 CComPtr<IPin> pPinTo;
1688 if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT
1689 && SUCCEEDED(pPin->ConnectedTo(&pPinTo)))
1691 m_pGraph->Disconnect(pPinTo);
1692 m_pGraph->Disconnect(pPin);
1693 m_pGraph->ConnectDirect(pPinTo, GetPin(2 + m_pTextInput.GetCount()-1), NULL);
1696 EndEnumPins
1698 if(FAILED(m_pGraph->RemoveFilter(pBF)))
1699 break;
1703 ///////////////////////////////////////////////////////////////////////////////
1705 bool CDirectVobSubFilter::Open()
1707 AMTRACE((TEXT(__FUNCTION__),0));
1708 XY_AUTO_TIMING(TEXT("CDirectVobSubFilter::Open"));
1710 AFX_MANAGE_STATE(AfxGetStaticModuleState());
1712 CAutoLock cAutolock(&m_csQueueLock);
1714 m_pSubStreams.RemoveAll();
1715 m_fIsSubStreamEmbeded.RemoveAll();
1717 m_frd.files.RemoveAll();
1719 CAtlArray<CString> paths;
1721 for(int i = 0; i < 10; i++)
1723 CString tmp;
1724 tmp.Format(IDS_RP_PATH, i);
1725 CString path = theApp.GetProfileString(ResStr(IDS_R_DEFTEXTPATHES), tmp);
1726 if(!path.IsEmpty()) paths.Add(path);
1729 CAtlArray<SubFile> ret;
1730 GetSubFileNames(m_FileName, paths, m_xy_str_opt[DirectVobSubXyOptions::STRING_LOAD_EXT_LIST], ret);
1732 for(size_t i = 0; i < ret.GetCount(); i++)
1734 if(m_frd.files.Find(ret[i].full_file_name))
1735 continue;
1737 CComPtr<ISubStream> pSubStream;
1739 if(!pSubStream)
1741 // CAutoTiming t(TEXT("CRenderedTextSubtitle::Open"), 0);
1742 XY_AUTO_TIMING(TEXT("CRenderedTextSubtitle::Open"));
1743 CAutoPtr<CRenderedTextSubtitle> pRTS(new CRenderedTextSubtitle(&m_csSubLock));
1744 if(pRTS && pRTS->Open(ret[i].full_file_name, DEFAULT_CHARSET) && pRTS->GetStreamCount() > 0)
1746 pSubStream = pRTS.Detach();
1747 m_frd.files.AddTail(ret[i].full_file_name + _T(".style"));
1751 if(!pSubStream)
1753 CAutoTiming t(TEXT("CVobSubFile::Open"), 0);
1754 CAutoPtr<CVobSubFile> pVSF(new CVobSubFile(&m_csSubLock));
1755 if(pVSF && pVSF->Open(ret[i].full_file_name) && pVSF->GetStreamCount() > 0)
1757 pSubStream = pVSF.Detach();
1758 m_frd.files.AddTail(ret[i].full_file_name.Left(ret[i].full_file_name.GetLength()-4) + _T(".sub"));
1762 if(!pSubStream)
1764 CAutoTiming t(TEXT("ssf::CRenderer::Open"), 0);
1765 CAutoPtr<ssf::CRenderer> pSSF(new ssf::CRenderer(&m_csSubLock));
1766 if(pSSF && pSSF->Open(ret[i].full_file_name) && pSSF->GetStreamCount() > 0)
1768 pSubStream = pSSF.Detach();
1772 if(pSubStream)
1774 m_pSubStreams.AddTail(pSubStream);
1775 m_fIsSubStreamEmbeded.AddTail(false);
1776 m_frd.files.AddTail(ret[i].full_file_name);
1780 for(size_t i = 0; i < m_pTextInput.GetCount(); i++)
1782 if(m_pTextInput[i]->IsConnected())
1784 m_pSubStreams.AddTail(m_pTextInput[i]->GetSubStream());
1785 m_fIsSubStreamEmbeded.AddTail(true);
1789 if(S_FALSE == put_SelectedLanguage(FindPreferedLanguage()))
1790 UpdateSubtitle(false); // make sure pSubPicProvider of our queue gets updated even if the stream number hasn't changed
1792 m_frd.RefreshEvent.Set();
1794 return(m_pSubStreams.GetCount() > 0);
1797 void CDirectVobSubFilter::UpdateSubtitle(bool fApplyDefStyle)
1799 CAutoLock cAutolock(&m_csQueueLock);
1801 if(!m_simple_provider) return;
1803 InvalidateSubtitle();
1805 CComPtr<ISubStream> pSubStream;
1807 if(!m_fHideSubtitles)
1809 int i = m_iSelectedLanguage;
1811 for(POSITION pos = m_pSubStreams.GetHeadPosition(); i >= 0 && pos; pSubStream = NULL)
1813 pSubStream = m_pSubStreams.GetNext(pos);
1815 if(i < pSubStream->GetStreamCount())
1817 CAutoLock cAutoLock(&m_csSubLock);
1818 pSubStream->SetStream(i);
1819 break;
1822 i -= pSubStream->GetStreamCount();
1826 SetSubtitle(pSubStream, fApplyDefStyle);
1829 void CDirectVobSubFilter::SetSubtitle(ISubStream* pSubStream, bool fApplyDefStyle)
1831 DbgLog((LOG_TRACE, 3, "%s(%d): %s", __FILE__, __LINE__, __FUNCTION__));
1832 DbgLog((LOG_TRACE, 3, "\tpSubStream:%x fApplyDefStyle:%d", pSubStream, (int)fApplyDefStyle));
1833 CAutoLock cAutolock(&m_csQueueLock);
1835 CSize playres(0,0);
1836 m_script_selected_yuv = CSimpleTextSubtitle::YCbCrMatrix_AUTO;
1837 m_script_selected_range = CSimpleTextSubtitle::YCbCrRange_AUTO;
1838 if(pSubStream)
1840 CAutoLock cAutolock(&m_csSubLock);
1842 CLSID clsid;
1843 pSubStream->GetClassID(&clsid);
1845 if(clsid == __uuidof(CVobSubFile))
1847 CVobSubSettings* pVSS = dynamic_cast<CVobSubFile*>(pSubStream);
1849 if(fApplyDefStyle)
1851 pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
1852 pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
1855 else if(clsid == __uuidof(CVobSubStream))
1857 CVobSubSettings* pVSS = dynamic_cast<CVobSubStream*>(pSubStream);
1859 if(fApplyDefStyle)
1861 pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
1862 pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
1865 else if(clsid == __uuidof(CRenderedTextSubtitle))
1867 CRenderedTextSubtitle* pRTS = dynamic_cast<CRenderedTextSubtitle*>(pSubStream);
1869 if(fApplyDefStyle || pRTS->m_fUsingAutoGeneratedDefaultStyle)
1871 STSStyle s = m_defStyle;
1873 if(m_fOverridePlacement)
1875 s.scrAlignment = 2;
1876 int w = pRTS->m_dstScreenSize.cx;
1877 int h = pRTS->m_dstScreenSize.cy;
1878 CRect tmp_rect = s.marginRect.get();
1879 int mw = w - tmp_rect.left - tmp_rect.right;
1880 tmp_rect.bottom = h - MulDiv(h, m_PlacementYperc, 100);
1881 tmp_rect.left = MulDiv(w, m_PlacementXperc, 100) - mw/2;
1882 tmp_rect.right = w - (tmp_rect.left + mw);
1883 s.marginRect = tmp_rect;
1886 pRTS->SetDefaultStyle(s);
1889 pRTS->m_ePARCompensationType = m_ePARCompensationType;
1890 if (m_CurrentVIH2.dwPictAspectRatioX != 0 && m_CurrentVIH2.dwPictAspectRatioY != 0&& m_CurrentVIH2.bmiHeader.biWidth != 0 && m_CurrentVIH2.bmiHeader.biHeight != 0)
1892 pRTS->m_dPARCompensation = ((double)abs(m_CurrentVIH2.bmiHeader.biWidth) / (double)abs(m_CurrentVIH2.bmiHeader.biHeight)) /
1893 ((double)abs((long)m_CurrentVIH2.dwPictAspectRatioX) / (double)abs((long)m_CurrentVIH2.dwPictAspectRatioY));
1896 else
1898 pRTS->m_dPARCompensation = 1.00;
1901 m_script_selected_yuv = pRTS->m_eYCbCrMatrix;
1902 m_script_selected_range = pRTS->m_eYCbCrRange;
1903 pRTS->Deinit();
1904 playres = pRTS->m_dstScreenSize;
1906 else if(clsid == __uuidof(CRenderedHdmvSubtitle))
1908 CRenderedHdmvSubtitle *sub = dynamic_cast<CRenderedHdmvSubtitle*>(pSubStream);
1909 CompositionObject::ColorType color_type = CompositionObject::NONE;
1910 CompositionObject::YuvRangeType range_type = CompositionObject::RANGE_NONE;
1911 if ( m_xy_str_opt[STRING_PGS_YUV_RANGE].CompareNoCase(_T("PC"))==0 )
1913 range_type = CompositionObject::RANGE_PC;
1915 else if ( m_xy_str_opt[STRING_PGS_YUV_RANGE].CompareNoCase(_T("TV"))==0 )
1917 range_type = CompositionObject::RANGE_TV;
1919 if ( m_xy_str_opt[STRING_PGS_YUV_MATRIX].CompareNoCase(_T("BT601"))==0 )
1921 color_type = CompositionObject::YUV_Rec601;
1923 else if ( m_xy_str_opt[STRING_PGS_YUV_MATRIX].CompareNoCase(_T("BT709"))==0 )
1925 color_type = CompositionObject::YUV_Rec709;
1927 sub->SetYuvType(color_type, range_type);
1931 if(!fApplyDefStyle)
1933 int i = 0;
1935 POSITION pos = m_pSubStreams.GetHeadPosition();
1936 while(pos)
1938 CComPtr<ISubStream> pSubStream2 = m_pSubStreams.GetNext(pos);
1940 if(pSubStream == pSubStream2)
1942 m_iSelectedLanguage = i + pSubStream2->GetStream();
1943 break;
1946 i += pSubStream2->GetStreamCount();
1950 m_nSubtitleId = reinterpret_cast<DWORD_PTR>(pSubStream);
1952 SetYuvMatrix();
1954 XySetSize(SIZE_ASS_PLAY_RESOLUTION, playres);
1955 if(m_simple_provider)
1956 m_simple_provider->SetSubPicProvider(CComQIPtr<ISubPicProviderEx>(pSubStream));
1959 void CDirectVobSubFilter::InvalidateSubtitle(REFERENCE_TIME rtInvalidate, DWORD_PTR nSubtitleId)
1961 CAutoLock cAutolock(&m_csQueueLock);
1963 if(m_simple_provider)
1965 if(nSubtitleId == -1 || nSubtitleId == m_nSubtitleId)
1967 DbgLog((LOG_TRACE, 3, "InvalidateSubtitle::Invalidate"));
1968 m_simple_provider->Invalidate(rtInvalidate);
1973 //////////////////////////////////////////////////////////////////////////////////////////
1975 void CDirectVobSubFilter::AddSubStream(ISubStream* pSubStream)
1977 CAutoLock cAutoLock(&m_csQueueLock);
1979 POSITION pos = m_pSubStreams.Find(pSubStream);
1980 if(!pos)
1982 m_pSubStreams.AddTail(pSubStream);
1983 m_fIsSubStreamEmbeded.AddTail(true);//todo: fix me
1986 int len = m_pTextInput.GetCount();
1987 for(size_t i = 0; i < m_pTextInput.GetCount(); i++)
1988 if(m_pTextInput[i]->IsConnected()) len--;
1990 if(len == 0)
1992 HRESULT hr = S_OK;
1993 m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
1997 void CDirectVobSubFilter::RemoveSubStream(ISubStream* pSubStream)
1999 CAutoLock cAutoLock(&m_csQueueLock);
2001 POSITION pos = m_pSubStreams.GetHeadPosition();
2002 POSITION pos2 = m_fIsSubStreamEmbeded.GetHeadPosition();
2003 while(pos!=NULL)
2005 if( m_pSubStreams.GetAt(pos)==pSubStream )
2007 m_pSubStreams.RemoveAt(pos);
2008 m_fIsSubStreamEmbeded.RemoveAt(pos2);
2009 break;
2011 else
2013 m_pSubStreams.GetNext(pos);
2014 m_fIsSubStreamEmbeded.GetNext(pos2);
2019 void CDirectVobSubFilter::Post_EC_OLE_EVENT(CString str, DWORD_PTR nSubtitleId)
2021 if(nSubtitleId != -1 && nSubtitleId != m_nSubtitleId)
2022 return;
2024 CComQIPtr<IMediaEventSink> pMES = m_pGraph;
2025 if(!pMES) return;
2027 CComBSTR bstr1("Text"), bstr2(" ");
2029 str.Trim();
2030 if(!str.IsEmpty()) bstr2 = CStringA(str);
2032 pMES->Notify(EC_OLE_EVENT, (LONG_PTR)bstr1.Detach(), (LONG_PTR)bstr2.Detach());
2035 ////////////////////////////////////////////////////////////////
2037 void CDirectVobSubFilter::SetupFRD(CStringArray& paths, CAtlArray<HANDLE>& handles)
2039 CAutoLock cAutolock(&m_csSubLock);
2041 for(size_t i = 2; i < handles.GetCount(); i++)
2043 FindCloseChangeNotification(handles[i]);
2046 paths.RemoveAll();
2047 handles.RemoveAll();
2049 handles.Add(m_frd.EndThreadEvent);
2050 handles.Add(m_frd.RefreshEvent);
2052 m_frd.mtime.SetCount(m_frd.files.GetCount());
2054 POSITION pos = m_frd.files.GetHeadPosition();
2055 for(int i = 0; pos; i++)
2057 CString fn = m_frd.files.GetNext(pos);
2059 CFileStatus status;
2060 if(CFileGetStatus(fn, status))
2061 m_frd.mtime[i] = status.m_mtime;
2063 fn.Replace('\\', '/');
2064 fn = fn.Left(fn.ReverseFind('/')+1);
2066 bool fFound = false;
2068 for(int j = 0; !fFound && j < paths.GetCount(); j++)
2070 if(paths[j] == fn) fFound = true;
2073 if(!fFound)
2075 paths.Add(fn);
2077 HANDLE h = FindFirstChangeNotification(fn, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
2078 if(h != INVALID_HANDLE_VALUE) handles.Add(h);
2083 DWORD CDirectVobSubFilter::ThreadProc()
2085 SetThreadPriority(m_hThread, THREAD_PRIORITY_LOWEST/*THREAD_PRIORITY_BELOW_NORMAL*/);
2087 CStringArray paths;
2088 CAtlArray<HANDLE> handles;
2090 SetupFRD(paths, handles);
2092 while(1)
2094 DWORD idx = WaitForMultipleObjects(handles.GetCount(), handles.GetData(), FALSE, INFINITE);
2096 if(idx == (WAIT_OBJECT_0 + 0)) // m_frd.hEndThreadEvent
2098 break;
2100 if(idx == (WAIT_OBJECT_0 + 1)) // m_frd.hRefreshEvent
2102 SetupFRD(paths, handles);
2104 else if(idx >= (WAIT_OBJECT_0 + 2) && idx < (WAIT_OBJECT_0 + handles.GetCount()))
2106 bool fLocked = true;
2107 IsSubtitleReloaderLocked(&fLocked);
2108 if(fLocked) continue;
2110 if(FindNextChangeNotification(handles[idx - WAIT_OBJECT_0]) == FALSE)
2111 break;
2113 int j = 0;
2115 POSITION pos = m_frd.files.GetHeadPosition();
2116 for(int i = 0; pos && j == 0; i++)
2118 CString fn = m_frd.files.GetNext(pos);
2120 CFileStatus status;
2121 if(CFileGetStatus(fn, status) && m_frd.mtime[i] != status.m_mtime)
2123 for(j = 0; j < 10; j++)
2125 if(FILE* f = _tfopen(fn, _T("rb+")))
2127 fclose(f);
2128 j = 0;
2129 break;
2131 else
2133 Sleep(100);
2134 j++;
2140 if(j > 0)
2142 SetupFRD(paths, handles);
2144 else
2146 Sleep(500);
2148 POSITION pos = m_frd.files.GetHeadPosition();
2149 for(int i = 0; pos; i++)
2151 CFileStatus status;
2152 if(CFileGetStatus(m_frd.files.GetNext(pos), status)
2153 && m_frd.mtime[i] != status.m_mtime)
2155 Open();
2156 SetupFRD(paths, handles);
2157 break;
2162 else
2164 break;
2168 for(size_t i = 2; i < handles.GetCount(); i++)
2170 FindCloseChangeNotification(handles[i]);
2173 return 0;
2176 void CDirectVobSubFilter::GetInputColorspaces( ColorSpaceId *preferredOrder, UINT *count )
2178 ColorSpaceOpt *color_space=NULL;
2179 int tempCount = 0;
2180 if( XyGetBin(BIN_INPUT_COLOR_FORMAT, reinterpret_cast<LPVOID*>(&color_space), &tempCount)==S_OK )
2182 *count = 0;
2183 for (int i=0;i<tempCount;i++)
2185 if(color_space[i].selected)
2187 preferredOrder[*count] = color_space[i].color_space;
2188 (*count)++;
2192 else
2194 CBaseVideoFilter::GetInputColorspaces(preferredOrder, count);
2196 delete[]color_space;
2199 void CDirectVobSubFilter::GetOutputColorspaces( ColorSpaceId *preferredOrder, UINT *count )
2201 ColorSpaceOpt *color_space=NULL;
2202 int tempCount = 0;
2203 if( XyGetBin(BIN_OUTPUT_COLOR_FORMAT, reinterpret_cast<LPVOID*>(&color_space), &tempCount)==S_OK )
2205 *count = 0;
2206 for (int i=0;i<tempCount;i++)
2208 if(color_space[i].selected)
2210 preferredOrder[*count] = color_space[i].color_space;
2211 (*count)++;
2215 else
2217 CBaseVideoFilter::GetInputColorspaces(preferredOrder, count);
2219 delete []color_space;
2222 HRESULT CDirectVobSubFilter::GetIsEmbeddedSubStream( int iSelected, bool *fIsEmbedded )
2224 CAutoLock cAutolock(&m_csQueueLock);
2226 HRESULT hr = E_INVALIDARG;
2227 if (!fIsEmbedded)
2229 return S_FALSE;
2232 int i = iSelected;
2233 *fIsEmbedded = false;
2235 POSITION pos = m_pSubStreams.GetHeadPosition();
2236 POSITION pos2 = m_fIsSubStreamEmbeded.GetHeadPosition();
2237 while(i >= 0 && pos)
2239 CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
2240 bool isEmbedded = m_fIsSubStreamEmbeded.GetNext(pos2);
2241 if(i < pSubStream->GetStreamCount())
2243 hr = NOERROR;
2244 *fIsEmbedded = isEmbedded;
2245 break;
2248 i -= pSubStream->GetStreamCount();
2250 return hr;
2253 void CDirectVobSubFilter::SetYuvMatrix()
2255 ColorConvTable::YuvMatrixType yuv_matrix = ColorConvTable::BT601;
2256 ColorConvTable::YuvRangeType yuv_range = ColorConvTable::RANGE_TV;
2258 if ( m_xy_int_opt[INT_COLOR_SPACE]==CDirectVobSub::YuvMatrix_AUTO )
2260 switch(m_script_selected_yuv)
2262 case CSimpleTextSubtitle::YCbCrMatrix_BT601:
2263 yuv_matrix = ColorConvTable::BT601;
2264 break;
2265 case CSimpleTextSubtitle::YCbCrMatrix_BT709:
2266 yuv_matrix = ColorConvTable::BT709;
2267 break;
2268 case CSimpleTextSubtitle::YCbCrMatrix_AUTO:
2269 default:
2270 yuv_matrix = ColorConvTable::BT601;
2271 break;
2274 else
2276 switch(m_xy_int_opt[INT_COLOR_SPACE])
2278 case CDirectVobSub::BT_601:
2279 yuv_matrix = ColorConvTable::BT601;
2280 break;
2281 case CDirectVobSub::BT_709:
2282 yuv_matrix = ColorConvTable::BT709;
2283 break;
2284 case CDirectVobSub::GUESS:
2285 default:
2286 yuv_matrix = (m_w > m_bt601Width || m_h > m_bt601Height) ? ColorConvTable::BT709 : ColorConvTable::BT601;
2287 break;
2291 if( m_xy_int_opt[INT_YUV_RANGE]==CDirectVobSub::YuvRange_Auto )
2293 switch(m_script_selected_range)
2295 case CSimpleTextSubtitle::YCbCrRange_PC:
2296 yuv_range = ColorConvTable::RANGE_PC;
2297 break;
2298 case CSimpleTextSubtitle::YCbCrRange_TV:
2299 yuv_range = ColorConvTable::RANGE_TV;
2300 break;
2301 case CSimpleTextSubtitle::YCbCrRange_AUTO:
2302 default:
2303 yuv_range = ColorConvTable::RANGE_TV;
2304 break;
2307 else
2309 switch(m_xy_int_opt[INT_YUV_RANGE])
2311 case CDirectVobSub::YuvRange_TV:
2312 yuv_range = ColorConvTable::RANGE_TV;
2313 break;
2314 case CDirectVobSub::YuvRange_PC:
2315 yuv_range = ColorConvTable::RANGE_PC;
2316 break;
2317 case CDirectVobSub::YuvRange_Auto:
2318 yuv_range = ColorConvTable::RANGE_TV;
2319 break;
2323 ColorConvTable::SetDefaultConvType(yuv_matrix, yuv_range);
2326 // IDirectVobSubXy
2328 STDMETHODIMP CDirectVobSubFilter::XySetBool( int field, bool value )
2330 CAutoLock cAutolock(&m_csQueueLock);
2331 HRESULT hr = CDirectVobSub::XySetBool(field, value);
2332 if(hr != NOERROR)
2334 return hr;
2336 switch(field)
2338 case DirectVobSubXyOptions::BOOL_FOLLOW_UPSTREAM_PREFERRED_ORDER:
2339 m_donot_follow_upstream_preferred_order = !m_xy_bool_opt[BOOL_FOLLOW_UPSTREAM_PREFERRED_ORDER];
2340 break;
2341 default:
2342 hr = E_NOTIMPL;
2343 break;
2345 return hr;
2348 STDMETHODIMP CDirectVobSubFilter::XySetInt( int field, int value )
2350 CAutoLock cAutolock(&m_csQueueLock);
2351 HRESULT hr = CDirectVobSub::XySetInt(field, value);
2352 if(hr != NOERROR)
2354 return hr;
2356 switch(field)
2358 case DirectVobSubXyOptions::INT_COLOR_SPACE:
2359 case DirectVobSubXyOptions::INT_YUV_RANGE:
2360 SetYuvMatrix();
2361 break;
2362 case DirectVobSubXyOptions::INT_OVERLAY_CACHE_MAX_ITEM_NUM:
2363 CacheManager::GetOverlayMruCache()->SetMaxItemNum(m_xy_int_opt[field]);
2364 break;
2365 case DirectVobSubXyOptions::INT_SCAN_LINE_DATA_CACHE_MAX_ITEM_NUM:
2366 CacheManager::GetScanLineData2MruCache()->SetMaxItemNum(m_xy_int_opt[field]);
2367 break;
2368 case DirectVobSubXyOptions::INT_PATH_DATA_CACHE_MAX_ITEM_NUM:
2369 CacheManager::GetPathDataMruCache()->SetMaxItemNum(m_xy_int_opt[field]);
2370 break;
2371 case DirectVobSubXyOptions::INT_OVERLAY_NO_BLUR_CACHE_MAX_ITEM_NUM:
2372 CacheManager::GetOverlayNoBlurMruCache()->SetMaxItemNum(m_xy_int_opt[field]);
2373 break;
2374 case DirectVobSubXyOptions::INT_BITMAP_MRU_CACHE_ITEM_NUM:
2375 CacheManager::GetBitmapMruCache()->SetMaxItemNum(m_xy_int_opt[field]);
2376 break;
2377 case DirectVobSubXyOptions::INT_CLIPPER_MRU_CACHE_ITEM_NUM:
2378 CacheManager::GetClipperAlphaMaskMruCache()->SetMaxItemNum(m_xy_int_opt[field]);
2379 break;
2380 case DirectVobSubXyOptions::INT_TEXT_INFO_CACHE_ITEM_NUM:
2381 CacheManager::GetTextInfoCache()->SetMaxItemNum(m_xy_int_opt[field]);
2382 break;
2383 case DirectVobSubXyOptions::INT_ASS_TAG_LIST_CACHE_ITEM_NUM:
2384 CacheManager::GetAssTagListMruCache()->SetMaxItemNum(m_xy_int_opt[field]);
2385 break;
2386 case DirectVobSubXyOptions::INT_SUBPIXEL_POS_LEVEL:
2387 SubpixelPositionControler::GetGlobalControler().SetSubpixelLevel( static_cast<SubpixelPositionControler::SUBPIXEL_LEVEL>(m_xy_int_opt[field]) );
2388 break;
2389 default:
2390 hr = E_NOTIMPL;
2391 break;
2394 return hr;