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 //---------------------------------------------------------------------------
86 #undef wxUSE_DIRECTSHOW
87 #define wxUSE_DIRECTSHOW 0
93 #define WM_GRAPHNOTIFY WM_USER+13
96 #define wxDSVERIFY(x) wxASSERT( SUCCEEDED ((x)) )
98 #define wxDSVERIFY(x) (x)
101 class wxDXMediaCtrlImpl
: public wxMediaCtrlImpl
106 virtual ~wxDXMediaCtrlImpl();
108 virtual bool Create(wxMediaCtrl
* ctrl
);
111 virtual bool Pause();
114 virtual bool Load(const wxString
& fileName
);
115 virtual bool Load(const wxURI
& location
);
117 virtual wxMediaState
GetState();
119 virtual bool SetPosition(long where
);
120 virtual long GetPosition();
121 virtual long GetDuration();
123 virtual void DoMoveWindow(int x
, int y
, int w
, int h
);
124 wxSize
DoGetBestSize() const;
126 virtual double GetPlaybackRate();
127 virtual bool SetPlaybackRate(double);
133 bool MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
);
137 IGraphBuilder
* m_pGB
;
138 IMediaControl
* m_pMC
;
139 IMediaEventEx
* m_pME
;
143 IMediaSeeking
* m_pMS
;
148 #endif //wxUSE_DIRECTSHOW
150 //---------------------------------------------------------------------------
151 // wxWMMEMediaCtrlImpl
152 //---------------------------------------------------------------------------
154 #include <mmsystem.h>
155 #include <digitalv.h>
157 class wxWMMEMediaCtrlImpl
: public wxMediaCtrlImpl
161 wxWMMEMediaCtrlImpl();
162 ~wxWMMEMediaCtrlImpl();
164 virtual bool Create(wxMediaCtrl
* ctrl
);
167 virtual bool Pause();
170 virtual bool Load(const wxString
& fileName
);
171 virtual bool Load(const wxURI
& location
);
173 virtual wxMediaState
GetState();
175 virtual bool SetPosition(long where
);
176 virtual long GetPosition();
177 virtual long GetDuration();
179 virtual void DoMoveWindow(int x
, int y
, int w
, int h
);
180 wxSize
DoGetBestSize() const;
182 virtual double GetPlaybackRate();
183 virtual bool SetPlaybackRate(double);
185 bool MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
);
192 //###########################################################################
196 //###########################################################################
198 //---------------------------------------------------------------------------
202 //---------------------------------------------------------------------------
204 bool wxMediaCtrl::Create(wxWindow
* parent
, wxWindowID id
, const wxString
& fileName
,
205 const wxPoint
& pos
, const wxSize
& size
,
206 long style
, long WXUNUSED(driver
), const wxString
& name
)
209 if ( !wxControl::Create(parent
, id
, pos
, size
, (style
| wxNO_BORDER
) | wxCLIP_CHILDREN
,
210 wxDefaultValidator
, name
) )
213 //Set our background color to black by default
214 SetBackgroundColour(*wxBLACK
);
217 m_imp
= new wxDXMediaCtrlImpl
;
218 if(!m_imp
->Create(this))
222 m_imp
= new wxWMMEMediaCtrlImpl
;
223 if(!m_imp
->Create(this))
233 if(!fileName
.empty())
242 bool wxMediaCtrl::Create(wxWindow
* parent
, wxWindowID id
, const wxURI
& location
,
243 const wxPoint
& pos
, const wxSize
& size
,
244 long style
, long WXUNUSED(driver
), const wxString
& name
)
247 if ( !wxControl::Create(parent
, id
, pos
, size
, (style
| wxNO_BORDER
) | wxCLIP_CHILDREN
,
248 wxDefaultValidator
, name
) )
251 //Set our background color to black by default
252 SetBackgroundColour(*wxBLACK
);
255 m_imp
= new wxDXMediaCtrlImpl
;
256 if(!m_imp
->Create(this))
260 m_imp
= new wxWMMEMediaCtrlImpl
;
261 if(!m_imp
->Create(this))
277 bool wxMediaCtrl::Load(const wxString
& fileName
)
280 return m_imp
->Load(fileName
);
284 bool wxMediaCtrl::Load(const wxURI
& location
)
287 return m_imp
->Load(location
);
291 bool wxMediaCtrl::Play()
293 if(m_imp
&& m_imp
->IsLoaded())
294 return m_imp
->Play();
298 bool wxMediaCtrl::Pause()
300 if(m_imp
&& m_imp
->IsLoaded())
301 return m_imp
->Pause();
305 bool wxMediaCtrl::Stop()
307 if(m_imp
&& m_imp
->IsLoaded())
308 return m_imp
->Stop();
312 double wxMediaCtrl::GetPlaybackRate()
314 if(m_imp
&& m_imp
->IsLoaded())
315 return m_imp
->GetPlaybackRate();
319 bool wxMediaCtrl::SetPlaybackRate(double dRate
)
321 if(m_imp
&& m_imp
->IsLoaded())
322 return m_imp
->SetPlaybackRate(dRate
);
326 bool wxMediaCtrl::SetPosition(long where
)
328 if(m_imp
&& m_imp
->IsLoaded())
329 return m_imp
->SetPosition(where
);
333 long wxMediaCtrl::GetPosition()
335 if(m_imp
&& m_imp
->IsLoaded())
336 return m_imp
->GetPosition();
340 long wxMediaCtrl::GetDuration()
342 if(m_imp
&& m_imp
->IsLoaded())
343 return m_imp
->GetDuration();
347 wxMediaState
wxMediaCtrl::GetState()
349 if(m_imp
&& m_imp
->IsLoaded())
350 return m_imp
->GetState();
351 return wxMEDIASTATE_STOPPED
;
354 WXLRESULT
wxMediaCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
356 if(m_imp
&& m_imp
->IsLoaded() && m_imp
->MSWWindowProc(nMsg
, wParam
, lParam
) )
357 return wxControl::MSWDefWindowProc(nMsg
, wParam
, lParam
);
358 //pass the event to our parent
359 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
362 wxSize
wxMediaCtrl::DoGetBestSize() const
364 if(m_imp
&& m_imp
->IsLoaded())
365 return m_imp
->DoGetBestSize();
369 void wxMediaCtrl::DoMoveWindow(int x
, int y
, int w
, int h
)
371 wxControl::DoMoveWindow(x
,y
,w
,h
);
373 if(m_imp
&& m_imp
->IsLoaded())
374 m_imp
->DoMoveWindow(x
, y
, w
, h
);
377 wxMediaCtrl::~wxMediaCtrl()
384 //---------------------------------------------------------------------------
388 //---------------------------------------------------------------------------
392 wxDXMediaCtrlImpl::wxDXMediaCtrlImpl() : m_pGB(NULL
)
396 bool wxDXMediaCtrlImpl::Create(wxMediaCtrl
* ctrl
)
398 //create our filter graph
399 HRESULT hr
= CoCreateInstance(CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
400 IID_IGraphBuilder
, (void**)&m_pGB
);
402 //directshow not installed?
411 #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
413 bool wxDXMediaCtrlImpl::Load(const wxString
& fileName
)
420 CoCreateInstance(CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
421 IID_IGraphBuilder
, (void**)&m_pGB
);
423 //load the graph & render
424 if( FAILED(m_pGB
->RenderFile(fileName
.wc_str(wxConvLocal
), NULL
)) )
427 //get the interfaces, all of them
428 wxDSVERIFY( m_pGB
->QueryInterface(IID_IMediaControl
, (void**)&m_pMC
) );
429 wxDSVERIFY( m_pGB
->QueryInterface(IID_IMediaEventEx
, (void**)&m_pME
) );
430 wxDSVERIFY( m_pGB
->QueryInterface(IID_IMediaSeeking
, (void**)&m_pMS
) );
431 wxDSVERIFY( m_pGB
->QueryInterface(IID_IVideoWindow
, (void**)&m_pVW
) );
432 wxDSVERIFY( m_pGB
->QueryInterface(IID_IBasicAudio
, (void**)&m_pBA
) );
433 wxDSVERIFY( m_pGB
->QueryInterface(IID_IBasicVideo
, (void**)&m_pBV
) );
436 //pBA->get_Volume(&lVolume);
439 //get the _actual_ size of the movie & remember it
440 long nX
, nY
, nSX
, nSY
;
441 if (FAILED(m_pVW
->GetWindowPosition(&nX
,&nY
,&nSX
,&nSY
)))
457 wxDSVERIFY( m_pVW
->put_Owner((OAHWND
)m_ctrl
->GetHandle()) );
458 wxDSVERIFY( m_pVW
->put_WindowStyle(WS_CHILD
| WS_CLIPSIBLINGS
) );
459 wxDSVERIFY( m_pVW
->put_Visible(OATRUE
) ); //OATRUE == -1
462 //make it so that wxEVT_MOVIE_FINISHED works
463 wxDSVERIFY( m_pME
->SetNotifyWindow((OAHWND
)m_ctrl
->GetHandle(), WM_GRAPHNOTIFY
, 0) );
465 //set the time format
466 wxDSVERIFY( m_pMS
->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME
) );
468 //so that DoGetBestSize will work :)
471 //work around refresh issues
472 m_ctrl
->InvalidateBestSize();
473 m_ctrl
->GetParent()->Layout();
474 m_ctrl
->GetParent()->Refresh();
475 m_ctrl
->GetParent()->Update();
480 bool wxDXMediaCtrlImpl::Load(const wxURI
& location
)
482 return Load(location
.BuildUnescapedURI());
485 bool wxDXMediaCtrlImpl::Play()
487 return SUCCEEDED( m_pMC
->Run() );
490 bool wxDXMediaCtrlImpl::Pause()
492 return SUCCEEDED( m_pMC
->Pause() );
495 bool wxDXMediaCtrlImpl::Stop()
497 bool bOK
= SUCCEEDED( m_pMC
->Stop() );
499 //We don't care if it can't get to the beginning in directshow -
500 //it could be a non-seeking filter (wince midi) in which case playing
501 //starts all over again
506 bool wxDXMediaCtrlImpl::SetPosition(long where
)
508 //DS uses 100 nanos - so we need a 10 mult
509 LONGLONG pos
= ((LONGLONG
)where
) * 10000;
511 return SUCCEEDED( m_pMS
->SetPositions(
513 AM_SEEKING_AbsolutePositioning
,
515 AM_SEEKING_NoPositioning
519 long wxDXMediaCtrlImpl::GetPosition()
521 LONGLONG outCur
, outStop
;
522 wxDSVERIFY( m_pMS
->GetPositions(&outCur
, &outStop
) );
524 //h,m,s,milli - outdur is in 100 nanos
528 long wxDXMediaCtrlImpl::GetDuration()
530 LONGLONG outDuration
;
531 wxDSVERIFY( m_pMS
->GetDuration(&outDuration
) );
533 //h,m,s,milli - outdur is in 100 nanos
534 return outDuration
/10000;
537 wxMediaState
wxDXMediaCtrlImpl::GetState()
539 //TODO: MS recommends against INFINITE here - do it in stages
541 OAFilterState theState
;
542 hr
= m_pMC
->GetState(INFINITE
, &theState
);
544 wxASSERT( SUCCEEDED(hr
) );
546 //MSW state is the same as ours
548 //State_Paused = State_Stopped + 1,
549 //State_Running = State_Paused + 1
551 return (wxMediaState
) theState
;
554 double wxDXMediaCtrlImpl::GetPlaybackRate()
557 wxDSVERIFY( m_pMS
->GetRate(&dRate
) );
561 bool wxDXMediaCtrlImpl::SetPlaybackRate(double dRate
)
563 return SUCCEEDED( m_pMS
->SetRate(dRate
) );
566 bool wxDXMediaCtrlImpl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
568 if (nMsg
== WM_GRAPHNOTIFY
)
570 LONG evCode
, evParam1
, evParam2
;
573 // Process all queued events
574 while(SUCCEEDED(m_pME
->GetEvent(&evCode
, (LONG_PTR
*) &evParam1
,
575 (LONG_PTR
*) &evParam2
, 0)
579 // Free memory associated with callback, since we're not using it
580 hr
= m_pME
->FreeEventParams(evCode
, evParam1
, evParam2
);
582 // If this is the end of the clip, notify handler
583 if(EC_COMPLETE
== evCode
)
585 //Interestingly enough, DirectShow does not actually stop
586 //the filters - even when it reaches the end!
593 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
, m_ctrl
->GetId());
594 m_ctrl
->GetParent()->ProcessEvent(theEvent
);
602 void wxDXMediaCtrlImpl::Cleanup()
604 // Hide then disown the window
607 m_pVW
->put_Visible(OAFALSE
); //OSFALSE == 0
608 m_pVW
->put_Owner(NULL
);
611 // Release and zero DirectShow interfaces
620 wxDXMediaCtrlImpl::~wxDXMediaCtrlImpl()
628 wxSize
wxDXMediaCtrlImpl::DoGetBestSize() const
633 void wxDXMediaCtrlImpl::DoMoveWindow(int x
, int y
, int w
, int h
)
635 if(m_bLoaded
&& m_bVideo
)
637 wxDSVERIFY( m_pVW
->SetWindowPosition(0, 0, w
, h
) );
641 #endif //wxUSE_DIRECTSHOW
643 //---------------------------------------------------------------------------
645 // wxWMMEMediaCtrlImpl
647 //---------------------------------------------------------------------------
649 wxWMMEMediaCtrlImpl::wxWMMEMediaCtrlImpl() : m_bVideo(false)
652 mciGetErrorString(nError, sz, 5000);
653 wxMessageBox(wxString::Format(_T("Error:%s"), sz));
657 wxWMMEMediaCtrlImpl::~wxWMMEMediaCtrlImpl()
659 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
662 bool wxWMMEMediaCtrlImpl::Create(wxMediaCtrl
* ctrl
)
668 bool wxWMMEMediaCtrlImpl::Load(const wxString
& fileName
)
671 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
673 MCI_OPEN_PARMS openParms
;
674 MCI_SET_PARMS setParms
;
676 openParms
.lpstrElementName
= (wxChar
*) fileName
.c_str();
678 //Here's where the trick lies - if you don't specify MCI_OPEN_TYPE,
679 //then it actually automagically finds the device for you!
680 if ( mciSendCommand(0, MCI_OPEN
,
682 (DWORD
)(LPVOID
)&openParms
) != 0)
685 m_hDev
= openParms
.wDeviceID
;
687 setParms
.dwCallback
= 0;
688 setParms
.dwTimeFormat
= MCI_FORMAT_MILLISECONDS
;
690 if (mciSendCommand(m_hDev
, MCI_SET
, MCI_SET_TIME_FORMAT
,
691 (DWORD
)(LPVOID
)&setParms
) != 0)
694 MCI_DGV_WINDOW_PARMS windowParms
;
696 windowParms
.hWnd
= (HWND
)m_ctrl
->GetHandle();
697 m_bVideo
= (mciSendCommand(m_hDev
, MCI_WINDOW
,
698 MCI_DGV_WINDOW_HWND
, (DWORD
)(LPVOID
)&windowParms
) == 0);
701 //work around refresh issues
702 m_ctrl
->InvalidateBestSize();
703 m_ctrl
->GetParent()->Layout();
704 m_ctrl
->GetParent()->Refresh();
705 m_ctrl
->GetParent()->Update();
710 bool wxWMMEMediaCtrlImpl::Load(const wxURI
& WXUNUSED(location
))
715 bool wxWMMEMediaCtrlImpl::Play()
717 //the directshow driver ("mpegvideo") will crash if we don't do a playParms here
718 MCI_PLAY_PARMS playParms
;
719 playParms
.dwCallback
= (WORD
)(HWND
)m_ctrl
->GetHWND();
720 bool bOK
= mciSendCommand(m_hDev
, MCI_PLAY
, MCI_NOTIFY
, (DWORD
)(LPVOID
)&playParms
) == 0;
722 (mciSendCommand(m_hDev, MCI_RESUME, 0, 0) == 0);*/
725 bool wxWMMEMediaCtrlImpl::Pause()
727 return (mciSendCommand(m_hDev
, MCI_PAUSE
, MCI_WAIT
, 0) == 0);
730 bool wxWMMEMediaCtrlImpl::Stop()
732 return (mciSendCommand(m_hDev
, MCI_STOP
, MCI_WAIT
, 0) == 0) &&
733 (mciSendCommand(m_hDev
, MCI_SEEK
, MCI_SEEK_TO_START
, 0) == 0);
737 wxMediaState
wxWMMEMediaCtrlImpl::GetState()
739 MCI_STATUS_PARMS statusParms
;
740 statusParms
.dwItem
= MCI_STATUS_MODE
;
741 mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
742 (DWORD
)(LPVOID
)&statusParms
);
744 if(statusParms
.dwReturn
== MCI_MODE_PAUSE
)
745 return wxMEDIASTATE_PAUSED
;
746 else if(statusParms
.dwReturn
== MCI_MODE_PLAY
)
747 return wxMEDIASTATE_PLAYING
;
749 return wxMEDIASTATE_STOPPED
;
752 bool wxWMMEMediaCtrlImpl::SetPosition(long where
)
754 MCI_SEEK_PARMS seekParms
;
755 seekParms
.dwCallback
= 0;
756 seekParms
.dwTo
= where
;
758 bool bReplay
= GetState() == wxMEDIASTATE_PLAYING
;
760 if( mciSendCommand(m_hDev
, MCI_SEEK
, MCI_TO
, (DWORD
)(LPVOID
)&seekParms
) != 0)
769 long wxWMMEMediaCtrlImpl::GetPosition()
771 MCI_STATUS_PARMS statusParms
;
773 statusParms
.dwItem
= MCI_STATUS_POSITION
;
774 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
775 (DWORD
)(LPSTR
)&statusParms
) != 0)
778 return statusParms
.dwReturn
;
781 long wxWMMEMediaCtrlImpl::GetDuration()
783 MCI_STATUS_PARMS statusParms
;
785 statusParms
.dwItem
= MCI_STATUS_LENGTH
;
786 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
787 (DWORD
)(LPSTR
)&statusParms
) != 0)
790 return statusParms
.dwReturn
;
793 void wxWMMEMediaCtrlImpl::DoMoveWindow(int, int, int, int)
797 wxSize
wxWMMEMediaCtrlImpl::DoGetBestSize() const
801 MCI_DGV_RECT_PARMS rect
;
803 mciSendCommand(m_hDev
, MCI_WHERE
, MCI_DGV_WHERE_SOURCE
, (DWORD
)(LPSTR
)&rect
);
804 return wxSize(rect
.rc
.right
, rect
.rc
.bottom
);
809 double wxWMMEMediaCtrlImpl::GetPlaybackRate()
814 bool wxWMMEMediaCtrlImpl::SetPlaybackRate(double)
819 bool wxWMMEMediaCtrlImpl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
821 if(nMsg
== MM_MCINOTIFY
)
823 wxASSERT(lParam
== (WXLPARAM
) m_hDev
);
824 if(wParam
== (WXWPARAM
) MCI_NOTIFY_SUCCESSFUL
&& lParam
== (WXLPARAM
) m_hDev
)
827 wxASSERT(mciSendCommand(m_hDev
, MCI_SEEK
, MCI_SEEK_TO_START
, 0) == 0);
829 mciSendCommand(m_hDev
, MCI_SEEK
, MCI_SEEK_TO_START
, 0);
832 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
, m_ctrl
->GetId());
833 m_ctrl
->GetParent()->ProcessEvent(theEvent
);
840 #endif //wxUSE_MEDIACTRL