]> git.saurik.com Git - wxWidgets.git/blob - src/msw/moviectrl.cpp
3b9c85c663f0b4d95c2bcc031e8c16c983f9ece4
[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 m_bVideo = false;
111 else
112 {
113 m_bVideo = true;
114
115 this->Connect( wxID_ANY,
116 wxEVT_SIZE,
117 (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) &wxMovieCtrl::OnSize );
118 }
119
120 m_bestSize.x = nSX;
121 m_bestSize.y = nSY;
122
123 if (m_bVideo)
124 {
125 wxDSVERIFY( pVW->put_Owner((OAHWND)this->GetHandle()) );
126 wxDSVERIFY( pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS) );
127 // wxDSVERIFY( pME->SetNotifyWindow((OAHWND)this->GetHandle(), WM_GRAPHNOTIFY, 0) );
128 wxDSVERIFY( pVW->put_Visible(OATRUE) ); //OATRUE actually == -1 :)
129 }
130
131 //set the time format
132 wxDSVERIFY( pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME) );
133
134
135 SetLabel(GetLabel());
136
137 m_bLoaded = true;
138 return true;
139 }
140
141 void wxMovieCtrl::SetLabel(const wxString& label)
142 {
143 wxControl::SetLabel(label);
144
145 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
146
147 //wxBasicString will have a null string on an
148 //empty wxString - gotta love those workarounds!!
149 if(!label.empty() && m_bVideo)
150 {
151 wxBasicString theBasicString(label.mb_str());
152 wxDSVERIFY( pVW->put_Caption(theBasicString.Get()) );
153 }
154 }
155
156 bool wxMovieCtrl::Play()
157 {
158 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Run() );
159 }
160
161 bool wxMovieCtrl::Pause()
162 {
163 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Pause() );
164 }
165
166 bool wxMovieCtrl::Stop()
167 {
168 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Stop() );
169 }
170
171 #if wxUSE_DATETIME
172
173 bool wxMovieCtrl::Seek(const wxTimeSpan& where)
174 {
175 //DS uses 100 nanos - so we need a 10 mult
176 LONGLONG pos = ((size_t)where.GetMilliseconds().ToLong()) * 10;
177
178 return SUCCEEDED( ((IMediaSeeking*&)m_pMS)->SetPositions(
179 &pos,
180 AM_SEEKING_AbsolutePositioning,
181 NULL,
182 AM_SEEKING_NoPositioning
183 ) );
184 }
185
186 wxTimeSpan wxMovieCtrl::Tell()
187 {
188 LONGLONG outCur, outStop;
189 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetPositions(&outCur, &outStop) );
190
191 return outCur;
192 }
193
194 wxTimeSpan wxMovieCtrl::Length()
195 {
196 LONGLONG outDuration;
197 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetDuration(&outDuration) );
198
199 return outDuration;
200 }
201
202 #endif // wxUSE_DATETIME
203
204 wxMovieCtrlState wxMovieCtrl::GetState()
205 {
206 HRESULT hr;
207 OAFilterState theState;
208 hr = ((IMediaControl*&)m_pMC)->GetState(INFINITE, &theState);
209
210 wxASSERT( SUCCEEDED(hr) );
211
212 //MSW state is the same as ours
213 //State_Stopped = 0,
214 //State_Paused = State_Stopped + 1,
215 //State_Running = State_Paused + 1
216
217 return (wxMovieCtrlState) theState;
218 }
219
220 double wxMovieCtrl::GetPlaybackRate()
221 {
222 double dRate;
223 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetRate(&dRate) );
224 return dRate;
225 }
226
227 bool wxMovieCtrl::SetPlaybackRate(double dRate)
228 {
229 return SUCCEEDED( ((IMediaSeeking*&)m_pMS)->SetRate(dRate) );
230 }
231
232 WXLRESULT wxMovieCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
233 {
234 //cast helpers
235 // IMediaControl*& pMC = (IMediaControl*&) m_pMC;
236 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
237 // IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
238
239 if (nMsg == WM_GRAPHNOTIFY)
240 {
241 LONG evCode, evParam1, evParam2;
242 HRESULT hr=S_OK;
243
244 // Process all queued events
245 while(SUCCEEDED(pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
246 (LONG_PTR *) &evParam2, 0)
247 )
248 )
249 {
250 // Free memory associated with callback, since we're not using it
251 hr = pME->FreeEventParams(evCode, evParam1, evParam2);
252
253 // If this is the end of the clip, notify handler
254 if(EC_COMPLETE == evCode)
255 {
256 wxMovieEvent theEvent(wxEVT_MOVIE_FINISHED, this->GetId());
257 GetParent()->ProcessEvent(theEvent);
258 /*
259 LONGLONG pos=0;
260
261 // Reset to first frame of movie
262 hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
263 NULL, AM_SEEKING_NoPositioning);
264 if (FAILED(hr))
265 {
266 hr = pMC->Stop();
267 // for filters that don't support seeking do a rewind
268 if (FAILED(hr))
269 {
270 wxFAIL_MSG(
271 wxString::Format(TEXT("Failed(0x%08lx) to stop media clip!\r\n"), hr)
272 );
273 break;
274 }
275
276 hr = hr = pMC->Run();
277
278 if (FAILED(hr))
279 {
280 wxFAIL_MSG(
281 wxString::Format(TEXT("Failed(0x%08lx) to reset media clip!\r\n"), hr)
282 );
283 break;
284 }
285 }
286 */
287 }
288 }
289 return wxControl::MSWDefWindowProc(nMsg, wParam, lParam);
290 }
291 //pass the event to our parent
292 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
293 }
294
295 void wxMovieCtrl::Cleanup()
296 {
297 if(m_bVideo)
298 this->Disconnect( wxID_ANY,
299 wxEVT_SIZE,
300 (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) &wxMovieCtrl::OnSize );
301
302 //cast helpers
303 IGraphBuilder*& pGB = (IGraphBuilder*&) m_pGB;
304 IMediaControl*& pMC = (IMediaControl*&) m_pMC;
305 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
306 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
307 IBasicAudio*& pBA = (IBasicAudio*&) m_pBA;
308 IBasicVideo*& pBV = (IBasicVideo*&) m_pBV;
309 IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
310
311 // Hide then disown the window
312 if(pVW)
313 {
314 pVW->put_Visible(OAFALSE); //OSFALSE == 0
315 pVW->put_Owner(NULL);
316 }
317
318 // Release and zero DirectShow interfaces
319 SAFE_RELEASE(pME);
320 SAFE_RELEASE(pMS);
321 SAFE_RELEASE(pMC);
322 SAFE_RELEASE(pBA);
323 SAFE_RELEASE(pBV);
324 SAFE_RELEASE(pVW);
325 SAFE_RELEASE(pGB);
326 }
327
328 wxMovieCtrl::~wxMovieCtrl()
329 {
330 if (m_bLoaded)
331 Cleanup();
332 }
333
334 wxSize wxMovieCtrl::DoGetBestSize() const
335 {
336 return m_bestSize;
337 }
338
339 void wxMovieCtrl::OnSize(wxSizeEvent& evt)
340 {
341 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
342 wxDSVERIFY( pVW->SetWindowPosition(0, 0, evt.GetSize().GetWidth(), evt.GetSize().GetHeight()) );
343
344 evt.Skip();
345 }
346
347 #endif //wxUSE_MOVIECTRL