1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: mediaplayer.cpp
3 // Purpose: wxMediaCtrl sample
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
15 // This is a simple example of how to use all the funtionality of
16 // the wxMediaCtrl class in wxWidgets.
18 // To use this sample, simply select Open File from the file menu,
19 // select the file you want to play - and MediaPlayer will play the file,
20 // showing video if neccessary.
22 // You can select one of the menu options, or move the slider around
23 // to manipulate what is playing.
24 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
26 // ============================================================================
28 // ============================================================================
30 // ----------------------------------------------------------------------------
31 // Pre-compiled header stuff
32 // ----------------------------------------------------------------------------
34 #include "wx/wxprec.h"
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 #include "wx/mediactrl.h" //for wxMediaCtrl
49 #include "wx/filedlg.h" //for opening files from OpenFile
50 #include "wx/slider.h" //for a slider for seeking within media
51 #include "wx/sizer.h" //for positioning controls/wxBoxSizer
52 #include "wx/timer.h" //timer for updating status bar
53 #include "wx/textdlg.h" //for getting user text from OpenURL
55 // ----------------------------------------------------------------------------
56 // Bail out if the user doesn't want one of the
58 // ----------------------------------------------------------------------------
61 #error "This is a GUI sample"
64 #if !wxUSE_MEDIACTRL || !wxUSE_MENUS || !wxUSE_SLIDER || !wxUSE_TIMER
65 #error "menus, slider, mediactrl, and timers must all enabled for this sample!"
68 // ============================================================================
70 // ============================================================================
72 // ----------------------------------------------------------------------------
74 // ----------------------------------------------------------------------------
76 // IDs for the controls and the menu commands
84 // wxID_STOP, [built-in to wxWidgets]
85 // wxID_ABOUT, [built-in to wxWidgets]
86 // wxID_EXIT, [built-in to wxWidgets]
91 // id for our wxMediaCtrl
95 // ----------------------------------------------------------------------------
97 // ----------------------------------------------------------------------------
99 class MyApp
: public wxApp
102 virtual bool OnInit();
105 // ----------------------------------------------------------------------------
107 // ----------------------------------------------------------------------------
109 class MyFrame
: public wxFrame
113 MyFrame(const wxString
& title
);
116 // Menu event handlers
117 void OnQuit(wxCommandEvent
& event
);
118 void OnAbout(wxCommandEvent
& event
);
119 void OnLoop(wxCommandEvent
& event
);
121 void OnOpenFile(wxCommandEvent
& event
);
122 void OnOpenURL(wxCommandEvent
& event
);
124 void OnPlay(wxCommandEvent
& event
);
125 void OnPause(wxCommandEvent
& event
);
126 void OnStop(wxCommandEvent
& event
);
128 // Slider event handlers
129 void OnSeek(wxCommandEvent
& event
);
131 // Media event handlers
132 void OnMediaStop(wxMediaEvent
& event
);
135 // Rebuild base status string (see Implementation)
138 wxMediaCtrl
* m_mediactrl
; //Our media control
139 wxSlider
* m_slider
; //The slider below our media control
140 class MyTimer
* m_timer
; //Timer to write info to status bar
141 wxString m_basestatus
; //Base status string (see ResetStatus())
142 int m_nLoops
; //Counter, incremented each time media loops
144 // So that mytimer can access MyFrame's members
145 friend class MyTimer
;
148 // ----------------------------------------------------------------------------
150 // ----------------------------------------------------------------------------
152 class MyTimer
: public wxTimer
156 MyTimer(MyFrame
* frame
) {m_frame
= frame
;}
158 //Called each time the timer's timeout expires
161 MyFrame
* m_frame
; //The MyFrame
164 // ============================================================================
168 // ============================================================================
170 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
174 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
176 // ----------------------------------------------------------------------------
177 // wxGetMediaStateText
179 // Converts a wxMediaCtrl state into something useful that we can display
181 // ----------------------------------------------------------------------------
182 const wxChar
* wxGetMediaStateText(int nState
)
186 case wxMEDIASTATE_PLAYING
:
187 return wxT("Playing");
188 case wxMEDIASTATE_STOPPED
:
189 return wxT("Stopped");
190 ///case wxMEDIASTATE_PAUSED:
192 return wxT("Paused");
196 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
200 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
202 // ----------------------------------------------------------------------------
203 // This sets up this wxApp as the global wxApp that gui calls in wxWidgets
204 // use. For example, if you were to be in windows and use a file dialog,
205 // wxWidgets would use wxTheApp->GetHInstance() which would get the instance
206 // handle of the application. These routines in wx _DO NOT_ check to see if
207 // the wxApp exists, and thus will crash the application if you try it.
209 // IMPLEMENT_APP does this, and also implements the platform-specific entry
210 // routine, such as main or WinMain(). Use IMPLEMENT_APP_NO_MAIN if you do
211 // not desire this behavior.
212 // ----------------------------------------------------------------------------
216 // ----------------------------------------------------------------------------
219 // Where execution starts - akin to a main or WinMain.
220 // 1) Create the frame and show it to the user
221 // 2) return true specifying that we want execution to continue past OnInit
222 // ----------------------------------------------------------------------------
225 MyFrame
*frame
= new MyFrame(_T("MediaPlayer wxWidgets Sample"));
232 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
236 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
238 // ----------------------------------------------------------------------------
239 // MyFrame Constructor
241 // 1) Create our menus
242 // 2) Create our controls and add them to some sizers
243 // 3) Create our status bar
244 // 4) Connect our events
245 // 5) Start our timer
246 // ----------------------------------------------------------------------------
247 MyFrame::MyFrame(const wxString
& title
)
248 : wxFrame(NULL
, wxID_ANY
, title
)
253 wxMenu
*menuFile
= new wxMenu
;
255 wxMenu
*helpMenu
= new wxMenu
;
256 helpMenu
->Append(wxID_ABOUT
,
258 _T("Show about dialog"));
260 menuFile
->Append(wxID_OPENFILE
, _T("&Open File"), _T("Open a File"));
261 menuFile
->AppendSeparator();
262 menuFile
->Append(wxID_PLAY
, _T("&Play"), _T("Resume playback"));
263 menuFile
->Append(wxID_PAUSE
, _T("P&ause"), _T("Pause playback"));
264 menuFile
->Append(wxID_STOP
, _T("&Stop"), _T("Stop playback"));
265 menuFile
->AppendSeparator();
266 menuFile
->AppendCheckItem(wxID_LOOP
,
268 _T("Loop Selected Media"));
269 menuFile
->AppendSeparator();
270 menuFile
->Append(wxID_EXIT
,
272 _T("Quit this program"));
274 wxMenuBar
*menuBar
= new wxMenuBar();
275 menuBar
->Append(menuFile
, _T("&File"));
276 menuBar
->Append(helpMenu
, _T("&Help"));
281 // Create and attach the first/main sizer
283 wxBoxSizer
* vertsizer
= new wxBoxSizer(wxVERTICAL
);
284 this->SetSizer(vertsizer
);
285 this->SetAutoLayout(true);
288 // Create our media control
290 m_mediactrl
= new wxMediaCtrl(this, wxID_MEDIACTRL
);
291 vertsizer
->Add(m_mediactrl
, 0, wxALIGN_CENTER_HORIZONTAL
|wxALL
, 5);
296 m_slider
= new wxSlider(this, wxID_SLIDER
, 0, //init
299 wxDefaultPosition
, wxDefaultSize
,
301 vertsizer
->Add(m_slider
, 0, wxALIGN_CENTER_HORIZONTAL
|wxALL
|wxEXPAND
, 5);
305 // Create the second sizer which will position things
308 // -------Menu----------
313 wxBoxSizer
* horzsizer
= new wxBoxSizer(wxHORIZONTAL
);
314 vertsizer
->Add(horzsizer
, 0, wxALIGN_CENTER_HORIZONTAL
|wxALL
, 5);
317 // Create our status bar
320 // create a status bar just for fun (by default with 1 pane only)
323 SetStatusText(m_basestatus
);
324 #endif // wxUSE_STATUSBAR
329 // There are two ways in wxWidgets to use events -
330 // Message Maps and Connections.
332 // Message Maps are implemented by putting
333 // DECLARE_MESSAGE_MAP in your wxEvtHandler-derived
334 // class you want to use for events, such as MyFrame.
336 // Then after your class declaration you put
337 // BEGIN_EVENT_TABLE(MyFrame, wxFrame)
341 // Where MyFrame is the class with the DECLARE_MESSAGE_MAP
342 // in it. EVT_XXX(XXX) are each of your handlers, such
343 // as EVT_MENU for menu events and the XXX inside
344 // is the parameters to the event macro - in the case
345 // of EVT_MENU the menu id and then the function to call.
347 // However, with wxEvtHandler::Connect you can avoid a
348 // global message map for your class and those annoying
349 // macros. You can also change the context in which
350 // the call the handler (more later).
352 // The downside is that due to the limitation that
353 // wxWidgets doesn't use templates in certain areas,
354 // You have to triple-cast the event function.
356 // There are five parameters to wxEvtHandler::Connect -
358 // The first is the id of the instance whose events
359 // you want to handle - i.e. a menu id for menus,
360 // a control id for controls (wxControl::GetId())
363 // The second is the event id. This is the same
364 // as the message maps (EVT_MENU) except prefixed
365 // with "wx" (wxEVT_MENU).
367 // The third is the function handler for the event -
368 // You need to cast it to the specific event handler
369 // type, then to a wxEventFunction, then to a
370 // wxObjectEventFunction - I.E.
371 // (wxObjectEventFunction)(wxEventFunction)
372 // (wxCommandEventFunction) &MyFrame::MyHandler
374 // The fourth is an optional userdata param -
375 // this is of historical relevance only and is
376 // there only for backwards compatability.
378 // The fifth is the context in which to call the
379 // handler - by default (this param is optional)
380 // this. For example in your event handler
381 // if you were to call "this->MyFunc()"
382 // it would literally do this->MyFunc. However,
383 // if you were to pass myHandler as the fifth
384 // parameter, for instance, you would _really_
385 // be calling myHandler->MyFunc, even though
386 // the compiler doesn't really know it.
392 this->Connect(wxID_EXIT
, wxEVT_COMMAND_MENU_SELECTED
,
393 (wxObjectEventFunction
) (wxEventFunction
)
394 (wxCommandEventFunction
) &MyFrame::OnQuit
);
396 this->Connect(wxID_ABOUT
, wxEVT_COMMAND_MENU_SELECTED
,
397 (wxObjectEventFunction
) (wxEventFunction
)
398 (wxCommandEventFunction
) &MyFrame::OnAbout
);
400 this->Connect(wxID_LOOP
, wxEVT_COMMAND_MENU_SELECTED
,
401 (wxObjectEventFunction
) (wxEventFunction
)
402 (wxCommandEventFunction
) &MyFrame::OnLoop
);
404 this->Connect(wxID_OPENFILE
, wxEVT_COMMAND_MENU_SELECTED
,
405 (wxObjectEventFunction
) (wxEventFunction
)
406 (wxCommandEventFunction
) &MyFrame::OnOpenFile
);
408 this->Connect(wxID_PLAY
, wxEVT_COMMAND_MENU_SELECTED
,
409 (wxObjectEventFunction
) (wxEventFunction
)
410 (wxCommandEventFunction
) &MyFrame::OnPlay
);
412 this->Connect(wxID_PAUSE
, wxEVT_COMMAND_MENU_SELECTED
,
413 (wxObjectEventFunction
) (wxEventFunction
)
414 (wxCommandEventFunction
) &MyFrame::OnPause
);
416 this->Connect(wxID_STOP
, wxEVT_COMMAND_MENU_SELECTED
,
417 (wxObjectEventFunction
) (wxEventFunction
)
418 (wxCommandEventFunction
) &MyFrame::OnStop
);
424 this->Connect(wxID_SLIDER
, wxEVT_COMMAND_SLIDER_UPDATED
,
425 (wxObjectEventFunction
) (wxEventFunction
)
426 (wxCommandEventFunction
) &MyFrame::OnSeek
);
429 // Media Control events
431 this->Connect(wxID_MEDIACTRL
, wxEVT_MEDIA_STOP
,
432 (wxObjectEventFunction
) (wxEventFunction
)
433 (wxCommandEventFunction
) &MyFrame::OnMediaStop
);
440 // Set our loop counter to 0
445 // Create a timer to update our status bar
447 m_timer
= new MyTimer(this);
451 // ----------------------------------------------------------------------------
452 // MyFrame Destructor
454 // 1) Deletes child objects implicitly
455 // 2) Delete our timer explicitly
456 // ----------------------------------------------------------------------------
462 // ----------------------------------------------------------------------------
463 // MyFrame::ResetStatus
465 // Here we just make a simple status string with some useful info about
466 // the media that we won't change later - such as the length of the media.
468 // We then append some other info that changes in MyTimer::Notify, then
469 // set the status bar to this text.
471 // In real applications, you'd want to find a better way to do this,
472 // such as static text controls (wxStaticText).
474 // We display info here in seconds (wxMediaCtrl uses milliseconds - that's why
475 // we divide by 1000).
477 // We also reset our loop counter here.
478 // ----------------------------------------------------------------------------
479 void MyFrame::ResetStatus()
481 m_basestatus
= wxString::Format(_T("Size(x,y):%i,%i ")
482 _T("Length(Seconds):%u Speed:%1.1fx"),
483 m_mediactrl
->GetBestSize().x
,
484 m_mediactrl
->GetBestSize().y
,
485 (unsigned)((m_mediactrl
->GetDuration() / 1000).ToLong()),
486 m_mediactrl
->GetPlaybackRate()
489 m_slider
->SetRange(0, (m_mediactrl
->GetDuration() / 1000).ToLong());
494 // ----------------------------------------------------------------------------
497 // Called from file->quit.
498 // Closes this application.
499 // ----------------------------------------------------------------------------
500 void MyFrame::OnQuit(wxCommandEvent
& WXUNUSED(event
))
502 // true is to force the frame to close
506 // ----------------------------------------------------------------------------
509 // Called from help->about.
510 // Gets some info about this application.
511 // ----------------------------------------------------------------------------
512 void MyFrame::OnAbout(wxCommandEvent
& WXUNUSED(event
))
515 msg
.Printf( _T("This is a test of wxMediaCtrl.\n")
516 _T("Welcome to %s"), wxVERSION_STRING
);
518 wxMessageBox(msg
, _T("About wxMediaCtrl test"), wxOK
| wxICON_INFORMATION
, this);
521 // ----------------------------------------------------------------------------
524 // Called from file->loop.
525 // Changes the state of whether we want to loop or not.
526 // ----------------------------------------------------------------------------
527 void MyFrame::OnLoop(wxCommandEvent
& WXUNUSED(event
))
529 m_mediactrl
->Loop( !m_mediactrl
->IsLooped() );
532 // ----------------------------------------------------------------------------
533 // MyFrame::OnOpenFile
535 // Called from file->openfile.
536 // Opens and plays a media file
537 // ----------------------------------------------------------------------------
538 void MyFrame::OnOpenFile(wxCommandEvent
& WXUNUSED(event
))
540 wxFileDialog
fd(this);
542 if(fd
.ShowModal() == wxID_OK
)
544 if( !m_mediactrl
->Load(fd
.GetPath()) )
545 wxMessageBox(wxT("Couldn't load file!"));
547 if( !m_mediactrl
->Play() )
548 wxMessageBox(wxT("Couldn't play movie!"));
554 // ----------------------------------------------------------------------------
557 // Called from file->play.
558 // Resumes the media if it is paused or stopped.
559 // ----------------------------------------------------------------------------
560 void MyFrame::OnPlay(wxCommandEvent
& WXUNUSED(event
))
562 if( !m_mediactrl
->Play() )
563 wxMessageBox(wxT("Couldn't play movie!"));
566 // ----------------------------------------------------------------------------
569 // Called from file->pause.
570 // Pauses the media in-place.
571 // ----------------------------------------------------------------------------
572 void MyFrame::OnPause(wxCommandEvent
& WXUNUSED(event
))
574 if( !m_mediactrl
->Pause() )
575 wxMessageBox(wxT("Couldn't pause movie!"));
578 // ----------------------------------------------------------------------------
581 // Called from file->stop.
582 // Where it stops depends on whether you can seek in the
583 // media control or not - if you can it stops and seeks to the beginning,
584 // otherwise it will appear to be at the end - but it will start over again
585 // when Play() is called
586 // ----------------------------------------------------------------------------
587 void MyFrame::OnStop(wxCommandEvent
& WXUNUSED(event
))
589 if( !m_mediactrl
->Stop() )
590 wxMessageBox(wxT("Couldn't stop movie!"));
593 // ----------------------------------------------------------------------------
596 // Called from file->seek.
597 // Called when the user moves the slider -
598 // seeks to a position within the media
599 // ----------------------------------------------------------------------------
600 void MyFrame::OnSeek(wxCommandEvent
& WXUNUSED(event
))
602 if( !m_mediactrl
->SetPosition( m_slider
->GetValue() * 1000 ) )
603 wxMessageBox(wxT("Couldn't seek in movie!"));
606 // ----------------------------------------------------------------------------
607 // MyFrame::OnMediaStop
609 // Called when the media is about to stop playing.
610 // Here we just increase our loop counter
611 // ----------------------------------------------------------------------------
612 void MyFrame::OnMediaStop(wxMediaEvent
& WXUNUSED(event
))
617 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
621 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
623 // ----------------------------------------------------------------------------
626 // 1) Update our slider with the position were are in in the media
627 // 2) Update our status bar with the base text from MyFrame::ResetStatus,
628 // append some non-static (changing) info to it, then set the
629 // status bar text to that result
630 // ----------------------------------------------------------------------------
631 void MyTimer::Notify()
633 long lPosition
= (m_frame
->m_mediactrl
->GetPosition() / 1000).ToLong();
634 m_frame
->m_slider
->SetValue(lPosition
);
637 m_frame
->SetStatusText(wxString::Format(
638 _T("%s Pos:%u State:%s Loops:%i"),
639 m_frame
->m_basestatus
.c_str(),
640 (unsigned int)lPosition
,
641 wxGetMediaStateText(m_frame
->m_mediactrl
->GetState()),
649 // End of MediaPlayer sample