1///////////////////////////////////////////////////////////////////////////// 2// Name: src/msw/mediactrl_qt.cpp 3// Purpose: QuickTime Media Backend for Windows 4// Author: Ryan Norton <wxprojects@comcast.net> 5// Modified by: Robin Dunn (moved QT code from mediactrl.cpp) 6// 7// Created: 11/07/04 8// RCS-ID: $Id: mediactrl_qt.cpp 45498 2007-04-16 13:03:05Z VZ $ 9// Copyright: (c) Ryan Norton 10// Licence: wxWindows licence 11///////////////////////////////////////////////////////////////////////////// 12 13 14//=========================================================================== 15// DECLARATIONS 16//=========================================================================== 17 18//--------------------------------------------------------------------------- 19// Pre-compiled header stuff 20//--------------------------------------------------------------------------- 21 22// For compilers that support precompilation, includes "wx.h". 23#include "wx/wxprec.h" 24 25#ifdef __BORLANDC__ 26 #pragma hdrstop 27#endif 28 29#if wxUSE_MEDIACTRL 30 31#include "wx/mediactrl.h" 32 33#ifndef WX_PRECOMP 34 #include "wx/log.h" 35 #include "wx/dcclient.h" 36 #include "wx/timer.h" 37 #include "wx/math.h" // log10 & pow 38#endif 39 40#include "wx/msw/private.h" // user info and wndproc setting/getting 41#include "wx/dynlib.h" 42 43//--------------------------------------------------------------------------- 44// Externals (somewhere in src/msw/app.cpp and src/msw/window.cpp) 45//--------------------------------------------------------------------------- 46extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance(void); 47#ifdef __WXWINCE__ 48extern WXDLLIMPEXP_CORE wxChar *wxCanvasClassName; 49#else 50extern WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName; 51#endif 52 53LRESULT WXDLLIMPEXP_CORE APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message, 54 WPARAM wParam, LPARAM lParam); 55 56//--------------------------------------------------------------------------- 57// Killed MSVC warnings 58//--------------------------------------------------------------------------- 59//disable "cast truncates constant value" for VARIANT_BOOL values 60//passed as parameters in VC5 and up 61#ifdef _MSC_VER 62#pragma warning (disable:4310) 63#endif 64 65 66//--------------------------------------------------------------------------- 67// wxQTMediaBackend 68// 69// We don't include Quicktime headers here and define all the types 70// ourselves because looking for the quicktime libaries etc. would 71// be tricky to do and making this a dependency for the MSVC projects 72// would be unrealistic. 73// 74// Thanks to Robert Roebling for the wxDL macro/library idea 75//--------------------------------------------------------------------------- 76 77//--------------------------------------------------------------------------- 78// QT Includes 79//--------------------------------------------------------------------------- 80//#include <qtml.h> // Windoze QT include 81//#include <QuickTimeComponents.h> // Standard QT stuff 82#include "wx/dynlib.h" 83 84//--------------------------------------------------------------------------- 85// QT Types 86//--------------------------------------------------------------------------- 87typedef struct MovieRecord* Movie; 88typedef wxInt16 OSErr; 89typedef wxInt32 OSStatus; 90#define noErr 0 91#define fsRdPerm 1 92typedef unsigned char Str255[256]; 93#define StringPtr unsigned char* 94#define newMovieActive 1 95#define newMovieAsyncOK (1 << 8) 96#define Ptr char* 97#define Handle Ptr* 98#define Fixed long 99#define OSType unsigned long 100#define CGrafPtr struct GrafPort * 101#define TimeScale long 102#define TimeBase struct TimeBaseRecord * 103typedef struct ComponentInstanceRecord * ComponentInstance; 104#define kMovieLoadStatePlayable 10000 105#define Boolean int 106#define MovieController ComponentInstance 107 108#ifndef URLDataHandlerSubType 109#if defined(__WATCOMC__) || defined(__MINGW32__) 110// use magic numbers for compilers which complain about multicharacter integers 111const OSType URLDataHandlerSubType = 1970433056; 112const OSType VisualMediaCharacteristic = 1702454643; 113#else 114const OSType URLDataHandlerSubType = 'url '; 115const OSType VisualMediaCharacteristic = 'eyes'; 116#endif 117#endif 118 119struct FSSpec 120{ 121 short vRefNum; 122 long parID; 123 Str255 name; // Str63 on mac, Str255 on msw 124}; 125 126struct Rect 127{ 128 short top; 129 short left; 130 short bottom; 131 short right; 132}; 133 134struct wide 135{ 136 wxInt32 hi; 137 wxUint32 lo; 138}; 139 140struct TimeRecord 141{ 142 wide value; // units 143 TimeScale scale; // units per second 144 TimeBase base; 145}; 146 147struct Point 148{ 149 short v; 150 short h; 151}; 152 153struct EventRecord 154{ 155 wxUint16 what; 156 wxUint32 message; 157 wxUint32 when; 158 Point where; 159 wxUint16 modifiers; 160}; 161 162enum 163{ 164 mcTopLeftMovie = 1, 165 mcScaleMovieToFit = 2, 166 mcWithBadge = 4, 167 mcNotVisible = 8, 168 mcWithFrame = 16 169}; 170 171//--------------------------------------------------------------------------- 172// QT Library 173//--------------------------------------------------------------------------- 174#define wxDL_METHOD_DEFINE( rettype, name, args, shortargs, defret ) \ 175 typedef rettype (* name ## Type) args ; \ 176 name ## Type pfn_ ## name; \ 177 rettype name args \ 178 { if (m_ok) return pfn_ ## name shortargs ; return defret; } 179 180#define wxDL_VOIDMETHOD_DEFINE( name, args, shortargs ) \ 181 typedef void (* name ## Type) args ; \ 182 name ## Type pfn_ ## name; \ 183 void name args \ 184 { if (m_ok) pfn_ ## name shortargs ; } 185 186#define wxDL_METHOD_LOAD( lib, name, success ) \ 187 pfn_ ## name = (name ## Type) lib.GetSymbol( wxT(#name), &success ); \ 188 if (!success) return false 189 190 191class WXDLLIMPEXP_MEDIA wxQuickTimeLibrary 192{ 193public: 194 ~wxQuickTimeLibrary() 195 { 196 if (m_dll.IsLoaded()) 197 m_dll.Unload(); 198 } 199 200 bool Initialize(); 201 bool IsOk() const {return m_ok;} 202 203protected: 204 wxDynamicLibrary m_dll; 205 bool m_ok; 206 207public: 208 wxDL_VOIDMETHOD_DEFINE( StartMovie, (Movie m), (m) ) 209 wxDL_VOIDMETHOD_DEFINE( StopMovie, (Movie m), (m) ) 210 wxDL_METHOD_DEFINE( bool, IsMovieDone, (Movie m), (m), false) 211 wxDL_VOIDMETHOD_DEFINE( GoToBeginningOfMovie, (Movie m), (m) ) 212 wxDL_METHOD_DEFINE( OSErr, GetMoviesError, (), (), -1) 213 wxDL_METHOD_DEFINE( OSErr, EnterMovies, (), (), -1) 214 wxDL_VOIDMETHOD_DEFINE( ExitMovies, (), () ) 215 wxDL_METHOD_DEFINE( OSErr, InitializeQTML, (long flags), (flags), -1) 216 wxDL_VOIDMETHOD_DEFINE( TerminateQTML, (), () ) 217 218 wxDL_METHOD_DEFINE( OSErr, NativePathNameToFSSpec, 219 (char* inName, FSSpec* outFile, long flags), 220 (inName, outFile, flags), -1) 221 222 wxDL_METHOD_DEFINE( OSErr, OpenMovieFile, 223 (const FSSpec * fileSpec, short * resRefNum, wxInt8 permission), 224 (fileSpec, resRefNum, permission), -1 ) 225 226 wxDL_METHOD_DEFINE( OSErr, CloseMovieFile, 227 (short resRefNum), (resRefNum), -1) 228 229 wxDL_METHOD_DEFINE( OSErr, NewMovieFromFile, 230 (Movie * theMovie, short resRefNum, short * resId, 231 StringPtr resName, short newMovieFlags, 232 bool * dataRefWasChanged), 233 (theMovie, resRefNum, resId, resName, newMovieFlags, 234 dataRefWasChanged), -1) 235 236 wxDL_VOIDMETHOD_DEFINE( SetMovieRate, (Movie m, Fixed rate), (m, rate) ) 237 wxDL_METHOD_DEFINE( Fixed, GetMovieRate, (Movie m), (m), 0) 238 wxDL_VOIDMETHOD_DEFINE( MoviesTask, (Movie m, long maxms), (m, maxms) ) 239 wxDL_VOIDMETHOD_DEFINE( BlockMove, 240 (const char* p1, const char* p2, long s), (p1,p2,s) ) 241 wxDL_METHOD_DEFINE( Handle, NewHandleClear, (long s), (s), NULL ) 242 243 wxDL_METHOD_DEFINE( OSErr, NewMovieFromDataRef, 244 (Movie * m, short flags, short * id, 245 Handle dataRef, OSType dataRefType), 246 (m,flags,id,dataRef,dataRefType), -1 ) 247 248 wxDL_VOIDMETHOD_DEFINE( DisposeHandle, (Handle h), (h) ) 249 wxDL_VOIDMETHOD_DEFINE( GetMovieNaturalBoundsRect, (Movie m, Rect* r), (m,r) ) 250 wxDL_METHOD_DEFINE( void*, GetMovieIndTrackType, 251 (Movie m, long index, OSType type, long flags), 252 (m,index,type,flags), NULL ) 253 wxDL_VOIDMETHOD_DEFINE( CreatePortAssociation, 254 (void* hWnd, void* junk, long morejunk), (hWnd, junk, morejunk) ) 255 wxDL_METHOD_DEFINE(void*, GetNativeWindowPort, (void* hWnd), (hWnd), NULL) 256 wxDL_VOIDMETHOD_DEFINE(SetMovieGWorld, (Movie m, CGrafPtr port, void* whatever), 257 (m, port, whatever) ) 258 wxDL_VOIDMETHOD_DEFINE(DisposeMovie, (Movie m), (m) ) 259 wxDL_VOIDMETHOD_DEFINE(SetMovieBox, (Movie m, Rect* r), (m,r)) 260 wxDL_VOIDMETHOD_DEFINE(SetMovieTimeScale, (Movie m, long s), (m,s)) 261 wxDL_METHOD_DEFINE(long, GetMovieDuration, (Movie m), (m), 0) 262 wxDL_METHOD_DEFINE(TimeBase, GetMovieTimeBase, (Movie m), (m), 0) 263 wxDL_METHOD_DEFINE(TimeScale, GetMovieTimeScale, (Movie m), (m), 0) 264 wxDL_METHOD_DEFINE(long, GetMovieTime, (Movie m, void* cruft), (m,cruft), 0) 265 wxDL_VOIDMETHOD_DEFINE(SetMovieTime, (Movie m, TimeRecord* tr), (m,tr) ) 266 wxDL_METHOD_DEFINE(short, GetMovieVolume, (Movie m), (m), 0) 267 wxDL_VOIDMETHOD_DEFINE(SetMovieVolume, (Movie m, short sVolume), (m,sVolume) ) 268 wxDL_VOIDMETHOD_DEFINE(SetMovieTimeValue, (Movie m, long s), (m,s)) 269 wxDL_METHOD_DEFINE(ComponentInstance, NewMovieController, (Movie m, const Rect* mr, long fl), (m,mr,fl), 0) 270 wxDL_VOIDMETHOD_DEFINE(DisposeMovieController, (ComponentInstance ci), (ci)) 271 wxDL_METHOD_DEFINE(int, MCSetVisible, (ComponentInstance m, int b), (m, b), 0) 272 273 wxDL_VOIDMETHOD_DEFINE(PrePrerollMovie, (Movie m, long t, Fixed r, WXFARPROC p1, void* p2), (m,t,r,p1,p2) ) 274 wxDL_VOIDMETHOD_DEFINE(PrerollMovie, (Movie m, long t, Fixed r), (m,t,r) ) 275 wxDL_METHOD_DEFINE(Fixed, GetMoviePreferredRate, (Movie m), (m), 0) 276 wxDL_METHOD_DEFINE(long, GetMovieLoadState, (Movie m), (m), 0) 277 wxDL_METHOD_DEFINE(void*, NewRoutineDescriptor, (WXFARPROC f, int l, void* junk), (f, l, junk), 0) 278 wxDL_VOIDMETHOD_DEFINE(DisposeRoutineDescriptor, (void* f), (f)) 279 wxDL_METHOD_DEFINE(void*, GetCurrentArchitecture, (), (), 0) 280 wxDL_METHOD_DEFINE(int, MCDoAction, (ComponentInstance ci, long f, void* p), (ci,f,p), 0) 281 wxDL_VOIDMETHOD_DEFINE(MCSetControllerBoundsRect, (ComponentInstance ci, Rect* r), (ci,r)) 282 wxDL_VOIDMETHOD_DEFINE(DestroyPortAssociation, (CGrafPtr g), (g)) 283 wxDL_VOIDMETHOD_DEFINE(NativeEventToMacEvent, (MSG* p1, EventRecord* p2), (p1,p2)) 284 wxDL_VOIDMETHOD_DEFINE(MCIsPlayerEvent, (ComponentInstance ci, EventRecord* p2), (ci, p2)) 285 wxDL_METHOD_DEFINE(int, MCSetMovie, (ComponentInstance ci, Movie m, void* p1, Point w), 286 (ci,m,p1,w),0) 287 wxDL_VOIDMETHOD_DEFINE(MCPositionController, 288 (ComponentInstance ci, Rect* r, void* junk, void* morejunk), (ci,r,junk,morejunk)) 289 wxDL_VOIDMETHOD_DEFINE(MCSetActionFilterWithRefCon, 290 (ComponentInstance ci, WXFARPROC cb, void* ref), (ci,cb,ref)) 291 wxDL_VOIDMETHOD_DEFINE(MCGetControllerInfo, (MovieController mc, long* flags), (mc,flags)) 292 wxDL_VOIDMETHOD_DEFINE(BeginUpdate, (CGrafPtr port), (port)) 293 wxDL_VOIDMETHOD_DEFINE(UpdateMovie, (Movie m), (m)) 294 wxDL_VOIDMETHOD_DEFINE(EndUpdate, (CGrafPtr port), (port)) 295 wxDL_METHOD_DEFINE( OSErr, GetMoviesStickyError, (), (), -1) 296}; 297 298bool wxQuickTimeLibrary::Initialize() 299{ 300 m_ok = false; 301 302 // Turn off the wxDynamicLibrary logging as we're prepared to handle the 303 // errors 304 wxLogNull nolog; 305 306 if (!m_dll.Load(wxT("qtmlClient.dll"))) 307 { 308 return false; 309 } 310 311 wxDL_METHOD_LOAD( m_dll, StartMovie, m_ok ); 312 wxDL_METHOD_LOAD( m_dll, StopMovie, m_ok ); 313 wxDL_METHOD_LOAD( m_dll, IsMovieDone, m_ok ); 314 wxDL_METHOD_LOAD( m_dll, GoToBeginningOfMovie, m_ok ); 315 wxDL_METHOD_LOAD( m_dll, GetMoviesError, m_ok ); 316 wxDL_METHOD_LOAD( m_dll, EnterMovies, m_ok ); 317 wxDL_METHOD_LOAD( m_dll, ExitMovies, m_ok ); 318 wxDL_METHOD_LOAD( m_dll, InitializeQTML, m_ok ); 319 wxDL_METHOD_LOAD( m_dll, TerminateQTML, m_ok ); 320 wxDL_METHOD_LOAD( m_dll, NativePathNameToFSSpec, m_ok ); 321 wxDL_METHOD_LOAD( m_dll, OpenMovieFile, m_ok ); 322 wxDL_METHOD_LOAD( m_dll, CloseMovieFile, m_ok ); 323 wxDL_METHOD_LOAD( m_dll, NewMovieFromFile, m_ok ); 324 wxDL_METHOD_LOAD( m_dll, GetMovieRate, m_ok ); 325 wxDL_METHOD_LOAD( m_dll, SetMovieRate, m_ok ); 326 wxDL_METHOD_LOAD( m_dll, MoviesTask, m_ok ); 327 wxDL_METHOD_LOAD( m_dll, BlockMove, m_ok ); 328 wxDL_METHOD_LOAD( m_dll, NewHandleClear, m_ok ); 329 wxDL_METHOD_LOAD( m_dll, NewMovieFromDataRef, m_ok ); 330 wxDL_METHOD_LOAD( m_dll, DisposeHandle, m_ok ); 331 wxDL_METHOD_LOAD( m_dll, GetMovieNaturalBoundsRect, m_ok ); 332 wxDL_METHOD_LOAD( m_dll, GetMovieIndTrackType, m_ok ); 333 wxDL_METHOD_LOAD( m_dll, CreatePortAssociation, m_ok ); 334 wxDL_METHOD_LOAD( m_dll, DestroyPortAssociation, m_ok ); 335 wxDL_METHOD_LOAD( m_dll, GetNativeWindowPort, m_ok ); 336 wxDL_METHOD_LOAD( m_dll, SetMovieGWorld, m_ok ); 337 wxDL_METHOD_LOAD( m_dll, DisposeMovie, m_ok ); 338 wxDL_METHOD_LOAD( m_dll, SetMovieBox, m_ok ); 339 wxDL_METHOD_LOAD( m_dll, SetMovieTimeScale, m_ok ); 340 wxDL_METHOD_LOAD( m_dll, GetMovieDuration, m_ok ); 341 wxDL_METHOD_LOAD( m_dll, GetMovieTimeBase, m_ok ); 342 wxDL_METHOD_LOAD( m_dll, GetMovieTimeScale, m_ok ); 343 wxDL_METHOD_LOAD( m_dll, GetMovieTime, m_ok ); 344 wxDL_METHOD_LOAD( m_dll, SetMovieTime, m_ok ); 345 wxDL_METHOD_LOAD( m_dll, GetMovieVolume, m_ok ); 346 wxDL_METHOD_LOAD( m_dll, SetMovieVolume, m_ok ); 347 wxDL_METHOD_LOAD( m_dll, SetMovieTimeValue, m_ok ); 348 wxDL_METHOD_LOAD( m_dll, NewMovieController, m_ok ); 349 wxDL_METHOD_LOAD( m_dll, DisposeMovieController, m_ok ); 350 wxDL_METHOD_LOAD( m_dll, MCSetVisible, m_ok ); 351 wxDL_METHOD_LOAD( m_dll, PrePrerollMovie, m_ok ); 352 wxDL_METHOD_LOAD( m_dll, PrerollMovie, m_ok ); 353 wxDL_METHOD_LOAD( m_dll, GetMoviePreferredRate, m_ok ); 354 wxDL_METHOD_LOAD( m_dll, GetMovieLoadState, m_ok ); 355 wxDL_METHOD_LOAD( m_dll, MCDoAction, m_ok ); 356 wxDL_METHOD_LOAD( m_dll, MCSetControllerBoundsRect, m_ok ); 357 wxDL_METHOD_LOAD( m_dll, NativeEventToMacEvent, m_ok ); 358 wxDL_METHOD_LOAD( m_dll, MCIsPlayerEvent, m_ok ); 359 wxDL_METHOD_LOAD( m_dll, MCSetMovie, m_ok ); 360 wxDL_METHOD_LOAD( m_dll, MCSetActionFilterWithRefCon, m_ok ); 361 wxDL_METHOD_LOAD( m_dll, MCGetControllerInfo, m_ok ); 362 wxDL_METHOD_LOAD( m_dll, BeginUpdate, m_ok ); 363 wxDL_METHOD_LOAD( m_dll, UpdateMovie, m_ok ); 364 wxDL_METHOD_LOAD( m_dll, EndUpdate, m_ok ); 365 wxDL_METHOD_LOAD( m_dll, GetMoviesStickyError, m_ok ); 366 367 m_ok = true; 368 369 return true; 370} 371 372class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase 373{ 374public: 375 wxQTMediaBackend(); 376 virtual ~wxQTMediaBackend(); 377 378 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent, 379 wxWindowID id, 380 const wxPoint& pos, 381 const wxSize& size, 382 long style, 383 const wxValidator& validator, 384 const wxString& name); 385 386 virtual bool Play(); 387 virtual bool Pause(); 388 virtual bool Stop(); 389 390 virtual bool Load(const wxURI& location, 391 const wxURI& proxy) 392 { return wxMediaBackend::Load(location, proxy); } 393 394 virtual bool Load(const wxString& fileName); 395 virtual bool Load(const wxURI& location); 396 397 virtual wxMediaState GetState(); 398 399 virtual bool SetPosition(wxLongLong where); 400 virtual wxLongLong GetPosition(); 401 virtual wxLongLong GetDuration(); 402 403 virtual void Move(int x, int y, int w, int h); 404 wxSize GetVideoSize() const; 405 406 virtual double GetPlaybackRate(); 407 virtual bool SetPlaybackRate(double dRate); 408 409 virtual double GetVolume(); 410 virtual bool SetVolume(double); 411 412 void Cleanup(); 413 void FinishLoad(); 414 415 static void PPRMProc (Movie theMovie, OSErr theErr, void* theRefCon); 416 417 // TODO: Last param actually long - does this work on 64bit machines? 418 static Boolean MCFilterProc(MovieController theController, 419 short action, void *params, LONG_PTR refCon); 420 421 static LRESULT CALLBACK QTWndProc(HWND, UINT, WPARAM, LPARAM); 422 423 virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags); 424 425 wxSize m_bestSize; // Original movie size 426 Movie m_movie; // QT Movie handle/instance 427 bool m_bVideo; // Whether or not we have video 428 bool m_bPlaying; // Whether or not movie is playing 429 wxTimer* m_timer; // Load or Play timer 430 wxQuickTimeLibrary m_lib; // DLL to load functions from 431 ComponentInstance m_pMC; // Movie Controller 432 433 friend class wxQTMediaEvtHandler; 434 435 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend) 436}; 437 438// helper to hijack background erasing for the QT window 439class WXDLLIMPEXP_MEDIA wxQTMediaEvtHandler : public wxEvtHandler 440{ 441public: 442 wxQTMediaEvtHandler(wxQTMediaBackend *qtb, WXHWND hwnd) 443 { 444 m_qtb = qtb; 445 m_hwnd = hwnd; 446 447 m_qtb->m_ctrl->Connect(m_qtb->m_ctrl->GetId(), 448 wxEVT_ERASE_BACKGROUND, 449 wxEraseEventHandler(wxQTMediaEvtHandler::OnEraseBackground), 450 NULL, this); 451 } 452 453 void OnEraseBackground(wxEraseEvent& event); 454 455private: 456 wxQTMediaBackend *m_qtb; 457 WXHWND m_hwnd; 458 459 DECLARE_NO_COPY_CLASS(wxQTMediaEvtHandler) 460}; 461 462 463//=========================================================================== 464// IMPLEMENTATION 465//=========================================================================== 466 467 468//--------------------------------------------------------------------------- 469// wxQTMediaBackend 470// 471// TODO: Use a less kludgy way to pause/get state/set state 472// FIXME: Greg Hazel reports that sometimes files that cannot be played 473// with this backend are treated as playable anyway - not verified though. 474//--------------------------------------------------------------------------- 475 476IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend) 477 478// Time between timer calls - this is the Apple recommendation to the TCL 479// team I believe 480#define MOVIE_DELAY 20 481 482//--------------------------------------------------------------------------- 483// wxQTLoadTimer 484// 485// QT, esp. QT for Windows is very picky about how you go about 486// async loading. If you were to go through a Windows message loop 487// or a MoviesTask or both and then check the movie load state 488// it would still return 1000 (loading)... even (pre)prerolling doesn't 489// help. However, making a load timer like this works 490//--------------------------------------------------------------------------- 491class wxQTLoadTimer : public wxTimer 492{ 493public: 494 wxQTLoadTimer(Movie movie, wxQTMediaBackend* parent, wxQuickTimeLibrary* pLib) : 495 m_movie(movie), m_parent(parent), m_pLib(pLib) {} 496 497 void Notify() 498 { 499 m_pLib->MoviesTask(m_movie, 0); 500 // kMovieLoadStatePlayable 501 if (m_pLib->GetMovieLoadState(m_movie) >= 10000) 502 { 503 m_parent->FinishLoad(); 504 delete this; 505 } 506 } 507 508protected: 509 Movie m_movie; //Our movie instance 510 wxQTMediaBackend* m_parent; //Backend pointer 511 wxQuickTimeLibrary* m_pLib; //Interfaces 512}; 513 514 515// -------------------------------------------------------------------------- 516// wxQTPlayTimer - Handle Asyncronous Playing 517// 518// 1) Checks to see if the movie is done, and if not continues 519// streaming the movie 520// 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of 521// the movie. 522// -------------------------------------------------------------------------- 523class wxQTPlayTimer : public wxTimer 524{ 525public: 526 wxQTPlayTimer(Movie movie, wxQTMediaBackend* parent, 527 wxQuickTimeLibrary* pLib) : 528 m_movie(movie), m_parent(parent), m_pLib(pLib) {} 529 530 void Notify() 531 { 532 // 533 // OK, a little explaining - basically originally 534 // we only called MoviesTask if the movie was actually 535 // playing (not paused or stopped)... this was before 536 // we realized MoviesTask actually handles repainting 537 // of the current frame - so if you were to resize 538 // or something it would previously not redraw that 539 // portion of the movie. 540 // 541 // So now we call MoviesTask always so that it repaints 542 // correctly. 543 // 544 m_pLib->MoviesTask(m_movie, 0); 545 546 // 547 // Handle the stop event - if the movie has reached 548 // the end, notify our handler 549 // 550 // m_bPlaying == !(Stopped | Paused) 551 // 552 if (m_parent->m_bPlaying) 553 { 554 if (m_pLib->IsMovieDone(m_movie)) 555 { 556 if ( m_parent->SendStopEvent() ) 557 { 558 m_parent->Stop(); 559 wxASSERT(m_pLib->GetMoviesError() == noErr); 560 561 m_parent->QueueFinishEvent(); 562 } 563 } 564 } 565 } 566 567protected: 568 Movie m_movie; // Our movie instance 569 wxQTMediaBackend* m_parent; //Backend pointer 570 wxQuickTimeLibrary* m_pLib; //Interfaces 571}; 572 573 574//--------------------------------------------------------------------------- 575// wxQTMediaBackend::QTWndProc 576// 577// Forwards events to the Movie Controller so that it can 578// redraw itself/process messages etc.. 579//--------------------------------------------------------------------------- 580LRESULT CALLBACK wxQTMediaBackend::QTWndProc(HWND hWnd, UINT nMsg, 581 WPARAM wParam, LPARAM lParam) 582{ 583 wxQTMediaBackend* pThis = (wxQTMediaBackend*)wxGetWindowUserData(hWnd); 584 585 MSG msg; 586 msg.hwnd = hWnd; 587 msg.message = nMsg; 588 msg.wParam = wParam; 589 msg.lParam = lParam; 590 msg.time = 0; 591 msg.pt.x = 0; 592 msg.pt.y = 0; 593 EventRecord theEvent; 594 pThis->m_lib.NativeEventToMacEvent(&msg, &theEvent); 595 pThis->m_lib.MCIsPlayerEvent(pThis->m_pMC, &theEvent); 596 597 return pThis->m_ctrl->MSWWindowProc(nMsg, wParam, lParam); 598} 599 600//--------------------------------------------------------------------------- 601// wxQTMediaBackend Destructor 602// 603// Sets m_timer to NULL signifying we havn't loaded anything yet 604//--------------------------------------------------------------------------- 605wxQTMediaBackend::wxQTMediaBackend() 606: m_movie(NULL), m_bPlaying(false), m_timer(NULL), m_pMC(NULL) 607{ 608} 609 610//--------------------------------------------------------------------------- 611// wxQTMediaBackend Destructor 612// 613// 1) Cleans up the QuickTime movie instance 614// 2) Decrements the QuickTime reference counter - if this reaches 615// 0, QuickTime shuts down 616// 3) Decrements the QuickTime Windows Media Layer reference counter - 617// if this reaches 0, QuickTime shuts down the Windows Media Layer 618//--------------------------------------------------------------------------- 619wxQTMediaBackend::~wxQTMediaBackend() 620{ 621 if (m_movie) 622 Cleanup(); 623 624 if (m_lib.IsOk()) 625 { 626 if (m_pMC) 627 { 628 m_lib.DisposeMovieController(m_pMC); 629 // m_pMC = NULL; 630 } 631 632 // destroy wxQTMediaEvtHandler we pushed on it 633 m_ctrl->PopEventHandler(true); 634 635 m_lib.DestroyPortAssociation( 636 (CGrafPtr)m_lib.GetNativeWindowPort(m_ctrl->GetHWND())); 637 638 //Note that ExitMovies() is not necessary, but 639 //the docs are fuzzy on whether or not TerminateQTML is 640 m_lib.ExitMovies(); 641 m_lib.TerminateQTML(); 642 } 643} 644 645//--------------------------------------------------------------------------- 646// wxQTMediaBackend::CreateControl 647// 648// 1) Intializes QuickTime 649// 2) Creates the control window 650//--------------------------------------------------------------------------- 651bool wxQTMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent, 652 wxWindowID id, 653 const wxPoint& pos, 654 const wxSize& size, 655 long style, 656 const wxValidator& validator, 657 const wxString& name) 658{ 659 if (!m_lib.Initialize()) 660 return false; 661 662 int nError = m_lib.InitializeQTML(0); 663 if (nError != noErr) //-2093 no dll 664 { 665 wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError)); 666 return false; 667 } 668 669 m_lib.EnterMovies(); 670 671 // Create window 672 // By default wxWindow(s) is created with a border - 673 // so we need to get rid of those 674 // 675 // Since we don't have a child window like most other 676 // backends, we don't need wxCLIP_CHILDREN 677 if ( !ctrl->wxControl::Create(parent, id, pos, size, 678 (style & ~wxBORDER_MASK) | wxBORDER_NONE, 679 validator, name) ) 680 { 681 return false; 682 } 683 684 m_ctrl = wxStaticCast(ctrl, wxMediaCtrl); 685 686 // Create a port association for our window so we 687 // can use it as a WindowRef 688 m_lib.CreatePortAssociation(m_ctrl->GetHWND(), NULL, 0L); 689 690 // Part of a suggestion from Greg Hazel 691 // to repaint movie when idle 692 m_ctrl->PushEventHandler(new wxQTMediaEvtHandler(this, m_ctrl->GetHWND())); 693 694 // done 695 return true; 696} 697 698//--------------------------------------------------------------------------- 699// wxQTMediaBackend::Load (file version) 700// 701// 1) Get an FSSpec from the Windows path name 702// 2) Open the movie 703// 3) Obtain the movie instance from the movie resource 704// 4) Close the movie resource 705// 5) Finish loading 706//--------------------------------------------------------------------------- 707bool wxQTMediaBackend::Load(const wxString& fileName) 708{ 709 if (m_movie) 710 Cleanup(); 711 712 bool result = true; 713 OSErr err = noErr; 714 short movieResFile = 0; //= 0 because of annoying VC6 warning 715 FSSpec sfFile; 716 717 err = m_lib.NativePathNameToFSSpec( 718 (char*) (const char*) fileName.mb_str(), 719 &sfFile, 0); 720 result = (err == noErr); 721 722 if (result) 723 { 724 err = m_lib.OpenMovieFile(&sfFile, &movieResFile, fsRdPerm); 725 result = (err == noErr); 726 } 727 728 if (result) 729 { 730 short movieResID = 0; 731 Str255 movieName; 732 733 err = m_lib.NewMovieFromFile( 734 &m_movie, 735 movieResFile, 736 &movieResID, 737 movieName, 738 newMovieActive, 739 NULL ); // wasChanged 740 result = (err == noErr /*&& m_lib.GetMoviesStickyError() == noErr*/); 741 742 // check m_lib.GetMoviesStickyError() because it may not find the 743 // proper codec and play black video and other strange effects, 744 // not to mention mess up the dynamic backend loading scheme 745 // of wxMediaCtrl - so it just does what the QuickTime player does 746 if (result) 747 { 748 m_lib.CloseMovieFile(movieResFile); 749 FinishLoad(); 750 } 751 } 752 753 return result; 754} 755 756//--------------------------------------------------------------------------- 757// wxQTMediaBackend::PPRMProc (static) 758// 759// Called when done PrePrerolling the movie. 760// Note that in 99% of the cases this does nothing... 761// Anyway we set up the loading timer here to tell us when the movie is done 762//--------------------------------------------------------------------------- 763void wxQTMediaBackend::PPRMProc (Movie theMovie, 764 OSErr WXUNUSED_UNLESS_DEBUG(theErr), 765 void* theRefCon) 766{ 767 wxASSERT( theMovie ); 768 wxASSERT( theRefCon ); 769 wxASSERT( theErr == noErr ); 770 771 wxQTMediaBackend* pBE = (wxQTMediaBackend*) theRefCon; 772 773 long lTime = pBE->m_lib.GetMovieTime(theMovie,NULL); 774 Fixed rate = pBE->m_lib.GetMoviePreferredRate(theMovie); 775 pBE->m_lib.PrerollMovie(theMovie, lTime, rate); 776 pBE->m_timer = new wxQTLoadTimer(pBE->m_movie, pBE, &pBE->m_lib); 777 pBE->m_timer->Start(MOVIE_DELAY); 778} 779 780//--------------------------------------------------------------------------- 781// wxQTMediaBackend::Load (URL Version) 782// 783// 1) Build an escaped URI from location 784// 2) Create a handle to store the URI string 785// 3) Put the URI string inside the handle 786// 4) Make a QuickTime URL data ref from the handle with the URI in it 787// 5) Clean up the URI string handle 788// 6) Do some prerolling 789// 7) Finish Loading 790//--------------------------------------------------------------------------- 791bool wxQTMediaBackend::Load(const wxURI& location) 792{ 793 if (m_movie) 794 Cleanup(); 795 796 wxString theURI = location.BuildURI(); 797 798 Handle theHandle = m_lib.NewHandleClear(theURI.length() + 1); 799 wxASSERT(theHandle); 800 801 m_lib.BlockMove(theURI.mb_str(), *theHandle, theURI.length() + 1); 802 803 // create the movie from the handle that refers to the URI 804 OSErr err = m_lib.NewMovieFromDataRef(&m_movie, newMovieActive | 805 newMovieAsyncOK 806 /* | newMovieIdleImportOK */, 807 NULL, theHandle, 808 URLDataHandlerSubType); 809 810 m_lib.DisposeHandle(theHandle); 811 812 if (err == noErr) 813 { 814 long timeNow; 815 Fixed playRate; 816 817 timeNow = m_lib.GetMovieTime(m_movie, NULL); 818 wxASSERT(m_lib.GetMoviesError() == noErr); 819 820 playRate = m_lib.GetMoviePreferredRate(m_movie); 821 wxASSERT(m_lib.GetMoviesError() == noErr); 822 823 // Note that the callback here is optional, 824 // but without it PrePrerollMovie can be buggy 825 // (see Apple ml). Also, some may wonder 826 // why we need this at all - this is because 827 // Apple docs say QuickTime streamed movies 828 // require it if you don't use a Movie Controller, 829 // which we don't by default. 830 // 831 m_lib.PrePrerollMovie(m_movie, timeNow, playRate, 832 (WXFARPROC)wxQTMediaBackend::PPRMProc, 833 (void*)this); 834 835 return true; 836 } 837 else 838 return false; 839} 840 841//--------------------------------------------------------------------------- 842// wxQTMediaBackend::FinishLoad 843// 844// 1) Create the movie timer 845// 2) Get real size of movie for GetBestSize/sizers 846// 3) Set the movie time scale to something usable so that seeking 847// etc. will work correctly 848// 4) Set our Movie Controller to display the movie if it exists, 849// otherwise set the bounds of the Movie 850// 5) Refresh parent window 851//--------------------------------------------------------------------------- 852void wxQTMediaBackend::FinishLoad() 853{ 854 // Create the playing/streaming timer 855 m_timer = new wxQTPlayTimer(m_movie, (wxQTMediaBackend*) this, &m_lib); 856 wxASSERT(m_timer); 857 858 m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS); 859 860 // get the real size of the movie 861 Rect outRect; 862 memset(&outRect, 0, sizeof(Rect)); // suppress annoying VC6 warning 863 m_lib.GetMovieNaturalBoundsRect (m_movie, &outRect); 864 wxASSERT(m_lib.GetMoviesError() == noErr); 865 866 m_bestSize.x = outRect.right - outRect.left; 867 m_bestSize.y = outRect.bottom - outRect.top; 868 869 // Handle the movie GWorld 870 if (m_pMC) 871 { 872 Point thePoint; 873 thePoint.h = thePoint.v = 0; 874 m_lib.MCSetMovie(m_pMC, m_movie, 875 m_lib.GetNativeWindowPort(m_ctrl->GetHandle()), 876 thePoint); 877 m_lib.MCSetVisible(m_pMC, true); 878 m_bestSize.y += 16; 879 } 880 else 881 { 882 m_lib.SetMovieGWorld(m_movie, 883 (CGrafPtr) m_lib.GetNativeWindowPort(m_ctrl->GetHWND()), 884 NULL); 885 } 886 887 // Set the movie to millisecond precision 888 m_lib.SetMovieTimeScale(m_movie, 1000); 889 wxASSERT(m_lib.GetMoviesError() == noErr); 890 891 NotifyMovieLoaded(); 892} 893 894//--------------------------------------------------------------------------- 895// wxQTMediaBackend::Play 896// 897// 1) Start the QT movie 898// 2) Start the movie loading timer 899// 900// NOTE: This will still return success even when 901// the movie is still loading, and as mentioned in wxQTLoadTimer 902// I don't know of a way to force this to be sync - so if its 903// still loading the function will return true but the movie will 904// still be in the stopped state 905//--------------------------------------------------------------------------- 906bool wxQTMediaBackend::Play() 907{ 908 m_lib.StartMovie(m_movie); 909 m_bPlaying = true; 910 911 return m_lib.GetMoviesError() == noErr; 912} 913 914//--------------------------------------------------------------------------- 915// wxQTMediaBackend::Pause 916// 917// 1) Stop the movie 918// 2) Stop the movie timer 919//--------------------------------------------------------------------------- 920bool wxQTMediaBackend::Pause() 921{ 922 m_bPlaying = false; 923 m_lib.StopMovie(m_movie); 924 925 return m_lib.GetMoviesError() == noErr; 926} 927 928//--------------------------------------------------------------------------- 929// wxQTMediaBackend::Stop 930// 931// 1) Stop the movie 932// 2) Stop the movie timer 933// 3) Seek to the beginning of the movie 934//--------------------------------------------------------------------------- 935bool wxQTMediaBackend::Stop() 936{ 937 m_bPlaying = false; 938 939 m_lib.StopMovie(m_movie); 940 if (m_lib.GetMoviesError() == noErr) 941 m_lib.GoToBeginningOfMovie(m_movie); 942 943 return m_lib.GetMoviesError() == noErr; 944} 945 946//--------------------------------------------------------------------------- 947// wxQTMediaBackend::GetPlaybackRate 948// 949// Get the movie playback rate from ::GetMovieRate 950//--------------------------------------------------------------------------- 951double wxQTMediaBackend::GetPlaybackRate() 952{ 953 return ( ((double)m_lib.GetMovieRate(m_movie)) / 0x10000); 954} 955 956//--------------------------------------------------------------------------- 957// wxQTMediaBackend::SetPlaybackRate 958// 959// Convert dRate to Fixed and Set the movie rate through SetMovieRate 960//--------------------------------------------------------------------------- 961bool wxQTMediaBackend::SetPlaybackRate(double dRate) 962{ 963 m_lib.SetMovieRate(m_movie, (Fixed) (dRate * 0x10000)); 964 965 return m_lib.GetMoviesError() == noErr; 966} 967 968//--------------------------------------------------------------------------- 969// wxQTMediaBackend::SetPosition 970// 971// 1) Create a time record struct (TimeRecord) with appropriate values 972// 2) Pass struct to SetMovieTime 973//--------------------------------------------------------------------------- 974bool wxQTMediaBackend::SetPosition(wxLongLong where) 975{ 976 // NB: For some reason SetMovieTime does not work 977 // correctly with the Quicktime Windows SDK (6) 978 // From Muskelkatermann at the wxForum 979 // http://www.solidsteel.nl/users/wxwidgets/viewtopic.php?t=2957 980 // RN - note that I have not verified this but there 981 // is no harm in calling SetMovieTimeValue instead 982#if 0 983 TimeRecord theTimeRecord; 984 memset(&theTimeRecord, 0, sizeof(TimeRecord)); 985 theTimeRecord.value.lo = where.GetLo(); 986 theTimeRecord.scale = m_lib.GetMovieTimeScale(m_movie); 987 theTimeRecord.base = m_lib.GetMovieTimeBase(m_movie); 988 m_lib.SetMovieTime(m_movie, &theTimeRecord); 989#else 990 m_lib.SetMovieTimeValue(m_movie, where.GetLo()); 991#endif 992 993 return (m_lib.GetMoviesError() == noErr); 994} 995 996//--------------------------------------------------------------------------- 997// wxQTMediaBackend::GetPosition 998// 999// 1) Calls GetMovieTime to get the position we are in in the movie 1000// in milliseconds (we called 1001//--------------------------------------------------------------------------- 1002wxLongLong wxQTMediaBackend::GetPosition() 1003{ 1004 return m_lib.GetMovieTime(m_movie, NULL); 1005} 1006 1007//--------------------------------------------------------------------------- 1008// wxQTMediaBackend::GetVolume 1009// 1010// Gets the volume through GetMovieVolume - which returns a 16 bit short - 1011// 1012// +--------+--------+ 1013// + (1) + (2) + 1014// +--------+--------+ 1015// 1016// (1) first 8 bits are value before decimal 1017// (2) second 8 bits are value after decimal 1018// 1019// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to 1020// 1 (full gain and sound) 1021//--------------------------------------------------------------------------- 1022double wxQTMediaBackend::GetVolume() 1023{ 1024 short sVolume = m_lib.GetMovieVolume(m_movie); 1025 wxASSERT(m_lib.GetMoviesError() == noErr); 1026 1027 if (sVolume & (128 << 8)) //negative - no sound 1028 return 0.0; 1029 1030 return sVolume / 256.0; 1031} 1032 1033//--------------------------------------------------------------------------- 1034// wxQTMediaBackend::SetVolume 1035// 1036// Sets the volume through SetMovieVolume - which takes a 16 bit short - 1037// 1038// +--------+--------+ 1039// + (1) + (2) + 1040// +--------+--------+ 1041// 1042// (1) first 8 bits are value before decimal 1043// (2) second 8 bits are value after decimal 1044// 1045// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to 1046// 1 (full gain and sound) 1047//--------------------------------------------------------------------------- 1048bool wxQTMediaBackend::SetVolume(double dVolume) 1049{ 1050 m_lib.SetMovieVolume(m_movie, (short) (dVolume * 256)); 1051 return m_lib.GetMoviesError() == noErr; 1052} 1053 1054//--------------------------------------------------------------------------- 1055// wxQTMediaBackend::GetDuration 1056// 1057// Calls GetMovieDuration 1058//--------------------------------------------------------------------------- 1059wxLongLong wxQTMediaBackend::GetDuration() 1060{ 1061 return m_lib.GetMovieDuration(m_movie); 1062} 1063 1064//--------------------------------------------------------------------------- 1065// wxQTMediaBackend::GetState 1066// 1067// Determines the current state: 1068// if we are at the beginning, then we are stopped 1069//--------------------------------------------------------------------------- 1070wxMediaState wxQTMediaBackend::GetState() 1071{ 1072 if (m_bPlaying) 1073 return wxMEDIASTATE_PLAYING; 1074 else if ( !m_movie || wxQTMediaBackend::GetPosition() == 0 ) 1075 return wxMEDIASTATE_STOPPED; 1076 else 1077 return wxMEDIASTATE_PAUSED; 1078} 1079 1080//--------------------------------------------------------------------------- 1081// wxQTMediaBackend::Cleanup 1082// 1083// Diposes of the movie timer, Disassociates the Movie Controller with 1084// movie and hides it if it exists, and stops and disposes 1085// of the QT movie 1086//--------------------------------------------------------------------------- 1087void wxQTMediaBackend::Cleanup() 1088{ 1089 m_bPlaying = false; 1090 1091 if (m_timer) 1092 { 1093 delete m_timer; 1094 m_timer = NULL; 1095 } 1096 1097 m_lib.StopMovie(m_movie); 1098 1099 if (m_pMC) 1100 { 1101 Point thePoint; 1102 thePoint.h = thePoint.v = 0; 1103 m_lib.MCSetVisible(m_pMC, false); 1104 m_lib.MCSetMovie(m_pMC, NULL, NULL, thePoint); 1105 } 1106 1107 m_lib.DisposeMovie(m_movie); 1108 m_movie = NULL; 1109} 1110 1111//--------------------------------------------------------------------------- 1112// wxQTMediaBackend::ShowPlayerControls 1113// 1114// Creates a movie controller for the Movie if the user wants it 1115//--------------------------------------------------------------------------- 1116bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags) 1117{ 1118 if (m_pMC) 1119 { 1120 // restore old wndproc 1121 wxSetWindowProc((HWND)m_ctrl->GetHWND(), wxWndProc); 1122 m_lib.DisposeMovieController(m_pMC); 1123 m_pMC = NULL; 1124 1125 // movie controller height 1126 m_bestSize.y -= 16; 1127 } 1128 1129 if (flags && m_movie) 1130 { 1131 Rect rect; 1132 wxRect wxrect = m_ctrl->GetClientRect(); 1133 1134 // make room for controller 1135 if (wxrect.width < 320) 1136 wxrect.width = 320; 1137 1138 rect.top = (short)wxrect.y; 1139 rect.left = (short)wxrect.x; 1140 rect.right = (short)(rect.left + wxrect.width); 1141 rect.bottom = (short)(rect.top + wxrect.height); 1142 1143 if (!m_pMC) 1144 { 1145 m_pMC = m_lib.NewMovieController(m_movie, &rect, mcTopLeftMovie | 1146 // mcScaleMovieToFit | 1147 // mcWithBadge | 1148 mcWithFrame); 1149 m_lib.MCDoAction(m_pMC, 32, (void*)true); // mcActionSetKeysEnabled 1150 m_lib.MCSetActionFilterWithRefCon(m_pMC, 1151 (WXFARPROC)wxQTMediaBackend::MCFilterProc, (void*)this); 1152 m_bestSize.y += 16; // movie controller height 1153 1154 // By default the movie controller uses its own colour palette 1155 // for the movie which can be bad on some files, so turn it off. 1156 // Also turn off its frame / border for the movie 1157 // Also take care of a couple of the interface flags here 1158 long mcFlags = 0; 1159 m_lib.MCDoAction(m_pMC, 39/*mcActionGetFlags*/, (void*)&mcFlags); 1160 1161 mcFlags |= 1162 // (1<< 0) /*mcFlagSuppressMovieFrame*/ | 1163 (1<< 3) /*mcFlagsUseWindowPalette*/ 1164 | ((flags & wxMEDIACTRLPLAYERCONTROLS_STEP) 1165 ? 0 : (1<< 1) /*mcFlagSuppressStepButtons*/) 1166 | ((flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME) 1167 ? 0 : (1<< 2) /*mcFlagSuppressSpeakerButton*/) 1168// | (1<< 4) /*mcFlagDontInvalidate*/ // if we take care of repainting ourselves 1169 ; 1170 1171 m_lib.MCDoAction(m_pMC, 38/*mcActionSetFlags*/, (void*)mcFlags); 1172 1173 // intercept the wndproc of our control window 1174 wxSetWindowProc((HWND)m_ctrl->GetHWND(), wxQTMediaBackend::QTWndProc); 1175 1176 // set the user data of our window 1177 wxSetWindowUserData((HWND)m_ctrl->GetHWND(), this); 1178 } 1179 } 1180 1181 NotifyMovieSizeChanged(); 1182 1183 return m_lib.GetMoviesError() == noErr; 1184} 1185 1186//--------------------------------------------------------------------------- 1187// wxQTMediaBackend::MCFilterProc (static) 1188// 1189// Callback for when the movie controller recieves a message 1190//--------------------------------------------------------------------------- 1191Boolean wxQTMediaBackend::MCFilterProc(MovieController WXUNUSED(theController), 1192 short action, 1193 void * WXUNUSED(params), 1194 LONG_PTR refCon) 1195{ 1196// NB: potential optimisation 1197// if (action == 1) 1198// return 0; 1199 1200 wxQTMediaBackend* pThis = (wxQTMediaBackend*)refCon; 1201 1202 switch (action) 1203 { 1204 case 1: 1205 // don't process idle events 1206 break; 1207 1208 case 8: 1209 // play button triggered - MC will set movie to opposite state 1210 // of current - playing ? paused : playing 1211 if (pThis) 1212 pThis->m_bPlaying = !(pThis->m_bPlaying); 1213 1214 // NB: Sometimes it doesn't redraw properly - 1215 // if you click on the button but don't move the mouse 1216 // the button will not change its state until you move 1217 // mcActionDraw and Refresh/Update combo do nothing 1218 // to help this unfortunately 1219 break; 1220 1221 default: 1222 break; 1223 } 1224 1225 return 0; 1226} 1227 1228//--------------------------------------------------------------------------- 1229// wxQTMediaBackend::GetVideoSize 1230// 1231// Returns the actual size of the QT movie 1232//--------------------------------------------------------------------------- 1233wxSize wxQTMediaBackend::GetVideoSize() const 1234{ 1235 return m_bestSize; 1236} 1237 1238//--------------------------------------------------------------------------- 1239// wxQTMediaBackend::Move 1240// 1241// Sets the bounds of either the Movie or Movie Controller 1242//--------------------------------------------------------------------------- 1243void wxQTMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y), int w, int h) 1244{ 1245 if (m_movie) 1246 { 1247 // make room for controller 1248 if (m_pMC) 1249 { 1250 if (w < 320) 1251 w = 320; 1252 1253 Rect theRect = {0, 0, (short)h, (short)w}; 1254 m_lib.MCSetControllerBoundsRect(m_pMC, &theRect); 1255 } 1256 else 1257 { 1258 Rect theRect = {0, 0, (short)h, (short)w}; 1259 m_lib.SetMovieBox(m_movie, &theRect); 1260 } 1261 1262 wxASSERT(m_lib.GetMoviesError() == noErr); 1263 } 1264} 1265 1266//--------------------------------------------------------------------------- 1267// wxQTMediaBackend::OnEraseBackground 1268// 1269// Suggestion from Greg Hazel to repaint the movie when idle 1270// (on pause also) 1271// 1272// TODO: We may be repainting too much here - under what exact circumstances 1273// do we need this? I think Move also repaints correctly for the Movie 1274// Controller, so in that instance we don't need this either 1275//--------------------------------------------------------------------------- 1276void wxQTMediaEvtHandler::OnEraseBackground(wxEraseEvent& evt) 1277{ 1278 wxQuickTimeLibrary& m_pLib = m_qtb->m_lib; 1279 1280 if ( m_qtb->m_pMC ) 1281 { 1282 // repaint movie controller 1283 m_pLib.MCDoAction(m_qtb->m_pMC, 2 /*mcActionDraw*/, 1284 m_pLib.GetNativeWindowPort(m_hwnd)); 1285 } 1286 else if ( m_qtb->m_movie ) 1287 { 1288 // no movie controller 1289 CGrafPtr port = (CGrafPtr)m_pLib.GetNativeWindowPort(m_hwnd); 1290 1291 m_pLib.BeginUpdate(port); 1292 m_pLib.UpdateMovie(m_qtb->m_movie); 1293 wxASSERT(m_pLib.GetMoviesError() == noErr); 1294 m_pLib.EndUpdate(port); 1295 } 1296 else 1297 { 1298 // no movie 1299 // let the system repaint the window 1300 evt.Skip(); 1301 } 1302} 1303 1304//--------------------------------------------------------------------------- 1305// End QT Backend 1306//--------------------------------------------------------------------------- 1307 1308// in source file that contains stuff you don't directly use 1309#include "wx/html/forcelnk.h" 1310FORCE_LINK_ME(wxmediabackend_qt) 1311 1312#endif // wxUSE_MEDIACTRL && wxUSE_ACTIVEX 1313