]> git.saurik.com Git - wxWidgets.git/blob - src/msw/moviectrl.cpp
6b2de258f2f6725ce65d70caad9fa9fe5469a78e
[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 //cast helpers
55 IGraphBuilder*& pGB = (IGraphBuilder*&) m_pGB;
56 IMediaControl*& pMC = (IMediaControl*&) m_pMC;
57 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
58 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
59 IBasicAudio*& pBA = (IBasicAudio*&) m_pBA;
60 IBasicVideo*& pBV = (IBasicVideo*&) m_pBV;
61 IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
62
63 //create our filter graph
64 CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
65 IID_IGraphBuilder, (void**)&pGB);
66
67 //load the graph & render
68 if (FAILED(pGB->RenderFile(fileName.wc_str(wxConvLocal), NULL)))
69 {
70 wxFAIL_MSG("Could not load movie!");
71 return false;
72 }
73
74 //get the interfaces, all of them
75 wxDSVERIFY( pGB->QueryInterface(IID_IMediaControl, (void**)&pMC) );
76 wxDSVERIFY( pGB->QueryInterface(IID_IMediaEventEx, (void**)&pME) );
77 wxDSVERIFY( pGB->QueryInterface(IID_IMediaSeeking, (void**)&pMS) );
78 wxDSVERIFY( pGB->QueryInterface(IID_IVideoWindow, (void**)&pVW) );
79 wxDSVERIFY( pGB->QueryInterface(IID_IBasicAudio, (void**)&pBA) );
80 wxDSVERIFY( pGB->QueryInterface(IID_IBasicVideo, (void**)&pBV) );
81
82 //get the _actual_ size of the movie & remember it
83 long nX, nY, nSX, nSY;
84 if (FAILED(pVW->GetWindowPosition(&nX,&nY,&nSX,&nSY)))
85 m_bVideo = false;
86 else
87 {
88 m_bVideo = true;
89
90 this->Connect( wxID_ANY,
91 wxEVT_SIZE,
92 (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) &wxMovieCtrl::OnSize );
93 }
94
95 m_bestSize.x = nSX;
96 m_bestSize.y = nSY;
97
98
99 //do some window stuff - ORDER IS IMPORTANT
100 //base create
101 if ( !wxControl::Create(parent, id, pos, size, wxNO_BORDER | wxCLIP_CHILDREN, wxDefaultValidator, name) )
102 return false;
103
104 //TODO: Connect() here instead of message maps
105
106 //Set our background color to black by default
107 SetBackgroundColour(*wxBLACK);
108
109 if (m_bVideo)
110 {
111 wxDSVERIFY( pVW->put_Owner((OAHWND)this->GetHandle()) );
112 wxDSVERIFY( pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS) );
113 // wxDSVERIFY( pME->SetNotifyWindow((OAHWND)this->GetHandle(), WM_GRAPHNOTIFY, 0) );
114 wxDSVERIFY( pVW->put_Visible(OATRUE) ); //OATRUE actually == -1 :)
115 }
116
117 //set the time format
118 wxDSVERIFY( pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME) );
119
120 SetLabel(label);
121 Play();
122
123 return true;
124 }
125
126 void wxMovieCtrl::SetLabel(const wxString& label)
127 {
128 wxControl::SetLabel(label);
129
130 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
131
132 //wxBasicString will have a null string on an
133 //empty wxString - gotta love those workarounds!!
134 if(!label.empty() && m_bVideo)
135 {
136 wxBasicString theBasicString(label.mb_str());
137 wxDSVERIFY( pVW->put_Caption(theBasicString.Get()) );
138 }
139 }
140
141 bool wxMovieCtrl::Play()
142 {
143 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Run() );
144 }
145
146 bool wxMovieCtrl::Pause()
147 {
148 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Pause() );
149 }
150
151 bool wxMovieCtrl::Stop()
152 {
153 return SUCCEEDED( ((IMediaControl*&)m_pMC)->Stop() );
154 }
155
156 #if wxUSE_DATETIME
157
158 bool wxMovieCtrl::Seek(const wxTimeSpan& where)
159 {
160 //DS uses 100 nanos - so we need a 10 mult
161 LONGLONG pos = ((size_t)where.GetMilliseconds().ToLong()) * 10;
162
163 return SUCCEEDED( ((IMediaSeeking*&)m_pMS)->SetPositions(
164 &pos,
165 AM_SEEKING_AbsolutePositioning,
166 NULL,
167 AM_SEEKING_NoPositioning
168 ) );
169 }
170
171 wxTimeSpan wxMovieCtrl::Tell()
172 {
173 LONGLONG outCur, outStop;
174 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetPositions(&outCur, &outStop) );
175
176 return outCur;
177 }
178
179 wxTimeSpan wxMovieCtrl::Length()
180 {
181 LONGLONG outDuration;
182 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetDuration(&outDuration) );
183
184 return outDuration;
185 }
186
187 #endif // wxUSE_DATETIME
188
189 wxMovieCtrlState wxMovieCtrl::GetState()
190 {
191 HRESULT hr;
192 OAFilterState theState;
193 hr = ((IMediaControl*&)m_pMC)->GetState(INFINITE, &theState);
194
195 wxASSERT( SUCCEEDED(hr) );
196
197 //MSW state is the same as ours
198 //State_Stopped = 0,
199 //State_Paused = State_Stopped + 1,
200 //State_Running = State_Paused + 1
201
202 return (wxMovieCtrlState) theState;
203 }
204
205 double wxMovieCtrl::GetPlaybackRate()
206 {
207 double dRate;
208 wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetRate(&dRate) );
209 return dRate;
210 }
211
212 bool wxMovieCtrl::SetPlaybackRate(double dRate)
213 {
214 return SUCCEEDED( ((IMediaSeeking*&)m_pMS)->SetRate(dRate) );
215 }
216
217 WXLRESULT wxMovieCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
218 {
219 //cast helpers
220 // IMediaControl*& pMC = (IMediaControl*&) m_pMC;
221 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
222 // IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
223
224 if (nMsg == WM_GRAPHNOTIFY)
225 {
226 LONG evCode, evParam1, evParam2;
227 HRESULT hr=S_OK;
228
229 // Process all queued events
230 while(SUCCEEDED(pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
231 (LONG_PTR *) &evParam2, 0)
232 )
233 )
234 {
235 // Free memory associated with callback, since we're not using it
236 hr = pME->FreeEventParams(evCode, evParam1, evParam2);
237
238 // If this is the end of the clip, notify handler
239 if(EC_COMPLETE == evCode)
240 {
241 wxMovieEvent theEvent(wxEVT_MOVIE_FINISHED, this->GetId());
242 GetParent()->ProcessEvent(theEvent);
243 /*
244 LONGLONG pos=0;
245
246 // Reset to first frame of movie
247 hr = pMS->SetPositions(&pos, AM_SEEKING_AbsolutePositioning ,
248 NULL, AM_SEEKING_NoPositioning);
249 if (FAILED(hr))
250 {
251 hr = pMC->Stop();
252 // for filters that don't support seeking do a rewind
253 if (FAILED(hr))
254 {
255 wxFAIL_MSG(
256 wxString::Format(TEXT("Failed(0x%08lx) to stop media clip!\r\n"), hr)
257 );
258 break;
259 }
260
261 hr = hr = pMC->Run();
262
263 if (FAILED(hr))
264 {
265 wxFAIL_MSG(
266 wxString::Format(TEXT("Failed(0x%08lx) to reset media clip!\r\n"), hr)
267 );
268 break;
269 }
270 }
271 */
272 }
273 }
274 return wxControl::MSWDefWindowProc(nMsg, wParam, lParam);
275 }
276 //pass the event to our parent
277 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
278 }
279
280 wxMovieCtrl::~wxMovieCtrl()
281 {
282 //cast helpers
283 IGraphBuilder*& pGB = (IGraphBuilder*&) m_pGB;
284 IMediaControl*& pMC = (IMediaControl*&) m_pMC;
285 IMediaEventEx*& pME = (IMediaEventEx*&) m_pME;
286 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
287 IBasicAudio*& pBA = (IBasicAudio*&) m_pBA;
288 IBasicVideo*& pBV = (IBasicVideo*&) m_pBV;
289 IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS;
290
291 // Hide then disown the window
292 if(pVW)
293 {
294 pVW->put_Visible(OAFALSE); //OSFALSE == 0
295 pVW->put_Owner(NULL);
296 }
297
298 // Release and zero DirectShow interfaces
299 SAFE_RELEASE(pME);
300 SAFE_RELEASE(pMS);
301 SAFE_RELEASE(pMC);
302 SAFE_RELEASE(pBA);
303 SAFE_RELEASE(pBV);
304 SAFE_RELEASE(pVW);
305 SAFE_RELEASE(pGB);
306 }
307
308 wxSize wxMovieCtrl::DoGetBestSize() const
309 {
310 return m_bestSize;
311 }
312
313 void wxMovieCtrl::OnSize(wxSizeEvent& evt)
314 {
315 IVideoWindow*& pVW = (IVideoWindow*&) m_pVW;
316 wxDSVERIFY( pVW->SetWindowPosition(0, 0, evt.GetSize().GetWidth(), evt.GetSize().GetHeight()) );
317
318 evt.Skip();
319 }
320
321 #endif //wxUSE_MOVIECTRL