1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/mediactrl.cpp
3 // Purpose: wxMediaCtrl MSW
4 // Author: Ryan Norton <wxprojects@comcast.net>
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 //---------------------------------------------------------------------------
14 //---------------------------------------------------------------------------
16 //#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
17 //#pragma implementation "moviectrl.h"
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
27 #include "wx/mediactrl.h"
31 //###########################################################################
33 //###########################################################################
35 IMPLEMENT_CLASS(wxMediaCtrl
, wxControl
);
36 IMPLEMENT_DYNAMIC_CLASS(wxMediaEvent
, wxEvent
);
37 DEFINE_EVENT_TYPE(wxEVT_MEDIA_FINISHED
);
39 //---------------------------------------------------------------------------
41 //---------------------------------------------------------------------------
46 wxMediaCtrlImpl() : m_bLoaded(false)
49 virtual ~wxMediaCtrlImpl()
52 virtual bool Create(wxMediaCtrl
* WXUNUSED(ctrl
))
55 virtual bool Play() { return false; }
56 virtual bool Pause() { return false; }
57 virtual bool Stop() { return false; }
59 virtual bool Load(const wxString
&) { return false; }
60 virtual bool Load(const wxURI
&) { return false; }
62 virtual wxMediaState
GetState() { return wxMEDIASTATE_STOPPED
; }
64 virtual bool SetPosition(long) { return 0; }
65 virtual long GetPosition() { return 0; }
66 virtual long GetDuration() { return 0; }
68 virtual void DoMoveWindow(int, int, int, int) { }
69 virtual wxSize
DoGetBestSize() const { return wxSize(0,0); }
71 virtual double GetPlaybackRate() { return 0; }
72 virtual bool SetPlaybackRate(double) { return false; }
74 virtual bool MSWWindowProc(WXUINT
, WXWPARAM
, WXLPARAM
) { return false; }
82 //---------------------------------------------------------------------------
84 //---------------------------------------------------------------------------
90 #define WM_GRAPHNOTIFY WM_USER+13
93 #define wxDSVERIFY(x) wxASSERT( SUCCEEDED ((x)) )
95 #define wxDSVERIFY(x) (x)
98 class wxDXMediaCtrlImpl
: public wxMediaCtrlImpl
103 virtual ~wxDXMediaCtrlImpl();
105 virtual bool Create(wxMediaCtrl
* ctrl
);
108 virtual bool Pause();
111 virtual bool Load(const wxString
& fileName
);
112 virtual bool Load(const wxURI
& location
);
114 virtual wxMediaState
GetState();
116 virtual bool SetPosition(long where
);
117 virtual long GetPosition();
118 virtual long GetDuration();
120 virtual void DoMoveWindow(int x
, int y
, int w
, int h
);
121 wxSize
DoGetBestSize() const;
123 virtual double GetPlaybackRate();
124 virtual bool SetPlaybackRate(double);
130 bool MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
);
134 IGraphBuilder
* m_pGB
;
135 IMediaControl
* m_pMC
;
136 IMediaEventEx
* m_pME
;
140 IMediaSeeking
* m_pMS
;
145 #endif //wxUSE_DIRECTSHOW
147 //---------------------------------------------------------------------------
148 // wxWMMEMediaCtrlImpl
149 //---------------------------------------------------------------------------
151 #include <mmsystem.h>
153 class wxWMMEMediaCtrlImpl
: public wxMediaCtrlImpl
157 wxWMMEMediaCtrlImpl();
158 ~wxWMMEMediaCtrlImpl();
160 virtual bool Create(wxMediaCtrl
* ctrl
);
163 virtual bool Pause();
166 virtual bool Load(const wxString
& fileName
);
167 virtual bool Load(const wxURI
& location
);
169 virtual wxMediaState
GetState();
171 virtual bool SetPosition(long where
);
172 virtual long GetPosition();
173 virtual long GetDuration();
175 virtual void DoMoveWindow(int x
, int y
, int w
, int h
);
176 wxSize
DoGetBestSize() const;
178 virtual double GetPlaybackRate();
179 virtual bool SetPlaybackRate(double);
181 bool MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
);
188 //###########################################################################
192 //###########################################################################
194 //---------------------------------------------------------------------------
198 //---------------------------------------------------------------------------
200 bool wxMediaCtrl::Create(wxWindow
* parent
, wxWindowID id
, const wxString
& fileName
,
201 const wxPoint
& pos
, const wxSize
& size
,
202 long style
, long WXUNUSED(driver
), const wxString
& name
)
205 if ( !wxControl::Create(parent
, id
, pos
, size
, (style
| wxNO_BORDER
) | wxCLIP_CHILDREN
,
206 wxDefaultValidator
, name
) )
209 //Set our background color to black by default
210 SetBackgroundColour(*wxBLACK
);
213 m_imp
= new wxDXMediaCtrlImpl
;
214 if(!m_imp
->Create(this))
218 m_imp
= new wxWMMEMediaCtrlImpl
;
219 if(!m_imp
->Create(this))
229 if(!fileName
.empty())
238 bool wxMediaCtrl::Create(wxWindow
* parent
, wxWindowID id
, const wxURI
& location
,
239 const wxPoint
& pos
, const wxSize
& size
,
240 long style
, long WXUNUSED(driver
), const wxString
& name
)
243 if ( !wxControl::Create(parent
, id
, pos
, size
, (style
| wxNO_BORDER
) | wxCLIP_CHILDREN
,
244 wxDefaultValidator
, name
) )
247 //Set our background color to black by default
248 SetBackgroundColour(*wxBLACK
);
251 m_imp
= new wxDXMediaCtrlImpl
;
252 if(!m_imp
->Create(this))
256 m_imp
= new wxWMMEMediaCtrlImpl
;
257 if(!m_imp
->Create(this))
273 bool wxMediaCtrl::Load(const wxString
& fileName
)
276 return m_imp
->Load(fileName
);
280 bool wxMediaCtrl::Load(const wxURI
& location
)
283 return m_imp
->Load(location
);
287 bool wxMediaCtrl::Play()
289 if(m_imp
&& m_imp
->IsLoaded())
290 return m_imp
->Play();
294 bool wxMediaCtrl::Pause()
296 if(m_imp
&& m_imp
->IsLoaded())
297 return m_imp
->Pause();
301 bool wxMediaCtrl::Stop()
303 if(m_imp
&& m_imp
->IsLoaded())
304 return m_imp
->Stop();
308 double wxMediaCtrl::GetPlaybackRate()
310 if(m_imp
&& m_imp
->IsLoaded())
311 return m_imp
->GetPlaybackRate();
315 bool wxMediaCtrl::SetPlaybackRate(double dRate
)
317 if(m_imp
&& m_imp
->IsLoaded())
318 return m_imp
->SetPlaybackRate(dRate
);
322 bool wxMediaCtrl::SetPosition(long where
)
324 if(m_imp
&& m_imp
->IsLoaded())
325 return m_imp
->SetPosition(where
);
329 long wxMediaCtrl::GetPosition()
331 if(m_imp
&& m_imp
->IsLoaded())
332 return m_imp
->GetPosition();
336 long wxMediaCtrl::GetDuration()
338 if(m_imp
&& m_imp
->IsLoaded())
339 return m_imp
->GetDuration();
343 wxMediaState
wxMediaCtrl::GetState()
345 if(m_imp
&& m_imp
->IsLoaded())
346 return m_imp
->GetState();
347 return wxMEDIASTATE_STOPPED
;
350 WXLRESULT
wxMediaCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
352 if(m_imp
&& m_imp
->IsLoaded() && m_imp
->MSWWindowProc(nMsg
, wParam
, lParam
) )
353 return wxControl::MSWDefWindowProc(nMsg
, wParam
, lParam
);
354 //pass the event to our parent
355 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
358 wxSize
wxMediaCtrl::DoGetBestSize() const
360 if(m_imp
&& m_imp
->IsLoaded())
361 return m_imp
->DoGetBestSize();
365 void wxMediaCtrl::DoMoveWindow(int x
, int y
, int w
, int h
)
367 wxControl::DoMoveWindow(x
,y
,w
,h
);
369 if(m_imp
&& m_imp
->IsLoaded())
370 m_imp
->DoMoveWindow(x
, y
, w
, h
);
373 wxMediaCtrl::~wxMediaCtrl()
380 //---------------------------------------------------------------------------
384 //---------------------------------------------------------------------------
388 wxDXMediaCtrlImpl::wxDXMediaCtrlImpl() : m_pGB(NULL
)
392 bool wxDXMediaCtrlImpl::Create(wxMediaCtrl
* ctrl
)
394 //create our filter graph
395 HRESULT hr
= CoCreateInstance(CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
396 IID_IGraphBuilder
, (void**)&m_pGB
);
398 //directshow not installed?
407 #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
409 bool wxDXMediaCtrlImpl::Load(const wxString
& fileName
)
416 CoCreateInstance(CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
417 IID_IGraphBuilder
, (void**)&m_pGB
);
419 //load the graph & render
420 if( FAILED(m_pGB
->RenderFile(fileName
.wc_str(wxConvLocal
), NULL
)) )
423 //get the interfaces, all of them
424 wxDSVERIFY( m_pGB
->QueryInterface(IID_IMediaControl
, (void**)&m_pMC
) );
425 wxDSVERIFY( m_pGB
->QueryInterface(IID_IMediaEventEx
, (void**)&m_pME
) );
426 wxDSVERIFY( m_pGB
->QueryInterface(IID_IMediaSeeking
, (void**)&m_pMS
) );
427 wxDSVERIFY( m_pGB
->QueryInterface(IID_IVideoWindow
, (void**)&m_pVW
) );
428 wxDSVERIFY( m_pGB
->QueryInterface(IID_IBasicAudio
, (void**)&m_pBA
) );
429 wxDSVERIFY( m_pGB
->QueryInterface(IID_IBasicVideo
, (void**)&m_pBV
) );
432 //pBA->get_Volume(&lVolume);
435 //get the _actual_ size of the movie & remember it
436 long nX
, nY
, nSX
, nSY
;
437 if (FAILED(m_pVW
->GetWindowPosition(&nX
,&nY
,&nSX
,&nSY
)))
453 wxDSVERIFY( m_pVW
->put_Owner((OAHWND
)m_ctrl
->GetHandle()) );
454 wxDSVERIFY( m_pVW
->put_WindowStyle(WS_CHILD
| WS_CLIPSIBLINGS
) );
455 wxDSVERIFY( m_pVW
->put_Visible(OATRUE
) ); //OATRUE == -1
458 //make it so that wxEVT_MOVIE_FINISHED works
459 wxDSVERIFY( m_pME
->SetNotifyWindow((OAHWND
)m_ctrl
->GetHandle(), WM_GRAPHNOTIFY
, 0) );
461 //set the time format
462 wxDSVERIFY( m_pMS
->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME
) );
464 //so that DoGetBestSize will work :)
467 //work around refresh issues
468 m_ctrl
->InvalidateBestSize();
469 m_ctrl
->GetParent()->Layout();
470 m_ctrl
->GetParent()->Refresh();
471 m_ctrl
->GetParent()->Update();
476 bool wxDXMediaCtrlImpl::Load(const wxURI
& location
)
478 return Load(location
.BuildUnescapedURI());
481 bool wxDXMediaCtrlImpl::Play()
483 return SUCCEEDED( m_pMC
->Run() );
486 bool wxDXMediaCtrlImpl::Pause()
488 return SUCCEEDED( m_pMC
->Pause() );
491 bool wxDXMediaCtrlImpl::Stop()
493 bool bOK
= SUCCEEDED( m_pMC
->Stop() );
495 //We don't care if it can't get to the beginning in directshow -
496 //it could be a non-seeking filter (wince midi) in which case playing
497 //starts all over again
502 bool wxDXMediaCtrlImpl::SetPosition(long where
)
504 //DS uses 100 nanos - so we need a 10 mult
505 LONGLONG pos
= ((LONGLONG
)where
) * 10000;
507 return SUCCEEDED( m_pMS
->SetPositions(
509 AM_SEEKING_AbsolutePositioning
,
511 AM_SEEKING_NoPositioning
515 long wxDXMediaCtrlImpl::GetPosition()
517 LONGLONG outCur
, outStop
;
518 wxDSVERIFY( m_pMS
->GetPositions(&outCur
, &outStop
) );
520 //h,m,s,milli - outdur is in 100 nanos
524 long wxDXMediaCtrlImpl::GetDuration()
526 LONGLONG outDuration
;
527 wxDSVERIFY( m_pMS
->GetDuration(&outDuration
) );
529 //h,m,s,milli - outdur is in 100 nanos
530 return outDuration
/10000;
533 wxMediaState
wxDXMediaCtrlImpl::GetState()
535 //TODO: MS recommends against INFINITE here - do it in stages
537 OAFilterState theState
;
538 hr
= m_pMC
->GetState(INFINITE
, &theState
);
540 wxASSERT( SUCCEEDED(hr
) );
542 //MSW state is the same as ours
544 //State_Paused = State_Stopped + 1,
545 //State_Running = State_Paused + 1
547 return (wxMediaState
) theState
;
550 double wxDXMediaCtrlImpl::GetPlaybackRate()
553 wxDSVERIFY( m_pMS
->GetRate(&dRate
) );
557 bool wxDXMediaCtrlImpl::SetPlaybackRate(double dRate
)
559 return SUCCEEDED( m_pMS
->SetRate(dRate
) );
562 bool wxDXMediaCtrlImpl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
564 if (nMsg
== WM_GRAPHNOTIFY
)
566 LONG evCode
, evParam1
, evParam2
;
569 // Process all queued events
570 while(SUCCEEDED(m_pME
->GetEvent(&evCode
, (LONG_PTR
*) &evParam1
,
571 (LONG_PTR
*) &evParam2
, 0)
575 // Free memory associated with callback, since we're not using it
576 hr
= m_pME
->FreeEventParams(evCode
, evParam1
, evParam2
);
578 // If this is the end of the clip, notify handler
579 if(EC_COMPLETE
== evCode
)
581 //Interestingly enough, DirectShow does not actually stop
582 //the filters - even when it reaches the end!
589 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
, m_ctrl
->GetId());
590 m_ctrl
->GetParent()->ProcessEvent(theEvent
);
598 void wxDXMediaCtrlImpl::Cleanup()
600 // Hide then disown the window
603 m_pVW
->put_Visible(OAFALSE
); //OSFALSE == 0
604 m_pVW
->put_Owner(NULL
);
607 // Release and zero DirectShow interfaces
616 wxDXMediaCtrlImpl::~wxDXMediaCtrlImpl()
624 wxSize
wxDXMediaCtrlImpl::DoGetBestSize() const
629 void wxDXMediaCtrlImpl::DoMoveWindow(int x
, int y
, int w
, int h
)
631 if(m_bLoaded
&& m_bVideo
)
633 wxDSVERIFY( m_pVW
->SetWindowPosition(0, 0, w
, h
) );
637 #endif //wxUSE_DIRECTSHOW
639 //---------------------------------------------------------------------------
641 // wxWMMEMediaCtrlImpl
643 //---------------------------------------------------------------------------
646 // Cruft to simulate digitalv.h
650 DWORD_PTR dwCallback
;
651 #ifdef MCI_USE_OFFEXT
657 } MCI_DGV_RECT_PARMS
;
660 DWORD_PTR dwCallback
;
670 } MCI_DGV_WINDOW_PARMSA
;
673 DWORD_PTR dwCallback
;
683 } MCI_DGV_WINDOW_PARMSW
;
685 typedef MCI_DGV_WINDOW_PARMSW MCI_DGV_WINDOW_PARMS
;
687 typedef MCI_DGV_WINDOW_PARMSA MCI_DGV_WINDOW_PARMS
;
690 wxWMMEMediaCtrlImpl::wxWMMEMediaCtrlImpl() : m_bVideo(false)
693 mciGetErrorString(nError, sz, 5000);
694 wxMessageBox(wxString::Format(_T("Error:%s"), sz));
698 wxWMMEMediaCtrlImpl::~wxWMMEMediaCtrlImpl()
700 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
703 bool wxWMMEMediaCtrlImpl::Create(wxMediaCtrl
* ctrl
)
709 bool wxWMMEMediaCtrlImpl::Load(const wxString
& fileName
)
712 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
714 MCI_OPEN_PARMS openParms
;
715 MCI_SET_PARMS setParms
;
717 openParms
.lpstrElementName
= (wxChar
*) fileName
.c_str();
719 //Here's where the trick lies - if you don't specify MCI_OPEN_TYPE,
720 //then it actually automagically finds the device for you!
721 if ( mciSendCommand(0, MCI_OPEN
,
723 (DWORD
)(LPVOID
)&openParms
) != 0)
726 m_hDev
= openParms
.wDeviceID
;
728 setParms
.dwCallback
= 0;
729 setParms
.dwTimeFormat
= MCI_FORMAT_MILLISECONDS
;
731 if (mciSendCommand(m_hDev
, MCI_SET
, MCI_SET_TIME_FORMAT
,
732 (DWORD
)(LPVOID
)&setParms
) != 0)
735 MCI_DGV_WINDOW_PARMS windowParms
;
737 windowParms
.hWnd
= (HWND
)m_ctrl
->GetHandle();
738 m_bVideo
= (mciSendCommand(m_hDev
, MCI_WINDOW
,
739 0x00010000L
//MCI_DGV_WINDOW_HWND
741 (DWORD
)(LPVOID
)&windowParms
) == 0);
744 //work around refresh issues
745 m_ctrl
->InvalidateBestSize();
746 m_ctrl
->GetParent()->Layout();
747 m_ctrl
->GetParent()->Refresh();
748 m_ctrl
->GetParent()->Update();
753 bool wxWMMEMediaCtrlImpl::Load(const wxURI
& WXUNUSED(location
))
758 bool wxWMMEMediaCtrlImpl::Play()
760 //the directshow driver ("mpegvideo") will crash if we don't do a playParms here
761 MCI_PLAY_PARMS playParms
;
762 playParms
.dwCallback
= (WORD
)(HWND
)m_ctrl
->GetHWND();
763 bool bOK
= mciSendCommand(m_hDev
, MCI_PLAY
, MCI_NOTIFY
, (DWORD
)(LPVOID
)&playParms
) == 0;
765 (mciSendCommand(m_hDev, MCI_RESUME, 0, 0) == 0);*/
768 bool wxWMMEMediaCtrlImpl::Pause()
770 return (mciSendCommand(m_hDev
, MCI_PAUSE
, MCI_WAIT
, 0) == 0);
773 bool wxWMMEMediaCtrlImpl::Stop()
775 return (mciSendCommand(m_hDev
, MCI_STOP
, MCI_WAIT
, 0) == 0) &&
776 (mciSendCommand(m_hDev
, MCI_SEEK
, MCI_SEEK_TO_START
, 0) == 0);
780 wxMediaState
wxWMMEMediaCtrlImpl::GetState()
782 MCI_STATUS_PARMS statusParms
;
783 statusParms
.dwItem
= MCI_STATUS_MODE
;
784 mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
785 (DWORD
)(LPVOID
)&statusParms
);
787 if(statusParms
.dwReturn
== MCI_MODE_PAUSE
)
788 return wxMEDIASTATE_PAUSED
;
789 else if(statusParms
.dwReturn
== MCI_MODE_PLAY
)
790 return wxMEDIASTATE_PLAYING
;
792 return wxMEDIASTATE_STOPPED
;
795 bool wxWMMEMediaCtrlImpl::SetPosition(long where
)
797 MCI_SEEK_PARMS seekParms
;
798 seekParms
.dwCallback
= 0;
799 seekParms
.dwTo
= where
;
801 bool bReplay
= GetState() == wxMEDIASTATE_PLAYING
;
803 if( mciSendCommand(m_hDev
, MCI_SEEK
, MCI_TO
, (DWORD
)(LPVOID
)&seekParms
) != 0)
812 long wxWMMEMediaCtrlImpl::GetPosition()
814 MCI_STATUS_PARMS statusParms
;
816 statusParms
.dwItem
= MCI_STATUS_POSITION
;
817 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
818 (DWORD
)(LPSTR
)&statusParms
) != 0)
821 return statusParms
.dwReturn
;
824 long wxWMMEMediaCtrlImpl::GetDuration()
826 MCI_STATUS_PARMS statusParms
;
828 statusParms
.dwItem
= MCI_STATUS_LENGTH
;
829 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
830 (DWORD
)(LPSTR
)&statusParms
) != 0)
833 return statusParms
.dwReturn
;
836 void wxWMMEMediaCtrlImpl::DoMoveWindow(int, int, int, int)
840 wxSize
wxWMMEMediaCtrlImpl::DoGetBestSize() const
844 MCI_DGV_RECT_PARMS rect
;
846 mciSendCommand(m_hDev
, MCI_WHERE
, 0x00020000L
//MCI_DGV_WHERE_SOURCE
848 (DWORD
)(LPSTR
)&rect
);
849 return wxSize(rect
.rc
.right
, rect
.rc
.bottom
);
854 double wxWMMEMediaCtrlImpl::GetPlaybackRate()
859 bool wxWMMEMediaCtrlImpl::SetPlaybackRate(double)
864 bool wxWMMEMediaCtrlImpl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
866 if(nMsg
== MM_MCINOTIFY
)
868 wxASSERT(lParam
== (WXLPARAM
) m_hDev
);
869 if(wParam
== (WXWPARAM
) MCI_NOTIFY_SUCCESSFUL
&& lParam
== (WXLPARAM
) m_hDev
)
872 wxASSERT(mciSendCommand(m_hDev
, MCI_SEEK
, MCI_SEEK_TO_START
, 0) == 0);
874 mciSendCommand(m_hDev
, MCI_SEEK
, MCI_SEEK_TO_START
, 0);
877 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
, m_ctrl
->GetId());
878 m_ctrl
->GetParent()->ProcessEvent(theEvent
);
885 #endif //wxUSE_MEDIACTRL