00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "stdafx.h"
00023 #include <math.h>
00024 #include <time.h>
00025 #include "DirectVobSubFilter.h"
00026 #include "TextInputPin.h"
00027 #include "DirectVobSubPropPage.h"
00028 #include "VSFilter.h"
00029 #include "systray.h"
00030 #include "..\..\..\DSUtil\MediaTypes.h"
00031 #include "..\..\..\SubPic\MemSubPic.h"
00032
00033 #include <initguid.h>
00034 #include "..\..\..\..\include\moreuuids.h"
00035 #include "..\..\..\..\include\Ogg\OggDS.h"
00036
00038
00039
00040 bool g_RegOK = true;
00041 #include "valami.cpp"
00042
00044
00045
00046
00047
00048 CDirectVobSubFilter::CDirectVobSubFilter(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid)
00049 : CBaseVideoFilter(NAME("CDirectVobSubFilter"), punk, phr, clsid)
00050 , m_nSubtitleId(-1)
00051 , m_fMSMpeg4Fix(false)
00052 , m_fDivxPlusFix(false)
00053 , m_fps(25)
00054 {
00055 AFX_MANAGE_STATE(AfxGetStaticModuleState());
00056
00057 m_hdc = 0;
00058 m_hbm = 0;
00059 m_hfont = 0;
00060
00061 {
00062 LOGFONT lf;
00063 memset(&lf, 0, sizeof(lf));
00064 lf.lfCharSet = DEFAULT_CHARSET;
00065 lf.lfOutPrecision = OUT_CHARACTER_PRECIS;
00066 lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
00067 lf.lfQuality = ANTIALIASED_QUALITY;
00068 HDC hdc = GetDC(NULL);
00069 lf.lfHeight = -MulDiv(10, GetDeviceCaps(hdc, LOGPIXELSY), 72);
00070 ReleaseDC(NULL, hdc);
00071 lf.lfWeight = FW_BOLD;
00072 _tcscpy(lf.lfFaceName, _T("Arial"));
00073 m_hfont = CreateFontIndirect(&lf);
00074 }
00075
00076 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Hint"), _T("The first three are fixed, but you can add more up to ten entries."));
00077 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path0"), _T("."));
00078 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path1"), _T("c:\\subtitles"));
00079 theApp.WriteProfileString(ResStr(IDS_R_DEFTEXTPATHES), _T("Path2"), _T(".\\subtitles"));
00080
00081 m_fLoading = true;
00082
00083 m_hSystrayThread = 0;
00084 m_tbid.hSystrayWnd = NULL;
00085 m_tbid.graph = NULL;
00086 m_tbid.fRunOnce = false;
00087 m_tbid.fShowIcon = (theApp.m_AppName.Find(_T("zplayer"), 0) < 0 || !!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_ENABLEZPICON), 0));
00088
00089 HRESULT hr = S_OK;
00090 m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
00091 ASSERT(SUCCEEDED(hr));
00092
00093 CAMThread::Create();
00094 m_frd.EndThreadEvent.Create(0, FALSE, FALSE, 0);
00095 m_frd.RefreshEvent.Create(0, FALSE, FALSE, 0);
00096 }
00097
00098 CDirectVobSubFilter::~CDirectVobSubFilter()
00099 {
00100 CAutoLock cAutoLock(&m_csQueueLock);
00101 if(m_pSubPicQueue) m_pSubPicQueue->Invalidate();
00102 m_pSubPicQueue = NULL;
00103
00104 if(m_hfont) {DeleteObject(m_hfont); m_hfont = 0;}
00105 if(m_hbm) {DeleteObject(m_hbm); m_hbm = 0;}
00106 if(m_hdc) {DeleteObject(m_hdc); m_hdc = 0;}
00107
00108 for(int i = 0; i < m_pTextInput.GetSize(); i++)
00109 delete m_pTextInput[i];
00110
00111 m_frd.EndThreadEvent.Set();
00112 CAMThread::Close();
00113 }
00114
00115 STDMETHODIMP CDirectVobSubFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
00116 {
00117 CheckPointer(ppv, E_POINTER);
00118
00119 return
00120 QI(IDirectVobSub)
00121 QI(IDirectVobSub2)
00122 QI(IFilterVersion)
00123 QI(ISpecifyPropertyPages)
00124 QI(IAMStreamSelect)
00125 __super::NonDelegatingQueryInterface(riid, ppv);
00126 }
00127
00128
00129
00130 void CDirectVobSubFilter::GetOutputSize(int& w, int& h, int& arx, int& ary)
00131 {
00132 CSize s(w, h), os = s;
00133 AdjustFrameSize(s);
00134 w = s.cx;
00135 h = s.cy;
00136
00137 if(w != os.cx)
00138 {
00139 while(arx < 100) arx *= 10, ary *= 10;
00140 arx = arx * w / os.cx;
00141 }
00142
00143 if(h != os.cy)
00144 {
00145 while(ary < 100) arx *= 10, ary *= 10;
00146 ary = ary * h / os.cy;
00147 }
00148 }
00149
00150 HRESULT CDirectVobSubFilter::Transform(IMediaSample* pIn)
00151 {
00152 HRESULT hr;
00153
00154
00155 REFERENCE_TIME rtStart, rtStop;
00156 if(SUCCEEDED(pIn->GetTime(&rtStart, &rtStop)))
00157 {
00158 double dRate = m_pInput->CurrentRate();
00159
00160 m_tPrev = m_pInput->CurrentStartTime() + dRate*rtStart;
00161
00162 REFERENCE_TIME rtAvgTimePerFrame = rtStop - rtStart;
00163 if(CComQIPtr<ISubClock2> pSC2 = m_pSubClock)
00164 {
00165 REFERENCE_TIME rt;
00166 if(S_OK == pSC2->GetAvgTimePerFrame(&rt))
00167 rtAvgTimePerFrame = rt;
00168 }
00169
00170 m_fps = 10000000.0/rtAvgTimePerFrame / dRate;
00171 }
00172
00173
00174
00175 {
00176 CAutoLock cAutoLock(&m_csQueueLock);
00177
00178 if(m_pSubPicQueue)
00179 {
00180 m_pSubPicQueue->SetTime(CalcCurrentTime());
00181 m_pSubPicQueue->SetFPS(m_fps);
00182 }
00183 }
00184
00185
00186
00187 BYTE* pDataIn = NULL;
00188 if(FAILED(pIn->GetPointer(&pDataIn)) || !pDataIn)
00189 return S_FALSE;
00190
00191 const CMediaType& mt = m_pInput->CurrentMediaType();
00192
00193 BITMAPINFOHEADER bihIn;
00194 ExtractBIH(&mt, &bihIn);
00195
00196 bool fYV12 = (mt.subtype == MEDIASUBTYPE_YV12 || mt.subtype == MEDIASUBTYPE_I420 || mt.subtype == MEDIASUBTYPE_IYUV);
00197 int bpp = fYV12 ? 8 : bihIn.biBitCount;
00198 DWORD black = fYV12 ? 0x10101010 : (bihIn.biCompression == '2YUY') ? 0x80108010 : 0;
00199
00200 CSize sub(m_w, m_h);
00201 CSize in(bihIn.biWidth, bihIn.biHeight);
00202
00203 if(FAILED(Copy((BYTE*)m_pTempPicBuff, pDataIn, sub, in, bpp, mt.subtype, black)))
00204 return E_FAIL;
00205
00206 if(fYV12)
00207 {
00208 BYTE* pSubV = (BYTE*)m_pTempPicBuff + (sub.cx*bpp>>3)*sub.cy;
00209 BYTE* pInV = pDataIn + (in.cx*bpp>>3)*in.cy;
00210 sub.cx >>= 1; sub.cy >>= 1; in.cx >>= 1; in.cy >>= 1;
00211 BYTE* pSubU = pSubV + (sub.cx*bpp>>3)*sub.cy;
00212 BYTE* pInU = pInV + (in.cx*bpp>>3)*in.cy;
00213 if(FAILED(Copy(pSubV, pInV, sub, in, bpp, mt.subtype, 0x80808080)))
00214 return E_FAIL;
00215 if(FAILED(Copy(pSubU, pInU, sub, in, bpp, mt.subtype, 0x80808080)))
00216 return E_FAIL;
00217 }
00218
00219
00220
00221 SubPicDesc spd = m_spd;
00222
00223 CComPtr<IMediaSample> pOut;
00224 BYTE* pDataOut = NULL;
00225 if(FAILED(hr = GetDeliveryBuffer(spd.w, spd.h, &pOut))
00226 || FAILED(hr = pOut->GetPointer(&pDataOut)))
00227 return hr;
00228
00229 pOut->SetTime(&rtStart, &rtStop);
00230 pOut->SetMediaTime(NULL, NULL);
00231
00232
00233
00234 BITMAPINFOHEADER bihOut;
00235 ExtractBIH(&m_pOutput->CurrentMediaType(), &bihOut);
00236
00237 bool fInputFlipped = bihIn.biHeight >= 0 && bihIn.biCompression <= 3;
00238 bool fOutputFlipped = bihOut.biHeight >= 0 && bihOut.biCompression <= 3;
00239
00240 bool fFlip = fInputFlipped != fOutputFlipped;
00241 if(m_fFlipPicture) fFlip = !fFlip;
00242 if(m_fMSMpeg4Fix) fFlip = !fFlip;
00243
00244
00245 bool fFlipSub = fOutputFlipped;
00246 if(m_fFlipSubtitles) fFlipSub = !fFlipSub;
00247
00248
00249
00250
00251 {
00252 CAutoLock cAutoLock(&m_csQueueLock);
00253
00254 if(m_pSubPicQueue)
00255 {
00256 CComPtr<ISubPic> pSubPic;
00257 if(SUCCEEDED(m_pSubPicQueue->LookupSubPic(CalcCurrentTime(), &pSubPic)) && pSubPic)
00258 {
00259 CRect r;
00260 pSubPic->GetDirtyRect(r);
00261
00262 if(fFlip ^ fFlipSub)
00263 spd.h = -spd.h;
00264
00265 pSubPic->AlphaBlt(r, r, &spd);
00266 }
00267 }
00268 }
00269
00270 CopyBuffer(pDataOut, (BYTE*)spd.bits, spd.w, abs(spd.h)*(fFlip?-1:1), spd.pitch, mt.subtype);
00271
00272 PrintMessages(pDataOut);
00273
00274 return m_pOutput->Deliver(pOut);
00275 }
00276
00277
00278
00279 CBasePin* CDirectVobSubFilter::GetPin(int n)
00280 {
00281 if(n < __super::GetPinCount())
00282 return __super::GetPin(n);
00283
00284 n -= __super::GetPinCount();
00285
00286 if(n >= 0 && n < m_pTextInput.GetSize())
00287 return m_pTextInput[n];
00288
00289 n -= m_pTextInput.GetSize();
00290
00291 return NULL;
00292 }
00293
00294 int CDirectVobSubFilter::GetPinCount()
00295 {
00296 return __super::GetPinCount() + m_pTextInput.GetSize();
00297 }
00298
00299 HRESULT CDirectVobSubFilter::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
00300 {
00301 if(pGraph)
00302 {
00303 AFX_MANAGE_STATE(AfxGetStaticModuleState());
00304
00305 if(!theApp.GetProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 0))
00306 {
00307 unsigned __int64 ver = GetFileVersion(_T("divx_c32.ax"));
00308 if(((ver >> 48)&0xffff) == 4 && ((ver >> 32)&0xffff) == 2)
00309 {
00310 DWORD dwVersion = GetVersion();
00311 DWORD dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
00312 DWORD dwWindowsMinorVersion = (DWORD)(HIBYTE(LOWORD(dwVersion)));
00313
00314 if(dwVersion < 0x80000000 && dwWindowsMajorVersion >= 5)
00315 {
00316 AfxMessageBox(IDS_DIVX_WARNING);
00317 theApp.WriteProfileInt(ResStr(IDS_R_GENERAL), ResStr(IDS_RG_SEENDIVXWARNING), 1);
00318 }
00319 }
00320 }
00321
00322
00323 if(!g_RegOK)
00324 {
00325 DllRegisterServer();
00326 g_RegOK = true;
00327 }
00328 }
00329 else
00330 {
00331 if(m_hSystrayThread)
00332 {
00333 SendMessage(m_tbid.hSystrayWnd, WM_CLOSE, 0, 0);
00334
00335 if(WaitForSingleObject(m_hSystrayThread, 10000) != WAIT_OBJECT_0)
00336 {
00337 DbgLog((LOG_TRACE, 0, _T("CALL THE AMBULANCE!!!")));
00338 TerminateThread(m_hSystrayThread, (DWORD)-1);
00339 }
00340
00341 m_hSystrayThread = 0;
00342 }
00343 }
00344
00345 return __super::JoinFilterGraph(pGraph, pName);
00346 }
00347
00348 STDMETHODIMP CDirectVobSubFilter::QueryFilterInfo(FILTER_INFO* pInfo)
00349 {
00350 CheckPointer(pInfo, E_POINTER);
00351 ValidateReadWritePtr(pInfo, sizeof(FILTER_INFO));
00352
00353 if(!get_Forced())
00354 return __super::QueryFilterInfo(pInfo);
00355
00356 wcscpy(pInfo->achName, L"DirectVobSub (forced auto-loading version)");
00357 if(pInfo->pGraph = m_pGraph) m_pGraph->AddRef();
00358
00359 return S_OK;
00360 }
00361
00362
00363
00364 HRESULT CDirectVobSubFilter::SetMediaType(PIN_DIRECTION dir, const CMediaType* pmt)
00365 {
00366 HRESULT hr = __super::SetMediaType(dir, pmt);
00367 if(FAILED(hr)) return hr;
00368
00369 if(dir == PINDIR_INPUT)
00370 {
00371 CAutoLock cAutoLock(&m_csReceive);
00372
00373 REFERENCE_TIME atpf =
00374 pmt->formattype == FORMAT_VideoInfo ? ((VIDEOINFOHEADER*)pmt->Format())->AvgTimePerFrame :
00375 pmt->formattype == FORMAT_VideoInfo2 ? ((VIDEOINFOHEADER2*)pmt->Format())->AvgTimePerFrame :
00376 0;
00377
00378 m_fps = atpf ? 10000000.0 / atpf : 25;
00379
00380 InitSubPicQueue();
00381 }
00382 else if(dir == PINDIR_OUTPUT)
00383 {
00384
00385 }
00386
00387 return hr;
00388 }
00389
00390 HRESULT CDirectVobSubFilter::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
00391 {
00392 if(dir == PINDIR_INPUT)
00393 {
00394 }
00395 else if(dir == PINDIR_OUTPUT)
00396 {
00397
00398 if(HmGyanusVagyTeNekem(pPin)) return(E_FAIL);
00399 }
00400
00401 return __super::CheckConnect(dir, pPin);
00402 }
00403
00404 HRESULT CDirectVobSubFilter::CompleteConnect(PIN_DIRECTION dir, IPin* pReceivePin)
00405 {
00406 if(dir == PINDIR_INPUT)
00407 {
00408 CComPtr<IBaseFilter> pFilter;
00409
00410
00411 if(SUCCEEDED(m_pGraph->FindFilterByName(L"DivX MPEG-4 DVD Video Decompressor ", &pFilter))
00412 && (GetFileVersion(_T("divx_c32.ax")) >> 48) <= 4
00413 || SUCCEEDED(m_pGraph->FindFilterByName(L"Microcrap MPEG-4 Video Decompressor", &pFilter))
00414 || SUCCEEDED(m_pGraph->FindFilterByName(L"Microsoft MPEG-4 Video Decompressor", &pFilter))
00415 && (GetFileVersion(_T("mpg4ds32.ax")) >> 48) <= 3)
00416 {
00417 m_fMSMpeg4Fix = true;
00418 }
00419 }
00420 else if(dir == PINDIR_OUTPUT)
00421 {
00422 if(!m_hSystrayThread)
00423 {
00424 m_tbid.graph = m_pGraph;
00425 m_tbid.dvs = static_cast<IDirectVobSub*>(this);
00426
00427 DWORD tid;
00428 m_hSystrayThread = CreateThread(0, 0, SystrayThreadProc, &m_tbid, 0, &tid);
00429 }
00430
00431
00432 m_pInput->SetMediaType(&m_pInput->CurrentMediaType());
00433 }
00434
00435 return __super::CompleteConnect(dir, pReceivePin);
00436 }
00437
00438 HRESULT CDirectVobSubFilter::BreakConnect(PIN_DIRECTION dir)
00439 {
00440 if(dir == PINDIR_INPUT)
00441 {
00442 if(m_pOutput->IsConnected())
00443 {
00444 m_pOutput->GetConnected()->Disconnect();
00445 m_pOutput->Disconnect();
00446 }
00447 }
00448 else if(dir == PINDIR_OUTPUT)
00449 {
00450
00451 CAutoLock cAutoLock(&m_csQueueLock);
00452 m_pSubPicQueue = NULL;
00453 }
00454
00455 return __super::BreakConnect(dir);
00456 }
00457
00458 HRESULT CDirectVobSubFilter::StartStreaming()
00459 {
00460 m_fLoading = false;
00461
00462 InitSubPicQueue();
00463
00464 m_tbid.fRunOnce = true;
00465
00466 CComPtr<IBaseFilter> pFilter;
00467 m_fDivxPlusFix = SUCCEEDED(m_pGraph->FindFilterByName(L"HPlus YUV Video Renderer", &pFilter));
00468
00469 put_MediaFPS(m_fMediaFPSEnabled, m_MediaFPS);
00470
00471 return __super::StartStreaming();
00472 }
00473
00474 HRESULT CDirectVobSubFilter::StopStreaming()
00475 {
00476 InvalidateSubtitle();
00477
00478 return __super::StopStreaming();
00479 }
00480
00481 HRESULT CDirectVobSubFilter::NewSegment(REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
00482 {
00483 m_tPrev = tStart;
00484 return __super::NewSegment(tStart, tStop, dRate);
00485 }
00486
00487
00488
00489 REFERENCE_TIME CDirectVobSubFilter::CalcCurrentTime()
00490 {
00491 REFERENCE_TIME rt = m_pSubClock ? m_pSubClock->GetTime() : m_tPrev;
00492 return (rt - 10000i64*m_SubtitleDelay) * m_SubtitleSpeedMul / m_SubtitleSpeedDiv;
00493 }
00494
00495 void CDirectVobSubFilter::InitSubPicQueue()
00496 {
00497 CAutoLock cAutoLock(&m_csQueueLock);
00498
00499 m_pSubPicQueue = NULL;
00500
00501 m_pTempPicBuff.Free();
00502 m_pTempPicBuff.Allocate(4*m_w*m_h);
00503
00504 const GUID& subtype = m_pInput->CurrentMediaType().subtype;
00505
00506 BITMAPINFOHEADER bihIn;
00507 ExtractBIH(&m_pInput->CurrentMediaType(), &bihIn);
00508
00509 m_spd.type = -1;
00510 if(subtype == MEDIASUBTYPE_YV12) m_spd.type = MSP_YV12;
00511 else if(subtype == MEDIASUBTYPE_I420 || subtype == MEDIASUBTYPE_IYUV) m_spd.type = MSP_IYUV;
00512 else if(subtype == MEDIASUBTYPE_YUY2) m_spd.type = MSP_YUY2;
00513 else if(subtype == MEDIASUBTYPE_RGB32) m_spd.type = MSP_RGB32;
00514 else if(subtype == MEDIASUBTYPE_RGB24) m_spd.type = MSP_RGB24;
00515 else if(subtype == MEDIASUBTYPE_RGB565) m_spd.type = MSP_RGB16;
00516 else if(subtype == MEDIASUBTYPE_RGB555) m_spd.type = MSP_RGB15;
00517 m_spd.w = m_w;
00518 m_spd.h = m_h;
00519 m_spd.bpp = (m_spd.type == MSP_YV12 || m_spd.type == MSP_IYUV) ? 8 : bihIn.biBitCount;
00520 m_spd.pitch = m_spd.w*m_spd.bpp>>3;
00521 m_spd.bits = (void*)m_pTempPicBuff;
00522
00523 CComPtr<ISubPicAllocator> pSubPicAllocator = new CMemSubPicAllocator(m_spd.type, CSize(m_w, m_h));
00524
00525 CSize video(bihIn.biWidth, bihIn.biHeight);
00526 CSize window(m_w, m_h);
00527 if(AdjustFrameSize(window)) video += video;
00528 pSubPicAllocator->SetCurSize(window);
00529 pSubPicAllocator->SetCurVidRect(CRect(CPoint((window.cx - video.cx)/2, (window.cy - video.cy)/2), video));
00530
00531 HRESULT hr = S_OK;
00532 m_pSubPicQueue = m_fDoPreBuffering
00533 ? (ISubPicQueue*)new CSubPicQueue(10, pSubPicAllocator, &hr)
00534 : (ISubPicQueue*)new CSubPicQueueNoThread(pSubPicAllocator, &hr);
00535
00536 if(FAILED(hr)) m_pSubPicQueue = NULL;
00537
00538 UpdateSubtitle(false);
00539
00540 if(m_hbm) {DeleteObject(m_hbm); m_hbm = NULL;}
00541 if(m_hdc) {DeleteDC(m_hdc); m_hdc = NULL;}
00542
00543 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};
00544 m_hdc = CreateCompatibleDC(NULL);
00545 m_hbm = CreateDIBSection(m_hdc, (BITMAPINFO*)&b, DIB_RGB_COLORS, NULL, NULL, 0);
00546
00547 BITMAP bm;
00548 GetObject(m_hbm, sizeof(bm), &bm);
00549 memsetd(bm.bmBits, 0xFF000000, bm.bmHeight*bm.bmWidthBytes);
00550 }
00551
00552 bool CDirectVobSubFilter::AdjustFrameSize(CSize& s)
00553 {
00554 int horizontal, vertical, resx2, resx2minw, resx2minh;
00555 get_ExtendPicture(&horizontal, &vertical, &resx2, &resx2minw, &resx2minh);
00556
00557 bool fRet;
00558 if(fRet = (resx2 == 1) || (resx2 == 2 && s.cx*s.cy <= resx2minw*resx2minh))
00559 {
00560 s.cx <<= 1;
00561 s.cy <<= 1;
00562 }
00563
00564 int h;
00565 switch(vertical&0x7f)
00566 {
00567 case 1:
00568 h = s.cx * 9 / 16;
00569 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
00570 break;
00571 case 2:
00572 h = s.cx * 3 / 4;
00573 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
00574 break;
00575 case 3:
00576 h = 480;
00577 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
00578 break;
00579 case 4:
00580 h = 576;
00581 if(s.cy < h || !!(vertical&0x80)) s.cy = (h + 3) & ~3;
00582 break;
00583 }
00584
00585 if(horizontal == 1)
00586 {
00587 s.cx = (s.cx + 31) & ~31;
00588 s.cy = (s.cy + 1) & ~1;
00589 }
00590
00591 return(fRet);
00592 }
00593
00594 STDMETHODIMP CDirectVobSubFilter::Count(DWORD* pcStreams)
00595 {
00596 if(!pcStreams) return E_POINTER;
00597
00598 *pcStreams = 0;
00599
00600 int nLangs = 0;
00601 if(SUCCEEDED(get_LanguageCount(&nLangs)))
00602 (*pcStreams) += nLangs;
00603
00604 (*pcStreams) += 2;
00605
00606 (*pcStreams) += 2;
00607
00608 return S_OK;
00609 }
00610
00611 #define MAXPREFLANGS 5
00612
00613 int CDirectVobSubFilter::FindPreferedLanguage(bool fHideToo)
00614 {
00615 AFX_MANAGE_STATE(AfxGetStaticModuleState());
00616
00617 int nLangs;
00618 get_LanguageCount(&nLangs);
00619
00620 if(nLangs <= 0) return(0);
00621
00622 for(int i = 0; i < MAXPREFLANGS; i++)
00623 {
00624 CString tmp;
00625 tmp.Format(IDS_RL_LANG, i);
00626
00627 CString lang = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
00628
00629 if(!lang.IsEmpty())
00630 {
00631 for(int ret = 0; ret < nLangs; ret++)
00632 {
00633 CString l;
00634 WCHAR* pName = NULL;
00635 get_LanguageName(ret, &pName);
00636 l = pName;
00637 CoTaskMemFree(pName);
00638
00639 if(!l.CompareNoCase(lang)) return(ret);
00640 }
00641 }
00642 }
00643
00644 return(0);
00645 }
00646
00647 void CDirectVobSubFilter::UpdatePreferedLanguages(CString l)
00648 {
00649 AFX_MANAGE_STATE(AfxGetStaticModuleState());
00650
00651 CString langs[MAXPREFLANGS+1];
00652
00653 int i = 0, j = 0, k = -1;
00654 for(; i < MAXPREFLANGS; i++)
00655 {
00656 CString tmp;
00657 tmp.Format(IDS_RL_LANG, i);
00658
00659 langs[j] = theApp.GetProfileString(ResStr(IDS_R_PREFLANGS), tmp);
00660
00661 if(!langs[j].IsEmpty())
00662 {
00663 if(!langs[j].CompareNoCase(l)) k = j;
00664 j++;
00665 }
00666 }
00667
00668 if(k == -1)
00669 {
00670 langs[k = j] = l;
00671 j++;
00672 }
00673
00674
00675
00676 while(k > 0)
00677 {
00678 CString tmp = langs[k]; langs[k] = langs[k-1]; langs[k-1] = tmp;
00679 k--;
00680 }
00681
00682
00683
00684 CString hidesubs;
00685 hidesubs.LoadString(IDS_M_HIDESUBTITLES);
00686
00687 for(k = 1; k < j; k++)
00688 {
00689 if(!langs[k].CompareNoCase(hidesubs)) break;
00690 }
00691
00692 while(k < j-1)
00693 {
00694 CString tmp = langs[k]; langs[k] = langs[k+1]; langs[k+1] = tmp;
00695 k++;
00696 }
00697
00698 for(i = 0; i < j; i++)
00699 {
00700 CString tmp;
00701 tmp.Format(IDS_RL_LANG, i);
00702
00703 theApp.WriteProfileString(ResStr(IDS_R_PREFLANGS), tmp, langs[i]);
00704 }
00705 }
00706
00707 STDMETHODIMP CDirectVobSubFilter::Enable(long lIndex, DWORD dwFlags)
00708 {
00709 if(!(dwFlags & AMSTREAMSELECTENABLE_ENABLE))
00710 return E_NOTIMPL;
00711
00712 int nLangs = 0;
00713 get_LanguageCount(&nLangs);
00714
00715 if(!(lIndex >= 0 && lIndex < nLangs+2+2))
00716 return E_INVALIDARG;
00717
00718 int i = lIndex-1;
00719
00720 if(i == -1 && !m_fLoading)
00721 {
00722 put_HideSubtitles(false);
00723 }
00724 else if(i >= 0 && i < nLangs)
00725 {
00726 put_HideSubtitles(false);
00727 put_SelectedLanguage(i);
00728
00729 WCHAR* pName = NULL;
00730 if(SUCCEEDED(get_LanguageName(i, &pName)))
00731 {
00732 UpdatePreferedLanguages(CString(pName));
00733 if(pName) CoTaskMemFree(pName);
00734 }
00735 }
00736 else if(i == nLangs && !m_fLoading)
00737 {
00738 put_HideSubtitles(true);
00739 }
00740 else if((i == nLangs+1 || i == nLangs+2) && !m_fLoading)
00741 {
00742 put_Flip(i == nLangs+2, m_fFlipSubtitles);
00743 }
00744
00745 return S_OK;
00746 }
00747
00748 STDMETHODIMP CDirectVobSubFilter::Info(long lIndex, AM_MEDIA_TYPE** ppmt, DWORD* pdwFlags, LCID* plcid, DWORD* pdwGroup, WCHAR** ppszName, IUnknown** ppObject, IUnknown** ppUnk)
00749 {
00750 AFX_MANAGE_STATE(AfxGetStaticModuleState());
00751
00752 int nLangs = 0;
00753 get_LanguageCount(&nLangs);
00754
00755 if(!(lIndex >= 0 && lIndex < nLangs+2+2))
00756 return E_INVALIDARG;
00757
00758 int i = lIndex-1;
00759
00760 if(ppmt) *ppmt = CreateMediaType(&m_pInput->CurrentMediaType());
00761
00762 if(pdwFlags)
00763 {
00764 *pdwFlags = 0;
00765
00766 if(i == -1 && !m_fHideSubtitles
00767 || i >= 0 && i < nLangs && i == m_iSelectedLanguage
00768 || i == nLangs && m_fHideSubtitles
00769 || i == nLangs+1 && !m_fFlipPicture
00770 || i == nLangs+2 && m_fFlipPicture)
00771 {
00772 *pdwFlags |= AMSTREAMSELECTINFO_ENABLED;
00773 }
00774 }
00775
00776 if(plcid) *plcid = 0;
00777
00778 if(pdwGroup) *pdwGroup = 0x648E51;
00779
00780 if(ppszName)
00781 {
00782 *ppszName = NULL;
00783
00784 CStringW str;
00785 if(i == -1) str = ResStr(IDS_M_SHOWSUBTITLES);
00786 else if(i >= 0 && i < nLangs) get_LanguageName(i, ppszName);
00787 else if(i == nLangs) str = ResStr(IDS_M_HIDESUBTITLES);
00788 else if(i == nLangs+1) {str = ResStr(IDS_M_ORIGINALPICTURE); if(pdwGroup) (*pdwGroup)++;}
00789 else if(i == nLangs+2) {str = ResStr(IDS_M_FLIPPEDPICTURE); if(pdwGroup) (*pdwGroup)++;}
00790
00791 if(!str.IsEmpty())
00792 {
00793 *ppszName = (WCHAR*)CoTaskMemAlloc((str.GetLength()+1)*sizeof(WCHAR));
00794 if(*ppszName == NULL) return S_FALSE;
00795 wcscpy(*ppszName, str);
00796 }
00797 }
00798
00799 if(ppObject) *ppObject = NULL;
00800
00801 if(ppUnk) *ppUnk = NULL;
00802
00803 return S_OK;
00804 }
00805
00806 STDMETHODIMP CDirectVobSubFilter::GetClassID(CLSID* pClsid)
00807 {
00808 if(pClsid == NULL) return E_POINTER;
00809 *pClsid = m_clsid;
00810 return NOERROR;
00811 }
00812
00813 STDMETHODIMP CDirectVobSubFilter::GetPages(CAUUID* pPages)
00814 {
00815 CheckPointer(pPages, E_POINTER);
00816
00817 pPages->cElems = 7;
00818 pPages->pElems = (GUID*)CoTaskMemAlloc(sizeof(GUID)*pPages->cElems);
00819
00820 if(pPages->pElems == NULL) return E_OUTOFMEMORY;
00821
00822 int i = 0;
00823 pPages->pElems[i++] = __uuidof(CDVSMainPPage);
00824 pPages->pElems[i++] = __uuidof(CDVSGeneralPPage);
00825 pPages->pElems[i++] = __uuidof(CDVSMiscPPage);
00826 pPages->pElems[i++] = __uuidof(CDVSTimingPPage);
00827 pPages->pElems[i++] = __uuidof(CDVSColorPPage);
00828 pPages->pElems[i++] = __uuidof(CDVSPathsPPage);
00829 pPages->pElems[i++] = __uuidof(CDVSAboutPPage);
00830
00831 return NOERROR;
00832 }
00833
00834
00835
00836 STDMETHODIMP CDirectVobSubFilter::put_FileName(WCHAR* fn)
00837 {
00838 HRESULT hr = CDirectVobSub::put_FileName(fn);
00839
00840 if(hr == S_OK && !Open())
00841 {
00842 m_FileName.Empty();
00843 hr = E_FAIL;
00844 }
00845
00846 return hr;
00847 }
00848
00849 STDMETHODIMP CDirectVobSubFilter::get_LanguageCount(int* nLangs)
00850 {
00851 HRESULT hr = CDirectVobSub::get_LanguageCount(nLangs);
00852
00853 if(hr == NOERROR && nLangs)
00854 {
00855 CAutoLock cAutolock(&m_csQueueLock);
00856
00857 *nLangs = 0;
00858 POSITION pos = m_pSubStreams.GetHeadPosition();
00859 while(pos) (*nLangs) += m_pSubStreams.GetNext(pos)->GetStreamCount();
00860 }
00861
00862 return hr;
00863 }
00864
00865 STDMETHODIMP CDirectVobSubFilter::get_LanguageName(int iLanguage, WCHAR** ppName)
00866 {
00867 HRESULT hr = CDirectVobSub::get_LanguageName(iLanguage, ppName);
00868
00869 if(!ppName) return E_POINTER;
00870
00871 if(hr == NOERROR)
00872 {
00873 CAutoLock cAutolock(&m_csQueueLock);
00874
00875 hr = E_INVALIDARG;
00876
00877 int i = iLanguage;
00878
00879 POSITION pos = m_pSubStreams.GetHeadPosition();
00880 while(i >= 0 && pos)
00881 {
00882 CComPtr<ISubStream> pSubStream = m_pSubStreams.GetNext(pos);
00883
00884 if(i < pSubStream->GetStreamCount())
00885 {
00886 pSubStream->GetStreamInfo(i, ppName, NULL);
00887 hr = NOERROR;
00888 break;
00889 }
00890
00891 i -= pSubStream->GetStreamCount();
00892 }
00893 }
00894
00895 return hr;
00896 }
00897
00898 STDMETHODIMP CDirectVobSubFilter::put_SelectedLanguage(int iSelected)
00899 {
00900 HRESULT hr = CDirectVobSub::put_SelectedLanguage(iSelected);
00901
00902 if(hr == NOERROR)
00903 {
00904 UpdateSubtitle(false);
00905 }
00906
00907 return hr;
00908 }
00909
00910 STDMETHODIMP CDirectVobSubFilter::put_HideSubtitles(bool fHideSubtitles)
00911 {
00912 HRESULT hr = CDirectVobSub::put_HideSubtitles(fHideSubtitles);
00913
00914 if(hr == NOERROR)
00915 {
00916 UpdateSubtitle(false);
00917 }
00918
00919 return hr;
00920 }
00921
00922 STDMETHODIMP CDirectVobSubFilter::put_PreBuffering(bool fDoPreBuffering)
00923 {
00924 HRESULT hr = CDirectVobSub::put_PreBuffering(fDoPreBuffering);
00925
00926 if(hr == NOERROR)
00927 {
00928 InitSubPicQueue();
00929 }
00930
00931 return hr;
00932 }
00933
00934 STDMETHODIMP CDirectVobSubFilter::put_Placement(bool fOverridePlacement, int xperc, int yperc)
00935 {
00936 HRESULT hr = CDirectVobSub::put_Placement(fOverridePlacement, xperc, yperc);
00937
00938 if(hr == NOERROR)
00939 {
00940 UpdateSubtitle(true);
00941 }
00942
00943 return hr;
00944 }
00945
00946 STDMETHODIMP CDirectVobSubFilter::put_VobSubSettings(bool fBuffer, bool fOnlyShowForcedSubs, bool fReserved)
00947 {
00948 HRESULT hr = CDirectVobSub::put_VobSubSettings(fBuffer, fOnlyShowForcedSubs, fReserved);
00949
00950 if(hr == NOERROR)
00951 {
00952
00953 InvalidateSubtitle();
00954 }
00955
00956 return hr;
00957 }
00958
00959 STDMETHODIMP CDirectVobSubFilter::put_TextSettings(void* lf, int lflen, COLORREF color, bool fShadow, bool fOutline, bool fAdvancedRenderer)
00960 {
00961 HRESULT hr = CDirectVobSub::put_TextSettings(lf, lflen, color, fShadow, fOutline, fAdvancedRenderer);
00962
00963 if(hr == NOERROR)
00964 {
00965
00966 InvalidateSubtitle();
00967 }
00968
00969 return hr;
00970 }
00971
00972 STDMETHODIMP CDirectVobSubFilter::put_SubtitleTiming(int delay, int speedmul, int speeddiv)
00973 {
00974 HRESULT hr = CDirectVobSub::put_SubtitleTiming(delay, speedmul, speeddiv);
00975
00976 if(hr == NOERROR)
00977 {
00978 InvalidateSubtitle();
00979 }
00980
00981 return hr;
00982 }
00983
00984 STDMETHODIMP CDirectVobSubFilter::get_MediaFPS(bool* fEnabled, double* fps)
00985 {
00986 HRESULT hr = CDirectVobSub::get_MediaFPS(fEnabled, fps);
00987
00988 CComQIPtr<IMediaSeeking> pMS = m_pGraph;
00989 double rate;
00990 if(pMS && SUCCEEDED(pMS->GetRate(&rate)))
00991 {
00992 m_MediaFPS = rate * m_fps;
00993 if(fps) *fps = m_MediaFPS;
00994 }
00995
00996 return hr;
00997 }
00998
00999 STDMETHODIMP CDirectVobSubFilter::put_MediaFPS(bool fEnabled, double fps)
01000 {
01001 HRESULT hr = CDirectVobSub::put_MediaFPS(fEnabled, fps);
01002
01003 CComQIPtr<IMediaSeeking> pMS = m_pGraph;
01004 if(pMS)
01005 {
01006 if(hr == NOERROR)
01007 {
01008 hr = pMS->SetRate(m_fMediaFPSEnabled ? m_MediaFPS / m_fps : 1.0);
01009 }
01010
01011 double dRate;
01012 if(SUCCEEDED(pMS->GetRate(&dRate)))
01013 m_MediaFPS = dRate * m_fps;
01014 }
01015
01016 return hr;
01017 }
01018
01019 STDMETHODIMP CDirectVobSubFilter::get_ZoomRect(NORMALIZEDRECT* rect)
01020 {
01021 return E_NOTIMPL;
01022 }
01023
01024 STDMETHODIMP CDirectVobSubFilter::put_ZoomRect(NORMALIZEDRECT* rect)
01025 {
01026 return E_NOTIMPL;
01027 }
01028
01029
01030
01031 STDMETHODIMP CDirectVobSubFilter::put_TextSettings(STSStyle* pDefStyle)
01032 {
01033 HRESULT hr = CDirectVobSub::put_TextSettings(pDefStyle);
01034
01035 if(hr == NOERROR)
01036 {
01037 UpdateSubtitle(true);
01038 }
01039
01040 return hr;
01041 }
01042
01043
01044
01045 STDMETHODIMP CDirectVobSubFilter::HasConfigDialog(int iSelected)
01046 {
01047 int nLangs;
01048 if(FAILED(get_LanguageCount(&nLangs))) return E_FAIL;
01049 return E_FAIL;
01050
01051
01052 }
01053
01054 STDMETHODIMP CDirectVobSubFilter::ShowConfigDialog(int iSelected, HWND hWndParent)
01055 {
01056
01057 return(E_FAIL);
01058 }
01059
01061
01062 CDirectVobSubFilter2::CDirectVobSubFilter2(LPUNKNOWN punk, HRESULT* phr, const GUID& clsid) :
01063 CDirectVobSubFilter(punk, phr, clsid)
01064 {
01065 }
01066
01067 HRESULT CDirectVobSubFilter2::CheckConnect(PIN_DIRECTION dir, IPin* pPin)
01068 {
01069 CPinInfo pi;
01070 if(FAILED(pPin->QueryPinInfo(&pi))) return E_FAIL;
01071
01072 if(CComQIPtr<IDirectVobSub>(pi.pFilter)) return E_FAIL;
01073
01074 if(dir == PINDIR_INPUT)
01075 {
01076 CFilterInfo fi;
01077 if(SUCCEEDED(pi.pFilter->QueryFilterInfo(&fi))
01078 && !wcsnicmp(fi.achName, L"Overlay Mixer", 13))
01079 return(E_FAIL);
01080 }
01081 else
01082 {
01083 }
01084
01085 return __super::CheckConnect(dir, pPin);
01086 }
01087
01088 HRESULT CDirectVobSubFilter2::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
01089 {
01090 if(pGraph)
01091 {
01092 BeginEnumFilters(pGraph, pEF, pBF)
01093 {
01094 if(pBF != (IBaseFilter*)this && CComQIPtr<IDirectVobSub>(pBF))
01095 return E_FAIL;
01096 }
01097 EndEnumFilters
01098
01099
01100
01101
01102
01103
01104
01105
01106
01107
01108
01109 if(!get_Forced())
01110 {
01111 BeginEnumFilters(pGraph, pEF, pBF)
01112 {
01113 if(CComQIPtr<IDirectVobSub>(pBF))
01114 continue;
01115
01116 CComPtr<IPin> pInPin = GetFirstPin(pBF, PINDIR_INPUT);
01117 CComPtr<IPin> pOutPin = GetFirstPin(pBF, PINDIR_OUTPUT);
01118
01119 if(!pInPin)
01120 continue;
01121
01122 CComPtr<IPin> pPin;
01123 if(pInPin && SUCCEEDED(pInPin->ConnectedTo(&pPin))
01124 || pOutPin && SUCCEEDED(pOutPin->ConnectedTo(&pPin)))
01125 continue;
01126
01127 if(pOutPin && GetFilterName(pBF) == _T("Overlay Mixer"))
01128 continue;
01129
01130 bool fVideoInputPin = false;
01131
01132 do
01133 {
01134 BITMAPINFOHEADER bih = {sizeof(BITMAPINFOHEADER), 384, 288, 1, 16, '2YUY', 384*288*2, 0, 0, 0, 0};
01135
01136 CMediaType cmt;
01137 cmt.majortype = MEDIATYPE_Video;
01138 cmt.subtype = MEDIASUBTYPE_YUY2;
01139 cmt.formattype = FORMAT_VideoInfo;
01140 cmt.pUnk = NULL;
01141 cmt.bFixedSizeSamples = TRUE;
01142 cmt.bTemporalCompression = TRUE;
01143 cmt.lSampleSize = 384*288*2;
01144 VIDEOINFOHEADER* vih = (VIDEOINFOHEADER*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER));
01145 memset(vih, 0, sizeof(VIDEOINFOHEADER));
01146 memcpy(&vih->bmiHeader, &bih, sizeof(bih));
01147 vih->AvgTimePerFrame = 400000;
01148
01149 if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
01150 {
01151 fVideoInputPin = true;
01152 break;
01153 }
01154
01155 VIDEOINFOHEADER2* vih2 = (VIDEOINFOHEADER2*)cmt.AllocFormatBuffer(sizeof(VIDEOINFOHEADER2));
01156 memset(vih2, 0, sizeof(VIDEOINFOHEADER2));
01157 memcpy(&vih2->bmiHeader, &bih, sizeof(bih));
01158 vih2->AvgTimePerFrame = 400000;
01159 vih2->dwPictAspectRatioX = 384;
01160 vih2->dwPictAspectRatioY = 288;
01161
01162 if(SUCCEEDED(pInPin->QueryAccept(&cmt)))
01163 {
01164 fVideoInputPin = true;
01165 break;
01166 }
01167 }
01168 while(false);
01169
01170 if(fVideoInputPin)
01171 {
01172 CComPtr<IBaseFilter> pDVS;
01173 if(ShouldWeAutoload(pGraph) && SUCCEEDED(pDVS.CoCreateInstance(__uuidof(CDirectVobSubFilter2))))
01174 {
01175 CComQIPtr<IDirectVobSub2>(pDVS)->put_Forced(true);
01176 CComQIPtr<IGraphConfig>(pGraph)->AddFilterToCache(pDVS);
01177 }
01178
01179 break;
01180 }
01181 }
01182 EndEnumFilters
01183 }
01184 }
01185 else
01186 {
01187 }
01188
01189 return __super::JoinFilterGraph(pGraph, pName);
01190 }
01191
01192 HRESULT CDirectVobSubFilter2::CheckInputType(const CMediaType* mtIn)
01193 {
01194 HRESULT hr = __super::CheckInputType(mtIn);
01195
01196 if(FAILED(hr) || m_pInput->IsConnected()) return hr;
01197
01198 if(!ShouldWeAutoload(m_pGraph)) return VFW_E_TYPE_NOT_ACCEPTED;
01199
01200 GetRidOfInternalScriptRenderer();
01201
01202 return NOERROR;
01203 }
01204
01205 bool CDirectVobSubFilter2::ShouldWeAutoload(IFilterGraph* pGraph)
01206 {
01207 TCHAR blacklistedapps[][32] =
01208 {
01209 _T("WM8EUTIL."),
01210 _T("explorer."),
01211 _T("producer."),
01212 };
01213
01214 for(int i = 0; i < countof(blacklistedapps); i++)
01215 {
01216 if(theApp.m_AppName.Find(blacklistedapps[i]) >= 0)
01217 return(false);
01218 }
01219
01220 int level;
01221 bool m_fExternalLoad, m_fWebLoad, m_fEmbeddedLoad;
01222 get_LoadSettings(&level, &m_fExternalLoad, &m_fWebLoad, &m_fEmbeddedLoad);
01223
01224 if(level < 0 || level >= 2) return(false);
01225
01226 bool fRet = false;
01227
01228 if(level == 1)
01229 fRet = m_fExternalLoad = m_fWebLoad = m_fEmbeddedLoad = true;
01230
01231
01232
01233 if(!fRet && m_fEmbeddedLoad)
01234 {
01235 CComPtr<IBaseFilter> pBF;
01236 if((pBF = FindFilter(CLSID_OggSplitter, pGraph)) || (pBF = FindFilter(CLSID_AviSplitter, pGraph))
01237 || (pBF = FindFilter(L"{34293064-02F2-41D5-9D75-CC5967ACA1AB}", pGraph))
01238 || (pBF = FindFilter(L"{0A68C3B5-9164-4a54-AFAF-995B2FF0E0D4}", pGraph))
01239 || (pBF = FindFilter(L"{149D2E01-C32E-4939-80F6-C07B81015A7A}", pGraph))
01240 || (pBF = FindFilter(L"{9AB95E90-1F37-427e-9B3D-257FB0CB25F7}", pGraph))
01241 || (pBF = FindFilter(L"{55DA30FC-F16B-49fc-BAA5-AE59FC65F82D}", pGraph))
01242 || (pBF = FindFilter(L"{52B63861-DC93-11CE-A099-00AA00479A58}", pGraph))
01243 || (pBF = FindFilter(L"{6D3688CE-3E9D-42F4-92CA-8A11119D25CD}", pGraph))
01244 || (pBF = FindFilter(L"{9FF48807-E133-40AA-826F-9B2959E5232D}", pGraph))
01245 || (pBF = FindFilter(L"{803E8280-F3CE-4201-982C-8CD8FB512004}", pGraph))
01246 || (pBF = FindFilter(L"{0912B4DD-A30A-4568-B590-7179EBB420EC}", pGraph)))
01247 {
01248 BeginEnumPins(pBF, pEP, pPin)
01249 {
01250 BeginEnumMediaTypes(pPin, pEM, pmt)
01251 {
01252 if(pmt->majortype == MEDIATYPE_Text || pmt->majortype == MEDIATYPE_Subtitle)
01253 {
01254 fRet = true;
01255 break;
01256 }
01257 }
01258 EndEnumMediaTypes(pmt)
01259 if(fRet) break;
01260 }
01261 EndEnumFilters
01262 }
01263 }
01264
01265
01266
01267 CStringW fn;
01268
01269 BeginEnumFilters(pGraph, pEF, pBF)
01270 {
01271 if(CComQIPtr<IFileSourceFilter> pFSF = pBF)
01272 {
01273 LPOLESTR fnw = NULL;
01274 if(!pFSF || FAILED(pFSF->GetCurFile(&fnw, NULL)) || !fnw)
01275 continue;
01276 fn = CString(fnw);
01277 CoTaskMemFree(fnw);
01278 break;
01279 }
01280 }
01281 EndEnumFilters
01282
01283 if((m_fExternalLoad || m_fWebLoad) && (m_fWebLoad || !(wcsstr(fn, L"http://") || wcsstr(fn, L"mms://"))))
01284 {
01285 bool fTemp = m_fHideSubtitles;
01286 fRet = !fn.IsEmpty() && SUCCEEDED(put_FileName((LPWSTR)(LPCWSTR)fn))
01287 || SUCCEEDED(put_FileName(L"c:\\tmp.srt"))
01288 || fRet;
01289 if(fTemp) m_fHideSubtitles = true;
01290 }
01291
01292 return(fRet);
01293 }
01294
01295 void CDirectVobSubFilter2::GetRidOfInternalScriptRenderer()
01296 {
01297 while(CComPtr<IBaseFilter> pBF = FindFilter(L"{48025243-2D39-11CE-875D-00608CB78066}", m_pGraph))
01298 {
01299 BeginEnumPins(pBF, pEP, pPin)
01300 {
01301 PIN_DIRECTION dir;
01302 CComPtr<IPin> pPinTo;
01303
01304 if(SUCCEEDED(pPin->QueryDirection(&dir)) && dir == PINDIR_INPUT
01305 && SUCCEEDED(pPin->ConnectedTo(&pPinTo)))
01306 {
01307 m_pGraph->Disconnect(pPinTo);
01308 m_pGraph->Disconnect(pPin);
01309 m_pGraph->ConnectDirect(pPinTo, GetPin(2 + m_pTextInput.GetSize()-1), NULL);
01310 }
01311 }
01312 EndEnumPins
01313
01314 if(FAILED(m_pGraph->RemoveFilter(pBF)))
01315 break;
01316 }
01317 }
01318
01320
01321 bool CDirectVobSubFilter::Open()
01322 {
01323 AFX_MANAGE_STATE(AfxGetStaticModuleState());
01324
01325 CAutoLock cAutolock(&m_csQueueLock);
01326
01327 m_pSubStreams.RemoveAll();
01328
01329 m_frd.files.RemoveAll();
01330
01331 CStringArray paths;
01332
01333 for(int i = 0; i < 10; i++)
01334 {
01335 CString tmp;
01336 tmp.Format(IDS_RP_PATH, i);
01337 CString path = theApp.GetProfileString(ResStr(IDS_R_DEFTEXTPATHES), tmp);
01338 if(!path.IsEmpty()) paths.Add(path);
01339 }
01340
01341 SubFiles ret;
01342 GetSubFileNames(m_FileName, paths, ret);
01343
01344 for(int i = 0; i < ret.GetSize(); i++)
01345 {
01346 if(m_frd.files.Find(ret[i].fn))
01347 continue;
01348
01349 CComPtr<ISubStream> pSubStream;
01350
01351 if(!pSubStream)
01352 {
01353 CAutoPtr<CVobSubFile> pVSF(new CVobSubFile(&m_csSubLock));
01354 if(pVSF && pVSF->Open(ret[i].fn) && pVSF->GetStreamCount() > 0)
01355 {
01356 pSubStream = pVSF.Detach();
01357 m_frd.files.AddTail(ret[i].fn.Left(ret[i].fn.GetLength()-4) + _T(".sub"));
01358 }
01359 }
01360
01361 if(!pSubStream)
01362 {
01363 CAutoPtr<CRenderedTextSubtitle> pRTS(new CRenderedTextSubtitle(&m_csSubLock));
01364 if(pRTS && pRTS->Open(ret[i].fn, DEFAULT_CHARSET) && pRTS->GetStreamCount() > 0)
01365 {
01366 pSubStream = pRTS.Detach();
01367 m_frd.files.AddTail(ret[i].fn + _T(".style"));
01368 }
01369 }
01370
01371 if(pSubStream)
01372 {
01373 m_pSubStreams.AddTail(pSubStream);
01374 m_frd.files.AddTail(ret[i].fn);
01375 }
01376 }
01377
01378 for(int i = 0; i < m_pTextInput.GetSize(); i++)
01379 {
01380 if(m_pTextInput[i]->IsConnected())
01381 m_pSubStreams.AddTail(m_pTextInput[i]->GetSubStream());
01382 }
01383
01384 if(S_FALSE == put_SelectedLanguage(FindPreferedLanguage()))
01385 UpdateSubtitle(false);
01386
01387 m_frd.RefreshEvent.Set();
01388
01389 return(m_pSubStreams.GetCount() > 0);
01390 }
01391
01392 void CDirectVobSubFilter::UpdateSubtitle(bool fApplyDefStyle)
01393 {
01394 CAutoLock cAutolock(&m_csQueueLock);
01395
01396 if(!m_pSubPicQueue) return;
01397
01398 InvalidateSubtitle();
01399
01400 CComPtr<ISubStream> pSubStream;
01401
01402 if(!m_fHideSubtitles)
01403 {
01404 int i = m_iSelectedLanguage;
01405
01406 for(POSITION pos = m_pSubStreams.GetHeadPosition(); i >= 0 && pos; pSubStream = NULL)
01407 {
01408 pSubStream = m_pSubStreams.GetNext(pos);
01409
01410 if(i < pSubStream->GetStreamCount())
01411 {
01412 CAutoLock cAutoLock(&m_csSubLock);
01413 pSubStream->SetStream(i);
01414 break;
01415 }
01416
01417 i -= pSubStream->GetStreamCount();
01418 }
01419 }
01420
01421 SetSubtitle(pSubStream, fApplyDefStyle);
01422 }
01423
01424 void CDirectVobSubFilter::SetSubtitle(ISubStream* pSubStream, bool fApplyDefStyle)
01425 {
01426 CAutoLock cAutolock(&m_csQueueLock);
01427
01428 if(pSubStream)
01429 {
01430 CAutoLock cAutolock(&m_csSubLock);
01431
01432 CLSID clsid;
01433 pSubStream->GetClassID(&clsid);
01434
01435 if(clsid == __uuidof(CVobSubFile))
01436 {
01437 CVobSubSettings* pVSS = (CVobSubFile*)(ISubStream*)pSubStream;
01438
01439 if(fApplyDefStyle)
01440 {
01441 pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
01442 pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
01443 }
01444 }
01445 else if(clsid == __uuidof(CVobSubStream))
01446 {
01447 CVobSubSettings* pVSS = (CVobSubStream*)(ISubStream*)pSubStream;
01448
01449 if(fApplyDefStyle)
01450 {
01451 pVSS->SetAlignment(m_fOverridePlacement, m_PlacementXperc, m_PlacementYperc, 1, 1);
01452 pVSS->m_fOnlyShowForcedSubs = m_fOnlyShowForcedVobSubs;
01453 }
01454 }
01455 else if(clsid == __uuidof(CRenderedTextSubtitle))
01456 {
01457 CRenderedTextSubtitle* pRTS = (CRenderedTextSubtitle*)(ISubStream*)pSubStream;
01458
01459 if(fApplyDefStyle || pRTS->m_fUsingAutoGeneratedDefaultStyle)
01460 {
01461 STSStyle s = m_defStyle;
01462
01463 if(m_fOverridePlacement)
01464 {
01465 s.scrAlignment = 2;
01466 int w = pRTS->m_dstScreenSize.cx;
01467 int h = pRTS->m_dstScreenSize.cy;
01468 int mw = w - s.marginRect.left - s.marginRect.right;
01469 s.marginRect.bottom = h - MulDiv(h, m_PlacementYperc, 100);
01470 s.marginRect.left = MulDiv(w, m_PlacementXperc, 100) - mw/2;
01471 s.marginRect.right = w - (s.marginRect.left + mw);
01472 }
01473
01474 pRTS->SetDefaultStyle(s);
01475 }
01476
01477 pRTS->Deinit();
01478 }
01479 }
01480
01481 if(!fApplyDefStyle)
01482 {
01483 int i = 0;
01484
01485 POSITION pos = m_pSubStreams.GetHeadPosition();
01486 while(pos)
01487 {
01488 CComPtr<ISubStream> pSubStream2 = m_pSubStreams.GetNext(pos);
01489
01490 if(pSubStream == pSubStream2)
01491 {
01492 m_iSelectedLanguage = i + pSubStream2->GetStream();
01493 break;
01494 }
01495
01496 i += pSubStream2->GetStreamCount();
01497 }
01498 }
01499
01500 m_nSubtitleId = (DWORD_PTR)pSubStream;
01501
01502 if(m_pSubPicQueue)
01503 m_pSubPicQueue->SetSubPicProvider(CComQIPtr<ISubPicProvider>(pSubStream));
01504 }
01505
01506 void CDirectVobSubFilter::InvalidateSubtitle(REFERENCE_TIME rtInvalidate, DWORD_PTR nSubtitleId)
01507 {
01508 CAutoLock cAutolock(&m_csQueueLock);
01509
01510 if(m_pSubPicQueue)
01511 {
01512 if(nSubtitleId == -1 || nSubtitleId == m_nSubtitleId)
01513 m_pSubPicQueue->Invalidate(rtInvalidate);
01514 }
01515 }
01516
01518
01519 void CDirectVobSubFilter::AddSubStream(ISubStream* pSubStream)
01520 {
01521 CAutoLock cAutoLock(&m_csQueueLock);
01522
01523 POSITION pos = m_pSubStreams.Find(pSubStream);
01524 if(!pos) m_pSubStreams.AddTail(pSubStream);
01525
01526 int len = m_pTextInput.GetSize();
01527 for(int i = 0; i < m_pTextInput.GetSize(); i++)
01528 if(m_pTextInput[i]->IsConnected()) len--;
01529
01530 if(len == 0)
01531 {
01532 HRESULT hr = S_OK;
01533 m_pTextInput.Add(new CTextInputPin(this, m_pLock, &m_csSubLock, &hr));
01534 }
01535 }
01536
01537 void CDirectVobSubFilter::RemoveSubStream(ISubStream* pSubStream)
01538 {
01539 CAutoLock cAutoLock(&m_csQueueLock);
01540
01541 POSITION pos = m_pSubStreams.Find(pSubStream);
01542 if(pos) m_pSubStreams.RemoveAt(pos);
01543 }
01544
01545 void CDirectVobSubFilter::Post_EC_OLE_EVENT(CString str, DWORD_PTR nSubtitleId)
01546 {
01547 if(nSubtitleId != -1 && nSubtitleId != m_nSubtitleId)
01548 return;
01549
01550 CComQIPtr<IMediaEventSink> pMES = m_pGraph;
01551 if(!pMES) return;
01552
01553 CComBSTR bstr1("Text"), bstr2(" ");
01554
01555 str.Trim();
01556 if(!str.IsEmpty()) bstr2 = CStringA(str);
01557
01558 pMES->Notify(EC_OLE_EVENT, (LONG_PTR)bstr1.Detach(), (LONG_PTR)bstr2.Detach());
01559 }
01560
01562
01563 void CDirectVobSubFilter::SetupFRD(CStringArray& paths, CArray<HANDLE>& handles)
01564 {
01565 CAutoLock cAutolock(&m_csSubLock);
01566
01567 for(int i = 2; i < handles.GetSize(); i++)
01568 {
01569 FindCloseChangeNotification(handles[i]);
01570 }
01571
01572 paths.RemoveAll();
01573 handles.RemoveAll();
01574
01575 handles.Add(m_frd.EndThreadEvent);
01576 handles.Add(m_frd.RefreshEvent);
01577
01578 m_frd.mtime.SetSize(m_frd.files.GetSize());
01579
01580 POSITION pos = m_frd.files.GetHeadPosition();
01581 for(int i = 0; pos; i++)
01582 {
01583 CString fn = m_frd.files.GetNext(pos);
01584
01585 CFileStatus status;
01586 if(CFileGetStatus(fn, status))
01587 m_frd.mtime[i] = status.m_mtime;
01588
01589 fn.Replace('\\', '/');
01590 fn = fn.Left(fn.ReverseFind('/')+1);
01591
01592 bool fFound = false;
01593
01594 for(int j = 0; !fFound && j < paths.GetSize(); j++)
01595 {
01596 if(paths[j] == fn) fFound = true;
01597 }
01598
01599 if(!fFound)
01600 {
01601 paths.Add(fn);
01602
01603 HANDLE h = FindFirstChangeNotification(fn, FALSE, FILE_NOTIFY_CHANGE_LAST_WRITE);
01604 if(h != INVALID_HANDLE_VALUE) handles.Add(h);
01605 }
01606 }
01607 }
01608
01609 DWORD CDirectVobSubFilter::ThreadProc()
01610 {
01611 SetThreadPriority(m_hThread, THREAD_PRIORITY_LOWEST);
01612
01613 CStringArray paths;
01614 CArray<HANDLE> handles;
01615
01616 SetupFRD(paths, handles);
01617
01618 while(1)
01619 {
01620 DWORD idx = WaitForMultipleObjects(handles.GetSize(), handles.GetData(), FALSE, INFINITE);
01621
01622 if(idx == (WAIT_OBJECT_0 + 0))
01623 {
01624 break;
01625 }
01626 if(idx == (WAIT_OBJECT_0 + 1))
01627 {
01628 SetupFRD(paths, handles);
01629 }
01630 else if(idx >= (WAIT_OBJECT_0 + 2) && idx < (WAIT_OBJECT_0 + handles.GetSize()))
01631 {
01632 bool fLocked = true;
01633 IsSubtitleReloaderLocked(&fLocked);
01634 if(fLocked) continue;
01635
01636 if(FindNextChangeNotification(handles[idx - WAIT_OBJECT_0]) == FALSE)
01637 break;
01638
01639 int j = 0;
01640
01641 POSITION pos = m_frd.files.GetHeadPosition();
01642 for(int i = 0; pos && j == 0; i++)
01643 {
01644 CString fn = m_frd.files.GetNext(pos);
01645
01646 CFileStatus status;
01647 if(CFileGetStatus(fn, status) && m_frd.mtime[i] != status.m_mtime)
01648 {
01649 for(j = 0; j < 10; j++)
01650 {
01651 if(FILE* f = _tfopen(fn, _T("rb+")))
01652 {
01653 fclose(f);
01654 j = 0;
01655 break;
01656 }
01657 else
01658 {
01659 Sleep(100);
01660 j++;
01661 }
01662 }
01663 }
01664 }
01665
01666 if(j > 0)
01667 {
01668 SetupFRD(paths, handles);
01669 }
01670 else
01671 {
01672 Sleep(500);
01673
01674 POSITION pos = m_frd.files.GetHeadPosition();
01675 for(int i = 0; pos; i++)
01676 {
01677 CFileStatus status;
01678 if(CFileGetStatus(m_frd.files.GetNext(pos), status)
01679 && m_frd.mtime[i] != status.m_mtime)
01680 {
01681 Open();
01682 SetupFRD(paths, handles);
01683 break;
01684 }
01685 }
01686 }
01687 }
01688 else
01689 {
01690 break;
01691 }
01692 }
01693
01694 for(int i = 2; i < handles.GetSize(); i++)
01695 {
01696 FindCloseChangeNotification(handles[i]);
01697 }
01698
01699 return 0;
01700 }