]>
Commit | Line | Data |
---|---|---|
4ad7af2b RN |
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); | |
0568fd59 RN |
31 | IMPLEMENT_DYNAMIC_CLASS(wxMovieEvent, wxEvent); |
32 | DEFINE_EVENT_TYPE(wxEVT_MOVIE_FINISHED); | |
4ad7af2b RN |
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 | ||
4ad7af2b RN |
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 | { | |
3a774635 RN |
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 | ||
16cfbafc RN |
60 | wxControl::SetLabel(label); |
61 | ||
3a774635 RN |
62 | if(!fileName.empty()) |
63 | { | |
64 | if (!Load(fileName)) | |
65 | return false; | |
66 | ||
3a774635 RN |
67 | if(!Play()) |
68 | return false; | |
69 | } | |
3a774635 RN |
70 | |
71 | return true; | |
72 | } | |
73 | ||
74 | bool wxMovieCtrl::Load(const wxString& fileName) | |
75 | { | |
76 | if(m_bLoaded) | |
77 | Cleanup(); | |
78 | ||
4ad7af2b RN |
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; | |
0568fd59 | 109 | if (FAILED(pVW->GetWindowPosition(&nX,&nY,&nSX,&nSY))) |
2bff0db1 | 110 | { |
0568fd59 | 111 | m_bVideo = false; |
2bff0db1 RN |
112 | |
113 | nSX = nSY = 0; | |
114 | } | |
0568fd59 RN |
115 | else |
116 | { | |
117 | m_bVideo = true; | |
118 | ||
119 | this->Connect( wxID_ANY, | |
120 | wxEVT_SIZE, | |
121 | (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) &wxMovieCtrl::OnSize ); | |
122 | } | |
4ad7af2b RN |
123 | |
124 | m_bestSize.x = nSX; | |
125 | m_bestSize.y = nSY; | |
126 | ||
0568fd59 RN |
127 | if (m_bVideo) |
128 | { | |
129 | wxDSVERIFY( pVW->put_Owner((OAHWND)this->GetHandle()) ); | |
130 | wxDSVERIFY( pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS) ); | |
2bff0db1 | 131 | wxDSVERIFY( pME->SetNotifyWindow((OAHWND)this->GetHandle(), WM_GRAPHNOTIFY, 0) ); |
0568fd59 RN |
132 | wxDSVERIFY( pVW->put_Visible(OATRUE) ); //OATRUE actually == -1 :) |
133 | } | |
4ad7af2b RN |
134 | |
135 | //set the time format | |
136 | wxDSVERIFY( pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME) ); | |
137 | ||
16cfbafc RN |
138 | |
139 | SetLabel(GetLabel()); | |
140 | ||
3a774635 | 141 | m_bLoaded = true; |
4ad7af2b RN |
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!! | |
0568fd59 | 153 | if(!label.empty() && m_bVideo) |
4ad7af2b RN |
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 | |
2bff0db1 | 180 | LONGLONG pos = (where.GetMilliseconds() * ((wxLongLong)10000)).GetValue(); |
4ad7af2b RN |
181 | |
182 | return SUCCEEDED( ((IMediaSeeking*&)m_pMS)->SetPositions( | |
183 | &pos, | |
184 | AM_SEEKING_AbsolutePositioning, | |
185 | NULL, | |
186 | AM_SEEKING_NoPositioning | |
187 | ) ); | |
188 | } | |
189 | ||
0568fd59 RN |
190 | wxTimeSpan wxMovieCtrl::Tell() |
191 | { | |
192 | LONGLONG outCur, outStop; | |
193 | wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetPositions(&outCur, &outStop) ); | |
194 | ||
2bff0db1 RN |
195 | //h,m,s,milli - outdur is in 100 nanos |
196 | return wxTimeSpan(0,0,0,outCur/10000); | |
0568fd59 RN |
197 | } |
198 | ||
199 | wxTimeSpan wxMovieCtrl::Length() | |
200 | { | |
201 | LONGLONG outDuration; | |
202 | wxDSVERIFY( ((IMediaSeeking*&)m_pMS)->GetDuration(&outDuration) ); | |
203 | ||
2bff0db1 RN |
204 | //h,m,s,milli - outdur is in 100 nanos |
205 | return wxTimeSpan(0,0, 0,outDuration/10000); | |
0568fd59 RN |
206 | } |
207 | ||
4ad7af2b RN |
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 | ||
0568fd59 RN |
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 | { | |
4ad7af2b | 240 | //cast helpers |
0568fd59 | 241 | // IMediaControl*& pMC = (IMediaControl*&) m_pMC; |
4ad7af2b | 242 | IMediaEventEx*& pME = (IMediaEventEx*&) m_pME; |
0568fd59 | 243 | // IMediaSeeking*& pMS = (IMediaSeeking*&) m_pMS; |
4ad7af2b RN |
244 | |
245 | if (nMsg == WM_GRAPHNOTIFY) | |
246 | { | |
247 | LONG evCode, evParam1, evParam2; | |
248 | HRESULT hr=S_OK; | |
249 | ||
4ad7af2b RN |
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 | ||
0568fd59 | 259 | // If this is the end of the clip, notify handler |
4ad7af2b RN |
260 | if(EC_COMPLETE == evCode) |
261 | { | |
0568fd59 RN |
262 | wxMovieEvent theEvent(wxEVT_MOVIE_FINISHED, this->GetId()); |
263 | GetParent()->ProcessEvent(theEvent); | |
264 | /* | |
4ad7af2b RN |
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 | } | |
0568fd59 | 292 | */ |
4ad7af2b RN |
293 | } |
294 | } | |
295 | return wxControl::MSWDefWindowProc(nMsg, wParam, lParam); | |
296 | } | |
4ad7af2b | 297 | //pass the event to our parent |
0568fd59 RN |
298 | return wxControl::MSWWindowProc(nMsg, wParam, lParam); |
299 | } | |
4ad7af2b | 300 | |
3a774635 | 301 | void wxMovieCtrl::Cleanup() |
4ad7af2b | 302 | { |
3a774635 RN |
303 | if(m_bVideo) |
304 | this->Disconnect( wxID_ANY, | |
305 | wxEVT_SIZE, | |
306 | (wxObjectEventFunction) (wxEventFunction) (wxSizeEventFunction) &wxMovieCtrl::OnSize ); | |
307 | ||
4ad7af2b RN |
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 | ||
3a774635 RN |
334 | wxMovieCtrl::~wxMovieCtrl() |
335 | { | |
336 | if (m_bLoaded) | |
337 | Cleanup(); | |
338 | } | |
339 | ||
4ad7af2b RN |
340 | wxSize wxMovieCtrl::DoGetBestSize() const |
341 | { | |
342 | return m_bestSize; | |
343 | } | |
344 | ||
4ad7af2b RN |
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 | } | |
4ad7af2b RN |
352 | |
353 | #endif //wxUSE_MOVIECTRL |