00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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
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
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
00150 return pfs ? *pfs = m_wndDestFrame.GetState(), S_OK : E_POINTER;
00151 }
00152
00153
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
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
00227 STDMETHODIMP CQuicktimeGraph::SetDestinationPosition(long Left, long Top, long Width, long Height)
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
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
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
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
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
00316
00317
00318
00319
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
00332 STDMETHODIMP_(engine_t) CQuicktimeGraph::GetEngine() {return QuickTime;}
00333
00334
00335
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
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
00369 WinEventToMacEvent(&theMsg, &macEvent);
00370
00371
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
00406
00407
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
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
00455 FSSpec sfFile;
00456 FSMakeFSSpec(0, 0L, (BYTE*)buff, &sfFile);
00457
00458
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,
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;
00505 bmi.bmiHeader.biWidth = m_size.cx;
00506 bmi.bmiHeader.biHeight = -m_size.cy;
00507 bmi.bmiHeader.biPlanes = 1;
00508 bmi.bmiHeader.biBitCount = 32;
00509
00510 bmi.bmiColors[0] = 0xff0000;
00511 bmi.bmiColors[1] = 0x00ff00;
00512 bmi.bmiColors[2] = 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);
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
00598 CreatePortAssociation(m_hWnd, NULL, 0);
00599 }
00600
00601 return 0;
00602 }
00603
00604 void CQuicktimeWindow::OnDestroy()
00605 {
00606 CPlayerWindow::OnDestroy();
00607
00608
00609 CloseMovie();
00610
00611 CComQIPtr<IQTVideoSurface> pQTVS = (IUnknown*)(INonDelegatingUnknown*)m_pGraph;
00612
00613 if(!pQTVS)
00614 {
00615
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
00641
00642
00643
00644
00645
00646
00647
00648 }
00649 }
00650
00651 __super::OnTimer(nIDEvent);
00652 }