]> git.saurik.com Git - wxWidgets.git/blob - src/msw/mediactrl.cpp
1bde220f0ffe81a713ae845dea0ab397931280c9
[wxWidgets.git] / src / msw / mediactrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/mediactrl.cpp
3 // Purpose: Built-in Media Backends for Windows
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 //===========================================================================
13 // DECLARATIONS
14 //===========================================================================
15
16 //---------------------------------------------------------------------------
17 // Pre-compiled header stuff
18 //---------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "mediactrl.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 //---------------------------------------------------------------------------
32 // Includes
33 //---------------------------------------------------------------------------
34 #include "wx/mediactrl.h"
35
36 //---------------------------------------------------------------------------
37 // Compilation guard
38 //---------------------------------------------------------------------------
39 #if wxUSE_MEDIACTRL
40
41 //---------------------------------------------------------------------------
42 // Externals (somewhere in src/msw/app.cpp)
43 //---------------------------------------------------------------------------
44 extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance(void);
45 #ifdef __WXWINCE__
46 extern wxChar *wxCanvasClassName;
47 #else
48 extern const wxChar *wxCanvasClassName;
49 #endif
50
51 //===========================================================================
52 // BACKEND DECLARATIONS
53 //===========================================================================
54
55 //---------------------------------------------------------------------------
56 //
57 // wxAMMediaBackend
58 //
59 //---------------------------------------------------------------------------
60
61 //---------------------------------------------------------------------------
62 // Compilation guard for DirectShow
63 //---------------------------------------------------------------------------
64 #if wxUSE_DIRECTSHOW
65
66 //---------------------------------------------------------------------------
67 // DirectShow includes
68 //---------------------------------------------------------------------------
69 #include <dshow.h>
70
71 class wxAMMediaBackend : public wxMediaBackend
72 {
73 public:
74 wxAMMediaBackend();
75
76 virtual ~wxAMMediaBackend();
77
78 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
79 wxWindowID id,
80 const wxPoint& pos,
81 const wxSize& size,
82 long style,
83 const wxValidator& validator,
84 const wxString& name);
85
86 virtual bool Play();
87 virtual bool Pause();
88 virtual bool Stop();
89
90 virtual bool Load(const wxString& fileName);
91 virtual bool Load(const wxURI& location);
92
93 virtual wxMediaState GetState();
94
95 virtual bool SetPosition(wxLongLong where);
96 virtual wxLongLong GetPosition();
97 virtual wxLongLong GetDuration();
98
99 virtual void Move(int x, int y, int w, int h);
100 wxSize GetVideoSize() const;
101
102 virtual double GetPlaybackRate();
103 virtual bool SetPlaybackRate(double);
104
105 void Cleanup();
106
107 bool m_bVideo;
108
109 static LRESULT CALLBACK NotifyWndProc(HWND hWnd, UINT nMsg,
110 WPARAM wParam, LPARAM lParam);
111
112 LRESULT CALLBACK OnNotifyWndProc(HWND hWnd, UINT nMsg,
113 WPARAM wParam, LPARAM lParam);
114
115 wxControl* m_ctrl;
116
117 IGraphBuilder* m_pGB;
118 IMediaControl* m_pMC;
119 IMediaEventEx* m_pME;
120 IVideoWindow* m_pVW;
121 IBasicAudio* m_pBA;
122 IBasicVideo* m_pBV;
123 IMediaSeeking* m_pMS;
124
125 HWND m_hNotifyWnd;
126 wxSize m_bestSize;
127
128 DECLARE_DYNAMIC_CLASS(wxAMMediaBackend);
129 };
130
131 #endif //wxUSE_DIRECTSHOW
132
133 //---------------------------------------------------------------------------
134 //
135 // wxMCIMediaBackend
136 //
137 //---------------------------------------------------------------------------
138
139 //---------------------------------------------------------------------------
140 // MCI Includes
141 //---------------------------------------------------------------------------
142 #include <mmsystem.h>
143
144 class wxMCIMediaBackend : public wxMediaBackend
145 {
146 public:
147
148 wxMCIMediaBackend();
149 ~wxMCIMediaBackend();
150
151 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
152 wxWindowID id,
153 const wxPoint& pos,
154 const wxSize& size,
155 long style,
156 const wxValidator& validator,
157 const wxString& name);
158
159 virtual bool Play();
160 virtual bool Pause();
161 virtual bool Stop();
162
163 virtual bool Load(const wxString& fileName);
164 virtual bool Load(const wxURI& location);
165
166 virtual wxMediaState GetState();
167
168 virtual bool SetPosition(wxLongLong where);
169 virtual wxLongLong GetPosition();
170 virtual wxLongLong GetDuration();
171
172 virtual void Move(int x, int y, int w, int h);
173 wxSize GetVideoSize() const;
174
175 virtual double GetPlaybackRate();
176 virtual bool SetPlaybackRate(double dRate);
177
178 static LRESULT CALLBACK NotifyWndProc(HWND hWnd, UINT nMsg,
179 WPARAM wParam, LPARAM lParam);
180
181 LRESULT CALLBACK OnNotifyWndProc(HWND hWnd, UINT nMsg,
182 WPARAM wParam, LPARAM lParam);
183
184 MCIDEVICEID m_hDev; //Our MCI Device ID/Handler
185 wxControl* m_ctrl; //Parent control
186 HWND m_hNotifyWnd; //Window to use for MCI events
187 bool m_bVideo; //Whether or not we have video
188
189 DECLARE_DYNAMIC_CLASS(wxMCIMediaBackend);
190 };
191
192 //---------------------------------------------------------------------------
193 //
194 // wxQTMediaBackend
195 //
196 //---------------------------------------------------------------------------
197
198 //---------------------------------------------------------------------------
199 // QT Compilation Guard
200 //---------------------------------------------------------------------------
201 #if wxUSE_QUICKTIME
202
203 //---------------------------------------------------------------------------
204 // QT Includes
205 //---------------------------------------------------------------------------
206 #include <qtml.h> //Windoze QT include
207 #include <QuickTimeComponents.h> //Standard QT stuff
208
209 class wxQTMediaBackend : public wxMediaBackend
210 {
211 public:
212
213 wxQTMediaBackend();
214 ~wxQTMediaBackend();
215
216 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
217 wxWindowID id,
218 const wxPoint& pos,
219 const wxSize& size,
220 long style,
221 const wxValidator& validator,
222 const wxString& name);
223
224 virtual bool Play();
225 virtual bool Pause();
226 virtual bool Stop();
227
228 virtual bool Load(const wxString& fileName);
229 virtual bool Load(const wxURI& location);
230
231 virtual wxMediaState GetState();
232
233 virtual bool SetPosition(wxLongLong where);
234 virtual wxLongLong GetPosition();
235 virtual wxLongLong GetDuration();
236
237 virtual void Move(int x, int y, int w, int h);
238 wxSize GetVideoSize() const;
239
240 virtual double GetPlaybackRate();
241 virtual bool SetPlaybackRate(double dRate);
242
243 void Cleanup();
244 void FinishLoad();
245
246 wxSize m_bestSize; //Original movie size
247 struct MovieRecord* m_movie; //QT Movie handle/instance
248 wxControl* m_ctrl; //Parent control
249 bool m_bVideo; //Whether or not we have video
250 class _wxQTTimer* m_timer; //Timer for streaming the movie
251
252 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend);
253 };
254
255 //---------------------------------------------------------------------------
256 // End QT Compilation Guard
257 //---------------------------------------------------------------------------
258 #endif //wxUSE_QUICKTIME
259
260 //===========================================================================
261 // IMPLEMENTATION
262 //===========================================================================
263
264 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
265 //
266 // wxAMMediaBackend
267 //
268 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
269
270 //---------------------------------------------------------------------------
271 // Only use if user wants it -
272 //---------------------------------------------------------------------------
273 #if wxUSE_DIRECTSHOW
274
275 IMPLEMENT_DYNAMIC_CLASS(wxAMMediaBackend, wxMediaBackend);
276
277 // Numerical value for when the graph reaches the stop position
278 #define WM_GRAPHNOTIFY WM_USER+13
279
280 //---------------------------------------------------------------------------
281 // Usual debugging macros
282 //---------------------------------------------------------------------------
283 #ifdef __WXDEBUG__
284 #define wxAMVERIFY(x) \
285 { \
286 HRESULT hrdsv = (x); \
287 if ( FAILED(hrdsv) ) \
288 { \
289 /*TCHAR szError[MAX_ERROR_TEXT_LEN];*/ \
290 /*if( AMGetErrorText(hrdsv, szError, MAX_ERROR_TEXT_LEN) == 0)*/ \
291 /*{*/ \
292 /*wxFAIL_MSG( wxString::Format(wxT("DirectShow error \"%s\" ")*/\
293 /*wxT("occured at line %i in ")*/ \
294 /*wxT("mediactrl.cpp"),*/ \
295 /*szError, __LINE__) );*/ \
296 /*}*/ \
297 /*else*/ \
298 wxFAIL_MSG( wxString::Format(wxT("Unknown error (%i) ") \
299 wxT("occured at") \
300 wxT(" line %i in mediactrl.cpp."), \
301 (int)hrdsv, __LINE__) ); \
302 } \
303 }
304 #define wxVERIFY(x) wxASSERT((x))
305 #else
306 #define wxAMVERIFY(x) (x)
307 #define wxVERIFY(x) (x)
308 #endif
309
310 //---------------------------------------------------------------------------
311 // Standard macros for ease of use
312 //---------------------------------------------------------------------------
313 #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
314
315 //---------------------------------------------------------------------------
316 // wxAMMediaBackend Constructor
317 //
318 // Sets m_hNotifyWnd to NULL to signify that we haven't loaded anything yet
319 //---------------------------------------------------------------------------
320 wxAMMediaBackend::wxAMMediaBackend() : m_hNotifyWnd(NULL)
321 {
322 }
323
324 //---------------------------------------------------------------------------
325 // wxAMMediaBackend Destructor
326 //
327 // Cleans up everything
328 //---------------------------------------------------------------------------
329 wxAMMediaBackend::~wxAMMediaBackend()
330 {
331 if (m_hNotifyWnd)
332 Cleanup();
333 }
334
335 //---------------------------------------------------------------------------
336 // wxAMMediaBackend::CreateControl
337 //
338 // ActiveMovie does not really have any native control to speak of,
339 // so we just create a normal control with a black background.
340 //
341 // We also check to see if ActiveMovie is installed
342 //---------------------------------------------------------------------------
343 bool wxAMMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
344 wxWindowID id,
345 const wxPoint& pos,
346 const wxSize& size,
347 long style,
348 const wxValidator& validator,
349 const wxString& name)
350 {
351 //create our filter graph
352 HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
353 IID_IGraphBuilder, (void**)&m_pGB);
354
355 //directshow not installed?
356 if ( FAILED(hr) )
357 return false;
358
359 //release the filter graph - we don't need it yet
360 m_pGB->Release();
361 m_pGB = NULL;
362
363 //
364 // Create window
365 // By default wxWindow(s) is created with a border -
366 // so we need to get rid of those, and create with
367 // wxCLIP_CHILDREN, so that if the driver/backend
368 // is a child window, it refereshes properly
369 //
370 if ( !ctrl->wxControl::Create(parent, id, pos, size,
371 (style | wxNO_BORDER) | wxCLIP_CHILDREN,
372 validator, name) )
373 return false;
374
375 //
376 //Set our background color to black by default
377 //
378 ctrl->SetBackgroundColour(*wxBLACK);
379
380 m_ctrl = ctrl;
381 return true;
382 }
383
384
385 //---------------------------------------------------------------------------
386 // wxAMMediaBackend::Load (file version)
387 //
388 // Creates an Active Movie filter graph from a file or url
389 //---------------------------------------------------------------------------
390 bool wxAMMediaBackend::Load(const wxString& fileName)
391 {
392 if(m_hNotifyWnd)
393 Cleanup();
394
395 CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
396 IID_IGraphBuilder, (void**)&m_pGB);
397
398 //load the graph & render
399 if( FAILED(m_pGB->RenderFile(fileName.wc_str(wxConvLocal), NULL)) )
400 return false;
401
402 //get the interfaces, all of them
403 wxAMVERIFY( m_pGB->QueryInterface(IID_IMediaControl, (void**)&m_pMC) );
404 wxAMVERIFY( m_pGB->QueryInterface(IID_IMediaEventEx, (void**)&m_pME) );
405 wxAMVERIFY( m_pGB->QueryInterface(IID_IMediaSeeking, (void**)&m_pMS) );
406 wxAMVERIFY( m_pGB->QueryInterface(IID_IVideoWindow, (void**)&m_pVW) );
407 wxAMVERIFY( m_pGB->QueryInterface(IID_IBasicAudio, (void**)&m_pBA) );
408 wxAMVERIFY( m_pGB->QueryInterface(IID_IBasicVideo, (void**)&m_pBV) );
409
410 //We could tell if the media has audio or not by
411 //something like
412 //-----
413 //long lVolume;
414 //pBA->get_Volume(&lVolume) == E_NOTIMPL
415 //-----
416 //here...
417
418 //
419 //Obtain the _actual_ size of the movie & remember it
420 //
421 long nX,
422 nY;
423
424 m_bestSize.x = m_bestSize.y = 0;
425
426 m_bVideo = SUCCEEDED( m_pVW->GetWindowPosition( &nX,
427 &nY,
428 (long*)&m_bestSize.x,
429 (long*)&m_bestSize.y) );
430
431 //
432 //If we have video in the media - set it up so that
433 //its a child window of the control, its visible,
434 //and that the control is the owner of the video window
435 //
436 if (m_bVideo)
437 {
438 wxAMVERIFY( m_pVW->put_Owner((OAHWND)m_ctrl->GetHandle()) );
439 wxAMVERIFY( m_pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS) );
440 wxAMVERIFY( m_pVW->put_Visible(OATRUE) ); //OATRUE == -1
441 }
442
443 //
444 // Create a hidden window and register to handle
445 // directshow events for this graph
446 // Note that wxCanvasClassName is already registered
447 // and used by all wxWindows and normal wxControls
448 //
449 m_hNotifyWnd = ::CreateWindow
450 (
451 wxCanvasClassName,
452 NULL,
453 0, 0, 0, 0,
454 0,
455 (HWND) NULL,
456 (HMENU)NULL,
457 wxGetInstance(),
458 (LPVOID) NULL
459 );
460
461 if(!m_hNotifyWnd)
462 {
463 wxLogSysError( wxT("Could not create hidden needed for ")
464 wxT("registering for DirectShow events!") );
465
466 return false;
467 }
468
469 ::SetWindowLongPtr(m_hNotifyWnd, GWLP_WNDPROC,
470 (LONG_PTR)wxAMMediaBackend::NotifyWndProc);
471
472 ::SetWindowLong(m_hNotifyWnd, GWL_USERDATA,
473 (LONG) this);
474
475 wxAMVERIFY( m_pME->SetNotifyWindow((OAHWND)m_hNotifyWnd,
476 WM_GRAPHNOTIFY, 0) );
477
478 //
479 //set the time format
480 //
481 wxAMVERIFY( m_pMS->SetTimeFormat(&TIME_FORMAT_MEDIA_TIME) );
482
483 //
484 // Force the parent window of this control to recalculate
485 // the size of this if sizers are being used
486 // and render the results immediately
487 //
488 m_ctrl->InvalidateBestSize();
489 m_ctrl->GetParent()->Layout();
490 m_ctrl->GetParent()->Refresh();
491 m_ctrl->GetParent()->Update();
492
493 return true;
494 }
495
496 //---------------------------------------------------------------------------
497 // wxAMMediaBackend::Load (URL Version)
498 //
499 // Loads media from a URL. Interestingly enough DirectShow
500 // appears (?) to escape the URL for us, at least on normal
501 // files
502 //---------------------------------------------------------------------------
503 bool wxAMMediaBackend::Load(const wxURI& location)
504 {
505 return Load(location.BuildUnescapedURI());
506 }
507
508 //---------------------------------------------------------------------------
509 // wxAMMediaBackend::Play
510 //
511 // Plays the stream. If it is non-seekable, it will restart it.
512 //---------------------------------------------------------------------------
513 bool wxAMMediaBackend::Play()
514 {
515 return SUCCEEDED( m_pMC->Run() );
516 }
517
518 //---------------------------------------------------------------------------
519 // wxAMMediaBackend::Pause
520 //
521 // Pauses the stream.
522 //---------------------------------------------------------------------------
523 bool wxAMMediaBackend::Pause()
524 {
525 return SUCCEEDED( m_pMC->Pause() );
526 }
527
528 //---------------------------------------------------------------------------
529 // wxAMMediaBackend::Stop
530 //
531 // Stops the stream.
532 //---------------------------------------------------------------------------
533 bool wxAMMediaBackend::Stop()
534 {
535 bool bOK = SUCCEEDED( m_pMC->Stop() );
536
537 //We don't care if it can't get to the beginning in directshow -
538 //it could be a non-seeking filter (wince midi) in which case playing
539 //starts all over again
540 SetPosition(0);
541 return bOK;
542 }
543
544 //---------------------------------------------------------------------------
545 // wxAMMediaBackend::SetPosition
546 //
547 // 1) Translates the current position's time to directshow time,
548 // which is in a scale of 100 nanoseconds
549 // 2) Sets the play position of the IMediaSeeking interface -
550 // passing NULL as the stop position means to keep the old
551 // stop position
552 //---------------------------------------------------------------------------
553 bool wxAMMediaBackend::SetPosition(wxLongLong where)
554 {
555 LONGLONG pos = ((LONGLONG)where.GetValue()) * 10000;
556
557 return SUCCEEDED( m_pMS->SetPositions(
558 &pos,
559 AM_SEEKING_AbsolutePositioning,
560 NULL,
561 AM_SEEKING_NoPositioning
562 ) );
563 }
564
565 //---------------------------------------------------------------------------
566 // wxAMMediaBackend::GetPosition
567 //
568 // 1) Obtains the current play and stop positions from IMediaSeeking
569 // 2) Returns the play position translated to our time base
570 //---------------------------------------------------------------------------
571 wxLongLong wxAMMediaBackend::GetPosition()
572 {
573 LONGLONG outCur, outStop;
574 wxAMVERIFY( m_pMS->GetPositions(&outCur, &outStop) );
575
576 //h,m,s,milli - outdur is in 100 nanos
577 return outCur/10000;
578 }
579
580 //---------------------------------------------------------------------------
581 // wxAMMediaBackend::GetDuration
582 //
583 // 1) Obtains the duration of the media from the IMediaSeeking interface
584 // 2) Converts that value to our time base, and returns it
585 //---------------------------------------------------------------------------
586 wxLongLong wxAMMediaBackend::GetDuration()
587 {
588 LONGLONG outDuration;
589 wxAMVERIFY( m_pMS->GetDuration(&outDuration) );
590
591 //h,m,s,milli - outdur is in 100 nanos
592 return outDuration/10000;
593 }
594
595 //---------------------------------------------------------------------------
596 // wxAMMediaBackend::GetState
597 //
598 // Obtains the state from the IMediaControl interface.
599 // Note that it's enumeration values for stopping/playing
600 // etc. are the same as ours, so we just do a straight cast.
601 // TODO: MS recommends against INFINITE here for
602 // IMediaControl::GetState- do it in stages
603 //---------------------------------------------------------------------------
604 wxMediaState wxAMMediaBackend::GetState()
605 {
606 HRESULT hr;
607 OAFilterState theState;
608 hr = m_pMC->GetState(INFINITE, &theState);
609
610 wxASSERT( SUCCEEDED(hr) );
611
612 //MSW state is the same as ours
613 //State_Stopped = 0,
614 //State_Paused = State_Stopped + 1,
615 //State_Running = State_Paused + 1
616
617 return (wxMediaState) theState;
618 }
619
620 //---------------------------------------------------------------------------
621 // wxAMMediaBackend::GetPlaybackRate
622 //
623 // Pretty simple way of obtaining the playback rate from
624 // the IMediaSeeking interface
625 //---------------------------------------------------------------------------
626 double wxAMMediaBackend::GetPlaybackRate()
627 {
628 double dRate;
629 wxAMVERIFY( m_pMS->GetRate(&dRate) );
630 return dRate;
631 }
632
633 //---------------------------------------------------------------------------
634 // wxAMMediaBackend::SetPlaybackRate
635 //
636 // Sets the playback rate of the media - DirectShow is pretty good
637 // about this, actually
638 //---------------------------------------------------------------------------
639 bool wxAMMediaBackend::SetPlaybackRate(double dRate)
640 {
641 return SUCCEEDED( m_pMS->SetRate(dRate) );
642 }
643
644 //---------------------------------------------------------------------------
645 // wxAMMediaBackend::NotifyWndProc
646 //
647 // Here we check to see if DirectShow tells us we've reached the stop
648 // position in our stream - if it has, it may not actually stop
649 // the stream - which we need to do...
650 //---------------------------------------------------------------------------
651 LRESULT CALLBACK wxAMMediaBackend::NotifyWndProc(HWND hWnd, UINT nMsg,
652 WPARAM wParam,
653 LPARAM lParam)
654 {
655 wxAMMediaBackend* backend = (wxAMMediaBackend*)
656 ::GetWindowLong(hWnd, GWL_USERDATA);
657
658 return backend->OnNotifyWndProc(hWnd, nMsg, wParam, lParam);
659 }
660
661 LRESULT CALLBACK wxAMMediaBackend::OnNotifyWndProc(HWND hWnd, UINT nMsg,
662 WPARAM wParam,
663 LPARAM lParam)
664 {
665 if (nMsg == WM_GRAPHNOTIFY)
666 {
667 LONG evCode,
668 evParam1,
669 evParam2;
670
671 //
672 // DirectShow keeps a list of queued events, and we need
673 // to go through them one by one, stopping at (Hopefully only one)
674 // EC_COMPLETE message
675 //
676 while(SUCCEEDED(m_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
677 (LONG_PTR *) &evParam2, 0)
678 )
679 )
680 {
681 // Cleanup memory that GetEvent allocated
682 wxAMVERIFY( m_pME->FreeEventParams(evCode, evParam1, evParam2) );
683
684 // If this is the end of the clip, notify handler
685 if(EC_COMPLETE == evCode)
686 {
687 //send the event to our child
688 wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId());
689 m_ctrl->ProcessEvent(theEvent);
690
691 //if the user didn't veto it, stop the stream
692 if (theEvent.IsAllowed())
693 {
694 //Interestingly enough, DirectShow does not actually stop
695 //the filters - even when it reaches the end!
696 wxVERIFY( Stop() );
697
698 //send the event to our child
699 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
700 m_ctrl->GetId());
701 m_ctrl->ProcessEvent(theEvent);
702 }
703 }
704 }
705 }
706 return DefWindowProc(hWnd, nMsg, wParam, lParam);
707 }
708
709 //---------------------------------------------------------------------------
710 // wxAMMediaBackend::Cleanup
711 //
712 // 1) Hide/disowns the video window (MS says bad things will happen if
713 // you don't)
714 // 2) Releases all the directshow interfaces we use
715 // TODO: Maybe there's a way to redirect the IGraphBuilder each time
716 // we load, rather then creating and destroying the interfaces
717 // each time?
718 //---------------------------------------------------------------------------
719 void wxAMMediaBackend::Cleanup()
720 {
721 // Hide then disown the window
722 if(m_pVW)
723 {
724 m_pVW->put_Visible(OAFALSE); //OSFALSE == 0
725 m_pVW->put_Owner(NULL);
726 }
727
728 // Release and zero DirectShow interfaces
729 SAFE_RELEASE(m_pME);
730 SAFE_RELEASE(m_pMS);
731 SAFE_RELEASE(m_pMC);
732 SAFE_RELEASE(m_pBA);
733 SAFE_RELEASE(m_pBV);
734 SAFE_RELEASE(m_pVW);
735 SAFE_RELEASE(m_pGB);
736
737 // Get rid of our hidden Window
738 DestroyWindow(m_hNotifyWnd);
739 m_hNotifyWnd = NULL;
740 }
741
742
743 //---------------------------------------------------------------------------
744 // wxAMMediaBackend::GetVideoSize
745 //
746 // Obtains the cached original video size
747 //---------------------------------------------------------------------------
748 wxSize wxAMMediaBackend::GetVideoSize() const
749 {
750 return m_bestSize;
751 }
752
753 //---------------------------------------------------------------------------
754 // wxAMMediaBackend::Move
755 //
756 // Resizes the IVideoWindow to the size of the control window
757 //---------------------------------------------------------------------------
758 void wxAMMediaBackend::Move(int x, int y, int w, int h)
759 {
760 if(m_hNotifyWnd && m_bVideo)
761 {
762 wxAMVERIFY( m_pVW->SetWindowPosition(0, 0, w, h) );
763 }
764 }
765
766 //---------------------------------------------------------------------------
767 // End of wxAMMediaBackend
768 //---------------------------------------------------------------------------
769 #endif //wxUSE_DIRECTSHOW
770
771 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
772 //
773 // wxMCIMediaBackend
774 //
775 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
776
777
778 IMPLEMENT_DYNAMIC_CLASS(wxMCIMediaBackend, wxMediaBackend);
779
780 //---------------------------------------------------------------------------
781 // Usual debugging macros for MCI returns
782 //---------------------------------------------------------------------------
783
784 #ifdef __WXDEBUG__
785 #define wxMCIVERIFY(arg) \
786 { \
787 DWORD nRet; \
788 if ( (nRet = (arg)) != 0) \
789 { \
790 TCHAR sz[5000]; \
791 mciGetErrorString(nRet, sz, 5000); \
792 wxFAIL_MSG(wxString::Format(_T("MCI Error:%s"), sz)); \
793 } \
794 }
795 #else
796 #define wxMCIVERIFY(arg) (arg);
797 #endif
798
799 //---------------------------------------------------------------------------
800 // Simulation for <digitalv.h>
801 //
802 // Mingw and possibly other compilers don't have the digitalv.h header
803 // that is needed to have some essential features of mci work with
804 // windows - so we provide the declarations for the types we use here
805 //---------------------------------------------------------------------------
806
807 typedef struct {
808 DWORD_PTR dwCallback;
809 #ifdef MCI_USE_OFFEXT
810 POINT ptOffset;
811 POINT ptExtent;
812 #else
813 RECT rc;
814 #endif
815 } MCI_DGV_RECT_PARMS;
816
817 typedef struct {
818 DWORD_PTR dwCallback;
819 HWND hWnd;
820 #ifndef _WIN32
821 WORD wReserved1;
822 #endif
823 UINT nCmdShow;
824 #ifndef _WIN32
825 WORD wReserved2;
826 #endif
827 wxChar* lpstrText;
828 } MCI_DGV_WINDOW_PARMS;
829
830 typedef struct {
831 DWORD_PTR dwCallback;
832 DWORD dwTimeFormat;
833 DWORD dwAudio;
834 DWORD dwFileFormat;
835 DWORD dwSpeed;
836 } MCI_DGV_SET_PARMS;
837
838 //---------------------------------------------------------------------------
839 // wxMCIMediaBackend Constructor
840 //
841 // Here we don't need to do much except say we don't have any video :)
842 //---------------------------------------------------------------------------
843 wxMCIMediaBackend::wxMCIMediaBackend() : m_hNotifyWnd(NULL), m_bVideo(false)
844 {
845 }
846
847 //---------------------------------------------------------------------------
848 // wxMCIMediaBackend Destructor
849 //
850 // We close the mci device - note that there may not be an mci device here,
851 // or it may fail - but we don't really care, since we're destructing
852 //---------------------------------------------------------------------------
853 wxMCIMediaBackend::~wxMCIMediaBackend()
854 {
855 if(m_hNotifyWnd)
856 {
857 mciSendCommand(m_hDev, MCI_CLOSE, 0, 0);
858 DestroyWindow(m_hNotifyWnd);
859 m_hNotifyWnd = NULL;
860 }
861 }
862
863 //---------------------------------------------------------------------------
864 // wxMCIMediaBackend::Create
865 //
866 // Here we just tell wxMediaCtrl that mci does exist (which it does, on all
867 // msw systems, at least in some form dating back to win16 days)
868 //---------------------------------------------------------------------------
869 bool wxMCIMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
870 wxWindowID id,
871 const wxPoint& pos,
872 const wxSize& size,
873 long style,
874 const wxValidator& validator,
875 const wxString& name)
876 {
877 //
878 // Create window
879 // By default wxWindow(s) is created with a border -
880 // so we need to get rid of those, and create with
881 // wxCLIP_CHILDREN, so that if the driver/backend
882 // is a child window, it refereshes properly
883 //
884 if ( !ctrl->wxControl::Create(parent, id, pos, size,
885 (style & ~wxBORDER_MASK) | wxCLIP_CHILDREN,
886 validator, name) )
887 return false;
888
889 //
890 //Set our background color to black by default
891 //
892 ctrl->SetBackgroundColour(*wxBLACK);
893
894 m_ctrl = ctrl;
895 return true;
896 }
897
898 //---------------------------------------------------------------------------
899 // wxMCIMediaBackend::Load (file version)
900 //
901 // Here we have MCI load a file and device, set the time format to our
902 // default (milliseconds), and set the video (if any) to play in the control
903 //---------------------------------------------------------------------------
904 bool wxMCIMediaBackend::Load(const wxString& fileName)
905 {
906 //
907 //if the user already called load close the previous MCI device
908 //
909 if(m_hNotifyWnd)
910 {
911 mciSendCommand(m_hDev, MCI_CLOSE, 0, 0);
912 DestroyWindow(m_hNotifyWnd);
913 m_hNotifyWnd = NULL;
914 }
915
916 //
917 //Opens a file and has MCI select a device. Normally you'd put
918 //MCI_OPEN_TYPE in addition to MCI_OPEN_ELEMENT - however if you
919 //omit this it tells MCI to select the device instead. This is
920 //good because we have no reliable way of "enumerating" the devices
921 //in MCI
922 //
923 MCI_OPEN_PARMS openParms;
924 openParms.lpstrElementName = (wxChar*) fileName.c_str();
925
926 if ( mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT,
927 (DWORD)(LPVOID)&openParms) != 0)
928 return false;
929
930 m_hDev = openParms.wDeviceID;
931
932 //
933 //Now set the time format for the device to milliseconds
934 //
935 MCI_SET_PARMS setParms;
936 setParms.dwCallback = 0;
937 setParms.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
938
939 if (mciSendCommand(m_hDev, MCI_SET, MCI_SET_TIME_FORMAT,
940 (DWORD)(LPVOID)&setParms) != 0)
941 return false;
942
943 //
944 //Now tell the MCI device to display the video in our wxMediaCtrl
945 //
946 MCI_DGV_WINDOW_PARMS windowParms;
947 windowParms.hWnd = (HWND)m_ctrl->GetHandle();
948
949 m_bVideo = (mciSendCommand(m_hDev, MCI_WINDOW,
950 0x00010000L, //MCI_DGV_WINDOW_HWND
951 (DWORD)(LPVOID)&windowParms) == 0);
952
953 //
954 // Create a hidden window and register to handle
955 // MCI events
956 // Note that wxCanvasClassName is already registered
957 // and used by all wxWindows and normal wxControls
958 //
959 m_hNotifyWnd = ::CreateWindow
960 (
961 wxCanvasClassName,
962 NULL,
963 0, 0, 0, 0,
964 0,
965 (HWND) NULL,
966 (HMENU)NULL,
967 wxGetInstance(),
968 (LPVOID) NULL
969 );
970
971 if(!m_hNotifyWnd)
972 {
973 wxLogSysError( wxT("Could not create hidden needed for ")
974 wxT("registering for DirectShow events!") );
975
976 return false;
977 }
978
979 ::SetWindowLong(m_hNotifyWnd, GWL_WNDPROC,
980 (LONG)wxMCIMediaBackend::NotifyWndProc);
981
982 ::SetWindowLong(m_hNotifyWnd, GWL_USERDATA,
983 (LONG) this);
984
985 //
986 //Here, if the parent of the control has a sizer - we
987 //tell it to recalculate the size of this control since
988 //the user opened a seperate media file
989 //
990 m_ctrl->InvalidateBestSize();
991 m_ctrl->GetParent()->Layout();
992 m_ctrl->GetParent()->Refresh();
993 m_ctrl->GetParent()->Update();
994
995 return true;
996 }
997
998 //---------------------------------------------------------------------------
999 // wxMCIMediaBackend::Load (URL version)
1000 //
1001 // MCI doesn't support URLs directly (?)
1002 //
1003 // TODO: Use wxURL/wxFileSystem and mmioInstallProc
1004 //---------------------------------------------------------------------------
1005 bool wxMCIMediaBackend::Load(const wxURI& WXUNUSED(location))
1006 {
1007 return false;
1008 }
1009
1010 //---------------------------------------------------------------------------
1011 // wxMCIMediaBackend::Play
1012 //
1013 // Plays/Resumes the MCI device... a couple notes:
1014 // 1) Certain drivers will crash and burn if we don't pass them an
1015 // MCI_PLAY_PARMS, despite the documentation that says otherwise...
1016 // 2) There is a MCI_RESUME command, but MCI_PLAY does the same thing
1017 // and will resume from a stopped state also, so there's no need to
1018 // call both, for example
1019 //---------------------------------------------------------------------------
1020 bool wxMCIMediaBackend::Play()
1021 {
1022 MCI_PLAY_PARMS playParms;
1023 playParms.dwCallback = (DWORD)m_hNotifyWnd;
1024
1025 return ( mciSendCommand(m_hDev, MCI_PLAY, MCI_NOTIFY,
1026 (DWORD)(LPVOID)&playParms) == 0 );
1027 }
1028
1029 //---------------------------------------------------------------------------
1030 // wxMCIMediaBackend::Pause
1031 //
1032 // Pauses the MCI device - nothing special
1033 //---------------------------------------------------------------------------
1034 bool wxMCIMediaBackend::Pause()
1035 {
1036 return (mciSendCommand(m_hDev, MCI_PAUSE, MCI_WAIT, 0) == 0);
1037 }
1038
1039 //---------------------------------------------------------------------------
1040 // wxMCIMediaBackend::Stop
1041 //
1042 // Stops the MCI device & seeks to the beginning as wxMediaCtrl docs outline
1043 //---------------------------------------------------------------------------
1044 bool wxMCIMediaBackend::Stop()
1045 {
1046 return (mciSendCommand(m_hDev, MCI_STOP, MCI_WAIT, 0) == 0) &&
1047 (mciSendCommand(m_hDev, MCI_SEEK, MCI_SEEK_TO_START, 0) == 0);
1048 }
1049
1050 //---------------------------------------------------------------------------
1051 // wxMCIMediaBackend::GetState
1052 //
1053 // Here we get the state and convert it to a wxMediaState -
1054 // since we use direct comparisons with MCI_MODE_PLAY and
1055 // MCI_MODE_PAUSE, we don't care if the MCI_STATUS call
1056 // fails or not
1057 //---------------------------------------------------------------------------
1058 wxMediaState wxMCIMediaBackend::GetState()
1059 {
1060 MCI_STATUS_PARMS statusParms;
1061 statusParms.dwItem = MCI_STATUS_MODE;
1062
1063 mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
1064 (DWORD)(LPVOID)&statusParms);
1065
1066 if(statusParms.dwReturn == MCI_MODE_PAUSE)
1067 return wxMEDIASTATE_PAUSED;
1068 else if(statusParms.dwReturn == MCI_MODE_PLAY)
1069 return wxMEDIASTATE_PLAYING;
1070 else
1071 return wxMEDIASTATE_STOPPED;
1072 }
1073
1074 //---------------------------------------------------------------------------
1075 // wxMCIMediaBackend::SetPosition
1076 //
1077 // Here we set the position of the device in the stream.
1078 // Note that MCI actually stops the device after you seek it if the
1079 // device is playing/paused, so we need to play the file after
1080 // MCI seeks like normal APIs would
1081 //---------------------------------------------------------------------------
1082 bool wxMCIMediaBackend::SetPosition(wxLongLong where)
1083 {
1084 MCI_SEEK_PARMS seekParms;
1085 seekParms.dwCallback = 0;
1086 seekParms.dwTo = where.GetValue();
1087
1088 //device was playing?
1089 bool bReplay = GetState() == wxMEDIASTATE_PLAYING;
1090
1091 if( mciSendCommand(m_hDev, MCI_SEEK, MCI_TO,
1092 (DWORD)(LPVOID)&seekParms) != 0)
1093 return false;
1094
1095 //If the device was playing, resume it
1096 if (bReplay)
1097 return Play();
1098 else
1099 return true;
1100 }
1101
1102 //---------------------------------------------------------------------------
1103 // wxMCIMediaBackend::GetPosition
1104 //
1105 // Gets the position of the device in the stream using the current
1106 // time format... nothing special here...
1107 //---------------------------------------------------------------------------
1108 wxLongLong wxMCIMediaBackend::GetPosition()
1109 {
1110 MCI_STATUS_PARMS statusParms;
1111 statusParms.dwItem = MCI_STATUS_POSITION;
1112
1113 if (mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
1114 (DWORD)(LPSTR)&statusParms) != 0)
1115 return 0;
1116
1117 return statusParms.dwReturn;
1118 }
1119
1120 //---------------------------------------------------------------------------
1121 // wxMCIMediaBackend::GetDuration
1122 //
1123 // Gets the duration of the stream... nothing special
1124 //---------------------------------------------------------------------------
1125 wxLongLong wxMCIMediaBackend::GetDuration()
1126 {
1127 MCI_STATUS_PARMS statusParms;
1128 statusParms.dwItem = MCI_STATUS_LENGTH;
1129
1130 if (mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
1131 (DWORD)(LPSTR)&statusParms) != 0)
1132 return 0;
1133
1134 return statusParms.dwReturn;
1135 }
1136
1137 //---------------------------------------------------------------------------
1138 // wxMCIMediaBackend::Move
1139 //
1140 // Moves the window to a location
1141 //---------------------------------------------------------------------------
1142 void wxMCIMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y),
1143 int w, int h)
1144 {
1145 if (m_hNotifyWnd && m_bVideo)
1146 {
1147 MCI_DGV_RECT_PARMS putParms; //ifdefed MCI_DGV_PUT_PARMS
1148 putParms.rc.top = 0;
1149 putParms.rc.bottom = 0;
1150 putParms.rc.right = w;
1151 putParms.rc.bottom = h;
1152
1153 wxMCIVERIFY( mciSendCommand(m_hDev, MCI_PUT,
1154 0x00040000L, //MCI_DGV_PUT_DESTINATION
1155 (DWORD)(LPSTR)&putParms) );
1156 }
1157 }
1158
1159 //---------------------------------------------------------------------------
1160 // wxMCIMediaBackend::GetVideoSize
1161 //
1162 // Gets the original size of the movie for sizers
1163 //---------------------------------------------------------------------------
1164 wxSize wxMCIMediaBackend::GetVideoSize() const
1165 {
1166 if(m_bVideo)
1167 {
1168 MCI_DGV_RECT_PARMS whereParms; //ifdefed MCI_DGV_WHERE_PARMS
1169
1170 wxMCIVERIFY( mciSendCommand(m_hDev, MCI_WHERE,
1171 0x00020000L, //MCI_DGV_WHERE_SOURCE
1172 (DWORD)(LPSTR)&whereParms) );
1173
1174 return wxSize(whereParms.rc.right, whereParms.rc.bottom);
1175 }
1176 return wxSize(0,0);
1177 }
1178
1179 //---------------------------------------------------------------------------
1180 // wxMCIMediaBackend::GetPlaybackRate
1181 //
1182 // TODO
1183 //---------------------------------------------------------------------------
1184 double wxMCIMediaBackend::GetPlaybackRate()
1185 {
1186 return 1.0;
1187 }
1188
1189 //---------------------------------------------------------------------------
1190 // wxMCIMediaBackend::SetPlaybackRate
1191 //
1192 // TODO
1193 //---------------------------------------------------------------------------
1194 bool wxMCIMediaBackend::SetPlaybackRate(double WXUNUSED(dRate))
1195 {
1196 /*
1197 MCI_WAVE_SET_SAMPLESPERSEC
1198 MCI_DGV_SET_PARMS setParms;
1199 setParms.dwSpeed = (DWORD) (dRate * 1000.0);
1200
1201 return (mciSendCommand(m_hDev, MCI_SET,
1202 0x00020000L, //MCI_DGV_SET_SPEED
1203 (DWORD)(LPSTR)&setParms) == 0);
1204 */
1205 return false;
1206 }
1207
1208 //---------------------------------------------------------------------------
1209 // [static] wxMCIMediaBackend::MSWWindowProc
1210 //
1211 // Here we process a message when MCI reaches the stopping point
1212 // in the stream
1213 //---------------------------------------------------------------------------
1214 LRESULT CALLBACK wxMCIMediaBackend::NotifyWndProc(HWND hWnd, UINT nMsg,
1215 WPARAM wParam,
1216 LPARAM lParam)
1217 {
1218 wxMCIMediaBackend* backend = (wxMCIMediaBackend*)
1219 ::GetWindowLong(hWnd, GWL_USERDATA);
1220 wxASSERT(backend);
1221
1222 return backend->OnNotifyWndProc(hWnd, nMsg, wParam, lParam);
1223 }
1224
1225 LRESULT CALLBACK wxMCIMediaBackend::OnNotifyWndProc(HWND hWnd, UINT nMsg,
1226 WPARAM wParam,
1227 LPARAM lParam)
1228 {
1229 if(nMsg == MM_MCINOTIFY)
1230 {
1231 wxASSERT(lParam == (LPARAM) m_hDev);
1232 if(wParam == MCI_NOTIFY_SUCCESSFUL && lParam == (LPARAM)m_hDev)
1233 {
1234 wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId());
1235 m_ctrl->ProcessEvent(theEvent);
1236
1237 if(theEvent.IsAllowed())
1238 {
1239 wxMCIVERIFY( mciSendCommand(m_hDev, MCI_SEEK,
1240 MCI_SEEK_TO_START, 0) );
1241
1242 //send the event to our child
1243 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
1244 m_ctrl->GetId());
1245 m_ctrl->ProcessEvent(theEvent);
1246 }
1247 }
1248 }
1249 return DefWindowProc(hWnd, nMsg, wParam, lParam);
1250 }
1251 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1252 //
1253 // wxQTMediaBackend
1254 //
1255 // TODO: Use a less cludgy way to pause/get state/set state
1256 // TODO: Dynamically load from qtml.dll
1257 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1258
1259 #if wxUSE_QUICKTIME
1260
1261 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
1262
1263 //Time between timer calls
1264 #define MOVIE_DELAY 100
1265
1266 #include "wx/timer.h"
1267
1268 // --------------------------------------------------------------------------
1269 // wxQTTimer - Handle Asyncronous Playing
1270 // --------------------------------------------------------------------------
1271 class _wxQTTimer : public wxTimer
1272 {
1273 public:
1274 _wxQTTimer(Movie movie, wxQTMediaBackend* parent) :
1275 m_movie(movie), m_bPaused(false), m_parent(parent)
1276 {
1277 }
1278
1279 ~_wxQTTimer()
1280 {
1281 }
1282
1283 bool GetPaused() {return m_bPaused;}
1284 void SetPaused(bool bPaused) {m_bPaused = bPaused;}
1285
1286 //-----------------------------------------------------------------------
1287 // _wxQTTimer::Notify
1288 //
1289 // 1) Checks to see if the movie is done, and if not continues
1290 // streaming the movie
1291 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
1292 // the movie.
1293 //-----------------------------------------------------------------------
1294 void Notify()
1295 {
1296 if (!m_bPaused)
1297 {
1298 if(!IsMovieDone(m_movie))
1299 MoviesTask(m_movie, MOVIE_DELAY);
1300 else
1301 {
1302 wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
1303 m_parent->m_ctrl->GetId());
1304 m_parent->m_ctrl->ProcessEvent(theEvent);
1305
1306 if(theEvent.IsAllowed())
1307 {
1308 Stop();
1309 m_parent->Stop();
1310 wxASSERT(::GetMoviesError() == noErr);
1311
1312 //send the event to our child
1313 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
1314 m_parent->m_ctrl->GetId());
1315 m_parent->m_ctrl->ProcessEvent(theEvent);
1316 }
1317 }
1318 }
1319 }
1320
1321 protected:
1322 Movie m_movie; //Our movie instance
1323 bool m_bPaused; //Whether we are paused or not
1324 wxQTMediaBackend* m_parent; //Backend pointer
1325 };
1326
1327 //---------------------------------------------------------------------------
1328 // wxQTMediaBackend Destructor
1329 //
1330 // Sets m_timer to NULL signifying we havn't loaded anything yet
1331 //---------------------------------------------------------------------------
1332 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
1333 {
1334 }
1335
1336 //---------------------------------------------------------------------------
1337 // wxQTMediaBackend Destructor
1338 //
1339 // 1) Cleans up the QuickTime movie instance
1340 // 2) Decrements the QuickTime reference counter - if this reaches
1341 // 0, QuickTime shuts down
1342 // 3) Decrements the QuickTime Windows Media Layer reference counter -
1343 // if this reaches 0, QuickTime shuts down the Windows Media Layer
1344 //---------------------------------------------------------------------------
1345 wxQTMediaBackend::~wxQTMediaBackend()
1346 {
1347 if(m_timer)
1348 Cleanup();
1349
1350 //Note that ExitMovies() is not neccessary, but
1351 //the docs are fuzzy on whether or not TerminateQTML is
1352 ExitMovies();
1353 TerminateQTML();
1354 }
1355
1356 //---------------------------------------------------------------------------
1357 // wxQTMediaBackend::CreateControl
1358 //
1359 // 1) Intializes QuickTime
1360 // 2) Creates the control window
1361 //---------------------------------------------------------------------------
1362 bool wxQTMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
1363 wxWindowID id,
1364 const wxPoint& pos,
1365 const wxSize& size,
1366 long style,
1367 const wxValidator& validator,
1368 const wxString& name)
1369 {
1370 int nError;
1371 if ((nError = InitializeQTML(0)) != noErr) //-2093 no dll
1372 {
1373 wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError));
1374 return false;
1375 }
1376 EnterMovies();
1377
1378 //
1379 // Create window
1380 // By default wxWindow(s) is created with a border -
1381 // so we need to get rid of those
1382 //
1383 // Since we don't have a child window like most other
1384 // backends, we don't need wxCLIP_CHILDREN
1385 //
1386 if ( !ctrl->wxControl::Create(parent, id, pos, size,
1387 (style & ~wxBORDER_MASK),
1388 validator, name) )
1389 return false;
1390
1391 //
1392 //Set our background color to black by default
1393 //
1394 ctrl->SetBackgroundColour(*wxBLACK);
1395
1396 m_ctrl = ctrl;
1397 return true;
1398 }
1399
1400 //---------------------------------------------------------------------------
1401 // wxQTMediaBackend::Load (file version)
1402 //
1403 // 1) Get an FSSpec from the Windows path name
1404 // 2) Open the movie
1405 // 3) Obtain the movie instance from the movie resource
1406 // 4)
1407 //---------------------------------------------------------------------------
1408 bool wxQTMediaBackend::Load(const wxString& fileName)
1409 {
1410 if(m_timer)
1411 Cleanup();
1412
1413 OSErr err = noErr;
1414 short movieResFile;
1415 FSSpec sfFile;
1416
1417 if (NativePathNameToFSSpec ((char*) fileName.mb_str(), &sfFile, 0) != noErr)
1418 return false;
1419
1420 if (OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr)
1421 return false;
1422
1423 short movieResID = 0;
1424 Str255 movieName;
1425
1426 err = NewMovieFromFile (
1427 &m_movie,
1428 movieResFile,
1429 &movieResID,
1430 movieName,
1431 newMovieActive,
1432 NULL); //wasChanged
1433
1434 CloseMovieFile (movieResFile);
1435
1436 if (err != noErr)
1437 return false;
1438
1439 FinishLoad();
1440
1441 return ::GetMoviesError() == noErr;
1442 }
1443
1444 //---------------------------------------------------------------------------
1445 // wxQTMediaBackend::Move
1446 //
1447 // TODO
1448 //---------------------------------------------------------------------------
1449 bool wxQTMediaBackend::Load(const wxURI& location)
1450 {
1451 if(m_timer)
1452 Cleanup();
1453
1454 wxString theURI = location.BuildURI();
1455
1456 OSErr err = noErr;
1457
1458 Handle theHandle = NewHandleClear(theURI.length() + 1);
1459 wxASSERT(theHandle);
1460
1461 BlockMove(theURI.mb_str(), *theHandle, theURI.length() + 1);
1462
1463 //create the movie from the handle that refers to the URI
1464 err = NewMovieFromDataRef(&m_movie, newMovieActive,
1465 NULL, theHandle,
1466 URLDataHandlerSubType);
1467
1468 DisposeHandle(theHandle);
1469
1470 if (err != noErr)
1471 return false;
1472
1473 //preroll movie for streaming
1474 //TODO:Async this?
1475 TimeValue timeNow;
1476 Fixed playRate;
1477 timeNow = GetMovieTime(m_movie, NULL);
1478 playRate = GetMoviePreferredRate(m_movie);
1479 PrePrerollMovie(m_movie, timeNow, playRate, NULL, NULL);
1480 PrerollMovie(m_movie, timeNow, playRate);
1481 SetMovieRate(m_movie, playRate);
1482
1483 FinishLoad();
1484
1485 return ::GetMoviesError() == noErr;
1486 }
1487
1488 //---------------------------------------------------------------------------
1489 // wxQTMediaBackend::Move
1490 //
1491 // TODO
1492 //---------------------------------------------------------------------------
1493 void wxQTMediaBackend::FinishLoad()
1494 {
1495 m_timer = new _wxQTTimer(m_movie, (wxQTMediaBackend*) this);
1496 wxASSERT(m_timer);
1497
1498 //get the real size of the movie
1499 Rect outRect;
1500 ::GetMovieNaturalBoundsRect (m_movie, &outRect);
1501 wxASSERT(::GetMoviesError() == noErr);
1502
1503 m_bestSize.x = outRect.right - outRect.left;
1504 m_bestSize.y = outRect.bottom - outRect.top;
1505
1506 //reparent movie/*AudioMediaCharacteristic*/
1507 if(GetMovieIndTrackType(m_movie, 1,
1508 VisualMediaCharacteristic,
1509 movieTrackCharacteristic |
1510 movieTrackEnabledOnly) != NULL)
1511 {
1512 CreatePortAssociation(m_ctrl->GetHWND(), NULL, 0L);
1513
1514 SetMovieGWorld(m_movie,
1515 (CGrafPtr) GetNativeWindowPort(m_ctrl->GetHWND()),
1516 nil);
1517 }
1518
1519 //we want millisecond precision
1520 ::SetMovieTimeScale(m_movie, 1000);
1521 wxASSERT(::GetMoviesError() == noErr);
1522
1523 //
1524 //Here, if the parent of the control has a sizer - we
1525 //tell it to recalculate the size of this control since
1526 //the user opened a seperate media file
1527 //
1528 m_ctrl->InvalidateBestSize();
1529 m_ctrl->GetParent()->Layout();
1530 m_ctrl->GetParent()->Refresh();
1531 m_ctrl->GetParent()->Update();
1532 }
1533
1534 //---------------------------------------------------------------------------
1535 // wxQTMediaBackend::Move
1536 //
1537 // TODO
1538 //---------------------------------------------------------------------------
1539 bool wxQTMediaBackend::Play()
1540 {
1541 ::StartMovie(m_movie);
1542 m_timer->SetPaused(false);
1543 m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
1544 return ::GetMoviesError() == noErr;
1545 }
1546
1547 //---------------------------------------------------------------------------
1548 // wxQTMediaBackend::Move
1549 //
1550 // TODO
1551 //---------------------------------------------------------------------------
1552 bool wxQTMediaBackend::Pause()
1553 {
1554 ::StopMovie(m_movie);
1555 m_timer->SetPaused(true);
1556 m_timer->Stop();
1557 return ::GetMoviesError() == noErr;
1558 }
1559
1560 //---------------------------------------------------------------------------
1561 // wxQTMediaBackend::Move
1562 //
1563 // TODO
1564 //---------------------------------------------------------------------------
1565 bool wxQTMediaBackend::Stop()
1566 {
1567 m_timer->SetPaused(false);
1568 m_timer->Stop();
1569
1570 ::StopMovie(m_movie);
1571 if(::GetMoviesError() != noErr)
1572 return false;
1573
1574 ::GoToBeginningOfMovie(m_movie);
1575 return ::GetMoviesError() == noErr;
1576 }
1577
1578 //---------------------------------------------------------------------------
1579 // wxQTMediaBackend::Move
1580 //
1581 // TODO
1582 //---------------------------------------------------------------------------
1583 double wxQTMediaBackend::GetPlaybackRate()
1584 {
1585 return ( ((double)::GetMovieRate(m_movie)) / 0x10000);
1586 }
1587
1588 //---------------------------------------------------------------------------
1589 // wxQTMediaBackend::Move
1590 //
1591 // TODO
1592 //---------------------------------------------------------------------------
1593 bool wxQTMediaBackend::SetPlaybackRate(double dRate)
1594 {
1595 ::SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
1596 return ::GetMoviesError() == noErr;
1597 }
1598
1599 //---------------------------------------------------------------------------
1600 // wxQTMediaBackend::Move
1601 //
1602 // TODO
1603 //---------------------------------------------------------------------------
1604 bool wxQTMediaBackend::SetPosition(wxLongLong where)
1605 {
1606 TimeRecord theTimeRecord;
1607 memset(&theTimeRecord, 0, sizeof(TimeRecord));
1608 theTimeRecord.value.lo = where.GetValue();
1609 theTimeRecord.scale = ::GetMovieTimeScale(m_movie);
1610 theTimeRecord.base = ::GetMovieTimeBase(m_movie);
1611 ::SetMovieTime(m_movie, &theTimeRecord);
1612
1613 if (::GetMoviesError() != noErr)
1614 return false;
1615
1616 return true;
1617 }
1618
1619 //---------------------------------------------------------------------------
1620 // wxQTMediaBackend::Move
1621 //
1622 // TODO
1623 //---------------------------------------------------------------------------
1624 wxLongLong wxQTMediaBackend::GetPosition()
1625 {
1626 return ::GetMovieTime(m_movie, NULL);
1627 }
1628
1629 //---------------------------------------------------------------------------
1630 // wxQTMediaBackend::Move
1631 //
1632 // TODO
1633 //---------------------------------------------------------------------------
1634 wxLongLong wxQTMediaBackend::GetDuration()
1635 {
1636 return ::GetMovieDuration(m_movie);
1637 }
1638
1639 //---------------------------------------------------------------------------
1640 // wxQTMediaBackend::Move
1641 //
1642 // TODO
1643 //---------------------------------------------------------------------------
1644 wxMediaState wxQTMediaBackend::GetState()
1645 {
1646 if ( !m_timer || (m_timer->IsRunning() == false &&
1647 m_timer->GetPaused() == false) )
1648 return wxMEDIASTATE_STOPPED;
1649
1650 if( m_timer->IsRunning() == true )
1651 return wxMEDIASTATE_PLAYING;
1652 else
1653 return wxMEDIASTATE_PAUSED;
1654 }
1655
1656 //---------------------------------------------------------------------------
1657 // wxQTMediaBackend::Move
1658 //
1659 // TODO
1660 //---------------------------------------------------------------------------
1661 void wxQTMediaBackend::Cleanup()
1662 {
1663 delete m_timer;
1664 m_timer = NULL;
1665
1666 StopMovie(m_movie);
1667 DisposeMovie(m_movie);
1668 }
1669
1670 //---------------------------------------------------------------------------
1671 // wxQTMediaBackend::Move
1672 //
1673 // TODO
1674 //---------------------------------------------------------------------------
1675 wxSize wxQTMediaBackend::GetVideoSize() const
1676 {
1677 return m_bestSize;
1678 }
1679
1680 //---------------------------------------------------------------------------
1681 // wxQTMediaBackend::Move
1682 //
1683 // TODO
1684 //---------------------------------------------------------------------------
1685 void wxQTMediaBackend::Move(int x, int y, int w, int h)
1686 {
1687 if(m_timer)
1688 {
1689 Rect theRect = {0, 0, h, w};
1690
1691 ::SetMovieBox(m_movie, &theRect);
1692 wxASSERT(::GetMoviesError() == noErr);
1693 }
1694 }
1695
1696 //---------------------------------------------------------------------------
1697 // End QT Compilation Guard
1698 //---------------------------------------------------------------------------
1699 #endif //wxUSE_QUICKTIME
1700
1701 //in source file that contains stuff you don't directly use
1702 #include <wx/html/forcelnk.h>
1703 FORCE_LINK_ME(basewxmediabackends);
1704
1705 //---------------------------------------------------------------------------
1706 // End wxMediaCtrl Compilation Guard and this file
1707 //---------------------------------------------------------------------------
1708 #endif //wxUSE_MEDIACTRL
1709
1710