- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# ISubPic.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 "ISubPic.h"
    00024 #include "..\DSUtil\DSUtil.h"
    00025
    00026 //
    00027 // ISubPicImpl
    00028 //
    00029
    00030 ISubPicImpl::ISubPicImpl()
    00031         : CUnknown(NAME("ISubPicImpl"), NULL)
    00032         , m_rtStart(0), m_rtStop(0)
    00033         , m_rcDirty(0, 0, 0, 0), m_maxsize(0, 0), m_size(0, 0), m_vidrect(0, 0, 0, 0)
    00034 {
    00035 }
    00036
    00037 STDMETHODIMP ISubPicImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00038 {
    00039         return
    00040                 QI(ISubPic)
    00041                 __super::NonDelegatingQueryInterface(riid, ppv);
    00042 }
    00043
    00044 // ISubPic
    00045
    00046 STDMETHODIMP_(REFERENCE_TIME) ISubPicImpl::GetStart()
    00047 {
    00048         return(m_rtStart);
    00049 }
    00050
    00051 STDMETHODIMP_(REFERENCE_TIME) ISubPicImpl::GetStop()
    00052 {
    00053         return(m_rtStop);
    00054 }
    00055
    00056 STDMETHODIMP_(void) ISubPicImpl::SetStart(REFERENCE_TIME rtStart)
    00057 {
    00058         m_rtStart = rtStart;
    00059 }
    00060
    00061 STDMETHODIMP_(void) ISubPicImpl::SetStop(REFERENCE_TIME rtStop)
    00062 {
    00063         m_rtStop = rtStop;
    00064 }
    00065
    00066 STDMETHODIMP ISubPicImpl::CopyTo(ISubPic* pSubPic)
    00067 {
    00068         if(!pSubPic)
    00069                 return E_POINTER;
    00070
    00071         pSubPic->SetStart(m_rtStart);
    00072         pSubPic->SetStop(m_rtStop);
    00073         pSubPic->SetDirtyRect(m_rcDirty);
    00074         pSubPic->SetSize(m_size, m_vidrect);
    00075
    00076         return S_OK;
    00077 }
    00078
    00079 STDMETHODIMP ISubPicImpl::GetDirtyRect(RECT* pDirtyRect)
    00080 {
    00081         return pDirtyRect ? *pDirtyRect = m_rcDirty, S_OK : E_POINTER;
    00082 }
    00083
    00084 STDMETHODIMP ISubPicImpl::SetDirtyRect(RECT* pDirtyRect)
    00085 {
    00086         return pDirtyRect ? m_rcDirty = *pDirtyRect, S_OK : E_POINTER;
    00087 }
    00088
    00089 STDMETHODIMP ISubPicImpl::GetMaxSize(SIZE* pMaxSize)
    00090 {
    00091         return pMaxSize ? *pMaxSize = m_maxsize, S_OK : E_POINTER;
    00092 }
    00093
    00094 STDMETHODIMP ISubPicImpl::SetSize(SIZE size, RECT vidrect)
    00095 {
    00096         m_size = size;
    00097         m_vidrect = vidrect;
    00098
    00099         if(m_size.cx > m_maxsize.cx)
    00100         {
    00101                 m_size.cy = MulDiv(m_size.cy, m_maxsize.cx, m_size.cx);
    00102                 m_size.cx = m_maxsize.cx;
    00103         }
    00104
    00105         if(m_size.cy > m_maxsize.cy)
    00106         {
    00107                 m_size.cx = MulDiv(m_size.cx, m_maxsize.cy, m_size.cy);
    00108                 m_size.cy = m_maxsize.cy;
    00109         }
    00110
    00111         if(m_size.cx != size.cx || m_size.cy != size.cy)
    00112         {
    00113                 m_vidrect.top = MulDiv(m_vidrect.top, m_size.cx, size.cx);
    00114                 m_vidrect.bottom = MulDiv(m_vidrect.bottom, m_size.cx, size.cx);
    00115                 m_vidrect.left = MulDiv(m_vidrect.left, m_size.cy, size.cy);
    00116                 m_vidrect.right = MulDiv(m_vidrect.right, m_size.cy, size.cy);
    00117         }
    00118
    00119         return S_OK;
    00120 }
    00121
    00122 //
    00123 // ISubPicAllocatorImpl
    00124 //
    00125
    00126 ISubPicAllocatorImpl::ISubPicAllocatorImpl(SIZE cursize, bool fDynamicWriteOnly, bool fPow2Textures)
    00127         : CUnknown(NAME("ISubPicAllocatorImpl"), NULL)
    00128         , m_cursize(cursize)
    00129         , m_fDynamicWriteOnly(fDynamicWriteOnly)
    00130         , m_fPow2Textures(fPow2Textures)
    00131 {
    00132         m_curvidrect = CRect(CPoint(0,0), m_cursize);
    00133 }
    00134
    00135 STDMETHODIMP ISubPicAllocatorImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00136 {
    00137         return
    00138                 QI(ISubPicAllocator)
    00139                 __super::NonDelegatingQueryInterface(riid, ppv);
    00140 }
    00141
    00142 // ISubPicAllocator
    00143
    00144 STDMETHODIMP ISubPicAllocatorImpl::SetCurSize(SIZE cursize)
    00145 {
    00146         m_cursize = cursize;
    00147         return S_OK;
    00148 }
    00149
    00150 STDMETHODIMP ISubPicAllocatorImpl::SetCurVidRect(RECT curvidrect)
    00151 {
    00152         m_curvidrect = curvidrect;
    00153         return S_OK;
    00154 }
    00155
    00156 STDMETHODIMP ISubPicAllocatorImpl::GetStatic(ISubPic** ppSubPic)
    00157 {
    00158         if(!ppSubPic)
    00159                 return E_POINTER;
    00160
    00161         if(!m_pStatic)
    00162         {
    00163                 if(!Alloc(true, &m_pStatic) || !m_pStatic)
    00164                         return E_OUTOFMEMORY;
    00165         }
    00166
    00167         m_pStatic->SetSize(m_cursize, m_curvidrect);
    00168
    00169         (*ppSubPic = m_pStatic)->AddRef();
    00170
    00171         return S_OK;
    00172 }
    00173
    00174 STDMETHODIMP ISubPicAllocatorImpl::AllocDynamic(ISubPic** ppSubPic)
    00175 {
    00176         if(!ppSubPic)
    00177                 return E_POINTER;
    00178
    00179         if(!Alloc(false, ppSubPic) || !*ppSubPic)
    00180                 return E_OUTOFMEMORY;
    00181
    00182         (*ppSubPic)->SetSize(m_cursize, m_curvidrect);
    00183
    00184         return S_OK;
    00185 }
    00186
    00187 STDMETHODIMP_(bool) ISubPicAllocatorImpl::IsDynamicWriteOnly()
    00188 {
    00189         return(m_fDynamicWriteOnly);
    00190 }
    00191
    00192 STDMETHODIMP ISubPicAllocatorImpl::ChangeDevice(IUnknown* pDev)
    00193 {
    00194         m_pStatic = NULL;
    00195         return S_OK;
    00196 }
    00197
    00198 //
    00199 // ISubPicProviderImpl
    00200 //
    00201
    00202 ISubPicProviderImpl::ISubPicProviderImpl(CCritSec* pLock)
    00203         : CUnknown(NAME("ISubPicProviderImpl"), NULL)
    00204         , m_pLock(pLock)
    00205 {
    00206 }
    00207
    00208 ISubPicProviderImpl::~ISubPicProviderImpl()
    00209 {
    00210 }
    00211
    00212 STDMETHODIMP ISubPicProviderImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00213 {
    00214         return
    00215                 QI(ISubPicProvider)
    00216                 __super::NonDelegatingQueryInterface(riid, ppv);
    00217 }
    00218
    00219 // ISubPicProvider
    00220
    00221 STDMETHODIMP ISubPicProviderImpl::Lock()
    00222 {
    00223         return m_pLock ? m_pLock->Lock(), S_OK : E_FAIL;
    00224 }
    00225
    00226 STDMETHODIMP ISubPicProviderImpl::Unlock()
    00227 {
    00228         return m_pLock ? m_pLock->Unlock(), S_OK : E_FAIL;
    00229 }
    00230
    00231 //
    00232 // ISubPicQueueImpl
    00233 //
    00234
    00235 ISubPicQueueImpl::ISubPicQueueImpl(ISubPicAllocator* pAllocator, HRESULT* phr)
    00236         : CUnknown(NAME("ISubPicQueueImpl"), NULL)
    00237         , m_pAllocator(pAllocator)
    00238         , m_rtNow(0)
    00239         , m_fps(25.0)
    00240 {
    00241         if(phr) *phr = S_OK;
    00242
    00243         if(!m_pAllocator)
    00244         {
    00245                 if(phr) *phr = E_FAIL;
    00246                 return;
    00247         }
    00248 }
    00249
    00250 ISubPicQueueImpl::~ISubPicQueueImpl()
    00251 {
    00252 }
    00253
    00254 STDMETHODIMP ISubPicQueueImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00255 {
    00256         return
    00257                 QI(ISubPicQueue)
    00258                 __super::NonDelegatingQueryInterface(riid, ppv);
    00259 }
    00260
    00261 // ISubPicQueue
    00262
    00263 STDMETHODIMP ISubPicQueueImpl::SetSubPicProvider(ISubPicProvider* pSubPicProvider)
    00264 {
    00265         CAutoLock cAutoLock(&m_csSubPicProvider);
    00266
    00267 //      if(m_pSubPicProvider != pSubPicProvider)
    00268         {
    00269                 m_pSubPicProvider = pSubPicProvider;
    00270
    00271                 Invalidate();
    00272         }
    00273
    00274         return S_OK;
    00275 }
    00276
    00277 STDMETHODIMP ISubPicQueueImpl::GetSubPicProvider(ISubPicProvider** pSubPicProvider)
    00278 {
    00279         if(!pSubPicProvider)
    00280                 return E_POINTER;
    00281
    00282         CAutoLock cAutoLock(&m_csSubPicProvider);
    00283
    00284         if(m_pSubPicProvider)
    00285                 (*pSubPicProvider = m_pSubPicProvider)->AddRef();
    00286
    00287         return !!*pSubPicProvider ? S_OK : E_FAIL;
    00288 }
    00289
    00290 STDMETHODIMP ISubPicQueueImpl::SetFPS(double fps)
    00291 {
    00292         m_fps = fps;
    00293
    00294         return S_OK;
    00295 }
    00296
    00297 STDMETHODIMP ISubPicQueueImpl::SetTime(REFERENCE_TIME rtNow)
    00298 {
    00299         m_rtNow = rtNow;
    00300
    00301         return S_OK;
    00302 }
    00303
    00304 // private
    00305
    00306 HRESULT ISubPicQueueImpl::RenderTo(ISubPic* pSubPic, REFERENCE_TIME rtStart, REFERENCE_TIME rtStop, double fps)
    00307 {
    00308         HRESULT hr = E_FAIL;
    00309
    00310         if(!pSubPic)
    00311                 return hr;
    00312
    00313         CComPtr<ISubPicProvider> pSubPicProvider;
    00314         if(FAILED(GetSubPicProvider(&pSubPicProvider)) || !pSubPicProvider)
    00315                 return hr;
    00316
    00317         if(FAILED(pSubPicProvider->Lock()))
    00318                 return hr;
    00319
    00320         SubPicDesc spd;
    00321         if(SUCCEEDED(pSubPic->ClearDirtyRect(0xFF000000))
    00322         && SUCCEEDED(pSubPic->Lock(spd)))
    00323         {
    00324                 CRect r(0,0,0,0);
    00325                 hr = pSubPicProvider->Render(spd, (rtStart+rtStop)/2, fps, r);
    00326
    00327                 pSubPic->SetStart(rtStart);
    00328                 pSubPic->SetStop(rtStop);
    00329
    00330                 pSubPic->Unlock(r);
    00331         }
    00332
    00333         pSubPicProvider->Unlock();
    00334
    00335         return hr;
    00336 }
    00337
    00338 //
    00339 // CSubPicQueue
    00340 //
    00341
    00342 CSubPicQueue::CSubPicQueue(int nMaxSubPic, ISubPicAllocator* pAllocator, HRESULT* phr)
    00343         : ISubPicQueueImpl(pAllocator, phr)
    00344         , m_nMaxSubPic(nMaxSubPic)
    00345         , m_rtQueueStart(0)
    00346 {
    00347         if(phr && FAILED(*phr))
    00348                 return;
    00349
    00350         if(m_nMaxSubPic < 1)
    00351                 {if(phr) *phr = E_INVALIDARG; return;}
    00352
    00353         m_fBreakBuffering = false;
    00354         for(int i = 0; i < EVENT_COUNT; i++)
    00355                 m_ThreadEvents[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
    00356         CAMThread::Create();
    00357 }
    00358
    00359 CSubPicQueue::~CSubPicQueue()
    00360 {
    00361         m_fBreakBuffering = true;
    00362         SetEvent(m_ThreadEvents[EVENT_EXIT]);
    00363         CAMThread::Close();
    00364         for(int i = 0; i < EVENT_COUNT; i++)
    00365                 CloseHandle(m_ThreadEvents[i]);
    00366 }
    00367
    00368 // ISubPicQueue
    00369
    00370 STDMETHODIMP CSubPicQueue::SetFPS(double fps)
    00371 {
    00372         HRESULT hr = __super::SetFPS(fps);
    00373         if(FAILED(hr)) return hr;
    00374
    00375         SetEvent(m_ThreadEvents[EVENT_TIME]);
    00376
    00377         return S_OK;
    00378 }
    00379
    00380 STDMETHODIMP CSubPicQueue::SetTime(REFERENCE_TIME rtNow)
    00381 {
    00382         HRESULT hr = __super::SetTime(rtNow);
    00383         if(FAILED(hr)) return hr;
    00384
    00385         SetEvent(m_ThreadEvents[EVENT_TIME]);
    00386
    00387         return S_OK;
    00388 }
    00389
    00390 STDMETHODIMP CSubPicQueue::Invalidate(REFERENCE_TIME rtInvalidate)
    00391 {
    00392         {
    00393 //              CAutoLock cQueueLock(&m_csQueueLock);
    00394 //              RemoveAll();
    00395
    00396                 m_rtInvalidate = rtInvalidate;
    00397                 m_fBreakBuffering = true;
    00398                 SetEvent(m_ThreadEvents[EVENT_TIME]);
    00399         }
    00400
    00401         return S_OK;
    00402 }
    00403
    00404 STDMETHODIMP_(bool) CSubPicQueue::LookupSubPic(REFERENCE_TIME rtNow, ISubPic** ppSubPic)
    00405 {
    00406         if(!ppSubPic)
    00407                 return(false);
    00408
    00409         *ppSubPic = NULL;
    00410
    00411         CAutoLock cQueueLock(&m_csQueueLock);
    00412
    00413         POSITION pos = GetHeadPosition();
    00414         while(pos)
    00415         {
    00416                 CComPtr<ISubPic> pSubPic = GetNext(pos);
    00417                 if(pSubPic->GetStart() <= rtNow && rtNow < pSubPic->GetStop())
    00418                 {
    00419                         *ppSubPic = pSubPic.Detach();
    00420                         break;
    00421                 }
    00422         }
    00423
    00424         return(!!*ppSubPic);
    00425 }
    00426
    00427 STDMETHODIMP CSubPicQueue::GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop)
    00428 {
    00429         CAutoLock cQueueLock(&m_csQueueLock);
    00430
    00431         nSubPics = GetCount();
    00432         rtNow = m_rtNow;
    00433         rtStart = m_rtQueueStart;
    00434         rtStop = GetCount() > 0 ? GetTail()->GetStop() : rtStart;
    00435
    00436         return S_OK;
    00437 }
    00438
    00439 STDMETHODIMP CSubPicQueue::GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop)
    00440 {
    00441         CAutoLock cQueueLock(&m_csQueueLock);
    00442
    00443         rtStart = rtStop = -1;
    00444
    00445         if(nSubPic >= 0 && nSubPic < (int)GetCount())
    00446         {
    00447                 if(POSITION pos = FindIndex(nSubPic))
    00448                 {
    00449                         rtStart = GetAt(pos)->GetStart();
    00450                         rtStop = GetAt(pos)->GetStop();
    00451                 }
    00452         }
    00453         else
    00454         {
    00455                 return E_INVALIDARG;
    00456         }
    00457
    00458         return S_OK;
    00459 }
    00460
    00461 // private
    00462
    00463 REFERENCE_TIME CSubPicQueue::UpdateQueue()
    00464 {
    00465         CAutoLock cQueueLock(&m_csQueueLock);
    00466
    00467         REFERENCE_TIME rtNow = m_rtNow;
    00468
    00469         if(rtNow < m_rtQueueStart)
    00470         {
    00471                 RemoveAll();
    00472         }
    00473         else
    00474         {
    00475                 while(GetCount() > 0 && rtNow >= GetHead()->GetStop())
    00476                         RemoveHead();
    00477         }
    00478
    00479         m_rtQueueStart = rtNow;
    00480
    00481         if(GetCount() > 0)
    00482                 rtNow = GetTail()->GetStop();
    00483
    00484         return(rtNow);
    00485 }
    00486
    00487 void CSubPicQueue::AppendQueue(ISubPic* pSubPic)
    00488 {
    00489         CAutoLock cQueueLock(&m_csQueueLock);
    00490
    00491         AddTail(pSubPic);
    00492 }
    00493
    00494 // overrides
    00495
    00496 DWORD CSubPicQueue::ThreadProc()
    00497 {
    00498         SetThreadPriority(m_hThread, THREAD_PRIORITY_LOWEST/*THREAD_PRIORITY_BELOW_NORMAL*/);
    00499
    00500         while((WaitForMultipleObjects(EVENT_COUNT, m_ThreadEvents, FALSE, INFINITE) - WAIT_OBJECT_0) == EVENT_TIME)
    00501         {
    00502                 double fps = m_fps;
    00503                 REFERENCE_TIME rtNow = UpdateQueue();
    00504
    00505                 int nMaxSubPic = m_nMaxSubPic;
    00506
    00507                 CComPtr<ISubPicProvider> pSubPicProvider;
    00508                 if(SUCCEEDED(GetSubPicProvider(&pSubPicProvider)) && pSubPicProvider
    00509                 && SUCCEEDED(pSubPicProvider->Lock()))
    00510                 {
    00511                         for(POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps);
    00512                                 pos && !m_fBreakBuffering && GetCount() < (size_t)nMaxSubPic;
    00513                                 pos = pSubPicProvider->GetNext(pos))
    00514                         {
    00515                                 REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps);
    00516                                 REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps);
    00517
    00518                                 if(m_rtNow >= rtStart)
    00519                                 {
    00520 //                                              m_fBufferUnderrun = true;
    00521                                         if(m_rtNow >= rtStop) continue;
    00522                                 }
    00523
    00524                                 if(rtStart >= m_rtNow + 60*10000000i64) // we are already one minute ahead, this should be enough
    00525                                         break;
    00526
    00527                                 if(rtNow < rtStop)
    00528                                 {
    00529                                         CComPtr<ISubPic> pStatic;
    00530                                         if(FAILED(m_pAllocator->GetStatic(&pStatic)))
    00531                                                 break;
    00532
    00533                                         HRESULT hr = RenderTo(pStatic, rtStart, rtStop, fps);
    00534
    00535                                         if(FAILED(hr))
    00536                                                 break;
    00537
    00538                                         if(S_OK != hr) // subpic was probably empty
    00539                                                 continue;
    00540
    00541                                         CComPtr<ISubPic> pDynamic;
    00542                                         if(FAILED(m_pAllocator->AllocDynamic(&pDynamic))
    00543                                         || FAILED(pStatic->CopyTo(pDynamic)))
    00544                                                 break;
    00545
    00546                                         AppendQueue(pDynamic);
    00547                                 }
    00548                         }
    00549
    00550                         pSubPicProvider->Unlock();
    00551                 }
    00552
    00553                 if(m_fBreakBuffering)
    00554                 {
    00555                         CAutoLock cQueueLock(&m_csQueueLock);
    00556
    00557                         REFERENCE_TIME rtInvalidate = m_rtInvalidate;
    00558
    00559                         while(GetCount() && GetTail()->GetStop() > rtInvalidate)
    00560                         {
    00561                                 if(GetTail()->GetStart() < rtInvalidate)
    00562                                         GetTail()->SetStop(rtInvalidate);
    00563                                 else
    00564                                         RemoveTail();
    00565                         }
    00566
    00567                         m_fBreakBuffering = false;
    00568                 }
    00569         }
    00570
    00571         return(0);
    00572 }
    00573
    00574 //
    00575 // CSubPicQueueNoThread
    00576 //
    00577
    00578 CSubPicQueueNoThread::CSubPicQueueNoThread(ISubPicAllocator* pAllocator, HRESULT* phr)
    00579         : ISubPicQueueImpl(pAllocator, phr)
    00580 {
    00581 }
    00582
    00583 CSubPicQueueNoThread::~CSubPicQueueNoThread()
    00584 {
    00585 }
    00586
    00587 // ISubPicQueue
    00588
    00589 STDMETHODIMP CSubPicQueueNoThread::Invalidate(REFERENCE_TIME rtInvalidate)
    00590 {
    00591         CAutoLock cQueueLock(&m_csLock);
    00592
    00593         m_pSubPic = NULL;
    00594
    00595         return S_OK;
    00596 }
    00597
    00598 STDMETHODIMP_(bool) CSubPicQueueNoThread::LookupSubPic(REFERENCE_TIME rtNow, ISubPic** ppSubPic)
    00599 {
    00600         if(!ppSubPic)
    00601                 return(false);
    00602
    00603         *ppSubPic = NULL;
    00604
    00605         CComPtr<ISubPic> pSubPic;
    00606
    00607         {
    00608                 CAutoLock cAutoLock(&m_csLock);
    00609
    00610                 if(!m_pSubPic)
    00611                 {
    00612                         if(FAILED(m_pAllocator->AllocDynamic(&m_pSubPic)))
    00613                                 return(false);
    00614                 }
    00615
    00616                 pSubPic = m_pSubPic;
    00617         }
    00618
    00619         if(pSubPic->GetStart() <= rtNow && rtNow < pSubPic->GetStop())
    00620         {
    00621                 (*ppSubPic = pSubPic)->AddRef();
    00622         }
    00623         else
    00624         {
    00625                 CComPtr<ISubPicProvider> pSubPicProvider;
    00626                 if(SUCCEEDED(GetSubPicProvider(&pSubPicProvider)) && pSubPicProvider
    00627                 && SUCCEEDED(pSubPicProvider->Lock()))
    00628                 {
    00629                         double fps = m_fps;
    00630
    00631                         if(POSITION pos = pSubPicProvider->GetStartPosition(rtNow, fps))
    00632                         {
    00633                                 REFERENCE_TIME rtStart = pSubPicProvider->GetStart(pos, fps);
    00634                                 REFERENCE_TIME rtStop = pSubPicProvider->GetStop(pos, fps);
    00635
    00636                                 if(pSubPicProvider->IsAnimated(pos))
    00637                                 {
    00638                                         rtStart = rtNow;
    00639                                         rtStop = rtNow+1;
    00640                                 }
    00641
    00642                                 if(rtStart <= rtNow && rtNow < rtStop)
    00643                                 {
    00644                                         if(m_pAllocator->IsDynamicWriteOnly())
    00645                                         {
    00646                                                 CComPtr<ISubPic> pStatic;
    00647                                                 if(SUCCEEDED(m_pAllocator->GetStatic(&pStatic))
    00648                                                 && SUCCEEDED(RenderTo(pStatic, rtStart, rtStop, fps))
    00649                                                 && SUCCEEDED(pStatic->CopyTo(pSubPic)))
    00650                                                         (*ppSubPic = pSubPic)->AddRef();
    00651                                         }
    00652                                         else
    00653                                         {
    00654                                                 if(SUCCEEDED(RenderTo(m_pSubPic, rtStart, rtStop, fps)))
    00655                                                         (*ppSubPic = pSubPic)->AddRef();
    00656                                         }
    00657                                 }
    00658                         }
    00659
    00660                         pSubPicProvider->Unlock();
    00661
    00662                         if(*ppSubPic)
    00663                         {
    00664                                 CAutoLock cAutoLock(&m_csLock);
    00665
    00666                                 m_pSubPic = *ppSubPic;
    00667                         }
    00668                 }
    00669         }
    00670
    00671         return(!!*ppSubPic);
    00672 }
    00673
    00674 STDMETHODIMP CSubPicQueueNoThread::GetStats(int& nSubPics, REFERENCE_TIME& rtNow, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop)
    00675 {
    00676         CAutoLock cAutoLock(&m_csLock);
    00677
    00678         nSubPics = 0;
    00679         rtNow = m_rtNow;
    00680         rtStart = rtStop = 0;
    00681
    00682         if(m_pSubPic)
    00683         {
    00684                 nSubPics = 1;
    00685                 rtStart = m_pSubPic->GetStart();
    00686                 rtStop = m_pSubPic->GetStop();
    00687         }
    00688
    00689         return S_OK;
    00690 }
    00691
    00692 STDMETHODIMP CSubPicQueueNoThread::GetStats(int nSubPic, REFERENCE_TIME& rtStart, REFERENCE_TIME& rtStop)
    00693 {
    00694         CAutoLock cAutoLock(&m_csLock);
    00695
    00696         if(!m_pSubPic || nSubPic != 0)
    00697                 return E_INVALIDARG;
    00698
    00699         rtStart = m_pSubPic->GetStart();
    00700         rtStop = m_pSubPic->GetStop();
    00701
    00702         return S_OK;
    00703 }
    00704
    00705 //
    00706 // ISubPicAllocatorPresenterImpl
    00707 //
    00708
    00709 ISubPicAllocatorPresenterImpl::ISubPicAllocatorPresenterImpl(HWND hWnd)
    00710         : CUnknown(NAME("ISubPicAllocatorPresenterImpl"), NULL)
    00711         , m_hWnd(hWnd)
    00712         , m_NativeVideoSize(0, 0), m_AspectRatio(0, 0)
    00713         , m_VideoRect(0, 0, 0, 0), m_WindowRect(0, 0, 0, 0)
    00714         , m_fps(25.0)
    00715 {
    00716         SetVideoAngle(Vector(), false);
    00717 }
    00718
    00719 ISubPicAllocatorPresenterImpl::~ISubPicAllocatorPresenterImpl()
    00720 {
    00721 }
    00722
    00723 STDMETHODIMP ISubPicAllocatorPresenterImpl::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00724 {
    00725         return
    00726                 QI(ISubPicAllocatorPresenter)
    00727                 __super::NonDelegatingQueryInterface(riid, ppv);
    00728 }
    00729
    00730 void ISubPicAllocatorPresenterImpl::AlphaBltSubPic(CSize size, SubPicDesc* pTarget)
    00731 {
    00732         CComPtr<ISubPic> pSubPic;
    00733         if(m_pSubPicQueue->LookupSubPic(m_rtNow, &pSubPic))
    00734         {
    00735                 SubPicDesc spd;
    00736                 pSubPic->GetDesc(spd);
    00737
    00738                 CRect r;
    00739                 pSubPic->GetDirtyRect(r);
    00740
    00741                 // FIXME
    00742                 r.DeflateRect(1, 1);
    00743
    00744                 CRect rDstText(
    00745                         r.left * size.cx / spd.w,
    00746                         r.top * size.cy / spd.h,
    00747                         r.right * size.cx / spd.w,
    00748                         r.bottom * size.cy / spd.h);
    00749
    00750                 pSubPic->AlphaBlt(r, rDstText, pTarget);
    00751         }
    00752 }
    00753
    00754 // ISubPicAllocatorPresenter
    00755
    00756 STDMETHODIMP_(SIZE) ISubPicAllocatorPresenterImpl::GetVideoSize(bool fCorrectAR)
    00757 {
    00758         CSize VideoSize(m_NativeVideoSize);
    00759
    00760         if(fCorrectAR && m_AspectRatio.cx > 0 && m_AspectRatio.cy > 0)
    00761                 VideoSize.cx = VideoSize.cy*m_AspectRatio.cx/m_AspectRatio.cy;
    00762
    00763         return(VideoSize);
    00764 }
    00765
    00766 STDMETHODIMP_(void) ISubPicAllocatorPresenterImpl::SetPosition(RECT w, RECT v)
    00767 {
    00768         bool fWindowPosChanged = !!(m_WindowRect != w);
    00769         bool fWindowSizeChanged = !!(m_WindowRect.Size() != CRect(w).Size());
    00770
    00771         m_WindowRect = w;
    00772
    00773         bool fVideoRectChanged = !!(m_VideoRect != v);
    00774
    00775         m_VideoRect = v;
    00776
    00777         if(fWindowSizeChanged || fVideoRectChanged)
    00778         {
    00779                 if(m_pAllocator)
    00780                 {
    00781                         m_pAllocator->SetCurSize(m_WindowRect.Size());
    00782                         m_pAllocator->SetCurVidRect(m_VideoRect);
    00783                 }
    00784
    00785                 if(m_pSubPicQueue)
    00786                 {
    00787                         m_pSubPicQueue->Invalidate();
    00788                 }
    00789         }
    00790
    00791         if(fWindowPosChanged || fVideoRectChanged)
    00792                 Paint(fWindowSizeChanged || fVideoRectChanged);
    00793 }
    00794
    00795 STDMETHODIMP_(void) ISubPicAllocatorPresenterImpl::SetTime(REFERENCE_TIME rtNow)
    00796 {
    00797         m_rtNow = rtNow;
    00798
    00799         if(m_pSubPicQueue)
    00800         {
    00801                 m_pSubPicQueue->SetTime(rtNow);
    00802         }
    00803 }
    00804
    00805 STDMETHODIMP_(double) ISubPicAllocatorPresenterImpl::GetFPS()
    00806 {
    00807         return(m_fps);
    00808 }
    00809
    00810 STDMETHODIMP_(void) ISubPicAllocatorPresenterImpl::SetSubPicProvider(ISubPicProvider* pSubPicProvider)
    00811 {
    00812         // CComPtr will make sure it gets destroyed even if it was passed
    00813         // here with 0 refcnt and m_pSubPicQueue->SetSubPicProvider fails
    00814         // to accept it.
    00815         CComPtr<ISubPicProvider> pSPP = pSubPicProvider;
    00816
    00817         if(m_pSubPicQueue)
    00818                 m_pSubPicQueue->SetSubPicProvider(pSPP); // pSPP == NULL is ok, we use it to empty the provider
    00819 }
    00820
    00821 STDMETHODIMP_(void) ISubPicAllocatorPresenterImpl::Invalidate(REFERENCE_TIME rtInvalidate)
    00822 {
    00823         if(m_pSubPicQueue)
    00824                 m_pSubPicQueue->Invalidate(rtInvalidate);
    00825 }
    00826
    00827 #include <math.h>
    00828
    00829 void ISubPicAllocatorPresenterImpl::Transform(CRect r, Vector v[4])
    00830 {
    00831         v[0] = Vector(r.left, r.top, 0);
    00832         v[1] = Vector(r.right, r.top, 0);
    00833         v[2] = Vector(r.left, r.bottom, 0);
    00834         v[3] = Vector(r.right, r.bottom, 0);
    00835
    00836         Vector center(r.CenterPoint().x, r.CenterPoint().y, 0);
    00837         int l = (int)(Vector(r.Size().cx, r.Size().cy, 0).Length()*1.5f)+1;
    00838
    00839         for(int i = 0; i < 4; i++)
    00840         {
    00841                 v[i] = m_xform << (v[i] - center);
    00842                 v[i].z = v[i].z / l + 0.5f;
    00843                 v[i].x /= v[i].z*2;
    00844                 v[i].y /= v[i].z*2;
    00845                 v[i] += center;
    00846         }
    00847 }
    00848
    00849 STDMETHODIMP ISubPicAllocatorPresenterImpl::SetVideoAngle(Vector v, bool fRepaint)
    00850 {
    00851         m_xform = XForm(Ray(Vector(0, 0, 0), v), Vector(1, 1, 1), false);
    00852         if(fRepaint) Paint(true);
    00853         return S_OK;
    00854 }