wxMediaCtrl API changes for 2.5.x/2.6
[wxWidgets.git] / samples / mediaplayer / mediaplayer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: mediaplayer.cpp
3 // Purpose: wxMediaCtrl sample
4 // Author: Ryan Norton
5 // Modified by:
6 // Created: 11/10/04
7 // RCS-ID: $Id$
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
13 // MediaPlayer
14 //
15 // This is a simple example of how to use all the funtionality of
16 // the wxMediaCtrl class in wxWidgets.
17 //
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.
21 //
22 // You can select one of the menu options, or move the slider around
23 // to manipulate what is playing.
24 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
25
26 // ============================================================================
27 // Definitions
28 // ============================================================================
29
30 // ----------------------------------------------------------------------------
31 // Pre-compiled header stuff
32 // ----------------------------------------------------------------------------
33
34 #include "wx/wxprec.h"
35
36 #ifdef __BORLANDC__
37 #pragma hdrstop
38 #endif
39
40 #ifndef WX_PRECOMP
41 #include "wx/wx.h"
42 #endif
43
44 // ----------------------------------------------------------------------------
45 // Headers
46 // ----------------------------------------------------------------------------
47
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
54
55 // ----------------------------------------------------------------------------
56 // Bail out if the user doesn't want one of the
57 // things we need
58 // ----------------------------------------------------------------------------
59
60 #if !wxUSE_GUI
61 #error "This is a GUI sample"
62 #endif
63
64 #if !wxUSE_MEDIACTRL || !wxUSE_MENUS || !wxUSE_SLIDER || !wxUSE_TIMER
65 #error "menus, slider, mediactrl, and timers must all enabled for this sample!"
66 #endif
67
68 // ============================================================================
69 // Declarations
70 // ============================================================================
71
72 // ----------------------------------------------------------------------------
73 // Enumurations
74 // ----------------------------------------------------------------------------
75
76 // IDs for the controls and the menu commands
77 enum
78 {
79 // menu items
80 wxID_LOOP = 1,
81 wxID_OPENFILE,
82 wxID_PLAY,
83 wxID_PAUSE,
84 // wxID_STOP, [built-in to wxWidgets]
85 // wxID_ABOUT, [built-in to wxWidgets]
86 // wxID_EXIT, [built-in to wxWidgets]
87
88 // id for our slider
89 wxID_SLIDER,
90
91 // id for our wxMediaCtrl
92 wxID_MEDIACTRL
93 };
94
95 // ----------------------------------------------------------------------------
96 // MyApp
97 // ----------------------------------------------------------------------------
98
99 class MyApp : public wxApp
100 {
101 public:
102 virtual bool OnInit();
103 };
104
105 // ----------------------------------------------------------------------------
106 // MyFrame
107 // ----------------------------------------------------------------------------
108
109 class MyFrame : public wxFrame
110 {
111 public:
112 // Ctor/Dtor
113 MyFrame(const wxString& title);
114 ~MyFrame();
115
116 // Menu event handlers
117 void OnQuit(wxCommandEvent& event);
118 void OnAbout(wxCommandEvent& event);
119 void OnLoop(wxCommandEvent& event);
120
121 void OnOpenFile(wxCommandEvent& event);
122 void OnOpenURL(wxCommandEvent& event);
123
124 void OnPlay(wxCommandEvent& event);
125 void OnPause(wxCommandEvent& event);
126 void OnStop(wxCommandEvent& event);
127
128 // Slider event handlers
129 void OnSeek(wxCommandEvent& event);
130
131 // Media event handlers
132 void OnMediaStop(wxMediaEvent& event);
133
134 private:
135 // Rebuild base status string (see Implementation)
136 void ResetStatus();
137
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
143
144 // So that mytimer can access MyFrame's members
145 friend class MyTimer;
146 };
147
148 // ----------------------------------------------------------------------------
149 // MyTimer
150 // ----------------------------------------------------------------------------
151
152 class MyTimer : public wxTimer
153 {
154 public:
155 //Ctor
156 MyTimer(MyFrame* frame) {m_frame = frame;}
157
158 //Called each time the timer's timeout expires
159 void Notify();
160
161 MyFrame* m_frame; //The MyFrame
162 };
163
164 // ============================================================================
165 //
166 // Implementation
167 //
168 // ============================================================================
169
170 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
171 //
172 // [Functions]
173 //
174 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
175
176 // ----------------------------------------------------------------------------
177 // wxGetMediaStateText
178 //
179 // Converts a wxMediaCtrl state into something useful that we can display
180 // to the user
181 // ----------------------------------------------------------------------------
182 const wxChar* wxGetMediaStateText(int nState)
183 {
184 switch(nState)
185 {
186 case wxMEDIASTATE_PLAYING:
187 return wxT("Playing");
188 case wxMEDIASTATE_STOPPED:
189 return wxT("Stopped");
190 ///case wxMEDIASTATE_PAUSED:
191 default:
192 return wxT("Paused");
193 }
194 }
195
196 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
197 //
198 // MyApp
199 //
200 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
201
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.
208 //
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 // ----------------------------------------------------------------------------
213 IMPLEMENT_APP(MyApp)
214
215
216 // ----------------------------------------------------------------------------
217 // MyApp::OnInit
218 //
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 // ----------------------------------------------------------------------------
223 bool MyApp::OnInit()
224 {
225 MyFrame *frame = new MyFrame(_T("MediaPlayer wxWidgets Sample"));
226 frame->Show(true);
227
228 return true;
229 }
230
231
232 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
233 //
234 // MyFrame
235 //
236 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
237
238 // ----------------------------------------------------------------------------
239 // MyFrame Constructor
240 //
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
248 MyFrame::MyFrame(const wxString& title)
249 : wxFrame(NULL, wxID_ANY, title)
250 {
251 //
252 // Create Menus
253 //
254 wxMenu *menuFile = new wxMenu;
255
256 wxMenu *helpMenu = new wxMenu;
257 helpMenu->Append(wxID_ABOUT,
258 _T("&About...\tF1"),
259 _T("Show about dialog"));
260
261 menuFile->Append(wxID_OPENFILE, _T("&Open File"), _T("Open a File"));
262 menuFile->AppendSeparator();
263 menuFile->Append(wxID_PLAY, _T("&Play"), _T("Resume playback"));
264 menuFile->Append(wxID_PAUSE, _T("P&ause"), _T("Pause playback"));
265 menuFile->Append(wxID_STOP, _T("&Stop"), _T("Stop playback"));
266 menuFile->AppendSeparator();
267 menuFile->AppendCheckItem(wxID_LOOP,
268 _T("&Loop"),
269 _T("Loop Selected Media"));
270 menuFile->AppendSeparator();
271 menuFile->Append(wxID_EXIT,
272 _T("E&xit\tAlt-X"),
273 _T("Quit this program"));
274
275 wxMenuBar *menuBar = new wxMenuBar();
276 menuBar->Append(menuFile, _T("&File"));
277 menuBar->Append(helpMenu, _T("&Help"));
278
279 SetMenuBar(menuBar);
280
281 //
282 // Create and attach the first/main sizer
283 //
284 wxBoxSizer* vertsizer = new wxBoxSizer(wxVERTICAL);
285 this->SetSizer(vertsizer);
286 this->SetAutoLayout(true);
287
288 //
289 // Create our media control
290 //
291 m_mediactrl = new wxMediaCtrl(this, wxID_MEDIACTRL);
292 vertsizer->Add(m_mediactrl, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
293
294 //
295 // Create our slider
296 //
297 m_slider = new wxSlider(this, wxID_SLIDER, 0, //init
298 0, //start
299 0, //end
300 wxDefaultPosition, wxDefaultSize,
301 wxSL_HORIZONTAL );
302 vertsizer->Add(m_slider, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND , 5);
303
304
305 //
306 // Create the second sizer which will position things
307 // vertically -
308 //
309 // -------Menu----------
310 // [m_mediactrl]
311 //
312 // [m_slider]
313 //
314 wxBoxSizer* horzsizer = new wxBoxSizer(wxHORIZONTAL);
315 vertsizer->Add(horzsizer, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
316
317 //
318 // Create our status bar
319 //
320 #if wxUSE_STATUSBAR
321 // create a status bar just for fun (by default with 1 pane only)
322 CreateStatusBar(1);
323 ResetStatus();
324 SetStatusText(m_basestatus);
325 #endif // wxUSE_STATUSBAR
326
327 //
328 // Connect events.
329 //
330 // There are two ways in wxWidgets to use events -
331 // Message Maps and Connections.
332 //
333 // Message Maps are implemented by putting
334 // DECLARE_MESSAGE_MAP in your wxEvtHandler-derived
335 // class you want to use for events, such as MyFrame.
336 //
337 // Then after your class declaration you put
338 // BEGIN_EVENT_TABLE(MyFrame, wxFrame)
339 // EVT_XXX(XXX)...
340 // END_EVENT_TABLE()
341 //
342 // Where MyFrame is the class with the DECLARE_MESSAGE_MAP
343 // in it. EVT_XXX(XXX) are each of your handlers, such
344 // as EVT_MENU for menu events and the XXX inside
345 // is the parameters to the event macro - in the case
346 // of EVT_MENU the menu id and then the function to call.
347 //
348 // However, with wxEvtHandler::Connect you can avoid a
349 // global message map for your class and those annoying
350 // macros. You can also change the context in which
351 // the call the handler (more later).
352 //
353 // The downside is that due to the limitation that
354 // wxWidgets doesn't use templates in certain areas,
355 // You have to triple-cast the event function.
356 //
357 // There are five parameters to wxEvtHandler::Connect -
358 //
359 // The first is the id of the instance whose events
360 // you want to handle - i.e. a menu id for menus,
361 // a control id for controls (wxControl::GetId())
362 // and so on.
363 //
364 // The second is the event id. This is the same
365 // as the message maps (EVT_MENU) except prefixed
366 // with "wx" (wxEVT_MENU).
367 //
368 // The third is the function handler for the event -
369 // You need to cast it to the specific event handler
370 // type, then to a wxEventFunction, then to a
371 // wxObjectEventFunction - I.E.
372 // (wxObjectEventFunction)(wxEventFunction)
373 // (wxCommandEventFunction) &MyFrame::MyHandler
374 //
375 // The fourth is an optional userdata param -
376 // this is of historical relevance only and is
377 // there only for backwards compatability.
378 //
379 // The fifth is the context in which to call the
380 // handler - by default (this param is optional)
381 // this. For example in your event handler
382 // if you were to call "this->MyFunc()"
383 // it would literally do this->MyFunc. However,
384 // if you were to pass myHandler as the fifth
385 // parameter, for instance, you would _really_
386 // be calling myHandler->MyFunc, even though
387 // the compiler doesn't really know it.
388 //
389
390 //
391 // Menu events
392 //
393 this->Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED,
394 (wxObjectEventFunction) (wxEventFunction)
395 (wxCommandEventFunction) &MyFrame::OnQuit);
396
397 this->Connect(wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED,
398 (wxObjectEventFunction) (wxEventFunction)
399 (wxCommandEventFunction) &MyFrame::OnAbout);
400
401 this->Connect(wxID_LOOP, wxEVT_COMMAND_MENU_SELECTED,
402 (wxObjectEventFunction) (wxEventFunction)
403 (wxCommandEventFunction) &MyFrame::OnLoop);
404
405 this->Connect(wxID_OPENFILE, wxEVT_COMMAND_MENU_SELECTED,
406 (wxObjectEventFunction) (wxEventFunction)
407 (wxCommandEventFunction) &MyFrame::OnOpenFile);
408
409 this->Connect(wxID_PLAY, wxEVT_COMMAND_MENU_SELECTED,
410 (wxObjectEventFunction) (wxEventFunction)
411 (wxCommandEventFunction) &MyFrame::OnPlay);
412
413 this->Connect(wxID_PAUSE, wxEVT_COMMAND_MENU_SELECTED,
414 (wxObjectEventFunction) (wxEventFunction)
415 (wxCommandEventFunction) &MyFrame::OnPause);
416
417 this->Connect(wxID_STOP, wxEVT_COMMAND_MENU_SELECTED,
418 (wxObjectEventFunction) (wxEventFunction)
419 (wxCommandEventFunction) &MyFrame::OnStop);
420
421
422 //
423 // Slider events
424 //
425 this->Connect(wxID_SLIDER, wxEVT_COMMAND_SLIDER_UPDATED,
426 (wxObjectEventFunction) (wxEventFunction)
427 (wxCommandEventFunction) &MyFrame::OnSeek);
428
429 //
430 // Media Control events
431 //
432 this->Connect(wxID_MEDIACTRL, wxEVT_MEDIA_STOP,
433 (wxObjectEventFunction) (wxEventFunction)
434 (wxMediaEventFunction) &MyFrame::OnMediaStop);
435
436 //
437 // End of Events
438 //
439
440 //
441 // Set our loop counter to 0
442 //
443 m_nLoops = 0;
444
445 //
446 // Create a timer to update our status bar
447 //
448 m_timer = new MyTimer(this);
449 m_timer->Start(100);
450 }
451
452 // ----------------------------------------------------------------------------
453 // MyFrame Destructor
454 //
455 // 1) Deletes child objects implicitly
456 // 2) Delete our timer explicitly
457 // ----------------------------------------------------------------------------
458 MyFrame::~MyFrame()
459 {
460 delete m_timer;
461 }
462
463 // ----------------------------------------------------------------------------
464 // MyFrame::ResetStatus
465 //
466 // Here we just make a simple status string with some useful info about
467 // the media that we won't change later - such as the length of the media.
468 //
469 // We then append some other info that changes in MyTimer::Notify, then
470 // set the status bar to this text.
471 //
472 // In real applications, you'd want to find a better way to do this,
473 // such as static text controls (wxStaticText).
474 //
475 // We display info here in seconds (wxMediaCtrl uses milliseconds - that's why
476 // we divide by 1000).
477 //
478 // We also reset our loop counter here.
479 // ----------------------------------------------------------------------------
480 void MyFrame::ResetStatus()
481 {
482 m_basestatus = wxString::Format(_T("Size(x,y):%i,%i ")
483 _T("Length(Seconds):%u Speed:%1.1fx"),
484 m_mediactrl->GetBestSize().x,
485 m_mediactrl->GetBestSize().y,
486 (unsigned)((m_mediactrl->Length() / 1000)),
487 m_mediactrl->GetPlaybackRate()
488 );
489
490 m_slider->SetRange(0, (m_mediactrl->Length() / 1000));
491
492 m_nLoops = 0;
493 }
494
495 // ----------------------------------------------------------------------------
496 // MyFrame::OnQuit
497 //
498 // Called from file->quit.
499 // Closes this application.
500 // ----------------------------------------------------------------------------
501 void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
502 {
503 // true is to force the frame to close
504 Close(true);
505 }
506
507 // ----------------------------------------------------------------------------
508 // MyFrame::OnAbout
509 //
510 // Called from help->about.
511 // Gets some info about this application.
512 // ----------------------------------------------------------------------------
513 void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
514 {
515 wxString msg;
516 msg.Printf( _T("This is a test of wxMediaCtrl.\n")
517 _T("Welcome to %s"), wxVERSION_STRING);
518
519 wxMessageBox(msg, _T("About wxMediaCtrl test"), wxOK | wxICON_INFORMATION, this);
520 }
521
522 // ----------------------------------------------------------------------------
523 // MyFrame::OnLoop
524 //
525 // Called from file->loop.
526 // Changes the state of whether we want to loop or not.
527 // ----------------------------------------------------------------------------
528 void MyFrame::OnLoop(wxCommandEvent& WXUNUSED(event))
529 {
530 m_mediactrl->Loop( !m_mediactrl->IsLooped() );
531 }
532
533 // ----------------------------------------------------------------------------
534 // MyFrame::OnOpenFile
535 //
536 // Called from file->openfile.
537 // Opens and plays a media file
538 // ----------------------------------------------------------------------------
539 void MyFrame::OnOpenFile(wxCommandEvent& WXUNUSED(event))
540 {
541 wxFileDialog fd(this);
542
543 if(fd.ShowModal() == wxID_OK)
544 {
545 if( !m_mediactrl->Load(fd.GetPath()) )
546 wxMessageBox(wxT("Couldn't load file!"));
547
548 if( !m_mediactrl->Play() )
549 wxMessageBox(wxT("Couldn't play movie!"));
550
551 ResetStatus();
552 }
553 }
554
555 // ----------------------------------------------------------------------------
556 // MyFrame::OnPlay
557 //
558 // Called from file->play.
559 // Resumes the media if it is paused or stopped.
560 // ----------------------------------------------------------------------------
561 void MyFrame::OnPlay(wxCommandEvent& WXUNUSED(event))
562 {
563 if( !m_mediactrl->Play() )
564 wxMessageBox(wxT("Couldn't play movie!"));
565 }
566
567 // ----------------------------------------------------------------------------
568 // MyFrame::OnPause
569 //
570 // Called from file->pause.
571 // Pauses the media in-place.
572 // ----------------------------------------------------------------------------
573 void MyFrame::OnPause(wxCommandEvent& WXUNUSED(event))
574 {
575 if( !m_mediactrl->Pause() )
576 wxMessageBox(wxT("Couldn't pause movie!"));
577 }
578
579 // ----------------------------------------------------------------------------
580 // MyFrame::OnStop
581 //
582 // Called from file->stop.
583 // Where it stops depends on whether you can seek in the
584 // media control or not - if you can it stops and seeks to the beginning,
585 // otherwise it will appear to be at the end - but it will start over again
586 // when Play() is called
587 // ----------------------------------------------------------------------------
588 void MyFrame::OnStop(wxCommandEvent& WXUNUSED(event))
589 {
590 if( !m_mediactrl->Stop() )
591 wxMessageBox(wxT("Couldn't stop movie!"));
592 }
593
594 // ----------------------------------------------------------------------------
595 // MyFrame::OnSeek
596 //
597 // Called from file->seek.
598 // Called when the user moves the slider -
599 // seeks to a position within the media
600 // ----------------------------------------------------------------------------
601 void MyFrame::OnSeek(wxCommandEvent& WXUNUSED(event))
602 {
603 if( m_mediactrl->Seek( m_slider->GetValue() * 1000 ) == wxInvalidOffset )
604 wxMessageBox(wxT("Couldn't seek in movie!"));
605 }
606
607 // ----------------------------------------------------------------------------
608 // MyFrame::OnMediaStop
609 //
610 // Called when the media is about to stop playing.
611 // Here we just increase our loop counter
612 // ----------------------------------------------------------------------------
613 void MyFrame::OnMediaStop(wxMediaEvent& WXUNUSED(event))
614 {
615 ++m_nLoops;
616 }
617
618 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
619 //
620 // MyTimer
621 //
622 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
623
624 // ----------------------------------------------------------------------------
625 // MyTimer::Notify
626 //
627 // 1) Update our slider with the position were are in in the media
628 // 2) Update our status bar with the base text from MyFrame::ResetStatus,
629 // append some non-static (changing) info to it, then set the
630 // status bar text to that result
631 // ----------------------------------------------------------------------------
632 void MyTimer::Notify()
633 {
634 long lPosition = (m_frame->m_mediactrl->Tell() / 1000);
635 m_frame->m_slider->SetValue(lPosition);
636
637 #if wxUSE_STATUSBAR
638 m_frame->SetStatusText(wxString::Format(
639 _T("%s Pos:%u State:%s Loops:%i"),
640 m_frame->m_basestatus.c_str(),
641 (unsigned int)lPosition,
642 wxGetMediaStateText(m_frame->m_mediactrl->GetState()),
643 m_frame->m_nLoops
644 )
645 );
646 #endif
647 }
648
649 //
650 // End of MediaPlayer sample
651 //