- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# 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 }