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
54 #include "wx/notebook.h" //for wxNotebook and putting movies in pages
56 // ----------------------------------------------------------------------------
57 // Bail out if the user doesn't want one of the
59 // ----------------------------------------------------------------------------
62 #error "This is a GUI sample"
65 #if !wxUSE_MEDIACTRL || !wxUSE_MENUS || !wxUSE_SLIDER || !wxUSE_TIMER || !wxUSE_NOTEBOOK
66 #error "menus, slider, mediactrl, notebook, and timers must all be enabled for this sample!"
70 if (!m_notebook || !m_notebook->GetCurrentPage()) return; \
71 wxMediaCtrl* m_mediactrl = ((MyNotebookPage*)m_notebook->GetCurrentPage())->m_mediactrl; \
72 wxSlider* m_slider = ((MyNotebookPage*)m_notebook->GetCurrentPage())->m_slider;
74 // ============================================================================
76 // ============================================================================
78 // ----------------------------------------------------------------------------
80 // ----------------------------------------------------------------------------
82 // IDs for the controls and the menu commands
90 // wxID_CLOSE, [built-in to wxWidgets]
91 // wxID_STOP, [built-in to wxWidgets]
92 // wxID_ABOUT, [built-in to wxWidgets]
93 // wxID_EXIT, [built-in to wxWidgets]
99 // id for our wxMediaCtrl
103 // ----------------------------------------------------------------------------
105 // ----------------------------------------------------------------------------
107 class MyApp
: public wxApp
110 virtual bool OnInit();
113 // ----------------------------------------------------------------------------
115 // ----------------------------------------------------------------------------
117 class MyFrame
: public wxFrame
121 MyFrame(const wxString
& title
);
124 // Menu event handlers
125 void OnQuit(wxCommandEvent
& event
);
126 void OnAbout(wxCommandEvent
& event
);
127 void OnLoop(wxCommandEvent
& event
);
129 void OnOpenFile(wxCommandEvent
& event
);
130 void OnOpenURL(wxCommandEvent
& event
);
132 void OnPlay(wxCommandEvent
& event
);
133 void OnPause(wxCommandEvent
& event
);
134 void OnStop(wxCommandEvent
& event
);
135 void OnClose(wxCommandEvent
& event
);
137 // Slider event handlers
138 void OnSeek(wxCommandEvent
& event
);
140 // Media event handlers
141 void OnMediaStop(wxMediaEvent
& event
);
143 void OnPageChange(wxNotebookEvent
& event
);
144 void OnClosePage(wxCommandEvent
& event
);
147 // Rebuild base status string (see Implementation)
150 class MyTimer
* m_timer
; //Timer to write info to status bar
151 wxString m_basestatus
; //Base status string (see ResetStatus())
152 wxNotebook
* m_notebook
;
154 // So that mytimer can access MyFrame's members
155 friend class MyTimer
;
158 class MyNotebookPage
: public wxPanel
160 MyNotebookPage(wxNotebook
* boook
);
164 friend class MyFrame
;
165 wxMediaCtrl
* m_mediactrl
; //Our media control
166 wxSlider
* m_slider
; //The slider below our media control
169 // ----------------------------------------------------------------------------
171 // ----------------------------------------------------------------------------
173 class MyTimer
: public wxTimer
177 MyTimer(MyFrame
* frame
) {m_frame
= frame
;}
179 //Called each time the timer's timeout expires
182 MyFrame
* m_frame
; //The MyFrame
185 // ============================================================================
189 // ============================================================================
191 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
195 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
197 // ----------------------------------------------------------------------------
198 // wxGetMediaStateText
200 // Converts a wxMediaCtrl state into something useful that we can display
202 // ----------------------------------------------------------------------------
203 const wxChar
* wxGetMediaStateText(int nState
)
207 case wxMEDIASTATE_PLAYING
:
208 return wxT("Playing");
209 case wxMEDIASTATE_STOPPED
:
210 return wxT("Stopped");
211 ///case wxMEDIASTATE_PAUSED:
213 return wxT("Paused");
217 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
221 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
223 // ----------------------------------------------------------------------------
224 // This sets up this wxApp as the global wxApp that gui calls in wxWidgets
225 // use. For example, if you were to be in windows and use a file dialog,
226 // wxWidgets would use wxTheApp->GetHInstance() which would get the instance
227 // handle of the application. These routines in wx _DO NOT_ check to see if
228 // the wxApp exists, and thus will crash the application if you try it.
230 // IMPLEMENT_APP does this, and also implements the platform-specific entry
231 // routine, such as main or WinMain(). Use IMPLEMENT_APP_NO_MAIN if you do
232 // not desire this behavior.
233 // ----------------------------------------------------------------------------
237 // ----------------------------------------------------------------------------
240 // Where execution starts - akin to a main or WinMain.
241 // 1) Create the frame and show it to the user
242 // 2) return true specifying that we want execution to continue past OnInit
243 // ----------------------------------------------------------------------------
246 MyFrame
*frame
= new MyFrame(_T("MediaPlayer wxWidgets Sample"));
253 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
257 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
259 // ----------------------------------------------------------------------------
260 // MyFrame Constructor
262 // 1) Create our menus
263 // 2) Create our controls and add them to some sizers
264 // 3) Create our status bar
265 // 4) Connect our events
266 // 5) Start our timer
267 // ----------------------------------------------------------------------------
269 MyFrame
::MyFrame(const wxString
& title
)
270 : wxFrame(NULL
, wxID_ANY
, title
)
275 wxMenu
*menuFile
= new wxMenu
;
277 wxMenu
*helpMenu
= new wxMenu
;
278 helpMenu
->Append(wxID_ABOUT
,
280 _T("Show about dialog"));
282 menuFile
->Append(wxID_OPENFILE
, _T("&Open File"), _T("Open a File"));
283 menuFile
->AppendSeparator();
284 menuFile
->Append(wxID_PLAY
, _T("&Play"), _T("Resume playback"));
285 menuFile
->Append(wxID_PAUSE
, _T("P&ause"), _T("Pause playback"));
286 menuFile
->Append(wxID_STOP
, _T("&Stop"), _T("Stop playback"));
287 menuFile
->AppendSeparator();
288 menuFile
->Append(wxID_CLOSE
, _T("&Close"), _T("Close current notebook page"));
289 menuFile
->AppendSeparator();
290 menuFile
->AppendCheckItem(wxID_LOOP
,
292 _T("Loop Selected Media"));
293 menuFile
->AppendSeparator();
294 menuFile
->Append(wxID_EXIT
,
296 _T("Quit this program"));
298 wxMenuBar
*menuBar
= new wxMenuBar();
299 menuBar
->Append(menuFile
, _T("&File"));
300 menuBar
->Append(helpMenu
, _T("&Help"));
304 m_notebook
= new wxNotebook(this, wxID_NOTEBOOK
);
307 // Create our status bar
310 // create a status bar just for fun (by default with 1 pane only)
313 SetStatusText(m_basestatus
);
314 #endif // wxUSE_STATUSBAR
319 // There are two ways in wxWidgets to use events -
320 // Message Maps and Connections.
322 // Message Maps are implemented by putting
323 // DECLARE_MESSAGE_MAP in your wxEvtHandler-derived
324 // class you want to use for events, such as MyFrame.
326 // Then after your class declaration you put
327 // BEGIN_EVENT_TABLE(MyFrame, wxFrame)
331 // Where MyFrame is the class with the DECLARE_MESSAGE_MAP
332 // in it. EVT_XXX(XXX) are each of your handlers, such
333 // as EVT_MENU for menu events and the XXX inside
334 // is the parameters to the event macro - in the case
335 // of EVT_MENU the menu id and then the function to call.
337 // However, with wxEvtHandler::Connect you can avoid a
338 // global message map for your class and those annoying
339 // macros. You can also change the context in which
340 // the call the handler (more later).
342 // The downside is that due to the limitation that
343 // wxWidgets doesn't use templates in certain areas,
344 // You have to triple-cast the event function.
346 // There are five parameters to wxEvtHandler::Connect -
348 // The first is the id of the instance whose events
349 // you want to handle - i.e. a menu id for menus,
350 // a control id for controls (wxControl::GetId())
353 // The second is the event id. This is the same
354 // as the message maps (EVT_MENU) except prefixed
355 // with "wx" (wxEVT_MENU).
357 // The third is the function handler for the event -
358 // You need to cast it to the specific event handler
359 // type, then to a wxEventFunction, then to a
360 // wxObjectEventFunction - I.E.
361 // (wxObjectEventFunction)(wxEventFunction)
362 // (wxCommandEventFunction) &MyFrame::MyHandler
364 // The fourth is an optional userdata param -
365 // this is of historical relevance only and is
366 // there only for backwards compatability.
368 // The fifth is the context in which to call the
369 // handler - by default (this param is optional)
370 // this. For example in your event handler
371 // if you were to call "this->MyFunc()"
372 // it would literally do this->MyFunc. However,
373 // if you were to pass myHandler as the fifth
374 // parameter, for instance, you would _really_
375 // be calling myHandler->MyFunc, even though
376 // the compiler doesn't really know it.
382 this->Connect(wxID_EXIT
, wxEVT_COMMAND_MENU_SELECTED
,
383 (wxObjectEventFunction
) (wxEventFunction
)
384 (wxCommandEventFunction
) &MyFrame
::OnQuit
);
386 this->Connect(wxID_ABOUT
, wxEVT_COMMAND_MENU_SELECTED
,
387 (wxObjectEventFunction
) (wxEventFunction
)
388 (wxCommandEventFunction
) &MyFrame
::OnAbout
);
390 this->Connect(wxID_LOOP
, wxEVT_COMMAND_MENU_SELECTED
,
391 (wxObjectEventFunction
) (wxEventFunction
)
392 (wxCommandEventFunction
) &MyFrame
::OnLoop
);
394 this->Connect(wxID_OPENFILE
, wxEVT_COMMAND_MENU_SELECTED
,
395 (wxObjectEventFunction
) (wxEventFunction
)
396 (wxCommandEventFunction
) &MyFrame
::OnOpenFile
);
398 this->Connect(wxID_PLAY
, wxEVT_COMMAND_MENU_SELECTED
,
399 (wxObjectEventFunction
) (wxEventFunction
)
400 (wxCommandEventFunction
) &MyFrame
::OnPlay
);
402 this->Connect(wxID_PAUSE
, wxEVT_COMMAND_MENU_SELECTED
,
403 (wxObjectEventFunction
) (wxEventFunction
)
404 (wxCommandEventFunction
) &MyFrame
::OnPause
);
406 this->Connect(wxID_STOP
, wxEVT_COMMAND_MENU_SELECTED
,
407 (wxObjectEventFunction
) (wxEventFunction
)
408 (wxCommandEventFunction
) &MyFrame
::OnStop
);
410 this->Connect(wxID_CLOSE
, wxEVT_COMMAND_MENU_SELECTED
,
411 (wxObjectEventFunction
) (wxEventFunction
)
412 (wxCommandEventFunction
) &MyFrame
::OnClosePage
);
417 this->Connect(wxID_SLIDER
, wxEVT_COMMAND_SLIDER_UPDATED
,
418 (wxObjectEventFunction
) (wxEventFunction
)
419 (wxCommandEventFunction
) &MyFrame
::OnSeek
);
422 // Media Control events
424 this->Connect(wxID_MEDIACTRL
, wxEVT_MEDIA_STOP
,
425 (wxObjectEventFunction
) (wxEventFunction
)
426 (wxMediaEventFunction
) &MyFrame
::OnMediaStop
);
428 this->Connect(wxID_NOTEBOOK
, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED
,
429 (wxObjectEventFunction
) (wxEventFunction
)
430 (wxNotebookEventFunction
) &MyFrame
::OnPageChange
);
437 // Create a timer to update our status bar
439 m_timer
= new MyTimer(this);
443 // ----------------------------------------------------------------------------
444 // MyFrame Destructor
446 // 1) Deletes child objects implicitly
447 // 2) Delete our timer explicitly
448 // ----------------------------------------------------------------------------
454 // ----------------------------------------------------------------------------
455 // MyFrame::ResetStatus
457 // Here we just make a simple status string with some useful info about
458 // the media that we won't change later - such as the length of the media.
460 // We then append some other info that changes in MyTimer::Notify, then
461 // set the status bar to this text.
463 // In real applications, you'd want to find a better way to do this,
464 // such as static text controls (wxStaticText).
466 // We display info here in seconds (wxMediaCtrl uses milliseconds - that's why
467 // we divide by 1000).
469 // We also reset our loop counter here.
470 // ----------------------------------------------------------------------------
471 void MyFrame
::ResetStatus()
476 m_basestatus
= wxString
::Format(_T("Size(x,y):%i,%i ")
477 _T("Length(Seconds):%u Speed:%1.1fx"),
478 m_mediactrl
->GetBestSize().x
,
479 m_mediactrl
->GetBestSize().y
,
480 (unsigned)((m_mediactrl
->Length() / 1000)),
481 m_mediactrl
->GetPlaybackRate()
484 m_slider
->SetRange(0, (int)(m_mediactrl
->Length() / 1000));
488 // ----------------------------------------------------------------------------
491 // Called from file->quit.
492 // Closes this application.
493 // ----------------------------------------------------------------------------
494 void MyFrame
::OnQuit(wxCommandEvent
& WXUNUSED(event
))
496 // true is to force the frame to close
500 // ----------------------------------------------------------------------------
503 // Called from help->about.
504 // Gets some info about this application.
505 // ----------------------------------------------------------------------------
506 void MyFrame
::OnAbout(wxCommandEvent
& WXUNUSED(event
))
509 msg
.Printf( _T("This is a test of wxMediaCtrl.\n")
510 _T("Welcome to %s"), wxVERSION_STRING
);
512 wxMessageBox(msg
, _T("About wxMediaCtrl test"), wxOK
| wxICON_INFORMATION
, this);
515 // ----------------------------------------------------------------------------
518 // Called from file->loop.
519 // Changes the state of whether we want to loop or not.
520 // ----------------------------------------------------------------------------
521 void MyFrame
::OnLoop(wxCommandEvent
& WXUNUSED(event
))
524 m_mediactrl
->Loop( !m_mediactrl
->IsLooped() );
527 // ----------------------------------------------------------------------------
528 // MyFrame::OnOpenFile
530 // Called from file->openfile.
531 // Opens and plays a media file
532 // ----------------------------------------------------------------------------
533 void MyFrame
::OnOpenFile(wxCommandEvent
& WXUNUSED(event
))
535 wxFileDialog
fd(this);
537 if(fd
.ShowModal() == wxID_OK
)
539 m_notebook
->AddPage(new MyNotebookPage(m_notebook
), fd
.GetPath(), true);
543 if( !m_mediactrl
->Load(fd
.GetPath()) )
544 wxMessageBox(wxT("Couldn't load file!"));
546 if( !m_mediactrl
->Play() )
547 wxMessageBox(wxT("Couldn't play movie!"));
553 // ----------------------------------------------------------------------------
556 // Called from file->play.
557 // Resumes the media if it is paused or stopped.
558 // ----------------------------------------------------------------------------
559 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
))
575 if( !m_mediactrl
->Pause() )
576 wxMessageBox(wxT("Couldn't pause movie!"));
579 // ----------------------------------------------------------------------------
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
))
591 if( !m_mediactrl
->Stop() )
592 wxMessageBox(wxT("Couldn't stop movie!"));
595 // ----------------------------------------------------------------------------
598 // Called from file->seek.
599 // Called when the user moves the slider -
600 // seeks to a position within the media
601 // ----------------------------------------------------------------------------
602 void MyFrame
::OnSeek(wxCommandEvent
& WXUNUSED(event
))
605 if( m_mediactrl
->Seek( m_slider
->GetValue() * 1000 ) == wxInvalidOffset
)
606 wxMessageBox(wxT("Couldn't seek in movie!"));
609 // ----------------------------------------------------------------------------
610 // MyFrame::OnMediaStop
612 // Called when the media is about to stop playing.
613 // ----------------------------------------------------------------------------
614 void MyFrame
::OnMediaStop(wxMediaEvent
& WXUNUSED(event
))
618 void MyFrame
::OnPageChange(wxNotebookEvent
& WXUNUSED(event
))
623 void MyFrame
::OnClosePage(wxCommandEvent
& WXUNUSED(event
))
625 int sel
= m_notebook
->GetSelection();
627 if (sel
!= wxNOT_FOUND
)
629 m_notebook
->DeletePage(sel
);
633 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
637 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
639 // ----------------------------------------------------------------------------
642 // 1) Update our slider with the position were are in in the media
643 // 2) Update our status bar with the base text from MyFrame::ResetStatus,
644 // append some non-static (changing) info to it, then set the
645 // status bar text to that result
646 // ----------------------------------------------------------------------------
647 void MyTimer
::Notify()
650 if (!m_frame
->m_notebook
|| !m_frame
->m_notebook
->GetCurrentPage()) return;
651 wxMediaCtrl
* m_mediactrl
= ((MyNotebookPage
*)m_frame
->m_notebook
->GetCurrentPage())->m_mediactrl
;
652 wxSlider
* m_slider
= ((MyNotebookPage
*)m_frame
->m_notebook
->GetCurrentPage())->m_slider
;
653 if (!m_mediactrl
) return;
655 long lPosition
= (long)( m_mediactrl
->Tell() / 1000 );
656 m_slider
->SetValue(lPosition
);
659 m_frame
->SetStatusText(wxString
::Format(
660 _T("%s Pos:%u State:%s"),
661 m_frame
->m_basestatus
.c_str(),
662 (unsigned int)lPosition
,
663 wxGetMediaStateText(m_mediactrl
->GetState())
672 MyNotebookPage
::MyNotebookPage(wxNotebook
* theBook
) :
673 wxPanel(theBook
, wxID_ANY
)
677 // Create and attach the first/main sizer
679 wxBoxSizer
* vertsizer
= new wxBoxSizer(wxVERTICAL
);
680 this->SetSizer(vertsizer
);
681 this->SetAutoLayout(true);
684 // Create our media control
686 m_mediactrl
= new wxMediaCtrl(this, wxID_MEDIACTRL
);
687 vertsizer
->Add(m_mediactrl
, 0, wxALIGN_CENTER_HORIZONTAL
|wxALL
, 5);
692 m_slider
= new wxSlider(this, wxID_SLIDER
, 0, //init
695 wxDefaultPosition
, wxDefaultSize
,
697 vertsizer
->Add(m_slider
, 0, wxALIGN_CENTER_HORIZONTAL
|wxALL
|wxEXPAND
, 5);
701 // Create the second sizer which will position things
704 // -------Menu----------
709 wxBoxSizer
* horzsizer
= new wxBoxSizer(wxHORIZONTAL
);
710 vertsizer
->Add(horzsizer
, 0, wxALIGN_CENTER_HORIZONTAL
|wxALL
, 5);
716 // End of MediaPlayer sample