QuicktimeGraph.cpp
上传用户:tangyu_668
上传日期:2014-02-27
资源大小:678k
文件大小:16k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /* 
  2.  * Copyright (C) 2003-2006 Gabest
  3.  * http://www.gabest.org
  4.  *
  5.  *  This Program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2, or (at your option)
  8.  *  any later version.
  9.  *   
  10.  *  This Program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13.  *  GNU General Public License for more details.
  14.  *   
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with GNU Make; see the file COPYING.  If not, write to
  17.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  18.  *  http://www.gnu.org/copyleft/gpl.html
  19.  *
  20.  */
  21. #include "stdafx.h"
  22. #include <math.h>
  23. #include "QuicktimeGraph.h"
  24. #include "IQTVideoSurface.h"
  25. #include "mplayerc.h"
  26. #include "....DSUtilDSUtil.h"
  27. //
  28. // CQuicktimeGraph
  29. //
  30. #pragma warning(disable:4355) // 'this' : used in base member initializer list
  31. using namespace QT;
  32. CQuicktimeGraph::CQuicktimeGraph(HWND hWndParent, HRESULT& hr)
  33. : CBaseGraph()
  34. , m_wndDestFrame(this)
  35. , m_fQtInitialized(false)
  36. {
  37. hr = S_OK;
  38. DWORD dwStyle = WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
  39. AppSettings& s = AfxGetAppSettings();
  40. if(s.iQTVideoRendererType == VIDRNDT_QT_DX7)
  41. {
  42. if(SUCCEEDED(CreateAP7(CLSID_QT7AllocatorPresenter, hWndParent, &m_pQTAP))) 
  43. dwStyle &= ~WS_VISIBLE;
  44. }
  45. else if(s.iQTVideoRendererType == VIDRNDT_QT_DX9)
  46. {
  47. if(SUCCEEDED(CreateAP9(CLSID_QT9AllocatorPresenter, hWndParent, &m_pQTAP))) 
  48.             dwStyle &= ~WS_VISIBLE;
  49. }
  50. m_fQtInitialized = false;
  51. if(InitializeQTML(0) != 0) {hr = E_FAIL; return;}
  52. if(EnterMovies() != 0) {TerminateQTML(); hr = E_FAIL; return;}
  53. m_fQtInitialized = true;
  54. if(!m_wndWindowFrame.CreateEx(WS_EX_NOPARENTNOTIFY, NULL, NULL, dwStyle, CRect(0, 0, 0, 0), CWnd::FromHandle(hWndParent), 0))
  55. {
  56. hr = E_FAIL;
  57. return;
  58. }
  59. if(!m_wndDestFrame.Create(NULL, NULL, dwStyle, CRect(0, 0, 0, 0), &m_wndWindowFrame, 0))
  60. {
  61. hr = E_FAIL;
  62. return;
  63. }
  64. }
  65. CQuicktimeGraph::~CQuicktimeGraph()
  66. {
  67. m_wndDestFrame.DestroyWindow();
  68. m_wndWindowFrame.DestroyWindow();
  69. if(m_fQtInitialized)
  70. {
  71. ExitMovies();
  72. TerminateQTML();
  73. }
  74. }
  75. STDMETHODIMP CQuicktimeGraph::NonDelegatingQueryInterface(REFIID riid, void** ppv)
  76. {
  77.     CheckPointer(ppv, E_POINTER);
  78. return 
  79. QI(IVideoFrameStep)
  80. (m_pQTAP && (riid == __uuidof(ISubPicAllocatorPresenter) || riid == __uuidof(IQTVideoSurface))) ? m_pQTAP->QueryInterface(riid, ppv) : 
  81. __super::NonDelegatingQueryInterface(riid, ppv);
  82. }
  83. // IGraphBuilder
  84. STDMETHODIMP CQuicktimeGraph::RenderFile(LPCWSTR lpcwstrFile, LPCWSTR lpcwstrPlayList)
  85. {
  86. bool fRet = m_wndDestFrame.OpenMovie(CString(lpcwstrFile));
  87. if(fRet)
  88. {
  89. for(int i = 1, cnt = GetMovieTrackCount(m_wndDestFrame.theMovie); i <= cnt; i++)
  90. {
  91. Track aTrack = GetMovieIndTrack(m_wndDestFrame.theMovie, i);
  92. Media aMedia = GetTrackMedia(aTrack);
  93. OSType aTrackType;
  94. GetMediaHandlerDescription(aMedia, &aTrackType, 0, 0);
  95. if(aTrackType == SoundMediaType)
  96. {
  97. SampleDescriptionHandle aDesc = (SampleDescriptionHandle)NewHandle(sizeof(aDesc));
  98. GetMediaSampleDescription(aMedia, 1, aDesc);
  99. if(GetMoviesError() == noErr)
  100. {
  101. SoundDescription& desc = **(SoundDescriptionHandle)aDesc;
  102. NotifyEvent(EC_BG_AUDIO_CHANGED, desc.numChannels, 0);
  103. i = cnt;
  104. }
  105. DisposeHandle((Handle)aDesc);
  106. }
  107. }
  108. }
  109. return fRet ? S_OK : E_FAIL;
  110. }
  111. // IMediaControl
  112. STDMETHODIMP CQuicktimeGraph::Run()
  113. {
  114. m_wndDestFrame.Run();
  115. return S_OK;
  116. }
  117. STDMETHODIMP CQuicktimeGraph::Pause()
  118. {
  119. m_wndDestFrame.Pause();
  120. return S_OK;
  121. }
  122. STDMETHODIMP CQuicktimeGraph::Stop()
  123. {
  124. m_wndDestFrame.Stop();
  125. return S_OK;
  126. }
  127. STDMETHODIMP CQuicktimeGraph::GetState(LONG msTimeout, OAFilterState* pfs)
  128. {
  129. // TODO: this seems to deadlock when opening from the net
  130. return pfs ? *pfs = m_wndDestFrame.GetState(), S_OK : E_POINTER;
  131. }
  132. // IMediaSeeking
  133. STDMETHODIMP CQuicktimeGraph::GetDuration(LONGLONG* pDuration)
  134. {
  135. CheckPointer(pDuration, E_POINTER);
  136. *pDuration = 0;
  137. if(!m_wndDestFrame.theMovie) return E_UNEXPECTED;
  138. TimeScale ts = GetMovieTimeScale(m_wndDestFrame.theMovie);
  139. if(ts == 0) return E_FAIL;
  140. *pDuration = 10000i64*GetMovieDuration(m_wndDestFrame.theMovie)/ts*1000;
  141. return S_OK;
  142. }
  143. STDMETHODIMP CQuicktimeGraph::GetCurrentPosition(LONGLONG* pCurrent)
  144. {
  145. CheckPointer(pCurrent, E_POINTER);
  146. *pCurrent = 0;
  147. if(!m_wndDestFrame.theMovie) return E_UNEXPECTED;
  148. TimeScale ts = GetMovieTimeScale(m_wndDestFrame.theMovie);
  149. if(ts == 0) return E_FAIL;
  150. TimeRecord tr;
  151. *pCurrent = 10000i64*GetMovieTime(m_wndDestFrame.theMovie, &tr)/ts*1000;
  152. return S_OK;
  153. }
  154. STDMETHODIMP CQuicktimeGraph::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
  155. {
  156. CheckPointer(pCurrent, E_POINTER);
  157. if(!(dwCurrentFlags&AM_SEEKING_AbsolutePositioning)) return E_INVALIDARG;
  158. if(!m_wndDestFrame.theMovie) return E_UNEXPECTED;
  159. TimeScale ts = GetMovieTimeScale(m_wndDestFrame.theMovie);
  160. if(ts == 0) return E_FAIL;
  161. SetMovieTimeValue(m_wndDestFrame.theMovie, (TimeValue)(*pCurrent*ts/1000/10000i64));
  162. if(!m_wndDestFrame.theMC) 
  163. {
  164. UpdateMovie(m_wndDestFrame.theMovie);
  165. MoviesTask(m_wndDestFrame.theMovie, 0L);
  166. }
  167. return S_OK;
  168. }
  169. STDMETHODIMP CQuicktimeGraph::SetRate(double dRate)
  170. {
  171. return m_wndDestFrame.theMovie ? SetMovieRate(m_wndDestFrame.theMovie, (Fixed)(dRate * 0x10000)), S_OK : E_UNEXPECTED;
  172. }
  173. STDMETHODIMP CQuicktimeGraph::GetRate(double* pdRate)
  174. {
  175. CheckPointer(pdRate, E_POINTER);
  176. *pdRate = 1.0;
  177. return m_wndDestFrame.theMovie ? *pdRate = (double)GetMovieRate(m_wndDestFrame.theMovie) / 0x10000, S_OK : E_UNEXPECTED;
  178. }
  179. // IVideoWindow
  180. STDMETHODIMP CQuicktimeGraph::SetWindowPosition(long Left, long Top, long Width, long Height)
  181. {
  182. if(IsWindow(m_wndWindowFrame.m_hWnd))
  183. m_wndWindowFrame.MoveWindow(Left, Top, Width, Height);
  184. return S_OK;
  185. }
  186. // IBasicVideo
  187. STDMETHODIMP CQuicktimeGraph::SetDestinationPosition(long Left, long Top, long Width, long Height)// {return E_NOTIMPL;}
  188. {
  189. if(!m_pQTAP && IsWindow(m_wndDestFrame.m_hWnd))
  190. {
  191. m_wndDestFrame.MoveWindow(Left, Top, Width, Height);
  192. if(m_wndDestFrame.theMC)
  193. {
  194. Rect bounds = {0,0,(short)Height,(short)Width};
  195. MCPositionController(m_wndDestFrame.theMC, &bounds, NULL, mcTopLeftMovie|mcScaleMovieToFit);
  196. }
  197. }
  198. return S_OK;
  199. }
  200. STDMETHODIMP CQuicktimeGraph::GetVideoSize(long* pWidth, long* pHeight)
  201. {
  202. if(!pWidth || !pHeight) return E_POINTER;
  203. *pWidth = m_wndDestFrame.m_size.cx;
  204. *pHeight = m_wndDestFrame.m_size.cy;
  205. return S_OK;
  206. }
  207. // IBasicAudio
  208. STDMETHODIMP CQuicktimeGraph::put_Volume(long lVolume)
  209. {
  210. if(m_wndDestFrame.theMovie)
  211. {
  212. lVolume = (lVolume == -10000) ? 0 : (int)pow(10.0, (double)lVolume/4152.41 + 2.41);
  213. SetMovieVolume(m_wndDestFrame.theMovie, (short)max(min(lVolume, 256), 0));
  214. return S_OK;
  215. }
  216. return E_UNEXPECTED;
  217. }
  218. STDMETHODIMP CQuicktimeGraph::get_Volume(long* plVolume)
  219. {
  220. CheckPointer(plVolume, E_POINTER);
  221. if(m_wndDestFrame.theMovie)
  222. {
  223. long lVolume = (long)GetMovieVolume(m_wndDestFrame.theMovie);
  224. *plVolume = (int)((log10(1.0*lVolume)-2.41)*4152.41);
  225. *plVolume = max(min(*plVolume, 0), -10000);
  226. return S_OK;
  227. }
  228. return E_UNEXPECTED;
  229. }
  230. // IVideoFrameStep
  231. STDMETHODIMP CQuicktimeGraph::Step(DWORD dwFrames, IUnknown* pStepObject)
  232. {
  233. if(pStepObject) return E_INVALIDARG;
  234. if(dwFrames == 0) return S_OK;
  235. if(!m_wndDestFrame.theMovie) return E_UNEXPECTED;
  236. // w/o m_wndDestFrame.theMC
  237. OSType myTypes[] = {VisualMediaCharacteristic};
  238. TimeValue myCurrTime = GetMovieTime(m_wndDestFrame.theMovie, NULL);
  239. Fixed theRate = (int)dwFrames > 0 ? 0x00010000 : 0xffff0000;
  240. for(int nSteps = abs((int)dwFrames); nSteps > 0; nSteps--)
  241. {
  242. TimeValue myNextTime;
  243. GetMovieNextInterestingTime(m_wndDestFrame.theMovie, nextTimeStep, 1, myTypes, myCurrTime, theRate, &myNextTime, NULL);
  244. if(GetMoviesError() != noErr) return E_FAIL;
  245. myCurrTime = myNextTime;
  246. }
  247. if(myCurrTime >= 0 && myCurrTime < GetMovieDuration(m_wndDestFrame.theMovie))
  248. {
  249.         SetMovieTimeValue(m_wndDestFrame.theMovie, myCurrTime);
  250. if(GetMoviesError() != noErr) return E_FAIL;
  251. // the rest is not needed when we also have m_wndDestFrame.theMC:
  252. UpdateMovie(m_wndDestFrame.theMovie);
  253. if(GetMoviesError() != noErr) return E_FAIL;
  254. MoviesTask(m_wndDestFrame.theMovie, 0L);
  255. }
  256. NotifyEvent(EC_STEP_COMPLETE);
  257. return S_OK;
  258. /*
  259. // w/ m_wndDestFrame.theMC
  260. short myStep = (short)(long)dwFrames;
  261. return noErr == MCDoAction(m_wndDestFrame.theMC, mcActionStep, (Ptr)myStep)
  262. ? NotifyEvent(EC_STEP_COMPLETE), S_OK : E_FAIL;
  263. */
  264. }
  265. STDMETHODIMP CQuicktimeGraph::CanStep(long bMultiple, IUnknown* pStepObject)
  266. {
  267. return m_wndDestFrame.theMovie ? S_OK : S_FALSE;
  268. }
  269. STDMETHODIMP CQuicktimeGraph::CancelStep()
  270. {
  271. return E_NOTIMPL;
  272. }
  273. // IGraphEngine
  274. STDMETHODIMP_(engine_t) CQuicktimeGraph::GetEngine() {return QuickTime;}
  275. //
  276. // CQuicktimeWindow
  277. //
  278. CQuicktimeWindow::CQuicktimeWindow(CQuicktimeGraph* pGraph)
  279. : m_pGraph(pGraph)
  280. , theMovie(NULL)
  281. , theMC(NULL)
  282. , m_size(0, 0)
  283. , m_idEndPoller(0)
  284. , m_fs(State_Stopped)
  285. , m_offscreenGWorld(NULL)
  286. {
  287. }
  288. void CQuicktimeWindow::ProcessMovieEvent(unsigned int message, unsigned int wParam, long lParam) 
  289. {
  290. if(message >= WM_MOUSEFIRST && message <= WM_MOUSELAST
  291. || message >= WM_KEYFIRST && message <= WM_KEYLAST)
  292. return;
  293. // Convert the Windows event to a QTML event
  294. MSG theMsg;
  295. EventRecord macEvent;
  296. LONG thePoints = GetMessagePos();
  297. theMsg.hwnd = m_hWnd;
  298. theMsg.message = message;
  299. theMsg.wParam = wParam;
  300. theMsg.lParam = lParam;
  301. theMsg.time = GetMessageTime();
  302. theMsg.pt.x = LOWORD(thePoints);
  303. theMsg.pt.y = HIWORD(thePoints);
  304. // tranlate a windows event to a mac event
  305. WinEventToMacEvent(&theMsg, &macEvent);
  306. // Pump messages as mac event
  307. MCIsPlayerEvent(theMC, (const EventRecord*)&macEvent);
  308. }
  309. LRESULT CQuicktimeWindow::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
  310. {
  311. if(message == WM_ERASEBKGND)
  312. {
  313. LRESULT theResult = __super::WindowProc(message, wParam, lParam);
  314. ProcessMovieEvent(message, wParam, lParam);
  315. return theResult;
  316. }
  317. else
  318. {
  319. ProcessMovieEvent(message, wParam, lParam);
  320. return __super::WindowProc(message, wParam, lParam);
  321. }
  322. }
  323. OSErr CQuicktimeWindow::MyMovieDrawingCompleteProc(Movie theMovie, long refCon)
  324. {
  325. CQuicktimeWindow* pQW = (CQuicktimeWindow*)refCon;
  326. if(!pQW) return noErr;
  327. CQuicktimeGraph* pGraph = pQW->m_pGraph;
  328. if(!pGraph) return noErr;
  329. if(CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)pGraph)
  330. {
  331. BITMAP bm;
  332. pQW->m_bm.GetObject(sizeof(bm), &bm);
  333. pQTVS->DoBlt(bm);
  334. }
  335. /*
  336. else
  337. {
  338. pQW->Invalidate();
  339. }*/
  340. return(noErr);
  341. }
  342. bool CQuicktimeWindow::OpenMovie(CString fn)
  343. {
  344. CloseMovie();
  345. CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)m_pGraph;
  346. if(!pQTVS)
  347. {
  348. // Set the port
  349. SetGWorld((CGrafPtr)GetHWNDPort(m_hWnd), NULL);
  350. }
  351. if(fn.Find(_T("://")) > 0)
  352. {
  353. Handle myHandle = NULL;
  354. Size mySize = fn.GetLength()+1;
  355. if(!(myHandle = NewHandleClear(mySize)))
  356. return(false);
  357. BlockMove((LPSTR)(LPCSTR)CStringA(fn), *myHandle, mySize);
  358.         OSErr err = NewMovieFromDataRef(&theMovie, newMovieActive, NULL, myHandle, URLDataHandlerSubType);
  359. DisposeHandle(myHandle);
  360. if(err != noErr) return(false);
  361. }
  362. else
  363. {
  364. if(!(fn.GetLength() > 0 && fn.GetLength() < 255))
  365. return(false);
  366. CHAR buff[MAX_PATH] = {0, 0};
  367. #ifdef UNICODE
  368. WideCharToMultiByte(GetACP(), 0, fn, -1, buff+1, MAX_PATH-1, 0, 0);
  369. #else
  370. strcpy(buff+1, fn);
  371. #endif
  372. buff[0] = strlen(buff+1);
  373. // Make a FSSpec with a pascal string filename
  374. FSSpec sfFile;
  375. FSMakeFSSpec(0, 0L, (BYTE*)buff, &sfFile);
  376. // Open the movie file
  377. short movieResFile;
  378. OSErr err = OpenMovieFile(&sfFile, &movieResFile, fsRdPerm);
  379. if(err == noErr)
  380. {
  381. err = NewMovieFromFile(&theMovie, movieResFile, 0, 0, newMovieActive, 0);
  382. CloseMovieFile(movieResFile);
  383. }
  384. if(err != noErr) return(false);
  385. }
  386. Rect rect;
  387. GetMovieBox(theMovie, &rect);
  388. MacOffsetRect(&rect, -rect.left, -rect.top);
  389. SetMovieBox(theMovie, &rect);
  390. m_size.SetSize(rect.right - rect.left, rect.bottom - rect.top);
  391. Rect nrect;
  392. GetMovieNaturalBoundsRect(theMovie, &nrect);
  393. if(!pQTVS)
  394. {
  395. theMC = NewMovieController(theMovie, &rect, mcTopLeftMovie|mcNotVisible);
  396. }
  397. else if(m_size.cx > 0 && m_size.cy > 0)
  398. {
  399. SetMovieDrawingCompleteProc(theMovie, 
  400. movieDrawingCallWhenChanged,//|movieDrawingCallAlways, 
  401. MyMovieDrawingCompleteProc, (long)this);
  402. if(CDC* pDC = GetDC())
  403. {
  404. m_dc.CreateCompatibleDC(pDC);
  405. ReleaseDC(pDC);
  406. struct
  407. {   
  408. BITMAPINFOHEADER bmiHeader;
  409. long bmiColors[256];
  410. } bmi;
  411. memset(&bmi, 0, sizeof(bmi));
  412. int bpp = m_dc.GetDeviceCaps(BITSPIXEL);
  413. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  414. bmi.bmiHeader.biCompression = BI_BITFIELDS/*BI_RGB*/;
  415. bmi.bmiHeader.biWidth = m_size.cx;
  416. bmi.bmiHeader.biHeight = -m_size.cy;
  417. bmi.bmiHeader.biPlanes = 1;
  418. bmi.bmiHeader.biBitCount = 32/*bpp*/;
  419. bmi.bmiColors[0] = /*bpp == 16 ? 0xf800 :*/ 0xff0000;
  420. bmi.bmiColors[1] = /*bpp == 16 ? 0x07e0 :*/ 0x00ff00;
  421. bmi.bmiColors[2] = /*bpp == 16 ? 0x001f :*/ 0x0000ff;
  422. void* bits;
  423. m_bm.Attach(CreateDIBSection(m_dc, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, &bits, NULL, 0));
  424. QDErr err = NewGWorldFromHBITMAP(&m_offscreenGWorld, NULL, NULL, 0, m_bm.m_hObject, m_dc.m_hDC);
  425. SetMovieGWorld(theMovie, m_offscreenGWorld, GetGWorldDevice(m_offscreenGWorld));
  426. BITMAP bm;
  427. m_bm.GetObject(sizeof(bm), &bm);
  428. pQTVS->BeginBlt(bm);
  429. }
  430. }
  431. return(theMovie != NULL);
  432. }
  433. void CQuicktimeWindow::CloseMovie()
  434. {
  435. if(theMC) DisposeMovieController(theMC), theMC = NULL;
  436. if(theMovie) DisposeMovie(theMovie), theMovie = NULL;
  437. m_size.SetSize(0, 0);
  438. m_fs = State_Stopped;
  439. if(m_offscreenGWorld) DisposeGWorld(m_offscreenGWorld), m_offscreenGWorld = NULL;
  440. m_dc.DeleteDC();
  441. m_bm.DeleteObject();
  442. }
  443. void CQuicktimeWindow::Run()
  444. {
  445. if(theMovie)
  446. {
  447. StartMovie(theMovie);
  448. if(!m_idEndPoller) m_idEndPoller = SetTimer(1, 10, NULL); // 10ms -> 100fps max
  449. }
  450. m_fs = State_Running;
  451. }
  452. void CQuicktimeWindow::Pause()
  453. {
  454. if(theMovie)
  455. {
  456. StopMovie(theMovie);
  457. if(m_idEndPoller) KillTimer(m_idEndPoller), m_idEndPoller = 0;
  458. }
  459. m_fs = State_Paused;
  460. }
  461. void CQuicktimeWindow::Stop()
  462. {
  463. if(theMovie)
  464. {
  465. StopMovie(theMovie);
  466. GoToBeginningOfMovie(theMovie);
  467. if(m_idEndPoller) KillTimer(m_idEndPoller), m_idEndPoller = 0;
  468. }
  469. m_fs = State_Stopped;
  470. }
  471. FILTER_STATE CQuicktimeWindow::GetState()
  472. {
  473. return m_fs;
  474. }
  475. BEGIN_MESSAGE_MAP(CQuicktimeWindow, CPlayerWindow)
  476. ON_WM_CREATE()
  477. ON_WM_DESTROY()
  478. ON_WM_ERASEBKGND()
  479. ON_WM_TIMER()
  480. END_MESSAGE_MAP()
  481. int CQuicktimeWindow::OnCreate(LPCREATESTRUCT lpCreateStruct)
  482. {
  483. if(__super::OnCreate(lpCreateStruct) == -1)
  484. return -1;
  485. CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)m_pGraph;
  486. if(!pQTVS)
  487. {
  488. // Create GrafPort <-> HWND association
  489. CreatePortAssociation(m_hWnd, NULL, 0);
  490. }
  491. return 0;
  492. }
  493. void CQuicktimeWindow::OnDestroy()
  494. {
  495. CPlayerWindow::OnDestroy();
  496. // close any movies before destroying PortAssocation
  497. CloseMovie();
  498. CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)m_pGraph;
  499. if(!pQTVS)
  500. {
  501. // Destroy the view's GrafPort <-> HWND association
  502. if(m_hWnd)
  503. if(CGrafPtr windowPort = (CGrafPtr)GetHWNDPort(m_hWnd))
  504. DestroyPortAssociation(windowPort);
  505. }
  506. }
  507. BOOL CQuicktimeWindow::OnEraseBkgnd(CDC* pDC)
  508. {
  509. return m_fs != State_Stopped && theMovie ? TRUE : __super::OnEraseBkgnd(pDC);
  510. }
  511. void CQuicktimeWindow::OnTimer(UINT nIDEvent)
  512. {
  513. if(nIDEvent == m_idEndPoller && theMovie)
  514. {
  515. if(IsMovieDone(theMovie))
  516. {
  517. Pause();
  518. m_pGraph->NotifyEvent(EC_COMPLETE);
  519. }
  520. else if(CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)m_pGraph)
  521. {
  522.             MoviesTask(theMovie, 0);
  523. /*
  524. long duration = 0, scale = 1000;
  525. OSErr err = QTGetTimeUntilNextTask(&duration, scale);
  526. // err is 0 but still doesn't seem to work... returns duration=0 always
  527. TRACE(_T("%dn"), duration);
  528. KillTimer(m_idEndPoller);
  529. m_idEndPoller = SetTimer(m_idEndPoller, duration, NULL);
  530. */
  531. }
  532. }
  533. __super::OnTimer(nIDEvent);
  534. }