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