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