1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/mediactrl.cpp
3 // Purpose: Built-in Media Backends for Windows
4 // Author: Ryan Norton <wxprojects@comcast.net>
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 //===========================================================================
14 //===========================================================================
16 //---------------------------------------------------------------------------
17 // Pre-compiled header stuff
18 //---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "mediactrl.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
31 //---------------------------------------------------------------------------
33 //---------------------------------------------------------------------------
34 #include "wx/mediactrl.h"
36 //---------------------------------------------------------------------------
38 //---------------------------------------------------------------------------
41 //---------------------------------------------------------------------------
42 // Externals (somewhere in src/msw/app.cpp)
43 //---------------------------------------------------------------------------
44 extern "C" WXDLLIMPEXP_BASE HINSTANCE
wxGetInstance(void);
46 extern WXDLLIMPEXP_CORE wxChar
*wxCanvasClassName
;
48 extern WXDLLIMPEXP_CORE
const wxChar
*wxCanvasClassName
;
51 //===========================================================================
52 // BACKEND DECLARATIONS
53 //===========================================================================
55 //---------------------------------------------------------------------------
59 //---------------------------------------------------------------------------
61 //---------------------------------------------------------------------------
62 // Compilation guard for DirectShow
63 //---------------------------------------------------------------------------
66 //---------------------------------------------------------------------------
67 // DirectShow includes
68 //---------------------------------------------------------------------------
71 class WXDLLIMPEXP_MEDIA wxAMMediaBackend
: public wxMediaBackend
76 virtual ~wxAMMediaBackend();
78 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
83 const wxValidator
& validator
,
84 const wxString
& name
);
90 virtual bool Load(const wxString
& fileName
);
91 virtual bool Load(const wxURI
& location
);
93 virtual wxMediaState
GetState();
95 virtual bool SetPosition(wxLongLong where
);
96 virtual wxLongLong
GetPosition();
97 virtual wxLongLong
GetDuration();
99 virtual void Move(int x
, int y
, int w
, int h
);
100 wxSize
GetVideoSize() const;
102 virtual double GetPlaybackRate();
103 virtual bool SetPlaybackRate(double);
109 static LRESULT CALLBACK
NotifyWndProc(HWND hWnd
, UINT nMsg
,
110 WPARAM wParam
, LPARAM lParam
);
112 LRESULT CALLBACK
OnNotifyWndProc(HWND hWnd
, UINT nMsg
,
113 WPARAM wParam
, LPARAM lParam
);
117 IGraphBuilder
* m_pGB
;
118 IMediaControl
* m_pMC
;
119 IMediaEventEx
* m_pME
;
123 IMediaSeeking
* m_pMS
;
128 DECLARE_DYNAMIC_CLASS(wxAMMediaBackend
);
131 #endif //wxUSE_DIRECTSHOW
133 //---------------------------------------------------------------------------
137 //---------------------------------------------------------------------------
139 //---------------------------------------------------------------------------
141 //---------------------------------------------------------------------------
142 #include <mmsystem.h>
144 class WXDLLIMPEXP_MEDIA wxMCIMediaBackend
: public wxMediaBackend
149 ~wxMCIMediaBackend();
151 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
156 const wxValidator
& validator
,
157 const wxString
& name
);
160 virtual bool Pause();
163 virtual bool Load(const wxString
& fileName
);
164 virtual bool Load(const wxURI
& location
);
166 virtual wxMediaState
GetState();
168 virtual bool SetPosition(wxLongLong where
);
169 virtual wxLongLong
GetPosition();
170 virtual wxLongLong
GetDuration();
172 virtual void Move(int x
, int y
, int w
, int h
);
173 wxSize
GetVideoSize() const;
175 virtual double GetPlaybackRate();
176 virtual bool SetPlaybackRate(double dRate
);
178 static LRESULT CALLBACK
NotifyWndProc(HWND hWnd
, UINT nMsg
,
179 WPARAM wParam
, LPARAM lParam
);
181 LRESULT CALLBACK
OnNotifyWndProc(HWND hWnd
, UINT nMsg
,
182 WPARAM wParam
, LPARAM lParam
);
184 MCIDEVICEID m_hDev
; //Our MCI Device ID/Handler
185 wxControl
* m_ctrl
; //Parent control
186 HWND m_hNotifyWnd
; //Window to use for MCI events
187 bool m_bVideo
; //Whether or not we have video
189 DECLARE_DYNAMIC_CLASS(wxMCIMediaBackend
)
192 //---------------------------------------------------------------------------
196 //---------------------------------------------------------------------------
198 //---------------------------------------------------------------------------
199 // QT Compilation Guard
200 //---------------------------------------------------------------------------
203 //---------------------------------------------------------------------------
205 //---------------------------------------------------------------------------
206 #include <qtml.h> //Windoze QT include
207 #include <QuickTimeComponents.h> //Standard QT stuff
209 class WXDLLIMPEXP_MEDIA wxQTMediaBackend
: public wxMediaBackend
216 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
221 const wxValidator
& validator
,
222 const wxString
& name
);
225 virtual bool Pause();
228 virtual bool Load(const wxString
& fileName
);
229 virtual bool Load(const wxURI
& location
);
231 virtual wxMediaState
GetState();
233 virtual bool SetPosition(wxLongLong where
);
234 virtual wxLongLong
GetPosition();
235 virtual wxLongLong
GetDuration();
237 virtual void Move(int x
, int y
, int w
, int h
);
238 wxSize
GetVideoSize() const;
240 virtual double GetPlaybackRate();
241 virtual bool SetPlaybackRate(double dRate
);
246 wxSize m_bestSize
; //Original movie size
247 struct MovieRecord
* m_movie
; //QT Movie handle/instance
248 wxControl
* m_ctrl
; //Parent control
249 bool m_bVideo
; //Whether or not we have video
250 class _wxQTTimer
* m_timer
; //Timer for streaming the movie
252 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
);
255 //---------------------------------------------------------------------------
256 // End QT Compilation Guard
257 //---------------------------------------------------------------------------
258 #endif //wxUSE_QUICKTIME
260 //===========================================================================
262 //===========================================================================
264 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
268 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
270 //---------------------------------------------------------------------------
271 // Only use if user wants it -
272 //---------------------------------------------------------------------------
275 IMPLEMENT_DYNAMIC_CLASS(wxAMMediaBackend
, wxMediaBackend
);
277 // Numerical value for when the graph reaches the stop position
278 #define WM_GRAPHNOTIFY WM_USER+13
280 //---------------------------------------------------------------------------
281 // Usual debugging macros
282 //---------------------------------------------------------------------------
284 #define wxAMVERIFY(x) \
286 HRESULT hrdsv = (x); \
287 if ( FAILED(hrdsv) ) \
289 /*TCHAR szError[MAX_ERROR_TEXT_LEN];*/ \
290 /*if( AMGetErrorText(hrdsv, szError, MAX_ERROR_TEXT_LEN) == 0)*/ \
292 /*wxFAIL_MSG( wxString::Format(wxT("DirectShow error \"%s\" ")*/\
293 /*wxT("occured at line %i in ")*/ \
294 /*wxT("mediactrl.cpp"),*/ \
295 /*szError, __LINE__) );*/ \
298 wxFAIL_MSG( wxString::Format(wxT("Unknown error (%i) ") \
300 wxT(" line %i in mediactrl.cpp."), \
301 (int)hrdsv, __LINE__) ); \
304 #define wxVERIFY(x) wxASSERT((x))
306 #define wxAMVERIFY(x) (x)
307 #define wxVERIFY(x) (x)
310 //---------------------------------------------------------------------------
311 // Standard macros for ease of use
312 //---------------------------------------------------------------------------
313 #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
315 //---------------------------------------------------------------------------
316 // wxAMMediaBackend Constructor
318 // Sets m_hNotifyWnd to NULL to signify that we haven't loaded anything yet
319 //---------------------------------------------------------------------------
320 wxAMMediaBackend::wxAMMediaBackend() : m_hNotifyWnd(NULL
)
324 //---------------------------------------------------------------------------
325 // wxAMMediaBackend Destructor
327 // Cleans up everything
328 //---------------------------------------------------------------------------
329 wxAMMediaBackend::~wxAMMediaBackend()
335 //---------------------------------------------------------------------------
336 // wxAMMediaBackend::CreateControl
338 // ActiveMovie does not really have any native control to speak of,
339 // so we just create a normal control.
341 // We also check to see if ActiveMovie is installed
342 //---------------------------------------------------------------------------
343 bool wxAMMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
348 const wxValidator
& validator
,
349 const wxString
& name
)
351 //create our filter graph
352 HRESULT hr
= CoCreateInstance(CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
353 IID_IGraphBuilder
, (void**)&m_pGB
);
355 //directshow not installed?
359 //release the filter graph - we don't need it yet
365 // By default wxWindow(s) is created with a border -
366 // so we need to get rid of those, and create with
367 // wxCLIP_CHILDREN, so that if the driver/backend
368 // is a child window, it refereshes properly
370 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
371 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
| wxCLIP_CHILDREN
,
380 //---------------------------------------------------------------------------
381 // wxAMMediaBackend::Load (file version)
383 // Creates an Active Movie filter graph from a file or url
384 //---------------------------------------------------------------------------
385 bool wxAMMediaBackend::Load(const wxString
& fileName
)
390 CoCreateInstance(CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
391 IID_IGraphBuilder
, (void**)&m_pGB
);
393 //load the graph & render
394 if( FAILED(m_pGB
->RenderFile(fileName
.wc_str(wxConvLocal
), NULL
)) )
397 //get the interfaces, all of them
398 wxAMVERIFY( m_pGB
->QueryInterface(IID_IMediaControl
, (void**)&m_pMC
) );
399 wxAMVERIFY( m_pGB
->QueryInterface(IID_IMediaEventEx
, (void**)&m_pME
) );
400 wxAMVERIFY( m_pGB
->QueryInterface(IID_IMediaSeeking
, (void**)&m_pMS
) );
401 wxAMVERIFY( m_pGB
->QueryInterface(IID_IVideoWindow
, (void**)&m_pVW
) );
402 wxAMVERIFY( m_pGB
->QueryInterface(IID_IBasicAudio
, (void**)&m_pBA
) );
403 wxAMVERIFY( m_pGB
->QueryInterface(IID_IBasicVideo
, (void**)&m_pBV
) );
405 //We could tell if the media has audio or not by
409 //pBA->get_Volume(&lVolume) == E_NOTIMPL
414 //Obtain the _actual_ size of the movie & remember it
419 m_bestSize
.x
= m_bestSize
.y
= 0;
421 m_bVideo
= SUCCEEDED( m_pVW
->GetWindowPosition( &nX
,
423 (long*)&m_bestSize
.x
,
424 (long*)&m_bestSize
.y
) );
427 //If we have video in the media - set it up so that
428 //its a child window of the control, its visible,
429 //and that the control is the owner of the video window
433 wxAMVERIFY( m_pVW
->put_Owner((OAHWND
)m_ctrl
->GetHandle()) );
434 wxAMVERIFY( m_pVW
->put_WindowStyle(WS_CHILD
| WS_CLIPSIBLINGS
) );
435 wxAMVERIFY( m_pVW
->put_Visible(OATRUE
) ); //OATRUE == -1
439 // Create a hidden window and register to handle
440 // directshow events for this graph
441 // Note that wxCanvasClassName is already registered
442 // and used by all wxWindows and normal wxControls
444 m_hNotifyWnd
= ::CreateWindow
458 wxLogSysError( wxT("Could not create hidden needed for ")
459 wxT("registering for DirectShow events!") );
464 ::SetWindowLongPtr(m_hNotifyWnd
, GWLP_WNDPROC
,
465 (LONG_PTR
)wxAMMediaBackend::NotifyWndProc
);
467 ::SetWindowLong(m_hNotifyWnd
, GWL_USERDATA
,
470 wxAMVERIFY( m_pME
->SetNotifyWindow((OAHWND
)m_hNotifyWnd
,
471 WM_GRAPHNOTIFY
, 0) );
474 //set the time format
476 wxAMVERIFY( m_pMS
->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME
) );
479 // Force the parent window of this control to recalculate
480 // the size of this if sizers are being used
481 // and render the results immediately
483 m_ctrl
->InvalidateBestSize();
484 m_ctrl
->GetParent()->Layout();
485 m_ctrl
->GetParent()->Refresh();
486 m_ctrl
->GetParent()->Update();
491 //---------------------------------------------------------------------------
492 // wxAMMediaBackend::Load (URL Version)
494 // Loads media from a URL. Interestingly enough DirectShow
495 // appears (?) to escape the URL for us, at least on normal
497 //---------------------------------------------------------------------------
498 bool wxAMMediaBackend::Load(const wxURI
& location
)
500 return Load(location
.BuildUnescapedURI());
503 //---------------------------------------------------------------------------
504 // wxAMMediaBackend::Play
506 // Plays the stream. If it is non-seekable, it will restart it.
507 //---------------------------------------------------------------------------
508 bool wxAMMediaBackend::Play()
510 return SUCCEEDED( m_pMC
->Run() );
513 //---------------------------------------------------------------------------
514 // wxAMMediaBackend::Pause
516 // Pauses the stream.
517 //---------------------------------------------------------------------------
518 bool wxAMMediaBackend::Pause()
520 return SUCCEEDED( m_pMC
->Pause() );
523 //---------------------------------------------------------------------------
524 // wxAMMediaBackend::Stop
527 //---------------------------------------------------------------------------
528 bool wxAMMediaBackend::Stop()
530 bool bOK
= SUCCEEDED( m_pMC
->Stop() );
532 //We don't care if it can't get to the beginning in directshow -
533 //it could be a non-seeking filter (wince midi) in which case playing
534 //starts all over again
539 //---------------------------------------------------------------------------
540 // wxAMMediaBackend::SetPosition
542 // 1) Translates the current position's time to directshow time,
543 // which is in a scale of 100 nanoseconds
544 // 2) Sets the play position of the IMediaSeeking interface -
545 // passing NULL as the stop position means to keep the old
547 //---------------------------------------------------------------------------
548 bool wxAMMediaBackend::SetPosition(wxLongLong where
)
550 LONGLONG pos
= ((LONGLONG
)where
.GetValue()) * 10000;
552 return SUCCEEDED( m_pMS
->SetPositions(
554 AM_SEEKING_AbsolutePositioning
,
556 AM_SEEKING_NoPositioning
560 //---------------------------------------------------------------------------
561 // wxAMMediaBackend::GetPosition
563 // 1) Obtains the current play and stop positions from IMediaSeeking
564 // 2) Returns the play position translated to our time base
565 //---------------------------------------------------------------------------
566 wxLongLong
wxAMMediaBackend::GetPosition()
568 LONGLONG outCur
, outStop
;
569 wxAMVERIFY( m_pMS
->GetPositions(&outCur
, &outStop
) );
571 //h,m,s,milli - outdur is in 100 nanos
575 //---------------------------------------------------------------------------
576 // wxAMMediaBackend::GetDuration
578 // 1) Obtains the duration of the media from the IMediaSeeking interface
579 // 2) Converts that value to our time base, and returns it
580 //---------------------------------------------------------------------------
581 wxLongLong
wxAMMediaBackend::GetDuration()
583 LONGLONG outDuration
;
584 wxAMVERIFY( m_pMS
->GetDuration(&outDuration
) );
586 //h,m,s,milli - outdur is in 100 nanos
587 return outDuration
/10000;
590 //---------------------------------------------------------------------------
591 // wxAMMediaBackend::GetState
593 // Obtains the state from the IMediaControl interface.
594 // Note that it's enumeration values for stopping/playing
595 // etc. are the same as ours, so we just do a straight cast.
596 // TODO: MS recommends against INFINITE here for
597 // IMediaControl::GetState- do it in stages
598 //---------------------------------------------------------------------------
599 wxMediaState
wxAMMediaBackend::GetState()
602 OAFilterState theState
;
603 hr
= m_pMC
->GetState(INFINITE
, &theState
);
605 wxASSERT( SUCCEEDED(hr
) );
607 //MSW state is the same as ours
609 //State_Paused = State_Stopped + 1,
610 //State_Running = State_Paused + 1
612 return (wxMediaState
) theState
;
615 //---------------------------------------------------------------------------
616 // wxAMMediaBackend::GetPlaybackRate
618 // Pretty simple way of obtaining the playback rate from
619 // the IMediaSeeking interface
620 //---------------------------------------------------------------------------
621 double wxAMMediaBackend::GetPlaybackRate()
624 wxAMVERIFY( m_pMS
->GetRate(&dRate
) );
628 //---------------------------------------------------------------------------
629 // wxAMMediaBackend::SetPlaybackRate
631 // Sets the playback rate of the media - DirectShow is pretty good
632 // about this, actually
633 //---------------------------------------------------------------------------
634 bool wxAMMediaBackend::SetPlaybackRate(double dRate
)
636 return SUCCEEDED( m_pMS
->SetRate(dRate
) );
639 //---------------------------------------------------------------------------
640 // wxAMMediaBackend::NotifyWndProc
642 // Here we check to see if DirectShow tells us we've reached the stop
643 // position in our stream - if it has, it may not actually stop
644 // the stream - which we need to do...
645 //---------------------------------------------------------------------------
646 LRESULT CALLBACK
wxAMMediaBackend::NotifyWndProc(HWND hWnd
, UINT nMsg
,
650 wxAMMediaBackend
* backend
= (wxAMMediaBackend
*)
651 ::GetWindowLong(hWnd
, GWL_USERDATA
);
653 return backend
->OnNotifyWndProc(hWnd
, nMsg
, wParam
, lParam
);
656 LRESULT CALLBACK
wxAMMediaBackend::OnNotifyWndProc(HWND hWnd
, UINT nMsg
,
660 if (nMsg
== WM_GRAPHNOTIFY
)
667 // DirectShow keeps a list of queued events, and we need
668 // to go through them one by one, stopping at (Hopefully only one)
669 // EC_COMPLETE message
671 while(SUCCEEDED(m_pME
->GetEvent(&evCode
, (LONG_PTR
*) &evParam1
,
672 (LONG_PTR
*) &evParam2
, 0)
676 // Cleanup memory that GetEvent allocated
677 wxAMVERIFY( m_pME
->FreeEventParams(evCode
, evParam1
, evParam2
) );
679 // If this is the end of the clip, notify handler
680 if(EC_COMPLETE
== evCode
)
682 //send the event to our child
683 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
, m_ctrl
->GetId());
684 m_ctrl
->ProcessEvent(theEvent
);
686 //if the user didn't veto it, stop the stream
687 if (theEvent
.IsAllowed())
689 //Interestingly enough, DirectShow does not actually stop
690 //the filters - even when it reaches the end!
693 //send the event to our child
694 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
696 m_ctrl
->ProcessEvent(theEvent
);
701 return DefWindowProc(hWnd
, nMsg
, wParam
, lParam
);
704 //---------------------------------------------------------------------------
705 // wxAMMediaBackend::Cleanup
707 // 1) Hide/disowns the video window (MS says bad things will happen if
709 // 2) Releases all the directshow interfaces we use
710 // TODO: Maybe there's a way to redirect the IGraphBuilder each time
711 // we load, rather then creating and destroying the interfaces
713 //---------------------------------------------------------------------------
714 void wxAMMediaBackend::Cleanup()
716 // Hide then disown the window
719 m_pVW
->put_Visible(OAFALSE
); //OSFALSE == 0
720 m_pVW
->put_Owner(NULL
);
723 // Release and zero DirectShow interfaces
732 // Get rid of our hidden Window
733 DestroyWindow(m_hNotifyWnd
);
738 //---------------------------------------------------------------------------
739 // wxAMMediaBackend::GetVideoSize
741 // Obtains the cached original video size
742 //---------------------------------------------------------------------------
743 wxSize
wxAMMediaBackend::GetVideoSize() const
748 //---------------------------------------------------------------------------
749 // wxAMMediaBackend::Move
751 // Resizes the IVideoWindow to the size of the control window
752 //---------------------------------------------------------------------------
753 void wxAMMediaBackend::Move(int x
, int y
, int w
, int h
)
755 if(m_hNotifyWnd
&& m_bVideo
)
757 wxAMVERIFY( m_pVW
->SetWindowPosition(0, 0, w
, h
) );
761 //---------------------------------------------------------------------------
762 // End of wxAMMediaBackend
763 //---------------------------------------------------------------------------
764 #endif //wxUSE_DIRECTSHOW
766 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
770 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
773 IMPLEMENT_DYNAMIC_CLASS(wxMCIMediaBackend
, wxMediaBackend
);
775 //---------------------------------------------------------------------------
776 // Usual debugging macros for MCI returns
777 //---------------------------------------------------------------------------
780 #define wxMCIVERIFY(arg) \
783 if ( (nRet = (arg)) != 0) \
786 mciGetErrorString(nRet, sz, 5000); \
787 wxFAIL_MSG(wxString::Format(_T("MCI Error:%s"), sz)); \
791 #define wxMCIVERIFY(arg) (arg);
794 //---------------------------------------------------------------------------
795 // Simulation for <digitalv.h>
797 // Mingw and possibly other compilers don't have the digitalv.h header
798 // that is needed to have some essential features of mci work with
799 // windows - so we provide the declarations for the types we use here
800 //---------------------------------------------------------------------------
803 DWORD_PTR dwCallback
;
804 #ifdef MCI_USE_OFFEXT
810 } MCI_DGV_RECT_PARMS
;
813 DWORD_PTR dwCallback
;
823 } MCI_DGV_WINDOW_PARMS
;
826 DWORD_PTR dwCallback
;
833 //---------------------------------------------------------------------------
834 // wxMCIMediaBackend Constructor
836 // Here we don't need to do much except say we don't have any video :)
837 //---------------------------------------------------------------------------
838 wxMCIMediaBackend::wxMCIMediaBackend() : m_hNotifyWnd(NULL
), m_bVideo(false)
842 //---------------------------------------------------------------------------
843 // wxMCIMediaBackend Destructor
845 // We close the mci device - note that there may not be an mci device here,
846 // or it may fail - but we don't really care, since we're destructing
847 //---------------------------------------------------------------------------
848 wxMCIMediaBackend::~wxMCIMediaBackend()
852 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
853 DestroyWindow(m_hNotifyWnd
);
858 //---------------------------------------------------------------------------
859 // wxMCIMediaBackend::Create
861 // Here we just tell wxMediaCtrl that mci does exist (which it does, on all
862 // msw systems, at least in some form dating back to win16 days)
863 //---------------------------------------------------------------------------
864 bool wxMCIMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
869 const wxValidator
& validator
,
870 const wxString
& name
)
874 // By default wxWindow(s) is created with a border -
875 // so we need to get rid of those, and create with
876 // wxCLIP_CHILDREN, so that if the driver/backend
877 // is a child window, it refereshes properly
879 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
880 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
| wxCLIP_CHILDREN
,
888 //---------------------------------------------------------------------------
889 // wxMCIMediaBackend::Load (file version)
891 // Here we have MCI load a file and device, set the time format to our
892 // default (milliseconds), and set the video (if any) to play in the control
893 //---------------------------------------------------------------------------
894 bool wxMCIMediaBackend::Load(const wxString
& fileName
)
897 //if the user already called load close the previous MCI device
901 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
902 DestroyWindow(m_hNotifyWnd
);
907 //Opens a file and has MCI select a device. Normally you'd put
908 //MCI_OPEN_TYPE in addition to MCI_OPEN_ELEMENT - however if you
909 //omit this it tells MCI to select the device instead. This is
910 //good because we have no reliable way of "enumerating" the devices
913 MCI_OPEN_PARMS openParms
;
914 openParms
.lpstrElementName
= (wxChar
*) fileName
.c_str();
916 if ( mciSendCommand(0, MCI_OPEN
, MCI_OPEN_ELEMENT
,
917 (DWORD
)(LPVOID
)&openParms
) != 0)
920 m_hDev
= openParms
.wDeviceID
;
923 //Now set the time format for the device to milliseconds
925 MCI_SET_PARMS setParms
;
926 setParms
.dwCallback
= 0;
927 setParms
.dwTimeFormat
= MCI_FORMAT_MILLISECONDS
;
929 if (mciSendCommand(m_hDev
, MCI_SET
, MCI_SET_TIME_FORMAT
,
930 (DWORD
)(LPVOID
)&setParms
) != 0)
934 //Now tell the MCI device to display the video in our wxMediaCtrl
936 MCI_DGV_WINDOW_PARMS windowParms
;
937 windowParms
.hWnd
= (HWND
)m_ctrl
->GetHandle();
939 m_bVideo
= (mciSendCommand(m_hDev
, MCI_WINDOW
,
940 0x00010000L
, //MCI_DGV_WINDOW_HWND
941 (DWORD
)(LPVOID
)&windowParms
) == 0);
944 // Create a hidden window and register to handle
946 // Note that wxCanvasClassName is already registered
947 // and used by all wxWindows and normal wxControls
949 m_hNotifyWnd
= ::CreateWindow
963 wxLogSysError( wxT("Could not create hidden needed for ")
964 wxT("registering for DirectShow events!") );
969 ::SetWindowLong(m_hNotifyWnd
, GWL_WNDPROC
,
970 (LONG
)wxMCIMediaBackend::NotifyWndProc
);
972 ::SetWindowLong(m_hNotifyWnd
, GWL_USERDATA
,
978 //Here, if the parent of the control has a sizer - we
979 //tell it to recalculate the size of this control since
980 //the user opened a seperate media file
982 m_ctrl
->InvalidateBestSize();
983 m_ctrl
->GetParent()->Layout();
984 m_ctrl
->GetParent()->Refresh();
985 m_ctrl
->GetParent()->Update();
990 //---------------------------------------------------------------------------
991 // wxMCIMediaBackend::Load (URL version)
993 // MCI doesn't support URLs directly (?)
995 // TODO: Use wxURL/wxFileSystem and mmioInstallProc
996 //---------------------------------------------------------------------------
997 bool wxMCIMediaBackend::Load(const wxURI
& WXUNUSED(location
))
1002 //---------------------------------------------------------------------------
1003 // wxMCIMediaBackend::Play
1005 // Plays/Resumes the MCI device... a couple notes:
1006 // 1) Certain drivers will crash and burn if we don't pass them an
1007 // MCI_PLAY_PARMS, despite the documentation that says otherwise...
1008 // 2) There is a MCI_RESUME command, but MCI_PLAY does the same thing
1009 // and will resume from a stopped state also, so there's no need to
1010 // call both, for example
1011 //---------------------------------------------------------------------------
1012 bool wxMCIMediaBackend::Play()
1014 MCI_PLAY_PARMS playParms
;
1015 playParms
.dwCallback
= (DWORD
)m_hNotifyWnd
;
1017 bool bOK
= ( mciSendCommand(m_hDev
, MCI_PLAY
, MCI_NOTIFY
,
1018 (DWORD
)(LPVOID
)&playParms
) == 0 );
1021 m_ctrl
->Show(m_bVideo
);
1026 //---------------------------------------------------------------------------
1027 // wxMCIMediaBackend::Pause
1029 // Pauses the MCI device - nothing special
1030 //---------------------------------------------------------------------------
1031 bool wxMCIMediaBackend::Pause()
1033 return (mciSendCommand(m_hDev
, MCI_PAUSE
, MCI_WAIT
, 0) == 0);
1036 //---------------------------------------------------------------------------
1037 // wxMCIMediaBackend::Stop
1039 // Stops the MCI device & seeks to the beginning as wxMediaCtrl docs outline
1040 //---------------------------------------------------------------------------
1041 bool wxMCIMediaBackend::Stop()
1043 return (mciSendCommand(m_hDev
, MCI_STOP
, MCI_WAIT
, 0) == 0) &&
1044 (mciSendCommand(m_hDev
, MCI_SEEK
, MCI_SEEK_TO_START
, 0) == 0);
1047 //---------------------------------------------------------------------------
1048 // wxMCIMediaBackend::GetState
1050 // Here we get the state and convert it to a wxMediaState -
1051 // since we use direct comparisons with MCI_MODE_PLAY and
1052 // MCI_MODE_PAUSE, we don't care if the MCI_STATUS call
1054 //---------------------------------------------------------------------------
1055 wxMediaState
wxMCIMediaBackend::GetState()
1057 MCI_STATUS_PARMS statusParms
;
1058 statusParms
.dwItem
= MCI_STATUS_MODE
;
1060 mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
1061 (DWORD
)(LPVOID
)&statusParms
);
1063 if(statusParms
.dwReturn
== MCI_MODE_PAUSE
)
1064 return wxMEDIASTATE_PAUSED
;
1065 else if(statusParms
.dwReturn
== MCI_MODE_PLAY
)
1066 return wxMEDIASTATE_PLAYING
;
1068 return wxMEDIASTATE_STOPPED
;
1071 //---------------------------------------------------------------------------
1072 // wxMCIMediaBackend::SetPosition
1074 // Here we set the position of the device in the stream.
1075 // Note that MCI actually stops the device after you seek it if the
1076 // device is playing/paused, so we need to play the file after
1077 // MCI seeks like normal APIs would
1078 //---------------------------------------------------------------------------
1079 bool wxMCIMediaBackend::SetPosition(wxLongLong where
)
1081 MCI_SEEK_PARMS seekParms
;
1082 seekParms
.dwCallback
= 0;
1083 #if wxUSE_LONGLONG_NATIVE && !wxUSE_LONGLONG_WX
1084 seekParms
.dwTo
= (DWORD
)where
.GetValue();
1085 #else /* wxUSE_LONGLONG_WX */
1086 /* no way to return it in one piece */
1087 wxASSERT( where
.GetHi()==0 );
1088 seekParms
.dwTo
= (DWORD
)where
.GetLo();
1089 #endif /* wxUSE_LONGLONG_* */
1091 //device was playing?
1092 bool bReplay
= GetState() == wxMEDIASTATE_PLAYING
;
1094 if( mciSendCommand(m_hDev
, MCI_SEEK
, MCI_TO
,
1095 (DWORD
)(LPVOID
)&seekParms
) != 0)
1098 //If the device was playing, resume it
1105 //---------------------------------------------------------------------------
1106 // wxMCIMediaBackend::GetPosition
1108 // Gets the position of the device in the stream using the current
1109 // time format... nothing special here...
1110 //---------------------------------------------------------------------------
1111 wxLongLong
wxMCIMediaBackend::GetPosition()
1113 MCI_STATUS_PARMS statusParms
;
1114 statusParms
.dwItem
= MCI_STATUS_POSITION
;
1116 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
1117 (DWORD
)(LPSTR
)&statusParms
) != 0)
1120 return statusParms
.dwReturn
;
1123 //---------------------------------------------------------------------------
1124 // wxMCIMediaBackend::GetDuration
1126 // Gets the duration of the stream... nothing special
1127 //---------------------------------------------------------------------------
1128 wxLongLong
wxMCIMediaBackend::GetDuration()
1130 MCI_STATUS_PARMS statusParms
;
1131 statusParms
.dwItem
= MCI_STATUS_LENGTH
;
1133 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
1134 (DWORD
)(LPSTR
)&statusParms
) != 0)
1137 return statusParms
.dwReturn
;
1140 //---------------------------------------------------------------------------
1141 // wxMCIMediaBackend::Move
1143 // Moves the window to a location
1144 //---------------------------------------------------------------------------
1145 void wxMCIMediaBackend::Move(int WXUNUSED(x
), int WXUNUSED(y
),
1148 if (m_hNotifyWnd
&& m_bVideo
)
1150 MCI_DGV_RECT_PARMS putParms
; //ifdefed MCI_DGV_PUT_PARMS
1151 putParms
.rc
.top
= 0;
1152 putParms
.rc
.bottom
= 0;
1153 putParms
.rc
.right
= w
;
1154 putParms
.rc
.bottom
= h
;
1156 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_PUT
,
1157 0x00040000L
, //MCI_DGV_PUT_DESTINATION
1158 (DWORD
)(LPSTR
)&putParms
) );
1162 //---------------------------------------------------------------------------
1163 // wxMCIMediaBackend::GetVideoSize
1165 // Gets the original size of the movie for sizers
1166 //---------------------------------------------------------------------------
1167 wxSize
wxMCIMediaBackend::GetVideoSize() const
1171 MCI_DGV_RECT_PARMS whereParms
; //ifdefed MCI_DGV_WHERE_PARMS
1173 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_WHERE
,
1174 0x00020000L
, //MCI_DGV_WHERE_SOURCE
1175 (DWORD
)(LPSTR
)&whereParms
) );
1177 return wxSize(whereParms
.rc
.right
, whereParms
.rc
.bottom
);
1182 //---------------------------------------------------------------------------
1183 // wxMCIMediaBackend::GetPlaybackRate
1186 //---------------------------------------------------------------------------
1187 double wxMCIMediaBackend::GetPlaybackRate()
1192 //---------------------------------------------------------------------------
1193 // wxMCIMediaBackend::SetPlaybackRate
1196 //---------------------------------------------------------------------------
1197 bool wxMCIMediaBackend::SetPlaybackRate(double WXUNUSED(dRate
))
1200 MCI_WAVE_SET_SAMPLESPERSEC
1201 MCI_DGV_SET_PARMS setParms;
1202 setParms.dwSpeed = (DWORD) (dRate * 1000.0);
1204 return (mciSendCommand(m_hDev, MCI_SET,
1205 0x00020000L, //MCI_DGV_SET_SPEED
1206 (DWORD)(LPSTR)&setParms) == 0);
1211 //---------------------------------------------------------------------------
1212 // [static] wxMCIMediaBackend::MSWWindowProc
1214 // Here we process a message when MCI reaches the stopping point
1216 //---------------------------------------------------------------------------
1217 LRESULT CALLBACK
wxMCIMediaBackend::NotifyWndProc(HWND hWnd
, UINT nMsg
,
1221 wxMCIMediaBackend
* backend
= (wxMCIMediaBackend
*)
1222 ::GetWindowLong(hWnd
, GWL_USERDATA
);
1225 return backend
->OnNotifyWndProc(hWnd
, nMsg
, wParam
, lParam
);
1228 LRESULT CALLBACK
wxMCIMediaBackend::OnNotifyWndProc(HWND hWnd
, UINT nMsg
,
1232 if(nMsg
== MM_MCINOTIFY
)
1234 wxASSERT(lParam
== (LPARAM
) m_hDev
);
1235 if(wParam
== MCI_NOTIFY_SUCCESSFUL
&& lParam
== (LPARAM
)m_hDev
)
1237 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
, m_ctrl
->GetId());
1238 m_ctrl
->ProcessEvent(theEvent
);
1240 if(theEvent
.IsAllowed())
1242 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_SEEK
,
1243 MCI_SEEK_TO_START
, 0) );
1245 //send the event to our child
1246 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
1248 m_ctrl
->ProcessEvent(theEvent
);
1252 return DefWindowProc(hWnd
, nMsg
, wParam
, lParam
);
1254 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1258 // TODO: Use a less cludgy way to pause/get state/set state
1259 // TODO: Dynamically load from qtml.dll
1260 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1264 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
);
1266 //Time between timer calls
1267 #define MOVIE_DELAY 100
1269 #include "wx/timer.h"
1271 // --------------------------------------------------------------------------
1272 // wxQTTimer - Handle Asyncronous Playing
1273 // --------------------------------------------------------------------------
1274 class _wxQTTimer
: public wxTimer
1277 _wxQTTimer(Movie movie
, wxQTMediaBackend
* parent
) :
1278 m_movie(movie
), m_bPaused(false), m_parent(parent
)
1286 bool GetPaused() {return m_bPaused
;}
1287 void SetPaused(bool bPaused
) {m_bPaused
= bPaused
;}
1289 //-----------------------------------------------------------------------
1290 // _wxQTTimer::Notify
1292 // 1) Checks to see if the movie is done, and if not continues
1293 // streaming the movie
1294 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
1296 //-----------------------------------------------------------------------
1301 if(!IsMovieDone(m_movie
))
1302 MoviesTask(m_movie
, MOVIE_DELAY
);
1305 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
,
1306 m_parent
->m_ctrl
->GetId());
1307 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
1309 if(theEvent
.IsAllowed())
1313 wxASSERT(::GetMoviesError() == noErr
);
1315 //send the event to our child
1316 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
1317 m_parent
->m_ctrl
->GetId());
1318 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
1325 Movie m_movie
; //Our movie instance
1326 bool m_bPaused
; //Whether we are paused or not
1327 wxQTMediaBackend
* m_parent
; //Backend pointer
1330 //---------------------------------------------------------------------------
1331 // wxQTMediaBackend Destructor
1333 // Sets m_timer to NULL signifying we havn't loaded anything yet
1334 //---------------------------------------------------------------------------
1335 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL
)
1339 //---------------------------------------------------------------------------
1340 // wxQTMediaBackend Destructor
1342 // 1) Cleans up the QuickTime movie instance
1343 // 2) Decrements the QuickTime reference counter - if this reaches
1344 // 0, QuickTime shuts down
1345 // 3) Decrements the QuickTime Windows Media Layer reference counter -
1346 // if this reaches 0, QuickTime shuts down the Windows Media Layer
1347 //---------------------------------------------------------------------------
1348 wxQTMediaBackend::~wxQTMediaBackend()
1353 //Note that ExitMovies() is not neccessary, but
1354 //the docs are fuzzy on whether or not TerminateQTML is
1359 //---------------------------------------------------------------------------
1360 // wxQTMediaBackend::CreateControl
1362 // 1) Intializes QuickTime
1363 // 2) Creates the control window
1364 //---------------------------------------------------------------------------
1365 bool wxQTMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
1370 const wxValidator
& validator
,
1371 const wxString
& name
)
1374 if ((nError
= InitializeQTML(0)) != noErr
) //-2093 no dll
1376 wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError
));
1383 // By default wxWindow(s) is created with a border -
1384 // so we need to get rid of those
1386 // Since we don't have a child window like most other
1387 // backends, we don't need wxCLIP_CHILDREN
1389 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
1390 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
,
1398 //---------------------------------------------------------------------------
1399 // wxQTMediaBackend::Load (file version)
1401 // 1) Get an FSSpec from the Windows path name
1402 // 2) Open the movie
1403 // 3) Obtain the movie instance from the movie resource
1405 //---------------------------------------------------------------------------
1406 bool wxQTMediaBackend::Load(const wxString
& fileName
)
1415 if (NativePathNameToFSSpec ((char*) (const char*) fileName
.mb_str(),
1416 &sfFile
, 0) != noErr
)
1419 if (OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
1422 short movieResID
= 0;
1425 err
= NewMovieFromFile (
1433 CloseMovieFile (movieResFile
);
1440 return ::GetMoviesError() == noErr
;
1443 //---------------------------------------------------------------------------
1444 // wxQTMediaBackend::Move
1447 //---------------------------------------------------------------------------
1448 bool wxQTMediaBackend::Load(const wxURI
& location
)
1453 wxString theURI
= location
.BuildURI();
1457 Handle theHandle
= NewHandleClear(theURI
.length() + 1);
1458 wxASSERT(theHandle
);
1460 BlockMove(theURI
.mb_str(), *theHandle
, theURI
.length() + 1);
1462 //create the movie from the handle that refers to the URI
1463 err
= NewMovieFromDataRef(&m_movie
, newMovieActive
,
1465 URLDataHandlerSubType
);
1467 DisposeHandle(theHandle
);
1472 //preroll movie for streaming
1476 timeNow
= GetMovieTime(m_movie
, NULL
);
1477 playRate
= GetMoviePreferredRate(m_movie
);
1478 PrePrerollMovie(m_movie
, timeNow
, playRate
, NULL
, NULL
);
1479 PrerollMovie(m_movie
, timeNow
, playRate
);
1480 SetMovieRate(m_movie
, playRate
);
1484 return ::GetMoviesError() == noErr
;
1487 //---------------------------------------------------------------------------
1488 // wxQTMediaBackend::Move
1491 //---------------------------------------------------------------------------
1492 void wxQTMediaBackend::FinishLoad()
1494 m_timer
= new _wxQTTimer(m_movie
, (wxQTMediaBackend
*) this);
1497 //get the real size of the movie
1499 ::GetMovieNaturalBoundsRect (m_movie
, &outRect
);
1500 wxASSERT(::GetMoviesError() == noErr
);
1502 m_bestSize
.x
= outRect
.right
- outRect
.left
;
1503 m_bestSize
.y
= outRect
.bottom
- outRect
.top
;
1505 //reparent movie/*AudioMediaCharacteristic*/
1506 if(GetMovieIndTrackType(m_movie
, 1,
1507 VisualMediaCharacteristic
,
1508 movieTrackCharacteristic
|
1509 movieTrackEnabledOnly
) != NULL
)
1511 CreatePortAssociation(m_ctrl
->GetHWND(), NULL
, 0L);
1513 SetMovieGWorld(m_movie
,
1514 (CGrafPtr
) GetNativeWindowPort(m_ctrl
->GetHWND()),
1518 //we want millisecond precision
1519 ::SetMovieTimeScale(m_movie
, 1000);
1520 wxASSERT(::GetMoviesError() == noErr
);
1523 //Here, if the parent of the control has a sizer - we
1524 //tell it to recalculate the size of this control since
1525 //the user opened a seperate media file
1527 m_ctrl
->InvalidateBestSize();
1528 m_ctrl
->GetParent()->Layout();
1529 m_ctrl
->GetParent()->Refresh();
1530 m_ctrl
->GetParent()->Update();
1533 //---------------------------------------------------------------------------
1534 // wxQTMediaBackend::Move
1537 //---------------------------------------------------------------------------
1538 bool wxQTMediaBackend::Play()
1540 ::StartMovie(m_movie
);
1541 m_timer
->SetPaused(false);
1542 m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
1543 return ::GetMoviesError() == noErr
;
1546 //---------------------------------------------------------------------------
1547 // wxQTMediaBackend::Move
1550 //---------------------------------------------------------------------------
1551 bool wxQTMediaBackend::Pause()
1553 ::StopMovie(m_movie
);
1554 m_timer
->SetPaused(true);
1556 return ::GetMoviesError() == noErr
;
1559 //---------------------------------------------------------------------------
1560 // wxQTMediaBackend::Move
1563 //---------------------------------------------------------------------------
1564 bool wxQTMediaBackend::Stop()
1566 m_timer
->SetPaused(false);
1569 ::StopMovie(m_movie
);
1570 if(::GetMoviesError() != noErr
)
1573 ::GoToBeginningOfMovie(m_movie
);
1574 return ::GetMoviesError() == noErr
;
1577 //---------------------------------------------------------------------------
1578 // wxQTMediaBackend::Move
1581 //---------------------------------------------------------------------------
1582 double wxQTMediaBackend::GetPlaybackRate()
1584 return ( ((double)::GetMovieRate(m_movie
)) / 0x10000);
1587 //---------------------------------------------------------------------------
1588 // wxQTMediaBackend::Move
1591 //---------------------------------------------------------------------------
1592 bool wxQTMediaBackend::SetPlaybackRate(double dRate
)
1594 ::SetMovieRate(m_movie
, (Fixed
) (dRate
* 0x10000));
1595 return ::GetMoviesError() == noErr
;
1598 //---------------------------------------------------------------------------
1599 // wxQTMediaBackend::Move
1602 //---------------------------------------------------------------------------
1603 bool wxQTMediaBackend::SetPosition(wxLongLong where
)
1605 TimeRecord theTimeRecord
;
1606 memset(&theTimeRecord
, 0, sizeof(TimeRecord
));
1607 theTimeRecord
.value
.lo
= where
.GetValue();
1608 theTimeRecord
.scale
= ::GetMovieTimeScale(m_movie
);
1609 theTimeRecord
.base
= ::GetMovieTimeBase(m_movie
);
1610 ::SetMovieTime(m_movie
, &theTimeRecord
);
1612 if (::GetMoviesError() != noErr
)
1618 //---------------------------------------------------------------------------
1619 // wxQTMediaBackend::GetPosition
1621 // 1) Calls GetMovieTime to get the position we are in in the movie
1622 // in milliseconds (we called
1623 //---------------------------------------------------------------------------
1624 wxLongLong
wxQTMediaBackend::GetPosition()
1626 return ::GetMovieTime(m_movie
, NULL
);
1629 //---------------------------------------------------------------------------
1630 // wxQTMediaBackend::Move
1633 //---------------------------------------------------------------------------
1634 wxLongLong
wxQTMediaBackend::GetDuration()
1636 return ::GetMovieDuration(m_movie
);
1639 //---------------------------------------------------------------------------
1640 // wxQTMediaBackend::Move
1643 //---------------------------------------------------------------------------
1644 wxMediaState
wxQTMediaBackend::GetState()
1646 if ( !m_timer
|| (m_timer
->IsRunning() == false &&
1647 m_timer
->GetPaused() == false) )
1648 return wxMEDIASTATE_STOPPED
;
1650 if( m_timer
->IsRunning() == true )
1651 return wxMEDIASTATE_PLAYING
;
1653 return wxMEDIASTATE_PAUSED
;
1656 //---------------------------------------------------------------------------
1657 // wxQTMediaBackend::Move
1660 //---------------------------------------------------------------------------
1661 void wxQTMediaBackend::Cleanup()
1667 DisposeMovie(m_movie
);
1670 //---------------------------------------------------------------------------
1671 // wxQTMediaBackend::Move
1674 //---------------------------------------------------------------------------
1675 wxSize
wxQTMediaBackend::GetVideoSize() const
1680 //---------------------------------------------------------------------------
1681 // wxQTMediaBackend::Move
1684 //---------------------------------------------------------------------------
1685 void wxQTMediaBackend::Move(int x
, int y
, int w
, int h
)
1689 Rect theRect
= {0, 0, h
, w
};
1691 ::SetMovieBox(m_movie
, &theRect
);
1692 wxASSERT(::GetMoviesError() == noErr
);
1696 //---------------------------------------------------------------------------
1697 // End QT Compilation Guard
1698 //---------------------------------------------------------------------------
1699 #endif //wxUSE_QUICKTIME
1701 //in source file that contains stuff you don't directly use
1702 #include <wx/html/forcelnk.h>
1703 FORCE_LINK_ME(basewxmediabackends
);
1705 //---------------------------------------------------------------------------
1706 // End wxMediaCtrl Compilation Guard and this file
1707 //---------------------------------------------------------------------------
1708 #endif //wxUSE_MEDIACTRL