- Main Page
- Namespaces
- Classes
- Files
- Directories

- File List
- File Members

# QuicktimeGraph.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 "QuicktimeGraph.h"
    00025 #include "IQTVideoSurface.h"
    00026 #include "mplayerc.h"
    00027 #include "..\..\DSUtil\DSUtil.h"
    00028
    00029 //
    00030 // CQuicktimeGraph
    00031 //
    00032
    00033 #pragma warning(disable:4355) // 'this' : used in base member initializer list
    00034
    00035 using namespace QT;
    00036
    00037 CQuicktimeGraph::CQuicktimeGraph(HWND hWndParent, HRESULT& hr)
    00038         : CBaseGraph()
    00039         , m_wndDestFrame(this)
    00040         , m_fQtInitialized(false)
    00041 {
    00042         hr = S_OK;
    00043
    00044         DWORD dwStyle = WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
    00045
    00046         AppSettings& s = AfxGetAppSettings();
    00047
    00048         if(s.iQTVideoRendererType == VIDRNDT_QT_DX7)
    00049         {
    00050                 if(SUCCEEDED(CreateAP7(CLSID_QT7AllocatorPresenter, hWndParent, &m_pQTAP)))
    00051                         dwStyle &= ~WS_VISIBLE;
    00052         }
    00053         else if(s.iQTVideoRendererType == VIDRNDT_QT_DX9)
    00054         {
    00055                 if(SUCCEEDED(CreateAP9(CLSID_QT9AllocatorPresenter, hWndParent, &m_pQTAP)))
    00056             dwStyle &= ~WS_VISIBLE;
    00057         }
    00058
    00059         m_fQtInitialized = false;
    00060         if(InitializeQTML(0) != 0) {hr = E_FAIL; return;}
    00061         if(EnterMovies() != 0) {TerminateQTML(); hr = E_FAIL; return;}
    00062         m_fQtInitialized = true;
    00063
    00064         if(!m_wndWindowFrame.CreateEx(WS_EX_NOPARENTNOTIFY, NULL, NULL, dwStyle, CRect(0, 0, 0, 0), CWnd::FromHandle(hWndParent), 0))
    00065         {
    00066                 hr = E_FAIL;
    00067                 return;
    00068         }
    00069
    00070         if(!m_wndDestFrame.Create(NULL, NULL, dwStyle, CRect(0, 0, 0, 0), &m_wndWindowFrame, 0))
    00071         {
    00072                 hr = E_FAIL;
    00073                 return;
    00074         }
    00075 }
    00076
    00077 CQuicktimeGraph::~CQuicktimeGraph()
    00078 {
    00079         m_wndDestFrame.DestroyWindow();
    00080         m_wndWindowFrame.DestroyWindow();
    00081
    00082         if(m_fQtInitialized)
    00083         {
    00084                 ExitMovies();
    00085                 TerminateQTML();
    00086         }
    00087 }
    00088
    00089 STDMETHODIMP CQuicktimeGraph::NonDelegatingQueryInterface(REFIID riid, void** ppv)
    00090 {
    00091     CheckPointer(ppv, E_POINTER);
    00092
    00093         return
    00094                 QI(IVideoFrameStep)
    00095                 (m_pQTAP && (riid == __uuidof(ISubPicAllocatorPresenter) || riid == __uuidof(IQTVideoSurface))) ? m_pQTAP->QueryInterface(riid, ppv) :
    00096                 __super::NonDelegatingQueryInterface(riid, ppv);
    00097 }
    00098
    00099 // IGraphBuilder
    00100 STDMETHODIMP CQuicktimeGraph::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList)
    00101 {
    00102         bool fRet = m_wndDestFrame.OpenMovie(CString(lpcwstrFile));
    00103
    00104         if(fRet)
    00105         {
    00106                 for(int i = 1, cnt = GetMovieTrackCount(m_wndDestFrame.theMovie); i <= cnt; i++)
    00107                 {
    00108                         Track aTrack = GetMovieIndTrack(m_wndDestFrame.theMovie, i);
    00109                         Media aMedia = GetTrackMedia(aTrack);
    00110
    00111                         OSType aTrackType;
    00112                         GetMediaHandlerDescription(aMedia, &aTrackType, 0, 0);
    00113                         if(aTrackType == SoundMediaType)
    00114                         {
    00115                                 SampleDescriptionHandle aDesc = (SampleDescriptionHandle)NewHandle(sizeof(aDesc));
    00116                                 GetMediaSampleDescription(aMedia, 1, aDesc);
    00117                                 if(GetMoviesError() == noErr)
    00118                                 {
    00119                                         SoundDescription& desc = **(SoundDescriptionHandle)aDesc;
    00120                                         NotifyEvent(EC_BG_AUDIO_CHANGED, desc.numChannels, 0);
    00121                                         i = cnt;
    00122                                 }
    00123                                 DisposeHandle((Handle)aDesc);
    00124                         }
    00125                 }
    00126         }
    00127
    00128         return fRet ? S_OK : E_FAIL;
    00129 }
    00130
    00131 // IMediaControl
    00132 STDMETHODIMP CQuicktimeGraph::Run()
    00133 {
    00134         m_wndDestFrame.Run();
    00135         return S_OK;
    00136 }
    00137 STDMETHODIMP CQuicktimeGraph::Pause()
    00138 {
    00139         m_wndDestFrame.Pause();
    00140         return S_OK;
    00141 }
    00142 STDMETHODIMP CQuicktimeGraph::Stop()
    00143 {
    00144         m_wndDestFrame.Stop();
    00145         return S_OK;
    00146 }
    00147 STDMETHODIMP CQuicktimeGraph::GetState(LONG msTimeout, OAFilterState* pfs)
    00148 {
    00149         // TODO: this seems to deadlock when opening from the net
    00150         return pfs ? *pfs = m_wndDestFrame.GetState(), S_OK : E_POINTER;
    00151 }
    00152
    00153 // IMediaSeeking
    00154 STDMETHODIMP CQuicktimeGraph::GetDuration(LONGLONG* pDuration)
    00155 {
    00156         CheckPointer(pDuration, E_POINTER);
    00157
    00158         *pDuration = 0;
    00159
    00160         if(!m_wndDestFrame.theMovie) return E_UNEXPECTED;
    00161
    00162         TimeScale ts = GetMovieTimeScale(m_wndDestFrame.theMovie);
    00163         if(ts == 0) return E_FAIL;
    00164
    00165         *pDuration = 10000i64*GetMovieDuration(m_wndDestFrame.theMovie)/ts*1000;
    00166
    00167         return S_OK;
    00168 }
    00169 STDMETHODIMP CQuicktimeGraph::GetCurrentPosition(LONGLONG* pCurrent)
    00170 {
    00171         CheckPointer(pCurrent, E_POINTER);
    00172
    00173         *pCurrent = 0;
    00174
    00175         if(!m_wndDestFrame.theMovie) return E_UNEXPECTED;
    00176
    00177         TimeScale ts = GetMovieTimeScale(m_wndDestFrame.theMovie);
    00178         if(ts == 0) return E_FAIL;
    00179
    00180         TimeRecord tr;
    00181         *pCurrent = 10000i64*GetMovieTime(m_wndDestFrame.theMovie, &tr)/ts*1000;
    00182
    00183         return S_OK;
    00184 }
    00185 STDMETHODIMP CQuicktimeGraph::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
    00186 {
    00187         CheckPointer(pCurrent, E_POINTER);
    00188
    00189         if(!(dwCurrentFlags&AM_SEEKING_AbsolutePositioning)) return E_INVALIDARG;
    00190
    00191         if(!m_wndDestFrame.theMovie) return E_UNEXPECTED;
    00192
    00193         TimeScale ts = GetMovieTimeScale(m_wndDestFrame.theMovie);
    00194         if(ts == 0) return E_FAIL;
    00195
    00196         SetMovieTimeValue(m_wndDestFrame.theMovie, (TimeValue)(*pCurrent*ts/1000/10000i64));
    00197
    00198         if(!m_wndDestFrame.theMC)
    00199         {
    00200                 UpdateMovie(m_wndDestFrame.theMovie);
    00201                 MoviesTask(m_wndDestFrame.theMovie, 0L);
    00202         }
    00203
    00204         return S_OK;
    00205 }
    00206 STDMETHODIMP CQuicktimeGraph::SetRate(double dRate)
    00207 {
    00208         return m_wndDestFrame.theMovie ? SetMovieRate(m_wndDestFrame.theMovie, (Fixed)(dRate * 0x10000)), S_OK : E_UNEXPECTED;
    00209 }
    00210 STDMETHODIMP CQuicktimeGraph::GetRate(double* pdRate)
    00211 {
    00212         CheckPointer(pdRate, E_POINTER);
    00213         *pdRate = 1.0;
    00214         return m_wndDestFrame.theMovie ? *pdRate = (double)GetMovieRate(m_wndDestFrame.theMovie) / 0x10000, S_OK : E_UNEXPECTED;
    00215 }
    00216
    00217 // IVideoWindow
    00218 STDMETHODIMP CQuicktimeGraph::SetWindowPosition(long Left, long Top, long Width, long Height)
    00219 {
    00220         if(IsWindow(m_wndWindowFrame.m_hWnd))
    00221                 m_wndWindowFrame.MoveWindow(Left, Top, Width, Height);
    00222
    00223         return S_OK;
    00224 }
    00225
    00226 // IBasicVideo
    00227 STDMETHODIMP CQuicktimeGraph::SetDestinationPosition(long Left, long Top, long Width, long Height)// {return E_NOTIMPL;}
    00228 {
    00229         if(!m_pQTAP && IsWindow(m_wndDestFrame.m_hWnd))
    00230         {
    00231                 m_wndDestFrame.MoveWindow(Left, Top, Width, Height);
    00232
    00233                 if(m_wndDestFrame.theMC)
    00234                 {
    00235                         Rect bounds = {0,0,(short)Height,(short)Width};
    00236                         MCPositionController(m_wndDestFrame.theMC, &bounds, NULL, mcTopLeftMovie|mcScaleMovieToFit);
    00237                 }
    00238         }
    00239
    00240         return S_OK;
    00241 }
    00242 STDMETHODIMP CQuicktimeGraph::GetVideoSize(long* pWidth, long* pHeight)
    00243 {
    00244         if(!pWidth || !pHeight) return E_POINTER;
    00245
    00246         *pWidth = m_wndDestFrame.m_size.cx;
    00247         *pHeight = m_wndDestFrame.m_size.cy;
    00248
    00249         return S_OK;
    00250 }
    00251
    00252 // IBasicAudio
    00253 STDMETHODIMP CQuicktimeGraph::put_Volume(long lVolume)
    00254 {
    00255         if(m_wndDestFrame.theMovie)
    00256         {
    00257                 lVolume = (lVolume == -10000) ? 0 : (int)pow(10.0, (double)lVolume/4152.41 + 2.41);
    00258                 SetMovieVolume(m_wndDestFrame.theMovie, (short)max(min(lVolume, 256), 0));
    00259                 return S_OK;
    00260         }
    00261
    00262         return E_UNEXPECTED;
    00263 }
    00264 STDMETHODIMP CQuicktimeGraph::get_Volume(long* plVolume)
    00265 {
    00266         CheckPointer(plVolume, E_POINTER);
    00267
    00268         if(m_wndDestFrame.theMovie)
    00269         {
    00270                 long lVolume = (long)GetMovieVolume(m_wndDestFrame.theMovie);
    00271                 *plVolume = (int)((log10(1.0*lVolume)-2.41)*4152.41);
    00272                 *plVolume = max(min(*plVolume, 0), -10000);
    00273                 return S_OK;
    00274         }
    00275
    00276         return E_UNEXPECTED;
    00277 }
    00278
    00279 // IVideoFrameStep
    00280 STDMETHODIMP CQuicktimeGraph::Step(DWORD dwFrames, IUnknown* pStepObject)
    00281 {
    00282         if(pStepObject) return E_INVALIDARG;
    00283         if(dwFrames == 0) return S_OK;
    00284         if(!m_wndDestFrame.theMovie) return E_UNEXPECTED;
    00285
    00286         // w/o m_wndDestFrame.theMC
    00287
    00288         OSType myTypes[] = {VisualMediaCharacteristic};
    00289         TimeValue myCurrTime = GetMovieTime(m_wndDestFrame.theMovie, NULL);
    00290         Fixed theRate = (int)dwFrames > 0 ? 0x00010000 : 0xffff0000;
    00291
    00292         for(int nSteps = abs((int)dwFrames); nSteps > 0; nSteps--)
    00293         {
    00294                 TimeValue myNextTime;
    00295                 GetMovieNextInterestingTime(m_wndDestFrame.theMovie, nextTimeStep, 1, myTypes, myCurrTime, theRate, &myNextTime, NULL);
    00296                 if(GetMoviesError() != noErr) return E_FAIL;
    00297                 myCurrTime = myNextTime;
    00298         }
    00299
    00300         if(myCurrTime >= 0 && myCurrTime < GetMovieDuration(m_wndDestFrame.theMovie))
    00301         {
    00302         SetMovieTimeValue(m_wndDestFrame.theMovie, myCurrTime);
    00303                 if(GetMoviesError() != noErr) return E_FAIL;
    00304                 // the rest is not needed when we also have m_wndDestFrame.theMC:
    00305                 UpdateMovie(m_wndDestFrame.theMovie);
    00306                 if(GetMoviesError() != noErr) return E_FAIL;
    00307                 MoviesTask(m_wndDestFrame.theMovie, 0L);
    00308         }
    00309
    00310         NotifyEvent(EC_STEP_COMPLETE);
    00311
    00312         return S_OK;
    00313
    00314 /*
    00315         // w/ m_wndDestFrame.theMC
    00316
    00317         short myStep = (short)(long)dwFrames;
    00318         return noErr == MCDoAction(m_wndDestFrame.theMC, mcActionStep, (Ptr)myStep)
    00319                 ? NotifyEvent(EC_STEP_COMPLETE), S_OK : E_FAIL;
    00320 */
    00321 }
    00322 STDMETHODIMP CQuicktimeGraph::CanStep(long bMultiple, IUnknown* pStepObject)
    00323 {
    00324         return m_wndDestFrame.theMovie ? S_OK : S_FALSE;
    00325 }
    00326 STDMETHODIMP CQuicktimeGraph::CancelStep()
    00327 {
    00328         return E_NOTIMPL;
    00329 }
    00330
    00331 // IGraphEngine
    00332 STDMETHODIMP_(engine_t) CQuicktimeGraph::GetEngine() {return QuickTime;}
    00333
    00334 //
    00335 // CQuicktimeWindow
    00336 //
    00337
    00338 CQuicktimeWindow::CQuicktimeWindow(CQuicktimeGraph* pGraph)
    00339         : m_pGraph(pGraph)
    00340         , theMovie(NULL)
    00341         , theMC(NULL)
    00342         , m_size(0, 0)
    00343         , m_idEndPoller(0)
    00344         , m_fs(State_Stopped)
    00345         , m_offscreenGWorld(NULL)
    00346 {
    00347 }
    00348
    00349 void CQuicktimeWindow::ProcessMovieEvent(unsigned int message, unsigned int wParam, long lParam)
    00350 {
    00351         if(message >= WM_MOUSEFIRST && message <= WM_MOUSELAST
    00352         || message >= WM_KEYFIRST && message <= WM_KEYLAST)
    00353                 return;
    00354
    00355         // Convert the Windows event to a QTML event
    00356         MSG                             theMsg;
    00357         EventRecord             macEvent;
    00358         LONG                    thePoints = GetMessagePos();
    00359
    00360         theMsg.hwnd = m_hWnd;
    00361         theMsg.message = message;
    00362         theMsg.wParam = wParam;
    00363         theMsg.lParam = lParam;
    00364         theMsg.time = GetMessageTime();
    00365         theMsg.pt.x = LOWORD(thePoints);
    00366         theMsg.pt.y = HIWORD(thePoints);
    00367
    00368         // tranlate a windows event to a mac event
    00369         WinEventToMacEvent(&theMsg, &macEvent);
    00370
    00371         // Pump messages as mac event
    00372         MCIsPlayerEvent(theMC, (const EventRecord*)&macEvent);
    00373 }
    00374
    00375 LRESULT CQuicktimeWindow::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    00376 {
    00377         if(message == WM_ERASEBKGND)
    00378         {
    00379                 LRESULT theResult = __super::WindowProc(message, wParam, lParam);
    00380                 ProcessMovieEvent(message, wParam, lParam);
    00381                 return theResult;
    00382         }
    00383         else
    00384         {
    00385                 ProcessMovieEvent(message, wParam, lParam);
    00386                 return __super::WindowProc(message, wParam, lParam);
    00387         }
    00388 }
    00389
    00390 OSErr CQuicktimeWindow::MyMovieDrawingCompleteProc(Movie theMovie, long refCon)
    00391 {
    00392         CQuicktimeWindow* pQW = (CQuicktimeWindow*)refCon;
    00393         if(!pQW) return noErr;
    00394
    00395         CQuicktimeGraph* pGraph = pQW->m_pGraph;
    00396         if(!pGraph) return noErr;
    00397
    00398         if(CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)pGraph)
    00399         {
    00400                 BITMAP bm;
    00401                 pQW->m_bm.GetObject(sizeof(bm), &bm);
    00402                 pQTVS->DoBlt(bm);
    00403         }
    00404         /*
    00405         else
    00406         {
    00407                 pQW->Invalidate();
    00408         }*/
    00409
    00410         return(noErr);
    00411 }
    00412
    00413 bool CQuicktimeWindow::OpenMovie(CString fn)
    00414 {
    00415         CloseMovie();
    00416
    00417         CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)m_pGraph;
    00418
    00419         if(!pQTVS)
    00420         {
    00421                 // Set the port
    00422                 SetGWorld((CGrafPtr)GetHWNDPort(m_hWnd), NULL);
    00423         }
    00424
    00425         if(fn.Find(_T("://")) > 0)
    00426         {
    00427                 Handle myHandle = NULL;
    00428                 Size mySize = fn.GetLength()+1;
    00429
    00430                 if(!(myHandle = NewHandleClear(mySize)))
    00431                         return(false);
    00432
    00433                 BlockMove((LPSTR)(LPCSTR)CStringA(fn), *myHandle, mySize);
    00434
    00435         OSErr err = NewMovieFromDataRef(&theMovie, newMovieActive, NULL, myHandle, URLDataHandlerSubType);
    00436
    00437                 DisposeHandle(myHandle);
    00438
    00439                 if(err != noErr) return(false);
    00440         }
    00441         else
    00442         {
    00443                 if(!(fn.GetLength() > 0 && fn.GetLength() < 255))
    00444                         return(false);
    00445
    00446                 CHAR buff[MAX_PATH] = {0, 0};
    00447 #ifdef UNICODE
    00448                 WideCharToMultiByte(GetACP(), 0, fn, -1, buff+1, MAX_PATH-1, 0, 0);
    00449 #else
    00450                 strcpy(buff+1, fn);
    00451 #endif
    00452                 buff[0] = strlen(buff+1);
    00453
    00454                 // Make a FSSpec with a pascal string filename
    00455                 FSSpec sfFile;
    00456                 FSMakeFSSpec(0, 0L, (BYTE*)buff, &sfFile);
    00457
    00458                 // Open the movie file
    00459                 short movieResFile;
    00460                 OSErr err = OpenMovieFile(&sfFile, &movieResFile, fsRdPerm);
    00461                 if(err == noErr)
    00462                 {
    00463                         err = NewMovieFromFile(&theMovie, movieResFile, 0, 0, newMovieActive, 0);
    00464                         CloseMovieFile(movieResFile);
    00465                 }
    00466                 if(err != noErr) return(false);
    00467         }
    00468
    00469         Rect rect;
    00470         GetMovieBox(theMovie, &rect);
    00471         MacOffsetRect(&rect, -rect.left, -rect.top);
    00472         SetMovieBox(theMovie, &rect);
    00473         m_size.SetSize(rect.right - rect.left, rect.bottom - rect.top);
    00474
    00475         Rect nrect;
    00476         GetMovieNaturalBoundsRect(theMovie, &nrect);
    00477
    00478         if(!pQTVS)
    00479         {
    00480                 theMC = NewMovieController(theMovie, &rect, mcTopLeftMovie|mcNotVisible);
    00481         }
    00482         else if(m_size.cx > 0 && m_size.cy > 0)
    00483         {
    00484                 SetMovieDrawingCompleteProc(theMovie,
    00485                         movieDrawingCallWhenChanged,//|movieDrawingCallAlways,
    00486                         MyMovieDrawingCompleteProc, (long)this);
    00487
    00488                 if(CDC* pDC = GetDC())
    00489                 {
    00490                         m_dc.CreateCompatibleDC(pDC);
    00491                         ReleaseDC(pDC);
    00492
    00493                         struct
    00494                         {
    00495                                 BITMAPINFOHEADER bmiHeader;
    00496                                 long bmiColors[256];
    00497                         } bmi;
    00498
    00499                         memset(&bmi, 0, sizeof(bmi));
    00500
    00501                         int bpp = m_dc.GetDeviceCaps(BITSPIXEL);
    00502
    00503                         bmi.bmiHeader.biSize            = sizeof(BITMAPINFOHEADER);
    00504                         bmi.bmiHeader.biCompression     = BI_BITFIELDS/*BI_RGB*/;
    00505                         bmi.bmiHeader.biWidth           = m_size.cx;
    00506                         bmi.bmiHeader.biHeight          = -m_size.cy;
    00507                         bmi.bmiHeader.biPlanes          = 1;
    00508                         bmi.bmiHeader.biBitCount        = 32/*bpp*/;
    00509
    00510                         bmi.bmiColors[0] = /*bpp == 16 ? 0xf800 :*/ 0xff0000;
    00511                         bmi.bmiColors[1] = /*bpp == 16 ? 0x07e0 :*/ 0x00ff00;
    00512                         bmi.bmiColors[2] = /*bpp == 16 ? 0x001f :*/ 0x0000ff;
    00513
    00514                         void* bits;
    00515                         m_bm.Attach(CreateDIBSection(m_dc, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, &bits, NULL, 0));
    00516
    00517                         QDErr err = NewGWorldFromHBITMAP(&m_offscreenGWorld, NULL, NULL, 0, m_bm.m_hObject, m_dc.m_hDC);
    00518
    00519                         SetMovieGWorld(theMovie, m_offscreenGWorld, GetGWorldDevice(m_offscreenGWorld));
    00520
    00521                         BITMAP bm;
    00522                         m_bm.GetObject(sizeof(bm), &bm);
    00523                         pQTVS->BeginBlt(bm);
    00524                 }
    00525         }
    00526
    00527         return(theMovie != NULL);
    00528 }
    00529
    00530 void CQuicktimeWindow::CloseMovie()
    00531 {
    00532         if(theMC) DisposeMovieController(theMC), theMC = NULL;
    00533         if(theMovie) DisposeMovie(theMovie), theMovie = NULL;
    00534         m_size.SetSize(0, 0);
    00535         m_fs = State_Stopped;
    00536
    00537         if(m_offscreenGWorld) DisposeGWorld(m_offscreenGWorld), m_offscreenGWorld = NULL;
    00538         m_dc.DeleteDC();
    00539         m_bm.DeleteObject();
    00540 }
    00541
    00542 void CQuicktimeWindow::Run()
    00543 {
    00544         if(theMovie)
    00545         {
    00546                 StartMovie(theMovie);
    00547                 if(!m_idEndPoller) m_idEndPoller = SetTimer(1, 10, NULL); // 10ms -> 100fps max
    00548         }
    00549
    00550         m_fs = State_Running;
    00551 }
    00552
    00553 void CQuicktimeWindow::Pause()
    00554 {
    00555         if(theMovie)
    00556         {
    00557                 StopMovie(theMovie);
    00558                 if(m_idEndPoller) KillTimer(m_idEndPoller), m_idEndPoller = 0;
    00559         }
    00560
    00561         m_fs = State_Paused;
    00562 }
    00563
    00564 void CQuicktimeWindow::Stop()
    00565 {
    00566         if(theMovie)
    00567         {
    00568                 StopMovie(theMovie);
    00569                 GoToBeginningOfMovie(theMovie);
    00570                 if(m_idEndPoller) KillTimer(m_idEndPoller), m_idEndPoller = 0;
    00571         }
    00572
    00573         m_fs = State_Stopped;
    00574 }
    00575
    00576 FILTER_STATE CQuicktimeWindow::GetState()
    00577 {
    00578         return m_fs;
    00579 }
    00580
    00581 BEGIN_MESSAGE_MAP(CQuicktimeWindow, CPlayerWindow)
    00582         ON_WM_CREATE()
    00583         ON_WM_DESTROY()
    00584         ON_WM_ERASEBKGND()
    00585         ON_WM_TIMER()
    00586 END_MESSAGE_MAP()
    00587
    00588 int CQuicktimeWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
    00589 {
    00590         if(__super::OnCreate(lpCreateStruct) == -1)
    00591                 return -1;
    00592
    00593         CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)m_pGraph;
    00594
    00595         if(!pQTVS)
    00596         {
    00597                 // Create GrafPort <-> HWND association
    00598                 CreatePortAssociation(m_hWnd, NULL, 0);
    00599         }
    00600
    00601         return 0;
    00602 }
    00603
    00604 void CQuicktimeWindow::OnDestroy()
    00605 {
    00606         CPlayerWindow::OnDestroy();
    00607
    00608         // close any movies     before destroying PortAssocation
    00609         CloseMovie();
    00610
    00611         CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)m_pGraph;
    00612
    00613         if(!pQTVS)
    00614         {
    00615                 // Destroy the view's GrafPort <-> HWND association
    00616                 if(m_hWnd)
    00617                         if(CGrafPtr windowPort = (CGrafPtr)GetHWNDPort(m_hWnd))
    00618                                 DestroyPortAssociation(windowPort);
    00619         }
    00620 }
    00621
    00622 BOOL CQuicktimeWindow::OnEraseBkgnd(CDC* pDC)
    00623 {
    00624         return m_fs != State_Stopped && theMovie ? TRUE : __super::OnEraseBkgnd(pDC);
    00625 }
    00626
    00627 void CQuicktimeWindow::OnTimer(UINT nIDEvent)
    00628 {
    00629         if(nIDEvent == m_idEndPoller && theMovie)
    00630         {
    00631                 if(IsMovieDone(theMovie))
    00632                 {
    00633                         Pause();
    00634                         m_pGraph->NotifyEvent(EC_COMPLETE);
    00635                 }
    00636                 else if(CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)m_pGraph)
    00637                 {
    00638             MoviesTask(theMovie, 0);
    00639 /*
    00640                         long duration = 0, scale = 1000;
    00641                         OSErr err = QTGetTimeUntilNextTask(&duration, scale);
    00642
    00643                         // err is 0 but still doesn't seem to work... returns duration=0 always
    00644                         TRACE(_T("%d\n"), duration);
    00645                         KillTimer(m_idEndPoller);
    00646                         m_idEndPoller = SetTimer(m_idEndPoller, duration, NULL);
    00647 */
    00648                 }
    00649         }
    00650
    00651         __super::OnTimer(nIDEvent);
    00652 }