1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/moviectrl.cpp
3 // Purpose: wxMovieCtrl MSW
4 // Author: Ryan Norton <wxprojects@comcast.net>
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 //#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 //#pragma implementation "moviectrl.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
25 #include "wx/moviectrl.h"
26 #include "wx/msw/ole/oleutils.h" //for wxBasicString
30 IMPLEMENT_CLASS(wxMovieCtrl
, wxControl
);
31 IMPLEMENT_DYNAMIC_CLASS(wxMovieEvent
, wxEvent
);
32 DEFINE_EVENT_TYPE(wxEVT_MOVIE_FINISHED
);
34 #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
36 #define WM_GRAPHNOTIFY WM_USER+13
39 #define wxDSVERIFY(x) wxASSERT( SUCCEEDED ((x)) )
41 #define wxDSVERIFY(x) (x)
44 //it's there someplace :)
45 extern "C" WXDLLIMPEXP_BASE HWND
46 wxCreateHiddenWindow(LPCTSTR
*pclassname
, LPCTSTR classname
, WNDPROC wndproc
);
48 bool wxMovieCtrl::Create(wxWindow
* parent
, wxWindowID id
, const wxString
& fileName
,
49 const wxString
& label
, const wxPoint
& pos
, const wxSize
& size
,
50 long style
, const wxString
& name
)
52 //do some window stuff - ORDER IS IMPORTANT
54 if ( !wxControl::Create(parent
, id
, pos
, size
, wxNO_BORDER
| wxCLIP_CHILDREN
, wxDefaultValidator
, name
) )
57 //Set our background color to black by default
58 SetBackgroundColour(*wxBLACK
);
60 wxControl::SetLabel(label
);
74 bool wxMovieCtrl::Load(const wxString
& fileName
)
80 IGraphBuilder
*& pGB
= (IGraphBuilder
*&) m_pGB
;
81 IMediaControl
*& pMC
= (IMediaControl
*&) m_pMC
;
82 IMediaEventEx
*& pME
= (IMediaEventEx
*&) m_pME
;
83 IVideoWindow
*& pVW
= (IVideoWindow
*&) m_pVW
;
84 IBasicAudio
*& pBA
= (IBasicAudio
*&) m_pBA
;
85 IBasicVideo
*& pBV
= (IBasicVideo
*&) m_pBV
;
86 IMediaSeeking
*& pMS
= (IMediaSeeking
*&) m_pMS
;
88 //create our filter graph
89 CoCreateInstance(CLSID_FilterGraph
, NULL
, CLSCTX_INPROC_SERVER
,
90 IID_IGraphBuilder
, (void**)&pGB
);
92 //load the graph & render
93 if (FAILED(pGB
->RenderFile(fileName
.wc_str(wxConvLocal
), NULL
)))
95 wxFAIL_MSG("Could not load movie!");
99 //get the interfaces, all of them
100 wxDSVERIFY( pGB
->QueryInterface(IID_IMediaControl
, (void**)&pMC
) );
101 wxDSVERIFY( pGB
->QueryInterface(IID_IMediaEventEx
, (void**)&pME
) );
102 wxDSVERIFY( pGB
->QueryInterface(IID_IMediaSeeking
, (void**)&pMS
) );
103 wxDSVERIFY( pGB
->QueryInterface(IID_IVideoWindow
, (void**)&pVW
) );
104 wxDSVERIFY( pGB
->QueryInterface(IID_IBasicAudio
, (void**)&pBA
) );
105 wxDSVERIFY( pGB
->QueryInterface(IID_IBasicVideo
, (void**)&pBV
) );
107 //get the _actual_ size of the movie & remember it
108 long nX
, nY
, nSX
, nSY
;
109 if (FAILED(pVW
->GetWindowPosition(&nX
,&nY
,&nSX
,&nSY
)))
119 this->Connect( wxID_ANY
,
121 (wxObjectEventFunction
) (wxEventFunction
) (wxSizeEventFunction
) &wxMovieCtrl::OnSize
);
129 wxDSVERIFY( pVW
->put_Owner((OAHWND
)this->GetHandle()) );
130 wxDSVERIFY( pVW
->put_WindowStyle(WS_CHILD
| WS_CLIPSIBLINGS
) );
131 wxDSVERIFY( pME
->SetNotifyWindow((OAHWND
)this->GetHandle(), WM_GRAPHNOTIFY
, 0) );
132 wxDSVERIFY( pVW
->put_Visible(OATRUE
) ); //OATRUE actually == -1 :)
135 //set the time format
136 wxDSVERIFY( pMS
->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME
) );
139 SetLabel(GetLabel());
145 void wxMovieCtrl::SetLabel(const wxString
& label
)
147 wxControl::SetLabel(label
);
149 IVideoWindow
*& pVW
= (IVideoWindow
*&) m_pVW
;
151 //wxBasicString will have a null string on an
152 //empty wxString - gotta love those workarounds!!
153 if(!label
.empty() && m_bVideo
)
155 wxBasicString
theBasicString(label
.mb_str());
156 wxDSVERIFY( pVW
->put_Caption(theBasicString
.Get()) );
160 bool wxMovieCtrl::Play()
162 return SUCCEEDED( ((IMediaControl
*&)m_pMC
)->Run() );
165 bool wxMovieCtrl::Pause()
167 return SUCCEEDED( ((IMediaControl
*&)m_pMC
)->Pause() );
170 bool wxMovieCtrl::Stop()
172 return SUCCEEDED( ((IMediaControl
*&)m_pMC
)->Stop() );
177 bool wxMovieCtrl::Seek(const wxTimeSpan
& where
)
179 //DS uses 100 nanos - so we need a 10 mult
180 LONGLONG pos
= (where
.GetMilliseconds() * ((wxLongLong
)10000)).GetValue();
182 return SUCCEEDED( ((IMediaSeeking
*&)m_pMS
)->SetPositions(
184 AM_SEEKING_AbsolutePositioning
,
186 AM_SEEKING_NoPositioning
190 wxTimeSpan
wxMovieCtrl::Tell()
192 LONGLONG outCur
, outStop
;
193 wxDSVERIFY( ((IMediaSeeking
*&)m_pMS
)->GetPositions(&outCur
, &outStop
) );
195 //h,m,s,milli - outdur is in 100 nanos
196 return wxTimeSpan(0,0,0,outCur
/10000);
199 wxTimeSpan
wxMovieCtrl::Length()
201 LONGLONG outDuration
;
202 wxDSVERIFY( ((IMediaSeeking
*&)m_pMS
)->GetDuration(&outDuration
) );
204 //h,m,s,milli - outdur is in 100 nanos
205 return wxTimeSpan(0,0, 0,outDuration
/10000);
208 #endif // wxUSE_DATETIME
210 wxMovieCtrlState
wxMovieCtrl::GetState()
213 OAFilterState theState
;
214 hr
= ((IMediaControl
*&)m_pMC
)->GetState(INFINITE
, &theState
);
216 wxASSERT( SUCCEEDED(hr
) );
218 //MSW state is the same as ours
220 //State_Paused = State_Stopped + 1,
221 //State_Running = State_Paused + 1
223 return (wxMovieCtrlState
) theState
;
226 double wxMovieCtrl::GetPlaybackRate()
229 wxDSVERIFY( ((IMediaSeeking
*&)m_pMS
)->GetRate(&dRate
) );
233 bool wxMovieCtrl::SetPlaybackRate(double dRate
)
235 return SUCCEEDED( ((IMediaSeeking
*&)m_pMS
)->SetRate(dRate
) );
238 WXLRESULT
wxMovieCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
241 // IMediaControl*& pMC = (IMediaControl*&) m_pMC;
242 IMediaEventEx
*& pME
= (IMediaEventEx
*&) m_pME
;
243 // IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
245 if (nMsg
== WM_GRAPHNOTIFY
)
247 LONG evCode
, evParam1
, evParam2
;
250 // Process all queued events
251 while(SUCCEEDED(pME
->GetEvent(&evCode
, (LONG_PTR
*) &evParam1
,
252 (LONG_PTR
*) &evParam2
, 0)
256 // Free memory associated with callback, since we're not using it
257 hr
= pME
->FreeEventParams(evCode
, evParam1
, evParam2
);
259 // If this is the end of the clip, notify handler
260 if(EC_COMPLETE
== evCode
)
262 wxMovieEvent
theEvent(wxEVT_MOVIE_FINISHED
, this->GetId());
263 GetParent()->ProcessEvent(theEvent
);
267 // Reset to first frame of movie
268 hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
269 NULL, AM_SEEKING_NoPositioning);
273 // for filters that don't support seeking do a rewind
277 wxString::Format(TEXT("Failed(0x%08lx) to stop media clip!\r\n"), hr)
282 hr = hr = pMC->Run();
287 wxString::Format(TEXT("Failed(0x%08lx) to reset media clip!\r\n"), hr)
295 return wxControl::MSWDefWindowProc(nMsg
, wParam
, lParam
);
297 //pass the event to our parent
298 return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
);
301 void wxMovieCtrl::Cleanup()
304 this->Disconnect( wxID_ANY
,
306 (wxObjectEventFunction
) (wxEventFunction
) (wxSizeEventFunction
) &wxMovieCtrl::OnSize
);
309 IGraphBuilder
*& pGB
= (IGraphBuilder
*&) m_pGB
;
310 IMediaControl
*& pMC
= (IMediaControl
*&) m_pMC
;
311 IMediaEventEx
*& pME
= (IMediaEventEx
*&) m_pME
;
312 IVideoWindow
*& pVW
= (IVideoWindow
*&) m_pVW
;
313 IBasicAudio
*& pBA
= (IBasicAudio
*&) m_pBA
;
314 IBasicVideo
*& pBV
= (IBasicVideo
*&) m_pBV
;
315 IMediaSeeking
*& pMS
= (IMediaSeeking
*&) m_pMS
;
317 // Hide then disown the window
320 pVW
->put_Visible(OAFALSE
); //OSFALSE == 0
321 pVW
->put_Owner(NULL
);
324 // Release and zero DirectShow interfaces
334 wxMovieCtrl::~wxMovieCtrl()
340 wxSize
wxMovieCtrl::DoGetBestSize() const
345 void wxMovieCtrl::OnSize(wxSizeEvent
& evt
)
347 IVideoWindow
*& pVW
= (IVideoWindow
*&) m_pVW
;
348 wxDSVERIFY( pVW
->SetWindowPosition(0, 0, evt
.GetSize().GetWidth(), evt
.GetSize().GetHeight()) );
353 #endif //wxUSE_MOVIECTRL