Add several filters, including "LAV splitter"/"LAV Splitter Source"/"AV splitter...
[xy_vsfilter.git] / src / filters / transform / vsfilter / DirectVobSubFilter.cpp
blob211e54c66e9a3d098db64013fe7e0a65729daad5
1 /*
2 * Copyright (C) 2003-2006 Gabest
3 * http://www.gabest.org
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with GNU Make; see the file COPYING. If not, write to
17 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18 * http://www.gnu.org/copyleft/gpl.html
22 #include "stdafx.h"
23 #include <math.h>
24 #include <time.h>
25 #include "DirectVobSubFilter.h"
26 #include "TextInputPin.h"
27 #include "DirectVobSubPropPage.h"
28 #include "VSFilter.h"
29 #include "systray.h"
30 #include "../../../DSUtil/MediaTypes.h"
31 #include "../../../SubPic/SubPicQueueImpl.h"
32 #include "../../../SubPic/PooledSubPic.h"
33 #include "../../../subpic/color_conv_table.h"
35 #include <initguid.h>
36 #include "..\..\..\..\include\moreuuids.h"
38 #include "CAutoTiming.h"
39 #include "xy_logger.h"
41 #define MAX_SUBPIC_QUEUE_LENGTH 1
43 ///////////////////////////////////////////////////////////////////////////
45 /*removeme*/
46 bool g_RegOK = true;//false; // doesn't work with the dvd graph builder
47 #include "valami.cpp"
49 #ifdef __DO_LOG
50 EXTERN_C IMAGE_DOS_HEADER __ImageBase;
51 #endif
53 ////////////////////////////////////////////////////////////////////////////
55 // Constructor
58 CDirectVobSubFilter::CDirectVobSubFilter(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid)
59 : CBaseVideoFilter(NAME("CDirectVobSubFilter"), punk, phr, clsid)
60 , m_nSubtitleId(-1)
61 , m_fMSMpeg4Fix(false)
62 , m_fps(25)
64 DbgLog((LOG_TRACE, 3, _T("CDirectVobSubFilter::CDirectVobSubFilter")));
66 // and then, anywhere you need it:
68 #ifdef __DO_LOG
69 LPTSTR strDLLPath = new TCHAR[_MAX_PATH];
70 ::GetModuleFileName( reinterpret_cast<HINSTANCE>(&__ImageBase), strDLLPath, _MAX_PATH);
71 CString dllPath = strDLLPath;
72 dllPath += ".properties";
73 xy_logger::doConfigure( dllPath.GetString() );
74 #endif
76 AFX_MANAGE_STATE(AfxGetStaticModuleState());
78 m_hdc = 0;
79 m_hbm = 0;
80 m_hfont = 0;
83 LOGFONT lf;
84 memset(&lf, 0, sizeof(lf));
85 lf.lfCharSet = DEFAULT_CHARSET;
86 lf.lfOutPrecision = OUT_CHARACTER_PRECIS;
87 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
88 lf.lfQuality = ANTIALIASED_QUALITY;
89 HDC hdc = GetDC(NULL);
90 lf.lfHeight = 28;
91 //MulDiv(20, GetDeviceCaps(hdc, LOGPIXELSY), 54);
92 ReleaseDC(NULL, hdc);
93 lf.lfWeight = FW_BOLD;
94 _tcscpy(lf.lfFaceName, _T("Arial"));
95 m_hfont = CreateFontIndirect(&lf);
98 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Hint"), _T("The first three are fixed, but you can add more up to ten entries."));
99 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path0"), _T("."));
100 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path1"), _T("c:\\subtitles"));
101 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path2"), _T(".\\subtitles"));
103 m_fLoading = true;
105 m_hSystrayThread = 0;
106 m_tbid.hSystrayWnd = NULL;
107 m_tbid.graph = NULL;
108 m_tbid.fRunOnce = false;
109 m_tbid.fShowIcon = (theApp.m_AppName.Find(_T("zplayer"), 0) < 0 || !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_ENABLEZPICON), 0));
111 HRESULT hr = S_OK;
112 m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
113 ASSERT(SUCCEEDED(hr));
115 CAMThread::Create();
116 m_frd.EndThreadEvent.Create(0, FALSE, FALSE, 0);
117 m_frd.RefreshEvent.Create(0, FALSE, FALSE, 0);
119 memset(&m_CurrentVIH2, 0, sizeof(VIDEOINFOHEADER2));
121 m_donot_follow_upstream_preferred_order = !m_fFollowUpstreamPreferredOrder;
123 m_time_alphablt = m_time_rasterization = 0;
126 CDirectVobSubFilter::~CDirectVobSubFilter()
128 CAutoLock cAutoLock(&m_csQueueLock);
129 if(m_pSubPicQueue)
131 DbgLog((LOG_TRACE, 3, "~CDirectVobSubFilter::Invalidate"));
132 m_pSubPicQueue->Invalidate();
134 m_pSubPicQueue = NULL;
136 if(m_hfont) {DeleteObject(m_hfont); m_hfont = 0;}
137 if(m_hbm) {DeleteObject(m_hbm); m_hbm = 0;}
138 if(m_hdc) {DeleteObject(m_hdc); m_hdc = 0;}
140 for(int i = 0; i < m_pTextInput.GetCount(); i++)
141 delete m_pTextInput[i];
143 m_frd.EndThreadEvent.Set();
144 CAMThread::Close();
146 DbgLog((LOG_TRACE, 3, _T("CDirectVobSubFilter::~CDirectVobSubFilter")));
148 //Trace(_T("CDirectVobSubFilter::~CDirectVobSubFilter"));
149 //ReleaseTracer;
152 STDMETHODIMP CDirectVobSubFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
154 CheckPointer(ppv, E_POINTER);
156 return
157 QI(IDirectVobSub)
158 QI(IDirectVobSub2)
159 QI(IDirectVobSubXy)
160 QI(IFilterVersion)
161 QI(ISpecifyPropertyPages)
162 QI(IAMStreamSelect)
163 __super::NonDelegatingQueryInterface(riid, ppv);
166 // CBaseVideoFilter
168 void CDirectVobSubFilter::GetOutputSize(int& w, int& h, int& arx, int& ary)
170 CSize s(w, h), os = s;
171 AdjustFrameSize(s);
172 w = s.cx;
173 h = s.cy;
175 if(w != os.cx)
177 while(arx < 100) arx *= 10, ary *= 10;
178 arx = arx * w / os.cx;
181 if(h != os.cy)
183 while(ary < 100) arx *= 10, ary *= 10;
184 ary = ary * h / os.cy;
188 HRESULT CDirectVobSubFilter::TryNotCopy(IMediaSample* pIn, const CMediaType& mt, const BITMAPINFOHEADER& bihIn )
190 CSize sub(m_w, m_h);
191 CSize in(bihIn.biWidth, bihIn.biHeight);
192 BYTE* pDataIn = NULL;
193 if(FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn)
194 return S_FALSE;
195 if( sub==in )
197 m_spd.bits = pDataIn;
199 else
201 m_spd.bits = static_cast<BYTE*>(m_pTempPicBuff);
202 bool fYV12 = (mt.subtype == MEDIASUBTYPE_YV12 || mt.subtype == MEDIASUBTYPE_I420 || mt.subtype == MEDIASUBTYPE_IYUV);
203 bool fNV12 = (mt.subtype == MEDIASUBTYPE_NV12 || mt.subtype == MEDIASUBTYPE_NV21);
204 bool fP010 = (mt.subtype == MEDIASUBTYPE_P010 || mt.subtype == MEDIASUBTYPE_P016);
206 int bpp = fP010 ? 16 : (fYV12||fNV12) ? 8 : bihIn.biBitCount;
207 DWORD black = fP010 ? 0x10001000 : (fYV12||fNV12) ? 0x10101010 : (bihIn.biCompression == '2YUY') ? 0x80108010 : 0;
210 if(FAILED(Copy((BYTE*)m_pTempPicBuff, pDataIn, sub, in, bpp, mt.subtype, black)))
211 return E_FAIL;
213 if(fYV12)
215 BYTE* pSubV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
216 BYTE* pInV = pDataIn + (in.cx*bpp>>3)*in.cy;
217 sub.cx >>= 1; sub.cy >>= 1; in.cx >>= 1; in.cy >>= 1;
218 BYTE* pSubU = pSubV + (sub.cx*bpp>>3)*sub.cy;
219 BYTE* pInU = pInV + (in.cx*bpp>>3)*in.cy;
220 if(FAILED(Copy(pSubV, pInV, sub, in, bpp, mt.subtype, 0x80808080)))
221 return E_FAIL;
222 if(FAILED(Copy(pSubU, pInU, sub, in, bpp, mt.subtype, 0x80808080)))
223 return E_FAIL;
225 else if (fP010)
227 BYTE* pSubUV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
228 BYTE* pInUV = pDataIn + (in.cx*bpp>>3)*in.cy;
229 sub.cy >>= 1; in.cy >>= 1;
230 if(FAILED(Copy(pSubUV, pInUV, sub, in, bpp, mt.subtype, 0x80008000)))
231 return E_FAIL;
233 else if(fNV12) {
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;
237 in.cy >>= 1;
238 if(FAILED(Copy(pSubUV, pInUV, sub, in, bpp, mt.subtype, 0x80808080)))
239 return E_FAIL;
242 return S_OK;
245 HRESULT CDirectVobSubFilter::Transform(IMediaSample* pIn)
247 XY_LOG_ONCE(0, _T("CDirectVobSubFilter::Transform"));
248 HRESULT hr;
251 REFERENCE_TIME rtStart, rtStop;
252 if(SUCCEEDED(pIn->GetTime(&rtStart, &rtStop)))
254 double dRate = m_pInput->CurrentRate();
256 m_tPrev = m_pInput->CurrentStartTime() + dRate*rtStart;
258 REFERENCE_TIME rtAvgTimePerFrame = rtStop - rtStart;
259 if(CComQIPtr<ISubClock2> pSC2 = m_pSubClock)
261 REFERENCE_TIME rt;
262 if(S_OK == pSC2->GetAvgTimePerFrame(&rt))
263 rtAvgTimePerFrame = rt;
266 m_fps = 10000000.0/rtAvgTimePerFrame / dRate;
272 CAutoLock cAutoLock(&m_csQueueLock);
274 if(m_pSubPicQueue)
276 m_pSubPicQueue->SetTime(CalcCurrentTime());
277 m_pSubPicQueue->SetFPS(m_fps);
284 const CMediaType& mt = m_pInput->CurrentMediaType();
286 BITMAPINFOHEADER bihIn;
287 ExtractBIH(&mt, &bihIn);
289 hr = TryNotCopy(pIn, mt, bihIn);
290 if( hr!=S_OK )
292 //fix me: log error
293 return hr;
297 SubPicDesc spd = m_spd;
299 CComPtr<IMediaSample> pOut;
300 BYTE* pDataOut = NULL;
301 if(FAILED(hr = GetDeliveryBuffer(spd.w, spd.h, &pOut))
302 || FAILED(hr = pOut->GetPointer(&pDataOut)))
303 return hr;
304 pOut->SetTime(&rtStart, &rtStop);
305 pOut->SetMediaTime(NULL, NULL);
306 pOut->SetDiscontinuity(pIn->IsDiscontinuity() == S_OK);
307 pOut->SetSyncPoint(pIn->IsSyncPoint() == S_OK);
308 pOut->SetPreroll(pIn->IsPreroll() == S_OK);
311 BITMAPINFOHEADER bihOut;
312 ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
314 bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3;
315 bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3;
317 bool fFlip = fInputFlipped != fOutputFlipped;
318 if(m_fFlipPicture) fFlip = !fFlip;
319 if(m_fMSMpeg4Fix) fFlip = !fFlip;
321 bool fFlipSub = fOutputFlipped;
322 if(m_fFlipSubtitles) fFlipSub = !fFlipSub;
327 CAutoLock cAutoLock(&m_csQueueLock);
329 if(m_pSubPicQueue)
331 CComPtr<ISubPicEx> pSubPic;
333 //int timeStamp1 = GetTickCount();
334 bool lookupResult = SUCCEEDED(m_pSubPicQueue->LookupSubPicEx(CalcCurrentTime(), &pSubPic));
335 //int timeStamp2 = GetTickCount();
336 //m_time_rasterization += timeStamp2-timeStamp1;
338 if(lookupResult && pSubPic)
340 //CRect r;
341 //pSubPic->GetDirtyRect(r);
342 CAtlList<const CRect> rectList;
343 pSubPic->GetDirtyRects(rectList);
345 if(fFlip ^ fFlipSub)
346 spd.h = -spd.h;
348 POSITION pos = rectList.GetHeadPosition();
349 while(pos!=NULL)
351 const CRect& cRect = rectList.GetNext(pos);
352 pSubPic->AlphaBlt(cRect, cRect, &spd);
353 //pSubPic->AlphaBlt(r, r, &spd);
356 //m_time_alphablt += GetTickCount() - timeStamp2;
358 DbgLog((LOG_TRACE,3,"AlphaBlt time:%lu", (ULONG)(CalcCurrentTime()/10000)));
362 CopyBuffer(pDataOut, (BYTE*)spd.bits, spd.w, abs(spd.h)*(fFlip?-1:1), spd.pitch, mt.subtype);
364 PrintMessages(pDataOut);
365 return m_pOutput->Deliver(pOut);
368 // CBaseFilter
370 CBasePin* CDirectVobSubFilter::GetPin(int n)
372 if(n < __super::GetPinCount())
373 return __super::GetPin(n);
375 n -= __super::GetPinCount();
377 if(n >= 0 && n < m_pTextInput.GetCount())
378 return m_pTextInput[n];
380 n -= m_pTextInput.GetCount();
382 return NULL;
385 int CDirectVobSubFilter::GetPinCount()
387 return __super::GetPinCount() + m_pTextInput.GetCount();
390 HRESULT CDirectVobSubFilter::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
392 if(pGraph)
394 AFX_MANAGE_STATE(AfxGetStaticModuleState());
396 if(!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 0))
398 unsigned __int64 ver = GetFileVersion(_T("divx_c32.ax"));
399 if(((ver >> 48)&0xffff) == 4 && ((ver >> 32)&0xffff) == 2)
401 DWORD dwVersion = GetVersion();
402 DWORD dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
403 DWORD dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
405 if(dwVersion < 0x80000000 && dwWindowsMajorVersion >= 5)
407 AfxMessageBox(IDS_DIVX_WARNING);
408 theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 1);
413 /*removeme*/
414 if(!g_RegOK)
416 DllRegisterServer();
417 g_RegOK = true;
420 else
422 if(m_hSystrayThread)
424 SendMessage(m_tbid.hSystrayWnd, WM_CLOSE, 0, 0);
426 if(WaitForSingleObject(m_hSystrayThread, 10000) != WAIT_OBJECT_0)
428 DbgLog((LOG_TRACE, 0, _T("CALL THE AMBULANCE!!!")));
429 TerminateThread(m_hSystrayThread, (DWORD)-1);
432 m_hSystrayThread = 0;
436 return __super::JoinFilterGraph(pGraph, pName);
439 STDMETHODIMP CDirectVobSubFilter::QueryFilterInfo(FILTER_INFO* pInfo)
441 CheckPointer(pInfo, E_POINTER);
442 ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO));
444 if(!get_Forced())
445 return __super::QueryFilterInfo(pInfo);
447 wcscpy(pInfo->achName, L"DirectVobSub (forced auto-loading version)");
448 if(pInfo->pGraph = m_pGraph) m_pGraph->AddRef();
450 return S_OK;
453 // CTransformFilter
455 HRESULT CDirectVobSubFilter::SetMediaType(PIN_DIRECTION dir, const CMediaType* pmt)
457 HRESULT hr = __super::SetMediaType(dir, pmt);
458 if(FAILED(hr)) return hr;
460 if(dir == PINDIR_INPUT)
462 CAutoLock cAutoLock(&m_csReceive);
464 REFERENCE_TIME atpf =
465 pmt->formattype == FORMAT_VideoInfo ? ((VIDEOINFOHEADER*)pmt->Format())->AvgTimePerFrame :
466 pmt->formattype == FORMAT_VideoInfo2 ? ((VIDEOINFOHEADER2*)pmt->Format())->AvgTimePerFrame :
469 m_fps = atpf ? 10000000.0 / atpf : 25;
471 if (pmt->formattype == FORMAT_VideoInfo2)
472 m_CurrentVIH2 = *(VIDEOINFOHEADER2*)pmt->Format();
474 DbgLog((LOG_TRACE, 3, "SetMediaType => InitSubPicQueue"));
475 InitSubPicQueue();
477 else if(dir == PINDIR_OUTPUT)
482 return hr;
485 HRESULT CDirectVobSubFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
487 if(dir == PINDIR_INPUT)
490 else if(dir == PINDIR_OUTPUT)
492 /*removeme*/
493 if(HmGyanusVagyTeNekem(pPin)) return(E_FAIL);
496 return __super::CheckConnect(dir, pPin);
499 HRESULT CDirectVobSubFilter::CompleteConnect(PIN_DIRECTION dir, IPin* pReceivePin)
501 bool reconnected = false;
502 if(dir == PINDIR_INPUT)
504 DbgLog((LOG_TRACE, 3, TEXT("connect input")));
505 DumpGraph(m_pGraph,0);
506 CComPtr<IBaseFilter> pFilter;
508 // needed when we have a decoder with a version number of 3.x
509 if(SUCCEEDED(m_pGraph->FindFilterByName(L"DivX MPEG-4 DVD Video Decompressor ", &pFilter))
510 && (GetFileVersion(_T("divx_c32.ax")) >> 48) <= 4
511 || SUCCEEDED(m_pGraph->FindFilterByName(L"Microcrap MPEG-4 Video Decompressor", &pFilter))
512 || SUCCEEDED(m_pGraph->FindFilterByName(L"Microsoft MPEG-4 Video Decompressor", &pFilter))
513 && (GetFileVersion(_T("mpg4ds32.ax")) >> 48) <= 3)
515 m_fMSMpeg4Fix = true;
518 else if(dir == PINDIR_OUTPUT)
520 DbgLog((LOG_TRACE, 3, TEXT("connect output")));
521 DumpGraph(m_pGraph,0);
522 const CMediaType* mtIn = &(m_pInput->CurrentMediaType());
523 const CMediaType* mtOut = &(m_pOutput->CurrentMediaType());
524 CMediaType desiredMt;
525 int position = 0;
526 HRESULT hr;
528 bool can_reconnect = false;
529 bool can_transform = (DoCheckTransform(mtIn, mtOut, true)==S_OK);
530 if( mtIn->subtype!=mtOut->subtype )
532 position = GetOutputSubtypePosition(mtOut->subtype);
533 if(position>=0)
535 hr = GetMediaType(position, &desiredMt);
536 if (hr!=S_OK)
538 DbgLog((LOG_ERROR, 3, TEXT("Unexpected error when GetMediaType, position:%d"), position));
540 else
542 hr = DoCheckTransform(&desiredMt, mtOut, true);
543 if (hr!=S_OK)
545 DbgLog((LOG_TRACE, 3, TEXT("Transform not accept:")));
546 DisplayType(0,&desiredMt);
547 DisplayType(0,mtOut);
549 else
551 hr = m_pInput->GetConnected()->QueryAccept(&desiredMt);
552 if(hr!=S_OK)
554 DbgLog((LOG_TRACE, 3, TEXT("Upstream not accept:")));
555 DisplayType(0, &desiredMt);
557 else
559 can_reconnect = true;
560 DbgLog((LOG_ERROR, 3, TEXT("Can use the same subtype!")));
565 else
567 DbgLog((LOG_ERROR, 3, TEXT("Cannot use the same subtype!")));
570 if(!can_reconnect && !can_transform)
572 position = 0;
575 hr = GetMediaType(position, &desiredMt);
576 ++position;
577 //if( FAILED(hr) )
578 if( hr!=S_OK )
579 break;
581 DbgLog((LOG_TRACE, 3, TEXT("Checking reconnect with media type:")));
582 DisplayType(0, &desiredMt);
584 if( DoCheckTransform(&desiredMt, mtOut, true)!=S_OK ||
585 m_pInput->GetConnected()->QueryAccept(&desiredMt)!=S_OK )
587 continue;
589 else
591 can_reconnect = true;
592 break;
594 } while ( true );
596 if ( can_reconnect )
598 if (SUCCEEDED(ReconnectPin(m_pInput, &desiredMt)))
600 reconnected = true;
601 DumpGraph(m_pGraph,0);
602 //m_pInput->SetMediaType(&desiredMt);
603 DbgLog((LOG_TRACE, 3, TEXT("reconnected succeed!")));
606 else if(!can_transform)
608 DbgLog((LOG_TRACE, 3, TEXT("Failed to agree reconnect type!")));
609 if(m_pInput->IsConnected())
611 m_pInput->GetConnected()->Disconnect();
612 m_pInput->Disconnect();
614 if(m_pOutput->IsConnected())
616 m_pOutput->GetConnected()->Disconnect();
617 m_pOutput->Disconnect();
619 return VFW_E_TYPE_NOT_ACCEPTED;
622 if (!reconnected && m_pOutput->IsConnected())
624 if(!m_hSystrayThread)
626 m_tbid.graph = m_pGraph;
627 m_tbid.dvs = static_cast<IDirectVobSub*>(this);
629 DWORD tid;
630 m_hSystrayThread = CreateThread(0, 0, SystrayThreadProc, &m_tbid, 0, &tid);
632 m_pInput->SetMediaType( &m_pInput->CurrentMediaType() );
635 HRESULT hr = __super::CompleteConnect(dir, pReceivePin);
636 DbgLog((LOG_TRACE, 3, TEXT("connect fininshed!")));
637 DumpGraph(m_pGraph,0);
638 return hr;
641 HRESULT CDirectVobSubFilter::BreakConnect(PIN_DIRECTION dir)
643 if(dir == PINDIR_INPUT)
645 //if(m_pOutput->IsConnected())
647 // m_pOutput->GetConnected()->Disconnect();
648 // m_pOutput->Disconnect();
651 else if(dir == PINDIR_OUTPUT)
653 // not really needed, but may free up a little memory
654 CAutoLock cAutoLock(&m_csQueueLock);
655 m_pSubPicQueue = NULL;
658 return __super::BreakConnect(dir);
661 HRESULT CDirectVobSubFilter::StartStreaming()
663 /* WARNING: calls to m_pGraph member functions from within this function will generate deadlock with Haali
664 * Video Renderer in MPC. Reason is that CAutoLock's variables in IFilterGraph functions are overriden by
665 * CFGManager class.
668 m_fLoading = false;
670 DbgLog((LOG_TRACE, 3, "StartStreaming => InitSubPicQueue"));
671 InitSubPicQueue();
673 m_tbid.fRunOnce = true;
675 put_MediaFPS(m_fMediaFPSEnabled, m_MediaFPS);
677 return __super::StartStreaming();
680 HRESULT CDirectVobSubFilter::StopStreaming()
682 InvalidateSubtitle();
684 //xy Timing
685 //FILE * timingFile = fopen("C:\\vsfilter_timing.txt", "at");
686 //fprintf(timingFile, "%s:%ld %s:%ld\n", "m_time_alphablt", m_time_alphablt, "m_time_rasterization", m_time_rasterization);
687 //fclose(timingFile);
689 return __super::StopStreaming();
692 HRESULT CDirectVobSubFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
694 m_tPrev = tStart;
695 return __super::NewSegment(tStart, tStop, dRate);
700 REFERENCE_TIME CDirectVobSubFilter::CalcCurrentTime()
702 REFERENCE_TIME rt = m_pSubClock ? m_pSubClock->GetTime() : m_tPrev;
703 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)
706 void CDirectVobSubFilter::InitSubPicQueue()
708 CAutoLock cAutoLock(&m_csQueueLock);
709 switch(m_colourSpace)
711 case CDirectVobSub::BT_601:
712 ColorConvTable::SetDefaultYUVType(ColorConvTable::BT601);
713 break;
714 case CDirectVobSub::BT_709:
715 ColorConvTable::SetDefaultYUVType(ColorConvTable::BT709);
716 break;
717 case CDirectVobSub::AUTO_GUESS:
718 ColorConvTable::SetDefaultYUVType( (m_w > m_bt601Width || m_h > m_bt601Height) ?
719 ColorConvTable::BT709 : ColorConvTable::BT601 );
720 break;
722 CacheManager::GetPathDataMruCache()->SetMaxItemNum(m_path_data_cache_max_item_num);
723 CacheManager::GetScanLineDataMruCache()->SetMaxItemNum(m_scan_line_data_cache_max_item_num);
724 CacheManager::GetOverlayNoBlurMruCache()->SetMaxItemNum(m_overlay_no_blur_cache_max_item_num);
725 CacheManager::GetOverlayMruCache()->SetMaxItemNum(m_overlay_cache_max_item_num);
726 SubpixelPositionControler::GetGlobalControler().SetSubpixelLevel( static_cast<SubpixelPositionControler::SUBPIXEL_LEVEL>(m_subpixel_pos_level) );
728 m_pSubPicQueue = NULL;
730 const GUID& subtype = m_pInput->CurrentMediaType().subtype;
732 BITMAPINFOHEADER bihIn;
733 ExtractBIH(&m_pInput->CurrentMediaType(), &bihIn);
735 m_spd.type = -1;
737 if(subtype == MEDIASUBTYPE_YV12) m_spd.type = MSP_YV12;
738 else if(subtype == MEDIASUBTYPE_P010) m_spd.type = MSP_P010;
739 else if(subtype == MEDIASUBTYPE_P016) m_spd.type = MSP_P016;
740 else if(subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV) m_spd.type = MSP_IYUV;
741 else if(subtype == MEDIASUBTYPE_YUY2) m_spd.type = MSP_YUY2;
742 else if(subtype == MEDIASUBTYPE_RGB32) m_spd.type = MSP_RGB32;
743 else if(subtype == MEDIASUBTYPE_RGB24) m_spd.type = MSP_RGB24;
744 else if(subtype == MEDIASUBTYPE_RGB565) m_spd.type = MSP_RGB16;
745 else if(subtype == MEDIASUBTYPE_RGB555) m_spd.type = MSP_RGB15;
746 else if(subtype == MEDIASUBTYPE_NV12) m_spd.type = MSP_NV12;
747 else if(subtype == MEDIASUBTYPE_NV21) m_spd.type = MSP_NV21;
749 m_spd.w = m_w;
750 m_spd.h = m_h;
751 m_spd.bpp = (m_spd.type == MSP_P010 || m_spd.type == MSP_P016) ? 16 :
752 (m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV || m_spd.type == MSP_NV12 || m_spd.type == MSP_NV21) ? 8 : bihIn.biBitCount;
753 m_spd.pitch = m_spd.w*m_spd.bpp>>3;
755 m_pTempPicBuff.Free();
756 if(m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV)
757 m_pTempPicBuff.Allocate(4*m_spd.pitch*m_spd.h);
758 else if(m_spd.type == MSP_P010 || m_spd.type == MSP_P016)
759 m_pTempPicBuff.Allocate(m_spd.pitch*m_spd.h+m_spd.pitch*m_spd.h/2);
760 else
761 m_pTempPicBuff.Allocate(m_spd.pitch*m_spd.h);
762 m_spd.bits = (void*)m_pTempPicBuff;
764 //CComPtr<ISubPicExAllocator> pSubPicAllocator = new CMemSubPicAllocator(m_spd.type, CSize(m_w, m_h));
765 CComPtr<ISubPicExAllocator> pSubPicAllocator = new CPooledSubPicAllocator(m_spd.type, CSize(m_w, m_h), MAX_SUBPIC_QUEUE_LENGTH + 1);
766 if(pSubPicAllocator==NULL)
768 //fix me: log error
771 CSize video(bihIn.biWidth, bihIn.biHeight), window = video;
772 if(AdjustFrameSize(window)) video += video;
773 ASSERT(window == CSize(m_w, m_h));
775 pSubPicAllocator->SetCurSize(window);
776 pSubPicAllocator->SetCurVidRect(CRect(CPoint((window.cx - video.cx)/2, (window.cy - video.cy)/2), video));
778 HRESULT hr = S_OK;
779 //m_pSubPicQueue = m_fDoPreBuffering
780 // ? (ISubPicQueue*)new CSubPicQueue(MAX_SUBPIC_QUEUE_LENGTH, pSubPicAllocator, &hr)
781 // : (ISubPicQueue*)new CSubPicQueueNoThread(pSubPicAllocator, &hr);
782 m_pSubPicQueue = new CSubPicQueueNoThread(pSubPicAllocator, &hr);
784 if(FAILED(hr)) m_pSubPicQueue = NULL;
786 UpdateSubtitle(false);
788 if(m_hbm) {DeleteObject(m_hbm); m_hbm = NULL;}
789 if(m_hdc) {DeleteDC(m_hdc); m_hdc = NULL;}
791 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};
792 m_hdc = CreateCompatibleDC(NULL);
793 m_hbm = CreateDIBSection(m_hdc, (BITMAPINFO*)&b, DIB_RGB_COLORS, NULL, NULL, 0);
795 BITMAP bm;
796 GetObject(m_hbm, sizeof(bm), &bm);
797 memsetd(bm.bmBits, 0xFF000000, bm.bmHeight*bm.bmWidthBytes);
800 bool CDirectVobSubFilter::AdjustFrameSize(CSize& s)
802 int horizontal, vertical, resx2, resx2minw, resx2minh;
803 get_ExtendPicture(&horizontal, &vertical, &resx2, &resx2minw, &resx2minh);
805 bool fRet = (resx2 == 1) || (resx2 == 2 && s.cx*s.cy <= resx2minw*resx2minh);
807 if(fRet)
809 s.cx <<= 1;
810 s.cy <<= 1;
813 int h;
814 switch(vertical&0x7f)
816 case 1:
817 h = s.cx * 9 / 16;
818 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
819 break;
820 case 2:
821 h = s.cx * 3 / 4;
822 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
823 break;
824 case 3:
825 h = 480;
826 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
827 break;
828 case 4:
829 h = 576;
830 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
831 break;
834 if(horizontal == 1)
836 s.cx = (s.cx + 31) & ~31;
837 s.cy = (s.cy + 1) & ~1;
840 return(fRet);
843 STDMETHODIMP CDirectVobSubFilter::Count(DWORD* pcStreams)
845 if(!pcStreams) return E_POINTER;
847 *pcStreams = 0;
849 int nLangs = 0;
850 if(SUCCEEDED(get_LanguageCount(&nLangs)))
851 (*pcStreams) += nLangs;
853 (*pcStreams) += 2; // enable ... disable
855 (*pcStreams) += 2; // normal flipped
857 return S_OK;
860 #define MAXPREFLANGS 5
862 int CDirectVobSubFilter::FindPreferedLanguage(bool fHideToo)
864 AFX_MANAGE_STATE(AfxGetStaticModuleState());
866 int nLangs;
867 get_LanguageCount(&nLangs);
869 if(nLangs <= 0) return(0);
871 for(int i = 0; i < MAXPREFLANGS; i++)
873 CString tmp;
874 tmp.Format(IDS_RL_LANG, i);
876 CString lang = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
878 if(!lang.IsEmpty())
880 for(int ret = 0; ret < nLangs; ret++)
882 CString l;
883 WCHAR* pName = NULL;
884 get_LanguageName(ret, &pName);
885 l = pName;
886 CoTaskMemFree(pName);
888 if(!l.CompareNoCase(lang)) return(ret);
893 return(0);
896 void CDirectVobSubFilter::UpdatePreferedLanguages(CString l)
898 AFX_MANAGE_STATE(AfxGetStaticModuleState());
900 CString langs[MAXPREFLANGS+1];
902 int i = 0, j = 0, k = -1;
903 for(; i < MAXPREFLANGS; i++)
905 CString tmp;
906 tmp.Format(IDS_RL_LANG, i);
908 langs[j] = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
910 if(!langs[j].IsEmpty())
912 if(!langs[j].CompareNoCase(l)) k = j;
913 j++;
917 if(k == -1)
919 langs[k = j] = l;
920 j++;
923 // move the selected to the top of the list
925 while(k > 0)
927 CString tmp = langs[k]; langs[k] = langs[k-1]; langs[k-1] = tmp;
928 k--;
931 // move "Hide subtitles" to the last position if it wasn't our selection
933 CString hidesubs;
934 hidesubs.LoadString(IDS_M_HIDESUBTITLES);
936 for(k = 1; k < j; k++)
938 if(!langs[k].CompareNoCase(hidesubs)) break;
941 while(k < j-1)
943 CString tmp = langs[k]; langs[k] = langs[k+1]; langs[k+1] = tmp;
944 k++;
947 for(i = 0; i < j; i++)
949 CString tmp;
950 tmp.Format(IDS_RL_LANG, i);
952 theApp.WriteProfileString(ResStr(IDS_R_PREFLANGS), tmp, langs[i]);
956 STDMETHODIMP CDirectVobSubFilter::Enable(long lIndex, DWORD dwFlags)
958 if(!(dwFlags & AMSTREAMSELECTENABLE_ENABLE))
959 return E_NOTIMPL;
961 int nLangs = 0;
962 get_LanguageCount(&nLangs);
964 if(!(lIndex >= 0 && lIndex < nLangs+2+2))
965 return E_INVALIDARG;
967 int i = lIndex-1;
969 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
971 put_HideSubtitles(false);
973 else if(i >= 0 && i < nLangs)
975 put_HideSubtitles(false);
976 put_SelectedLanguage(i);
978 WCHAR* pName = NULL;
979 if(SUCCEEDED(get_LanguageName(i, &pName)))
981 UpdatePreferedLanguages(CString(pName));
982 if(pName) CoTaskMemFree(pName);
985 else if(i == nLangs && !m_fLoading)
987 put_HideSubtitles(true);
989 else if((i == nLangs+1 || i == nLangs+2) && !m_fLoading)
991 put_Flip(i == nLangs+2, m_fFlipSubtitles);
994 return S_OK;
997 STDMETHODIMP CDirectVobSubFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk)
999 AFX_MANAGE_STATE(AfxGetStaticModuleState());
1000 const int FLAG_CMD = 1;
1001 const int FLAG_EXTERNAL_SUB = 2;
1002 const int FLAG_PICTURE_CMD = 4;
1003 const int FLAG_VISIBILITY_CMD = 8;
1005 const int GROUP_NUM_BASE = 0x648E40;//random number
1007 int nLangs = 0;
1008 get_LanguageCount(&nLangs);
1010 if(!(lIndex >= 0 && lIndex < nLangs+2+2))
1011 return E_INVALIDARG;
1013 int i = lIndex-1;
1015 if(ppmt) *ppmt = CreateMediaType(&m_pInput->CurrentMediaType());
1017 if(pdwFlags)
1019 *pdwFlags = 0;
1021 if(i == -1 && !m_fHideSubtitles
1022 || i >= 0 && i < nLangs && i == m_iSelectedLanguage
1023 || i == nLangs && m_fHideSubtitles
1024 || i == nLangs+1 && !m_fFlipPicture
1025 || i == nLangs+2 && m_fFlipPicture)
1027 *pdwFlags |= AMSTREAMSELECTINFO_ENABLED;
1031 if(plcid) *plcid = 0;
1033 if(pdwGroup)
1035 *pdwGroup = GROUP_NUM_BASE;
1036 if(i == -1)
1038 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_VISIBILITY_CMD;
1040 else if(i >= 0 && i < nLangs)
1042 bool isEmbedded = false;
1043 if( SUCCEEDED(GetIsEmbeddedSubStream(i, &isEmbedded)) )
1045 if(isEmbedded)
1047 *pdwGroup = GROUP_NUM_BASE & ~(FLAG_CMD | FLAG_EXTERNAL_SUB);
1049 else
1051 *pdwGroup = (GROUP_NUM_BASE & ~FLAG_CMD) | FLAG_EXTERNAL_SUB;
1055 else if(i == nLangs)
1057 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_VISIBILITY_CMD;
1059 else if(i == nLangs+1)
1061 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_PICTURE_CMD;
1063 else if(i == nLangs+2)
1065 *pdwGroup = GROUP_NUM_BASE | FLAG_CMD | FLAG_PICTURE_CMD;
1069 if(ppszName)
1071 *ppszName = NULL;
1073 CStringW str;
1074 if(i == -1) str = ResStr(IDS_M_SHOWSUBTITLES);
1075 else if(i >= 0 && i < nLangs)
1077 get_LanguageName(i, ppszName);
1079 else if(i == nLangs)
1081 str = ResStr(IDS_M_HIDESUBTITLES);
1083 else if(i == nLangs+1)
1085 str = ResStr(IDS_M_ORIGINALPICTURE);
1087 else if(i == nLangs+2)
1089 str = ResStr(IDS_M_FLIPPEDPICTURE);
1092 if(!str.IsEmpty())
1094 *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength()+1)*sizeof(WCHAR));
1095 if(*ppszName == NULL) return S_FALSE;
1096 wcscpy(*ppszName, str);
1100 if(ppObject) *ppObject = NULL;
1102 if(ppUnk) *ppUnk = NULL;
1104 return S_OK;
1107 STDMETHODIMP CDirectVobSubFilter::GetClassID(CLSID* pClsid)
1109 if(pClsid == NULL) return E_POINTER;
1110 *pClsid = m_clsid;
1111 return NOERROR;
1114 STDMETHODIMP CDirectVobSubFilter::GetPages(CAUUID* pPages)
1116 CheckPointer(pPages, E_POINTER);
1118 pPages->cElems = 8;
1119 pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID)*pPages->cElems);
1121 if(pPages->pElems == NULL) return E_OUTOFMEMORY;
1123 int i = 0;
1124 pPages->pElems[i++] = __uuidof(CDVSMainPPage);
1125 pPages->pElems[i++] = __uuidof(CDVSGeneralPPage);
1126 pPages->pElems[i++] = __uuidof(CDVSMiscPPage);
1127 pPages->pElems[i++] = __uuidof(CDVSMorePPage);
1128 pPages->pElems[i++] = __uuidof(CDVSTimingPPage);
1129 pPages->pElems[i++] = __uuidof(CDVSColorPPage);
1130 pPages->pElems[i++] = __uuidof(CDVSPathsPPage);
1131 pPages->pElems[i++] = __uuidof(CDVSAboutPPage);
1133 return NOERROR;
1136 // IDirectVobSub
1138 STDMETHODIMP CDirectVobSubFilter::put_FileName(WCHAR* fn)
1140 AMTRACE((TEXT(__FUNCTION__),0));
1141 HRESULT hr = CDirectVobSub::put_FileName(fn);
1143 if(hr == S_OK && !Open())
1145 m_FileName.Empty();
1146 hr = E_FAIL;
1149 return hr;
1152 STDMETHODIMP CDirectVobSubFilter::get_LanguageCount(int* nLangs)
1154 HRESULT hr = CDirectVobSub::get_LanguageCount(nLangs);
1156 if(hr == NOERROR && nLangs)
1158 CAutoLock cAutolock(&m_csQueueLock);
1160 *nLangs = 0;
1161 POSITION pos = m_pSubStreams.GetHeadPosition();
1162 while(pos) (*nLangs) += m_pSubStreams.GetNext(pos)->GetStreamCount();
1165 return hr;
1168 STDMETHODIMP CDirectVobSubFilter::get_LanguageName(int iLanguage, WCHAR** ppName)
1170 HRESULT hr = CDirectVobSub::get_LanguageName(iLanguage, ppName);
1172 if(!ppName) return E_POINTER;
1174 if(hr == NOERROR)
1176 CAutoLock cAutolock(&m_csQueueLock);
1178 hr = E_INVALIDARG;
1180 int i = iLanguage;
1182 POSITION pos = m_pSubStreams.GetHeadPosition();
1183 while(i >= 0 && pos)
1185 CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
1187 if(i < pSubStream->GetStreamCount())
1189 pSubStream->GetStreamInfo(i, ppName, NULL);
1190 hr = NOERROR;
1191 break;
1194 i -= pSubStream->GetStreamCount();
1198 return hr;
1201 STDMETHODIMP CDirectVobSubFilter::put_SelectedLanguage(int iSelected)
1203 HRESULT hr = CDirectVobSub::put_SelectedLanguage(iSelected);
1205 if(hr == NOERROR)
1207 UpdateSubtitle(false);
1210 return hr;
1213 STDMETHODIMP CDirectVobSubFilter::put_HideSubtitles(bool fHideSubtitles)
1215 HRESULT hr = CDirectVobSub::put_HideSubtitles(fHideSubtitles);
1217 if(hr == NOERROR)
1219 UpdateSubtitle(false);
1222 return hr;
1225 STDMETHODIMP CDirectVobSubFilter::put_PreBuffering(bool fDoPreBuffering)
1227 HRESULT hr = CDirectVobSub::put_PreBuffering(fDoPreBuffering);
1229 if(hr == NOERROR)
1231 DbgLog((LOG_TRACE, 3, "put_PreBuffering => InitSubPicQueue"));
1232 InitSubPicQueue();
1235 return hr;
1238 STDMETHODIMP CDirectVobSubFilter::put_ColourSpace(int colourSpace)
1240 CAutoLock cAutolock(&m_csQueueLock);
1241 HRESULT hr = CDirectVobSub::put_ColourSpace(colourSpace);
1243 if(hr == NOERROR)
1245 switch(m_colourSpace)
1247 case CDirectVobSub::BT_601:
1248 ColorConvTable::SetDefaultYUVType(ColorConvTable::BT601);
1249 break;
1250 case CDirectVobSub::BT_709:
1251 ColorConvTable::SetDefaultYUVType(ColorConvTable::BT709);
1252 break;
1253 case CDirectVobSub::AUTO_GUESS:
1254 ColorConvTable::SetDefaultYUVType( (m_w > m_bt601Width || m_h > m_bt601Height) ?
1255 ColorConvTable::BT709 : ColorConvTable::BT601 );
1256 break;
1260 return hr;
1263 STDMETHODIMP CDirectVobSubFilter::put_Placement(bool fOverridePlacement, int xperc, int yperc)
1265 DbgLog((LOG_TRACE, 3, "%s(%d) %s", __FILE__, __LINE__, __FUNCTION__));
1266 HRESULT hr = CDirectVobSub::put_Placement(fOverridePlacement, xperc, yperc);
1268 if(hr == NOERROR)
1270 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1271 //UpdateSubtitle(true);
1272 UpdateSubtitle(false);
1275 return hr;
1278 STDMETHODIMP CDirectVobSubFilter::put_VobSubSettings(bool fBuffer, bool fOnlyShowForcedSubs, bool fReserved)
1280 HRESULT hr = CDirectVobSub::put_VobSubSettings(fBuffer, fOnlyShowForcedSubs, fReserved);
1282 if(hr == NOERROR)
1284 // UpdateSubtitle(false);
1285 InvalidateSubtitle();
1288 return hr;
1291 STDMETHODIMP CDirectVobSubFilter::put_TextSettings(void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer)
1293 HRESULT hr = CDirectVobSub::put_TextSettings(lf, lflen, color, fShadow, fOutline, fAdvancedRenderer);
1295 if(hr == NOERROR)
1297 // UpdateSubtitle(true);
1298 InvalidateSubtitle();
1301 return hr;
1304 STDMETHODIMP CDirectVobSubFilter::put_SubtitleTiming(int delay, int speedmul, int speeddiv)
1306 HRESULT hr = CDirectVobSub::put_SubtitleTiming(delay, speedmul, speeddiv);
1308 if(hr == NOERROR)
1310 InvalidateSubtitle();
1313 return hr;
1316 STDMETHODIMP CDirectVobSubFilter::put_OverlayCacheMaxItemNum( int overlay_cache_max_item_num )
1318 CAutoLock cAutolock(&m_csQueueLock);
1319 HRESULT hr = CDirectVobSub::put_OverlayCacheMaxItemNum(overlay_cache_max_item_num);
1321 if(hr == NOERROR)
1323 CacheManager::GetOverlayMruCache()->SetMaxItemNum(m_overlay_cache_max_item_num);
1326 return hr;
1329 STDMETHODIMP CDirectVobSubFilter::put_ScanLineDataCacheMaxItemNum( int scan_line_data_cache_max_item_num )
1331 CAutoLock cAutolock(&m_csQueueLock);
1332 HRESULT hr = CDirectVobSub::put_ScanLineDataCacheMaxItemNum(scan_line_data_cache_max_item_num);
1334 if(hr == NOERROR)
1336 CacheManager::GetScanLineDataMruCache()->SetMaxItemNum(m_scan_line_data_cache_max_item_num);
1339 return hr;
1342 STDMETHODIMP CDirectVobSubFilter::put_PathDataCacheMaxItemNum(int path_data_cache_max_item_num)
1344 CAutoLock cAutolock(&m_csQueueLock);
1345 HRESULT hr = CDirectVobSub::put_PathDataCacheMaxItemNum(path_data_cache_max_item_num);
1347 if(hr == NOERROR)
1349 CacheManager::GetPathDataMruCache()->SetMaxItemNum(m_path_data_cache_max_item_num);
1352 return hr;
1355 STDMETHODIMP CDirectVobSubFilter::put_OverlayNoBlurCacheMaxItemNum(int overlay_no_blur_cache_max_item_num)
1357 CAutoLock cAutolock(&m_csQueueLock);
1358 HRESULT hr = CDirectVobSub::put_OverlayNoBlurCacheMaxItemNum(overlay_no_blur_cache_max_item_num);
1360 if(hr == NOERROR)
1362 CacheManager::GetOverlayNoBlurMruCache()->SetMaxItemNum(m_overlay_no_blur_cache_max_item_num);
1365 return hr;
1368 STDMETHODIMP CDirectVobSubFilter::get_CachesInfo(CachesInfo* caches_info)
1370 CAutoLock cAutoLock(&m_csQueueLock);
1371 HRESULT hr = CDirectVobSub::get_CachesInfo(caches_info);
1373 caches_info->path_cache_cur_item_num = CacheManager::GetPathDataMruCache()->GetCurItemNum();
1374 caches_info->path_cache_hit_count = CacheManager::GetPathDataMruCache()->GetCacheHitCount();
1375 caches_info->path_cache_query_count = CacheManager::GetPathDataMruCache()->GetQueryCount();
1376 caches_info->scanline_cache_cur_item_num= CacheManager::GetScanLineDataMruCache()->GetCurItemNum();
1377 caches_info->scanline_cache_hit_count = CacheManager::GetScanLineDataMruCache()->GetCacheHitCount();
1378 caches_info->scanline_cache_query_count = CacheManager::GetScanLineDataMruCache()->GetQueryCount();
1379 caches_info->non_blur_cache_cur_item_num= CacheManager::GetOverlayNoBlurMruCache()->GetCurItemNum();
1380 caches_info->non_blur_cache_hit_count = CacheManager::GetOverlayNoBlurMruCache()->GetCacheHitCount();
1381 caches_info->non_blur_cache_query_count = CacheManager::GetOverlayNoBlurMruCache()->GetQueryCount();
1382 caches_info->overlay_cache_cur_item_num = CacheManager::GetOverlayMruCache()->GetCurItemNum();
1383 caches_info->overlay_cache_hit_count = CacheManager::GetOverlayMruCache()->GetCacheHitCount();
1384 caches_info->overlay_cache_query_count = CacheManager::GetOverlayMruCache()->GetQueryCount();
1386 caches_info->interpolate_cache_cur_item_num = CacheManager::GetSubpixelVarianceCache()->GetCurItemNum();
1387 caches_info->interpolate_cache_hit_count = CacheManager::GetSubpixelVarianceCache()->GetCacheHitCount();
1388 caches_info->interpolate_cache_query_count = CacheManager::GetSubpixelVarianceCache()->GetQueryCount();
1389 caches_info->text_info_cache_cur_item_num = CacheManager::GetTextInfoCache()->GetCurItemNum();
1390 caches_info->text_info_cache_hit_count = CacheManager::GetTextInfoCache()->GetCacheHitCount();
1391 caches_info->text_info_cache_query_count = CacheManager::GetTextInfoCache()->GetQueryCount();
1393 caches_info->word_info_cache_cur_item_num = CacheManager::GetAssTagListMruCache()->GetCurItemNum();
1394 caches_info->word_info_cache_hit_count = CacheManager::GetAssTagListMruCache()->GetCacheHitCount();
1395 caches_info->word_info_cache_query_count = CacheManager::GetAssTagListMruCache()->GetQueryCount();
1397 return hr;
1400 STDMETHODIMP CDirectVobSubFilter::put_SubpixelPositionLevel(int subpixel_pos_level)
1402 CAutoLock cAutolock(&m_csQueueLock);
1403 HRESULT hr = CDirectVobSub::put_SubpixelPositionLevel(subpixel_pos_level);
1405 if(hr == NOERROR)
1407 SubpixelPositionControler::GetGlobalControler().SetSubpixelLevel( static_cast<SubpixelPositionControler::SUBPIXEL_LEVEL>(subpixel_pos_level) );
1410 return hr;
1413 STDMETHODIMP CDirectVobSubFilter::put_FollowUpstreamPreferredOrder( bool fFollowUpstreamPreferredOrder )
1415 CAutoLock cAutolock(&m_csQueueLock);
1416 HRESULT hr = CDirectVobSub::put_FollowUpstreamPreferredOrder(fFollowUpstreamPreferredOrder);
1418 if(hr == NOERROR)
1420 m_donot_follow_upstream_preferred_order = !m_fFollowUpstreamPreferredOrder;
1423 return hr;
1426 STDMETHODIMP CDirectVobSubFilter::get_MediaFPS(bool* fEnabled, double* fps)
1428 HRESULT hr = CDirectVobSub::get_MediaFPS(fEnabled, fps);
1430 CComQIPtr<IMediaSeeking> pMS = m_pGraph;
1431 double rate;
1432 if(pMS && SUCCEEDED(pMS->GetRate(&rate)))
1434 m_MediaFPS = rate * m_fps;
1435 if(fps) *fps = m_MediaFPS;
1438 return hr;
1441 STDMETHODIMP CDirectVobSubFilter::put_MediaFPS(bool fEnabled, double fps)
1443 HRESULT hr = CDirectVobSub::put_MediaFPS(fEnabled, fps);
1445 CComQIPtr<IMediaSeeking> pMS = m_pGraph;
1446 if(pMS)
1448 if(hr == NOERROR)
1450 hr = pMS->SetRate(m_fMediaFPSEnabled ? m_MediaFPS / m_fps : 1.0);
1453 double dRate;
1454 if(SUCCEEDED(pMS->GetRate(&dRate)))
1455 m_MediaFPS = dRate * m_fps;
1458 return hr;
1461 STDMETHODIMP CDirectVobSubFilter::get_ZoomRect(NORMALIZEDRECT* rect)
1463 return E_NOTIMPL;
1466 STDMETHODIMP CDirectVobSubFilter::put_ZoomRect(NORMALIZEDRECT* rect)
1468 return E_NOTIMPL;
1471 // IDirectVobSub2
1473 STDMETHODIMP CDirectVobSubFilter::put_TextSettings(STSStyle* pDefStyle)
1475 HRESULT hr = CDirectVobSub::put_TextSettings(pDefStyle);
1477 if(hr == NOERROR)
1479 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1480 //UpdateSubtitle(true);
1481 UpdateSubtitle(false);
1484 return hr;
1487 STDMETHODIMP CDirectVobSubFilter::put_AspectRatioSettings(CSimpleTextSubtitle::EPARCompensationType* ePARCompensationType)
1489 HRESULT hr = CDirectVobSub::put_AspectRatioSettings(ePARCompensationType);
1491 if(hr == NOERROR)
1493 //DbgLog((LOG_TRACE, 3, "%d %s:UpdateSubtitle(true)", __LINE__, __FUNCTION__));
1494 //UpdateSubtitle(true);
1495 UpdateSubtitle(false);
1498 return hr;
1501 // IDirectVobSubFilterColor
1503 STDMETHODIMP CDirectVobSubFilter::HasConfigDialog(int iSelected)
1505 int nLangs;
1506 if(FAILED(get_LanguageCount(&nLangs))) return E_FAIL;
1507 return E_FAIL;
1508 // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
1509 // return(nLangs >= 0 && iSelected < nLangs ? S_OK : E_FAIL);
1512 STDMETHODIMP CDirectVobSubFilter::ShowConfigDialog(int iSelected, HWND hWndParent)
1514 // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
1515 return(E_FAIL);
1518 ///////////////////////////////////////////////////////////////////////////
1520 CDirectVobSubFilter2::CDirectVobSubFilter2(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid) :
1521 CDirectVobSubFilter(punk, phr, clsid)
1525 HRESULT CDirectVobSubFilter2::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
1527 CPinInfo pi;
1528 if(FAILED(pPin->QueryPinInfo(&pi))) return E_FAIL;
1530 if(CComQIPtr<IDirectVobSub>(pi.pFilter)) return E_FAIL;
1532 if(dir == PINDIR_INPUT)
1534 CFilterInfo fi;
1535 if(SUCCEEDED(pi.pFilter->QueryFilterInfo(&fi))
1536 && !wcsnicmp(fi.achName, L"Overlay Mixer", 13))
1537 return(E_FAIL);
1539 else
1543 return __super::CheckConnect(dir, pPin);
1546 HRESULT CDirectVobSubFilter2::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
1548 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::JoinFilterGraph"));
1549 if(pGraph)
1551 BeginEnumFilters(pGraph, pEF, pBF)
1553 if(pBF != (IBaseFilter*)this && CComQIPtr<IDirectVobSub>(pBF))
1554 return E_FAIL;
1556 EndEnumFilters
1558 // don't look... we will do some serious graph hacking again...
1560 // we will add dvs2 to the filter graph cache
1561 // - if the main app has already added some kind of renderer or overlay mixer (anything which accepts video on its input)
1562 // and
1563 // - if we have a reason to auto-load (we don't want to make any trouble when there is no need :)
1565 // This whole workaround is needed because the video stream will always be connected
1566 // to the pre-added filters first, no matter how high merit we have.
1568 if(!get_Forced())
1570 BeginEnumFilters(pGraph, pEF, pBF)
1572 if(CComQIPtr<IDirectVobSub>(pBF))
1573 continue;
1575 CComPtr<IPin> pInPin = GetFirstPin(pBF, PINDIR_INPUT);
1576 CComPtr<IPin> pOutPin = GetFirstPin(pBF, PINDIR_OUTPUT);
1578 if(!pInPin)
1579 continue;
1581 CComPtr<IPin> pPin;
1582 if(pInPin && SUCCEEDED(pInPin->ConnectedTo(&pPin))
1583 || pOutPin && SUCCEEDED(pOutPin->ConnectedTo(&pPin)))
1584 continue;
1586 if(pOutPin && GetFilterName(pBF) == _T("Overlay Mixer"))
1587 continue;
1589 bool fVideoInputPin = false;
1593 BITMAPINFOHEADER bih = {sizeof(BITMAPINFOHEADER), 384, 288, 1, 16, '2YUY', 384*288*2, 0, 0, 0, 0};
1595 CMediaType cmt;
1596 cmt.majortype = MEDIATYPE_Video;
1597 cmt.subtype = MEDIASUBTYPE_YUY2;
1598 cmt.formattype = FORMAT_VideoInfo;
1599 cmt.pUnk = NULL;
1600 cmt.bFixedSizeSamples = TRUE;
1601 cmt.bTemporalCompression = TRUE;
1602 cmt.lSampleSize = 384*288*2;
1603 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
1604 memset(vih, 0, sizeof(VIDEOINFOHEADER));
1605 memcpy(&vih->bmiHeader, &bih, sizeof(bih));
1606 vih->AvgTimePerFrame = 400000;
1608 if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
1610 fVideoInputPin = true;
1611 break;
1614 VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER2));
1615 memset(vih2, 0, sizeof(VIDEOINFOHEADER2));
1616 memcpy(&vih2->bmiHeader, &bih, sizeof(bih));
1617 vih2->AvgTimePerFrame = 400000;
1618 vih2->dwPictAspectRatioX = 384;
1619 vih2->dwPictAspectRatioY = 288;
1621 if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
1623 fVideoInputPin = true;
1624 break;
1627 while(false);
1629 if(fVideoInputPin)
1631 CComPtr<IBaseFilter> pDVS;
1632 if(ShouldWeAutoload(pGraph) && SUCCEEDED(pDVS.CoCreateInstance(__uuidof(CDirectVobSubFilter2))))
1634 CComQIPtr<IDirectVobSub2>(pDVS)->put_Forced(true);
1635 CComQIPtr<IGraphConfig>(pGraph)->AddFilterToCache(pDVS);
1638 break;
1641 EndEnumFilters
1644 else
1648 return __super::JoinFilterGraph(pGraph, pName);
1651 HRESULT CDirectVobSubFilter2::CheckInputType(const CMediaType* mtIn)
1653 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::CheckInputType"));
1654 HRESULT hr = __super::CheckInputType(mtIn);
1656 if(FAILED(hr) || m_pInput->IsConnected()) return hr;
1658 if(!ShouldWeAutoload(m_pGraph)) return VFW_E_TYPE_NOT_ACCEPTED;
1660 GetRidOfInternalScriptRenderer();
1662 return NOERROR;
1665 bool CDirectVobSubFilter2::ShouldWeAutoload(IFilterGraph* pGraph)
1667 XY_AUTO_TIMING(_T("CDirectVobSubFilter2::ShouldWeAutoload"));
1668 TCHAR blacklistedapps[][32] =
1670 _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)
1671 _T("explorer."), // as some users reported thumbnail preview loads dvobsub, I've never experienced this yet...
1672 _T("producer."), // this is real's producer
1673 _T("GoogleDesktopIndex."), // Google Desktop
1674 _T("GoogleDesktopDisplay."), // Google Desktop
1675 _T("GoogleDesktopCrawl."), // Google Desktop
1678 for(int i = 0; i < countof(blacklistedapps); i++)
1680 if(theApp.m_AppName.Find(blacklistedapps[i]) >= 0)
1681 return(false);
1684 int level;
1685 bool m_fExternalLoad, m_fWebLoad, m_fEmbeddedLoad;
1686 get_LoadSettings(&level, &m_fExternalLoad, &m_fWebLoad, &m_fEmbeddedLoad);
1688 if(level < 0 || level >= 2) return(false);
1690 bool fRet = false;
1692 if(level == 1)
1693 fRet = m_fExternalLoad = m_fWebLoad = m_fEmbeddedLoad = true;
1695 // find text stream on known splitters
1697 if(!fRet && m_fEmbeddedLoad)
1699 CComPtr<IBaseFilter> pBF;
1700 if((pBF = FindFilter(CLSID_OggSplitter, pGraph)) || (pBF = FindFilter(CLSID_AviSplitter, pGraph))
1701 || (pBF = FindFilter(L"{34293064-02F2-41D5-9D75-CC5967ACA1AB}", pGraph)) // matroska demux
1702 || (pBF = FindFilter(L"{0A68C3B5-9164-4a54-AFAF-995B2FF0E0D4}", pGraph)) // matroska source
1703 || (pBF = FindFilter(L"{149D2E01-C32E-4939-80F6-C07B81015A7A}", pGraph)) // matroska splitter
1704 || (pBF = FindFilter(L"{55DA30FC-F16B-49fc-BAA5-AE59FC65F82D}", pGraph)) // Haali Media Splitter
1705 || (pBF = FindFilter(L"{564FD788-86C9-4444-971E-CC4A243DA150}", pGraph)) // Haali Media Splitter (AR)
1706 || (pBF = FindFilter(L"{8F43B7D9-9D6B-4F48-BE18-4D787C795EEA}", pGraph)) // Haali Simple Media Splitter
1707 || (pBF = FindFilter(L"{52B63861-DC93-11CE-A099-00AA00479A58}", pGraph)) // 3ivx splitter
1708 || (pBF = FindFilter(L"{6D3688CE-3E9D-42F4-92CA-8A11119D25CD}", pGraph)) // our ogg source
1709 || (pBF = FindFilter(L"{9FF48807-E133-40AA-826F-9B2959E5232D}", pGraph)) // our ogg splitter
1710 || (pBF = FindFilter(L"{803E8280-F3CE-4201-982C-8CD8FB512004}", pGraph)) // dsm source
1711 || (pBF = FindFilter(L"{0912B4DD-A30A-4568-B590-7179EBB420EC}", pGraph)) // dsm splitter
1712 || (pBF = FindFilter(L"{3CCC052E-BDEE-408a-BEA7-90914EF2964B}", pGraph)) // mp4 source
1713 || (pBF = FindFilter(L"{61F47056-E400-43d3-AF1E-AB7DFFD4C4AD}", pGraph)) // mp4 splitter
1714 || (pBF = FindFilter(L"{171252A0-8820-4AFE-9DF8-5C92B2D66B04}", pGraph)) // LAV splitter
1715 || (pBF = FindFilter(L"{B98D13E7-55DB-4385-A33D-09FD1BA26338}", pGraph)) // LAV Splitter Source
1716 || (pBF = FindFilter(L"{E436EBB5-524F-11CE-9F53-0020AF0BA770}", pGraph)) // Solveig matroska splitter
1717 || (pBF = FindFilter(L"{1365BE7A-C86A-473C-9A41-C0A6E82C9FA3}", pGraph)) // MPC-HC MPEG PS/TS/PVA source
1718 || (pBF = FindFilter(L"{DC257063-045F-4BE2-BD5B-E12279C464F0}", pGraph)) // MPC-HC MPEG splitter
1719 || (pBF = FindFilter(L"{529A00DB-0C43-4f5b-8EF2-05004CBE0C6F}", pGraph)) // AV splitter
1720 || (pBF = FindFilter(L"{D8980E15-E1F6-4916-A10F-D7EB4E9E10B8}", pGraph)) // AV source
1723 BeginEnumPins(pBF, pEP, pPin)
1725 BeginEnumMediaTypes(pPin, pEM, pmt)
1727 if(pmt->majortype == MEDIATYPE_Text || pmt->majortype == MEDIATYPE_Subtitle)
1729 fRet = true;
1730 break;
1733 EndEnumMediaTypes(pmt)
1734 if(fRet) break;
1736 EndEnumFilters
1740 // find file name
1742 CStringW fn;
1744 BeginEnumFilters(pGraph, pEF, pBF)
1746 if(CComQIPtr<IFileSourceFilter> pFSF = pBF)
1748 LPOLESTR fnw = NULL;
1749 if(!pFSF || FAILED(pFSF->GetCurFile(&fnw, NULL)) || !fnw)
1750 continue;
1751 fn = CString(fnw);
1752 CoTaskMemFree(fnw);
1753 break;
1756 EndEnumFilters
1758 if((m_fExternalLoad || m_fWebLoad) && (m_fWebLoad || !(wcsstr(fn, L"http://") || wcsstr(fn, L"mms://"))))
1760 bool fTemp = m_fHideSubtitles;
1761 fRet = !fn.IsEmpty() && SUCCEEDED(put_FileName((LPWSTR)(LPCWSTR)fn))
1762 || SUCCEEDED(put_FileName(L"c:\\tmp.srt"))
1763 || fRet;
1764 if(fTemp) m_fHideSubtitles = true;
1767 return(fRet);
1770 void CDirectVobSubFilter2::GetRidOfInternalScriptRenderer()
1772 while(CComPtr<IBaseFilter> pBF = FindFilter(L"{48025243-2D39-11CE-875D-00608CB78066}", m_pGraph))
1774 BeginEnumPins(pBF, pEP, pPin)
1776 PIN_DIRECTION dir;
1777 CComPtr<IPin> pPinTo;
1779 if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT
1780 && SUCCEEDED(pPin->ConnectedTo(&pPinTo)))
1782 m_pGraph->Disconnect(pPinTo);
1783 m_pGraph->Disconnect(pPin);
1784 m_pGraph->ConnectDirect(pPinTo, GetPin(2 + m_pTextInput.GetCount()-1), NULL);
1787 EndEnumPins
1789 if(FAILED(m_pGraph->RemoveFilter(pBF)))
1790 break;
1794 ///////////////////////////////////////////////////////////////////////////////
1796 bool CDirectVobSubFilter::Open()
1798 AMTRACE((TEXT(__FUNCTION__),0));
1799 XY_AUTO_TIMING(TEXT("CDirectVobSubFilter::Open"));
1801 AFX_MANAGE_STATE(AfxGetStaticModuleState());
1803 CAutoLock cAutolock(&m_csQueueLock);
1805 m_pSubStreams.RemoveAll();
1806 m_fIsSubStreamEmbeded.RemoveAll();
1808 m_frd.files.RemoveAll();
1810 CAtlArray<CString> paths;
1812 for(int i = 0; i < 10; i++)
1814 CString tmp;
1815 tmp.Format(IDS_RP_PATH, i);
1816 CString path = theApp.GetProfileString(ResStr(IDS_R_DEFTEXTPATHES), tmp);
1817 if(!path.IsEmpty()) paths.Add(path);
1820 CAtlArray<SubFile> ret;
1821 GetSubFileNames(m_FileName, paths, ret);
1823 for(int i = 0; i < ret.GetCount(); i++)
1825 if(m_frd.files.Find(ret[i].fn))
1826 continue;
1828 CComPtr<ISubStream> pSubStream;
1830 if(!pSubStream)
1832 // CAutoTiming t(TEXT("CRenderedTextSubtitle::Open"), 0);
1833 XY_AUTO_TIMING(TEXT("CRenderedTextSubtitle::Open"));
1834 CAutoPtr<CRenderedTextSubtitle> pRTS(new CRenderedTextSubtitle(&m_csSubLock));
1835 if(pRTS && pRTS->Open(ret[i].fn, DEFAULT_CHARSET) && pRTS->GetStreamCount() > 0)
1837 pSubStream = pRTS.Detach();
1838 m_frd.files.AddTail(ret[i].fn + _T(".style"));
1842 if(!pSubStream)
1844 CAutoTiming t(TEXT("CVobSubFile::Open"), 0);
1845 CAutoPtr<CVobSubFile> pVSF(new CVobSubFile(&m_csSubLock));
1846 if(pVSF && pVSF->Open(ret[i].fn) && pVSF->GetStreamCount() > 0)
1848 pSubStream = pVSF.Detach();
1849 m_frd.files.AddTail(ret[i].fn.Left(ret[i].fn.GetLength()-4) + _T(".sub"));
1853 if(!pSubStream)
1855 CAutoTiming t(TEXT("ssf::CRenderer::Open"), 0);
1856 CAutoPtr<ssf::CRenderer> pSSF(new ssf::CRenderer(&m_csSubLock));
1857 if(pSSF && pSSF->Open(ret[i].fn) && pSSF->GetStreamCount() > 0)
1859 pSubStream = pSSF.Detach();
1863 if(pSubStream)
1865 m_pSubStreams.AddTail(pSubStream);
1866 m_fIsSubStreamEmbeded.AddTail(false);
1867 m_frd.files.AddTail(ret[i].fn);
1871 for(int i = 0; i < m_pTextInput.GetCount(); i++)
1873 if(m_pTextInput[i]->IsConnected())
1875 m_pSubStreams.AddTail(m_pTextInput[i]->GetSubStream());
1876 m_fIsSubStreamEmbeded.AddTail(true);
1880 if(S_FALSE == put_SelectedLanguage(FindPreferedLanguage()))
1881 UpdateSubtitle(false); // make sure pSubPicProvider of our queue gets updated even if the stream number hasn't changed
1883 m_frd.RefreshEvent.Set();
1885 return(m_pSubStreams.GetCount() > 0);
1888 void CDirectVobSubFilter::UpdateSubtitle(bool fApplyDefStyle)
1890 CAutoLock cAutolock(&m_csQueueLock);
1892 if(!m_pSubPicQueue) return;
1894 InvalidateSubtitle();
1896 CComPtr<ISubStream> pSubStream;
1898 if(!m_fHideSubtitles)
1900 int i = m_iSelectedLanguage;
1902 for(POSITION pos = m_pSubStreams.GetHeadPosition(); i >= 0 && pos; pSubStream = NULL)
1904 pSubStream = m_pSubStreams.GetNext(pos);
1906 if(i < pSubStream->GetStreamCount())
1908 CAutoLock cAutoLock(&m_csSubLock);
1909 pSubStream->SetStream(i);
1910 break;
1913 i -= pSubStream->GetStreamCount();
1917 SetSubtitle(pSubStream, fApplyDefStyle);
1920 void CDirectVobSubFilter::SetSubtitle(ISubStream* pSubStream, bool fApplyDefStyle)
1922 DbgLog((LOG_TRACE, 3, "%s(%d): %s", __FILE__, __LINE__, __FUNCTION__));
1923 DbgLog((LOG_TRACE, 3, "\tpSubStream:%x fApplyDefStyle:%d", pSubStream, (int)fApplyDefStyle));
1924 CAutoLock cAutolock(&m_csQueueLock);
1926 if(pSubStream)
1928 CAutoLock cAutolock(&m_csSubLock);
1930 CLSID clsid;
1931 pSubStream->GetClassID(&clsid);
1933 if(clsid == __uuidof(CVobSubFile))
1935 CVobSubSettings* pVSS = dynamic_cast<CVobSubFile*>(pSubStream);
1937 if(fApplyDefStyle)
1939 pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
1940 pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
1943 else if(clsid == __uuidof(CVobSubStream))
1945 CVobSubSettings* pVSS = dynamic_cast<CVobSubStream*>(pSubStream);
1947 if(fApplyDefStyle)
1949 pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
1950 pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
1953 else if(clsid == __uuidof(CRenderedTextSubtitle))
1955 CRenderedTextSubtitle* pRTS = dynamic_cast<CRenderedTextSubtitle*>(pSubStream);
1957 if(fApplyDefStyle || pRTS->m_fUsingAutoGeneratedDefaultStyle)
1959 STSStyle s = m_defStyle;
1961 if(m_fOverridePlacement)
1963 s.scrAlignment = 2;
1964 int w = pRTS->m_dstScreenSize.cx;
1965 int h = pRTS->m_dstScreenSize.cy;
1966 CRect tmp_rect = s.marginRect.get();
1967 int mw = w - tmp_rect.left - tmp_rect.right;
1968 tmp_rect.bottom = h - MulDiv(h, m_PlacementYperc, 100);
1969 tmp_rect.left = MulDiv(w, m_PlacementXperc, 100) - mw/2;
1970 tmp_rect.right = w - (tmp_rect.left + mw);
1971 s.marginRect = tmp_rect;
1974 pRTS->SetDefaultStyle(s);
1977 pRTS->m_ePARCompensationType = m_ePARCompensationType;
1978 if (m_CurrentVIH2.dwPictAspectRatioX != 0 && m_CurrentVIH2.dwPictAspectRatioY != 0&& m_CurrentVIH2.bmiHeader.biWidth != 0 && m_CurrentVIH2.bmiHeader.biHeight != 0)
1980 pRTS->m_dPARCompensation = ((double)abs(m_CurrentVIH2.bmiHeader.biWidth) / (double)abs(m_CurrentVIH2.bmiHeader.biHeight)) /
1981 ((double)abs((long)m_CurrentVIH2.dwPictAspectRatioX) / (double)abs((long)m_CurrentVIH2.dwPictAspectRatioY));
1984 else
1986 pRTS->m_dPARCompensation = 1.00;
1989 pRTS->Deinit();
1993 if(!fApplyDefStyle)
1995 int i = 0;
1997 POSITION pos = m_pSubStreams.GetHeadPosition();
1998 while(pos)
2000 CComPtr<ISubStream> pSubStream2 = m_pSubStreams.GetNext(pos);
2002 if(pSubStream == pSubStream2)
2004 m_iSelectedLanguage = i + pSubStream2->GetStream();
2005 break;
2008 i += pSubStream2->GetStreamCount();
2012 m_nSubtitleId = reinterpret_cast<DWORD_PTR>(pSubStream);
2014 if(m_pSubPicQueue)
2015 m_pSubPicQueue->SetSubPicProviderEx(CComQIPtr<ISubPicProviderEx>(pSubStream));
2018 void CDirectVobSubFilter::InvalidateSubtitle(REFERENCE_TIME rtInvalidate, DWORD_PTR nSubtitleId)
2020 CAutoLock cAutolock(&m_csQueueLock);
2022 if(m_pSubPicQueue)
2024 if(nSubtitleId == -1 || nSubtitleId == m_nSubtitleId)
2026 DbgLog((LOG_TRACE, 3, "InvalidateSubtitle::Invalidate"));
2027 m_pSubPicQueue->Invalidate(rtInvalidate);
2032 //////////////////////////////////////////////////////////////////////////////////////////
2034 void CDirectVobSubFilter::AddSubStream(ISubStream* pSubStream)
2036 CAutoLock cAutoLock(&m_csQueueLock);
2038 POSITION pos = m_pSubStreams.Find(pSubStream);
2039 if(!pos)
2041 m_pSubStreams.AddTail(pSubStream);
2042 m_fIsSubStreamEmbeded.AddTail(true);//todo: fix me
2045 int len = m_pTextInput.GetCount();
2046 for(int i = 0; i < m_pTextInput.GetCount(); i++)
2047 if(m_pTextInput[i]->IsConnected()) len--;
2049 if(len == 0)
2051 HRESULT hr = S_OK;
2052 m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
2056 void CDirectVobSubFilter::RemoveSubStream(ISubStream* pSubStream)
2058 CAutoLock cAutoLock(&m_csQueueLock);
2060 POSITION pos = m_pSubStreams.GetHeadPosition();
2061 POSITION pos2 = m_fIsSubStreamEmbeded.GetHeadPosition();
2062 while(pos!=NULL)
2064 if( m_pSubStreams.GetAt(pos)==pSubStream )
2066 m_pSubStreams.RemoveAt(pos);
2067 m_fIsSubStreamEmbeded.RemoveAt(pos2);
2068 break;
2070 else
2072 m_pSubStreams.GetNext(pos);
2073 m_fIsSubStreamEmbeded.GetNext(pos2);
2078 void CDirectVobSubFilter::Post_EC_OLE_EVENT(CString str, DWORD_PTR nSubtitleId)
2080 if(nSubtitleId != -1 && nSubtitleId != m_nSubtitleId)
2081 return;
2083 CComQIPtr<IMediaEventSink> pMES = m_pGraph;
2084 if(!pMES) return;
2086 CComBSTR bstr1("Text"), bstr2(" ");
2088 str.Trim();
2089 if(!str.IsEmpty()) bstr2 = CStringA(str);
2091 pMES->Notify(EC_OLE_EVENT, (LONG_PTR)bstr1.Detach(), (LONG_PTR)bstr2.Detach());
2094 ////////////////////////////////////////////////////////////////
2096 void CDirectVobSubFilter::SetupFRD(CStringArray& paths, CAtlArray<HANDLE>& handles)
2098 CAutoLock cAutolock(&m_csSubLock);
2100 for(int i = 2; i < handles.GetCount(); i++)
2102 FindCloseChangeNotification(handles[i]);
2105 paths.RemoveAll();
2106 handles.RemoveAll();
2108 handles.Add(m_frd.EndThreadEvent);
2109 handles.Add(m_frd.RefreshEvent);
2111 m_frd.mtime.SetCount(m_frd.files.GetCount());
2113 POSITION pos = m_frd.files.GetHeadPosition();
2114 for(int i = 0; pos; i++)
2116 CString fn = m_frd.files.GetNext(pos);
2118 CFileStatus status;
2119 if(CFileGetStatus(fn, status))
2120 m_frd.mtime[i] = status.m_mtime;
2122 fn.Replace('\\', '/');
2123 fn = fn.Left(fn.ReverseFind('/')+1);
2125 bool fFound = false;
2127 for(int j = 0; !fFound && j < paths.GetCount(); j++)
2129 if(paths[j] == fn) fFound = true;
2132 if(!fFound)
2134 paths.Add(fn);
2136 HANDLE h = FindFirstChangeNotification(fn, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
2137 if(h != INVALID_HANDLE_VALUE) handles.Add(h);
2142 DWORD CDirectVobSubFilter::ThreadProc()
2144 SetThreadPriority(m_hThread, THREAD_PRIORITY_LOWEST/*THREAD_PRIORITY_BELOW_NORMAL*/);
2146 CStringArray paths;
2147 CAtlArray<HANDLE> handles;
2149 SetupFRD(paths, handles);
2151 while(1)
2153 DWORD idx = WaitForMultipleObjects(handles.GetCount(), handles.GetData(), FALSE, INFINITE);
2155 if(idx == (WAIT_OBJECT_0 + 0)) // m_frd.hEndThreadEvent
2157 break;
2159 if(idx == (WAIT_OBJECT_0 + 1)) // m_frd.hRefreshEvent
2161 SetupFRD(paths, handles);
2163 else if(idx >= (WAIT_OBJECT_0 + 2) && idx < (WAIT_OBJECT_0 + handles.GetCount()))
2165 bool fLocked = true;
2166 IsSubtitleReloaderLocked(&fLocked);
2167 if(fLocked) continue;
2169 if(FindNextChangeNotification(handles[idx - WAIT_OBJECT_0]) == FALSE)
2170 break;
2172 int j = 0;
2174 POSITION pos = m_frd.files.GetHeadPosition();
2175 for(int i = 0; pos && j == 0; i++)
2177 CString fn = m_frd.files.GetNext(pos);
2179 CFileStatus status;
2180 if(CFileGetStatus(fn, status) && m_frd.mtime[i] != status.m_mtime)
2182 for(j = 0; j < 10; j++)
2184 if(FILE* f = _tfopen(fn, _T("rb+")))
2186 fclose(f);
2187 j = 0;
2188 break;
2190 else
2192 Sleep(100);
2193 j++;
2199 if(j > 0)
2201 SetupFRD(paths, handles);
2203 else
2205 Sleep(500);
2207 POSITION pos = m_frd.files.GetHeadPosition();
2208 for(int i = 0; pos; i++)
2210 CFileStatus status;
2211 if(CFileGetStatus(m_frd.files.GetNext(pos), status)
2212 && m_frd.mtime[i] != status.m_mtime)
2214 Open();
2215 SetupFRD(paths, handles);
2216 break;
2221 else
2223 break;
2227 for(int i = 2; i < handles.GetCount(); i++)
2229 FindCloseChangeNotification(handles[i]);
2232 return 0;
2235 void CDirectVobSubFilter::GetInputColorspaces( ColorSpaceId *preferredOrder, UINT *count )
2237 ColorSpaceId colorspace[MAX_COLOR_SPACE_NUM];
2238 bool selected[MAX_COLOR_SPACE_NUM];
2239 UINT tempCount;
2240 if( get_InputColorFormat(colorspace, selected, &tempCount)==S_OK )
2242 *count = 0;
2243 for (int i=0;i<tempCount;i++)
2245 if(selected[i])
2247 preferredOrder[*count] = colorspace[i];
2248 (*count)++;
2252 else
2254 CBaseVideoFilter::GetInputColorspaces(preferredOrder, count);
2258 void CDirectVobSubFilter::GetOutputColorspaces( ColorSpaceId *preferredOrder, UINT *count )
2260 ColorSpaceId colorspace[MAX_COLOR_SPACE_NUM];
2261 bool selected[MAX_COLOR_SPACE_NUM];
2262 UINT tempCount;
2263 if( get_OutputColorFormat(colorspace, selected, &tempCount)==S_OK )
2265 *count = 0;
2266 for (int i=0;i<tempCount;i++)
2268 if(selected[i])
2270 preferredOrder[*count] = colorspace[i];
2271 (*count)++;
2275 else
2277 CBaseVideoFilter::GetInputColorspaces(preferredOrder, count);
2281 HRESULT CDirectVobSubFilter::GetIsEmbeddedSubStream( int iSelected, bool *fIsEmbedded )
2283 CAutoLock cAutolock(&m_csQueueLock);
2285 HRESULT hr = E_INVALIDARG;
2286 if (!fIsEmbedded)
2288 return S_FALSE;
2291 int i = iSelected;
2292 *fIsEmbedded = false;
2294 POSITION pos = m_pSubStreams.GetHeadPosition();
2295 POSITION pos2 = m_fIsSubStreamEmbeded.GetHeadPosition();
2296 while(i >= 0 && pos)
2298 CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
2299 bool isEmbedded = m_fIsSubStreamEmbeded.GetNext(pos2);
2300 if(i < pSubStream->GetStreamCount())
2302 hr = NOERROR;
2303 *fIsEmbedded = isEmbedded;
2304 break;
2307 i -= pSubStream->GetStreamCount();
2309 return hr;