DirectVobSubFilter.cpp

00001 /* 
00002  *      Copyright (C) 2003-2005 Gabest
00003  *      http://www.gabest.org
00004  *
00005  *  This Program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2, or (at your option)
00008  *  any later version.
00009  *   
00010  *  This Program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00013  *  GNU General Public License for more details.
00014  *   
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with GNU Make; see the file COPYING.  If not, write to
00017  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
00018  *  http://www.gnu.org/copyleft/gpl.html
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 /*removeme*/
00040 bool g_RegOK = true;//false; // doesn't work with the dvd graph builder
00041 #include "valami.cpp"
00042 
00044 //
00045 // Constructor
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 // CBaseVideoFilter
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 //      if(m_fDivxPlusFix) fFlip = !fFlip;
00244 
00245         bool fFlipSub = fOutputFlipped;
00246         if(m_fFlipSubtitles) fFlipSub = !fFlipSub;
00247 //      if(m_fDivxPlusFix) fFlipSub = !fFlipSub;
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 // CBaseFilter
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                 /*removeme*/
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 // CTransformFilter
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                 /*removeme*/
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                 // needed when we have a decoder with a version number of 3.x
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                 // HACK: triggers CBaseVideoFilter::SetMediaType to adjust m_w/m_h/.. and InitSubPicQueue() to realloc buffers
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                 // not really needed, but may free up a little memory
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; // 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)
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; // enable ... disable
00605 
00606         (*pcStreams) += 2; // normal flipped
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         // move the selected to the top of the list
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         // move "Hide subtitles" to the last position if it wasn't our selection
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) // we need this because when loading something stupid media player pushes the first stream it founds, which is "enable" in our case
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 // IDirectVobSub
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 //              UpdateSubtitle(false);
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 //              UpdateSubtitle(true);
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 // IDirectVobSub2
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 // IDirectVobSubFilterColor
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         // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
01051 //      return(nLangs >= 0 && iSelected < nLangs ? S_OK : E_FAIL);
01052 }
01053 
01054 STDMETHODIMP CDirectVobSubFilter::ShowConfigDialog(int iSelected, HWND hWndParent)
01055 {
01056         // TODO: temporally disabled since we don't have a new textsub/vobsub editor dlg for dvs yet
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                 // don't look... we will do some serious graph hacking again...
01100                 //
01101                 // we will add dvs2 to the filter graph cache
01102                 // - if the main app has already added some kind of renderer or overlay mixer (anything which accepts video on its input)
01103                 // and 
01104                 // - if we have a reason to auto-load (we don't want to make any trouble when there is no need :)
01105                 //
01106                 // This whole workaround is needed because the video stream will always be connected 
01107                 // to the pre-added filters first, no matter how high merit we have.
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."), // 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)
01210                 _T("explorer."), // as some users reported thumbnail preview loads dvobsub, I've never experienced this yet...
01211                 _T("producer."), // this is real's 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         // find text stream on known splitters
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)) // matroska demux
01238                 || (pBF = FindFilter(L"{0A68C3B5-9164-4a54-AFAF-995B2FF0E0D4}", pGraph)) // matroska source
01239                 || (pBF = FindFilter(L"{149D2E01-C32E-4939-80F6-C07B81015A7A}", pGraph)) // matroska splitter
01240                 || (pBF = FindFilter(L"{9AB95E90-1F37-427e-9B3D-257FB0CB25F7}", pGraph)) // Haali's matroska splitter (?)
01241                 || (pBF = FindFilter(L"{55DA30FC-F16B-49fc-BAA5-AE59FC65F82D}", pGraph)) // Haali's matroska splitter                   
01242                 || (pBF = FindFilter(L"{52B63861-DC93-11CE-A099-00AA00479A58}", pGraph)) // 3ivx splitter
01243                 || (pBF = FindFilter(L"{6D3688CE-3E9D-42F4-92CA-8A11119D25CD}", pGraph)) // our ogg source
01244                 || (pBF = FindFilter(L"{9FF48807-E133-40AA-826F-9B2959E5232D}", pGraph)) // our ogg splitter
01245                 || (pBF = FindFilter(L"{803E8280-F3CE-4201-982C-8CD8FB512004}", pGraph)) // dsm source
01246                 || (pBF = FindFilter(L"{0912B4DD-A30A-4568-B590-7179EBB420EC}", pGraph))) // dsm splitter
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         // find file name
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); // make sure pSubPicProvider of our queue gets updated even if the stream number hasn't changed
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/*THREAD_PRIORITY_BELOW_NORMAL*/);
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)) // m_frd.hEndThreadEvent
01623                 {
01624                         break;
01625                 }
01626                 if(idx == (WAIT_OBJECT_0 + 1)) // m_frd.hRefreshEvent
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 }

Generated on Tue Dec 13 14:47:51 2005 for guliverkli by  doxygen 1.4.5