1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/mediactrlcmn.cpp
3 // Purpose:     wxMediaCtrl common code
4 // Author:      Ryan Norton <wxprojects@comcast.net>
5 // Modified by:
6 // Created:     11/07/04
7 // Copyright:   (c) Ryan Norton
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // TODO: Platform specific backend defaults?
12 
13 //===========================================================================
14 // Declarations
15 //===========================================================================
16 
17 //---------------------------------------------------------------------------
18 // Includes
19 //---------------------------------------------------------------------------
20 
21 #include "wx/wxprec.h"
22 
23 #ifdef __BORLANDC__
24     #pragma hdrstop
25 #endif
26 
27 #if wxUSE_MEDIACTRL
28 
29 #ifndef WX_PRECOMP
30     #include "wx/hash.h"
31     #include "wx/log.h"
32 #endif
33 
34 #include "wx/mediactrl.h"
35 
36 //===========================================================================
37 //
38 // Implementation
39 //
40 //===========================================================================
41 
42 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
43 // RTTI and Event implementations
44 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
45 
46 IMPLEMENT_CLASS(wxMediaCtrl, wxControl)
47 wxDEFINE_EVENT( wxEVT_MEDIA_STATECHANGED, wxMediaEvent );
48 wxDEFINE_EVENT( wxEVT_MEDIA_PLAY, wxMediaEvent );
49 wxDEFINE_EVENT( wxEVT_MEDIA_PAUSE, wxMediaEvent );
50 IMPLEMENT_CLASS(wxMediaBackend, wxObject)
51 IMPLEMENT_DYNAMIC_CLASS(wxMediaEvent, wxEvent)
52 wxDEFINE_EVENT( wxEVT_MEDIA_FINISHED, wxMediaEvent );
53 wxDEFINE_EVENT( wxEVT_MEDIA_LOADED, wxMediaEvent );
54 wxDEFINE_EVENT( wxEVT_MEDIA_STOP, wxMediaEvent );
55 
56 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
57 //
58 //  wxMediaCtrl
59 //
60 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
61 
62 //---------------------------------------------------------------------------
63 // wxMediaBackend Destructor
64 //
65 // This is here because the DARWIN gcc compiler badly screwed up and
66 // needs the destructor implementation in the source
67 //---------------------------------------------------------------------------
~wxMediaBackend()68 wxMediaBackend::~wxMediaBackend()
69 {
70 }
71 
72 //---------------------------------------------------------------------------
73 // wxMediaCtrl::Create (file version)
74 // wxMediaCtrl::Create (URL version)
75 //
76 // Searches for a backend that is installed on the system (backends
77 // starting with lower characters in the alphabet are given priority),
78 // and creates the control from it
79 //
80 // This searches by searching the global RTTI hashtable, class by class,
81 // attempting to call CreateControl on each one found that is a derivative
82 // of wxMediaBackend - if it succeeded Create returns true, otherwise
83 // it keeps iterating through the hashmap.
84 //---------------------------------------------------------------------------
Create(wxWindow * parent,wxWindowID id,const wxString & fileName,const wxPoint & pos,const wxSize & size,long style,const wxString & szBackend,const wxValidator & validator,const wxString & name)85 bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id,
86                 const wxString& fileName,
87                 const wxPoint& pos,
88                 const wxSize& size,
89                 long style,
90                 const wxString& szBackend,
91                 const wxValidator& validator,
92                 const wxString& name)
93 {
94     if(!szBackend.empty())
95     {
96         wxClassInfo* pClassInfo = wxClassInfo::FindClass(szBackend);
97 
98         if(!pClassInfo || !DoCreate(pClassInfo, parent, id,
99                                     pos, size, style, validator, name))
100         {
101             m_imp = NULL;
102             return false;
103         }
104 
105         if (!fileName.empty())
106         {
107             if (!Load(fileName))
108             {
109                 wxDELETE(m_imp);
110                 return false;
111             }
112         }
113 
114         SetInitialSize(size);
115         return true;
116     }
117     else
118     {
119         wxClassInfo::const_iterator it = wxClassInfo::begin_classinfo();
120 
121         const wxClassInfo* classInfo;
122 
123         while((classInfo = NextBackend(&it)) != NULL)
124         {
125             if(!DoCreate(classInfo, parent, id,
126                          pos, size, style, validator, name))
127                 continue;
128 
129             if (!fileName.empty())
130             {
131                 if (Load(fileName))
132                 {
133                     SetInitialSize(size);
134                     return true;
135                 }
136                 else
137                     delete m_imp;
138             }
139             else
140             {
141                 SetInitialSize(size);
142                 return true;
143             }
144         }
145 
146         m_imp = NULL;
147         return false;
148     }
149 }
150 
Create(wxWindow * parent,wxWindowID id,const wxURI & location,const wxPoint & pos,const wxSize & size,long style,const wxString & szBackend,const wxValidator & validator,const wxString & name)151 bool wxMediaCtrl::Create(wxWindow* parent, wxWindowID id,
152                          const wxURI& location,
153                          const wxPoint& pos,
154                          const wxSize& size,
155                          long style,
156                          const wxString& szBackend,
157                          const wxValidator& validator,
158                          const wxString& name)
159 {
160     if(!szBackend.empty())
161     {
162         wxClassInfo* pClassInfo = wxClassInfo::FindClass(szBackend);
163         if(!pClassInfo || !DoCreate(pClassInfo, parent, id,
164                                     pos, size, style, validator, name))
165         {
166             m_imp = NULL;
167             return false;
168         }
169 
170         if (!Load(location))
171         {
172             wxDELETE(m_imp);
173             return false;
174         }
175 
176         SetInitialSize(size);
177         return true;
178     }
179     else
180     {
181         wxClassInfo::const_iterator it  = wxClassInfo::begin_classinfo();
182 
183         const wxClassInfo* classInfo;
184 
185         while((classInfo = NextBackend(&it)) != NULL)
186         {
187             if(!DoCreate(classInfo, parent, id,
188                          pos, size, style, validator, name))
189                 continue;
190 
191             if (Load(location))
192             {
193                 SetInitialSize(size);
194                 return true;
195             }
196             else
197                 delete m_imp;
198         }
199 
200         m_imp = NULL;
201         return false;
202     }
203 }
204 
205 //---------------------------------------------------------------------------
206 // wxMediaCtrl::DoCreate
207 //
208 // Attempts to create the control from a backend
209 //---------------------------------------------------------------------------
DoCreate(const wxClassInfo * classInfo,wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)210 bool wxMediaCtrl::DoCreate(const wxClassInfo* classInfo,
211                             wxWindow* parent, wxWindowID id,
212                             const wxPoint& pos,
213                             const wxSize& size,
214                             long style,
215                             const wxValidator& validator,
216                             const wxString& name)
217 {
218     m_imp = (wxMediaBackend*)classInfo->CreateObject();
219 
220     if( m_imp->CreateControl(this, parent, id, pos, size,
221                              style, validator, name) )
222     {
223         return true;
224     }
225 
226     delete m_imp;
227     return false;
228 }
229 
230 //---------------------------------------------------------------------------
231 // wxMediaCtrl::NextBackend (static)
232 //
233 //
234 // Search through the RTTI hashmap one at a
235 // time, attempting to create each derivative
236 // of wxMediaBackend
237 //
238 //
239 // STL isn't compatible with and will have a compilation error
240 // on a wxNode, however, wxHashTable::compatibility_iterator is
241 // incompatible with the old 2.4 stable version - but since
242 // we're in 2.5+ only we don't need to worry about the new version
243 //---------------------------------------------------------------------------
NextBackend(wxClassInfo::const_iterator * it)244 const wxClassInfo* wxMediaCtrl::NextBackend(wxClassInfo::const_iterator* it)
245 {
246     for ( wxClassInfo::const_iterator end = wxClassInfo::end_classinfo();
247           *it != end; ++(*it) )
248     {
249         const wxClassInfo* classInfo = **it;
250         if ( classInfo->IsKindOf(wxCLASSINFO(wxMediaBackend))  &&
251              classInfo != wxCLASSINFO(wxMediaBackend) )
252         {
253             ++(*it);
254             return classInfo;
255         }
256     }
257 
258     //
259     // Nope - couldn't successfully find one... fail
260     //
261     return NULL;
262 }
263 
264 
265 //---------------------------------------------------------------------------
266 // wxMediaCtrl Destructor
267 //
268 // Free up the backend if it exists
269 //---------------------------------------------------------------------------
~wxMediaCtrl()270 wxMediaCtrl::~wxMediaCtrl()
271 {
272     if (m_imp)
273         delete m_imp;
274 }
275 
276 //---------------------------------------------------------------------------
277 // wxMediaCtrl::Load (file version)
278 // wxMediaCtrl::Load (URL version)
279 // wxMediaCtrl::Load (URL & Proxy version)
280 // wxMediaCtrl::Load (wxInputStream version)
281 //
282 // Here we call load of the backend - keeping
283 // track of whether it was successful or not - which
284 // will determine which later method calls work
285 //---------------------------------------------------------------------------
Load(const wxString & fileName)286 bool wxMediaCtrl::Load(const wxString& fileName)
287 {
288     if(m_imp)
289         return (m_bLoaded = m_imp->Load(fileName));
290     return false;
291 }
292 
Load(const wxURI & location)293 bool wxMediaCtrl::Load(const wxURI& location)
294 {
295     if(m_imp)
296         return (m_bLoaded = m_imp->Load(location));
297     return false;
298 }
299 
Load(const wxURI & location,const wxURI & proxy)300 bool wxMediaCtrl::Load(const wxURI& location, const wxURI& proxy)
301 {
302     if(m_imp)
303         return (m_bLoaded = m_imp->Load(location, proxy));
304     return false;
305 }
306 
307 //---------------------------------------------------------------------------
308 // wxMediaCtrl::Play
309 // wxMediaCtrl::Pause
310 // wxMediaCtrl::Stop
311 // wxMediaCtrl::GetPlaybackRate
312 // wxMediaCtrl::SetPlaybackRate
313 // wxMediaCtrl::Seek --> SetPosition
314 // wxMediaCtrl::Tell --> GetPosition
315 // wxMediaCtrl::Length --> GetDuration
316 // wxMediaCtrl::GetState
317 // wxMediaCtrl::DoGetBestSize
318 // wxMediaCtrl::SetVolume
319 // wxMediaCtrl::GetVolume
320 // wxMediaCtrl::ShowInterface
321 // wxMediaCtrl::GetDownloadProgress
322 // wxMediaCtrl::GetDownloadTotal
323 //
324 // 1) Check to see whether the backend exists and is loading
325 // 2) Call the backend's version of the method, returning success
326 //    if the backend's version succeeds
327 //---------------------------------------------------------------------------
Play()328 bool wxMediaCtrl::Play()
329 {
330     if(m_imp && m_bLoaded)
331         return m_imp->Play();
332     return 0;
333 }
334 
Pause()335 bool wxMediaCtrl::Pause()
336 {
337     if(m_imp && m_bLoaded)
338         return m_imp->Pause();
339     return 0;
340 }
341 
Stop()342 bool wxMediaCtrl::Stop()
343 {
344     if(m_imp && m_bLoaded)
345         return m_imp->Stop();
346     return 0;
347 }
348 
GetPlaybackRate()349 double wxMediaCtrl::GetPlaybackRate()
350 {
351     if(m_imp && m_bLoaded)
352         return m_imp->GetPlaybackRate();
353     return 0;
354 }
355 
SetPlaybackRate(double dRate)356 bool wxMediaCtrl::SetPlaybackRate(double dRate)
357 {
358     if(m_imp && m_bLoaded)
359         return m_imp->SetPlaybackRate(dRate);
360     return false;
361 }
362 
Seek(wxFileOffset where,wxSeekMode mode)363 wxFileOffset wxMediaCtrl::Seek(wxFileOffset where, wxSeekMode mode)
364 {
365     wxFileOffset offset;
366 
367     switch (mode)
368     {
369     case wxFromStart:
370         offset = where;
371         break;
372     case wxFromEnd:
373         offset = Length() - where;
374         break;
375 //    case wxFromCurrent:
376     default:
377         offset = Tell() + where;
378         break;
379     }
380 
381     if(m_imp && m_bLoaded && m_imp->SetPosition(offset))
382         return offset;
383     return wxInvalidOffset;
384 }
385 
Tell()386 wxFileOffset wxMediaCtrl::Tell()
387 {
388     if(m_imp && m_bLoaded)
389         return (wxFileOffset) m_imp->GetPosition().ToLong();
390     return wxInvalidOffset;
391 }
392 
Length()393 wxFileOffset wxMediaCtrl::Length()
394 {
395     if(m_imp && m_bLoaded)
396         return (wxFileOffset) m_imp->GetDuration().ToLong();
397     return wxInvalidOffset;
398 }
399 
GetState()400 wxMediaState wxMediaCtrl::GetState()
401 {
402     if(m_imp && m_bLoaded)
403         return m_imp->GetState();
404     return wxMEDIASTATE_STOPPED;
405 }
406 
DoGetBestSize() const407 wxSize wxMediaCtrl::DoGetBestSize() const
408 {
409     if(m_imp)
410         return m_imp->GetVideoSize();
411     return wxSize(0,0);
412 }
413 
GetVolume()414 double wxMediaCtrl::GetVolume()
415 {
416     if(m_imp && m_bLoaded)
417         return m_imp->GetVolume();
418     return 0.0;
419 }
420 
SetVolume(double dVolume)421 bool wxMediaCtrl::SetVolume(double dVolume)
422 {
423     if(m_imp && m_bLoaded)
424         return m_imp->SetVolume(dVolume);
425     return false;
426 }
427 
ShowPlayerControls(wxMediaCtrlPlayerControls flags)428 bool wxMediaCtrl::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
429 {
430     if(m_imp)
431         return m_imp->ShowPlayerControls(flags);
432     return false;
433 }
434 
GetDownloadProgress()435 wxFileOffset wxMediaCtrl::GetDownloadProgress()
436 {
437     if(m_imp && m_bLoaded)
438         return (wxFileOffset) m_imp->GetDownloadProgress().ToLong();
439     return wxInvalidOffset;
440 }
441 
GetDownloadTotal()442 wxFileOffset wxMediaCtrl::GetDownloadTotal()
443 {
444     if(m_imp && m_bLoaded)
445         return (wxFileOffset) m_imp->GetDownloadTotal().ToLong();
446     return wxInvalidOffset;
447 }
448 
449 //---------------------------------------------------------------------------
450 // wxMediaCtrl::DoMoveWindow
451 //
452 // 1) Call parent's version so that our control's window moves where
453 //    it's supposed to
454 // 2) If the backend exists and is loaded, move the video
455 //    of the media to where our control's window is now located
456 //---------------------------------------------------------------------------
DoMoveWindow(int x,int y,int w,int h)457 void wxMediaCtrl::DoMoveWindow(int x, int y, int w, int h)
458 {
459     wxControl::DoMoveWindow(x,y,w,h);
460 
461     if(m_imp)
462         m_imp->Move(x, y, w, h);
463 }
464 
465 //---------------------------------------------------------------------------
466 // wxMediaCtrl::MacVisibilityChanged
467 //---------------------------------------------------------------------------
468 #ifdef __WXOSX_CARBON__
MacVisibilityChanged()469 void wxMediaCtrl::MacVisibilityChanged()
470 {
471     wxControl::MacVisibilityChanged();
472 
473     if(m_imp)
474         m_imp->MacVisibilityChanged();
475 }
476 #endif
477 
478 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
479 //
480 //  wxMediaBackendCommonBase
481 //
482 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
483 
NotifyMovieSizeChanged()484 void wxMediaBackendCommonBase::NotifyMovieSizeChanged()
485 {
486     // our best size changed after opening a new file
487     m_ctrl->InvalidateBestSize();
488     m_ctrl->SetSize(m_ctrl->GetSize());
489 
490     // if the parent of the control has a sizer ask it to refresh our size
491     wxWindow * const parent = m_ctrl->GetParent();
492     if ( parent->GetSizer() )
493     {
494         m_ctrl->GetParent()->Layout();
495         m_ctrl->GetParent()->Refresh();
496         m_ctrl->GetParent()->Update();
497     }
498 }
499 
NotifyMovieLoaded()500 void wxMediaBackendCommonBase::NotifyMovieLoaded()
501 {
502     NotifyMovieSizeChanged();
503 
504     // notify about movie being fully loaded
505     QueueEvent(wxEVT_MEDIA_LOADED);
506 }
507 
SendStopEvent()508 bool wxMediaBackendCommonBase::SendStopEvent()
509 {
510     wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId());
511 
512     return !m_ctrl->GetEventHandler()->ProcessEvent(theEvent) || theEvent.IsAllowed();
513 }
514 
QueueEvent(wxEventType evtType)515 void wxMediaBackendCommonBase::QueueEvent(wxEventType evtType)
516 {
517     wxMediaEvent theEvent(evtType, m_ctrl->GetId());
518     m_ctrl->GetEventHandler()->AddPendingEvent(theEvent);
519 }
520 
QueuePlayEvent()521 void wxMediaBackendCommonBase::QueuePlayEvent()
522 {
523     QueueEvent(wxEVT_MEDIA_STATECHANGED);
524     QueueEvent(wxEVT_MEDIA_PLAY);
525 }
526 
QueuePauseEvent()527 void wxMediaBackendCommonBase::QueuePauseEvent()
528 {
529     QueueEvent(wxEVT_MEDIA_STATECHANGED);
530     QueueEvent(wxEVT_MEDIA_PAUSE);
531 }
532 
QueueStopEvent()533 void wxMediaBackendCommonBase::QueueStopEvent()
534 {
535     QueueEvent(wxEVT_MEDIA_STATECHANGED);
536     QueueEvent(wxEVT_MEDIA_STOP);
537 }
538 
539 
540 //
541 // Force link default backends in -
542 // see http://wiki.wxwidgets.org/wiki.pl?RTTI
543 //
544 #include "wx/html/forcelnk.h"
545 
546 #ifdef __WXMSW__ // MSW has huge backends so we do it separately
547 FORCE_LINK(wxmediabackend_am)
548 FORCE_LINK(wxmediabackend_wmp10)
549 #else
550 FORCE_LINK(basewxmediabackends)
551 #endif
552 
553 #endif //wxUSE_MEDIACTRL
554