]>
Commit | Line | Data |
---|---|---|
1a680109 RN |
1 | ///////////////////////////////////////////////////////////////////////////// |
2 | // Name: msw/mediactrl.cpp | |
3 | // Purpose: wxMediaCtrl MSW | |
4 | // Author: Ryan Norton <wxprojects@comcast.net> | |
72259e00 | 5 | // Modified by: |
1a680109 RN |
6 | // Created: 11/07/04 |
7 | // RCS-ID: $Id$ | |
8 | // Copyright: (c) Ryan Norton | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | //--------------------------------------------------------------------------- | |
13 | // Pre-wx includes | |
14 | //--------------------------------------------------------------------------- | |
15 | ||
16 | //#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) | |
17 | //#pragma implementation "moviectrl.h" | |
18 | //#endif | |
19 | ||
20 | // For compilers that support precompilation, includes "wx.h". | |
21 | #include "wx/wxprec.h" | |
22 | ||
23 | #ifdef __BORLANDC__ | |
24 | #pragma hdrstop | |
25 | #endif | |
26 | ||
27 | #include "wx/mediactrl.h" | |
28 | ||
29 | #if wxUSE_MEDIACTRL | |
30 | ||
31 | //########################################################################### | |
32 | // DECLARATIONS | |
33 | //########################################################################### | |
34 | ||
35 | IMPLEMENT_CLASS(wxMediaCtrl, wxControl); | |
72259e00 RL |
36 | IMPLEMENT_DYNAMIC_CLASS(wxMediaEvent, wxEvent); |
37 | DEFINE_EVENT_TYPE(wxEVT_MEDIA_FINISHED); | |
1a680109 RN |
38 | |
39 | //--------------------------------------------------------------------------- | |
40 | // wxMediaCtrlImpl | |
41 | //--------------------------------------------------------------------------- | |
42 | ||
43 | class wxMediaCtrlImpl | |
44 | { | |
45 | public: | |
46 | wxMediaCtrlImpl() : m_bLoaded(false) | |
47 | { } | |
48 | ||
72259e00 | 49 | virtual ~wxMediaCtrlImpl() |
1a680109 RN |
50 | { } |
51 | ||
72259e00 | 52 | virtual bool Create(wxMediaCtrl* WXUNUSED(ctrl)) |
1a680109 RN |
53 | { return false; } |
54 | ||
55 | virtual bool Play() { return false; } | |
56 | virtual bool Pause() { return false; } | |
57 | virtual bool Stop() { return false; } | |
58 | ||
59 | virtual bool Load(const wxString&) { return false; } | |
60 | virtual bool Load(const wxURI&) { return false; } | |
61 | ||
62 | virtual wxMediaState GetState() { return wxMEDIASTATE_STOPPED; } | |
63 | ||
64 | virtual bool SetPosition(long) { return 0; } | |
65 | virtual long GetPosition() { return 0; } | |
66 | virtual long GetDuration() { return 0; } | |
67 | ||
68 | virtual void DoMoveWindow(int, int, int, int) { } | |
69 | virtual wxSize DoGetBestSize() const { return wxSize(0,0); } | |
70 | ||
71 | virtual double GetPlaybackRate() { return 0; } | |
72 | virtual bool SetPlaybackRate(double) { return false; } | |
72259e00 | 73 | |
1a680109 RN |
74 | virtual bool MSWWindowProc(WXUINT, WXWPARAM, WXLPARAM) { return false; } |
75 | ||
76 | bool IsLoaded() | |
77 | { return m_bLoaded; } | |
78 | ||
79 | bool m_bLoaded; | |
80 | }; | |
81 | ||
82 | //--------------------------------------------------------------------------- | |
83 | // wxDXMediaCtrlImpl | |
84 | //--------------------------------------------------------------------------- | |
85 | ||
86 | #if wxUSE_DIRECTSHOW | |
87 | ||
88 | #include <dshow.h> | |
89 | ||
90 | #define WM_GRAPHNOTIFY WM_USER+13 | |
91 | ||
92 | #ifdef __WXDEBUG__ | |
93 | #define wxDSVERIFY(x) wxASSERT( SUCCEEDED ((x)) ) | |
94 | #else | |
95 | #define wxDSVERIFY(x) (x) | |
96 | #endif | |
97 | ||
98 | class wxDXMediaCtrlImpl : public wxMediaCtrlImpl | |
99 | { | |
100 | public: | |
101 | wxDXMediaCtrlImpl(); | |
102 | ||
103 | virtual ~wxDXMediaCtrlImpl(); | |
104 | ||
105 | virtual bool Create(wxMediaCtrl* ctrl); | |
106 | ||
107 | virtual bool Play(); | |
108 | virtual bool Pause(); | |
109 | virtual bool Stop(); | |
110 | ||
111 | virtual bool Load(const wxString& fileName); | |
112 | virtual bool Load(const wxURI& location); | |
113 | ||
114 | virtual wxMediaState GetState(); | |
115 | ||
116 | virtual bool SetPosition(long where); | |
117 | virtual long GetPosition(); | |
118 | virtual long GetDuration(); | |
119 | ||
120 | virtual void DoMoveWindow(int x, int y, int w, int h); | |
121 | wxSize DoGetBestSize() const; | |
122 | ||
123 | virtual double GetPlaybackRate(); | |
124 | virtual bool SetPlaybackRate(double); | |
125 | ||
126 | void Cleanup(); | |
127 | ||
128 | bool m_bVideo; | |
129 | ||
130 | bool MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); | |
131 | ||
132 | wxMediaCtrl* m_ctrl; | |
133 | ||
134 | IGraphBuilder* m_pGB; | |
135 | IMediaControl* m_pMC; | |
136 | IMediaEventEx* m_pME; | |
137 | IVideoWindow* m_pVW; | |
138 | IBasicAudio* m_pBA; | |
139 | IBasicVideo* m_pBV; | |
140 | IMediaSeeking* m_pMS; | |
141 | ||
142 | wxSize m_bestSize; | |
143 | }; | |
144 | ||
145 | #endif //wxUSE_DIRECTSHOW | |
146 | ||
147 | //--------------------------------------------------------------------------- | |
148 | // wxWMMEMediaCtrlImpl | |
149 | //--------------------------------------------------------------------------- | |
150 | ||
151 | #include <mmsystem.h> | |
1a680109 RN |
152 | |
153 | class wxWMMEMediaCtrlImpl : public wxMediaCtrlImpl | |
154 | { | |
155 | public: | |
3f9a3bf9 | 156 | |
1a680109 RN |
157 | wxWMMEMediaCtrlImpl(); |
158 | ~wxWMMEMediaCtrlImpl(); | |
159 | ||
1a680109 RN |
160 | virtual bool Create(wxMediaCtrl* ctrl); |
161 | ||
162 | virtual bool Play(); | |
163 | virtual bool Pause(); | |
164 | virtual bool Stop(); | |
165 | ||
166 | virtual bool Load(const wxString& fileName); | |
167 | virtual bool Load(const wxURI& location); | |
168 | ||
169 | virtual wxMediaState GetState(); | |
170 | ||
171 | virtual bool SetPosition(long where); | |
172 | virtual long GetPosition(); | |
173 | virtual long GetDuration(); | |
174 | ||
175 | virtual void DoMoveWindow(int x, int y, int w, int h); | |
176 | wxSize DoGetBestSize() const; | |
177 | ||
178 | virtual double GetPlaybackRate(); | |
179 | virtual bool SetPlaybackRate(double); | |
3f9a3bf9 | 180 | |
5987f174 RN |
181 | bool MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam); |
182 | ||
1a680109 | 183 | MCIDEVICEID m_hDev; |
3f9a3bf9 RN |
184 | wxMediaCtrl* m_ctrl; |
185 | bool m_bVideo; | |
1a680109 RN |
186 | }; |
187 | ||
1a680109 RN |
188 | //########################################################################### |
189 | // | |
190 | // IMPLEMENTATION | |
191 | // | |
192 | //########################################################################### | |
193 | ||
194 | //--------------------------------------------------------------------------- | |
195 | // | |
196 | // wxMediaCtrl | |
197 | // | |
198 | //--------------------------------------------------------------------------- | |
199 | ||
72259e00 RL |
200 | bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id, const wxString& fileName, |
201 | const wxPoint& pos, const wxSize& size, | |
1a680109 RN |
202 | long style, long WXUNUSED(driver), const wxString& name) |
203 | { | |
204 | //base create | |
72259e00 | 205 | if ( !wxControl::Create(parent, id, pos, size, (style | wxNO_BORDER) | wxCLIP_CHILDREN, |
1a680109 RN |
206 | wxDefaultValidator, name) ) |
207 | return false; | |
208 | ||
209 | //Set our background color to black by default | |
210 | SetBackgroundColour(*wxBLACK); | |
211 | ||
212 | #if wxUSE_DIRECTSHOW | |
213 | m_imp = new wxDXMediaCtrlImpl; | |
214 | if(!m_imp->Create(this)) | |
215 | { | |
216 | delete m_imp; | |
217 | #endif | |
5987f174 RN |
218 | m_imp = new wxWMMEMediaCtrlImpl; |
219 | if(!m_imp->Create(this)) | |
1a680109 | 220 | { |
5987f174 | 221 | delete m_imp; |
1a680109 RN |
222 | m_imp = NULL; |
223 | return false; | |
224 | } | |
225 | #if wxUSE_DIRECTSHOW | |
226 | } | |
227 | #endif | |
228 | ||
229 | if(!fileName.empty()) | |
230 | { | |
231 | if (!Load(fileName)) | |
232 | return false; | |
233 | } | |
234 | ||
235 | return true; | |
236 | } | |
237 | ||
72259e00 RL |
238 | bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id, const wxURI& location, |
239 | const wxPoint& pos, const wxSize& size, | |
1a680109 RN |
240 | long style, long WXUNUSED(driver), const wxString& name) |
241 | { | |
242 | //base create | |
72259e00 | 243 | if ( !wxControl::Create(parent, id, pos, size, (style | wxNO_BORDER) | wxCLIP_CHILDREN, |
1a680109 RN |
244 | wxDefaultValidator, name) ) |
245 | return false; | |
246 | ||
247 | //Set our background color to black by default | |
248 | SetBackgroundColour(*wxBLACK); | |
249 | ||
250 | #if wxUSE_DIRECTSHOW | |
251 | m_imp = new wxDXMediaCtrlImpl; | |
252 | if(!m_imp->Create(this)) | |
253 | { | |
254 | delete m_imp; | |
255 | #endif | |
5987f174 RN |
256 | m_imp = new wxWMMEMediaCtrlImpl; |
257 | if(!m_imp->Create(this)) | |
1a680109 | 258 | { |
5987f174 | 259 | delete m_imp; |
1a680109 RN |
260 | m_imp = NULL; |
261 | return false; | |
262 | } | |
263 | #if wxUSE_DIRECTSHOW | |
264 | } | |
265 | #endif | |
266 | ||
267 | if (!Load(location)) | |
268 | return false; | |
269 | ||
270 | return true; | |
271 | } | |
272 | ||
273 | bool wxMediaCtrl::Load(const wxString& fileName) | |
274 | { | |
275 | if(m_imp) | |
276 | return m_imp->Load(fileName); | |
277 | return false; | |
278 | } | |
279 | ||
280 | bool wxMediaCtrl::Load(const wxURI& location) | |
281 | { | |
282 | if(m_imp) | |
283 | return m_imp->Load(location); | |
284 | return false; | |
285 | } | |
286 | ||
287 | bool wxMediaCtrl::Play() | |
288 | { | |
289 | if(m_imp && m_imp->IsLoaded()) | |
290 | return m_imp->Play(); | |
291 | return false; | |
292 | } | |
293 | ||
294 | bool wxMediaCtrl::Pause() | |
295 | { | |
296 | if(m_imp && m_imp->IsLoaded()) | |
297 | return m_imp->Pause(); | |
298 | return false; | |
299 | } | |
300 | ||
301 | bool wxMediaCtrl::Stop() | |
302 | { | |
303 | if(m_imp && m_imp->IsLoaded()) | |
304 | return m_imp->Stop(); | |
305 | return false; | |
306 | } | |
307 | ||
308 | double wxMediaCtrl::GetPlaybackRate() | |
309 | { | |
310 | if(m_imp && m_imp->IsLoaded()) | |
311 | return m_imp->GetPlaybackRate(); | |
312 | return 0; | |
313 | } | |
314 | ||
315 | bool wxMediaCtrl::SetPlaybackRate(double dRate) | |
316 | { | |
317 | if(m_imp && m_imp->IsLoaded()) | |
318 | return m_imp->SetPlaybackRate(dRate); | |
319 | return false; | |
320 | } | |
321 | ||
322 | bool wxMediaCtrl::SetPosition(long where) | |
323 | { | |
324 | if(m_imp && m_imp->IsLoaded()) | |
325 | return m_imp->SetPosition(where); | |
326 | return false; | |
327 | } | |
328 | ||
329 | long wxMediaCtrl::GetPosition() | |
330 | { | |
331 | if(m_imp && m_imp->IsLoaded()) | |
332 | return m_imp->GetPosition(); | |
333 | return 0; | |
334 | } | |
335 | ||
336 | long wxMediaCtrl::GetDuration() | |
337 | { | |
338 | if(m_imp && m_imp->IsLoaded()) | |
339 | return m_imp->GetDuration(); | |
340 | return 0; | |
341 | } | |
342 | ||
343 | wxMediaState wxMediaCtrl::GetState() | |
344 | { | |
345 | if(m_imp && m_imp->IsLoaded()) | |
346 | return m_imp->GetState(); | |
347 | return wxMEDIASTATE_STOPPED; | |
348 | } | |
349 | ||
350 | WXLRESULT wxMediaCtrl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) | |
351 | { | |
352 | if(m_imp && m_imp->IsLoaded() && m_imp->MSWWindowProc(nMsg, wParam, lParam) ) | |
353 | return wxControl::MSWDefWindowProc(nMsg, wParam, lParam); | |
354 | //pass the event to our parent | |
355 | return wxControl::MSWWindowProc(nMsg, wParam, lParam); | |
356 | } | |
357 | ||
358 | wxSize wxMediaCtrl::DoGetBestSize() const | |
359 | { | |
360 | if(m_imp && m_imp->IsLoaded()) | |
361 | return m_imp->DoGetBestSize(); | |
362 | return wxSize(0,0); | |
363 | } | |
364 | ||
365 | void wxMediaCtrl::DoMoveWindow(int x, int y, int w, int h) | |
366 | { | |
367 | wxControl::DoMoveWindow(x,y,w,h); | |
368 | ||
369 | if(m_imp && m_imp->IsLoaded()) | |
370 | m_imp->DoMoveWindow(x, y, w, h); | |
371 | } | |
372 | ||
373 | wxMediaCtrl::~wxMediaCtrl() | |
374 | { | |
375 | if (m_imp) | |
376 | delete m_imp; | |
377 | } | |
378 | ||
379 | ||
380 | //--------------------------------------------------------------------------- | |
381 | // | |
382 | // wxDXMediaCtrlImpl | |
383 | // | |
384 | //--------------------------------------------------------------------------- | |
385 | ||
72259e00 | 386 | #if wxUSE_DIRECTSHOW |
1a680109 RN |
387 | |
388 | wxDXMediaCtrlImpl::wxDXMediaCtrlImpl() : m_pGB(NULL) | |
389 | { | |
390 | } | |
391 | ||
392 | bool wxDXMediaCtrlImpl::Create(wxMediaCtrl* ctrl) | |
393 | { | |
394 | //create our filter graph | |
395 | HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, | |
396 | IID_IGraphBuilder, (void**)&m_pGB); | |
397 | ||
398 | //directshow not installed? | |
399 | if ( FAILED(hr) ) | |
400 | return false; | |
401 | ||
402 | m_ctrl = ctrl; | |
403 | ||
404 | return true; | |
405 | } | |
406 | ||
407 | #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; } | |
408 | ||
409 | bool wxDXMediaCtrlImpl::Load(const wxString& fileName) | |
410 | { | |
411 | if(m_bLoaded) | |
72259e00 RL |
412 | Cleanup(); |
413 | ||
1a680109 RN |
414 | SAFE_RELEASE(m_pGB); |
415 | ||
416 | CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, | |
417 | IID_IGraphBuilder, (void**)&m_pGB); | |
418 | ||
72259e00 | 419 | //load the graph & render |
1a680109 RN |
420 | if( FAILED(m_pGB->RenderFile(fileName.wc_str(wxConvLocal), NULL)) ) |
421 | return false; | |
422 | ||
423 | //get the interfaces, all of them | |
424 | wxDSVERIFY( m_pGB->QueryInterface(IID_IMediaControl, (void**)&m_pMC) ); | |
425 | wxDSVERIFY( m_pGB->QueryInterface(IID_IMediaEventEx, (void**)&m_pME) ); | |
426 | wxDSVERIFY( m_pGB->QueryInterface(IID_IMediaSeeking, (void**)&m_pMS) ); | |
427 | wxDSVERIFY( m_pGB->QueryInterface(IID_IVideoWindow, (void**)&m_pVW) ); | |
428 | wxDSVERIFY( m_pGB->QueryInterface(IID_IBasicAudio, (void**)&m_pBA) ); | |
429 | wxDSVERIFY( m_pGB->QueryInterface(IID_IBasicVideo, (void**)&m_pBV) ); | |
430 | ||
431 | //long lVolume; | |
432 | //pBA->get_Volume(&lVolume); | |
433 | //E_NOTIMPL | |
434 | ||
435 | //get the _actual_ size of the movie & remember it | |
436 | long nX, nY, nSX, nSY; | |
437 | if (FAILED(m_pVW->GetWindowPosition(&nX,&nY,&nSX,&nSY))) | |
438 | { | |
439 | m_bVideo = false; | |
440 | ||
441 | nSX = nSY = 0; | |
442 | } | |
72259e00 | 443 | else |
1a680109 RN |
444 | { |
445 | m_bVideo = true; | |
446 | } | |
447 | ||
448 | m_bestSize.x = nSX; | |
449 | m_bestSize.y = nSY; | |
450 | ||
451 | if (m_bVideo) | |
452 | { | |
453 | wxDSVERIFY( m_pVW->put_Owner((OAHWND)m_ctrl->GetHandle()) ); | |
454 | wxDSVERIFY( m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS) ); | |
455 | wxDSVERIFY( m_pVW->put_Visible(OATRUE) ); //OATRUE == -1 | |
456 | } | |
457 | ||
458 | //make it so that wxEVT_MOVIE_FINISHED works | |
459 | wxDSVERIFY( m_pME->SetNotifyWindow((OAHWND)m_ctrl->GetHandle(), WM_GRAPHNOTIFY, 0) ); | |
460 | ||
461 | //set the time format | |
462 | wxDSVERIFY( m_pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME) ); | |
463 | ||
3f9a3bf9 RN |
464 | //so that DoGetBestSize will work :) |
465 | m_bLoaded = true; | |
466 | ||
1a680109 | 467 | //work around refresh issues |
3f9a3bf9 RN |
468 | m_ctrl->InvalidateBestSize(); |
469 | m_ctrl->GetParent()->Layout(); | |
1a680109 RN |
470 | m_ctrl->GetParent()->Refresh(); |
471 | m_ctrl->GetParent()->Update(); | |
472 | ||
1a680109 RN |
473 | return true; |
474 | } | |
475 | ||
476 | bool wxDXMediaCtrlImpl::Load(const wxURI& location) | |
477 | { | |
478 | return Load(location.BuildUnescapedURI()); | |
479 | } | |
480 | ||
481 | bool wxDXMediaCtrlImpl::Play() | |
482 | { | |
483 | return SUCCEEDED( m_pMC->Run() ); | |
484 | } | |
485 | ||
486 | bool wxDXMediaCtrlImpl::Pause() | |
487 | { | |
488 | return SUCCEEDED( m_pMC->Pause() ); | |
489 | } | |
490 | ||
491 | bool wxDXMediaCtrlImpl::Stop() | |
492 | { | |
e4b12a53 RN |
493 | bool bOK = SUCCEEDED( m_pMC->Stop() ); |
494 | ||
495 | //We don't care if it can't get to the beginning in directshow - | |
496 | //it could be a non-seeking filter (wince midi) in which case playing | |
497 | //starts all over again | |
498 | SetPosition(0); | |
499 | return bOK; | |
1a680109 RN |
500 | } |
501 | ||
502 | bool wxDXMediaCtrlImpl::SetPosition(long where) | |
503 | { | |
504 | //DS uses 100 nanos - so we need a 10 mult | |
505 | LONGLONG pos = ((LONGLONG)where) * 10000; | |
506 | ||
507 | return SUCCEEDED( m_pMS->SetPositions( | |
72259e00 | 508 | &pos, |
1a680109 | 509 | AM_SEEKING_AbsolutePositioning, |
72259e00 | 510 | NULL, |
1a680109 RN |
511 | AM_SEEKING_NoPositioning |
512 | ) ); | |
513 | } | |
514 | ||
515 | long wxDXMediaCtrlImpl::GetPosition() | |
516 | { | |
517 | LONGLONG outCur, outStop; | |
518 | wxDSVERIFY( m_pMS->GetPositions(&outCur, &outStop) ); | |
519 | ||
520 | //h,m,s,milli - outdur is in 100 nanos | |
521 | return outCur/10000; | |
522 | } | |
523 | ||
524 | long wxDXMediaCtrlImpl::GetDuration() | |
525 | { | |
526 | LONGLONG outDuration; | |
527 | wxDSVERIFY( m_pMS->GetDuration(&outDuration) ); | |
528 | ||
529 | //h,m,s,milli - outdur is in 100 nanos | |
530 | return outDuration/10000; | |
531 | } | |
532 | ||
533 | wxMediaState wxDXMediaCtrlImpl::GetState() | |
534 | { | |
535 | //TODO: MS recommends against INFINITE here - do it in stages | |
536 | HRESULT hr; | |
537 | OAFilterState theState; | |
538 | hr = m_pMC->GetState(INFINITE, &theState); | |
72259e00 | 539 | |
1a680109 RN |
540 | wxASSERT( SUCCEEDED(hr) ); |
541 | ||
542 | //MSW state is the same as ours | |
543 | //State_Stopped = 0, | |
544 | //State_Paused = State_Stopped + 1, | |
545 | //State_Running = State_Paused + 1 | |
546 | ||
547 | return (wxMediaState) theState; | |
548 | } | |
549 | ||
550 | double wxDXMediaCtrlImpl::GetPlaybackRate() | |
551 | { | |
552 | double dRate; | |
553 | wxDSVERIFY( m_pMS->GetRate(&dRate) ); | |
554 | return dRate; | |
555 | } | |
556 | ||
557 | bool wxDXMediaCtrlImpl::SetPlaybackRate(double dRate) | |
558 | { | |
559 | return SUCCEEDED( m_pMS->SetRate(dRate) ); | |
560 | } | |
561 | ||
562 | bool wxDXMediaCtrlImpl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) | |
563 | { | |
564 | if (nMsg == WM_GRAPHNOTIFY) | |
565 | { | |
566 | LONG evCode, evParam1, evParam2; | |
567 | HRESULT hr=S_OK; | |
568 | ||
569 | // Process all queued events | |
570 | while(SUCCEEDED(m_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1, | |
72259e00 RL |
571 | (LONG_PTR *) &evParam2, 0) |
572 | ) | |
1a680109 RN |
573 | ) |
574 | { | |
575 | // Free memory associated with callback, since we're not using it | |
576 | hr = m_pME->FreeEventParams(evCode, evParam1, evParam2); | |
577 | ||
578 | // If this is the end of the clip, notify handler | |
579 | if(EC_COMPLETE == evCode) | |
580 | { | |
e4b12a53 RN |
581 | //Interestingly enough, DirectShow does not actually stop |
582 | //the filters - even when it reaches the end! | |
1a680109 RN |
583 | #ifdef __WXDEBUG__ |
584 | wxASSERT( Stop() ); | |
585 | #else | |
586 | Stop(); | |
587 | #endif | |
e4b12a53 | 588 | |
1a680109 RN |
589 | wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED, m_ctrl->GetId()); |
590 | m_ctrl->GetParent()->ProcessEvent(theEvent); | |
591 | } | |
72259e00 | 592 | } |
1a680109 RN |
593 | return true; |
594 | } | |
595 | return false; | |
596 | } | |
597 | ||
598 | void wxDXMediaCtrlImpl::Cleanup() | |
599 | { | |
600 | // Hide then disown the window | |
601 | if(m_pVW) | |
602 | { | |
603 | m_pVW->put_Visible(OAFALSE); //OSFALSE == 0 | |
604 | m_pVW->put_Owner(NULL); | |
605 | } | |
606 | ||
607 | // Release and zero DirectShow interfaces | |
608 | SAFE_RELEASE(m_pME); | |
609 | SAFE_RELEASE(m_pMS); | |
610 | SAFE_RELEASE(m_pMC); | |
611 | SAFE_RELEASE(m_pBA); | |
612 | SAFE_RELEASE(m_pBV); | |
613 | SAFE_RELEASE(m_pVW); | |
614 | } | |
615 | ||
616 | wxDXMediaCtrlImpl::~wxDXMediaCtrlImpl() | |
617 | { | |
618 | if (m_bLoaded) | |
619 | Cleanup(); | |
620 | ||
621 | SAFE_RELEASE(m_pGB); | |
622 | } | |
623 | ||
624 | wxSize wxDXMediaCtrlImpl::DoGetBestSize() const | |
625 | { | |
626 | return m_bestSize; | |
627 | } | |
628 | ||
629 | void wxDXMediaCtrlImpl::DoMoveWindow(int x, int y, int w, int h) | |
630 | { | |
631 | if(m_bLoaded && m_bVideo) | |
632 | { | |
633 | wxDSVERIFY( m_pVW->SetWindowPosition(0, 0, w, h) ); | |
634 | } | |
635 | } | |
636 | ||
637 | #endif //wxUSE_DIRECTSHOW | |
638 | ||
639 | //--------------------------------------------------------------------------- | |
640 | // | |
641 | // wxWMMEMediaCtrlImpl | |
642 | // | |
643 | //--------------------------------------------------------------------------- | |
644 | ||
33d8e2fc RN |
645 | // |
646 | // Cruft to simulate digitalv.h | |
647 | // | |
648 | ||
649 | typedef struct { | |
650 | DWORD_PTR dwCallback; | |
651 | #ifdef MCI_USE_OFFEXT | |
652 | POINT ptOffset; | |
653 | POINT ptExtent; | |
654 | #else | |
655 | RECT rc; | |
656 | #endif | |
657 | } MCI_DGV_RECT_PARMS; | |
658 | ||
659 | typedef struct { | |
660 | DWORD_PTR dwCallback; | |
661 | HWND hWnd; | |
662 | #ifndef _WIN32 | |
663 | WORD wReserved1; | |
664 | #endif | |
665 | UINT nCmdShow; | |
666 | #ifndef _WIN32 | |
667 | WORD wReserved2; | |
668 | #endif | |
669 | LPSTR lpstrText; | |
670 | } MCI_DGV_WINDOW_PARMSA; | |
671 | ||
672 | typedef struct { | |
673 | DWORD_PTR dwCallback; | |
674 | HWND hWnd; | |
675 | #ifndef _WIN32 | |
676 | WORD wReserved1; | |
677 | #endif | |
678 | UINT nCmdShow; | |
679 | #ifndef _WIN32 | |
680 | WORD wReserved2; | |
681 | #endif | |
682 | LPWSTR lpstrText; | |
683 | } MCI_DGV_WINDOW_PARMSW; | |
684 | #ifdef UNICODE | |
685 | typedef MCI_DGV_WINDOW_PARMSW MCI_DGV_WINDOW_PARMS; | |
686 | #else | |
687 | typedef MCI_DGV_WINDOW_PARMSA MCI_DGV_WINDOW_PARMS; | |
688 | #endif // UNICODE | |
689 | ||
3f9a3bf9 RN |
690 | wxWMMEMediaCtrlImpl::wxWMMEMediaCtrlImpl() : m_bVideo(false) |
691 | { | |
5987f174 RN |
692 | /* TCHAR sz[5000]; |
693 | mciGetErrorString(nError, sz, 5000); | |
694 | wxMessageBox(wxString::Format(_T("Error:%s"), sz)); | |
72259e00 | 695 | */ |
3f9a3bf9 RN |
696 | } |
697 | ||
698 | wxWMMEMediaCtrlImpl::~wxWMMEMediaCtrlImpl() | |
699 | { | |
700 | mciSendCommand(m_hDev, MCI_CLOSE, 0, 0); | |
701 | } | |
702 | ||
703 | bool wxWMMEMediaCtrlImpl::Create(wxMediaCtrl* ctrl) | |
72259e00 | 704 | { |
3f9a3bf9 RN |
705 | m_ctrl = ctrl; |
706 | return true; | |
707 | } | |
708 | ||
3f9a3bf9 RN |
709 | bool wxWMMEMediaCtrlImpl::Load(const wxString& fileName) |
710 | { | |
711 | if(m_bLoaded) | |
712 | mciSendCommand(m_hDev, MCI_CLOSE, 0, 0); | |
713 | ||
714 | MCI_OPEN_PARMS openParms; | |
715 | MCI_SET_PARMS setParms; | |
716 | ||
3f9a3bf9 RN |
717 | openParms.lpstrElementName = (wxChar*) fileName.c_str(); |
718 | ||
5987f174 RN |
719 | //Here's where the trick lies - if you don't specify MCI_OPEN_TYPE, |
720 | //then it actually automagically finds the device for you! | |
721 | if ( mciSendCommand(0, MCI_OPEN, | |
722 | MCI_OPEN_ELEMENT, | |
72259e00 | 723 | (DWORD)(LPVOID)&openParms) != 0) |
5987f174 | 724 | return false; |
3f9a3bf9 RN |
725 | |
726 | m_hDev = openParms.wDeviceID; | |
727 | ||
3f9a3bf9 RN |
728 | setParms.dwCallback = 0; |
729 | setParms.dwTimeFormat = MCI_FORMAT_MILLISECONDS; | |
730 | ||
731 | if (mciSendCommand(m_hDev, MCI_SET, MCI_SET_TIME_FORMAT, | |
732 | (DWORD)(LPVOID)&setParms) != 0) | |
733 | return false; | |
734 | ||
3f9a3bf9 RN |
735 | MCI_DGV_WINDOW_PARMS windowParms; |
736 | ||
5987f174 | 737 | windowParms.hWnd = (HWND)m_ctrl->GetHandle(); |
3f9a3bf9 | 738 | m_bVideo = (mciSendCommand(m_hDev, MCI_WINDOW, |
33d8e2fc | 739 | 0x00010000L //MCI_DGV_WINDOW_HWND |
72259e00 | 740 | , |
33d8e2fc | 741 | (DWORD)(LPVOID)&windowParms) == 0); |
3f9a3bf9 RN |
742 | m_bLoaded = true; |
743 | ||
5987f174 RN |
744 | //work around refresh issues |
745 | m_ctrl->InvalidateBestSize(); | |
746 | m_ctrl->GetParent()->Layout(); | |
747 | m_ctrl->GetParent()->Refresh(); | |
748 | m_ctrl->GetParent()->Update(); | |
72259e00 | 749 | |
3f9a3bf9 RN |
750 | return true; |
751 | } | |
752 | ||
753 | bool wxWMMEMediaCtrlImpl::Load(const wxURI& WXUNUSED(location)) | |
754 | { | |
755 | return false; | |
756 | } | |
757 | ||
5987f174 RN |
758 | bool wxWMMEMediaCtrlImpl::Play() |
759 | { | |
760 | //the directshow driver ("mpegvideo") will crash if we don't do a playParms here | |
761 | MCI_PLAY_PARMS playParms; | |
cf237250 | 762 | playParms.dwCallback = (DWORD)(HWND)m_ctrl->GetHWND(); |
5987f174 RN |
763 | bool bOK = mciSendCommand(m_hDev, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPVOID)&playParms) == 0; |
764 | return (bOK) ;/*|| | |
765 | (mciSendCommand(m_hDev, MCI_RESUME, 0, 0) == 0);*/ | |
766 | } | |
767 | ||
768 | bool wxWMMEMediaCtrlImpl::Pause() | |
769 | { | |
770 | return (mciSendCommand(m_hDev, MCI_PAUSE, MCI_WAIT, 0) == 0); | |
771 | } | |
772 | ||
773 | bool wxWMMEMediaCtrlImpl::Stop() | |
774 | { | |
775 | return (mciSendCommand(m_hDev, MCI_STOP, MCI_WAIT, 0) == 0) && | |
776 | (mciSendCommand(m_hDev, MCI_SEEK, MCI_SEEK_TO_START, 0) == 0); | |
777 | } | |
778 | ||
779 | ||
3f9a3bf9 RN |
780 | wxMediaState wxWMMEMediaCtrlImpl::GetState() |
781 | { | |
782 | MCI_STATUS_PARMS statusParms; | |
783 | statusParms.dwItem = MCI_STATUS_MODE; | |
784 | mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM, | |
785 | (DWORD)(LPVOID)&statusParms); | |
786 | ||
787 | if(statusParms.dwReturn == MCI_MODE_PAUSE) | |
788 | return wxMEDIASTATE_PAUSED; | |
789 | else if(statusParms.dwReturn == MCI_MODE_PLAY) | |
790 | return wxMEDIASTATE_PLAYING; | |
791 | else | |
792 | return wxMEDIASTATE_STOPPED; | |
793 | } | |
794 | ||
795 | bool wxWMMEMediaCtrlImpl::SetPosition(long where) | |
796 | { | |
797 | MCI_SEEK_PARMS seekParms; | |
798 | seekParms.dwCallback = 0; | |
799 | seekParms.dwTo = where; | |
800 | ||
801 | bool bReplay = GetState() == wxMEDIASTATE_PLAYING; | |
802 | ||
803 | if( mciSendCommand(m_hDev, MCI_SEEK, MCI_TO, (DWORD)(LPVOID)&seekParms) != 0) | |
804 | return false; | |
3f9a3bf9 RN |
805 | |
806 | if (bReplay) | |
807 | return Play(); | |
808 | else | |
809 | return true; | |
810 | } | |
811 | ||
812 | long wxWMMEMediaCtrlImpl::GetPosition() | |
813 | { | |
814 | MCI_STATUS_PARMS statusParms; | |
72259e00 RL |
815 | |
816 | statusParms.dwItem = MCI_STATUS_POSITION; | |
817 | if (mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM, | |
3f9a3bf9 RN |
818 | (DWORD)(LPSTR)&statusParms) != 0) |
819 | return 0; | |
820 | ||
821 | return statusParms.dwReturn; | |
822 | } | |
823 | ||
824 | long wxWMMEMediaCtrlImpl::GetDuration() | |
825 | { | |
826 | MCI_STATUS_PARMS statusParms; | |
72259e00 RL |
827 | |
828 | statusParms.dwItem = MCI_STATUS_LENGTH; | |
829 | if (mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM, | |
3f9a3bf9 RN |
830 | (DWORD)(LPSTR)&statusParms) != 0) |
831 | return 0; | |
832 | ||
833 | return statusParms.dwReturn; | |
834 | } | |
835 | ||
836 | void wxWMMEMediaCtrlImpl::DoMoveWindow(int, int, int, int) | |
837 | { | |
838 | } | |
839 | ||
840 | wxSize wxWMMEMediaCtrlImpl::DoGetBestSize() const | |
841 | { | |
842 | if(m_bVideo) | |
843 | { | |
72259e00 | 844 | MCI_DGV_RECT_PARMS rect; |
3f9a3bf9 | 845 | |
33d8e2fc | 846 | mciSendCommand(m_hDev, MCI_WHERE, 0x00020000L//MCI_DGV_WHERE_SOURCE |
72259e00 | 847 | , |
33d8e2fc | 848 | (DWORD)(LPSTR)&rect); |
3f9a3bf9 | 849 | return wxSize(rect.rc.right, rect.rc.bottom); |
3f9a3bf9 RN |
850 | } |
851 | return wxSize(0,0); | |
852 | } | |
853 | ||
854 | double wxWMMEMediaCtrlImpl::GetPlaybackRate() | |
855 | { | |
856 | return 1.0; | |
857 | } | |
858 | ||
859 | bool wxWMMEMediaCtrlImpl::SetPlaybackRate(double) | |
860 | { | |
861 | return false; | |
862 | } | |
863 | ||
5987f174 | 864 | bool wxWMMEMediaCtrlImpl::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) |
3f9a3bf9 | 865 | { |
5987f174 RN |
866 | if(nMsg == MM_MCINOTIFY) |
867 | { | |
868 | wxASSERT(lParam == (WXLPARAM) m_hDev); | |
869 | if(wParam == (WXWPARAM) MCI_NOTIFY_SUCCESSFUL && lParam == (WXLPARAM) m_hDev) | |
870 | { | |
871 | #ifdef __WXDEBUG__ | |
872 | wxASSERT(mciSendCommand(m_hDev, MCI_SEEK, MCI_SEEK_TO_START, 0) == 0); | |
873 | #else | |
874 | mciSendCommand(m_hDev, MCI_SEEK, MCI_SEEK_TO_START, 0); | |
875 | #endif | |
3f9a3bf9 | 876 | |
5987f174 RN |
877 | wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED, m_ctrl->GetId()); |
878 | m_ctrl->GetParent()->ProcessEvent(theEvent); | |
879 | } | |
880 | return true; | |
881 | } | |
3f9a3bf9 RN |
882 | return false; |
883 | } | |
884 | ||
72259e00 RL |
885 | #endif //wxUSE_MEDIACTRL |
886 |