Changing to new interface. [PART 16]
[xy_vsfilter.git] / src / filters / transform / vsfilter / DirectVobSubFilter.cpp
blob93eaca065a3ce79db46d2d0e838b3709cb16b518
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 ////////////////////////////////////////////////////////////////////////////
57 // Constructor
60 CDirectVobSubFilter::CDirectVobSubFilter(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid)
61 : CBaseVideoFilter(NAME("CDirectVobSubFilter"), punk, phr, clsid)
62 , m_nSubtitleId(-1)
63 , m_fMSMpeg4Fix(false)
64 , m_fps(25)
66 DbgLog((LOG_TRACE, 3, _T("CDirectVobSubFilter::CDirectVobSubFilter")));
68 // and then, anywhere you need it:
70 #ifdef __DO_LOG
71 LPTSTR strDLLPath = new TCHAR[_MAX_PATH];
72 ::GetModuleFileName( reinterpret_cast<HINSTANCE>(&__ImageBase), strDLLPath, _MAX_PATH);
73 CString dllPath = strDLLPath;
74 dllPath += ".properties";
75 xy_logger::doConfigure( dllPath.GetString() );
76 #endif
78 AFX_MANAGE_STATE(AfxGetStaticModuleState());
80 m_hdc = 0;
81 m_hbm = 0;
82 m_hfont = 0;
85 LOGFONT lf;
86 memset(&lf, 0, sizeof(lf));
87 lf.lfCharSet = DEFAULT_CHARSET;
88 lf.lfOutPrecision = OUT_CHARACTER_PRECIS;
89 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
90 lf.lfQuality = ANTIALIASED_QUALITY;
91 HDC hdc = GetDC(NULL);
92 lf.lfHeight = 28;
93 //MulDiv(20, GetDeviceCaps(hdc, LOGPIXELSY), 54);
94 ReleaseDC(NULL, hdc);
95 lf.lfWeight = FW_BOLD;
96 _tcscpy(lf.lfFaceName, _T("Arial"));
97 m_hfont = CreateFontIndirect(&lf);
100 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Hint"), _T("The first three are fixed, but you can add more up to ten entries."));
101 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path0"), _T("."));
102 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path1"), _T("c:\\subtitles"));
103 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path2"), _T(".\\subtitles"));
105 m_fLoading = true;
107 m_hSystrayThread = 0;
108 m_tbid.hSystrayWnd = NULL;
109 m_tbid.graph = NULL;
110 m_tbid.fRunOnce = false;
111 m_tbid.fShowIcon = (theApp.m_AppName.Find(_T("zplayer"), 0) < 0 || !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_ENABLEZPICON), 0));
113 HRESULT hr = S_OK;
114 m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
115 ASSERT(SUCCEEDED(hr));
117 CAMThread::Create();
118 m_frd.EndThreadEvent.Create(0, FALSE, FALSE, 0);
119 m_frd.RefreshEvent.Create(0, FALSE, FALSE, 0);
121 memset(&m_CurrentVIH2, 0, sizeof(VIDEOINFOHEADER2));
123 m_donot_follow_upstream_preferred_order = !m_fFollowUpstreamPreferredOrder;
125 m_time_alphablt = m_time_rasterization = 0;
127 m_script_selected_yuv = CSimpleTextSubtitle::YCbCrMatrix_AUTO;
128 m_script_selected_range = CSimpleTextSubtitle::YCbCrRange_AUTO;
131 CDirectVobSubFilter::~CDirectVobSubFilter()
133 CAutoLock cAutoLock(&m_csQueueLock);
134 if(m_simple_provider)
136 DbgLog((LOG_TRACE, 3, "~CDirectVobSubFilter::Invalidate"));
137 m_simple_provider->Invalidate();
139 m_simple_provider = NULL;
141 if(m_hfont) {DeleteObject(m_hfont); m_hfont = 0;}
142 if(m_hbm) {DeleteObject(m_hbm); m_hbm = 0;}
143 if(m_hdc) {DeleteObject(m_hdc); m_hdc = 0;}
145 for(int i = 0; i < m_pTextInput.GetCount(); i++)
146 delete m_pTextInput[i];
148 m_frd.EndThreadEvent.Set();
149 CAMThread::Close();
151 DbgLog((LOG_TRACE, 3, _T("CDirectVobSubFilter::~CDirectVobSubFilter")));
153 //Trace(_T("CDirectVobSubFilter::~CDirectVobSubFilter"));
154 //ReleaseTracer;
157 STDMETHODIMP CDirectVobSubFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
159 CheckPointer(ppv, E_POINTER);
161 return
162 QI(IDirectVobSub)
163 QI(IDirectVobSub2)
164 QI(IDirectVobSubXy)
165 QI(IFilterVersion)
166 QI(ISpecifyPropertyPages)
167 QI(IAMStreamSelect)
168 __super::NonDelegatingQueryInterface(riid, ppv);
171 // CBaseVideoFilter
173 void CDirectVobSubFilter::GetOutputSize(int& w, int& h, int& arx, int& ary)
175 CSize s(w, h), os = s;
176 AdjustFrameSize(s);
177 w = s.cx;
178 h = s.cy;
180 if(w != os.cx)
182 while(arx < 100) arx *= 10, ary *= 10;
183 arx = arx * w / os.cx;
186 if(h != os.cy)
188 while(ary < 100) arx *= 10, ary *= 10;
189 ary = ary * h / os.cy;
193 HRESULT CDirectVobSubFilter::TryNotCopy(IMediaSample* pIn, const CMediaType& mt, const BITMAPINFOHEADER& bihIn )
195 CSize sub(m_w, m_h);
196 CSize in(bihIn.biWidth, bihIn.biHeight);
197 BYTE* pDataIn = NULL;
198 if(FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn)
199 return S_FALSE;
200 if( sub==in )
202 m_spd.bits = pDataIn;
204 else
206 m_spd.bits = static_cast<BYTE*>(m_pTempPicBuff);
207 bool fYV12 = (mt.subtype == MEDIASUBTYPE_YV12 || mt.subtype == MEDIASUBTYPE_I420 || mt.subtype == MEDIASUBTYPE_IYUV);
208 bool fNV12 = (mt.subtype == MEDIASUBTYPE_NV12 || mt.subtype == MEDIASUBTYPE_NV21);
209 bool fP010 = (mt.subtype == MEDIASUBTYPE_P010 || mt.subtype == MEDIASUBTYPE_P016);
211 int bpp = fP010 ? 16 : (fYV12||fNV12) ? 8 : bihIn.biBitCount;
212 DWORD black = fP010 ? 0x10001000 : (fYV12||fNV12) ? 0x10101010 : (bihIn.biCompression == '2YUY') ? 0x80108010 : 0;
215 if(FAILED(Copy((BYTE*)m_pTempPicBuff, pDataIn, sub, in, bpp, mt.subtype, black)))
216 return E_FAIL;
218 if(fYV12)
220 BYTE* pSubV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
221 BYTE* pInV = pDataIn + (in.cx*bpp>>3)*in.cy;
222 sub.cx >>= 1; sub.cy >>= 1; in.cx >>= 1; in.cy >>= 1;
223 BYTE* pSubU = pSubV + (sub.cx*bpp>>3)*sub.cy;
224 BYTE* pInU = pInV + (in.cx*bpp>>3)*in.cy;
225 if(FAILED(Copy(pSubV, pInV, sub, in, bpp, mt.subtype, 0x80808080)))
226 return E_FAIL;
227 if(FAILED(Copy(pSubU, pInU, sub, in, bpp, mt.subtype, 0x80808080)))
228 return E_FAIL;
230 else if (fP010)
232 BYTE* pSubUV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
233 BYTE* pInUV = pDataIn + (in.cx*bpp>>3)*in.cy;
234 sub.cy >>= 1; in.cy >>= 1;
235 if(FAILED(Copy(pSubUV, pInUV, sub, in, bpp, mt.subtype, 0x80008000)))
236 return E_FAIL;
238 else if(fNV12) {
239 BYTE* pSubUV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
240 BYTE* pInUV = pDataIn + (in.cx*bpp>>3)*in.cy;
241 sub.cy >>= 1;
242 in.cy >>= 1;
243 if(FAILED(Copy(pSubUV, pInUV, sub, in, bpp, mt.subtype, 0x80808080)))
244 return E_FAIL;
247 return S_OK;
250 HRESULT CDirectVobSubFilter::Transform(IMediaSample* pIn)
252 XY_LOG_ONCE(0, _T("CDirectVobSubFilter::Transform"));
253 HRESULT hr;
256 REFERENCE_TIME rtStart, rtStop;
257 if(SUCCEEDED(pIn->GetTime(&rtStart, &rtStop)))
259 double dRate = m_pInput->CurrentRate();
261 m_tPrev = m_pInput->CurrentStartTime() + dRate*rtStart;
263 REFERENCE_TIME rtAvgTimePerFrame = rtStop - rtStart;
264 if(CComQIPtr<ISubClock2> pSC2 = m_pSubClock)
266 REFERENCE_TIME rt;
267 if(S_OK == pSC2->GetAvgTimePerFrame(&rt))
268 rtAvgTimePerFrame = rt;
271 m_fps = 10000000.0/rtAvgTimePerFrame / dRate;
277 CAutoLock cAutoLock(&m_csQueueLock);
279 if(m_simple_provider)
281 m_simple_provider->SetTime(CalcCurrentTime());
282 m_simple_provider->SetFPS(m_fps);
289 const CMediaType& mt = m_pInput->CurrentMediaType();
291 BITMAPINFOHEADER bihIn;
292 ExtractBIH(&mt, &bihIn);
294 hr = TryNotCopy(pIn, mt, bihIn);
295 if( hr!=S_OK )
297 //fix me: log error
298 return hr;
302 SubPicDesc spd = m_spd;
304 CComPtr<IMediaSample> pOut;
305 BYTE* pDataOut = NULL;
306 if(FAILED(hr = GetDeliveryBuffer(spd.w, spd.h, &pOut))
307 || FAILED(hr = pOut->GetPointer(&pDataOut)))
308 return hr;
309 pOut->SetTime(&rtStart, &rtStop);
310 pOut->SetMediaTime(NULL, NULL);
311 pOut->SetDiscontinuity(pIn->IsDiscontinuity() == S_OK);
312 pOut->SetSyncPoint(pIn->IsSyncPoint() == S_OK);
313 pOut->SetPreroll(pIn->IsPreroll() == S_OK);
316 BITMAPINFOHEADER bihOut;
317 ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
319 bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3;
320 bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3;
322 bool fFlip = fInputFlipped != fOutputFlipped;
323 if(m_fFlipPicture) fFlip = !fFlip;
324 if(m_fMSMpeg4Fix) fFlip = !fFlip;
326 bool fFlipSub = fOutputFlipped;
327 if(m_fFlipSubtitles) fFlipSub = !fFlipSub;
332 CAutoLock cAutoLock(&m_csQueueLock);
334 if(m_simple_provider)
336 CComPtr<ISimpleSubPic> pSubPic;
337 //int timeStamp1 = GetTickCount();
338 bool lookupResult = m_simple_provider->LookupSubPic(CalcCurrentTime(), &pSubPic);
339 //int timeStamp2 = GetTickCount();
340 //m_time_rasterization += timeStamp2-timeStamp1;
342 if(lookupResult && pSubPic)
344 if(fFlip ^ fFlipSub)
345 spd.h = -spd.h;
346 pSubPic->AlphaBlt(&spd);
347 DbgLog((LOG_TRACE,3,"AlphaBlt time:%lu", (ULONG)(CalcCurrentTime()/10000)));
351 CopyBuffer(pDataOut, (BYTE*)spd.bits, spd.w, abs(spd.h)*(fFlip?-1:1), spd.pitch, mt.subtype);
353 PrintMessages(pDataOut);
354 return m_pOutput->Deliver(pOut);
357 // CBaseFilter
359 CBasePin* CDirectVobSubFilter::GetPin(int n)
361 if(n < __super::GetPinCount())
362 return __super::GetPin(n);
364 n -= __super::GetPinCount();
366 if(n >= 0 && n < m_pTextInput.GetCount())
367 return m_pTextInput[n];
369 n -= m_pTextInput.GetCount();
371 return NULL;
374 int CDirectVobSubFilter::GetPinCount()
376 return __super::GetPinCount() + m_pTextInput.GetCount();
379 HRESULT CDirectVobSubFilter::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
381 if(pGraph)
383 AFX_MANAGE_STATE(AfxGetStaticModuleState());
385 if(!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 0))
387 unsigned __int64 ver = GetFileVersion(_T("divx_c32.ax"));
388 if(((ver >> 48)&0xffff) == 4 && ((ver >> 32)&0xffff) == 2)
390 DWORD dwVersion = GetVersion();
391 DWORD dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
392 DWORD dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
394 if(dwVersion < 0x80000000 && dwWindowsMajorVersion >= 5)
396 AfxMessageBox(IDS_DIVX_WARNING);
397 theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 1);
402 /*removeme*/
403 if(!g_RegOK)
405 DllRegisterServer();
406 g_RegOK = true;
409 else
411 if(m_hSystrayThread)
413 SendMessage(m_tbid.hSystrayWnd, WM_CLOSE, 0, 0);
415 if(WaitForSingleObject(m_hSystrayThread, 10000) != WAIT_OBJECT_0)
417 DbgLog((LOG_TRACE, 0, _T("CALL THE AMBULANCE!!!")));
418 TerminateThread(m_hSystrayThread, (DWORD)-1);
421 m_hSystrayThread = 0;
425 return __super::JoinFilterGraph(pGraph, pName);
428 STDMETHODIMP CDirectVobSubFilter::QueryFilterInfo(FILTER_INFO* pInfo)
430 CheckPointer(pInfo, E_POINTER);
431 ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO));
433 if(!get_Forced())
434 return __super::QueryFilterInfo(pInfo);
436 wcscpy(pInfo->achName, L"DirectVobSub (forced auto-loading version)");
437 if(pInfo->pGraph = m_pGraph) m_pGraph->AddRef();
439 return S_OK;
442 // CTransformFilter
444 HRESULT CDirectVobSubFilter::SetMediaType(PIN_DIRECTION dir, const CMediaType* pmt)
446 HRESULT hr = __super::SetMediaType(dir, pmt);
447 if(FAILED(hr)) return hr;
449 if(dir == PINDIR_INPUT)
451 CAutoLock cAutoLock(&m_csReceive);
453 REFERENCE_TIME atpf =
454 pmt->formattype == FORMAT_VideoInfo ? ((VIDEOINFOHEADER*)pmt->Format())->AvgTimePerFrame :
455 pmt->formattype == FORMAT_VideoInfo2 ? ((VIDEOINFOHEADER2*)pmt->Format())->AvgTimePerFrame :
458 m_fps = atpf ? 10000000.0 / atpf : 25;
460 if (pmt->formattype == FORMAT_VideoInfo2)
461 m_CurrentVIH2 = *(VIDEOINFOHEADER2*)pmt->Format();
463 DbgLog((LOG_TRACE, 3, "SetMediaType => InitSubPicQueue"));
464 InitSubPicQueue();
466 else if(dir == PINDIR_OUTPUT)
471 return hr;
474 HRESULT CDirectVobSubFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
476 if(dir == PINDIR_INPUT)
479 else if(dir == PINDIR_OUTPUT)
481 /*removeme*/
482 if(HmGyanusVagyTeNekem(pPin)) return(E_FAIL);
485 return __super::CheckConnect(dir, pPin);
488 HRESULT CDirectVobSubFilter::CompleteConnect(PIN_DIRECTION dir, IPin* pReceivePin)
490 bool reconnected = false;
491 if(dir == PINDIR_INPUT)
493 DbgLog((LOG_TRACE, 3, TEXT("connect input")));
494 DumpGraph(m_pGraph,0);
495 CComPtr<IBaseFilter> pFilter;
497 // needed when we have a decoder with a version number of 3.x
498 if(SUCCEEDED(m_pGraph->FindFilterByName(L"DivX MPEG-4 DVD Video Decompressor ", &pFilter))
499 && (GetFileVersion(_T("divx_c32.ax")) >> 48) <= 4
500 || SUCCEEDED(m_pGraph->FindFilterByName(L"Microcrap MPEG-4 Video Decompressor", &pFilter))
501 || SUCCEEDED(m_pGraph->FindFilterByName(L"Microsoft MPEG-4 Video Decompressor", &pFilter))
502 && (GetFileVersion(_T("mpg4ds32.ax")) >> 48) <= 3)
504 m_fMSMpeg4Fix = true;
507 else if(dir == PINDIR_OUTPUT)
509 DbgLog((LOG_TRACE, 3, TEXT("connect output")));
510 DumpGraph(m_pGraph,0);
511 const CMediaType* mtIn = &(m_pInput->CurrentMediaType());
512 const CMediaType* mtOut = &(m_pOutput->CurrentMediaType());
513 CMediaType desiredMt;
514 int position = 0;
515 HRESULT hr;
517 bool can_reconnect = false;
518 bool can_transform = (DoCheckTransform(mtIn, mtOut, true)==S_OK);
519 if( mtIn->subtype!=mtOut->subtype )
521 position = GetOutputSubtypePosition(mtOut->subtype);
522 if(position>=0)
524 hr = GetMediaType(position, &desiredMt);
525 if (hr!=S_OK)
527 DbgLog((LOG_ERROR, 3, TEXT("Unexpected error when GetMediaType, position:%d"), position));
529 else
531 hr = DoCheckTransform(&desiredMt, mtOut, true);
532 if (hr!=S_OK)
534 DbgLog((LOG_TRACE, 3, TEXT("Transform not accept:")));
535 DisplayType(0,&desiredMt);
536 DisplayType(0,mtOut);
538 else
540 hr = m_pInput->GetConnected()->QueryAccept(&desiredMt);
541 if(hr!=S_OK)
543 DbgLog((LOG_TRACE, 3, TEXT("Upstream not accept:")));
544 DisplayType(0, &desiredMt);
546 else
548 can_reconnect = true;
549 DbgLog((LOG_ERROR, 3, TEXT("Can use the same subtype!")));
554 else
556 DbgLog((LOG_ERROR, 3, TEXT("Cannot use the same subtype!")));
559 if(!can_reconnect && !can_transform)
561 position = 0;
564 hr = GetMediaType(position, &desiredMt);
565 ++position;
566 //if( FAILED(hr) )
567 if( hr!=S_OK )
568 break;
570 DbgLog((LOG_TRACE, 3, TEXT("Checking reconnect with media type:")));
571 DisplayType(0, &desiredMt);
573 if( DoCheckTransform(&desiredMt, mtOut, true)!=S_OK ||
574 m_pInput->GetConnected()->QueryAccept(&desiredMt)!=S_OK )
576 continue;
578 else
580 can_reconnect = true;
581 break;
583 } while ( true );
585 if ( can_reconnect )
587 if (SUCCEEDED(ReconnectPin(m_pInput, &desiredMt)))
589 reconnected = true;
590 DumpGraph(m_pGraph,0);
591 //m_pInput->SetMediaType(&desiredMt);
592 DbgLog((LOG_TRACE, 3, TEXT("reconnected succeed!")));
595 else if(!can_transform)
597 DbgLog((LOG_TRACE, 3, TEXT("Failed to agree reconnect type!")));
598 if(m_pInput->IsConnected())
600 m_pInput->GetConnected()->Disconnect();
601 m_pInput->Disconnect();
603 if(m_pOutput->IsConnected())
605 m_pOutput->GetConnected()->Disconnect();
606 m_pOutput->Disconnect();
608 return VFW_E_TYPE_NOT_ACCEPTED;
611 if (!reconnected && m_pOutput->IsConnected())
613 if(!m_hSystrayThread && !m_fHideTrayIcon)
615 m_tbid.graph = m_pGraph;
616 m_tbid.dvs = static_cast<IDirectVobSub*>(this);
618 DWORD tid;
619 m_hSystrayThread = CreateThread(0, 0, SystrayThreadProc, &m_tbid, 0, &tid);
621 m_pInput->SetMediaType( &m_pInput->CurrentMediaType() );
624 HRESULT hr = __super::CompleteConnect(dir, pReceivePin);
625 DbgLog((LOG_TRACE, 3, TEXT("connect fininshed!")));
626 DumpGraph(m_pGraph,0);
627 return hr;
630 HRESULT CDirectVobSubFilter::BreakConnect(PIN_DIRECTION dir)
632 if(dir == PINDIR_INPUT)
634 //if(m_pOutput->IsConnected())
636 // m_pOutput->GetConnected()->Disconnect();
637 // m_pOutput->Disconnect();
640 else if(dir == PINDIR_OUTPUT)
642 // not really needed, but may free up a little memory
643 CAutoLock cAutoLock(&m_csQueueLock);
644 m_simple_provider = NULL;
647 return __super::BreakConnect(dir);
650 HRESULT CDirectVobSubFilter::StartStreaming()
652 /* WARNING: calls to m_pGraph member functions from within this function will generate deadlock with Haali
653 * Video Renderer in MPC. Reason is that CAutoLock's variables in IFilterGraph functions are overriden by
654 * CFGManager class.
657 m_fLoading = false;
659 DbgLog((LOG_TRACE, 3, "StartStreaming => InitSubPicQueue"));
660 InitSubPicQueue();
662 m_tbid.fRunOnce = true;
664 put_MediaFPS(m_fMediaFPSEnabled, m_MediaFPS);
666 return __super::StartStreaming();
669 HRESULT CDirectVobSubFilter::StopStreaming()
671 InvalidateSubtitle();
673 //xy Timing
674 //FILE * timingFile = fopen("C:\\vsfilter_timing.txt", "at");
675 //fprintf(timingFile, "%s:%ld %s:%ld\n", "m_time_alphablt", m_time_alphablt, "m_time_rasterization", m_time_rasterization);
676 //fclose(timingFile);
678 return __super::StopStreaming();
681 HRESULT CDirectVobSubFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
683 m_tPrev = tStart;
684 return __super::NewSegment(tStart, tStop, dRate);
689 REFERENCE_TIME CDirectVobSubFilter::CalcCurrentTime()
691 REFERENCE_TIME rt = m_pSubClock ? m_pSubClock->GetTime() : m_tPrev;
692 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)
695 void CDirectVobSubFilter::InitSubPicQueue()
697 CAutoLock cAutoLock(&m_csQueueLock);
699 CacheManager::GetPathDataMruCache()->SetMaxItemNum(m_path_data_cache_max_item_num);
700 CacheManager::GetScanLineData2MruCache()->SetMaxItemNum(m_scan_line_data_cache_max_item_num);
701 CacheManager::GetOverlayNoBlurMruCache()->SetMaxItemNum(m_overlay_no_blur_cache_max_item_num);
702 CacheManager::GetOverlayMruCache()->SetMaxItemNum(m_overlay_cache_max_item_num);
703 SubpixelPositionControler::GetGlobalControler().SetSubpixelLevel( static_cast<SubpixelPositionControler::SUBPIXEL_LEVEL>(m_subpixel_pos_level) );
705 m_simple_provider = NULL;
707 const GUID& subtype = m_pInput->CurrentMediaType().subtype;
709 BITMAPINFOHEADER bihIn;
710 ExtractBIH(&m_pInput->CurrentMediaType(), &bihIn);
712 m_spd.type = -1;
714 if(subtype == MEDIASUBTYPE_YV12) m_spd.type = MSP_YV12;
715 else if(subtype == MEDIASUBTYPE_P010) m_spd.type = MSP_P010;
716 else if(subtype == MEDIASUBTYPE_P016) m_spd.type = MSP_P016;
717 else if(subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV) m_spd.type = MSP_IYUV;
718 else if(subtype == MEDIASUBTYPE_YUY2) m_spd.type = MSP_YUY2;
719 else if(subtype == MEDIASUBTYPE_RGB32) m_spd.type = MSP_RGB32;
720 else if(subtype == MEDIASUBTYPE_RGB24) m_spd.type = MSP_RGB24;
721 else if(subtype == MEDIASUBTYPE_RGB565) m_spd.type = MSP_RGB16;
722 else if(subtype == MEDIASUBTYPE_RGB555) m_spd.type = MSP_RGB15;
723 else if(subtype == MEDIASUBTYPE_NV12) m_spd.type = MSP_NV12;
724 else if(subtype == MEDIASUBTYPE_NV21) m_spd.type = MSP_NV21;
726 m_spd.w = m_w;
727 m_spd.h = m_h;
728 m_spd.bpp = (m_spd.type == MSP_P010 || m_spd.type == MSP_P016) ? 16 :
729 (m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV || m_spd.type == MSP_NV12 || m_spd.type == MSP_NV21) ? 8 : bihIn.biBitCount;
730 m_spd.pitch = m_spd.w*m_spd.bpp>>3;
732 m_pTempPicBuff.Free();
733 if(m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV || m_spd.type == MSP_NV12 || m_spd.type == MSP_NV21)
734 m_pTempPicBuff.Allocate(4*m_spd.pitch*m_spd.h);//fix me: can be smaller
735 else if(m_spd.type == MSP_P010 || m_spd.type == MSP_P016)
736 m_pTempPicBuff.Allocate(m_spd.pitch*m_spd.h+m_spd.pitch*m_spd.h/2);
737 else
738 m_pTempPicBuff.Allocate(m_spd.pitch*m_spd.h);
739 m_spd.bits = (void*)m_pTempPicBuff;
741 CSize video(bihIn.biWidth, bihIn.biHeight), window = video;
742 if(AdjustFrameSize(window)) video += video;
743 ASSERT(window == CSize(m_w, m_h));
744 CRect video_rect(CPoint((window.cx - video.cx)/2, (window.cy - video.cy)/2), video);
746 HRESULT hr = S_OK;
747 //m_pSubPicQueue = m_fDoPreBuffering
748 // ? (ISubPicQueue*)new CSubPicQueue(MAX_SUBPIC_QUEUE_LENGTH, pSubPicAllocator, &hr)
749 // : (ISubPicQueue*)new CSubPicQueueNoThread(pSubPicAllocator, &hr);
750 m_simple_provider = new SimpleSubPicProvider2(m_spd.type, CSize(m_w, m_h), window, video_rect, &hr);
752 if(FAILED(hr)) m_simple_provider = NULL;
754 UpdateSubtitle(false);
756 if(m_hbm) {DeleteObject(m_hbm); m_hbm = NULL;}
757 if(m_hdc) {DeleteDC(m_hdc); m_hdc = NULL;}
759 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};
760 m_hdc = CreateCompatibleDC(NULL);
761 m_hbm = CreateDIBSection(m_hdc, (BITMAPINFO*)&b, DIB_RGB_COLORS, NULL, NULL, 0);
763 BITMAP bm;
764 GetObject(m_hbm, sizeof(bm), &bm);
765 memsetd(bm.bmBits, 0xFF000000, bm.bmHeight*bm.bmWidthBytes);
768 bool CDirectVobSubFilter::AdjustFrameSize(CSize& s)
770 int horizontal, vertical, resx2, resx2minw, resx2minh;
771 get_ExtendPicture(&horizontal, &vertical, &resx2, &resx2minw, &resx2minh);
773 bool fRet = (resx2 == 1) || (resx2 == 2 && s.cx*s.cy <= resx2minw*resx2minh);
775 if(fRet)
777 s.cx <<= 1;
778 s.cy <<= 1;
781 int h;
782 switch(vertical&0x7f)
784 case 1:
785 h = s.cx * 9 / 16;
786 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
787 break;
788 case 2:
789 h = s.cx * 3 / 4;
790 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
791 break;
792 case 3:
793 h = 480;
794 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
795 break;
796 case 4:
797 h = 576;
798 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
799 break;
802 if(horizontal == 1)
804 s.cx = (s.cx + 31) & ~31;
805 s.cy = (s.cy + 1) & ~1;
808 return(fRet);
811 STDMETHODIMP CDirectVobSubFilter::Count(DWORD* pcStreams)
813 if(!pcStreams) return E_POINTER;
815 *pcStreams = 0;
817 int nLangs = 0;
818 if(SUCCEEDED(get_LanguageCount(&nLangs)))
819 (*pcStreams) += nLangs;
821 (*pcStreams) += 2; // enable ... disable
823 (*pcStreams) += 2; // normal flipped
825 return S_OK;
828 #define MAXPREFLANGS 5
830 int CDirectVobSubFilter::FindPreferedLanguage(bool fHideToo)
832 AFX_MANAGE_STATE(AfxGetStaticModuleState());
834 int nLangs;
835 get_LanguageCount(&nLangs);
837 if(nLangs <= 0) return(0);
839 for(int i = 0; i < MAXPREFLANGS; i++)
841 CString tmp;
842 tmp.Format(IDS_RL_LANG, i);
844 CString lang = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
846 if(!lang.IsEmpty())
848 for(int ret = 0; ret < nLangs; ret++)
850 CString l;
851 WCHAR* pName = NULL;
852 get_LanguageName(ret, &pName);
853 l = pName;
854 CoTaskMemFree(pName);
856 if(!l.CompareNoCase(lang)) return(ret);
861 return(0);
864 void CDirectVobSubFilter::UpdatePreferedLanguages(CString l)
866 AFX_MANAGE_STATE(AfxGetStaticModuleState());
868 CString langs[MAXPREFLANGS+1];
870 int i = 0, j = 0, k = -1;
871 for(; i < MAXPREFLANGS; i++)
873 CString tmp;
874 tmp.Format(IDS_RL_LANG, i);
876 langs[j] = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
878 if(!langs[j].IsEmpty())
880 if(!langs[j].CompareNoCase(l)) k = j;
881 j++;
885 if(k == -1)
887 langs[k = j] = l;
888 j++;
891 // move the selected to the top of the list
893 while(k > 0)
895 CString tmp = langs[k]; langs[k] = langs[k-1]; langs[k-1] = tmp;
896 k--;
899 // move "Hide subtitles" to the last position if it wasn't our selection
901 CString hidesubs;
902 hidesubs.LoadString(IDS_M_HIDESUBTITLES);
904 for(k = 1; k < j; k++)
906 if(!langs[k].CompareNoCase(hidesubs)) break;
909 while(k < j-1)
911 CString tmp = langs[k]; langs[k] = langs[k+1]; langs[k+1] = tmp;
912 k++;
915 for(i = 0; i < j; i++)
917 CString tmp;
918 tmp.Format(IDS_RL_LANG, i);
920 theApp.WriteProfileString(ResStr(IDS_R_PREFLANGS), tmp, langs[i]);
924 STDMETHODIMP CDirectVobSubFilter::Enable(long lIndex, DWORD dwFlags)
926 if(!(dwFlags & AMSTREAMSELECTENABLE_ENABLE))
927 return E_NOTIMPL;
929 int nLangs = 0;
930 get_LanguageCount(&nLangs);
932 if(!(lIndex >= 0 && lIndex < nLangs+2+2))
933 return E_INVALIDARG;
935 int i = lIndex-1;
937 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
939 put_HideSubtitles(false);
941 else if(i >= 0 && i < nLangs)
943 put_HideSubtitles(false);
944 put_SelectedLanguage(i);
946 WCHAR* pName = NULL;
947 if(SUCCEEDED(get_LanguageName(i, &pName)))
949 UpdatePreferedLanguages(CString(pName));
950 if(pName) CoTaskMemFree(pName);
953 else if(i == nLangs && !m_fLoading)
955 put_HideSubtitles(true);
957 else if((i == nLangs+1 || i == nLangs+2) && !m_fLoading)
959 put_Flip(i == nLangs+2, m_fFlipSubtitles);
962 return S_OK;
965 STDMETHODIMP CDirectVobSubFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk)
967 AFX_MANAGE_STATE(AfxGetStaticModuleState());
968 const int FLAG_CMD = 1;
969 const int FLAG_EXTERNAL_SUB = 2;
970 const int FLAG_PICTURE_CMD = 4;
971 const int FLAG_VISIBILITY_CMD = 8;
973 const int GROUP_NUM_BASE = 0x648E40;//random number
975 int nLangs = 0;
976 get_LanguageCount(&nLangs);
978 if(!(lIndex >= 0 && lIndex < nLangs+2+2))
979 return E_INVALIDARG;
981 int i = lIndex-1;
983 if(ppmt) *ppmt = CreateMediaType(&m_pInput->CurrentMediaType());
985 if(pdwFlags)
987 *pdwFlags = 0;
989 if(i == -1 && !m_fHideSubtitles
990 || i >= 0 && i < nLangs && i == m_iSelectedLanguage
991 || i == nLangs && m_fHideSubtitles
992 || i == nLangs+1 && !m_fFlipPicture
993 || i == nLangs+2 && m_fFlipPicture)
995 *pdwFlags |= AMSTREAMSELECTINFO_ENABLED;
999 if(plcid) *plcid = 0;
1001 if(pdwGroup)
1003 *pdwGroup = GROUP_NUM_BASE;
1004 if(i == -1)
1006 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_VISIBILITY_CMD;
1008 else if(i >= 0 && i < nLangs)
1010 bool isEmbedded = false;
1011 if( SUCCEEDED(GetIsEmbeddedSubStream(i, &isEmbedded)) )
1013 if(isEmbedded)
1015 *pdwGroup = GROUP_NUM_BASE & ~(FLAG_CMD | FLAG_EXTERNAL_SUB);
1017 else
1019 *pdwGroup = (GROUP_NUM_BASE & ~FLAG_CMD) | FLAG_EXTERNAL_SUB;
1023 else if(i == nLangs)
1025 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_VISIBILITY_CMD;
1027 else if(i == nLangs+1)
1029 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_PICTURE_CMD;
1031 else if(i == nLangs+2)
1033 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_PICTURE_CMD;
1037 if(ppszName)
1039 *ppszName = NULL;
1041 CStringW str;
1042 if(i == -1) str = ResStr(IDS_M_SHOWSUBTITLES);
1043 else if(i >= 0 && i < nLangs)
1045 get_LanguageName(i, ppszName);
1047 else if(i == nLangs)
1049 str = ResStr(IDS_M_HIDESUBTITLES);
1051 else if(i == nLangs+1)
1053 str = ResStr(IDS_M_ORIGINALPICTURE);
1055 else if(i == nLangs+2)
1057 str = ResStr(IDS_M_FLIPPEDPICTURE);
1060 if(!str.IsEmpty())
1062 *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength()+1)*sizeof(WCHAR));
1063 if(*ppszName == NULL) return S_FALSE;
1064 wcscpy(*ppszName, str);
1068 if(ppObject) *ppObject = NULL;
1070 if(ppUnk) *ppUnk = NULL;
1072 return S_OK;
1075 STDMETHODIMP CDirectVobSubFilter::GetClassID(CLSID* pClsid)
1077 if(pClsid == NULL) return E_POINTER;
1078 *pClsid = m_clsid;
1079 return NOERROR;
1082 STDMETHODIMP CDirectVobSubFilter::GetPages(CAUUID* pPages)
1084 CheckPointer(pPages, E_POINTER);
1086 pPages->cElems = 8;
1087 pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID)*pPages->cElems);
1089 if(pPages->pElems == NULL) return E_OUTOFMEMORY;
1091 int i = 0;
1092 pPages->pElems[i++] = __uuidof(CDVSMainPPage);
1093 pPages->pElems[i++] = __uuidof(CDVSGeneralPPage);
1094 pPages->pElems[i++] = __uuidof(CDVSMiscPPage);
1095 pPages->pElems[i++] = __uuidof(CDVSMorePPage);
1096 pPages->pElems[i++] = __uuidof(CDVSTimingPPage);
1097 pPages->pElems[i++] = __uuidof(CDVSColorPPage);
1098 pPages->pElems[i++] = __uuidof(CDVSPathsPPage);
1099 pPages->pElems[i++] = __uuidof(CDVSAboutPPage);
1101 return NOERROR;
1104 // IDirectVobSub
1106 STDMETHODIMP CDirectVobSubFilter::put_FileName(WCHAR* fn)
1108 AMTRACE((TEXT(__FUNCTION__),0));
1109 HRESULT hr = CDirectVobSub::put_FileName(fn);
1111 if(hr == S_OK && !Open())
1113 m_FileName.Empty();
1114 hr = E_FAIL;
1117 return hr;
1120 STDMETHODIMP CDirectVobSubFilter::get_LanguageCount(int* nLangs)
1122 HRESULT hr = CDirectVobSub::get_LanguageCount(nLangs);
1124 if(hr == NOERROR && nLangs)
1126 CAutoLock cAutolock(&m_csQueueLock);
1128 *nLangs = 0;
1129 POSITION pos = m_pSubStreams.GetHeadPosition();
1130 while(pos) (*nLangs) += m_pSubStreams.GetNext(pos)->GetStreamCount();
1133 return hr;
1136 STDMETHODIMP CDirectVobSubFilter::get_LanguageName(int iLanguage, WCHAR** ppName)
1138 HRESULT hr = CDirectVobSub::get_LanguageName(iLanguage, ppName);
1140 if(!ppName) return E_POINTER;
1142 if(hr == NOERROR)
1144 CAutoLock cAutolock(&m_csQueueLock);
1146 hr = E_INVALIDARG;
1148 int i = iLanguage;
1150 POSITION pos = m_pSubStreams.GetHeadPosition();
1151 while(i >= 0 && pos)
1153 CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
1155 if(i < pSubStream->GetStreamCount())
1157 pSubStream->GetStreamInfo(i, ppName, NULL);
1158 hr = NOERROR;
1159 break;
1162 i -= pSubStream->GetStreamCount();
1166 return hr;
1169 STDMETHODIMP CDirectVobSubFilter::put_SelectedLanguage(int iSelected)
1171 HRESULT hr = CDirectVobSub::put_SelectedLanguage(iSelected);
1173 if(hr == NOERROR)
1175 UpdateSubtitle(false);
1178 return hr;
1181 STDMETHODIMP CDirectVobSubFilter::put_HideSubtitles(bool fHideSubtitles)
1183 HRESULT hr = CDirectVobSub::put_HideSubtitles(fHideSubtitles);
1185 if(hr == NOERROR)
1187 UpdateSubtitle(false);
1190 return hr;
1193 STDMETHODIMP CDirectVobSubFilter::put_PreBuffering(bool fDoPreBuffering)
1195 HRESULT hr = CDirectVobSub::put_PreBuffering(fDoPreBuffering);
1197 if(hr == NOERROR)
1199 DbgLog((LOG_TRACE, 3, "put_PreBuffering => InitSubPicQueue"));
1200 InitSubPicQueue();
1203 return hr;
1206 STDMETHODIMP CDirectVobSubFilter::put_ColorSpace(int colorSpace)
1208 CAutoLock cAutolock(&m_csQueueLock);
1209 HRESULT hr = CDirectVobSub::put_ColorSpace(colorSpace);
1211 if(hr == NOERROR)
1213 SetYuvMatrix();
1216 return hr;
1219 STDMETHODIMP CDirectVobSubFilter::put_YuvRange( int yuvRange )
1221 CAutoLock cAutolock(&m_csQueueLock);
1222 HRESULT hr = CDirectVobSub::put_YuvRange(yuvRange);
1224 if(hr == NOERROR)
1226 SetYuvMatrix();
1229 return hr;
1232 STDMETHODIMP CDirectVobSubFilter::put_Placement(bool fOverridePlacement, int xperc, int yperc)
1234 DbgLog((LOG_TRACE, 3, "%s(%d) %s", __FILE__, __LINE__, __FUNCTION__));
1235 HRESULT hr = CDirectVobSub::put_Placement(fOverridePlacement, xperc, yperc);
1237 if(hr == NOERROR)
1239 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1240 //UpdateSubtitle(true);
1241 UpdateSubtitle(false);
1244 return hr;
1247 STDMETHODIMP CDirectVobSubFilter::put_VobSubSettings(bool fBuffer, bool fOnlyShowForcedSubs, bool fReserved)
1249 HRESULT hr = CDirectVobSub::put_VobSubSettings(fBuffer, fOnlyShowForcedSubs, fReserved);
1251 if(hr == NOERROR)
1253 // UpdateSubtitle(false);
1254 InvalidateSubtitle();
1257 return hr;
1260 STDMETHODIMP CDirectVobSubFilter::put_TextSettings(void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer)
1262 HRESULT hr = CDirectVobSub::put_TextSettings(lf, lflen, color, fShadow, fOutline, fAdvancedRenderer);
1264 if(hr == NOERROR)
1266 // UpdateSubtitle(true);
1267 InvalidateSubtitle();
1270 return hr;
1273 STDMETHODIMP CDirectVobSubFilter::put_SubtitleTiming(int delay, int speedmul, int speeddiv)
1275 HRESULT hr = CDirectVobSub::put_SubtitleTiming(delay, speedmul, speeddiv);
1277 if(hr == NOERROR)
1279 InvalidateSubtitle();
1282 return hr;
1285 STDMETHODIMP CDirectVobSubFilter::put_OverlayCacheMaxItemNum( int overlay_cache_max_item_num )
1287 CAutoLock cAutolock(&m_csQueueLock);
1288 HRESULT hr = CDirectVobSub::put_OverlayCacheMaxItemNum(overlay_cache_max_item_num);
1290 if(hr == NOERROR)
1292 CacheManager::GetOverlayMruCache()->SetMaxItemNum(m_overlay_cache_max_item_num);
1295 return hr;
1298 STDMETHODIMP CDirectVobSubFilter::put_ScanLineDataCacheMaxItemNum( int scan_line_data_cache_max_item_num )
1300 CAutoLock cAutolock(&m_csQueueLock);
1301 HRESULT hr = CDirectVobSub::put_ScanLineDataCacheMaxItemNum(scan_line_data_cache_max_item_num);
1303 if(hr == NOERROR)
1305 CacheManager::GetScanLineData2MruCache()->SetMaxItemNum(m_scan_line_data_cache_max_item_num);
1308 return hr;
1311 STDMETHODIMP CDirectVobSubFilter::put_PathDataCacheMaxItemNum(int path_data_cache_max_item_num)
1313 CAutoLock cAutolock(&m_csQueueLock);
1314 HRESULT hr = CDirectVobSub::put_PathDataCacheMaxItemNum(path_data_cache_max_item_num);
1316 if(hr == NOERROR)
1318 CacheManager::GetPathDataMruCache()->SetMaxItemNum(m_path_data_cache_max_item_num);
1321 return hr;
1324 STDMETHODIMP CDirectVobSubFilter::put_OverlayNoBlurCacheMaxItemNum(int overlay_no_blur_cache_max_item_num)
1326 CAutoLock cAutolock(&m_csQueueLock);
1327 HRESULT hr = CDirectVobSub::put_OverlayNoBlurCacheMaxItemNum(overlay_no_blur_cache_max_item_num);
1329 if(hr == NOERROR)
1331 CacheManager::GetOverlayNoBlurMruCache()->SetMaxItemNum(m_overlay_no_blur_cache_max_item_num);
1334 return hr;
1337 STDMETHODIMP CDirectVobSubFilter::get_CachesInfo(CachesInfo* caches_info)
1339 CAutoLock cAutoLock(&m_csQueueLock);
1340 HRESULT hr = CDirectVobSub::get_CachesInfo(caches_info);
1342 caches_info->path_cache_cur_item_num = CacheManager::GetPathDataMruCache()->GetCurItemNum();
1343 caches_info->path_cache_hit_count = CacheManager::GetPathDataMruCache()->GetCacheHitCount();
1344 caches_info->path_cache_query_count = CacheManager::GetPathDataMruCache()->GetQueryCount();
1345 caches_info->scanline_cache2_cur_item_num= CacheManager::GetScanLineData2MruCache()->GetCurItemNum();
1346 caches_info->scanline_cache2_hit_count = CacheManager::GetScanLineData2MruCache()->GetCacheHitCount();
1347 caches_info->scanline_cache2_query_count = CacheManager::GetScanLineData2MruCache()->GetQueryCount();
1348 caches_info->non_blur_cache_cur_item_num= CacheManager::GetOverlayNoBlurMruCache()->GetCurItemNum();
1349 caches_info->non_blur_cache_hit_count = CacheManager::GetOverlayNoBlurMruCache()->GetCacheHitCount();
1350 caches_info->non_blur_cache_query_count = CacheManager::GetOverlayNoBlurMruCache()->GetQueryCount();
1351 caches_info->overlay_cache_cur_item_num = CacheManager::GetOverlayMruCache()->GetCurItemNum();
1352 caches_info->overlay_cache_hit_count = CacheManager::GetOverlayMruCache()->GetCacheHitCount();
1353 caches_info->overlay_cache_query_count = CacheManager::GetOverlayMruCache()->GetQueryCount();
1355 caches_info->bitmap_cache_cur_item_num = CacheManager::GetBitmapMruCache()->GetCurItemNum();
1356 caches_info->bitmap_cache_hit_count = CacheManager::GetBitmapMruCache()->GetCacheHitCount();
1357 caches_info->bitmap_cache_query_count = CacheManager::GetBitmapMruCache()->GetQueryCount();
1359 caches_info->interpolate_cache_cur_item_num = CacheManager::GetSubpixelVarianceCache()->GetCurItemNum();
1360 caches_info->interpolate_cache_hit_count = CacheManager::GetSubpixelVarianceCache()->GetCacheHitCount();
1361 caches_info->interpolate_cache_query_count = CacheManager::GetSubpixelVarianceCache()->GetQueryCount();
1362 caches_info->text_info_cache_cur_item_num = CacheManager::GetTextInfoCache()->GetCurItemNum();
1363 caches_info->text_info_cache_hit_count = CacheManager::GetTextInfoCache()->GetCacheHitCount();
1364 caches_info->text_info_cache_query_count = CacheManager::GetTextInfoCache()->GetQueryCount();
1366 caches_info->word_info_cache_cur_item_num = CacheManager::GetAssTagListMruCache()->GetCurItemNum();
1367 caches_info->word_info_cache_hit_count = CacheManager::GetAssTagListMruCache()->GetCacheHitCount();
1368 caches_info->word_info_cache_query_count = CacheManager::GetAssTagListMruCache()->GetQueryCount();
1370 caches_info->scanline_cache_cur_item_num = CacheManager::GetScanLineDataMruCache()->GetCurItemNum();
1371 caches_info->scanline_cache_hit_count = CacheManager::GetScanLineDataMruCache()->GetCacheHitCount();
1372 caches_info->scanline_cache_query_count = CacheManager::GetScanLineDataMruCache()->GetQueryCount();
1374 caches_info->overlay_key_cache_cur_item_num = CacheManager::GetOverlayNoOffsetMruCache()->GetCurItemNum();
1375 caches_info->overlay_key_cache_hit_count = CacheManager::GetOverlayNoOffsetMruCache()->GetCacheHitCount();
1376 caches_info->overlay_key_cache_query_count = CacheManager::GetOverlayNoOffsetMruCache()->GetQueryCount();
1378 caches_info->clipper_cache_cur_item_num = CacheManager::GetClipperAlphaMaskMruCache()->GetCurItemNum();
1379 caches_info->clipper_cache_hit_count = CacheManager::GetClipperAlphaMaskMruCache()->GetCacheHitCount();
1380 caches_info->clipper_cache_query_count = CacheManager::GetClipperAlphaMaskMruCache()->GetQueryCount();
1382 return hr;
1385 STDMETHODIMP CDirectVobSubFilter::put_SubpixelPositionLevel(int subpixel_pos_level)
1387 CAutoLock cAutolock(&m_csQueueLock);
1388 HRESULT hr = CDirectVobSub::put_SubpixelPositionLevel(subpixel_pos_level);
1390 if(hr == NOERROR)
1392 SubpixelPositionControler::GetGlobalControler().SetSubpixelLevel( static_cast<SubpixelPositionControler::SUBPIXEL_LEVEL>(subpixel_pos_level) );
1395 return hr;
1398 STDMETHODIMP CDirectVobSubFilter::put_FollowUpstreamPreferredOrder( bool fFollowUpstreamPreferredOrder )
1400 CAutoLock cAutolock(&m_csQueueLock);
1401 HRESULT hr = CDirectVobSub::put_FollowUpstreamPreferredOrder(fFollowUpstreamPreferredOrder);
1403 if(hr == NOERROR)
1405 m_donot_follow_upstream_preferred_order = !m_fFollowUpstreamPreferredOrder;
1408 return hr;
1411 STDMETHODIMP CDirectVobSubFilter::get_MediaFPS(bool* fEnabled, double* fps)
1413 HRESULT hr = CDirectVobSub::get_MediaFPS(fEnabled, fps);
1415 CComQIPtr<IMediaSeeking> pMS = m_pGraph;
1416 double rate;
1417 if(pMS && SUCCEEDED(pMS->GetRate(&rate)))
1419 m_MediaFPS = rate * m_fps;
1420 if(fps) *fps = m_MediaFPS;
1423 return hr;
1426 STDMETHODIMP CDirectVobSubFilter::put_MediaFPS(bool fEnabled, double fps)
1428 HRESULT hr = CDirectVobSub::put_MediaFPS(fEnabled, fps);
1430 CComQIPtr<IMediaSeeking> pMS = m_pGraph;
1431 if(pMS)
1433 if(hr == NOERROR)
1435 hr = pMS->SetRate(m_fMediaFPSEnabled ? m_MediaFPS / m_fps : 1.0);
1438 double dRate;
1439 if(SUCCEEDED(pMS->GetRate(&dRate)))
1440 m_MediaFPS = dRate * m_fps;
1443 return hr;
1446 STDMETHODIMP CDirectVobSubFilter::get_ZoomRect(NORMALIZEDRECT* rect)
1448 return E_NOTIMPL;
1451 STDMETHODIMP CDirectVobSubFilter::put_ZoomRect(NORMALIZEDRECT* rect)
1453 return E_NOTIMPL;
1456 // IDirectVobSub2
1458 STDMETHODIMP CDirectVobSubFilter::put_TextSettings(STSStyle* pDefStyle)
1460 HRESULT hr = CDirectVobSub::put_TextSettings(pDefStyle);
1462 if(hr == NOERROR)
1464 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1465 //UpdateSubtitle(true);
1466 UpdateSubtitle(false);
1469 return hr;
1472 STDMETHODIMP CDirectVobSubFilter::put_AspectRatioSettings(CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType)
1474 HRESULT hr = CDirectVobSub::put_AspectRatioSettings(ePARCompensationType);
1476 if(hr == NOERROR)
1478 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1479 //UpdateSubtitle(true);
1480 UpdateSubtitle(false);
1483 return hr;
1486 // IDirectVobSubFilterColor
1488 STDMETHODIMP CDirectVobSubFilter::HasConfigDialog(int iSelected)
1490 int nLangs;
1491 if(FAILED(get_LanguageCount(&nLangs))) return E_FAIL;
1492 return E_FAIL;
1493 // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
1494 // return(nLangs >= 0 && iSelected < nLangs ? S_OK : E_FAIL);
1497 STDMETHODIMP CDirectVobSubFilter::ShowConfigDialog(int iSelected, HWND hWndParent)
1499 // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
1500 return(E_FAIL);
1503 ///////////////////////////////////////////////////////////////////////////
1505 CDirectVobSubFilter2::CDirectVobSubFilter2(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid) :
1506 CDirectVobSubFilter(punk, phr, clsid)
1510 HRESULT CDirectVobSubFilter2::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
1512 CPinInfo pi;
1513 if(FAILED(pPin->QueryPinInfo(&pi))) return E_FAIL;
1515 if(CComQIPtr<IDirectVobSub>(pi.pFilter)) return E_FAIL;
1517 if(dir == PINDIR_INPUT)
1519 CFilterInfo fi;
1520 if(SUCCEEDED(pi.pFilter->QueryFilterInfo(&fi))
1521 && !wcsnicmp(fi.achName, L"Overlay Mixer", 13))
1522 return(E_FAIL);
1524 else
1528 return __super::CheckConnect(dir, pPin);
1531 HRESULT CDirectVobSubFilter2::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
1533 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::JoinFilterGraph"));
1534 if(pGraph)
1536 BeginEnumFilters(pGraph, pEF, pBF)
1538 if(pBF != (IBaseFilter*)this && CComQIPtr<IDirectVobSub>(pBF))
1539 return E_FAIL;
1541 EndEnumFilters
1543 // don't look... we will do some serious graph hacking again...
1545 // we will add dvs2 to the filter graph cache
1546 // - if the main app has already added some kind of renderer or overlay mixer (anything which accepts video on its input)
1547 // and
1548 // - if we have a reason to auto-load (we don't want to make any trouble when there is no need :)
1550 // This whole workaround is needed because the video stream will always be connected
1551 // to the pre-added filters first, no matter how high merit we have.
1553 if(!get_Forced())
1555 BeginEnumFilters(pGraph, pEF, pBF)
1557 if(CComQIPtr<IDirectVobSub>(pBF))
1558 continue;
1560 CComPtr<IPin> pInPin = GetFirstPin(pBF, PINDIR_INPUT);
1561 CComPtr<IPin> pOutPin = GetFirstPin(pBF, PINDIR_OUTPUT);
1563 if(!pInPin)
1564 continue;
1566 CComPtr<IPin> pPin;
1567 if(pInPin && SUCCEEDED(pInPin->ConnectedTo(&pPin))
1568 || pOutPin && SUCCEEDED(pOutPin->ConnectedTo(&pPin)))
1569 continue;
1571 if(pOutPin && GetFilterName(pBF) == _T("Overlay Mixer"))
1572 continue;
1574 bool fVideoInputPin = false;
1578 BITMAPINFOHEADER bih = {sizeof(BITMAPINFOHEADER), 384, 288, 1, 16, '2YUY', 384*288*2, 0, 0, 0, 0};
1580 CMediaType cmt;
1581 cmt.majortype = MEDIATYPE_Video;
1582 cmt.subtype = MEDIASUBTYPE_YUY2;
1583 cmt.formattype = FORMAT_VideoInfo;
1584 cmt.pUnk = NULL;
1585 cmt.bFixedSizeSamples = TRUE;
1586 cmt.bTemporalCompression = TRUE;
1587 cmt.lSampleSize = 384*288*2;
1588 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
1589 memset(vih, 0, sizeof(VIDEOINFOHEADER));
1590 memcpy(&vih->bmiHeader, &bih, sizeof(bih));
1591 vih->AvgTimePerFrame = 400000;
1593 if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
1595 fVideoInputPin = true;
1596 break;
1599 VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER2));
1600 memset(vih2, 0, sizeof(VIDEOINFOHEADER2));
1601 memcpy(&vih2->bmiHeader, &bih, sizeof(bih));
1602 vih2->AvgTimePerFrame = 400000;
1603 vih2->dwPictAspectRatioX = 384;
1604 vih2->dwPictAspectRatioY = 288;
1606 if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
1608 fVideoInputPin = true;
1609 break;
1612 while(false);
1614 if(fVideoInputPin)
1616 CComPtr<IBaseFilter> pDVS;
1617 if(ShouldWeAutoload(pGraph) && SUCCEEDED(pDVS.CoCreateInstance(__uuidof(CDirectVobSubFilter2))))
1619 CComQIPtr<IDirectVobSub2>(pDVS)->put_Forced(true);
1620 CComQIPtr<IGraphConfig>(pGraph)->AddFilterToCache(pDVS);
1623 break;
1626 EndEnumFilters
1629 else
1633 return __super::JoinFilterGraph(pGraph, pName);
1636 HRESULT CDirectVobSubFilter2::CheckInputType(const CMediaType* mtIn)
1638 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::CheckInputType"));
1639 HRESULT hr = __super::CheckInputType(mtIn);
1641 if(FAILED(hr) || m_pInput->IsConnected()) return hr;
1643 if(!ShouldWeAutoload(m_pGraph)) return VFW_E_TYPE_NOT_ACCEPTED;
1645 GetRidOfInternalScriptRenderer();
1647 return NOERROR;
1650 bool CDirectVobSubFilter2::ShouldWeAutoload(IFilterGraph* pGraph)
1652 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::ShouldWeAutoload"));
1653 TCHAR blacklistedapps[][32] =
1655 _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)
1656 _T("explorer."), // as some users reported thumbnail preview loads dvobsub, I've never experienced this yet...
1657 _T("producer."), // this is real's producer
1658 _T("GoogleDesktopIndex."), // Google Desktop
1659 _T("GoogleDesktopDisplay."), // Google Desktop
1660 _T("GoogleDesktopCrawl."), // Google Desktop
1663 for(int i = 0; i < countof(blacklistedapps); i++)
1665 if(theApp.m_AppName.Find(blacklistedapps[i]) >= 0)
1666 return(false);
1669 int level;
1670 bool m_fExternalLoad, m_fWebLoad, m_fEmbeddedLoad;
1671 get_LoadSettings(&level, &m_fExternalLoad, &m_fWebLoad, &m_fEmbeddedLoad);
1673 if(level < 0 || level >= 2) return(false);
1675 bool fRet = false;
1677 if(level == 1)
1678 fRet = m_fExternalLoad = m_fWebLoad = m_fEmbeddedLoad = true;
1680 // find text stream on known splitters
1682 if(!fRet && m_fEmbeddedLoad)
1684 CComPtr<IBaseFilter> pBF;
1685 if((pBF = FindFilter(CLSID_OggSplitter, pGraph)) || (pBF = FindFilter(CLSID_AviSplitter, pGraph))
1686 || (pBF = FindFilter(L"{34293064-02F2-41D5-9D75-CC5967ACA1AB}", pGraph)) // matroska demux
1687 || (pBF = FindFilter(L"{0A68C3B5-9164-4a54-AFAF-995B2FF0E0D4}", pGraph)) // matroska source
1688 || (pBF = FindFilter(L"{149D2E01-C32E-4939-80F6-C07B81015A7A}", pGraph)) // matroska splitter
1689 || (pBF = FindFilter(L"{55DA30FC-F16B-49fc-BAA5-AE59FC65F82D}", pGraph)) // Haali Media Splitter
1690 || (pBF = FindFilter(L"{564FD788-86C9-4444-971E-CC4A243DA150}", pGraph)) // Haali Media Splitter (AR)
1691 || (pBF = FindFilter(L"{8F43B7D9-9D6B-4F48-BE18-4D787C795EEA}", pGraph)) // Haali Simple Media Splitter
1692 || (pBF = FindFilter(L"{52B63861-DC93-11CE-A099-00AA00479A58}", pGraph)) // 3ivx splitter
1693 || (pBF = FindFilter(L"{6D3688CE-3E9D-42F4-92CA-8A11119D25CD}", pGraph)) // our ogg source
1694 || (pBF = FindFilter(L"{9FF48807-E133-40AA-826F-9B2959E5232D}", pGraph)) // our ogg splitter
1695 || (pBF = FindFilter(L"{803E8280-F3CE-4201-982C-8CD8FB512004}", pGraph)) // dsm source
1696 || (pBF = FindFilter(L"{0912B4DD-A30A-4568-B590-7179EBB420EC}", pGraph)) // dsm splitter
1697 || (pBF = FindFilter(L"{3CCC052E-BDEE-408a-BEA7-90914EF2964B}", pGraph)) // mp4 source
1698 || (pBF = FindFilter(L"{61F47056-E400-43d3-AF1E-AB7DFFD4C4AD}", pGraph)) // mp4 splitter
1699 || (pBF = FindFilter(L"{171252A0-8820-4AFE-9DF8-5C92B2D66B04}", pGraph)) // LAV splitter
1700 || (pBF = FindFilter(L"{B98D13E7-55DB-4385-A33D-09FD1BA26338}", pGraph)) // LAV Splitter Source
1701 || (pBF = FindFilter(L"{E436EBB5-524F-11CE-9F53-0020AF0BA770}", pGraph)) // Solveig matroska splitter
1702 || (pBF = FindFilter(L"{1365BE7A-C86A-473C-9A41-C0A6E82C9FA3}", pGraph)) // MPC-HC MPEG PS/TS/PVA source
1703 || (pBF = FindFilter(L"{DC257063-045F-4BE2-BD5B-E12279C464F0}", pGraph)) // MPC-HC MPEG splitter
1704 || (pBF = FindFilter(L"{529A00DB-0C43-4f5b-8EF2-05004CBE0C6F}", pGraph)) // AV splitter
1705 || (pBF = FindFilter(L"{D8980E15-E1F6-4916-A10F-D7EB4E9E10B8}", pGraph)) // AV source
1708 BeginEnumPins(pBF, pEP, pPin)
1710 BeginEnumMediaTypes(pPin, pEM, pmt)
1712 if(pmt->majortype == MEDIATYPE_Text || pmt->majortype == MEDIATYPE_Subtitle)
1714 fRet = true;
1715 break;
1718 EndEnumMediaTypes(pmt)
1719 if(fRet) break;
1721 EndEnumFilters
1725 // find file name
1727 CStringW fn;
1729 BeginEnumFilters(pGraph, pEF, pBF)
1731 if(CComQIPtr<IFileSourceFilter> pFSF = pBF)
1733 LPOLESTR fnw = NULL;
1734 if(!pFSF || FAILED(pFSF->GetCurFile(&fnw, NULL)) || !fnw)
1735 continue;
1736 fn = CString(fnw);
1737 CoTaskMemFree(fnw);
1738 break;
1741 EndEnumFilters
1743 if((m_fExternalLoad || m_fWebLoad) && (m_fWebLoad || !(wcsstr(fn, L"http://") || wcsstr(fn, L"mms://"))))
1745 bool fTemp = m_fHideSubtitles;
1746 fRet = !fn.IsEmpty() && SUCCEEDED(put_FileName((LPWSTR)(LPCWSTR)fn))
1747 || SUCCEEDED(put_FileName(L"c:\\tmp.srt"))
1748 || fRet;
1749 if(fTemp) m_fHideSubtitles = true;
1752 return(fRet);
1755 void CDirectVobSubFilter2::GetRidOfInternalScriptRenderer()
1757 while(CComPtr<IBaseFilter> pBF = FindFilter(L"{48025243-2D39-11CE-875D-00608CB78066}", m_pGraph))
1759 BeginEnumPins(pBF, pEP, pPin)
1761 PIN_DIRECTION dir;
1762 CComPtr<IPin> pPinTo;
1764 if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT
1765 && SUCCEEDED(pPin->ConnectedTo(&pPinTo)))
1767 m_pGraph->Disconnect(pPinTo);
1768 m_pGraph->Disconnect(pPin);
1769 m_pGraph->ConnectDirect(pPinTo, GetPin(2 + m_pTextInput.GetCount()-1), NULL);
1772 EndEnumPins
1774 if(FAILED(m_pGraph->RemoveFilter(pBF)))
1775 break;
1779 ///////////////////////////////////////////////////////////////////////////////
1781 bool CDirectVobSubFilter::Open()
1783 AMTRACE((TEXT(__FUNCTION__),0));
1784 XY_AUTO_TIMING(TEXT("CDirectVobSubFilter::Open"));
1786 AFX_MANAGE_STATE(AfxGetStaticModuleState());
1788 CAutoLock cAutolock(&m_csQueueLock);
1790 m_pSubStreams.RemoveAll();
1791 m_fIsSubStreamEmbeded.RemoveAll();
1793 m_frd.files.RemoveAll();
1795 CAtlArray<CString> paths;
1797 for(int i = 0; i < 10; i++)
1799 CString tmp;
1800 tmp.Format(IDS_RP_PATH, i);
1801 CString path = theApp.GetProfileString(ResStr(IDS_R_DEFTEXTPATHES), tmp);
1802 if(!path.IsEmpty()) paths.Add(path);
1805 CAtlArray<SubFile> ret;
1806 GetSubFileNames(m_FileName, paths, ret);
1808 for(int i = 0; i < ret.GetCount(); i++)
1810 if(m_frd.files.Find(ret[i].fn))
1811 continue;
1813 CComPtr<ISubStream> pSubStream;
1815 if(!pSubStream)
1817 // CAutoTiming t(TEXT("CRenderedTextSubtitle::Open"), 0);
1818 XY_AUTO_TIMING(TEXT("CRenderedTextSubtitle::Open"));
1819 CAutoPtr<CRenderedTextSubtitle> pRTS(new CRenderedTextSubtitle(&m_csSubLock));
1820 if(pRTS && pRTS->Open(ret[i].fn, DEFAULT_CHARSET) && pRTS->GetStreamCount() > 0)
1822 pSubStream = pRTS.Detach();
1823 m_frd.files.AddTail(ret[i].fn + _T(".style"));
1827 if(!pSubStream)
1829 CAutoTiming t(TEXT("CVobSubFile::Open"), 0);
1830 CAutoPtr<CVobSubFile> pVSF(new CVobSubFile(&m_csSubLock));
1831 if(pVSF && pVSF->Open(ret[i].fn) && pVSF->GetStreamCount() > 0)
1833 pSubStream = pVSF.Detach();
1834 m_frd.files.AddTail(ret[i].fn.Left(ret[i].fn.GetLength()-4) + _T(".sub"));
1838 if(!pSubStream)
1840 CAutoTiming t(TEXT("ssf::CRenderer::Open"), 0);
1841 CAutoPtr<ssf::CRenderer> pSSF(new ssf::CRenderer(&m_csSubLock));
1842 if(pSSF && pSSF->Open(ret[i].fn) && pSSF->GetStreamCount() > 0)
1844 pSubStream = pSSF.Detach();
1848 if(pSubStream)
1850 m_pSubStreams.AddTail(pSubStream);
1851 m_fIsSubStreamEmbeded.AddTail(false);
1852 m_frd.files.AddTail(ret[i].fn);
1856 for(int i = 0; i < m_pTextInput.GetCount(); i++)
1858 if(m_pTextInput[i]->IsConnected())
1860 m_pSubStreams.AddTail(m_pTextInput[i]->GetSubStream());
1861 m_fIsSubStreamEmbeded.AddTail(true);
1865 if(S_FALSE == put_SelectedLanguage(FindPreferedLanguage()))
1866 UpdateSubtitle(false); // make sure pSubPicProvider of our queue gets updated even if the stream number hasn't changed
1868 m_frd.RefreshEvent.Set();
1870 return(m_pSubStreams.GetCount() > 0);
1873 void CDirectVobSubFilter::UpdateSubtitle(bool fApplyDefStyle)
1875 CAutoLock cAutolock(&m_csQueueLock);
1877 if(!m_simple_provider) return;
1879 InvalidateSubtitle();
1881 CComPtr<ISubStream> pSubStream;
1883 if(!m_fHideSubtitles)
1885 int i = m_iSelectedLanguage;
1887 for(POSITION pos = m_pSubStreams.GetHeadPosition(); i >= 0 && pos; pSubStream = NULL)
1889 pSubStream = m_pSubStreams.GetNext(pos);
1891 if(i < pSubStream->GetStreamCount())
1893 CAutoLock cAutoLock(&m_csSubLock);
1894 pSubStream->SetStream(i);
1895 break;
1898 i -= pSubStream->GetStreamCount();
1902 SetSubtitle(pSubStream, fApplyDefStyle);
1905 void CDirectVobSubFilter::SetSubtitle(ISubStream* pSubStream, bool fApplyDefStyle)
1907 DbgLog((LOG_TRACE, 3, "%s(%d): %s", __FILE__, __LINE__, __FUNCTION__));
1908 DbgLog((LOG_TRACE, 3, "\tpSubStream:%x fApplyDefStyle:%d", pSubStream, (int)fApplyDefStyle));
1909 CAutoLock cAutolock(&m_csQueueLock);
1911 m_script_selected_yuv = CSimpleTextSubtitle::YCbCrMatrix_AUTO;
1912 m_script_selected_range = CSimpleTextSubtitle::YCbCrRange_AUTO;
1913 if(pSubStream)
1915 CAutoLock cAutolock(&m_csSubLock);
1917 CLSID clsid;
1918 pSubStream->GetClassID(&clsid);
1920 if(clsid == __uuidof(CVobSubFile))
1922 CVobSubSettings* pVSS = dynamic_cast<CVobSubFile*>(pSubStream);
1924 if(fApplyDefStyle)
1926 pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
1927 pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
1930 else if(clsid == __uuidof(CVobSubStream))
1932 CVobSubSettings* pVSS = dynamic_cast<CVobSubStream*>(pSubStream);
1934 if(fApplyDefStyle)
1936 pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
1937 pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
1940 else if(clsid == __uuidof(CRenderedTextSubtitle))
1942 CRenderedTextSubtitle* pRTS = dynamic_cast<CRenderedTextSubtitle*>(pSubStream);
1944 if(fApplyDefStyle || pRTS->m_fUsingAutoGeneratedDefaultStyle)
1946 STSStyle s = m_defStyle;
1948 if(m_fOverridePlacement)
1950 s.scrAlignment = 2;
1951 int w = pRTS->m_dstScreenSize.cx;
1952 int h = pRTS->m_dstScreenSize.cy;
1953 CRect tmp_rect = s.marginRect.get();
1954 int mw = w - tmp_rect.left - tmp_rect.right;
1955 tmp_rect.bottom = h - MulDiv(h, m_PlacementYperc, 100);
1956 tmp_rect.left = MulDiv(w, m_PlacementXperc, 100) - mw/2;
1957 tmp_rect.right = w - (tmp_rect.left + mw);
1958 s.marginRect = tmp_rect;
1961 pRTS->SetDefaultStyle(s);
1964 pRTS->m_ePARCompensationType = m_ePARCompensationType;
1965 if (m_CurrentVIH2.dwPictAspectRatioX != 0 && m_CurrentVIH2.dwPictAspectRatioY != 0&& m_CurrentVIH2.bmiHeader.biWidth != 0 && m_CurrentVIH2.bmiHeader.biHeight != 0)
1967 pRTS->m_dPARCompensation = ((double)abs(m_CurrentVIH2.bmiHeader.biWidth) / (double)abs(m_CurrentVIH2.bmiHeader.biHeight)) /
1968 ((double)abs((long)m_CurrentVIH2.dwPictAspectRatioX) / (double)abs((long)m_CurrentVIH2.dwPictAspectRatioY));
1971 else
1973 pRTS->m_dPARCompensation = 1.00;
1976 m_script_selected_yuv = pRTS->m_eYCbCrMatrix;
1977 m_script_selected_range = pRTS->m_eYCbCrRange;
1978 pRTS->Deinit();
1982 if(!fApplyDefStyle)
1984 int i = 0;
1986 POSITION pos = m_pSubStreams.GetHeadPosition();
1987 while(pos)
1989 CComPtr<ISubStream> pSubStream2 = m_pSubStreams.GetNext(pos);
1991 if(pSubStream == pSubStream2)
1993 m_iSelectedLanguage = i + pSubStream2->GetStream();
1994 break;
1997 i += pSubStream2->GetStreamCount();
2001 m_nSubtitleId = reinterpret_cast<DWORD_PTR>(pSubStream);
2003 SetYuvMatrix();
2005 if(m_simple_provider)
2006 m_simple_provider->SetSubPicProvider(CComQIPtr<ISubPicProviderEx>(pSubStream));
2009 void CDirectVobSubFilter::InvalidateSubtitle(REFERENCE_TIME rtInvalidate, DWORD_PTR nSubtitleId)
2011 CAutoLock cAutolock(&m_csQueueLock);
2013 if(m_simple_provider)
2015 if(nSubtitleId == -1 || nSubtitleId == m_nSubtitleId)
2017 DbgLog((LOG_TRACE, 3, "InvalidateSubtitle::Invalidate"));
2018 m_simple_provider->Invalidate(rtInvalidate);
2023 //////////////////////////////////////////////////////////////////////////////////////////
2025 void CDirectVobSubFilter::AddSubStream(ISubStream* pSubStream)
2027 CAutoLock cAutoLock(&m_csQueueLock);
2029 POSITION pos = m_pSubStreams.Find(pSubStream);
2030 if(!pos)
2032 m_pSubStreams.AddTail(pSubStream);
2033 m_fIsSubStreamEmbeded.AddTail(true);//todo: fix me
2036 int len = m_pTextInput.GetCount();
2037 for(int i = 0; i < m_pTextInput.GetCount(); i++)
2038 if(m_pTextInput[i]->IsConnected()) len--;
2040 if(len == 0)
2042 HRESULT hr = S_OK;
2043 m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
2047 void CDirectVobSubFilter::RemoveSubStream(ISubStream* pSubStream)
2049 CAutoLock cAutoLock(&m_csQueueLock);
2051 POSITION pos = m_pSubStreams.GetHeadPosition();
2052 POSITION pos2 = m_fIsSubStreamEmbeded.GetHeadPosition();
2053 while(pos!=NULL)
2055 if( m_pSubStreams.GetAt(pos)==pSubStream )
2057 m_pSubStreams.RemoveAt(pos);
2058 m_fIsSubStreamEmbeded.RemoveAt(pos2);
2059 break;
2061 else
2063 m_pSubStreams.GetNext(pos);
2064 m_fIsSubStreamEmbeded.GetNext(pos2);
2069 void CDirectVobSubFilter::Post_EC_OLE_EVENT(CString str, DWORD_PTR nSubtitleId)
2071 if(nSubtitleId != -1 && nSubtitleId != m_nSubtitleId)
2072 return;
2074 CComQIPtr<IMediaEventSink> pMES = m_pGraph;
2075 if(!pMES) return;
2077 CComBSTR bstr1("Text"), bstr2(" ");
2079 str.Trim();
2080 if(!str.IsEmpty()) bstr2 = CStringA(str);
2082 pMES->Notify(EC_OLE_EVENT, (LONG_PTR)bstr1.Detach(), (LONG_PTR)bstr2.Detach());
2085 ////////////////////////////////////////////////////////////////
2087 void CDirectVobSubFilter::SetupFRD(CStringArray& paths, CAtlArray<HANDLE>& handles)
2089 CAutoLock cAutolock(&m_csSubLock);
2091 for(int i = 2; i < handles.GetCount(); i++)
2093 FindCloseChangeNotification(handles[i]);
2096 paths.RemoveAll();
2097 handles.RemoveAll();
2099 handles.Add(m_frd.EndThreadEvent);
2100 handles.Add(m_frd.RefreshEvent);
2102 m_frd.mtime.SetCount(m_frd.files.GetCount());
2104 POSITION pos = m_frd.files.GetHeadPosition();
2105 for(int i = 0; pos; i++)
2107 CString fn = m_frd.files.GetNext(pos);
2109 CFileStatus status;
2110 if(CFileGetStatus(fn, status))
2111 m_frd.mtime[i] = status.m_mtime;
2113 fn.Replace('\\', '/');
2114 fn = fn.Left(fn.ReverseFind('/')+1);
2116 bool fFound = false;
2118 for(int j = 0; !fFound && j < paths.GetCount(); j++)
2120 if(paths[j] == fn) fFound = true;
2123 if(!fFound)
2125 paths.Add(fn);
2127 HANDLE h = FindFirstChangeNotification(fn, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
2128 if(h != INVALID_HANDLE_VALUE) handles.Add(h);
2133 DWORD CDirectVobSubFilter::ThreadProc()
2135 SetThreadPriority(m_hThread, THREAD_PRIORITY_LOWEST/*THREAD_PRIORITY_BELOW_NORMAL*/);
2137 CStringArray paths;
2138 CAtlArray<HANDLE> handles;
2140 SetupFRD(paths, handles);
2142 while(1)
2144 DWORD idx = WaitForMultipleObjects(handles.GetCount(), handles.GetData(), FALSE, INFINITE);
2146 if(idx == (WAIT_OBJECT_0 + 0)) // m_frd.hEndThreadEvent
2148 break;
2150 if(idx == (WAIT_OBJECT_0 + 1)) // m_frd.hRefreshEvent
2152 SetupFRD(paths, handles);
2154 else if(idx >= (WAIT_OBJECT_0 + 2) && idx < (WAIT_OBJECT_0 + handles.GetCount()))
2156 bool fLocked = true;
2157 IsSubtitleReloaderLocked(&fLocked);
2158 if(fLocked) continue;
2160 if(FindNextChangeNotification(handles[idx - WAIT_OBJECT_0]) == FALSE)
2161 break;
2163 int j = 0;
2165 POSITION pos = m_frd.files.GetHeadPosition();
2166 for(int i = 0; pos && j == 0; i++)
2168 CString fn = m_frd.files.GetNext(pos);
2170 CFileStatus status;
2171 if(CFileGetStatus(fn, status) && m_frd.mtime[i] != status.m_mtime)
2173 for(j = 0; j < 10; j++)
2175 if(FILE* f = _tfopen(fn, _T("rb+")))
2177 fclose(f);
2178 j = 0;
2179 break;
2181 else
2183 Sleep(100);
2184 j++;
2190 if(j > 0)
2192 SetupFRD(paths, handles);
2194 else
2196 Sleep(500);
2198 POSITION pos = m_frd.files.GetHeadPosition();
2199 for(int i = 0; pos; i++)
2201 CFileStatus status;
2202 if(CFileGetStatus(m_frd.files.GetNext(pos), status)
2203 && m_frd.mtime[i] != status.m_mtime)
2205 Open();
2206 SetupFRD(paths, handles);
2207 break;
2212 else
2214 break;
2218 for(int i = 2; i < handles.GetCount(); i++)
2220 FindCloseChangeNotification(handles[i]);
2223 return 0;
2226 void CDirectVobSubFilter::GetInputColorspaces( ColorSpaceId *preferredOrder, UINT *count )
2228 ColorSpaceId colorspace[MAX_COLOR_SPACE_NUM];
2229 bool selected[MAX_COLOR_SPACE_NUM];
2230 UINT tempCount;
2231 if( get_InputColorFormat(colorspace, selected, &tempCount)==S_OK )
2233 *count = 0;
2234 for (int i=0;i<tempCount;i++)
2236 if(selected[i])
2238 preferredOrder[*count] = colorspace[i];
2239 (*count)++;
2243 else
2245 CBaseVideoFilter::GetInputColorspaces(preferredOrder, count);
2249 void CDirectVobSubFilter::GetOutputColorspaces( ColorSpaceId *preferredOrder, UINT *count )
2251 ColorSpaceId colorspace[MAX_COLOR_SPACE_NUM];
2252 bool selected[MAX_COLOR_SPACE_NUM];
2253 UINT tempCount;
2254 if( get_OutputColorFormat(colorspace, selected, &tempCount)==S_OK )
2256 *count = 0;
2257 for (int i=0;i<tempCount;i++)
2259 if(selected[i])
2261 preferredOrder[*count] = colorspace[i];
2262 (*count)++;
2266 else
2268 CBaseVideoFilter::GetInputColorspaces(preferredOrder, count);
2272 HRESULT CDirectVobSubFilter::GetIsEmbeddedSubStream( int iSelected, bool *fIsEmbedded )
2274 CAutoLock cAutolock(&m_csQueueLock);
2276 HRESULT hr = E_INVALIDARG;
2277 if (!fIsEmbedded)
2279 return S_FALSE;
2282 int i = iSelected;
2283 *fIsEmbedded = false;
2285 POSITION pos = m_pSubStreams.GetHeadPosition();
2286 POSITION pos2 = m_fIsSubStreamEmbeded.GetHeadPosition();
2287 while(i >= 0 && pos)
2289 CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
2290 bool isEmbedded = m_fIsSubStreamEmbeded.GetNext(pos2);
2291 if(i < pSubStream->GetStreamCount())
2293 hr = NOERROR;
2294 *fIsEmbedded = isEmbedded;
2295 break;
2298 i -= pSubStream->GetStreamCount();
2300 return hr;
2303 void CDirectVobSubFilter::SetYuvMatrix()
2305 ColorConvTable::YuvMatrixType yuv_matrix = ColorConvTable::BT601;
2306 ColorConvTable::YuvRangeType yuv_range = ColorConvTable::RANGE_TV;
2308 if ( m_colorSpace==CDirectVobSub::YuvMatrix_AUTO )
2310 switch(m_script_selected_yuv)
2312 case CSimpleTextSubtitle::YCbCrMatrix_BT601:
2313 yuv_matrix = ColorConvTable::BT601;
2314 break;
2315 case CSimpleTextSubtitle::YCbCrMatrix_BT709:
2316 yuv_matrix = ColorConvTable::BT709;
2317 break;
2318 case CSimpleTextSubtitle::YCbCrMatrix_AUTO:
2319 default:
2320 yuv_matrix = ColorConvTable::BT601;
2321 break;
2324 else
2326 switch(m_colorSpace)
2328 case CDirectVobSub::BT_601:
2329 yuv_matrix = ColorConvTable::BT601;
2330 break;
2331 case CDirectVobSub::BT_709:
2332 yuv_matrix = ColorConvTable::BT709;
2333 break;
2334 case CDirectVobSub::GUESS:
2335 default:
2336 yuv_matrix = (m_w > m_bt601Width || m_h > m_bt601Height) ? ColorConvTable::BT709 : ColorConvTable::BT601;
2337 break;
2341 if( m_yuvRange==CDirectVobSub::YuvRange_Auto )
2343 switch(m_script_selected_range)
2345 case CSimpleTextSubtitle::YCbCrRange_PC:
2346 yuv_range = ColorConvTable::RANGE_PC;
2347 break;
2348 case CSimpleTextSubtitle::YCbCrRange_TV:
2349 yuv_range = ColorConvTable::RANGE_TV;
2350 break;
2351 case CSimpleTextSubtitle::YCbCrRange_AUTO:
2352 default:
2353 yuv_range = ColorConvTable::RANGE_TV;
2354 break;
2357 else
2359 switch(m_yuvRange)
2361 case CDirectVobSub::YuvRange_TV:
2362 yuv_range = ColorConvTable::RANGE_TV;
2363 break;
2364 case CDirectVobSub::YuvRange_PC:
2365 yuv_range = ColorConvTable::RANGE_PC;
2366 break;
2367 case CDirectVobSub::YuvRange_Auto:
2368 yuv_range = ColorConvTable::RANGE_TV;
2369 break;
2373 ColorConvTable::SetDefaultConvType(yuv_matrix, yuv_range);