]> git.saurik.com Git - wxWidgets.git/blob - src/msw/moviectrl.cpp
7917b6382bbc9de0ee5db290f52482e6d957363f
[wxWidgets.git] / src / msw / moviectrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/moviectrl.cpp
3 // Purpose: wxMovieCtrl MSW
4 // Author: Ryan Norton <wxprojects@comcast.net>
5 // Modified by:
6 // Created: 11/07/04
7 // RCS-ID: $Id$
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 //#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 //#pragma implementation "moviectrl.h"
14 //#endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #define wxUSE_MOVIECTRL 1
24
25 #if wxUSE_MOVIECTRL
26
27 #include "wx/moviectrl.h"
28 #include "wx/msw/ole/oleutils.h" //for wxBasicString
29
30 #include <dshow.h>
31
32 IMPLEMENT_CLASS(wxMovieCtrl, wxControl);
33 IMPLEMENT_DYNAMIC_CLASS(wxMovieEvent, wxEvent);
34 DEFINE_EVENT_TYPE(wxEVT_MOVIE_FINISHED);
35
36 #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
37
38 #define WM_GRAPHNOTIFY WM_USER+13
39
40 #ifdef __WXDEBUG__
41 #define wxDSVERIFY(x) wxASSERT( SUCCEEDED ((x)) )
42 #else
43 #define wxDSVERIFY(x) (x)
44 #endif
45
46 //it's there someplace :)
47 extern "C" WXDLLIMPEXP_BASE HWND
48 wxCreateHiddenWindow(LPCTSTR *pclassname, LPCTSTR classname, WNDPROC wndproc);
49
50 bool wxMovieCtrl::Create(wxWindow* parent, wxWindowID id, const wxString& fileName,
51 const wxString& label, const wxPoint& pos, const wxSize& size,
52 long style, const wxString& name)
53 {
54 //do some window stuff - ORDER IS IMPORTANT
55 //base create
56 if ( !wxControl::Create(parent, id, pos, size, wxNO_BORDER | wxCLIP_CHILDREN, wxDefaultValidator, name) )
57 return false;
58
59 //Set our background color to black by default
60 SetBackgroundColour(*wxBLACK);
61
62 if(!fileName.empty())
63 {
64 if (!Load(fileName))
65 return false;
66
67 SetLabel(label);
68
69 if(!Play())
70 return false;
71 }
72 else
73 wxControl::SetLabel(label);
74
75 return true;
76 }
77
78 bool wxMovieCtrl::Load(const wxString& fileName)
79 {
80 if(m_bLoaded)
81 Cleanup();
82
83 //cast helpers
84 IGraphBuilder*& pGB = (IGraphBuilder*&) m_pGB;
85 IMediaControl*& pMC = (IMediaControl*&) m_pMC;
86 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
87 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
88 IBasicAudio*& pBA = (IBasicAudio*&) m_pBA;
89 IBasicVideo*& pBV = (IBasicVideo*&) m_pBV;
90 IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
91
92 //create our filter graph
93 CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
94 IID_IGraphBuilder, (void**)&pGB);
95
96 //load the graph & render
97 if (FAILED(pGB->RenderFile(fileName.wc_str(wxConvLocal), NULL)))
98 {
99 wxFAIL_MSG("Could not load movie!");
100 return false;
101 }
102
103 //get the interfaces, all of them
104 wxDSVERIFY( pGB->QueryInterface(IID_IMediaControl, (void**)&pMC) );
105 wxDSVERIFY( pGB->QueryInterface(IID_IMediaEventEx, (void**)&pME) );
106 wxDSVERIFY( pGB->QueryInterface(IID_IMediaSeeking, (void**)&pMS) );
107 wxDSVERIFY( pGB->QueryInterface(IID_IVideoWindow, (void**)&pVW) );
108 wxDSVERIFY( pGB->QueryInterface(IID_IBasicAudio, (void**)&pBA) );
109 wxDSVERIFY( pGB->QueryInterface(IID_IBasicVideo, (void**)&pBV) );
110
111 //get the _actual_ size of the movie & remember it
112 long nX, nY, nSX, nSY;
113 if (FAILED(pVW->GetWindowPosition(&nX,&nY,&nSX,&nSY)))
114 m_bVideo = false;
115 else
116 {
117 m_bVideo = true;
118
119 this->Connect( wxID_ANY,
120 wxEVT_SIZE,
121 (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) &wxMovieCtrl::OnSize );
122 }
123
124 m_bestSize.x = nSX;
125 m_bestSize.y = nSY;
126
127 if (m_bVideo)
128 {
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 :)
133 }
134
135 //set the time format
136 wxDSVERIFY( pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME) );
137
138 m_bLoaded = true;
139 return true;
140 }
141
142 void wxMovieCtrl::SetLabel(const wxString& label)
143 {
144 wxControl::SetLabel(label);
145
146 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
147
148 //wxBasicString will have a null string on an
149 //empty wxString - gotta love those workarounds!!
150 if(!label.empty() && m_bVideo)
151 {
152 wxBasicString theBasicString(label.mb_str());
153 wxDSVERIFY( pVW->put_Caption(theBasicString.Get()) );
154 }
155 }
156
157 bool wxMovieCtrl::Play()
158 {
159 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Run() );
160 }
161
162 bool wxMovieCtrl::Pause()
163 {
164 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Pause() );
165 }
166
167 bool wxMovieCtrl::Stop()
168 {
169 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Stop() );
170 }
171
172 #if wxUSE_DATETIME
173
174 bool wxMovieCtrl::Seek(const wxTimeSpan& where)
175 {
176 //DS uses 100 nanos - so we need a 10 mult
177 LONGLONG pos = ((size_t)where.GetMilliseconds().ToLong()) * 10;
178
179 return SUCCEEDED( ((IMediaSeeking*&)m_pMS)->SetPositions(
180 &pos,
181 AM_SEEKING_AbsolutePositioning,
182 NULL,
183 AM_SEEKING_NoPositioning
184 ) );
185 }
186
187 wxTimeSpan wxMovieCtrl::Tell()
188 {
189 LONGLONG outCur, outStop;
190 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetPositions(&outCur, &outStop) );
191
192 return outCur;
193 }
194
195 wxTimeSpan wxMovieCtrl::Length()
196 {
197 LONGLONG outDuration;
198 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetDuration(&outDuration) );
199
200 return outDuration;
201 }
202
203 #endif // wxUSE_DATETIME
204
205 wxMovieCtrlState wxMovieCtrl::GetState()
206 {
207 HRESULT hr;
208 OAFilterState theState;
209 hr = ((IMediaControl*&)m_pMC)->GetState(INFINITE, &theState);
210
211 wxASSERT( SUCCEEDED(hr) );
212
213 //MSW state is the same as ours
214 //State_Stopped = 0,
215 //State_Paused = State_Stopped + 1,
216 //State_Running = State_Paused + 1
217
218 return (wxMovieCtrlState) theState;
219 }
220
221 double wxMovieCtrl::GetPlaybackRate()
222 {
223 double dRate;
224 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetRate(&dRate) );
225 return dRate;
226 }
227
228 bool wxMovieCtrl::SetPlaybackRate(double dRate)
229 {
230 return SUCCEEDED( ((IMediaSeeking*&)m_pMS)->SetRate(dRate) );
231 }
232
233 WXLRESULT wxMovieCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
234 {
235 //cast helpers
236 // IMediaControl*& pMC = (IMediaControl*&) m_pMC;
237 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
238 // IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
239
240 if (nMsg == WM_GRAPHNOTIFY)
241 {
242 LONG evCode, evParam1, evParam2;
243 HRESULT hr=S_OK;
244
245 // Process all queued events
246 while(SUCCEEDED(pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
247 (LONG_PTR *) &evParam2, 0)
248 )
249 )
250 {
251 // Free memory associated with callback, since we're not using it
252 hr = pME->FreeEventParams(evCode, evParam1, evParam2);
253
254 // If this is the end of the clip, notify handler
255 if(EC_COMPLETE == evCode)
256 {
257 wxMovieEvent theEvent(wxEVT_MOVIE_FINISHED, this->GetId());
258 GetParent()->ProcessEvent(theEvent);
259 /*
260 LONGLONG pos=0;
261
262 // Reset to first frame of movie
263 hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
264 NULL, AM_SEEKING_NoPositioning);
265 if (FAILED(hr))
266 {
267 hr = pMC->Stop();
268 // for filters that don't support seeking do a rewind
269 if (FAILED(hr))
270 {
271 wxFAIL_MSG(
272 wxString::Format(TEXT("Failed(0x%08lx) to stop media clip!\r\n"), hr)
273 );
274 break;
275 }
276
277 hr = hr = pMC->Run();
278
279 if (FAILED(hr))
280 {
281 wxFAIL_MSG(
282 wxString::Format(TEXT("Failed(0x%08lx) to reset media clip!\r\n"), hr)
283 );
284 break;
285 }
286 }
287 */
288 }
289 }
290 return wxControl::MSWDefWindowProc(nMsg, wParam, lParam);
291 }
292 //pass the event to our parent
293 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
294 }
295
296 void wxMovieCtrl::Cleanup()
297 {
298 if(m_bVideo)
299 this->Disconnect( wxID_ANY,
300 wxEVT_SIZE,
301 (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) &wxMovieCtrl::OnSize );
302
303 //cast helpers
304 IGraphBuilder*& pGB = (IGraphBuilder*&) m_pGB;
305 IMediaControl*& pMC = (IMediaControl*&) m_pMC;
306 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
307 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
308 IBasicAudio*& pBA = (IBasicAudio*&) m_pBA;
309 IBasicVideo*& pBV = (IBasicVideo*&) m_pBV;
310 IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
311
312 // Hide then disown the window
313 if(pVW)
314 {
315 pVW->put_Visible(OAFALSE); //OSFALSE == 0
316 pVW->put_Owner(NULL);
317 }
318
319 // Release and zero DirectShow interfaces
320 SAFE_RELEASE(pME);
321 SAFE_RELEASE(pMS);
322 SAFE_RELEASE(pMC);
323 SAFE_RELEASE(pBA);
324 SAFE_RELEASE(pBV);
325 SAFE_RELEASE(pVW);
326 SAFE_RELEASE(pGB);
327 }
328
329 wxMovieCtrl::~wxMovieCtrl()
330 {
331 if (m_bLoaded)
332 Cleanup();
333 }
334
335 wxSize wxMovieCtrl::DoGetBestSize() const
336 {
337 return m_bestSize;
338 }
339
340 void wxMovieCtrl::OnSize(wxSizeEvent& evt)
341 {
342 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
343 wxDSVERIFY( pVW->SetWindowPosition(0, 0, evt.GetSize().GetWidth(), evt.GetSize().GetHeight()) );
344
345 evt.Skip();
346 }
347
348 #endif //wxUSE_MOVIECTRL