]> git.saurik.com Git - wxWidgets.git/commitdiff
many improvements/bug fixes to media control: new wxEVT_MEDIA_LOADED event, new metho...
authorVadim Zeitlin <vadim@wxwidgets.org>
Thu, 28 Jul 2005 23:56:57 +0000 (23:56 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Thu, 28 Jul 2005 23:56:57 +0000 (23:56 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@34974 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
docs/latex/wx/mediactrl.tex
docs/latex/wx/mediaevt.tex
include/wx/mediactrl.h
samples/mediaplayer/mediaplayer.cpp
src/common/mediactrlcmn.cpp
src/mac/carbon/mediactrl.cpp
src/msw/mediactrl.cpp
src/unix/mediactrl.cpp
version-script.in

index 91201f08e4ed6b16a544ab0c6484363ce0b2b60d..b674115f8734fdaece551f2590fa1b925201d52e 100644 (file)
@@ -9,6 +9,8 @@ All:
 
 - Fixed wxScopeGuard to work with VC++, documented it.
 - Fixed proxy handling in wxURL.
 
 - Fixed wxScopeGuard to work with VC++, documented it.
 - Fixed proxy handling in wxURL.
+- Added wxEVT_MEDIA_LOADED event for wxMediaCtrl
+- Added new methods to wxMediaCtrl (wxURI version of Load, ShowPlayerControls)
 - Added wxZipFSHandler::Cleanup() (Stas Sergeev)
 - Added wxImage::RotateHue() and RGB <-> HSV conversions (John Anderson)
 
 - Added wxZipFSHandler::Cleanup() (Stas Sergeev)
 - Added wxImage::RotateHue() and RGB <-> HSV conversions (John Anderson)
 
index 95c6f5cb3fdb6cde5af3a551df82846d8e0b1784..843e3d0f6dc2a51dfa683966c7781acebc5a4336 100644 (file)
@@ -39,8 +39,9 @@ realm of licensing restrictions).
 
 For general operation, all you need to do is call 
 \helpref{wxMediaCtrl::Load}{wxmediactrlload} to load the file
 
 For general operation, all you need to do is call 
 \helpref{wxMediaCtrl::Load}{wxmediactrlload} to load the file
-you want to render, then call \helpref{wxMediaCtrl::Play}{wxmediactrlplay} 
-to show the video/audio of the media.
+you want to render, catch the EVT\_MEDIA\_LOADED event,
+and then call \helpref{wxMediaCtrl::Play}{wxmediactrlplay} 
+to show the video/audio of the media in that event.
 
 More complex operations are generally more heavily dependant on the
 capabilities of the backend.  For example, QuickTime cannot set
 
 More complex operations are generally more heavily dependant on the
 capabilities of the backend.  For example, QuickTime cannot set
@@ -102,7 +103,7 @@ Use ActiveMovie/DirectShow.  Requires wxUSE\_DIRECTSHOW to be
 enabled, requires linkage with the static library strmiids.lib,
 and is available on Windows Only.}
 \twocolitem{{\bf wxMEDIABACKEND\_QUICKTIME}}{
 enabled, requires linkage with the static library strmiids.lib,
 and is available on Windows Only.}
 \twocolitem{{\bf wxMEDIABACKEND\_QUICKTIME}}{
-Use QuickTime.  Windows and Mac Only. WARNING: On Mac Systems lower than OSX 10.2 this defaults to emulating window positioning and suffers from several bugs, including not working correctly embedded in a wxNotebook. }
+Use QuickTime.  Windows and Mac Only. NOTE: On Mac Systems lower than OSX 10.2 this defaults to emulating window positioning and suffers from several bugs, including not working correctly embedded in a wxNotebook. }
 \twocolitem{{\bf wxMEDIABACKEND\_MCI}}{
 Use Media Command Interface.  Windows Only. }
 \twocolitem{{\bf wxMEDIABACKEND\_GSTREAMER}}{
 \twocolitem{{\bf wxMEDIABACKEND\_MCI}}{
 Use Media Command Interface.  Windows Only. }
 \twocolitem{{\bf wxMEDIABACKEND\_GSTREAMER}}{
@@ -206,6 +207,13 @@ Obtains the state the playback of the movie is in -
 
 Loads the file that \tt{fileName} refers to.  Returns false if loading fails.
 
 
 Loads the file that \tt{fileName} refers to.  Returns false if loading fails.
 
+
+\membersection{wxMediaCtrl::Load}\label{wxmediactrlloaduri}
+
+\func{bool}{Load}{\param{const wxURI\& }{location}}
+
+Loads the url that \tt{location} refers to.  Returns false if loading fails.  
+
 \membersection{wxMediaCtrl::Pause}\label{wxmediactrlpause}
 
 \func{bool}{Pause}{\void}
 \membersection{wxMediaCtrl::Pause}\label{wxmediactrlpause}
 
 \func{bool}{Pause}{\void}
@@ -222,7 +230,7 @@ Resumes playback of the movie.
 
 \membersection{wxMediaCtrl::Seek}\label{wxmediactrlsetposition}
 
 
 \membersection{wxMediaCtrl::Seek}\label{wxmediactrlsetposition}
 
-\func{wxFileOffset}{SetPosition}{\param{wxFileOffset }{where}, \param{wxSeekMode }{mode}}
+\func{wxFileOffset}{Seek}{\param{wxFileOffset }{where}, \param{wxSeekMode }{mode}}
 
 Seeks to a position within the movie.
 
 
 Seeks to a position within the movie.
 
@@ -235,3 +243,45 @@ Stops the media.
 
 See \helpref{Operation}{operationwxmediactrl} for an overview of how stopping works.
 
 
 See \helpref{Operation}{operationwxmediactrl} for an overview of how stopping works.
 
+
+\membersection{wxMediaCtrl::SetVolume}\label{wxmediactrlsetvolume}
+
+\func{bool}{SetVolume}{\param{double }{dVolume}}
+
+Sets the volume of the media from a 0.0 to 1.0 range.
+
+
+\membersection{wxMediaCtrl::GetVolume}\label{wxmediactrlgetvolume}
+
+\func{double}{GetVolume}{\void}
+
+Gets the volume of the media from a 0.0 to 1.0 range.
+
+
+\membersection{wxMediaCtrl::GetPlaybackRate}\label{wxmediactrlgetplaybackrate}
+
+\func{double}{GetPlaybackrate}{\void}
+
+Gets the playback rate of the media; for example 2.0 is double speed.
+Not implemented on MCI or GStreamer.
+
+
+\membersection{wxMediaCtrl::SetPlaybackRate}\label{wxmediactrlsetplaybackrate}
+
+\func{bool}{SetPlaybackrate}{\param{double }{dVolume}}
+
+Sets the rate that the media plays; for example 0.5 is half speed.
+
+
+\membersection{wxMediaCtrl::ShowPlayerControls}\label{wxmediactrlshowplayercontrols}
+
+\func{bool}{ShowPlayerControls}{\param{wxMediaCtrlPlayerControls }{flags}}
+
+Normally, when you use wxMediaCtrl it is just a window for the video to 
+play in.  However, platforms generally have their own media player interface,
+like quicktime has a bar below the video with a slider etc..  If you want that native 
+interface instead of making your own use this function.  There are several options
+for the flags parameter, however you can look at the mediactrl header for these. 
+The two general flags are wxMEDIACTRLPLAYERCONTROLS\_NONE which turns off the 
+native interface, and wxMEDIACTRLPLAYERCONTROLS\_DEFAULT which lets wxMediaCtrl
+decide what native controls on the interface.
index 903c675658b1f0b76e1a5c33516950c70c50e0d7..937dd514189e05e0aa447de2e7fd4e3107f83e97 100644 (file)
@@ -25,6 +25,7 @@ Event \helpref{wxMediaCtrl}{wxmediactrl} uses.
 
 \twocolwidtha{7cm}
 \begin{twocollist}\itemsep=0pt
 
 \twocolwidtha{7cm}
 \begin{twocollist}\itemsep=0pt
+\twocolitem{{\bf EVT\_MEDIA\_LOADED(func)}}{Sent when a media has loaded enough data that it can start playing.}
 \twocolitem{{\bf EVT\_MEDIA\_STOP(func)}}{
 Triggerred right before the media stops.  You can Veto this event to prevent it from stopping, causing it to continue playing - even if it has reached that end of the media. }
 \twocolitem{{\bf EVT\_MEDIA\_FINISHED(func)}}{Sent when a media has finished playing in a \helpref{wxMediaCtrl}{wxmediactrl}.  Note that if you connect to this event and don't skip it, it will override the looping behaviour of the media control.}
 \twocolitem{{\bf EVT\_MEDIA\_STOP(func)}}{
 Triggerred right before the media stops.  You can Veto this event to prevent it from stopping, causing it to continue playing - even if it has reached that end of the media. }
 \twocolitem{{\bf EVT\_MEDIA\_FINISHED(func)}}{Sent when a media has finished playing in a \helpref{wxMediaCtrl}{wxmediactrl}.  Note that if you connect to this event and don't skip it, it will override the looping behaviour of the media control.}
index 9646aeed81d6db9b1da8da320c33264162648334..fbd3fe2c5c0faa7f54cf8fd94e0972149c51eec6 100644 (file)
@@ -58,11 +58,24 @@ enum wxMediaState
     wxMEDIASTATE_PLAYING
 };
 
     wxMEDIASTATE_PLAYING
 };
 
+enum wxMediaCtrlPlayerControls
+{
+    wxMEDIACTRLPLAYERCONTROLS_NONE           =   0,
+    //Step controls like fastfoward, step one frame etc.
+    wxMEDIACTRLPLAYERCONTROLS_STEP           =   1 << 0,
+    //Volume controls like the speaker icon, volume slider, etc.
+    wxMEDIACTRLPLAYERCONTROLS_VOLUME         =   1 << 1,
+    wxMEDIACTRLPLAYERCONTROLS_DEFAULT        =
+                    wxMEDIACTRLPLAYERCONTROLS_STEP |
+                    wxMEDIACTRLPLAYERCONTROLS_VOLUME
+};
+
 #define wxMEDIABACKEND_DIRECTSHOW   wxT("wxAMMediaBackend")
 #define wxMEDIABACKEND_MCI          wxT("wxMCIMediaBackend")
 #define wxMEDIABACKEND_QUICKTIME    wxT("wxQTMediaBackend")
 #define wxMEDIABACKEND_GSTREAMER    wxT("wxGStreamerMediaBackend")
 
 #define wxMEDIABACKEND_DIRECTSHOW   wxT("wxAMMediaBackend")
 #define wxMEDIABACKEND_MCI          wxT("wxMCIMediaBackend")
 #define wxMEDIABACKEND_QUICKTIME    wxT("wxQTMediaBackend")
 #define wxMEDIABACKEND_GSTREAMER    wxT("wxGStreamerMediaBackend")
 
+
 // ----------------------------------------------------------------------------
 //
 // wxMediaEvent
 // ----------------------------------------------------------------------------
 //
 // wxMediaEvent
@@ -158,7 +171,7 @@ public:
                 long style = 0,
                 const wxString& szBackend = wxEmptyString,
                 const wxValidator& validator = wxDefaultValidator,
                 long style = 0,
                 const wxString& szBackend = wxEmptyString,
                 const wxValidator& validator = wxDefaultValidator,
-                const wxString& name = wxT("mediaCtrl")); //DirectShow only
+                const wxString& name = wxT("mediaCtrl"));
 
     bool DoCreate(wxClassInfo* instance,
                 wxWindow* parent, wxWindowID winid,
 
     bool DoCreate(wxClassInfo* instance,
                 wxWindow* parent, wxWindowID winid,
@@ -174,25 +187,36 @@ public:
 
     bool Load(const wxString& fileName);
 
 
     bool Load(const wxString& fileName);
 
-
     wxMediaState GetState();
 
     wxFileOffset Seek(wxFileOffset where, wxSeekMode mode = wxFromStart);
     wxFileOffset Tell(); //FIXME: This should be const
     wxFileOffset Length(); //FIXME: This should be const
 
     wxMediaState GetState();
 
     wxFileOffset Seek(wxFileOffset where, wxSeekMode mode = wxFromStart);
     wxFileOffset Tell(); //FIXME: This should be const
     wxFileOffset Length(); //FIXME: This should be const
 
-    //
-    // Unofficial parts of API
-    //
-    //DirectShow/GStreamer only.  Quicktime too, but somewhat buggy...
-    bool Load(const wxURI& location);
-
+#if wxABI_VERSION >= 20601 /* 2.6.1+ only */
     double GetPlaybackRate();           //All but MCI & GStreamer
     bool SetPlaybackRate(double dRate); //All but MCI & GStreamer
     double GetPlaybackRate();           //All but MCI & GStreamer
     bool SetPlaybackRate(double dRate); //All but MCI & GStreamer
+#endif
+
+#if wxABI_VERSION >= 20602 /* 2.6.2+ only */
+    bool Load(const wxURI& location);
+    bool Load(const wxURI& location, const wxURI& proxy);
+
+    wxFileOffset GetDownloadProgress();
+    wxFileOffset GetDownloadTotal();
 
 
-    double GetVolume();                 //DirectShow only
-    bool   SetVolume(double dVolume);   //DirectShow only
+    double GetVolume();
+    bool   SetVolume(double dVolume);
 
 
+    bool    ShowPlayerControls(
+        wxMediaCtrlPlayerControls flags = wxMEDIACTRLPLAYERCONTROLS_DEFAULT);
+
+    //helpers for the wxPython people
+    bool LoadURI(const wxString& fileName)
+    {   return Load(wxURI(fileName));       }
+    bool LoadURIWithProxy(const wxString& fileName, const wxString& proxy)
+    {   return Load(wxURI(fileName), wxURI(proxy));       }
+#endif
 protected:
     static wxClassInfo* NextBackend();
 
 protected:
     static wxClassInfo* NextBackend();
 
@@ -202,10 +226,7 @@ protected:
 
     //FIXME:  This is nasty... find a better way to work around
     //inheritance issues
 
     //FIXME:  This is nasty... find a better way to work around
     //inheritance issues
-#ifdef __WXMAC__
-    friend class wxQTMediaBackend;
-#endif
-#ifdef __WXCOCOA__
+#if defined(__WXMAC__) || defined(__WXCOCOA__)
     friend class wxQTMediaBackend;
 #endif
     class wxMediaBackend* m_imp;
     friend class wxQTMediaBackend;
 #endif
     class wxMediaBackend* m_imp;
@@ -218,7 +239,13 @@ protected:
 //
 // wxMediaBackend
 //
 //
 // wxMediaBackend
 //
-// Currently an internal class - API stability not guaranteed.
+// Derive from this and use standard wxWidgets RTTI
+// (DECLARE_DYNAMIC_CLASS and IMPLEMENT_CLASS) to make a backend
+// for wxMediaCtrl.  Backends are searched alphabetically -
+// the one with the earliest letter is tried first.
+//
+// Note that this is currently not API or ABI compatable -
+// so statically link or make the client compile on-site.
 //
 // ----------------------------------------------------------------------------
 
 //
 // ----------------------------------------------------------------------------
 
@@ -278,11 +305,21 @@ public:
     virtual bool SetVolume(double WXUNUSED(dVolume))
     {   return false;                   }
 
     virtual bool SetVolume(double WXUNUSED(dVolume))
     {   return false;                   }
 
-    virtual void RESERVED3() {}
-    virtual void RESERVED4() {}
-    virtual void RESERVED5() {}
-    virtual void RESERVED6() {}
-    virtual void RESERVED7() {}
+    virtual bool Load(const wxURI& WXUNUSED(location),
+                      const wxURI& WXUNUSED(proxy))
+    {   return false;                   }
+
+    virtual bool   ShowPlayerControls(
+                    wxMediaCtrlPlayerControls WXUNUSED(flags))
+    {   return false;                   }
+    virtual bool   IsInterfaceShown()
+    {   return false;                   }
+
+    virtual wxLongLong GetDownloadProgress()
+    {    return 0;                      }
+    virtual wxLongLong GetDownloadTotal()
+    {    return 0;                      }
+
     virtual void RESERVED8() {}
     virtual void RESERVED9() {}
 
     virtual void RESERVED8() {}
     virtual void RESERVED9() {}
 
@@ -307,6 +344,12 @@ typedef void (wxEvtHandler::*wxMediaEventFunction)(wxMediaEvent&);
 #define EVT_MEDIA_FINISHED(winid, fn) DECLARE_EVENT_TABLE_ENTRY( wxEVT_MEDIA_FINISHED, winid, wxID_ANY, wxMediaEventHandler(fn), (wxObject *) NULL ),
 #define EVT_MEDIA_STOP(winid, fn) DECLARE_EVENT_TABLE_ENTRY( wxEVT_MEDIA_STOP, winid, wxID_ANY, wxMediaEventHandler(fn), (wxObject *) NULL ),
 
 #define EVT_MEDIA_FINISHED(winid, fn) DECLARE_EVENT_TABLE_ENTRY( wxEVT_MEDIA_FINISHED, winid, wxID_ANY, wxMediaEventHandler(fn), (wxObject *) NULL ),
 #define EVT_MEDIA_STOP(winid, fn) DECLARE_EVENT_TABLE_ENTRY( wxEVT_MEDIA_STOP, winid, wxID_ANY, wxMediaEventHandler(fn), (wxObject *) NULL ),
 
+#if wxABI_VERSION >= 20602 /* 2.6.2+ only */
+#   define wxMEDIA_LOADED_ID      13002
+    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_MEDIA, wxEVT_MEDIA_LOADED,     wxMEDIA_LOADED_ID)
+#   define EVT_MEDIA_LOADED(winid, fn) DECLARE_EVENT_TABLE_ENTRY( wxEVT_MEDIA_LOADED, winid, wxID_ANY, wxMediaEventHandler(fn), (wxObject *) NULL ),
+#endif
+
 // ----------------------------------------------------------------------------
 // End compilation gaurd
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // End compilation gaurd
 // ----------------------------------------------------------------------------
index 999ee558cea71f748956918e22431c3a2e989bb0..fd9915f74b08cb356b7b61cea3945660f54ad88b 100644 (file)
 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 // MediaPlayer
 //
 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 // MediaPlayer
 //
-// This is a simple example of how to use all the funtionality of
-// the wxMediaCtrl class in wxWidgets.
+// This is a somewhat comprehensive example of how to use all the funtionality
+// of the wxMediaCtrl class in wxWidgets.
 //
 // To use this sample, simply select Open File from the file menu,
 // select the file you want to play - and MediaPlayer will play the file in a
 //
 // To use this sample, simply select Open File from the file menu,
 // select the file you want to play - and MediaPlayer will play the file in a
-// new notebook page, showing video if necessary.
+// the current notebook page, showing video if necessary.
 //
 // You can select one of the menu options, or move the slider around
 // to manipulate what is playing.
 //
 // You can select one of the menu options, or move the slider around
 // to manipulate what is playing.
 //    Cocoa NSMovieView-Quicktime).
 // 2) Positioning on Mac Carbon is messed up if put in a sub-control like a
 //    Notebook (like this sample does) on OS versions < 10.2.
 //    Cocoa NSMovieView-Quicktime).
 // 2) Positioning on Mac Carbon is messed up if put in a sub-control like a
 //    Notebook (like this sample does) on OS versions < 10.2.
+// 3) On unix the video may not work - it only checks for a few video
+//    sinks - xvimagesink, ximagesink and whatever gnome preferences has -
+//    if gnome preferences is not available or you have a different video
+//    sink then those two (such as sdlvideosink) then you'll get black video
 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 // ============================================================================
 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 // ============================================================================
 #include "wx/slider.h"      //for a slider for seeking within media
 #include "wx/sizer.h"       //for positioning controls/wxBoxSizer
 #include "wx/timer.h"       //timer for updating status bar
 #include "wx/slider.h"      //for a slider for seeking within media
 #include "wx/sizer.h"       //for positioning controls/wxBoxSizer
 #include "wx/timer.h"       //timer for updating status bar
-#include "wx/textdlg.h"     //for getting user text from OpenURL
+#include "wx/textdlg.h"     //for getting user text from OpenURL/Debug
 #include "wx/notebook.h"    //for wxNotebook and putting movies in pages
 #include "wx/notebook.h"    //for wxNotebook and putting movies in pages
-
-// Use some stuff that's not part of the current API, such as loading
-// media from a URL, etc.
-#define wxUSE_UNOFFICIALSTUFF 0
+#include "wx/cmdline.h"     //for wxCmdLineParser (optional)
+#include "wx/listctrl.h"    //for wxListCtrl
+#include "wx/dnd.h"         //drag and drop for the playlist
+#include "wx/filename.h"    //For wxFileName::GetName()
+#include "wx/config.h"      //for native wxConfig
 
 // ----------------------------------------------------------------------------
 // Bail out if the user doesn't want one of the
 // things we need
 // ----------------------------------------------------------------------------
 
 
 // ----------------------------------------------------------------------------
 // Bail out if the user doesn't want one of the
 // things we need
 // ----------------------------------------------------------------------------
 
+// RN:  I'm not sure why this is here - even minimal doesn't check for 
+//      wxUSE_GUI.  I may have added it myself though...
 #if !wxUSE_GUI
 #error "This is a GUI sample"
 #endif
 
 #if !wxUSE_GUI
 #error "This is a GUI sample"
 #endif
 
-#if !wxUSE_MEDIACTRL || !wxUSE_MENUS || !wxUSE_SLIDER || !wxUSE_TIMER || !wxUSE_NOTEBOOK
-#error "menus, slider, mediactrl, notebook, and timers must all be enabled for this sample!"
+#if !wxUSE_MEDIACTRL || !wxUSE_MENUS || !wxUSE_SLIDER || !wxUSE_TIMER || \
+    !wxUSE_NOTEBOOK || !wxUSE_LISTCTRL || !wxUSE_DRAG_AND_DROP
+#error "Not all required elements are enabled.  Please modify setup.h!"
 #endif
 
 // ============================================================================
 #endif
 
 // ============================================================================
@@ -90,7 +98,7 @@
 // IDs for the controls and the menu commands
 enum
 {
 // IDs for the controls and the menu commands
 enum
 {
-    // menu items
+    // Menu event IDs
     wxID_LOOP = 1,
     wxID_OPENFILESAMEPAGE,
     wxID_OPENFILENEWPAGE,
     wxID_LOOP = 1,
     wxID_OPENFILESAMEPAGE,
     wxID_OPENFILENEWPAGE,
@@ -99,39 +107,61 @@ enum
     wxID_CLOSECURRENTPAGE,
     wxID_PLAY,
     wxID_PAUSE,
     wxID_CLOSECURRENTPAGE,
     wxID_PLAY,
     wxID_PAUSE,
+    wxID_NEXT,
+    wxID_PREV,
+    wxID_SELECTBACKEND,
+    wxID_SHOWINTERFACE,
 //    wxID_STOP,   [built-in to wxWidgets]
 //    wxID_ABOUT,  [built-in to wxWidgets]
 //    wxID_EXIT,   [built-in to wxWidgets]
 //    wxID_STOP,   [built-in to wxWidgets]
 //    wxID_ABOUT,  [built-in to wxWidgets]
 //    wxID_EXIT,   [built-in to wxWidgets]
-    wxID_SLIDER,    // event id for our slider
-    wxID_NOTEBOOK,  // event id for our notebook
-    wxID_MEDIACTRL  // event id for our wxMediaCtrl
+    // Control event IDs
+    wxID_SLIDER,    
+    wxID_NOTEBOOK, 
+    wxID_MEDIACTRL,  
+    wxID_BUTTONNEXT,
+    wxID_BUTTONPREV,
+    wxID_BUTTONSTOP,
+    wxID_BUTTONPLAY,
+    wxID_BUTTONVD,
+    wxID_BUTTONVU,
+    wxID_LISTCTRL,
+    wxID_GAUGE
 };
 
 // ----------------------------------------------------------------------------
 };
 
 // ----------------------------------------------------------------------------
-// MyApp
+// wxMediaPlayerApp
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 
-class MyApp : public wxApp
+class wxMediaPlayerApp : public wxApp
 {
 public:
 {
 public:
+#ifdef __WXMAC__
+    virtual void MacOpenFile(const wxString & fileName )
+    {
+        //Called when a user drags a file over our app
+        m_frame->DoOpenFile(fileName);
+    }
+#endif
     virtual bool OnInit();
     virtual bool OnInit();
+
+protected:
+    class wxMediaPlayerFrame* m_frame;
 };
 
 // ----------------------------------------------------------------------------
 };
 
 // ----------------------------------------------------------------------------
-// MyFrame
+// wxMediaPlayerFrame
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 
-class MyFrame : public wxFrame
+class wxMediaPlayerFrame : public wxFrame
 {
 public:
     // Ctor/Dtor
 {
 public:
     // Ctor/Dtor
-    MyFrame(const wxString& title);
-    ~MyFrame();
+    wxMediaPlayerFrame(const wxString& title);
+    ~wxMediaPlayerFrame();
 
     // Menu event handlers
     void OnQuit(wxCommandEvent& event);
     void OnAbout(wxCommandEvent& event);
 
     // Menu event handlers
     void OnQuit(wxCommandEvent& event);
     void OnAbout(wxCommandEvent& event);
-    void OnLoop(wxCommandEvent& event);
 
     void OnOpenFileSamePage(wxCommandEvent& event);
     void OnOpenFileNewPage(wxCommandEvent& event);
 
     void OnOpenFileSamePage(wxCommandEvent& event);
     void OnOpenFileNewPage(wxCommandEvent& event);
@@ -142,10 +172,34 @@ public:
     void OnPlay(wxCommandEvent& event);
     void OnPause(wxCommandEvent& event);
     void OnStop(wxCommandEvent& event);
     void OnPlay(wxCommandEvent& event);
     void OnPause(wxCommandEvent& event);
     void OnStop(wxCommandEvent& event);
+    void OnNext(wxCommandEvent& event);
+    void OnPrev(wxCommandEvent& event);
+    void OnVolumeDown(wxCommandEvent& event);
+    void OnVolumeUp(wxCommandEvent& event);
+
+    void OnLoop(wxCommandEvent& event);
+    void OnShowInterface(wxCommandEvent& event);
+
+    void OnSelectBackend(wxCommandEvent& event);
 
     // Notebook event handlers
     void OnPageChange(wxNotebookEvent& event);
 
 
     // Notebook event handlers
     void OnPageChange(wxNotebookEvent& event);
 
+    // Key event handlers
+    void OnKeyDown(wxKeyEvent& event);
+
+    // Quickie for playing from command line
+    void AddToPlayList(const wxString& szString);
+
+    // ListCtrl event handlers
+    void OnChangeSong(wxListEvent& event);
+
+    // Media event handlers
+    void OnMediaLoaded(wxMediaEvent& event);
+
+    // Close event handlers
+    void OnClose(wxCloseEvent& event); 
+
 private:
     // Rebuild base status string (see Implementation)
     void ResetStatus();
 private:
     // Rebuild base status string (see Implementation)
     void ResetStatus();
@@ -153,57 +207,154 @@ private:
     // Common open file code
     void OpenFile(bool bNewPage);
     void OpenURL(bool bNewPage);
     // Common open file code
     void OpenFile(bool bNewPage);
     void OpenURL(bool bNewPage);
+    void DoOpenFile(const wxString& path, bool bNewPage);
+    void DoPlayFile(const wxString& path);
 
 
-    // Get the media control and slider of current notebook page
+    // Get the controls of current notebook page
     wxMediaCtrl* GetCurrentMediaCtrl();
     wxSlider*    GetCurrentSlider();
     wxMediaCtrl* GetCurrentMediaCtrl();
     wxSlider*    GetCurrentSlider();
+    wxGauge*    GetCurrentGauge();
 
 
-    class MyTimer* m_timer;     //Timer to write info to status bar
+    int      m_nLastFileId;     //List ID of played file in listctrl
+    wxString m_szFile;          //Name of currently playing file/location
+    class wxMediaPlayerTimer* m_timer;     //Timer to write info to status bar
     wxString m_basestatus;      //Base status string (see ResetStatus())
     wxNotebook* m_notebook;     //Notebook containing our pages
 
     wxString m_basestatus;      //Base status string (see ResetStatus())
     wxNotebook* m_notebook;     //Notebook containing our pages
 
-    // So that mytimer can access MyFrame's members
-    friend class MyTimer;
+    // Maybe I should use more accessors, but for simplicity
+    // I'll allow the other classes access to our members
+    friend class wxMediaPlayerApp;
+    friend class wxMediaPlayerNotebookPage;
+    friend class wxMediaPlayerTimer;
 };
 
 
 
 // ----------------------------------------------------------------------------
 };
 
 
 
 // ----------------------------------------------------------------------------
-// MyNotebookPage
+// wxMediaPlayerNotebookPage
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 
-class MyNotebookPage : public wxPanel
+class wxMediaPlayerNotebookPage : public wxPanel
 {
 {
-    MyNotebookPage(wxNotebook* book);
+    wxMediaPlayerNotebookPage(wxMediaPlayerFrame* parentFrame, 
+        wxNotebook* book, const wxString& be = wxEmptyString);
 
     // Slider event handlers
 
     // Slider event handlers
-    void OnSeek(wxCommandEvent& event);
+    void OnBeginSeek(wxScrollEvent& event);
+    void OnEndSeek(wxScrollEvent& event);
 
     // Media event handlers
     void OnMediaFinished(wxMediaEvent& event);
 
 public:
 
     // Media event handlers
     void OnMediaFinished(wxMediaEvent& event);
 
 public:
-    friend class MyFrame;       //make MyFrame able to access private members
+    bool IsBeingDragged();      //accessor for m_bIsBeingDragged
+
+    //make wxMediaPlayerFrame able to access the private members
+    friend class wxMediaPlayerFrame;       
+
     wxMediaCtrl* m_mediactrl;   //Our media control
     wxMediaCtrl* m_mediactrl;   //Our media control
+    class wxMediaPlayerListCtrl* m_playlist;  //Our playlist
     wxSlider* m_slider;         //The slider below our media control
     int m_nLoops;               //Number of times media has looped
     bool m_bLoop;               //Whether we are looping or not
     wxSlider* m_slider;         //The slider below our media control
     int m_nLoops;               //Number of times media has looped
     bool m_bLoop;               //Whether we are looping or not
+    bool m_bIsBeingDragged;     //Whether the user is dragging the scroll bar
+    wxMediaPlayerFrame* m_parentFrame;  //Main wxFrame of our sample
+    wxButton* m_prevButton;     //Go to previous file button
+    wxButton* m_playButton;     //Play/pause file button
+    wxButton* m_stopButton;     //Stop playing file button
+    wxButton* m_nextButton;     //Next file button
+    wxButton* m_vdButton;       //Volume down button
+    wxButton* m_vuButton;       //Volume up button
+    wxGauge*  m_gauge;          //Gauge to keep in line with slider
 };
 
 // ----------------------------------------------------------------------------
 };
 
 // ----------------------------------------------------------------------------
-// MyTimer
+// wxMediaPlayerTimer
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
 
-class MyTimer : public wxTimer
+class wxMediaPlayerTimer : public wxTimer
 {
 public:
     //Ctor
 {
 public:
     //Ctor
-    MyTimer(MyFrame* frame) {m_frame = frame;}
+    wxMediaPlayerTimer(wxMediaPlayerFrame* frame) {m_frame = frame;}
 
     //Called each time the timer's timeout expires
     void Notify();
 
 
     //Called each time the timer's timeout expires
     void Notify();
 
-    MyFrame* m_frame;       //The MyFrame
+    wxMediaPlayerFrame* m_frame;       //The wxMediaPlayerFrame
+};
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerListCtrl
+// ----------------------------------------------------------------------------
+class wxMediaPlayerListCtrl : public wxListCtrl
+{
+public:
+    void AddToPlayList(const wxString& szString)
+    {
+        wxListItem kNewItem;
+        kNewItem.SetAlign(wxLIST_FORMAT_LEFT);
+
+        int nID;
+
+        kNewItem.SetId(nID = this->GetItemCount());
+        kNewItem.SetMask(wxLIST_MASK_DATA);
+        kNewItem.SetData(new wxString(szString));
+
+        this->InsertItem(kNewItem);
+        this->SetItem(nID, 0, _T("*"));
+        this->SetItem(nID, 1, wxFileName(szString).GetName());
+
+        if (nID % 2)
+        {
+            kNewItem.SetBackgroundColour(wxColour(192,192,192));
+            this->SetItem(kNewItem);
+        }
+    }
+
+    void GetSelectedItem(wxListItem& listitem)
+    {
+        listitem.SetMask(wxLIST_MASK_TEXT |  wxLIST_MASK_DATA);
+        int nLast = -1, nLastSelected = -1;
+        while ((nLast = this->GetNextItem(nLast,
+                                         wxLIST_NEXT_ALL,
+                                         wxLIST_STATE_SELECTED)) != -1)
+        {
+            listitem.SetId(nLast);
+            this->GetItem(listitem);
+            if ((listitem.GetState() & wxLIST_STATE_FOCUSED) )
+                break;
+            nLastSelected = nLast;
+        }
+        if (nLast == -1 && nLastSelected == -1)
+            return;
+        listitem.SetId(nLastSelected == -1 ? nLast : nLastSelected);
+        this->GetItem(listitem);
+    }
+
+};
+
+// ----------------------------------------------------------------------------
+// wxPlayListDropTarget
+//
+//  Drop target for playlist (i.e. user drags a file from explorer unto 
+//  playlist it adds the file)
+// ----------------------------------------------------------------------------
+class wxPlayListDropTarget : public wxFileDropTarget
+{
+public:
+    wxPlayListDropTarget(wxMediaPlayerListCtrl& list) : m_list(list) {}
+    ~wxPlayListDropTarget(){}
+        virtual bool OnDropFiles(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y),
+                         const wxArrayString& files)
+    {
+        for (size_t i = 0; i < files.GetCount(); ++i)
+        {
+            m_list.AddToPlayList(files[i]);
+        }
+        return true;
+    }
+    wxMediaPlayerListCtrl& m_list;
 };
 
 // ============================================================================
 };
 
 // ============================================================================
@@ -240,7 +391,7 @@ const wxChar* wxGetMediaStateText(int nState)
 
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
 
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
-// MyApp
+// wxMediaPlayerApp
 //
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 //
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
@@ -255,33 +406,64 @@ const wxChar* wxGetMediaStateText(int nState)
 // routine, such as main or WinMain().  Use IMPLEMENT_APP_NO_MAIN if you do
 // not desire this behavior.
 // ----------------------------------------------------------------------------
 // routine, such as main or WinMain().  Use IMPLEMENT_APP_NO_MAIN if you do
 // not desire this behavior.
 // ----------------------------------------------------------------------------
-IMPLEMENT_APP(MyApp)
-
+IMPLEMENT_APP(wxMediaPlayerApp)
 
 // ----------------------------------------------------------------------------
 
 // ----------------------------------------------------------------------------
-// MyApp::OnInit
+// wxMediaPlayerApp::OnInit
 //
 // Where execution starts - akin to a main or WinMain.
 // 1) Create the frame and show it to the user
 //
 // Where execution starts - akin to a main or WinMain.
 // 1) Create the frame and show it to the user
-// 2) return true specifying that we want execution to continue past OnInit
+// 2) Process filenames from the commandline
+// 3) return true specifying that we want execution to continue past OnInit
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-bool MyApp::OnInit()
+bool wxMediaPlayerApp::OnInit()
 {
 {
-    MyFrame *frame = new MyFrame(_T("MediaPlayer wxWidgets Sample"));
+    wxMediaPlayerFrame *frame = 
+        new wxMediaPlayerFrame(_T("MediaPlayer wxWidgets Sample"));
     frame->Show(true);
 
     frame->Show(true);
 
+#if wxUSE_CMDLINE_PARSER
+    // 
+    //  What this does is get all the command line arguments
+    //  and treat each one as a file to put to the initial playlist
+    //
+    wxCmdLineEntryDesc cmdLineDesc[2];
+    cmdLineDesc[0].kind = wxCMD_LINE_PARAM;
+    cmdLineDesc[0].shortName = NULL;
+    cmdLineDesc[0].longName = NULL;
+    cmdLineDesc[0].description = wxT("input files");
+    cmdLineDesc[0].type = wxCMD_LINE_VAL_STRING;
+    cmdLineDesc[0].flags = wxCMD_LINE_PARAM_OPTIONAL | wxCMD_LINE_PARAM_MULTIPLE;
+
+    cmdLineDesc[1].kind = wxCMD_LINE_NONE;
+
+    //gets the passed media files from cmd line
+    wxCmdLineParser parser (cmdLineDesc, argc, argv);
+
+    // get filenames from the commandline
+    if (parser.Parse() == 0) 
+    {
+        for (size_t paramNr=0; paramNr < parser.GetParamCount(); ++paramNr) 
+        {
+            frame->AddToPlayList((parser.GetParam (paramNr)));
+        }
+        wxCommandEvent emptyevt;
+        frame->OnNext(emptyevt);
+    }
+#endif
+
     return true;
 }
 
 
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
     return true;
 }
 
 
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
-// MyFrame
+// wxMediaPlayerFrame
 //
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 // ----------------------------------------------------------------------------
 //
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 // ----------------------------------------------------------------------------
-// MyFrame Constructor
+// wxMediaPlayerFrame Constructor
 //
 // 1) Create our menus
 // 2) Create our notebook control and add it to the frame
 //
 // 1) Create our menus
 // 2) Create our notebook control and add it to the frame
@@ -290,49 +472,63 @@ bool MyApp::OnInit()
 // 5) Start our timer
 // ----------------------------------------------------------------------------
 
 // 5) Start our timer
 // ----------------------------------------------------------------------------
 
-MyFrame::MyFrame(const wxString& title)
-       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(400,400))
+wxMediaPlayerFrame::wxMediaPlayerFrame(const wxString& title)
+       : wxFrame(NULL, wxID_ANY, title, wxDefaultPosition, wxSize(600,600)), 
+       m_nLastFileId(-1)
 {
     //
     //  Create Menus
     //
 {
     //
     //  Create Menus
     //
-    wxMenu *menuFile = new wxMenu;
-
+    wxMenu *fileMenu = new wxMenu;
+    wxMenu *controlsMenu = new wxMenu;
+    wxMenu *optionsMenu = new wxMenu;
     wxMenu *helpMenu = new wxMenu;
     wxMenu *helpMenu = new wxMenu;
-    helpMenu->Append(wxID_ABOUT,
-                     _T("&About...\tF1"),
-                     _T("Show about dialog"));
+    wxMenu *debugMenu = new wxMenu;
 
 
-    menuFile->Append(wxID_OPENFILESAMEPAGE, _T("&Open File"),
+    fileMenu->Append(wxID_OPENFILESAMEPAGE, _T("&Open File\tCtrl-Shift-O"),
                         _T("Open a File in the current notebook page"));
                         _T("Open a File in the current notebook page"));
-    menuFile->Append(wxID_OPENFILENEWPAGE, _T("&Open File in a new page"),
+    fileMenu->Append(wxID_OPENFILENEWPAGE, _T("&Open File in a new page"),
                         _T("Open a File in a new notebook page"));
                         _T("Open a File in a new notebook page"));
-#if wxUSE_UNOFFICIALSTUFF
-    menuFile->Append(wxID_OPENURLSAMEPAGE, _T("&Open URL"),
+    fileMenu->Append(wxID_OPENURLSAMEPAGE, _T("&Open URL"),
                         _T("Open a URL in the current notebook page"));
                         _T("Open a URL in the current notebook page"));
-    menuFile->Append(wxID_OPENURLNEWPAGE, _T("&Open URL in a new page"),
+    fileMenu->Append(wxID_OPENURLNEWPAGE, _T("&Open URL in a new page"),
                         _T("Open a URL in a new notebook page"));
                         _T("Open a URL in a new notebook page"));
-#endif
-    menuFile->AppendSeparator();
-    menuFile->Append(wxID_CLOSECURRENTPAGE, _T("&Close Current Page"),
+    fileMenu->AppendSeparator();
+    fileMenu->Append(wxID_CLOSECURRENTPAGE, _T("&Close Current Page\tCtrl-C"),
                         _T("Close current notebook page"));
                         _T("Close current notebook page"));
-    menuFile->AppendSeparator();
-    menuFile->Append(wxID_PLAY, _T("&Play"), _T("Resume playback"));
-    menuFile->Append(wxID_PAUSE, _T("P&ause"), _T("Pause playback"));
-    menuFile->Append(wxID_STOP, _T("&Stop"), _T("Stop playback"));
-    menuFile->AppendSeparator();
-    menuFile->AppendCheckItem(wxID_LOOP,
-                              _T("&Loop"),
-                              _T("Loop Selected Media"));
-    menuFile->AppendSeparator();
-    menuFile->Append(wxID_EXIT,
+    fileMenu->AppendSeparator();
+    fileMenu->Append(wxID_EXIT,
                      _T("E&xit\tAlt-X"),
                      _T("Quit this program"));
 
                      _T("E&xit\tAlt-X"),
                      _T("Quit this program"));
 
+    controlsMenu->Append(wxID_PLAY, _T("&Play/Pause\tCtrl-P"), _T("Resume/Pause playback"));
+    controlsMenu->Append(wxID_STOP, _T("&Stop\tCtrl-S"), _T("Stop playback"));
+    controlsMenu->AppendSeparator();
+    controlsMenu->Append(wxID_PREV, _T("&Previous\tCtrl-B"), _T("Go to previous track"));
+    controlsMenu->Append(wxID_NEXT, _T("&Next\tCtrl-N"), _T("Skip to next track"));
+
+    optionsMenu->AppendCheckItem(wxID_LOOP,
+                              _T("&Loop\tCtrl-L"),
+                              _T("Loop Selected Media"));
+    optionsMenu->AppendCheckItem(wxID_SHOWINTERFACE,
+                              _T("&Show Interface\tCtrl-I"),
+                              _T("Show wxMediaCtrl native controls"));
+
+    debugMenu->Append(wxID_SELECTBACKEND,
+                     _T("&Select Backend...\tCtrl-D"),
+                     _T("Select a backend manually"));
+
+    helpMenu->Append(wxID_ABOUT,
+                     _T("&About...\tF1"),
+                     _T("Show about dialog"));
+
+
     wxMenuBar *menuBar = new wxMenuBar();
     wxMenuBar *menuBar = new wxMenuBar();
-    menuBar->Append(menuFile, _T("&File"));
+    menuBar->Append(fileMenu, _T("&File"));
+    menuBar->Append(controlsMenu, _T("&Controls"));
+    menuBar->Append(optionsMenu, _T("&Options"));
+    menuBar->Append(debugMenu, _T("&Debug"));
     menuBar->Append(helpMenu, _T("&Help"));
     menuBar->Append(helpMenu, _T("&Help"));
-
     SetMenuBar(menuBar);
 
     //
     SetMenuBar(menuBar);
 
     //
@@ -357,14 +553,14 @@ MyFrame::MyFrame(const wxString& title)
     //
     //  Message Maps are implemented by putting
     //  DECLARE_MESSAGE_MAP in your wxEvtHandler-derived
     //
     //  Message Maps are implemented by putting
     //  DECLARE_MESSAGE_MAP in your wxEvtHandler-derived
-    //  class you want to use for events, such as MyFrame.
+    //  class you want to use for events, such as wxMediaPlayerFrame.
     //
     //  Then after your class declaration you put
     //
     //  Then after your class declaration you put
-    //  BEGIN_EVENT_TABLE(MyFrame, wxFrame)
+    //  BEGIN_EVENT_TABLE(wxMediaPlayerFrame, wxFrame)
     //  EVT_XXX(XXX)...
     //  END_EVENT_TABLE()
     //
     //  EVT_XXX(XXX)...
     //  END_EVENT_TABLE()
     //
-    //  Where MyFrame is the class with the DECLARE_MESSAGE_MAP
+    //  Where wxMediaPlayerFrame is the class with the DECLARE_MESSAGE_MAP
     //  in it.  EVT_XXX(XXX) are each of your handlers, such
     //  as EVT_MENU for menu events and the XXX inside
     //  is the parameters to the event macro - in the case
     //  in it.  EVT_XXX(XXX) are each of your handlers, such
     //  as EVT_MENU for menu events and the XXX inside
     //  is the parameters to the event macro - in the case
@@ -395,12 +591,12 @@ MyFrame::MyFrame(const wxString& title)
     //  type, then to a wxEventFunction, then to a
     //  wxObjectEventFunction - I.E.
     //  (wxObjectEventFunction)(wxEventFunction)
     //  type, then to a wxEventFunction, then to a
     //  wxObjectEventFunction - I.E.
     //  (wxObjectEventFunction)(wxEventFunction)
-    //  (wxCommandEventFunction) &MyFrame::MyHandler
+    //  (wxCommandEventFunction) &wxMediaPlayerFrame::MyHandler
     //
     //  Or, you can use the new (2.5.5+) event handler
     //  conversion macros - for instance the above could
     //  be done as
     //
     //  Or, you can use the new (2.5.5+) event handler
     //  conversion macros - for instance the above could
     //  be done as
-    //  wxCommandEventHandler(MyFrame::MyHandler)
+    //  wxCommandEventHandler(wxMediaPlayerFrame::MyHandler)
     //  pretty simple, eh?
     //
     //  The fourth is an optional userdata param -
     //  pretty simple, eh?
     //
     //  The fourth is an optional userdata param -
@@ -422,73 +618,156 @@ MyFrame::MyFrame(const wxString& title)
     // Menu events
     //
     this->Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED,
     // Menu events
     //
     this->Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnQuit));
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnQuit));
 
     this->Connect(wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED,
 
     this->Connect(wxID_ABOUT, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnAbout));
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnAbout));
 
     this->Connect(wxID_LOOP, wxEVT_COMMAND_MENU_SELECTED,
 
     this->Connect(wxID_LOOP, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnLoop));
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnLoop));
+
+    this->Connect(wxID_SHOWINTERFACE, wxEVT_COMMAND_MENU_SELECTED,
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnShowInterface));
 
     this->Connect(wxID_OPENFILENEWPAGE, wxEVT_COMMAND_MENU_SELECTED,
 
     this->Connect(wxID_OPENFILENEWPAGE, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnOpenFileNewPage));
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnOpenFileNewPage));
 
     this->Connect(wxID_OPENFILESAMEPAGE, wxEVT_COMMAND_MENU_SELECTED,
 
     this->Connect(wxID_OPENFILESAMEPAGE, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnOpenFileSamePage));
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnOpenFileSamePage));
 
     this->Connect(wxID_OPENURLNEWPAGE, wxEVT_COMMAND_MENU_SELECTED,
 
     this->Connect(wxID_OPENURLNEWPAGE, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnOpenURLNewPage));
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnOpenURLNewPage));
 
     this->Connect(wxID_OPENURLSAMEPAGE, wxEVT_COMMAND_MENU_SELECTED,
 
     this->Connect(wxID_OPENURLSAMEPAGE, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnOpenURLSamePage));
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnOpenURLSamePage));
 
     this->Connect(wxID_CLOSECURRENTPAGE, wxEVT_COMMAND_MENU_SELECTED,
 
     this->Connect(wxID_CLOSECURRENTPAGE, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnCloseCurrentPage));
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnCloseCurrentPage));
 
     this->Connect(wxID_PLAY, wxEVT_COMMAND_MENU_SELECTED,
 
     this->Connect(wxID_PLAY, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnPlay));
-
-    this->Connect(wxID_PAUSE, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnPause));
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnPlay));
 
     this->Connect(wxID_STOP, wxEVT_COMMAND_MENU_SELECTED,
 
     this->Connect(wxID_STOP, wxEVT_COMMAND_MENU_SELECTED,
-                  wxCommandEventHandler(MyFrame::OnStop));
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnStop));
+
+    this->Connect(wxID_NEXT, wxEVT_COMMAND_MENU_SELECTED,
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnNext));
+
+    this->Connect(wxID_PREV, wxEVT_COMMAND_MENU_SELECTED,
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnPrev));
+
+    this->Connect(wxID_SELECTBACKEND, wxEVT_COMMAND_MENU_SELECTED,
+                  wxCommandEventHandler(wxMediaPlayerFrame::OnSelectBackend));
 
     //
     // Notebook events
     //
     this->Connect(wxID_NOTEBOOK, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
 
     //
     // Notebook events
     //
     this->Connect(wxID_NOTEBOOK, wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED,
-                  wxNotebookEventHandler(MyFrame::OnPageChange));
+                  wxNotebookEventHandler(wxMediaPlayerFrame::OnPageChange));
+
+    //
+    // Key events
+    //
+    wxTheApp->Connect(wxID_ANY, wxEVT_KEY_DOWN,
+                  wxKeyEventHandler(wxMediaPlayerFrame::OnKeyDown),
+                  (wxObject*)0, this);
+
+    //
+    // Close events
+    //
+    this->Connect(wxID_ANY, wxEVT_CLOSE_WINDOW, 
+                wxCloseEventHandler(wxMediaPlayerFrame::OnClose));
 
     //
     // End of Events
     //
 
 
     //
     // End of Events
     //
 
+    //
+    //  Create an initial notebook page so the user has something 
+    //  to work with without having to go file->open every time :).
+    //
+    m_notebook->AddPage(new wxMediaPlayerNotebookPage(this, m_notebook), 
+                        wxT(""), 
+                        true);
+
     //
     //  Create a timer to update our status bar
     //
     //
     //  Create a timer to update our status bar
     //
-    m_timer = new MyTimer(this);
+    m_timer = new wxMediaPlayerTimer(this);
     m_timer->Start(100);
 }
 
 // ----------------------------------------------------------------------------
     m_timer->Start(100);
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame Destructor
+// wxMediaPlayerFrame Destructor
 //
 // 1) Deletes child objects implicitly
 // 2) Delete our timer explicitly
 // ----------------------------------------------------------------------------
 //
 // 1) Deletes child objects implicitly
 // 2) Delete our timer explicitly
 // ----------------------------------------------------------------------------
-MyFrame::~MyFrame()
+wxMediaPlayerFrame::~wxMediaPlayerFrame()
 {
     delete m_timer;
 {
     delete m_timer;
+
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::OnClose
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::OnClose(wxCloseEvent& event)
+{
+    //
+    //  Here we save our info to the registry or whatever
+    //  mechanism the OS uses.
+    //
+    //  This makes it so that when mediaplayer loads up again
+    //  it restores the same files that were in the playlist
+    //  this time, rather than the user manually re-adding them.
+    //
+    //  We need to do conf->DeleteAll() here because by default
+    //  the config still contains the same files as last time
+    //  so we need to clear it before writing our new ones.
+    //
+    //  TODO:  Maybe you could add a menu option to the 
+    //  options menu to delete the configuration on exit -
+    //  all you'd need to do is just remove everything after
+    //  conf->DeleteAll() here
+    //
+    wxMediaPlayerListCtrl* m_playlist = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_playlist;
+
+    wxConfigBase* conf = wxConfigBase::Get();
+    conf->DeleteAll();
+
+    for(int i = 0; i < m_playlist->GetItemCount(); ++i)
+    {
+        wxString* pData = (wxString*) m_playlist->GetItemData(i);
+        wxString s;
+        s << i;
+        conf->Write(s, *(pData));
+        delete pData;
+    }
+
+    event.Skip(); //really close the frame
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::ResetStatus
+// wxMediaPlayerFrame::AddToPlayList
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::AddToPlayList(const wxString& szString)
+{   
+    wxMediaPlayerNotebookPage* currentpage = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage());
+    
+    currentpage->m_playlist->AddToPlayList(szString);    
+}
+
+    
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::ResetStatus
 //
 // Here we just make a simple status string with some useful info about
 // the media that we won't change later - such as the length of the media.
 //
 //
 // Here we just make a simple status string with some useful info about
 // the media that we won't change later - such as the length of the media.
 //
-// We then append some other info that changes in MyTimer::Notify, then
+// We then append some other info that changes in wxMediaPlayerTimer::Notify, then
 // set the status bar to this text.
 //
 // In real applications, you'd want to find a better way to do this,
 // set the status bar to this text.
 //
 // In real applications, you'd want to find a better way to do this,
@@ -499,7 +778,7 @@ MyFrame::~MyFrame()
 //
 // We also reset our loop counter here.
 // ----------------------------------------------------------------------------
 //
 // We also reset our loop counter here.
 // ----------------------------------------------------------------------------
-void MyFrame::ResetStatus()
+void wxMediaPlayerFrame::ResetStatus()
 {
     wxMediaCtrl* currentMediaCtrl = GetCurrentMediaCtrl();
 
 {
     wxMediaCtrl* currentMediaCtrl = GetCurrentMediaCtrl();
 
@@ -513,48 +792,55 @@ void MyFrame::ResetStatus()
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::GetCurrentMediaCtrl
+// wxMediaPlayerFrame::GetCurrentMediaCtrl
 //
 // Obtains the media control of the current page, or NULL if there are no
 // pages open
 // ----------------------------------------------------------------------------
 //
 // Obtains the media control of the current page, or NULL if there are no
 // pages open
 // ----------------------------------------------------------------------------
-wxMediaCtrl* MyFrame::GetCurrentMediaCtrl()
+wxMediaCtrl* wxMediaPlayerFrame::GetCurrentMediaCtrl()
 {
 {
-    wxASSERT(m_notebook->GetCurrentPage() != NULL);
-    return ((MyNotebookPage*)m_notebook->GetCurrentPage())->m_mediactrl;
+    return ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_mediactrl;
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::GetCurrentSlider
+// wxMediaPlayerFrame::GetCurrentSlider
 //
 //
-// Obtains the slider of the current page, or NULL if there are no
-// pages open
+// Obtains the slider of the current page
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-wxSlider*    MyFrame::GetCurrentSlider()
+wxSlider*    wxMediaPlayerFrame::GetCurrentSlider()
 {
 {
-    wxASSERT(m_notebook->GetCurrentPage() != NULL);
-    return ((MyNotebookPage*)m_notebook->GetCurrentPage())->m_slider;
+    return ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_slider;
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnQuit
+// wxMediaPlayerFrame::GetCurrentGauge
+//
+// Obtains the gauge of the current page
+// ----------------------------------------------------------------------------
+wxGauge*    wxMediaPlayerFrame::GetCurrentGauge()
+{
+    return ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_gauge;
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::OnQuit
 //
 // Called from file->quit.
 // Closes this application.
 // ----------------------------------------------------------------------------
 //
 // Called from file->quit.
 // Closes this application.
 // ----------------------------------------------------------------------------
-void MyFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnQuit(wxCommandEvent& WXUNUSED(event))
 {
     // true is to force the frame to close
     Close(true);
 }
 
 // ----------------------------------------------------------------------------
 {
     // true is to force the frame to close
     Close(true);
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnAbout
+// wxMediaPlayerFrame::OnAbout
 //
 // Called from help->about.
 // Gets some info about this application.
 // ----------------------------------------------------------------------------
 //
 // Called from help->about.
 // Gets some info about this application.
 // ----------------------------------------------------------------------------
-void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
 {
     wxString msg;
     msg.Printf( _T("This is a test of wxMediaCtrl.\n")
 {
     wxString msg;
     msg.Printf( _T("This is a test of wxMediaCtrl.\n")
@@ -564,12 +850,12 @@ void MyFrame::OnAbout(wxCommandEvent& WXUNUSED(event))
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnLoop
+// wxMediaPlayerFrame::OnLoop
 //
 // Called from file->loop.
 // Changes the state of whether we want to loop or not.
 // ----------------------------------------------------------------------------
 //
 // Called from file->loop.
 // Changes the state of whether we want to loop or not.
 // ----------------------------------------------------------------------------
-void MyFrame::OnLoop(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnLoop(wxCommandEvent& WXUNUSED(event))
 {
     if(!m_notebook->GetCurrentPage())
     {
 {
     if(!m_notebook->GetCurrentPage())
     {
@@ -577,130 +863,289 @@ void MyFrame::OnLoop(wxCommandEvent& WXUNUSED(event))
         return;
     }
 
         return;
     }
 
-    ((MyNotebookPage*)m_notebook->GetCurrentPage())->m_bLoop =
-            !((MyNotebookPage*)m_notebook->GetCurrentPage())->m_bLoop;
+    ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_bLoop =
+            !((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_bLoop;
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnOpenFileSamePage
+// wxMediaPlayerFrame::OnLoop
+//
+// Called from file->loop.
+// Changes the state of whether we want to loop or not.
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::OnShowInterface(wxCommandEvent& event)
+{
+    if(!m_notebook->GetCurrentPage())
+    {
+        wxMessageBox(wxT("No files are currently open!"));
+        return;
+    }
+
+    GetCurrentMediaCtrl()->ShowPlayerControls(event.IsChecked() ? 
+            wxMEDIACTRLPLAYERCONTROLS_DEFAULT : 
+             wxMEDIACTRLPLAYERCONTROLS_NONE);
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::OnOpenFileSamePage
 //
 // Called from file->openfile.
 // Opens and plays a media file in the current notebook page
 // ----------------------------------------------------------------------------
 //
 // Called from file->openfile.
 // Opens and plays a media file in the current notebook page
 // ----------------------------------------------------------------------------
-void MyFrame::OnOpenFileSamePage(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnOpenFileSamePage(wxCommandEvent& WXUNUSED(event))
 {
     OpenFile(false);
 }
 
 // ----------------------------------------------------------------------------
 {
     OpenFile(false);
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnOpenFileNewPage
+// wxMediaPlayerFrame::OnOpenFileNewPage
 //
 // Called from file->openfileinnewpage.
 // Opens and plays a media file in a new notebook page
 // ----------------------------------------------------------------------------
 //
 // Called from file->openfileinnewpage.
 // Opens and plays a media file in a new notebook page
 // ----------------------------------------------------------------------------
-void MyFrame::OnOpenFileNewPage(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnOpenFileNewPage(wxCommandEvent& WXUNUSED(event))
 {
     OpenFile(true);
 }
 
 // ----------------------------------------------------------------------------
 {
     OpenFile(true);
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OpenFile
-//
-// Code to actually open the media file
+// wxMediaPlayerFrame::OpenFile
 //
 //
-// 1) Create file dialog and ask the user for input file
-// 2) If the user didn't want anything, break out
-// 3) Create a new page if the user wanted one or there isn't a current page
-// 4) Load the media
-// 5) Play the media
-// 6) Reset the text on the status bar
-// 7) Set the slider of the current page to accurately reflect media length
+// Opens a file dialog asking the user for a filename, then
+// calls DoOpenFile which will add the file to the playlist and play it
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-void MyFrame::OpenFile(bool bNewPage)
+void wxMediaPlayerFrame::OpenFile(bool bNewPage)
 {
     wxFileDialog fd(this);
 
     if(fd.ShowModal() == wxID_OK)
     {
 {
     wxFileDialog fd(this);
 
     if(fd.ShowModal() == wxID_OK)
     {
-        if(bNewPage || !m_notebook->GetCurrentPage())
-            m_notebook->AddPage(new MyNotebookPage(m_notebook), fd.GetPath(), true);
-        else //don't forget to update notebook page title
-            m_notebook->SetPageText(m_notebook->GetSelection(), fd.GetPath());
+        DoOpenFile(fd.GetPath(), bNewPage);
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::DoOpenFile
+//
+// Adds the file to our playlist, selects it in the playlist,
+// and then calls DoPlayFile to play it
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::DoOpenFile(const wxString& path, bool bNewPage)
+{
+    if(bNewPage)
+    {
+        m_notebook->AddPage(
+            new wxMediaPlayerNotebookPage(this, m_notebook), 
+            path, 
+            true);
+    }
+
+    wxMediaPlayerListCtrl* m_playlist = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_playlist;
+
+    if(m_nLastFileId != -1)
+        m_playlist->SetItemState(m_nLastFileId, 0, wxLIST_STATE_SELECTED);
+
+    wxListItem newlistitem;
+    newlistitem.SetAlign(wxLIST_FORMAT_LEFT);
+
+    int nID;
+
+    newlistitem.SetId(nID = m_playlist->GetItemCount());
+    newlistitem.SetMask(wxLIST_MASK_DATA | wxLIST_MASK_STATE);
+    newlistitem.SetState(wxLIST_STATE_SELECTED);
+    newlistitem.SetData(new wxString(path));
+
+    m_playlist->InsertItem(newlistitem);
+    m_playlist->SetItem(nID, 0, _T("*"));
+    m_playlist->SetItem(nID, 1, wxFileName(path).GetName());
+    
+    if (nID % 2)
+    {
+        newlistitem.SetBackgroundColour(wxColour(192,192,192));
+        m_playlist->SetItem(newlistitem);
+    }
 
 
-        if( !GetCurrentMediaCtrl()->Load(fd.GetPath()) )
+    DoPlayFile(path);
+     //        m_playlist->Focus(nID);
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::DoPlayFile
+//
+// Pauses the file if its the currently playing file,
+// otherwise it plays the file
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::DoPlayFile(const wxString& path)
+{
+    wxMediaPlayerListCtrl* m_playlist = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_playlist;
+
+    wxListItem listitem;
+    m_playlist->GetSelectedItem(listitem);
+
+    if(listitem.GetData() != NULL && 
+       m_szFile.compare(path) == 0 &&
+       m_nLastFileId == listitem.GetId())
+    {
+        if(GetCurrentMediaCtrl()->GetState() == wxMEDIASTATE_PLAYING)
+    {
+            if( !GetCurrentMediaCtrl()->Pause() )
+                wxMessageBox(wxT("Couldn't pause movie!"));
+            else
+                m_playlist->SetItem(listitem.GetId(), 0, _T("||"));
+        }
+        else
+        {
+            if( !GetCurrentMediaCtrl()->Play() )
+                wxMessageBox(wxT("Couldn't pause movie!"));
+            else
+                m_playlist->SetItem(listitem.GetId(), 0, _T(">"));
+        }
+    }
+    else
+    {
+        m_notebook->SetPageText(m_notebook->GetSelection(), 
+                                wxFileName(path).GetName());
+
+        if(m_nLastFileId != -1)
+            m_playlist->SetItem(m_nLastFileId, 0, _T("*"));
+
+        wxURI uripath(path);
+        if( uripath.IsReference() )
+        {
+            if( !GetCurrentMediaCtrl()->Load(path) )
+            {
+                wxMessageBox(wxT("Couldn't load file!"));
+                m_playlist->SetItem(listitem.GetId(), 0, _T("E"));
+            }
+            else
+            {
+                m_playlist->SetItem(listitem.GetId(), 0, _T("O"));
+            }
+        }
+        else
+        {
+            if( !GetCurrentMediaCtrl()->Load(uripath) )
+            {
             wxMessageBox(wxT("Couldn't load file!"));
             wxMessageBox(wxT("Couldn't load file!"));
+                m_playlist->SetItem(listitem.GetId(), 0, _T("E"));
+            }
+            else
+            {
+                m_playlist->SetItem(listitem.GetId(), 0, _T("O"));
+            }
+        }
+
+        m_nLastFileId = listitem.GetId();
+        m_szFile = path;
+        m_playlist->SetItem(m_nLastFileId, 1, wxFileName(path).GetName());
+        m_playlist->SetItem(m_nLastFileId, 2, wxT(""));
+    }
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::OnMediaLoaded
+//
+// Called when the media is ready to be played - and does
+// so, also gets the length of media and shows that in the list control
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::OnMediaLoaded(wxMediaEvent& WXUNUSED(evt))
+{
+    wxMediaPlayerListCtrl* m_playlist = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_playlist;
+    wxListItem listitem;
+    m_playlist->GetSelectedItem(listitem);
 
         if( !GetCurrentMediaCtrl()->Play() )
 
         if( !GetCurrentMediaCtrl()->Play() )
+    {
             wxMessageBox(wxT("Couldn't play movie!"));
             wxMessageBox(wxT("Couldn't play movie!"));
+        m_playlist->SetItem(listitem.GetId(), 0, _T("E"));
+    }
+    else
+    {
+        m_playlist->SetItem(listitem.GetId(), 0, _T(">"));
+    }
+
+    m_playlist->SetItem(listitem.GetId(), 2, wxString::Format(wxT("%u"), 
+                        (unsigned) GetCurrentMediaCtrl()->Length() / 1000) );
 
         ResetStatus();
 
         GetCurrentSlider()->SetRange(0,
                         (int)(GetCurrentMediaCtrl()->Length() / 1000));
 
         ResetStatus();
 
         GetCurrentSlider()->SetRange(0,
                         (int)(GetCurrentMediaCtrl()->Length() / 1000));
+    GetCurrentGauge()->SetRange((int)(GetCurrentMediaCtrl()->Length() / 1000));   
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::OnSelectBackend
+//
+// Little debugging routine - enter the class name of a backend and it
+// will use that instead of letting wxMediaCtrl search the wxMediaBackend
+// RTTI class list.
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::OnSelectBackend(wxCommandEvent& WXUNUSED(evt))
+{
+    wxString sBackend = wxGetTextFromUser(wxT("Enter backend to use"));
+
+    if(sBackend.empty() == false)  //could have been cancelled by the user
+    {
+        int sel = m_notebook->GetSelection();
+
+        if (sel != wxNOT_FOUND)
+        {
+            m_notebook->DeletePage(sel);
+        }
+
+        m_notebook->AddPage(new wxMediaPlayerNotebookPage(this, m_notebook, 
+                                                        sBackend
+                                                        ), wxT(""), true);
+        DoOpenFile(m_szFile, false);
     }
 }
 
 // ----------------------------------------------------------------------------
     }
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnOpenURLSamePage
+// wxMediaPlayerFrame::OnOpenURLSamePage
 //
 // Called from file->openurl.
 // Opens and plays a media file from a URL in the current notebook page
 // ----------------------------------------------------------------------------
 //
 // Called from file->openurl.
 // Opens and plays a media file from a URL in the current notebook page
 // ----------------------------------------------------------------------------
-void MyFrame::OnOpenURLSamePage(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnOpenURLSamePage(wxCommandEvent& WXUNUSED(event))
 {
     OpenURL(false);
 }
 
 // ----------------------------------------------------------------------------
 {
     OpenURL(false);
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnOpenURLNewPage
+// wxMediaPlayerFrame::OnOpenURLNewPage
 //
 // Called from file->openurlinnewpage.
 // Opens and plays a media file from a URL in a new notebook page
 // ----------------------------------------------------------------------------
 //
 // Called from file->openurlinnewpage.
 // Opens and plays a media file from a URL in a new notebook page
 // ----------------------------------------------------------------------------
-void MyFrame::OnOpenURLNewPage(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnOpenURLNewPage(wxCommandEvent& WXUNUSED(event))
 {
     OpenURL(true);
 }
 
 // ----------------------------------------------------------------------------
 {
     OpenURL(true);
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OpenURL
-//
-// Code to actually open the media file from a URL
+// wxMediaPlayerFrame::OpenURL
 //
 //
-// 1) Create text input dialog and ask the user for an input URL
-// 2) If the user didn't want anything, break out
-// 3) Create a new page if the user wanted one or there isn't a current page
-// 4) Load the media
-// 5) Play the media
-// 6) Reset the text on the status bar
-// 7) Set the slider of the current page to accurately reflect media length
+// Just calls DoOpenFile with the url path - which calls DoPlayFile
+// which handles the real dirty work
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-void MyFrame::OpenURL(bool bNewPage)
+void wxMediaPlayerFrame::OpenURL(bool bNewPage)
 {
 {
-   wxString theURL = wxGetTextFromUser(wxT("Enter the URL that has the movie to play"));
+    wxString sUrl = wxGetTextFromUser(
+        wxT("Enter the URL that has the movie to play")
+                                     );
 
 
-    if(!theURL.empty())
+    if(sUrl.empty() == false) //could have been cancelled by user
     {
     {
-        if(bNewPage || !m_notebook->GetCurrentPage())
-            m_notebook->AddPage(new MyNotebookPage(m_notebook), theURL, true);
-        else //don't forget to update notebook page title
-            m_notebook->SetPageText(m_notebook->GetSelection(), theURL);
-
-        if( !GetCurrentMediaCtrl()->Load(wxURI(theURL)) )
-            wxMessageBox(wxT("Couldn't load URL!"));
-
-        if( !GetCurrentMediaCtrl()->Play() )
-            wxMessageBox(wxT("Couldn't play movie!"));
-
-        ResetStatus();
-
-        GetCurrentSlider()->SetRange(0,
-                        (int)(GetCurrentMediaCtrl()->Length() / 1000));
+        DoOpenFile(sUrl, bNewPage);
     }
 }
 
 // ----------------------------------------------------------------------------
     }
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnCloseCurrentPage
+// wxMediaPlayerFrame::OnCloseCurrentPage
 //
 // Called when the user wants to close the current notebook page
 //
 //
 // Called when the user wants to close the current notebook page
 //
@@ -708,54 +1153,98 @@ void MyFrame::OpenURL(bool bNewPage)
 // 2) If there is no current page, break out
 // 3) Delete the current page
 // ----------------------------------------------------------------------------
 // 2) If there is no current page, break out
 // 3) Delete the current page
 // ----------------------------------------------------------------------------
-void MyFrame::OnCloseCurrentPage(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnCloseCurrentPage(wxCommandEvent& WXUNUSED(event))
 {
 {
+    if( m_notebook->GetPageCount() > 1 )
+    {
     int sel = m_notebook->GetSelection();
 
     if (sel != wxNOT_FOUND)
     {
         m_notebook->DeletePage(sel);
     }
     int sel = m_notebook->GetSelection();
 
     if (sel != wxNOT_FOUND)
     {
         m_notebook->DeletePage(sel);
     }
+    }
+    else
+    {
+        wxMessageBox(wxT("Cannot close main page"));
+    }
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnPlay
+// wxMediaPlayerFrame::OnPlay
 //
 // Called from file->play.
 // Resumes the media if it is paused or stopped.
 // ----------------------------------------------------------------------------
 //
 // Called from file->play.
 // Resumes the media if it is paused or stopped.
 // ----------------------------------------------------------------------------
-void MyFrame::OnPlay(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnPlay(wxCommandEvent& WXUNUSED(event))
 {
 {
-    if(!m_notebook->GetCurrentPage())
+    wxMediaPlayerListCtrl* m_playlist = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_playlist;
+
+    wxListItem listitem;
+    m_playlist->GetSelectedItem(listitem);
+    if (listitem.GetData() == NULL)
     {
     {
-        wxMessageBox(wxT("No files are currently open!"));
+        int nLast = -1;
+        if ((nLast = m_playlist->GetNextItem(nLast,
+                                         wxLIST_NEXT_ALL,
+                                         wxLIST_STATE_DONTCARE)) == -1)
+        {
+            //no items in list
+            wxMessageBox(_T("No items in playlist!"));
         return;
     }
         return;
     }
-
-    if( !GetCurrentMediaCtrl()->Play() )
-        wxMessageBox(wxT("Couldn't play movie!"));
+        wxListItem listitem;
+        listitem.SetId(nLast);
+        m_playlist->GetItem(listitem);
+        listitem.SetMask(listitem.GetMask() | wxLIST_MASK_STATE);
+        listitem.SetState(listitem.GetState() | wxLIST_STATE_SELECTED);
+        m_playlist->SetItem(listitem);
+        wxListEvent event;
+        OnChangeSong(event);
+    }
+    else
+    {
+        wxListEvent event;
+        OnChangeSong(event);
+    }
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnPause
+// wxMediaPlayerFrame::OnKeyDown
 //
 //
-// Called from file->pause.
-// Pauses the media in-place.
+// Deletes all selected files from the playlist if the backspace key is pressed
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-void MyFrame::OnPause(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnKeyDown(wxKeyEvent& event)
 {
 {
-    if(!m_notebook->GetCurrentPage())
+   if(event.GetKeyCode() == WXK_BACK/*DELETE*/)
     {
     {
-        wxMessageBox(wxT("No files are currently open!"));
-        return;
+    wxMediaPlayerListCtrl* m_playlist = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_playlist;
+       //delete all selected items
+       while(true)
+       {
+           wxInt32 nSelectedItem = m_playlist->GetNextItem(
+                    -1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+           if (nSelectedItem == -1)
+               break;
+
+           wxListItem listitem;
+           listitem.SetId(nSelectedItem);
+           m_playlist->GetItem(listitem);
+           delete (wxString*) listitem.GetData();
+
+           m_playlist->DeleteItem(nSelectedItem);
+       }
     }
 
     }
 
-    if( !GetCurrentMediaCtrl()->Pause() )
-        wxMessageBox(wxT("Couldn't pause movie!"));
+   //Could be wxGetTextFromUser or something else important
+   if(event.GetEventObject() != this)
+       event.Skip(); 
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// MyFrame::OnStop
+// wxMediaPlayerFrame::OnStop
 //
 // Called from file->stop.
 // Where it stops depends on whether you can seek in the
 //
 // Called from file->stop.
 // Where it stops depends on whether you can seek in the
@@ -763,8 +1252,15 @@ void MyFrame::OnPause(wxCommandEvent& WXUNUSED(event))
 // otherwise it will appear to be at the end - but it will start over again
 // when Play() is called
 // ----------------------------------------------------------------------------
 // otherwise it will appear to be at the end - but it will start over again
 // when Play() is called
 // ----------------------------------------------------------------------------
-void MyFrame::OnStop(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnStop(wxCommandEvent& WXUNUSED(evt))
 {
 {
+    wxMediaPlayerListCtrl* m_playlist = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_playlist;
+
+    wxListItem listitem;
+    m_playlist->GetSelectedItem(listitem);
+    m_playlist->SetItem(listitem.GetId(), 0, _T("[]"));
+
     if(!m_notebook->GetCurrentPage())
     {
         wxMessageBox(wxT("No files are currently open!"));
     if(!m_notebook->GetCurrentPage())
     {
         wxMessageBox(wxT("No files are currently open!"));
@@ -775,73 +1271,225 @@ void MyFrame::OnStop(wxCommandEvent& WXUNUSED(event))
         wxMessageBox(wxT("Couldn't stop movie!"));
 }
 
         wxMessageBox(wxT("Couldn't stop movie!"));
 }
 
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::OnChangeSong
+//
+// Routine that plays the currently selected file in the playlist.
+// Called when the user actives the song from the playlist,
+// and from other various places in the sample
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::OnChangeSong(wxListEvent& WXUNUSED(evt))
+{
+    wxMediaPlayerListCtrl* m_playlist = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_playlist;
+
+    wxListItem listitem;
+    m_playlist->GetSelectedItem(listitem);
+    DoPlayFile((*((wxString*) listitem.GetData())));
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::OnPrev
+//
+// Tedious wxListCtrl stuff.  Goes to prevous song in list, or if at the 
+// beginning goes to the last in the list.
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::OnPrev(wxCommandEvent& WXUNUSED(event))
+{
+    wxMediaPlayerListCtrl* m_playlist = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_playlist;
+
+    if (m_playlist->GetItemCount() == 0)
+        return;
+
+    wxInt32 nLastSelectedItem = -1;
+    while(true)
+    {
+        wxInt32 nSelectedItem = m_playlist->GetNextItem(nLastSelectedItem,
+                                                     wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+        if (nSelectedItem == -1)
+            break;
+        nLastSelectedItem = nSelectedItem;
+        m_playlist->SetItemState(nSelectedItem, 0, wxLIST_STATE_SELECTED);
+    }
+
+    if (nLastSelectedItem <= 0)
+        nLastSelectedItem = m_playlist->GetItemCount() - 1;
+    else
+        nLastSelectedItem -= 1;
+
+    wxListItem listitem;
+    listitem.SetId(nLastSelectedItem);
+    m_playlist->GetItem(listitem);
+    listitem.SetMask(listitem.GetMask() | wxLIST_MASK_STATE);
+    listitem.SetState(listitem.GetState() | wxLIST_STATE_SELECTED);
+    m_playlist->SetItem(listitem);
+
+    wxListEvent emptyEvent;
+    OnChangeSong(emptyEvent);
+}
+
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-// MyFrame::OnCloseCurrentPage
+// wxMediaPlayerFrame::OnNext
+//
+// Tedious wxListCtrl stuff.  Goes to next song in list, or if at the 
+// end goes to the first in the list.
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::OnNext(wxCommandEvent& WXUNUSED(event))
+{
+    wxMediaPlayerListCtrl* m_playlist = 
+        ((wxMediaPlayerNotebookPage*)m_notebook->GetCurrentPage())->m_playlist;
+
+    if (m_playlist->GetItemCount() == 0)
+        return;
+
+    wxInt32 nLastSelectedItem = -1;
+    while(true)
+    {
+        wxInt32 nSelectedItem = m_playlist->GetNextItem(nLastSelectedItem,
+                                                     wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+        if (nSelectedItem == -1)
+            break;
+        nLastSelectedItem = nSelectedItem;
+        m_playlist->SetItemState(nSelectedItem, 0, wxLIST_STATE_SELECTED);
+    }
+
+    if (nLastSelectedItem == -1)
+        nLastSelectedItem = 0;
+    else
+    {
+        if (nLastSelectedItem == m_playlist->GetItemCount() - 1)
+            nLastSelectedItem = 0;
+        else
+            nLastSelectedItem += 1;
+    }
+
+    wxListItem listitem;
+    listitem.SetId(nLastSelectedItem);
+    m_playlist->GetItem(listitem);
+    listitem.SetMask(listitem.GetMask() | wxLIST_MASK_STATE);
+    listitem.SetState(listitem.GetState() | wxLIST_STATE_SELECTED);
+    m_playlist->SetItem(listitem);
+
+    wxListEvent emptyEvent;
+    OnChangeSong(emptyEvent);
+}
+
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::OnVolumeDown
+//
+// Lowers the volume of the media control by 10%
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::OnVolumeDown(wxCommandEvent& WXUNUSED(event))
+{
+    double dVolume = GetCurrentMediaCtrl()->GetVolume();
+    GetCurrentMediaCtrl()->SetVolume(dVolume < 0.1 ? 0.0 : dVolume - .1);
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::OnVolumeUp
+//
+// Increases the volume of the media control by 10%
+// ----------------------------------------------------------------------------
+void wxMediaPlayerFrame::OnVolumeUp(wxCommandEvent& WXUNUSED(event))
+{
+    double dVolume = GetCurrentMediaCtrl()->GetVolume();
+    GetCurrentMediaCtrl()->SetVolume(dVolume > 0.9 ? 1.0 : dVolume + .1);
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerFrame::OnCloseCurrentPage
 //
 // Called when the user wants to closes the current notebook page
 // ----------------------------------------------------------------------------
 
 //
 // Called when the user wants to closes the current notebook page
 // ----------------------------------------------------------------------------
 
-void MyFrame::OnPageChange(wxNotebookEvent& WXUNUSED(event))
+void wxMediaPlayerFrame::OnPageChange(wxNotebookEvent& WXUNUSED(event))
 {
     ResetStatus();
 }
 
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
 {
     ResetStatus();
 }
 
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
-// MyTimer
+// wxMediaPlayerTimer
 //
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 // ----------------------------------------------------------------------------
 //
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 // ----------------------------------------------------------------------------
-// MyTimer::Notify
+// wxMediaPlayerTimer::Notify
 //
 // 1) Update our slider with the position were are in in the media
 //
 // 1) Update our slider with the position were are in in the media
-// 2) Update our status bar with the base text from MyFrame::ResetStatus,
+// 2) Update our status bar with the base text from wxMediaPlayerFrame::ResetStatus,
 //    append some non-static (changing) info to it, then set the
 //    status bar text to that result
 // ----------------------------------------------------------------------------
 //    append some non-static (changing) info to it, then set the
 //    status bar text to that result
 // ----------------------------------------------------------------------------
-void MyTimer::Notify()
+void wxMediaPlayerTimer::Notify()
 {
 {
-    if (!m_frame->m_notebook->GetCurrentPage()) return;
-
-    wxMediaCtrl* m_mediactrl = ((MyNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_mediactrl;
-    wxSlider* m_slider = ((MyNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_slider;
-    if (!m_mediactrl) return;
-
-    long lPosition = (long)( m_mediactrl->Tell() / 1000 );
-    m_slider->SetValue(lPosition);
-
+    if(m_frame->m_notebook->GetCurrentPage())
+    {
+            // get some control pointers from current notebook page
+        wxMediaCtrl* mediactrl = 
+            ((wxMediaPlayerNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_mediactrl;
+        wxSlider* slider = 
+            ((wxMediaPlayerNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_slider;
+        wxGauge* gauge = 
+            ((wxMediaPlayerNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_gauge;
+
+        // if the slider is being dragged then update it with the song position
+        if(((wxMediaPlayerNotebookPage*)m_frame->m_notebook->GetCurrentPage())->IsBeingDragged() == false)
+        {
+            long lPosition = (long)( mediactrl->Tell() / 1000 );
+            slider->SetValue(lPosition);
+        }
+
+        // update guage with value from slider
+        gauge->SetValue(slider->GetValue());
 #if wxUSE_STATUSBAR
 #if wxUSE_STATUSBAR
-    m_frame->SetStatusText(wxString::Format(
-                     _T("%s Pos:%u State:%s Loops:%i"),
-                     m_frame->m_basestatus.c_str(),
-                     (unsigned int)lPosition,
-                     wxGetMediaStateText(m_mediactrl->GetState()),
-                    ((MyNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_nLoops
-
-                                            )
-                           );
-#endif
-
+        m_frame->SetStatusText(wxString::Format(
+                        wxT("%s Pos:%u State:%s Loops:%i D/T:[%i]/[%i] V:%i%%"),
+                        m_frame->m_basestatus.c_str(),
+                        slider->GetValue(),
+                        wxGetMediaStateText(mediactrl->GetState()),
+                        ((wxMediaPlayerNotebookPage*)m_frame->m_notebook->GetCurrentPage())->m_nLoops,
+                        (int)mediactrl->GetDownloadProgress(),
+                        (int)mediactrl->GetDownloadTotal(),
+                        (int)(mediactrl->GetVolume() * 100)));
+#endif // wxUSE_STATUSBAR
+    }
 }
 
 
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
 }
 
 
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
-// MyNotebookPage
+// wxMediaPlayerNotebookPage
 //
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 // ----------------------------------------------------------------------------
 //
 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 // ----------------------------------------------------------------------------
-// MyNotebookPage Constructor
+// wxMediaPlayerNotebookPage Constructor
 //
 // Creates a media control and slider and adds it to this panel,
 // along with some sizers for positioning
 // ----------------------------------------------------------------------------
 
 //
 // Creates a media control and slider and adds it to this panel,
 // along with some sizers for positioning
 // ----------------------------------------------------------------------------
 
-MyNotebookPage::MyNotebookPage(wxNotebook* theBook) :
-    wxPanel(theBook, wxID_ANY), m_nLoops(0), m_bLoop(false)
+wxMediaPlayerNotebookPage::wxMediaPlayerNotebookPage(wxMediaPlayerFrame* parentFrame,
+                                                      wxNotebook* theBook, 
+                                                const wxString& szBackend) :
+    wxPanel(theBook, wxID_ANY), m_bIsBeingDragged(false),
+        m_nLoops(0), m_bLoop(false), m_parentFrame(parentFrame)
 {
 {
+
+    //
+    //  Layout
+    //
+    //  [wxMediaCtrl]
+    //  [playlist]
+    //  [5 control buttons]
+    //  [slider]
+    //  [gauge]
+    //    
+
     //
     //  Create and attach the sizer
     //
     //
     //  Create and attach the sizer
     //
@@ -857,12 +1505,109 @@ MyNotebookPage::MyNotebookPage(wxNotebook* theBook) :
     m_mediactrl = new wxMediaCtrl();
 
     //  Make sure creation was successful
     m_mediactrl = new wxMediaCtrl();
 
     //  Make sure creation was successful
-    bool bOK = m_mediactrl->Create(this, wxID_MEDIACTRL);
+    bool bOK = m_mediactrl->Create(this, wxID_MEDIACTRL, wxEmptyString,
+                                    wxDefaultPosition, wxDefaultSize, 0,
+//you could specify a macrod backend here like
+//wxMEDIABACKEND_QUICKTIME);
+                                   szBackend);
+//you could change the cursor here like
+//    m_mediactrl->SetCursor(wxCURSOR_BLANK);
+//note that this may not effect it if SetPlayerControls
+//is set to something else than wxMEDIACTRLPLAYERCONTROLS_NONE
     wxASSERT_MSG(bOK, wxT("Could not create media control!"));
     wxUnusedVar(bOK);
 
     sizer->Add(m_mediactrl, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 5);
 
     wxASSERT_MSG(bOK, wxT("Could not create media control!"));
     wxUnusedVar(bOK);
 
     sizer->Add(m_mediactrl, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 5);
 
+    //
+    //  Create the playlist/listctrl
+    //
+    m_playlist = new wxMediaPlayerListCtrl();
+    m_playlist->Create(this, wxID_LISTCTRL, wxDefaultPosition, 
+                    wxDefaultSize,
+                    wxLC_REPORT //wxLC_LIST
+                    | wxSUNKEN_BORDER);
+
+    //  Set the background of our listctrl to white
+    m_playlist->SetBackgroundColour(wxColour(255,255,255));
+
+    //  The layout of the headers of the listctrl are like
+    //  |   | File               |  Length
+    //
+    //  Where Column one is a character representing the state the file is in:
+    //  * - not the current file
+    //  E - Error has occured 
+    //  > - Currently Playing
+    //  [] - Stopped
+    //  || - Paused
+    //  (( - Volume Down 10%
+    //  )) - Volume Up 10%
+    //
+    //  Column two is the name of the file
+    //
+    //  Column three is the length in seconds of the file
+    m_playlist->InsertColumn(0,_(""), wxLIST_FORMAT_CENTER, 20);
+    m_playlist->InsertColumn(1,_("File"), wxLIST_FORMAT_LEFT, /*wxLIST_AUTOSIZE_USEHEADER*/305);
+    m_playlist->InsertColumn(2,_("Length"), wxLIST_FORMAT_CENTER, 75);
+
+    m_playlist->SetDropTarget(new wxPlayListDropTarget(*m_playlist));
+    sizer->Add(m_playlist, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND, 5);
+
+    //
+    //  Here we load the our configuration - 
+    //  in our case we load all the files that were left in
+    //  the playlist the last time the user closed our application
+    //
+    //  TODO:  This is probably not the best practice since 
+    //  the user will load multiple notebook pages with multiple
+    //  wxMediaCtrl elements.
+    //
+    //  As an exercise to the reader try modifying it so that
+    //  it properly loads the playlist for each page without
+    //  conflicting (loading the same data) with the other ones.
+    //
+    wxConfigBase* conf = wxConfigBase::Get(); 
+    wxString key, outstring; 
+    for(int i = 0; ; ++i) 
+    { 
+        key.clear(); 
+        key << i; 
+        if(!conf->Read(key, &outstring)) 
+            break; 
+        m_playlist->AddToPlayList(outstring); 
+    } 
+
+    //
+    //  Create the control buttons  
+    //  TODO/FIXME/HACK:  This part about sizers is really a nice hack
+    //                    and probably isn't proper
+    //
+    wxBoxSizer* horsizer1 = new wxBoxSizer(wxHORIZONTAL);
+    wxBoxSizer* vertsizer = new wxBoxSizer(wxHORIZONTAL);
+
+    m_prevButton = new wxButton();
+    m_playButton = new wxButton();
+    m_stopButton = new wxButton();
+    m_nextButton = new wxButton();
+    m_vdButton = new wxButton();
+    m_vuButton = new wxButton();
+
+    m_prevButton->Create(this, wxID_BUTTONPREV, _T("|<"));
+    m_playButton->Create(this, wxID_BUTTONPLAY, _T(">"));
+    m_stopButton->Create(this, wxID_BUTTONSTOP, _T("[]"));
+    m_nextButton->Create(this, wxID_BUTTONNEXT, _T(">|"));
+    m_vdButton->Create(this, wxID_BUTTONVD, _T("(("));
+    m_vuButton->Create(this, wxID_BUTTONVU, _T("))"));
+    vertsizer->Add(m_prevButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+    vertsizer->Add(m_playButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+    vertsizer->Add(m_stopButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+    vertsizer->Add(m_nextButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+    vertsizer->Add(m_vdButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+    vertsizer->Add(m_vuButton, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+    horsizer1->Add(vertsizer, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+    sizer->Add(horsizer1, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
+
+
     //
     //  Create our slider
     //
     //
     //  Create our slider
     //
@@ -873,32 +1618,99 @@ MyNotebookPage::MyNotebookPage(wxNotebook* theBook) :
                             wxSL_HORIZONTAL );
     sizer->Add(m_slider, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND , 5);
 
                             wxSL_HORIZONTAL );
     sizer->Add(m_slider, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND , 5);
 
+
+    //
+    //  Create the gauge
+    //
+    m_gauge = new wxGauge();
+    m_gauge->Create(this, wxID_GAUGE, 0, wxDefaultPosition, wxDefaultSize,
+                        wxGA_HORIZONTAL | wxGA_SMOOTH);
+    sizer->Add(m_gauge, 0, wxALIGN_CENTER_HORIZONTAL|wxALL|wxEXPAND , 5);
+        
+    //
+    // ListCtrl events
+    //
+    this->Connect( wxID_LISTCTRL, wxEVT_COMMAND_LIST_ITEM_ACTIVATED, 
+        wxListEventHandler(wxMediaPlayerFrame::OnChangeSong),
+        (wxObject*)0, parentFrame);
+
     //
     // Slider events
     //
     //
     // Slider events
     //
-    this->Connect(wxID_SLIDER, wxEVT_COMMAND_SLIDER_UPDATED,
-                  wxCommandEventHandler(MyNotebookPage::OnSeek));
+    this->Connect(wxID_SLIDER, wxEVT_SCROLL_THUMBTRACK,
+                  wxScrollEventHandler(wxMediaPlayerNotebookPage::OnBeginSeek));
+    this->Connect(wxID_SLIDER, wxEVT_SCROLL_THUMBRELEASE,
+                  wxScrollEventHandler(wxMediaPlayerNotebookPage::OnEndSeek));
 
     //
     // Media Control events
     //
     this->Connect(wxID_MEDIACTRL, wxEVT_MEDIA_FINISHED,
 
     //
     // Media Control events
     //
     this->Connect(wxID_MEDIACTRL, wxEVT_MEDIA_FINISHED,
-                  wxMediaEventHandler(MyNotebookPage::OnMediaFinished));
+                  wxMediaEventHandler(wxMediaPlayerNotebookPage::OnMediaFinished));
+    this->Connect(wxID_MEDIACTRL, wxEVT_MEDIA_LOADED,
+                  wxMediaEventHandler(wxMediaPlayerFrame::OnMediaLoaded), 
+                  (wxObject*)0, parentFrame);
+
+    //
+    // Button events
+    //
+    this->Connect( wxID_BUTTONPREV, wxEVT_COMMAND_BUTTON_CLICKED, 
+        wxCommandEventHandler(wxMediaPlayerFrame::OnPrev),
+        (wxObject*)0, parentFrame);
+    this->Connect( wxID_BUTTONPLAY, wxEVT_COMMAND_BUTTON_CLICKED, 
+        wxCommandEventHandler(wxMediaPlayerFrame::OnPlay),
+        (wxObject*)0, parentFrame);
+    this->Connect( wxID_BUTTONSTOP, wxEVT_COMMAND_BUTTON_CLICKED, 
+        wxCommandEventHandler(wxMediaPlayerFrame::OnStop),
+        (wxObject*)0, parentFrame);
+    this->Connect( wxID_BUTTONNEXT, wxEVT_COMMAND_BUTTON_CLICKED, 
+        wxCommandEventHandler(wxMediaPlayerFrame::OnNext),
+        (wxObject*)0, parentFrame);
+    this->Connect( wxID_BUTTONVD, wxEVT_COMMAND_BUTTON_CLICKED, 
+        wxCommandEventHandler(wxMediaPlayerFrame::OnVolumeDown),
+        (wxObject*)0, parentFrame);
+    this->Connect( wxID_BUTTONVU, wxEVT_COMMAND_BUTTON_CLICKED, 
+        wxCommandEventHandler(wxMediaPlayerFrame::OnVolumeUp),
+        (wxObject*)0, parentFrame);
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
-// MyNotebook::OnSeek
+// MyNotebook::OnBeginSeek
+//
+// Sets m_bIsBeingDragged to true to stop the timer from changing the position
+// of our slider
+// ----------------------------------------------------------------------------
+void wxMediaPlayerNotebookPage::OnBeginSeek(wxScrollEvent& WXUNUSED(event))
+{
+    m_bIsBeingDragged = true;
+}
+
+// ----------------------------------------------------------------------------
+// MyNotebook::OnEndSeek
 //
 // Called from file->seek.
 // Called when the user moves the slider -
 // seeks to a position within the media
 //
 // Called from file->seek.
 // Called when the user moves the slider -
 // seeks to a position within the media
+// then sets m_bIsBeingDragged to false to ok the timer to change the position
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-void MyNotebookPage::OnSeek(wxCommandEvent& WXUNUSED(event))
+void wxMediaPlayerNotebookPage::OnEndSeek(wxScrollEvent& WXUNUSED(event))
 {
     if( m_mediactrl->Seek(
             m_slider->GetValue() * 1000
                                    ) == wxInvalidOffset )
         wxMessageBox(wxT("Couldn't seek in movie!"));
 {
     if( m_mediactrl->Seek(
             m_slider->GetValue() * 1000
                                    ) == wxInvalidOffset )
         wxMessageBox(wxT("Couldn't seek in movie!"));
+
+    m_bIsBeingDragged = false;
+}
+
+// ----------------------------------------------------------------------------
+// wxMediaPlayerNotebookPage::IsBeingDragged
+//
+// Returns true if the user is dragging the slider
+// ----------------------------------------------------------------------------
+bool wxMediaPlayerNotebookPage::IsBeingDragged()
+{   
+    return m_bIsBeingDragged;   
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -907,15 +1719,22 @@ void MyNotebookPage::OnSeek(wxCommandEvent& WXUNUSED(event))
 // Called when the media stops playing.
 // Here we loop it if the user wants to (has been selected from file menu)
 // ----------------------------------------------------------------------------
 // Called when the media stops playing.
 // Here we loop it if the user wants to (has been selected from file menu)
 // ----------------------------------------------------------------------------
-void MyNotebookPage::OnMediaFinished(wxMediaEvent& WXUNUSED(event))
+void wxMediaPlayerNotebookPage::OnMediaFinished(wxMediaEvent& WXUNUSED(event))
 {
     if(m_bLoop)
     {
         if ( !m_mediactrl->Play() )
 {
     if(m_bLoop)
     {
         if ( !m_mediactrl->Play() )
+        {
             wxMessageBox(wxT("Couldn't loop movie!"));
             wxMessageBox(wxT("Couldn't loop movie!"));
+            m_playlist->SetItem(m_parentFrame->m_nLastFileId, 0, _T("E"));        
+        }
         else
             ++m_nLoops;
     }
         else
             ++m_nLoops;
     }
+    else
+    {
+        m_playlist->SetItem(m_parentFrame->m_nLastFileId, 0, _T("[]"));        
+    }
 }
 
 //
 }
 
 //
index aeadd684516a716cb9cc25b74502e4cb40cc56f5..59a420aa81541133ada91900f08e4a717313cefc 100644 (file)
@@ -52,6 +52,7 @@ IMPLEMENT_CLASS(wxMediaCtrl, wxControl);
 IMPLEMENT_CLASS(wxMediaBackend, wxObject);
 IMPLEMENT_DYNAMIC_CLASS(wxMediaEvent, wxEvent);
 DEFINE_EVENT_TYPE(wxEVT_MEDIA_FINISHED);
 IMPLEMENT_CLASS(wxMediaBackend, wxObject);
 IMPLEMENT_DYNAMIC_CLASS(wxMediaEvent, wxEvent);
 DEFINE_EVENT_TYPE(wxEVT_MEDIA_FINISHED);
+DEFINE_EVENT_TYPE(wxEVT_MEDIA_LOADED);
 DEFINE_EVENT_TYPE(wxEVT_MEDIA_STOP);
 
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 DEFINE_EVENT_TYPE(wxEVT_MEDIA_STOP);
 
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@@ -281,6 +282,8 @@ wxMediaCtrl::~wxMediaCtrl()
 //---------------------------------------------------------------------------
 // wxMediaCtrl::Load (file version)
 // wxMediaCtrl::Load (URL version)
 //---------------------------------------------------------------------------
 // wxMediaCtrl::Load (file version)
 // wxMediaCtrl::Load (URL version)
+// wxMediaCtrl::Load (URL & Proxy version)
+// wxMediaCtrl::Load (wxInputStream version)
 //
 // Here we call load of the backend - keeping
 // track of whether it was successful or not - which
 //
 // Here we call load of the backend - keeping
 // track of whether it was successful or not - which
@@ -300,6 +303,13 @@ bool wxMediaCtrl::Load(const wxURI& location)
     return false;
 }
 
     return false;
 }
 
+bool wxMediaCtrl::Load(const wxURI& location, const wxURI& proxy)
+{
+    if(m_imp)
+        return (m_bLoaded = m_imp->Load(location, proxy));
+    return false;
+}
+
 //---------------------------------------------------------------------------
 // wxMediaCtrl::Play
 // wxMediaCtrl::Pause
 //---------------------------------------------------------------------------
 // wxMediaCtrl::Play
 // wxMediaCtrl::Pause
@@ -313,6 +323,9 @@ bool wxMediaCtrl::Load(const wxURI& location)
 // wxMediaCtrl::DoGetBestSize
 // wxMediaCtrl::SetVolume
 // wxMediaCtrl::GetVolume
 // wxMediaCtrl::DoGetBestSize
 // wxMediaCtrl::SetVolume
 // wxMediaCtrl::GetVolume
+// wxMediaCtrl::ShowInterface
+// wxMediaCtrl::GetDownloadProgress
+// wxMediaCtrl::GetDownloadTotal
 //
 // 1) Check to see whether the backend exists and is loading
 // 2) Call the backend's version of the method, returning success
 //
 // 1) Check to see whether the backend exists and is loading
 // 2) Call the backend's version of the method, returning success
@@ -418,6 +431,27 @@ bool wxMediaCtrl::SetVolume(double dVolume)
     return false;
 }
 
     return false;
 }
 
+bool wxMediaCtrl::ShowPlayerControls(wxMediaCtrlPlayerControls flags) 
+{
+    if(m_imp)
+        return m_imp->ShowPlayerControls(flags);
+    return false;
+}
+
+wxFileOffset wxMediaCtrl::GetDownloadProgress()
+{
+    if(m_imp && m_bLoaded)
+        return (wxFileOffset) m_imp->GetDownloadProgress().ToLong();
+    return wxInvalidOffset;
+}
+
+wxFileOffset wxMediaCtrl::GetDownloadTotal()
+{
+    if(m_imp && m_bLoaded)
+        return (wxFileOffset) m_imp->GetDownloadTotal().ToLong();
+    return wxInvalidOffset;
+}
+
 //---------------------------------------------------------------------------
 // wxMediaCtrl::DoMoveWindow
 //
 //---------------------------------------------------------------------------
 // wxMediaCtrl::DoMoveWindow
 //
index 623a4d9c01e0b2e8c440dd7ca090186edc837b07..d2eb4c053f6e567ba233ce85d3b92c6047bc6876 100644 (file)
@@ -118,6 +118,9 @@ public:
     virtual double GetPlaybackRate();
     virtual bool SetPlaybackRate(double dRate);
 
     virtual double GetPlaybackRate();
     virtual bool SetPlaybackRate(double dRate);
 
+    virtual double GetVolume();
+    virtual bool SetVolume(double);
+
     void Cleanup();
     void FinishLoad();
 
     void Cleanup();
     void FinishLoad();
 
@@ -477,6 +480,11 @@ void wxQTMediaBackend::FinishLoad()
     m_ctrl->GetParent()->Layout();
     m_ctrl->GetParent()->Refresh();
     m_ctrl->GetParent()->Update();
     m_ctrl->GetParent()->Layout();
     m_ctrl->GetParent()->Refresh();
     m_ctrl->GetParent()->Update();
+
+    //send loaded event
+    wxMediaEvent theEvent(wxEVT_MEDIA_LOADED,
+                            m_ctrl->GetId());
+    m_ctrl->AddPendingEvent(theEvent);
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
@@ -580,6 +588,53 @@ wxLongLong wxQTMediaBackend::GetPosition()
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
+// wxQTMediaBackend::GetVolume
+//
+// Gets the volume through GetMovieVolume - which returns a 16 bit short -
+//
+// +--------+--------+
+// +   (1)  +   (2)  +
+// +--------+--------+
+//
+// (1) first 8 bits are value before decimal
+// (2) second 8 bits are value after decimal
+//
+// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
+// 1 (full gain and sound)
+//---------------------------------------------------------------------------
+double wxQTMediaBackend::GetVolume()
+{
+    short sVolume = GetMovieVolume(m_movie);
+
+    if(sVolume & (128 << 8)) //negative - no sound
+        return 0.0;
+
+    return (sVolume & (127 << 8)) ? 1.0 : ((double)(sVolume & 255)) / 255.0;
+}
+
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::SetVolume
+//
+// Sets the volume through SetMovieVolume - which takes a 16 bit short -
+//
+// +--------+--------+
+// +   (1)  +   (2)  +
+// +--------+--------+
+//
+// (1) first 8 bits are value before decimal
+// (2) second 8 bits are value after decimal
+//
+// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
+// 1 (full gain and sound)
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::SetVolume(double dVolume)
+{
+    short sVolume = (short) (dVolume >= .9999 ? 1 << 8 : (dVolume * 255) );
+    SetMovieVolume(m_movie, sVolume);
+    return true;
+}
+ //---------------------------------------------------------------------------
 // wxQTMediaBackend::GetDuration
 //
 // Calls GetMovieDuration
 // wxQTMediaBackend::GetDuration
 //
 // Calls GetMovieDuration
index 6d56bfa700df7c41993fc4fc35dbc15760a56644..c0b8ad8306c4d025cb28a43acb98917080f071b8 100644 (file)
@@ -29,7 +29,7 @@
 #endif
 
 //---------------------------------------------------------------------------
 #endif
 
 //---------------------------------------------------------------------------
-// Includes
+// MediaCtrl include
 //---------------------------------------------------------------------------
 #include "wx/mediactrl.h"
 
 //---------------------------------------------------------------------------
 #include "wx/mediactrl.h"
 
 //---------------------------------------------------------------------------
 #if wxUSE_MEDIACTRL
 
 //---------------------------------------------------------------------------
 #if wxUSE_MEDIACTRL
 
-#include "wx/dcclient.h"
-#include "wx/thread.h"
+//---------------------------------------------------------------------------
+// WX Includes
+//---------------------------------------------------------------------------
+#include "wx/log.h"         //wxLogDebug
+#include "wx/math.h"        //log10 & pow
+#include "wx/msw/private.h" //user info and wndproc setting/getting
 
 //---------------------------------------------------------------------------
 
 //---------------------------------------------------------------------------
-// Externals (somewhere in src/msw/app.cpp)
+// Externals (somewhere in src/msw/app.cpp and src/msw/window.cpp)
 //---------------------------------------------------------------------------
 extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance(void);
 #ifdef __WXWINCE__
 //---------------------------------------------------------------------------
 extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance(void);
 #ifdef __WXWINCE__
@@ -51,6 +55,9 @@ extern WXDLLIMPEXP_CORE       wxChar *wxCanvasClassName;
 extern WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName;
 #endif
 
 extern WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName;
 #endif
 
+LRESULT WXDLLIMPEXP_CORE APIENTRY _EXPORT wxWndProc(HWND hWnd, UINT message,
+                                   WPARAM wParam, LPARAM lParam);
+
 //===========================================================================
 //  BACKEND DECLARATIONS
 //===========================================================================
 //===========================================================================
 //  BACKEND DECLARATIONS
 //===========================================================================
@@ -60,75 +67,35 @@ extern WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName;
 //  wxAMMediaBackend
 //
 //---------------------------------------------------------------------------
 //  wxAMMediaBackend
 //
 //---------------------------------------------------------------------------
-//
-//####################THE BIG DIRECTSHOW OVERVIEW############################
-//
-//
-//  OK... this deserves its own little tutorial.  Knowledge of COM and class
-//  factories is assumed throughout this code.
-//
-//  Basically, the way directshow works is that you tell it to render
-//  a file, and it builds and connects a bunch of filters together.
-//
-//  There are many, many ways to do this.
-//
-//  WAYS TO RENDER A FILE (URLS WORK IN DS ALSO)
-//
-//  1)  Create an instance of IGraphBuilder and call RenderFile on it
-//  2)  Create an instance of IMediaControl and call RenderFile on it
-//  3)  Create an instance of IAMMultiMediaStream, call
-//      IAMMultiMediaStream::AddStream and pass an IDirectDraw instance for
-//      the video, and pass an IDirectSound(Buffer?) instance or use the
-//      default sound renderer, then call RenderFile or RenderMoniker
-//  4)  Create a Moniker instance for the file and create and build
-//      all of the filtergraph manually
-//
-//  Our issue here is that we can't use the default representation of 1 and 2
-//  because the IVideoWindow instance hogs a lot of the useful window
-//  messages such as WM_SETCURSOR.
-//
-//  Solution #1 was to use #3 by creating a seperate IDirectDraw instance
-//  for our window and blitting to that through a thread... unfortunately
-//  the blitting resizing is very low quality and its quite slow.
-//
-//  The current way is to use windowless rendering and have directshow
-//  do all the DirectDraw-style clipping to our window
-//
-//  ~~~~~~~~~~~~~~AFTER RENDERING THE FILE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//
-//  When done rendering the file, we need to get several interfaces from
-//  either a IMediaControl or IGraphBuilder instance -
-//
-//  IMediaPosition - we can set the rate with this... we can also get
-//  positions and set positions through this with REFTIME (double) instead
-//  of the normal LONGLONG that IAMMultiMediaStream and IMediaControl use
-//
-//  IBasicAudio - we need this for setting/getting the volume
-//
-//  Interfaces that we don't use but might be useful one day -
-//
-//  IDirectDrawVideo - you can get this through the IFilter returned
-//  from L"Video Renderer" filter from FindFilter on the IGraphBuilder.
-//  Through this we can set the IDirectDraw instance DrawShow uses.
-//
-//  ~~~~~~~~~~~~~~STOPPING~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-//
-//  There are two ways we can do this -
-//  1)  Have a thread compare the current position to the end position
-//  about every 10 milliseconds
-//  2)  Have IMediaSeekingEx send a message to a windowproc or signal a
-//  windows event
-//
-//  Note that we can do these both, I.E. if an IMediaSeekingEx interface
-//  is unavailable we can check the position instead of an event
-//
-//---------------------------------------------------------------------------
 
 //---------------------------------------------------------------------------
 //  COM includes
 //---------------------------------------------------------------------------
 #include "wx/msw/ole/oleutils.h" //wxBasicString, IID etc.
 #include "wx/msw/ole/uuid.h" //IID etc..
 
 //---------------------------------------------------------------------------
 //  COM includes
 //---------------------------------------------------------------------------
 #include "wx/msw/ole/oleutils.h" //wxBasicString, IID etc.
 #include "wx/msw/ole/uuid.h" //IID etc..
+#include <oleidl.h>
+#include <olectl.h>
+#include <exdisp.h>
+#include <docobj.h>
+
+//
+//  These defines are from another ole header - but its not in the
+//  latest sdk.  Also the ifndef DISPID_READYSTATE is here because at
+//  least on my machine with the latest sdk olectl.h defines these 3
+//
+#ifndef DISPID_READYSTATE
+    #define DISPID_READYSTATE                               -525
+    #define DISPID_READYSTATECHANGE                         -609
+    #define DISPID_AMBIENT_TRANSFERPRIORITY                 -728
+#endif
+
+#define DISPID_AMBIENT_OFFLINEIFNOTCONNECTED            -5501
+#define DISPID_AMBIENT_SILENT                           -5502
+
+#ifndef DISPID_AMBIENT_CODEPAGE
+#   define DISPID_AMBIENT_CODEPAGE                         -725
+#   define DISPID_AMBIENT_CHARSET                          -727
+#endif
 
 //---------------------------------------------------------------------------
 //  COM compatability definitions
 
 //---------------------------------------------------------------------------
 //  COM compatability definitions
@@ -142,344 +109,709 @@ extern WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName;
 #ifndef PURE
 #define PURE = 0
 #endif
 #ifndef PURE
 #define PURE = 0
 #endif
+#ifndef __RPC_FAR
+#define __RPC_FAR FAR
+#endif
+
 //---------------------------------------------------------------------------
 //  IIDS - used by CoCreateInstance and IUnknown::QueryInterface
 //---------------------------------------------------------------------------
 //  IIDS - used by CoCreateInstance and IUnknown::QueryInterface
-//  Dumped from amstream.idl, quartz.idl, direct draw and with some
-//  confirmation from WINE
+//
+//  [idl name]          [idl decription]
+//  amcompat.idl        Microsoft Active Movie Control (Ver 2.0)
+//  nscompat.idl        Microsoft NetShow Player (Ver 1.0)
+//  msdxm.idl           Windows Media Player (Ver 1.0)
+//  quartz.idl
+//
+//  First, when I say I "from XXX.idl", I mean I go into the COM Browser
+//  ($Microsoft Visual Studio$/Common/Tools/OLEVIEW.EXE), open
+//  "type libraries", open a specific type library (for quartz for example its
+//  "ActiveMovie control type library (V1.0)"), save it as an .idl, compile the
+//  idl using the midl compiler that comes with visual studio
+//  ($Microsoft Visual Studio$/VC98/bin/midl.exe on VC6) with the /h argument
+//  to make it generate stubs (a .h & .c file), then clean up the generated
+//  interfaces I want with the STDMETHOD wrappers and then put them into
+//  mediactrl.cpp.
+//
+//  According to the MSDN docs, IMediaPlayer requires Windows 98 SE
+//  or greater.  NetShow is available on Windows 3.1 and I'm guessing
+//  IActiveMovie is too.  IMediaPlayer is essentially the Windows Media
+//  Player 6.4 SDK.
 //
 //  Some of these are not used but are kept here for future reference anyway
 //---------------------------------------------------------------------------
 //
 //  Some of these are not used but are kept here for future reference anyway
 //---------------------------------------------------------------------------
+const IID IID_IActiveMovie          = {0x05589FA2,0xC356,0x11CE,{0xBF,0x01,0x00,0xAA,0x00,0x55,0x59,0x5A}};
+const IID IID_IActiveMovie2         = {0xB6CD6554,0xE9CB,0x11D0,{0x82,0x1F,0x00,0xA0,0xC9,0x1F,0x9C,0xA0}};
+const IID IID_IActiveMovie3         = {0x265EC140,0xAE62,0x11D1,{0x85,0x00,0x00,0xA0,0xC9,0x1F,0x9C,0xA0}};
 
 
-//QUARTZ
-const IID LIBID_QuartzTypeLib = {0x56A868B0,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IAMCollection = {0x56A868B9,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IMediaControl = {0x56A868B1,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IMediaEvent = {0x56A868B6,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IMediaEventEx = {0x56A868C0,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IMediaPosition = {0x56A868B2,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IBasicAudio = {0x56A868B3,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IVideoWindow = {0x56A868B4,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IBasicVideo = {0x56A868B5,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IBasicVideo2 = {0x329BB360,0xF6EA,0x11D1,{0x90,0x38,0x00,0xA0,0xC9,0x69,0x72,0x98}};
-const IID IID_IDeferredCommand = {0x56A868B8,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IQueueCommand = {0x56A868B7,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IFilterInfo = {0x56A868BA,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IRegFilterInfo = {0x56A868BB,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IMediaTypeInfo = {0x56A868BC,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IPinInfo = {0x56A868BD,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
-const IID IID_IAMStats = {0xBC9BCF80,0xDCD2,0x11D2,{0xAB,0xF6,0x00,0xA0,0xC9,0x05,0xF3,0x75}};
-const CLSID CLSID_FilgraphManager = {0xE436EBB3,0x524F,0x11CE,{0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
+const IID IID_INSOPlay              = {0x2179C5D1,0xEBFF,0x11CF,{0xB6,0xFD,0x00,0xAA,0x00,0xB4,0xE2,0x20}};
+const IID IID_INSPlay               = {0xE7C4BE80,0x7960,0x11D0,{0xB7,0x27,0x00,0xAA,0x00,0xB4,0xE2,0x20}};
+const IID IID_INSPlay1              = {0x265EC141,0xAE62,0x11D1,{0x85,0x00,0x00,0xA0,0xC9,0x1F,0x9C,0xA0}};
+
+const IID IID_IMediaPlayer          = {0x22D6F311,0xB0F6,0x11D0,{0x94,0xAB,0x00,0x80,0xC7,0x4C,0x7E,0x95}};
+const IID IID_IMediaPlayer2         = {0x20D4F5E0,0x5475,0x11D2,{0x97,0x74,0x00,0x00,0xF8,0x08,0x55,0xE6}};
 
 
-//AMSTREAM
-const CLSID CLSID_AMMultiMediaStream = {0x49C47CE5, 0x9BA4, 0x11D0,{0x82, 0x12, 0x00, 0xC0, 0x4F, 0xC3, 0x2C, 0x45}};
-const IID IID_IAMMultiMediaStream = {0xBEBE595C, 0x9A6F, 0x11D0,{0x8F, 0xDE, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
-const IID IID_IDirectDrawMediaStream = {0xF4104FCE, 0x9A70, 0x11D0,{0x8F, 0xDE, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
-const GUID MSPID_PrimaryVideo = {0xa35FF56A, 0x9FDA, 0x11D0,{0x8F, 0xDF, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
-const GUID MSPID_PrimaryAudio = {0xa35FF56B, 0x9FDA, 0x11D0,{0x8F, 0xDF, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
+const CLSID CLSID_ActiveMovie       = {0x05589FA1,0xC356,0x11CE,{0xBF,0x01,0x00,0xAA,0x00,0x55,0x59,0x5A}};
+const CLSID CLSID_MediaPlayer       = {0x22D6F312,0xB0F6,0x11D0,{0x94,0xAB,0x00,0x80,0xC7,0x4C,0x7E,0x95}};
+const CLSID CLSID_NSPlay            = {0x2179C5D3,0xEBFF,0x11CF,{0xB6,0xFD,0x00,0xAA,0x00,0xB4,0xE2,0x20}};
 
 
-//DDRAW
-const IID IID_IDirectDraw = {0x6C14DB80,0xA733,0x11CE,{0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60}};
-const CLSID CLSID_DirectDraw = {0xD7B70EE0,0x4340,0x11CF,{0xB0,0x63,0x00,0x20,0xAF,0xC2,0xCD,0x35}};
+const IID IID_IAMOpenProgress = {0x8E1C39A1, 0xDE53, 0x11CF,{0xAA, 0x63, 0x00, 0x80, 0xC7, 0x44, 0x52, 0x8D}};
+
+// QUARTZ
+const CLSID CLSID_FilgraphManager = {0xE436EBB3,0x524F,0x11CE,{0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
+const IID IID_IMediaEvent = {0x56A868B6,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
 
 //??  QUARTZ Also?
 
 //??  QUARTZ Also?
-const CLSID CLSID_VideoMixingRenderer = {0xB87BEB7B, 0x8D29, 0x423F,{0xAE, 0x4D, 0x65, 0x82, 0xC1, 0x01, 0x75, 0xAC}};
-const IID IID_IVMRWindowlessControl =   {0x0EB1088C, 0x4DCD, 0x46F0,{0x87, 0x8F, 0x39, 0xDA, 0xE8, 0x6A, 0x51, 0xB7}};
+const CLSID CLSID_VideoMixingRenderer9 ={0x51B4ABF3, 0x748F, 0x4E3B,{0xA2, 0x76, 0xC8, 0x28, 0x33, 0x0E, 0x92, 0x6A}};
+const IID IID_IVMRWindowlessControl9 =  {0x8F537D09, 0xF85E, 0x4414,{0xB2, 0x3B, 0x50, 0x2E, 0x54, 0xC7, 0x99, 0x27}};
 const IID IID_IFilterGraph =            {0x56A8689F, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
 const IID IID_IGraphBuilder =           {0x56A868A9, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
 const IID IID_IFilterGraph =            {0x56A8689F, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
 const IID IID_IGraphBuilder =           {0x56A868A9, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
-const IID IID_IVMRFilterConfig =        {0x9E5530C5, 0x7034, 0x48B4,{0xBB, 0x46, 0x0B, 0x8A, 0x6E, 0xFC, 0x8E, 0x36}};
+const IID IID_IVMRFilterConfig9 =       {0x5A804648, 0x4F66, 0x4867,{0x9C, 0x43, 0x4F, 0x5C, 0x82, 0x2C, 0xF1, 0xB8}};
 const IID IID_IBaseFilter =             {0x56A86895, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
 
 //---------------------------------------------------------------------------
 const IID IID_IBaseFilter =             {0x56A86895, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
 
 //---------------------------------------------------------------------------
-//  DIRECTDRAW COM INTERFACES
+//  QUARTZ COM INTERFACES (dumped from quartz.idl from MSVC COM Browser)
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-//DDSURFACESDESC - we don't need most of the stuff here, esp. DDPIXELFORMAT,
-//so just put stubs in
-struct DDPIXELFORMAT {DWORD dw1,dw2,dw3,dw4,dw5,dw6,dw7,dw8;};
-struct DDCOLORKEY {DWORD dwLow, dwHigh;};
 
 
-typedef struct IDirectDrawClipper* LPDIRECTDRAWCLIPPER;
-typedef struct IDirectDraw* LPDIRECTDRAW;
-typedef struct IDirectDrawSurface* LPDIRECTDRAWSURFACE;
-typedef struct DDSURFACEDESC* LPDDSURFACEDESC;
-typedef struct IDirectDrawPalette* LPDIRECTDRAWPALETTE;
-typedef struct DDSCAPS* LPDDSCAPS;
-typedef DDCOLORKEY* LPDDCOLORKEY;
-typedef DDPIXELFORMAT* LPDDPIXELFORMAT;
-typedef struct DDCAPS* LPDDCAPS;
+struct IAMOpenProgress : public IUnknown
+{
+    STDMETHOD(QueryProgress)(LONGLONG *pllTotal, LONGLONG *pllCurrent) PURE;
+    STDMETHOD(AbortOperation)(void) PURE;
+};
 
 
-struct DDSURFACEDESC
+struct IMediaEvent : public IDispatch
 {
 {
-    DWORD               dwSize;
-    DWORD               dwFlags;
-    DWORD               dwHeight;
-    DWORD               dwWidth;
-    union
-    {
-        LONG            lPitch;
-        DWORD           dwLinearSize;
-    };
-    DWORD               dwBackBufferCount;
-    union
-    {
-        DWORD           dwMipMapCount;
-        DWORD           dwZBufferBitDepth;
-        DWORD           dwRefreshRate;
-    };
-    DWORD               dwAlphaBitDepth;
-    DWORD               dwReserved;
-    LPVOID              lpSurface;
-    DDCOLORKEY          ddckCKDestOverlay;
-    DDCOLORKEY          ddckCKDestBlt;
-    DDCOLORKEY          ddckCKSrcOverlay;
-    DDCOLORKEY          ddckCKSrcBlt;
-    DDPIXELFORMAT ddpfPixelFormat;
-    struct DDSCAPS {DWORD dwCaps;} ddsCaps;
+    STDMETHOD(GetEventHandle)(LONG_PTR *) PURE;
+    STDMETHOD(GetEvent)(long *, LONG_PTR *, LONG_PTR *, long) PURE;
+    STDMETHOD(WaitForCompletion)(long, long *) PURE;
+    STDMETHOD(CancelDefaultHandling)(long) PURE;
+    STDMETHOD(RestoreDefaultHandling)(long) PURE;
+    STDMETHOD(FreeEventParams)(long, LONG_PTR, LONG_PTR) PURE;
 };
 
 };
 
-struct IDirectDrawClipper : public IUnknown
+//---------------------------------------------------------------------------
+//  ACTIVEMOVIE COM INTERFACES (dumped from amcompat.idl from MSVC COM Browser)
+//---------------------------------------------------------------------------
+
+enum ReadyStateConstants
 {
 {
-    STDMETHOD(GetClipList)(LPRECT, LPRGNDATA, LPDWORD) PURE;
-    STDMETHOD(GetHWnd)(HWND*) PURE;
-    STDMETHOD(Initialize)(LPDIRECTDRAW, DWORD) PURE;
-    STDMETHOD(IsClipListChanged)(BOOL*) PURE;
-    STDMETHOD(SetClipList)(LPRGNDATA,DWORD) PURE;
-    STDMETHOD(SetHWnd)(DWORD, HWND) PURE;
+    amvUninitialized    = 0,
+    amvLoading    = 1,
+    amvInteractive    = 3,
+    amvComplete    = 4
 };
 
 };
 
-struct IDirectDrawSurface : public IUnknown
-{
-    STDMETHOD(AddAttachedSurface)(LPDIRECTDRAWSURFACE) PURE;
-    STDMETHOD(AddOverlayDirtyRect)(LPRECT) PURE;
-    STDMETHOD(Blt)(LPRECT,LPDIRECTDRAWSURFACE, LPRECT,DWORD, struct DDBLTFX*) PURE;
-    STDMETHOD(BltBatch)(struct DDBLTBATCH*, DWORD, DWORD ) PURE;
-    STDMETHOD(BltFast)(DWORD,DWORD,LPDIRECTDRAWSURFACE, LPRECT,DWORD) PURE;
-    STDMETHOD(DeleteAttachedSurface)(DWORD,LPDIRECTDRAWSURFACE) PURE;
-    STDMETHOD(EnumAttachedSurfaces)(LPVOID, LPVOID/*LPDDENUMSURFACESCALLBACK*/) PURE;
-    STDMETHOD(EnumOverlayZOrders)(DWORD,LPVOID,LPVOID/*LPDDENUMSURFACESCALLBACK*/) PURE;
-    STDMETHOD(Flip)(LPDIRECTDRAWSURFACE, DWORD) PURE;
-    STDMETHOD(GetAttachedSurface)(LPDDSCAPS, LPDIRECTDRAWSURFACE*) PURE;
-    STDMETHOD(GetBltStatus)(DWORD) PURE;
-    STDMETHOD(GetCaps)(LPDDSCAPS) PURE;
-    STDMETHOD(GetClipper)(LPDIRECTDRAWCLIPPER*) PURE;
-    STDMETHOD(GetColorKey)(DWORD, LPDDCOLORKEY) PURE;
-    STDMETHOD(GetDC)(HDC *) PURE;
-    STDMETHOD(GetFlipStatus)(DWORD) PURE;
-    STDMETHOD(GetOverlayPosition)(LPLONG, LPLONG ) PURE;
-    STDMETHOD(GetPalette)(LPDIRECTDRAWPALETTE FAR*) PURE;
-    STDMETHOD(GetPixelFormat)(LPDDPIXELFORMAT) PURE;
-    STDMETHOD(GetSurfaceDesc)(LPDDSURFACEDESC) PURE;
-    STDMETHOD(Initialize)(LPDIRECTDRAW, LPDDSURFACEDESC) PURE;
-    STDMETHOD(IsLost)(THIS) PURE;
-    STDMETHOD(Lock)(LPRECT,LPDDSURFACEDESC,DWORD,HANDLE) PURE;
-    STDMETHOD(ReleaseDC)(HDC) PURE;
-    STDMETHOD(Restore)(THIS) PURE;
-    STDMETHOD(SetClipper)(LPDIRECTDRAWCLIPPER) PURE;
-    STDMETHOD(SetColorKey)(DWORD, LPDDCOLORKEY) PURE;
-    STDMETHOD(SetOverlayPosition)(LONG, LONG ) PURE;
-    STDMETHOD(SetPalette)(IUnknown*) PURE;
-    STDMETHOD(Unlock)(LPVOID) PURE;
-    STDMETHOD(UpdateOverlay)(LPRECT, LPDIRECTDRAWSURFACE,LPRECT,
-                               DWORD, struct DDOVERLAYFX*) PURE;
-    STDMETHOD(UpdateOverlayDisplay)(DWORD) PURE;
-    STDMETHOD(UpdateOverlayZOrder)(DWORD, LPDIRECTDRAWSURFACE) PURE;
+enum StateConstants
+{
+    amvNotLoaded    = -1,
+    amvStopped    = 0,
+    amvPaused    = 1,
+    amvRunning    = 2
 };
 
 };
 
-struct IDirectDraw : public IUnknown
-{
-    STDMETHOD(Compact)() PURE;
-    STDMETHOD(CreateClipper)(DWORD, LPDIRECTDRAWCLIPPER*, IUnknown * ) PURE;
-    STDMETHOD(CreatePalette)(DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE *, IUnknown * ) PURE;
-    STDMETHOD(CreateSurface)(LPDDSURFACEDESC, LPDIRECTDRAWSURFACE *, IUnknown *) PURE;
-    STDMETHOD(DuplicateSurface)(LPDIRECTDRAWSURFACE, LPDIRECTDRAWSURFACE * ) PURE;
-    STDMETHOD(EnumDisplayModes)(DWORD, LPDDSURFACEDESC, LPVOID, LPVOID ) PURE;
-    STDMETHOD(EnumSurfaces)(DWORD, LPDDSURFACEDESC, LPVOID,LPVOID ) PURE;
-    STDMETHOD(FlipToGDISurface)() PURE;
-    STDMETHOD(GetCaps)(LPDDCAPS, LPDDCAPS) PURE;
-    STDMETHOD(GetDisplayMode)(LPDDSURFACEDESC) PURE;
-    STDMETHOD(GetFourCCCodes)(LPDWORD, LPDWORD ) PURE;
-    STDMETHOD(GetGDISurface)(LPDIRECTDRAWSURFACE *) PURE;
-    STDMETHOD(GetMonitorFrequency)(LPDWORD) PURE;
-    STDMETHOD(GetScanLine)(LPDWORD) PURE;
-    STDMETHOD(GetVerticalBlankStatus)(LPBOOL ) PURE;
-    STDMETHOD(Initialize)(GUID *) PURE;
-    STDMETHOD(RestoreDisplayMode)() PURE;
-    STDMETHOD(SetCooperativeLevel)(HWND, DWORD) PURE;
-    STDMETHOD(SetDisplayMode)(DWORD, DWORD,DWORD, DWORD, DWORD) PURE;
-    STDMETHOD(WaitForVerticalBlank)(DWORD, HANDLE ) PURE;
+enum DisplayModeConstants
+{
+    amvTime    = 0,
+    amvFrames    = 1
 };
 
 };
 
-//---------------------------------------------------------------------------
-//  AMMEDIA COM INTERFACES
-//---------------------------------------------------------------------------
-struct IMediaStream;
-struct IMultiMediaStream;
-struct IStreamSample : public IUnknown
+enum WindowSizeConstants
 {
 {
-public:
-    STDMETHOD(GetMediaStream)(IMediaStream **) PURE;
-    STDMETHOD(GetSampleTimes)(LONGLONG *, LONGLONG *, LONGLONG *) PURE;
-    STDMETHOD(SetSampleTimes)(const LONGLONG *, const LONGLONG *) PURE;
-    STDMETHOD(Update)(DWORD, HANDLE, LPVOID, DWORD_PTR) PURE;
-    STDMETHOD(CompletionStatus)(DWORD, DWORD) PURE;
+    amvOriginalSize    = 0,
+    amvDoubleOriginalSize    = 1,
+    amvOneSixteenthScreen    = 2,
+    amvOneFourthScreen    = 3,
+    amvOneHalfScreen    = 4
 };
 
 };
 
-struct IDirectDrawStreamSample : public IStreamSample
+enum AppearanceConstants
 {
 {
-public:
-    STDMETHOD(GetSurface)(IDirectDrawSurface **, RECT *) PURE;
-    STDMETHOD(SetRect)(const RECT *) PURE;
+    amvFlat    = 0,
+    amv3D    = 1
 };
 
 };
 
-struct IMediaStream : public IUnknown
+enum BorderStyleConstants
 {
 {
-    STDMETHOD(GetMultiMediaStream)(IMultiMediaStream **) PURE;
-    STDMETHOD(GetInformation)(GUID *, int *) PURE;
-    STDMETHOD(SetSameFormat)(IMediaStream *, DWORD) PURE;
-    STDMETHOD(AllocateSample)(DWORD, IStreamSample **) PURE;
-    STDMETHOD(CreateSharedSample)(IStreamSample *, DWORD,
-                                  IStreamSample **) PURE;
-    STDMETHOD(SendEndOfStream)(DWORD dwFlags) PURE;
+    amvNone    = 0,
+    amvFixedSingle    = 1
 };
 
 };
 
-struct IDirectDrawMediaStream : public IMediaStream
+struct IActiveMovie : public IDispatch
 {
 {
-    STDMETHOD(GetFormat)(DDSURFACEDESC *, IDirectDrawPalette **,
-                         DDSURFACEDESC *, DWORD *) PURE;
-    STDMETHOD(SetFormat)(const DDSURFACEDESC *, IDirectDrawPalette *) PURE;
-    STDMETHOD(GetDirectDraw)(IDirectDraw **) PURE;
-    STDMETHOD(SetDirectDraw)(IDirectDraw *) PURE;
-    STDMETHOD(CreateSample)(IDirectDrawSurface *, const RECT *,
-                              DWORD, IDirectDrawStreamSample **) PURE;
-    STDMETHOD(GetTimePerFrame)(LONGLONG *) PURE;
+    STDMETHOD(AboutBox)( void) PURE;
+    STDMETHOD(Run)( void) PURE;
+    STDMETHOD(Pause)( void) PURE;
+    STDMETHOD(Stop)( void) PURE;
+    STDMETHOD(get_ImageSourceWidth)(long __RPC_FAR *pWidth) PURE;
+    STDMETHOD(get_ImageSourceHeight)(long __RPC_FAR *pHeight) PURE;
+    STDMETHOD(get_Author)(BSTR __RPC_FAR *pbstrAuthor) PURE;
+    STDMETHOD(get_Title)(BSTR __RPC_FAR *pbstrTitle) PURE;
+    STDMETHOD(get_Copyright)(BSTR __RPC_FAR *pbstrCopyright) PURE;
+    STDMETHOD(get_Description)(BSTR __RPC_FAR *pbstrDescription) PURE;
+    STDMETHOD(get_Rating)(BSTR __RPC_FAR *pbstrRating) PURE;
+    STDMETHOD(get_FileName)(BSTR __RPC_FAR *pbstrFileName) PURE;
+    STDMETHOD(put_FileName)(BSTR pbstrFileName) PURE;
+    STDMETHOD(get_Duration)(double __RPC_FAR *pValue) PURE;
+    STDMETHOD(get_CurrentPosition)(double __RPC_FAR *pValue) PURE;
+    STDMETHOD(put_CurrentPosition)(double pValue) PURE;
+    STDMETHOD(get_PlayCount)(long __RPC_FAR *pPlayCount) PURE;
+    STDMETHOD(put_PlayCount)(long pPlayCount) PURE;
+    STDMETHOD(get_SelectionStart)(double __RPC_FAR *pValue) PURE;
+    STDMETHOD(put_SelectionStart)(double pValue) PURE;
+    STDMETHOD(get_SelectionEnd)(double __RPC_FAR *pValue) PURE;
+    STDMETHOD(put_SelectionEnd)(double pValue) PURE;
+    STDMETHOD(get_CurrentState)(StateConstants __RPC_FAR *pState) PURE;
+    STDMETHOD(get_Rate)(double __RPC_FAR *pValue) PURE;
+    STDMETHOD(put_Rate)(double pValue) PURE;
+    STDMETHOD(get_Volume)(long __RPC_FAR *pValue) PURE;
+    STDMETHOD(put_Volume)(long pValue) PURE;
+    STDMETHOD(get_Balance)(long __RPC_FAR *pValue) PURE;
+    STDMETHOD(put_Balance)(long pValue) PURE;
+    STDMETHOD(get_EnableContextMenu)(VARIANT_BOOL __RPC_FAR *pEnable) PURE;
+    STDMETHOD(put_EnableContextMenu)(VARIANT_BOOL pEnable) PURE;
+    STDMETHOD(get_ShowDisplay)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_ShowDisplay)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_ShowControls)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_ShowControls)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_ShowPositionControls)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_ShowPositionControls)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_ShowSelectionControls)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_ShowSelectionControls)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_ShowTracker)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_ShowTracker)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_EnablePositionControls)(VARIANT_BOOL __RPC_FAR *Enable) PURE;
+    STDMETHOD(put_EnablePositionControls)(VARIANT_BOOL Enable) PURE;
+    STDMETHOD(get_EnableSelectionControls)(VARIANT_BOOL __RPC_FAR *Enable) PURE;
+    STDMETHOD(put_EnableSelectionControls)(VARIANT_BOOL Enable) PURE;
+    STDMETHOD(get_EnableTracker)(VARIANT_BOOL __RPC_FAR *Enable) PURE;
+    STDMETHOD(put_EnableTracker)(VARIANT_BOOL Enable) PURE;
+    STDMETHOD(get_AllowHideDisplay)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_AllowHideDisplay)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_AllowHideControls)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_AllowHideControls)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_DisplayMode)(DisplayModeConstants __RPC_FAR *pValue) PURE;
+    STDMETHOD(put_DisplayMode)(DisplayModeConstants pValue) PURE;
+    STDMETHOD(get_AllowChangeDisplayMode)(VARIANT_BOOL __RPC_FAR *fAllow) PURE;
+    STDMETHOD(put_AllowChangeDisplayMode)(VARIANT_BOOL fAllow) PURE;
+    STDMETHOD(get_FilterGraph)(IUnknown __RPC_FAR *__RPC_FAR *ppFilterGraph) PURE;
+    STDMETHOD(put_FilterGraph)(IUnknown __RPC_FAR *ppFilterGraph) PURE;
+    STDMETHOD(get_FilterGraphDispatch)(IDispatch __RPC_FAR *__RPC_FAR *pDispatch) PURE;
+    STDMETHOD(get_DisplayForeColor)(unsigned long __RPC_FAR *ForeColor) PURE;
+    STDMETHOD(put_DisplayForeColor)(unsigned long ForeColor) PURE;
+    STDMETHOD(get_DisplayBackColor)(unsigned long __RPC_FAR *BackColor) PURE;
+    STDMETHOD(put_DisplayBackColor)(unsigned long BackColor) PURE;
+    STDMETHOD(get_MovieWindowSize)(WindowSizeConstants __RPC_FAR *WindowSize) PURE;
+    STDMETHOD(put_MovieWindowSize)(WindowSizeConstants WindowSize) PURE;
+    STDMETHOD(get_FullScreenMode)(VARIANT_BOOL __RPC_FAR *pEnable) PURE;
+    STDMETHOD(put_FullScreenMode)(VARIANT_BOOL pEnable) PURE;
+    STDMETHOD(get_AutoStart)(VARIANT_BOOL __RPC_FAR *pEnable) PURE;
+    STDMETHOD(put_AutoStart)(VARIANT_BOOL pEnable) PURE;
+    STDMETHOD(get_AutoRewind)(VARIANT_BOOL __RPC_FAR *pEnable) PURE;
+    STDMETHOD(put_AutoRewind)(VARIANT_BOOL pEnable) PURE;
+    STDMETHOD(get_hWnd)(long __RPC_FAR *hWnd) PURE;
+    STDMETHOD(get_Appearance)(AppearanceConstants __RPC_FAR *pAppearance) PURE;
+    STDMETHOD(put_Appearance)(AppearanceConstants pAppearance) PURE;
+    STDMETHOD(get_BorderStyle)(BorderStyleConstants __RPC_FAR *pBorderStyle) PURE;
+    STDMETHOD(put_BorderStyle)(BorderStyleConstants pBorderStyle) PURE;
+    STDMETHOD(get_Enabled)(VARIANT_BOOL __RPC_FAR *pEnabled) PURE;
+    STDMETHOD(put_Enabled)(VARIANT_BOOL pEnabled) PURE;
+    STDMETHOD(get_Info)(long __RPC_FAR *ppInfo) PURE;
 };
 
 };
 
-struct IMultiMediaStream : public IUnknown
-{
-    STDMETHOD(GetInformation)(DWORD *, int *) PURE;
-    STDMETHOD(GetMediaStream)(REFGUID, IMediaStream **) PURE;
-    STDMETHOD(EnumMediaStreams)(long, IMediaStream **) PURE;
-    STDMETHOD(GetState)(int *pCurrentState) PURE;
-    STDMETHOD(SetState)(int NewState) PURE;
-    STDMETHOD(GetTime)(LONGLONG *pCurrentTime) PURE;
-    STDMETHOD(GetDuration)(LONGLONG *pDuration) PURE;
-    STDMETHOD(Seek)(LONGLONG SeekTime) PURE;
-    STDMETHOD(GetEndOfStreamEventHandle)(HANDLE *phEOS) PURE;
+
+
+struct IActiveMovie2 : public IActiveMovie
+{
+    STDMETHOD(IsSoundCardEnabled)(VARIANT_BOOL __RPC_FAR *pbSoundCard) PURE;
+    STDMETHOD(get_ReadyState)(ReadyStateConstants __RPC_FAR *pValue) PURE;
 };
 
 };
 
-struct IAMMultiMediaStream : public IMultiMediaStream
+struct IActiveMovie3 : public IActiveMovie2
 {
 {
-    STDMETHOD(Initialize)(int, DWORD, IUnknown *) PURE;
-    STDMETHOD(GetFilterGraph)(IUnknown **) PURE;
-    STDMETHOD(GetFilter)(IUnknown **) PURE;
-    STDMETHOD(AddMediaStream)(IUnknown *, const GUID*, DWORD,
-                              IMediaStream **) PURE;
-    STDMETHOD(OpenFile)(LPCWSTR, DWORD) PURE;
-    STDMETHOD(OpenMoniker)(IBindCtx *, IMoniker *, DWORD) PURE;
-    STDMETHOD(Render)(DWORD) PURE;
+    STDMETHOD(get_MediaPlayer)(IDispatch __RPC_FAR *__RPC_FAR *ppDispatch) PURE;
 };
 
 };
 
+
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-//  QUARTZ COM INTERFACES (dumped from quartz.idl from MSVC COM Browser)
+//  MEDIAPLAYER COM INTERFACES (dumped from msdxm.idl from MSVC COM Browser)
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-struct IAMCollection : public IDispatch
+
+enum MPPlayStateConstants
 {
 {
-    STDMETHOD(get_Count)(long *) PURE;
-    STDMETHOD(Item)(long, IUnknown **) PURE;
-    STDMETHOD(get__NewEnum)(IUnknown **) PURE;
+    mpStopped = 0,
+    mpPaused    = 1,
+    mpPlaying    = 2,
+    mpWaiting    = 3,
+    mpScanForward    = 4,
+    mpScanReverse    = 5,
+    mpClosed    = 6
 };
 
 };
 
-struct IMediaControl : public IDispatch
-{
-    STDMETHOD(Run)() PURE;
-    STDMETHOD(Pause)() PURE;
-    STDMETHOD(Stop)() PURE;
-    STDMETHOD(GetState)(long, long*) PURE;
-    STDMETHOD(RenderFile)(BSTR) PURE;
-    STDMETHOD(AddSourceFilter)(BSTR, IDispatch **) PURE;
-    STDMETHOD(get_FilterCollection)(IDispatch **) PURE;
-    STDMETHOD(get_RegFilterCollection)(IDispatch **) PURE;
-    STDMETHOD(StopWhenReady)() PURE;
+enum MPDisplaySizeConstants
+{
+    mpDefaultSize = 0,
+    mpHalfSize    = 1,
+    mpDoubleSize    = 2,
+    mpFullScreen    = 3,
+    mpFitToSize    = 4,
+    mpOneSixteenthScreen    = 5,
+    mpOneFourthScreen    = 6,
+    mpOneHalfScreen    = 7
 };
 
 };
 
-struct IMediaEvent : public IDispatch
+enum MPReadyStateConstants
 {
 {
-    STDMETHOD(GetEventHandle)(LONG_PTR *) PURE;
-    STDMETHOD(GetEvent)(long *, LONG_PTR *, LONG_PTR *, long) PURE;
-    STDMETHOD(WaitForCompletion)(long, long *) PURE;
-    STDMETHOD(CancelDefaultHandling)(long) PURE;
-    STDMETHOD(RestoreDefaultHandling)(long) PURE;
-    STDMETHOD(FreeEventParams)(long, LONG_PTR, LONG_PTR) PURE;
+    mpReadyStateUninitialized = 0,
+    mpReadyStateLoading    = 1,
+    mpReadyStateInteractive    = 3,
+    mpReadyStateComplete    = 4
 };
 
 };
 
-struct IMediaEventEx : public IMediaEvent
+typedef unsigned long VB_OLE_COLOR;
+
+enum MPDisplayModeConstants
 {
 {
-    STDMETHOD(SetNotifyWindow)(LONG_PTR, long, LONG_PTR) PURE;
-    STDMETHOD(SetNotifyFlags)(long) PURE;
-    STDMETHOD(GetNotifyFlags)(long *) PURE;
+    mpTime = 0,
+    mpFrames    = 1
 };
 
 };
 
-struct IMediaPosition : public IDispatch
-{
-    STDMETHOD(get_Duration)(double *) PURE;
-    STDMETHOD(put_CurrentPosition)(double) PURE;
-    STDMETHOD(get_CurrentPosition)(double *) PURE;
-    STDMETHOD(get_StopTime)(double *) PURE;
-    STDMETHOD(put_StopTime)(double) PURE;
-    STDMETHOD(get_PrerollTime)(double *) PURE;
-    STDMETHOD(put_PrerollTime)(double) PURE;
-    STDMETHOD(put_Rate)(double) PURE;
-    STDMETHOD(get_Rate)(double *) PURE;
-    STDMETHOD(CanSeekForward)(long *) PURE;
-    STDMETHOD(CanSeekBackward)(long *) PURE;
+enum MPMoreInfoType
+{
+    mpShowURL = 0,
+    mpClipURL    = 1,
+    mpBannerURL    = 2
 };
 
 };
 
-struct IBasicAudio : public IDispatch
+enum MPMediaInfoType
 {
 {
-    STDMETHOD(put_Volume)(long) PURE;
-    STDMETHOD(get_Volume)(long *) PURE;
-    STDMETHOD(put_Balance)(long) PURE;
-    STDMETHOD(get_Balance)(long *) PURE;
+    mpShowFilename = 0,
+    mpShowTitle    = 1,
+    mpShowAuthor    = 2,
+    mpShowCopyright    = 3,
+    mpShowRating    = 4,
+    mpShowDescription    = 5,
+    mpShowLogoIcon    = 6,
+    mpClipFilename    = 7,
+    mpClipTitle    = 8,
+    mpClipAuthor    = 9,
+    mpClipCopyright    = 10,
+    mpClipRating    = 11,
+    mpClipDescription    = 12,
+    mpClipLogoIcon    = 13,
+    mpBannerImage    = 14,
+    mpBannerMoreInfo    = 15,
+    mpWatermark    = 16
+};
+
+enum DVDMenuIDConstants
+{
+    dvdMenu_Title    = 2,
+    dvdMenu_Root    = 3,
+    dvdMenu_Subpicture    = 4,
+    dvdMenu_Audio    = 5,
+    dvdMenu_Angle    = 6,
+    dvdMenu_Chapter    = 7
+};
+
+enum MPShowDialogConstants
+{
+    mpShowDialogHelp = 0,
+    mpShowDialogStatistics    = 1,
+    mpShowDialogOptions    = 2,
+    mpShowDialogContextMenu    = 3
+};
+
+
+struct IMediaPlayer : public IDispatch
+{
+    STDMETHOD(get_CurrentPosition)(double __RPC_FAR *pCurrentPosition) PURE;
+    STDMETHOD(put_CurrentPosition)(double pCurrentPosition) PURE;
+    STDMETHOD(get_Duration)(double __RPC_FAR *pDuration) PURE;
+    STDMETHOD(get_ImageSourceWidth)(long __RPC_FAR *pWidth) PURE;
+    STDMETHOD(get_ImageSourceHeight)(long __RPC_FAR *pHeight) PURE;
+    STDMETHOD(get_MarkerCount)(long __RPC_FAR *pMarkerCount) PURE;
+    STDMETHOD(get_CanScan)(VARIANT_BOOL __RPC_FAR *pCanScan) PURE;
+    STDMETHOD(get_CanSeek)(VARIANT_BOOL __RPC_FAR *pCanSeek) PURE;
+    STDMETHOD(get_CanSeekToMarkers)(VARIANT_BOOL __RPC_FAR *pCanSeekToMarkers) PURE;
+    STDMETHOD(get_CurrentMarker)(long __RPC_FAR *pCurrentMarker) PURE;
+    STDMETHOD(put_CurrentMarker)(long pCurrentMarker) PURE;
+    STDMETHOD(get_FileName)(BSTR __RPC_FAR *pbstrFileName) PURE;
+    STDMETHOD(put_FileName)(BSTR pbstrFileName) PURE;
+    STDMETHOD(get_SourceLink)(BSTR __RPC_FAR *pbstrSourceLink) PURE;
+    STDMETHOD(get_CreationDate)(DATE __RPC_FAR *pCreationDate) PURE;
+    STDMETHOD(get_ErrorCorrection)(BSTR __RPC_FAR *pbstrErrorCorrection) PURE;
+    STDMETHOD(get_Bandwidth)(long __RPC_FAR *pBandwidth) PURE;
+    STDMETHOD(get_SourceProtocol)(long __RPC_FAR *pSourceProtocol) PURE;
+    STDMETHOD(get_ReceivedPackets)(long __RPC_FAR *pReceivedPackets) PURE;
+    STDMETHOD(get_RecoveredPackets)(long __RPC_FAR *pRecoveredPackets) PURE;
+    STDMETHOD(get_LostPackets)(long __RPC_FAR *pLostPackets) PURE;
+    STDMETHOD(get_ReceptionQuality)(long __RPC_FAR *pReceptionQuality) PURE;
+    STDMETHOD(get_BufferingCount)(long __RPC_FAR *pBufferingCount) PURE;
+    STDMETHOD(get_IsBroadcast)(VARIANT_BOOL __RPC_FAR *pIsBroadcast) PURE;
+    STDMETHOD(get_BufferingProgress)(long __RPC_FAR *pBufferingProgress) PURE;
+    STDMETHOD(get_ChannelName)(BSTR __RPC_FAR *pbstrChannelName) PURE;
+    STDMETHOD(get_ChannelDescription)(BSTR __RPC_FAR *pbstrChannelDescription) PURE;
+    STDMETHOD(get_ChannelURL)(BSTR __RPC_FAR *pbstrChannelURL) PURE;
+    STDMETHOD(get_ContactAddress)(BSTR __RPC_FAR *pbstrContactAddress) PURE;
+    STDMETHOD(get_ContactPhone)(BSTR __RPC_FAR *pbstrContactPhone) PURE;
+    STDMETHOD(get_ContactEmail)(BSTR __RPC_FAR *pbstrContactEmail) PURE;
+    STDMETHOD(get_BufferingTime)(double __RPC_FAR *pBufferingTime) PURE;
+    STDMETHOD(put_BufferingTime)(double pBufferingTime) PURE;
+    STDMETHOD(get_AutoStart)(VARIANT_BOOL __RPC_FAR *pAutoStart) PURE;
+    STDMETHOD(put_AutoStart)(VARIANT_BOOL pAutoStart) PURE;
+    STDMETHOD(get_AutoRewind)(VARIANT_BOOL __RPC_FAR *pAutoRewind) PURE;
+    STDMETHOD(put_AutoRewind)(VARIANT_BOOL pAutoRewind) PURE;
+    STDMETHOD(get_Rate)(double __RPC_FAR *pRate) PURE;
+    STDMETHOD(put_Rate)(double pRate) PURE;
+    STDMETHOD(get_SendKeyboardEvents)(VARIANT_BOOL __RPC_FAR *pSendKeyboardEvents) PURE;
+    STDMETHOD(put_SendKeyboardEvents)(VARIANT_BOOL pSendKeyboardEvents) PURE;
+    STDMETHOD(get_SendMouseClickEvents)(VARIANT_BOOL __RPC_FAR *pSendMouseClickEvents) PURE;
+    STDMETHOD(put_SendMouseClickEvents)(VARIANT_BOOL pSendMouseClickEvents) PURE;
+    STDMETHOD(get_SendMouseMoveEvents)(VARIANT_BOOL __RPC_FAR *pSendMouseMoveEvents) PURE;
+    STDMETHOD(put_SendMouseMoveEvents)(VARIANT_BOOL pSendMouseMoveEvents) PURE;
+    STDMETHOD(get_PlayCount)(long __RPC_FAR *pPlayCount) PURE;
+    STDMETHOD(put_PlayCount)(long pPlayCount) PURE;
+    STDMETHOD(get_ClickToPlay)(VARIANT_BOOL __RPC_FAR *pClickToPlay) PURE;
+    STDMETHOD(put_ClickToPlay)(VARIANT_BOOL pClickToPlay) PURE;
+    STDMETHOD(get_AllowScan)(VARIANT_BOOL __RPC_FAR *pAllowScan) PURE;
+    STDMETHOD(put_AllowScan)(VARIANT_BOOL pAllowScan) PURE;
+    STDMETHOD(get_EnableContextMenu)(VARIANT_BOOL __RPC_FAR *pEnableContextMenu) PURE;
+    STDMETHOD(put_EnableContextMenu)(VARIANT_BOOL pEnableContextMenu) PURE;
+    STDMETHOD(get_CursorType)(long __RPC_FAR *pCursorType) PURE;
+    STDMETHOD(put_CursorType)(long pCursorType) PURE;
+    STDMETHOD(get_CodecCount)(long __RPC_FAR *pCodecCount) PURE;
+    STDMETHOD(get_AllowChangeDisplaySize)(VARIANT_BOOL __RPC_FAR *pAllowChangeDisplaySize) PURE;
+    STDMETHOD(put_AllowChangeDisplaySize)( VARIANT_BOOL pAllowChangeDisplaySize) PURE;
+    STDMETHOD(get_IsDurationValid)(VARIANT_BOOL __RPC_FAR *pIsDurationValid) PURE;
+    STDMETHOD(get_OpenState)(long __RPC_FAR *pOpenState) PURE;
+    STDMETHOD(get_SendOpenStateChangeEvents)(VARIANT_BOOL __RPC_FAR *pSendOpenStateChangeEvents) PURE;
+    STDMETHOD(put_SendOpenStateChangeEvents)(VARIANT_BOOL pSendOpenStateChangeEvents) PURE;
+    STDMETHOD(get_SendWarningEvents)( VARIANT_BOOL __RPC_FAR *pSendWarningEvents) PURE;
+    STDMETHOD(put_SendWarningEvents)(VARIANT_BOOL pSendWarningEvents) PURE;
+    STDMETHOD(get_SendErrorEvents)(VARIANT_BOOL __RPC_FAR *pSendErrorEvents) PURE;
+    STDMETHOD(put_SendErrorEvents)(VARIANT_BOOL pSendErrorEvents) PURE;
+    STDMETHOD(get_PlayState)(MPPlayStateConstants __RPC_FAR *pPlayState) PURE;
+    STDMETHOD(get_SendPlayStateChangeEvents)(VARIANT_BOOL __RPC_FAR *pSendPlayStateChangeEvents) PURE;
+    STDMETHOD(put_SendPlayStateChangeEvents)(VARIANT_BOOL pSendPlayStateChangeEvents) PURE;
+    STDMETHOD(get_DisplaySize)(MPDisplaySizeConstants __RPC_FAR *pDisplaySize) PURE;
+    STDMETHOD(put_DisplaySize)(MPDisplaySizeConstants pDisplaySize) PURE;
+    STDMETHOD(get_InvokeURLs)(VARIANT_BOOL __RPC_FAR *pInvokeURLs) PURE;
+    STDMETHOD(put_InvokeURLs)(VARIANT_BOOL pInvokeURLs) PURE;
+    STDMETHOD(get_BaseURL)(BSTR __RPC_FAR *pbstrBaseURL) PURE;
+    STDMETHOD(put_BaseURL)(BSTR pbstrBaseURL) PURE;
+    STDMETHOD(get_DefaultFrame)(BSTR __RPC_FAR *pbstrDefaultFrame) PURE;
+    STDMETHOD(put_DefaultFrame)(BSTR pbstrDefaultFrame) PURE;
+    STDMETHOD(get_HasError)(VARIANT_BOOL __RPC_FAR *pHasError) PURE;
+    STDMETHOD(get_ErrorDescription)(BSTR __RPC_FAR *pbstrErrorDescription) PURE;
+    STDMETHOD(get_ErrorCode)(long __RPC_FAR *pErrorCode) PURE;
+    STDMETHOD(get_AnimationAtStart)(VARIANT_BOOL __RPC_FAR *pAnimationAtStart) PURE;
+    STDMETHOD(put_AnimationAtStart)(VARIANT_BOOL pAnimationAtStart) PURE;
+    STDMETHOD(get_TransparentAtStart)( VARIANT_BOOL __RPC_FAR *pTransparentAtStart) PURE;
+    STDMETHOD(put_TransparentAtStart)(VARIANT_BOOL pTransparentAtStart) PURE;
+    STDMETHOD(get_Volume)(long __RPC_FAR *pVolume) PURE;
+    STDMETHOD(put_Volume)(long pVolume) PURE;
+    STDMETHOD(get_Balance)(long __RPC_FAR *pBalance) PURE;
+    STDMETHOD(put_Balance)(long pBalance) PURE;
+    STDMETHOD(get_ReadyState)(MPReadyStateConstants __RPC_FAR *pValue) PURE;
+    STDMETHOD(get_SelectionStart)(double __RPC_FAR *pValue) PURE;
+    STDMETHOD(put_SelectionStart)(double pValue) PURE;
+    STDMETHOD(get_SelectionEnd)(double __RPC_FAR *pValue) PURE;
+    STDMETHOD(put_SelectionEnd)(double pValue) PURE;
+    STDMETHOD(get_ShowDisplay)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_ShowDisplay)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_ShowControls)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_ShowControls)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_ShowPositionControls)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_ShowPositionControls)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_ShowTracker)(VARIANT_BOOL __RPC_FAR *Show) PURE;
+    STDMETHOD(put_ShowTracker)(VARIANT_BOOL Show) PURE;
+    STDMETHOD(get_EnablePositionControls)(VARIANT_BOOL __RPC_FAR *Enable) PURE;
+    STDMETHOD(put_EnablePositionControls)(VARIANT_BOOL Enable) PURE;
+    STDMETHOD(get_EnableTracker)(VARIANT_BOOL __RPC_FAR *Enable) PURE;
+    STDMETHOD(put_EnableTracker)(VARIANT_BOOL Enable) PURE;
+    STDMETHOD(get_Enabled)(VARIANT_BOOL __RPC_FAR *pEnabled) PURE;
+    STDMETHOD(put_Enabled)(VARIANT_BOOL pEnabled) PURE;
+    STDMETHOD(get_DisplayForeColor)(VB_OLE_COLOR __RPC_FAR *ForeColor) PURE;
+    STDMETHOD(put_DisplayForeColor)(VB_OLE_COLOR ForeColor) PURE;
+    STDMETHOD(get_DisplayBackColor)(VB_OLE_COLOR __RPC_FAR *BackColor) PURE;
+    STDMETHOD(put_DisplayBackColor)(VB_OLE_COLOR BackColor) PURE;
+    STDMETHOD(get_DisplayMode)(MPDisplayModeConstants __RPC_FAR *pValue) PURE;
+    STDMETHOD(put_DisplayMode)(MPDisplayModeConstants pValue) PURE;
+    STDMETHOD(get_VideoBorder3D)(VARIANT_BOOL __RPC_FAR *pVideoBorderWidth) PURE;
+    STDMETHOD(put_VideoBorder3D)(VARIANT_BOOL pVideoBorderWidth) PURE;
+    STDMETHOD(get_VideoBorderWidth)(long __RPC_FAR *pVideoBorderWidth) PURE;
+    STDMETHOD(put_VideoBorderWidth)(long pVideoBorderWidth) PURE;
+    STDMETHOD(get_VideoBorderColor)(VB_OLE_COLOR __RPC_FAR *pVideoBorderWidth) PURE;
+    STDMETHOD(put_VideoBorderColor)(VB_OLE_COLOR pVideoBorderWidth) PURE;
+    STDMETHOD(get_ShowGotoBar)(VARIANT_BOOL __RPC_FAR *pbool) PURE;
+    STDMETHOD(put_ShowGotoBar)(VARIANT_BOOL pbool) PURE;
+    STDMETHOD(get_ShowStatusBar)(VARIANT_BOOL __RPC_FAR *pbool) PURE;
+    STDMETHOD(put_ShowStatusBar)(VARIANT_BOOL pbool) PURE;
+    STDMETHOD(get_ShowCaptioning)(VARIANT_BOOL __RPC_FAR *pbool) PURE;
+    STDMETHOD(put_ShowCaptioning)(VARIANT_BOOL pbool) PURE;
+    STDMETHOD(get_ShowAudioControls)(VARIANT_BOOL __RPC_FAR *pbool) PURE;
+    STDMETHOD(put_ShowAudioControls)(VARIANT_BOOL pbool) PURE;
+    STDMETHOD(get_CaptioningID)( BSTR __RPC_FAR *pstrText) PURE;
+    STDMETHOD(put_CaptioningID)(BSTR pstrText) PURE;
+    STDMETHOD(get_Mute)(VARIANT_BOOL __RPC_FAR *vbool) PURE;
+    STDMETHOD(put_Mute)(VARIANT_BOOL vbool) PURE;
+    STDMETHOD(get_CanPreview)(VARIANT_BOOL __RPC_FAR *pCanPreview) PURE;
+    STDMETHOD(get_PreviewMode)(VARIANT_BOOL __RPC_FAR *pPreviewMode) PURE;
+    STDMETHOD(put_PreviewMode)(VARIANT_BOOL pPreviewMode) PURE;
+    STDMETHOD(get_HasMultipleItems)(VARIANT_BOOL __RPC_FAR *pHasMuliItems) PURE;
+    STDMETHOD(get_Language)(long __RPC_FAR *pLanguage) PURE;
+    STDMETHOD(put_Language)(long pLanguage) PURE;
+    STDMETHOD(get_AudioStream)(long __RPC_FAR *pStream) PURE;
+    STDMETHOD(put_AudioStream)(long pStream) PURE;
+    STDMETHOD(get_SAMIStyle)(BSTR __RPC_FAR *pbstrStyle) PURE;
+    STDMETHOD(put_SAMIStyle)(BSTR pbstrStyle) PURE;
+    STDMETHOD(get_SAMILang)(BSTR __RPC_FAR *pbstrLang) PURE;
+    STDMETHOD(put_SAMILang)(BSTR pbstrLang) PURE;
+    STDMETHOD(get_SAMIFileName)(BSTR __RPC_FAR *pbstrFileName) PURE;
+    STDMETHOD(put_SAMIFileName)(BSTR pbstrFileName) PURE;
+    STDMETHOD(get_StreamCount)( long __RPC_FAR *pStreamCount) PURE;
+    STDMETHOD(get_ClientId)(BSTR __RPC_FAR *pbstrClientId) PURE;
+    STDMETHOD(get_ConnectionSpeed)(long __RPC_FAR *plConnectionSpeed) PURE;
+    STDMETHOD(get_AutoSize)(VARIANT_BOOL __RPC_FAR *pbool) PURE;
+    STDMETHOD(put_AutoSize)(VARIANT_BOOL pbool) PURE;
+    STDMETHOD(get_EnableFullScreenControls)(VARIANT_BOOL __RPC_FAR *pbVal) PURE;
+    STDMETHOD(put_EnableFullScreenControls)(VARIANT_BOOL pbVal) PURE;
+    STDMETHOD(get_ActiveMovie)(IDispatch __RPC_FAR *__RPC_FAR *ppdispatch) PURE;
+    STDMETHOD(get_NSPlay)(IDispatch __RPC_FAR *__RPC_FAR *ppdispatch) PURE;
+    STDMETHOD(get_WindowlessVideo)(VARIANT_BOOL __RPC_FAR *pbool) PURE;
+    STDMETHOD(put_WindowlessVideo)(VARIANT_BOOL pbool) PURE;
+    STDMETHOD(Play)(void) PURE;
+    STDMETHOD(Stop)(void) PURE;
+    STDMETHOD(Pause)(void) PURE;
+    STDMETHOD(GetMarkerTime)(long MarkerNum,
+                             double __RPC_FAR *pMarkerTime) PURE;
+    STDMETHOD(GetMarkerName)(long MarkerNum,
+                             BSTR __RPC_FAR *pbstrMarkerName) PURE;
+    STDMETHOD(AboutBox)(void) PURE;
+    STDMETHOD(GetCodecInstalled)(long CodecNum,
+                              VARIANT_BOOL __RPC_FAR *pCodecInstalled) PURE;
+    STDMETHOD(GetCodecDescription)(long CodecNum,
+                                 BSTR __RPC_FAR *pbstrCodecDescription) PURE;
+    STDMETHOD(GetCodecURL)(long CodecNum,
+                           BSTR __RPC_FAR *pbstrCodecURL) PURE;
+    STDMETHOD(GetMoreInfoURL)(MPMoreInfoType MoreInfoType,
+                              BSTR __RPC_FAR *pbstrMoreInfoURL) PURE;
+    STDMETHOD(GetMediaInfoString)(MPMediaInfoType MediaInfoType,
+                                  BSTR __RPC_FAR *pbstrMediaInfo) PURE;
+    STDMETHOD(Cancel)(void) PURE;
+    STDMETHOD(Open)(BSTR bstrFileName) PURE;
+    STDMETHOD(IsSoundCardEnabled)(VARIANT_BOOL __RPC_FAR *pbSoundCard) PURE;
+    STDMETHOD(Next)(void) PURE;
+    STDMETHOD(Previous)(void) PURE;
+    STDMETHOD(StreamSelect)(long StreamNum) PURE;
+    STDMETHOD(FastForward)(void) PURE;
+    STDMETHOD(FastReverse)(void) PURE;
+    STDMETHOD(GetStreamName)(long StreamNum,
+                             BSTR __RPC_FAR *pbstrStreamName) PURE;
+    STDMETHOD(GetStreamGroup)(long StreamNum,
+                              long __RPC_FAR *pStreamGroup) PURE;
+    STDMETHOD(GetStreamSelected)(long StreamNum, VARIANT_BOOL __RPC_FAR *pStreamSelected) PURE;
+};
+
+struct IMediaPlayer2 : public IMediaPlayer
+{
+    STDMETHOD(get_DVD)(struct IMediaPlayerDvd __RPC_FAR *__RPC_FAR *ppdispatch) PURE;
+    STDMETHOD(GetMediaParameter)(long EntryNum, BSTR bstrParameterName, BSTR __RPC_FAR *pbstrParameterValue) PURE;
+    STDMETHOD(GetMediaParameterName(long EntryNum, long Index, BSTR __RPC_FAR *pbstrParameterName) PURE;
+    STDMETHOD(get_EntryCount)(long __RPC_FAR *pNumberEntries) PURE;
+    STDMETHOD(GetCurrentEntry)(long __RPC_FAR *pEntryNumber) PURE;
+    STDMETHOD(SetCurrentEntry)(long EntryNumber) PURE;
+    STDMETHOD(ShowDialog)(MPShowDialogConstants mpDialogIndex) PURE;
 };
 
 //---------------------------------------------------------------------------
 };
 
 //---------------------------------------------------------------------------
-// MISC COM INTERFACES
+//  NETSHOW COM INTERFACES (dumped from nscompat.idl from MSVC COM Browser)
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-struct IVMRWindowlessControl : public IUnknown
-{
-    STDMETHOD(GetNativeVideoSize)(LONG *, LONG *, LONG *, LONG *) PURE;
-    STDMETHOD(GetMinIdealVideoSize)(LONG *, LONG *) PURE;
-    STDMETHOD(GetMaxIdealVideoSize)(LONG *, LONG *) PURE;
-    STDMETHOD(SetVideoPosition)(const LPRECT,const LPRECT) PURE;
-    STDMETHOD(GetVideoPosition)(LPRECT, LPRECT) PURE;
-    STDMETHOD(GetAspectRatioMode)(DWORD *) PURE;
-    STDMETHOD(SetAspectRatioMode)(DWORD) PURE;
-    STDMETHOD(SetVideoClippingWindow)(HWND) PURE;
-    STDMETHOD(RepaintVideo)(HWND, HDC) PURE;
-    STDMETHOD(DisplayModeChanged)() PURE;
-    STDMETHOD(GetCurrentImage)(BYTE **) PURE;
-    STDMETHOD(SetBorderColor)(COLORREF) PURE;
-    STDMETHOD(GetBorderColor)(COLORREF *) PURE;
-    STDMETHOD(SetColorKey)(COLORREF) PURE;
-    STDMETHOD(GetColorKey)(COLORREF *) PURE;
+
+struct INSOPlay : public IDispatch
+{
+    STDMETHOD(get_ImageSourceWidth)(long __RPC_FAR *pWidth) PURE;
+    STDMETHOD(get_ImageSourceHeight)(long __RPC_FAR *pHeight) PURE;
+    STDMETHOD(get_Duration)(double __RPC_FAR *pDuration) PURE;
+    STDMETHOD(get_Author)(BSTR __RPC_FAR *pbstrAuthor) PURE;
+    STDMETHOD(get_Copyright)(BSTR __RPC_FAR *pbstrCopyright) PURE;
+    STDMETHOD(get_Description)(BSTR __RPC_FAR *pbstrDescription) PURE;
+    STDMETHOD(get_Rating)(BSTR __RPC_FAR *pbstrRating) PURE;
+    STDMETHOD(get_Title)(BSTR __RPC_FAR *pbstrTitle) PURE;
+    STDMETHOD(get_SourceLink)(BSTR __RPC_FAR *pbstrSourceLink) PURE;
+    STDMETHOD(get_MarkerCount)(long __RPC_FAR *pMarkerCount) PURE;
+    STDMETHOD(get_CanScan)(VARIANT_BOOL __RPC_FAR *pCanScan) PURE;
+    STDMETHOD(get_CanSeek)(VARIANT_BOOL __RPC_FAR *pCanSeek) PURE;
+    STDMETHOD(get_CanSeekToMarkers)(VARIANT_BOOL __RPC_FAR *pCanSeekToMarkers) PURE;
+    STDMETHOD(get_CreationDate)(DATE __RPC_FAR *pCreationDate) PURE;
+    STDMETHOD(get_Bandwidth)(long __RPC_FAR *pBandwidth) PURE;
+    STDMETHOD(get_ErrorCorrection)(BSTR __RPC_FAR *pbstrErrorCorrection) PURE;
+    STDMETHOD(get_AutoStart)(VARIANT_BOOL __RPC_FAR *pAutoStart) PURE;
+    STDMETHOD(put_AutoStart)(VARIANT_BOOL pAutoStart) PURE;
+    STDMETHOD(get_AutoRewind)(VARIANT_BOOL __RPC_FAR *pAutoRewind) PURE;
+    STDMETHOD(put_AutoRewind)(VARIANT_BOOL pAutoRewind) PURE;
+    STDMETHOD(get_AllowChangeControlType)(VARIANT_BOOL __RPC_FAR *pAllowChangeControlType) PURE;
+    STDMETHOD(put_AllowChangeControlType)(VARIANT_BOOL pAllowChangeControlType) PURE;
+    STDMETHOD(get_InvokeURLs)(VARIANT_BOOL __RPC_FAR *pInvokeURLs) PURE;
+    STDMETHOD(put_InvokeURLs)(VARIANT_BOOL pInvokeURLs) PURE;
+    STDMETHOD(get_EnableContextMenu)(VARIANT_BOOL __RPC_FAR *pEnableContextMenu) PURE;
+    STDMETHOD(put_EnableContextMenu)(VARIANT_BOOL pEnableContextMenu) PURE;
+    STDMETHOD(get_TransparentAtStart)(VARIANT_BOOL __RPC_FAR *pTransparentAtStart) PURE;
+    STDMETHOD(put_TransparentAtStart)(VARIANT_BOOL pTransparentAtStart) PURE;
+    STDMETHOD(get_TransparentOnStop)(VARIANT_BOOL __RPC_FAR *pTransparentOnStop) PURE;
+    STDMETHOD(put_TransparentOnStop)(VARIANT_BOOL pTransparentOnStop) PURE;
+    STDMETHOD(get_ClickToPlay)(VARIANT_BOOL __RPC_FAR *pClickToPlay) PURE;
+    STDMETHOD(put_ClickToPlay)(VARIANT_BOOL pClickToPlay) PURE;
+    STDMETHOD(get_FileName)(BSTR __RPC_FAR *pbstrFileName) PURE;
+    STDMETHOD(put_FileName)(BSTR pbstrFileName) PURE;
+    STDMETHOD(get_CurrentPosition)(double __RPC_FAR *pCurrentPosition) PURE;
+    STDMETHOD(put_CurrentPosition)(double pCurrentPosition) PURE;
+    STDMETHOD(get_Rate)(double __RPC_FAR *pRate) PURE;
+    STDMETHOD(put_Rate)(double pRate) PURE;
+    STDMETHOD(get_CurrentMarker)(long __RPC_FAR *pCurrentMarker) PURE;
+    STDMETHOD(put_CurrentMarker)(long pCurrentMarker) PURE;
+    STDMETHOD(get_PlayCount)(long __RPC_FAR *pPlayCount) PURE;
+    STDMETHOD(put_PlayCount)(long pPlayCount) PURE;
+    STDMETHOD(get_CurrentState)(long __RPC_FAR *pCurrentState) PURE;
+    STDMETHOD(get_DisplaySize)(long __RPC_FAR *pDisplaySize) PURE;
+    STDMETHOD(put_DisplaySize)(long pDisplaySize) PURE;
+    STDMETHOD(get_MainWindow)(long __RPC_FAR *pMainWindow) PURE;
+    STDMETHOD(get_ControlType)(long __RPC_FAR *pControlType) PURE;
+    STDMETHOD(put_ControlType)(long pControlType) PURE;
+    STDMETHOD(get_AllowScan)(VARIANT_BOOL __RPC_FAR *pAllowScan) PURE;
+    STDMETHOD(put_AllowScan)(VARIANT_BOOL pAllowScan) PURE;
+    STDMETHOD(get_SendKeyboardEvents)(VARIANT_BOOL __RPC_FAR *pSendKeyboardEvents) PURE;
+    STDMETHOD(put_SendKeyboardEvents)(VARIANT_BOOL pSendKeyboardEvents) PURE;
+    STDMETHOD(get_SendMouseClickEvents)(VARIANT_BOOL __RPC_FAR *pSendMouseClickEvents) PURE;
+    STDMETHOD(put_SendMouseClickEvents)(VARIANT_BOOL pSendMouseClickEvents) PURE;
+    STDMETHOD(get_SendMouseMoveEvents)(VARIANT_BOOL __RPC_FAR *pSendMouseMoveEvents) PURE;
+    STDMETHOD(put_SendMouseMoveEvents)(VARIANT_BOOL pSendMouseMoveEvents) PURE;
+    STDMETHOD(get_SendStateChangeEvents)(VARIANT_BOOL __RPC_FAR *pSendStateChangeEvents) PURE;
+    STDMETHOD(put_SendStateChangeEvents)(VARIANT_BOOL pSendStateChangeEvents) PURE;
+    STDMETHOD(get_ReceivedPackets)(long __RPC_FAR *pReceivedPackets) PURE;
+    STDMETHOD(get_RecoveredPackets)(long __RPC_FAR *pRecoveredPackets) PURE;
+    STDMETHOD(get_LostPackets)(long __RPC_FAR *pLostPackets) PURE;
+    STDMETHOD(get_ReceptionQuality)(long __RPC_FAR *pReceptionQuality) PURE;
+    STDMETHOD(get_BufferingCount)(long __RPC_FAR *pBufferingCount) PURE;
+    STDMETHOD(get_CursorType)(long __RPC_FAR *pCursorType) PURE;
+    STDMETHOD(put_CursorType)(long pCursorType) PURE;
+    STDMETHOD(get_AnimationAtStart)(VARIANT_BOOL __RPC_FAR *pAnimationAtStart) PURE;
+    STDMETHOD(put_AnimationAtStart)(VARIANT_BOOL pAnimationAtStart) PURE;
+    STDMETHOD(get_AnimationOnStop)(VARIANT_BOOL __RPC_FAR *pAnimationOnStop) PURE;
+    STDMETHOD(put_AnimationOnStop)(VARIANT_BOOL pAnimationOnStop) PURE;
+    STDMETHOD(Play)(void) PURE;
+    STDMETHOD(Pause)(void) PURE;
+    STDMETHOD(Stop)(void) PURE;
+    STDMETHOD(GetMarkerTime)(long MarkerNum, double __RPC_FAR *pMarkerTime) PURE;
+    STDMETHOD(GetMarkerName)(long MarkerNum, BSTR __RPC_FAR *pbstrMarkerName) PURE;
 };
 
 };
 
-typedef IUnknown IVMRImageCompositor;
+struct INSPlay : public INSOPlay
+{
+    STDMETHOD(get_ChannelName)(BSTR __RPC_FAR *pbstrChannelName) PURE;
+    STDMETHOD(get_ChannelDescription)(BSTR __RPC_FAR *pbstrChannelDescription) PURE;
+    STDMETHOD(get_ChannelURL)(BSTR __RPC_FAR *pbstrChannelURL) PURE;
+    STDMETHOD(get_ContactAddress)(BSTR __RPC_FAR *pbstrContactAddress) PURE;
+    STDMETHOD(get_ContactPhone)(BSTR __RPC_FAR *pbstrContactPhone) PURE;
+    STDMETHOD(get_ContactEmail)(BSTR __RPC_FAR *pbstrContactEmail) PURE;
+    STDMETHOD(get_AllowChangeDisplaySize)(VARIANT_BOOL __RPC_FAR *pAllowChangeDisplaySize) PURE;
+    STDMETHOD(put_AllowChangeDisplaySize)(VARIANT_BOOL pAllowChangeDisplaySize) PURE;
+    STDMETHOD(get_CodecCount)(long __RPC_FAR *pCodecCount) PURE;
+    STDMETHOD(get_IsBroadcast)(VARIANT_BOOL __RPC_FAR *pIsBroadcast) PURE;
+    STDMETHOD(get_IsDurationValid)(VARIANT_BOOL __RPC_FAR *pIsDurationValid) PURE;
+    STDMETHOD(get_SourceProtocol)(long __RPC_FAR *pSourceProtocol) PURE;
+    STDMETHOD(get_OpenState)(long __RPC_FAR *pOpenState) PURE;
+    STDMETHOD(get_SendOpenStateChangeEvents)(VARIANT_BOOL __RPC_FAR *pSendOpenStateChangeEvents) PURE;
+    STDMETHOD(put_SendOpenStateChangeEvents)(VARIANT_BOOL pSendOpenStateChangeEvents) PURE;
+    STDMETHOD(get_SendWarningEvents)(VARIANT_BOOL __RPC_FAR *pSendWarningEvents) PURE;
+    STDMETHOD(put_SendWarningEvents)(VARIANT_BOOL pSendWarningEvents) PURE;
+    STDMETHOD(get_SendErrorEvents)(VARIANT_BOOL __RPC_FAR *pSendErrorEvents) PURE;
+    STDMETHOD(put_SendErrorEvents)(VARIANT_BOOL pSendErrorEvents) PURE;
+    STDMETHOD(get_HasError)(VARIANT_BOOL __RPC_FAR *pHasError) PURE;
+    STDMETHOD(get_ErrorDescription)(BSTR __RPC_FAR *pbstrErrorDescription) PURE;
+    STDMETHOD(get_ErrorCode)(long __RPC_FAR *pErrorCode) PURE;
+    STDMETHOD(get_PlayState)(long __RPC_FAR *pPlayState) PURE;
+    STDMETHOD(get_SendPlayStateChangeEvents)(VARIANT_BOOL __RPC_FAR *pSendPlayStateChangeEvents) PURE;
+    STDMETHOD(put_SendPlayStateChangeEvents)(VARIANT_BOOL pSendPlayStateChangeEvents) PURE;
+    STDMETHOD(get_BufferingTime)(double __RPC_FAR *pBufferingTime) PURE;
+    STDMETHOD(put_BufferingTime)(double pBufferingTime) PURE;
+    STDMETHOD(get_UseFixedUDPPort)(VARIANT_BOOL __RPC_FAR *pUseFixedUDPPort) PURE;
+    STDMETHOD(put_UseFixedUDPPort)(VARIANT_BOOL pUseFixedUDPPort) PURE;
+    STDMETHOD(get_FixedUDPPort)(long __RPC_FAR *pFixedUDPPort) PURE;
+    STDMETHOD(put_FixedUDPPort)(long pFixedUDPPort) PURE;
+    STDMETHOD(get_UseHTTPProxy)(VARIANT_BOOL __RPC_FAR *pUseHTTPProxy) PURE;
+    STDMETHOD(put_UseHTTPProxy)(VARIANT_BOOL pUseHTTPProxy) PURE;
+    STDMETHOD(get_EnableAutoProxy)(VARIANT_BOOL __RPC_FAR *pEnableAutoProxy) PURE;
+    STDMETHOD(put_EnableAutoProxy)(VARIANT_BOOL pEnableAutoProxy) PURE;
+    STDMETHOD(get_HTTPProxyHost)(BSTR __RPC_FAR *pbstrHTTPProxyHost) PURE;
+    STDMETHOD(put_HTTPProxyHost)(BSTR pbstrHTTPProxyHost) PURE;
+    STDMETHOD(get_HTTPProxyPort)(long __RPC_FAR *pHTTPProxyPort) PURE;
+    STDMETHOD(put_HTTPProxyPort)(long pHTTPProxyPort) PURE;
+    STDMETHOD(get_EnableMulticast)(VARIANT_BOOL __RPC_FAR *pEnableMulticast) PURE;
+    STDMETHOD(put_EnableMulticast)(VARIANT_BOOL pEnableMulticast) PURE;
+    STDMETHOD(get_EnableUDP)(VARIANT_BOOL __RPC_FAR *pEnableUDP) PURE;
+    STDMETHOD(put_EnableUDP)(VARIANT_BOOL pEnableUDP) PURE;
+    STDMETHOD(get_EnableTCP)(VARIANT_BOOL __RPC_FAR *pEnableTCP) PURE;
+    STDMETHOD(put_EnableTCP)(VARIANT_BOOL pEnableTCP) PURE;
+    STDMETHOD(get_EnableHTTP)(VARIANT_BOOL __RPC_FAR *pEnableHTTP) PURE;
+    STDMETHOD(put_EnableHTTP)(VARIANT_BOOL pEnableHTTP) PURE;
+    STDMETHOD(get_BufferingProgress)(long __RPC_FAR *pBufferingProgress) PURE;
+    STDMETHOD(get_BaseURL)(BSTR __RPC_FAR *pbstrBaseURL) PURE;
+    STDMETHOD(put_BaseURL)(BSTR pbstrBaseURL) PURE;
+    STDMETHOD(get_DefaultFrame)(BSTR __RPC_FAR *pbstrDefaultFrame) PURE;
+    STDMETHOD(put_DefaultFrame)(BSTR pbstrDefaultFrame) PURE;
+    STDMETHOD(AboutBox))(void) PURE;
+    STDMETHOD(Cancel)(void) PURE;
+    STDMETHOD(GetCodecInstalled)(long CodecNum, VARIANT_BOOL __RPC_FAR *pCodecInstalled) PURE;
+    STDMETHOD(GetCodecDescription)(long CodecNum, BSTR __RPC_FAR *pbstrCodecDescription) PURE;
+    STDMETHOD(GetCodecURL)(long CodecNum, BSTR __RPC_FAR *pbstrCodecURL) PURE;
+    STDMETHOD(Open)(BSTR bstrFileName) PURE;
+};
 
 
-struct IVMRFilterConfig : public IUnknown
+
+struct INSPlay1 : public INSPlay
 {
 {
-    STDMETHOD(SetImageCompositor)(IVMRImageCompositor *) PURE;
-    STDMETHOD(SetNumberOfStreams)(DWORD) PURE;
-    STDMETHOD(GetNumberOfStreams)(DWORD *) PURE;
-    STDMETHOD(SetRenderingPrefs)(DWORD) PURE;
-    STDMETHOD(GetRenderingPrefs)(DWORD *) PURE;
-    STDMETHOD(SetRenderingMode)(DWORD) PURE;
-    STDMETHOD(GetRenderingMode)(DWORD *) PURE;
+    STDMETHOD(get_MediaPlayer)(IDispatch __RPC_FAR *__RPC_FAR *ppdispatch) PURE;
 };
 
 };
 
-typedef IUnknown IBaseFilter;
-typedef IUnknown IPin;
-typedef IUnknown IEnumFilters;
-typedef int AM_MEDIA_TYPE;
+//---------------------------------------------------------------------------
+// MISC COM INTERFACES
+//---------------------------------------------------------------------------
+typedef enum _FilterState
+{
+    State_Stopped,
+    State_Paused,
+    State_Running
+} FILTER_STATE;
+typedef enum _PinDirection {
+    PINDIR_INPUT,
+    PINDIR_OUTPUT
+} PIN_DIRECTION;
+
+typedef struct _FilterInfo {
+    WCHAR        achName[128];
+    struct IFilterGraph *pGraph;
+} FILTER_INFO;
+
+typedef struct _PinInfo {
+    struct IBaseFilter *pFilter;
+    PIN_DIRECTION dir;
+    WCHAR achName[128];
+} PIN_INFO;
+
+struct IBaseFilter;
+struct IPin;
+struct IEnumFilters;
+typedef struct  _MediaType {
+    GUID      majortype;
+    GUID      subtype;
+    BOOL      bFixedSizeSamples;
+    BOOL      bTemporalCompression;
+    ULONG     lSampleSize;
+    GUID      formattype;
+    IUnknown  *pUnk;
+    ULONG     cbFormat;
+    BYTE *pbFormat;
+} AM_MEDIA_TYPE;
 
 struct IFilterGraph : public IUnknown
 {
 
 struct IFilterGraph : public IUnknown
 {
@@ -495,7 +827,6 @@ struct IFilterGraph : public IUnknown
 
 struct IGraphBuilder : public IFilterGraph
 {
 
 struct IGraphBuilder : public IFilterGraph
 {
-public:
     STDMETHOD(Connect)(IPin *, IPin *) PURE;
     STDMETHOD(Render)(IPin *) PURE;
     STDMETHOD(RenderFile)(LPCWSTR, LPCWSTR) PURE;
     STDMETHOD(Connect)(IPin *, IPin *) PURE;
     STDMETHOD(Render)(IPin *) PURE;
     STDMETHOD(RenderFile)(LPCWSTR, LPCWSTR) PURE;
@@ -505,17 +836,943 @@ public:
     STDMETHOD(ShouldOperationContinue)() PURE;
 };
 
     STDMETHOD(ShouldOperationContinue)() PURE;
 };
 
-//------------------------------------------------------------------
-// wxAMMediaBackend (Active Movie)
-//------------------------------------------------------------------
-class WXDLLIMPEXP_MEDIA wxAMMediaThread : public wxThread
+struct IReferenceClock;
+struct IEnumPins;
+#define REFERENCE_TIME LONGLONG
+struct IMediaFilter : public IPersist
+{
+    STDMETHOD(Stop)( void) PURE;
+    STDMETHOD(Pause)( void) PURE;
+    STDMETHOD(Run)(REFERENCE_TIME tStart) PURE;
+    STDMETHOD(GetState)(DWORD dwMilliSecsTimeout,
+                       FILTER_STATE *State) PURE;
+    STDMETHOD(SetSyncSource)(IReferenceClock *pClock) PURE;
+    STDMETHOD(GetSyncSource)(IReferenceClock **pClock) PURE;
+};
+
+struct IBaseFilter : public IMediaFilter
 {
 {
+    STDMETHOD(EnumPins)(IEnumPins **ppEnum) PURE;
+    STDMETHOD(FindPin)(LPCWSTR Id, IPin **ppPin) PURE;
+    STDMETHOD(QueryFilterInfo)(FILTER_INFO *pInfo) PURE;
+    STDMETHOD(JoinFilterGraph)(IFilterGraph *pGraph, LPCWSTR pName) PURE;
+    STDMETHOD(QueryVendorInfo)(LPWSTR *pVendorInfo) PURE;
+};
+
+//---------------------------------------------------------------------------
+//
+//  wxActiveX (Ryan Norton's version :))
+//  wxActiveX is (C) 2003 Lindsay Mathieson
+//
+//---------------------------------------------------------------------------
+#define WX_DECLARE_AUTOOLE(wxAutoOleInterface, I) \
+class wxAutoOleInterface \
+{   \
+    protected: \
+    I *m_interface; \
+\
+    public: \
+    explicit wxAutoOleInterface(I *pInterface = NULL) : m_interface(pInterface) {} \
+    wxAutoOleInterface(REFIID riid, IUnknown *pUnk) : m_interface(NULL) \
+    {   QueryInterface(riid, pUnk); } \
+    wxAutoOleInterface(REFIID riid, IDispatch *pDispatch) : m_interface(NULL) \
+    {   QueryInterface(riid, pDispatch); } \
+    wxAutoOleInterface(REFCLSID clsid, REFIID riid) : m_interface(NULL)\
+    {   CreateInstance(clsid, riid); }\
+    wxAutoOleInterface(const wxAutoOleInterface& ti) : m_interface(NULL)\
+    {   operator = (ti); }\
+\
+    wxAutoOleInterface& operator = (const wxAutoOleInterface& ti)\
+    {\
+        if (ti.m_interface)\
+            ti.m_interface->AddRef();\
+        Free();\
+        m_interface = ti.m_interface;\
+        return *this;\
+    }\
+\
+    wxAutoOleInterface& operator = (I *&ti)\
+    {\
+        Free();\
+        m_interface = ti;\
+        return *this;\
+    }\
+\
+    ~wxAutoOleInterface() {   Free();   }\
+\
+    inline void Free()\
+    {\
+        if (m_interface)\
+            m_interface->Release();\
+        m_interface = NULL;\
+    }\
+\
+    HRESULT QueryInterface(REFIID riid, IUnknown *pUnk)\
+    {\
+        Free();\
+        wxASSERT(pUnk != NULL);\
+        return pUnk->QueryInterface(riid, (void **) &m_interface);\
+    }\
+\
+    HRESULT CreateInstance(REFCLSID clsid, REFIID riid)\
+    {\
+        Free();\
+        return CoCreateInstance(clsid, NULL, CLSCTX_ALL, riid, (void **) &m_interface);\
+    }\
+\
+    inline operator I *() const {return m_interface;}\
+    inline I* operator ->() {return m_interface;}\
+    inline I** GetRef()    {return &m_interface;}\
+    inline bool Ok() const    {return m_interface != NULL;}\
+};
+
+WX_DECLARE_AUTOOLE(wxAutoIDispatch, IDispatch)
+WX_DECLARE_AUTOOLE(wxAutoIOleClientSite, IOleClientSite)
+WX_DECLARE_AUTOOLE(wxAutoIUnknown, IUnknown)
+WX_DECLARE_AUTOOLE(wxAutoIOleObject, IOleObject)
+WX_DECLARE_AUTOOLE(wxAutoIOleInPlaceObject, IOleInPlaceObject)
+WX_DECLARE_AUTOOLE(wxAutoIOleInPlaceActiveObject, IOleInPlaceActiveObject)
+WX_DECLARE_AUTOOLE(wxAutoIOleDocumentView, IOleDocumentView)
+WX_DECLARE_AUTOOLE(wxAutoIViewObject, IViewObject)
+WX_DECLARE_AUTOOLE(wxAutoIOleInPlaceSite, IOleInPlaceSite)
+WX_DECLARE_AUTOOLE(wxAutoIOleDocument, IOleDocument)
+WX_DECLARE_AUTOOLE(wxAutoIPersistStreamInit, IPersistStreamInit)
+WX_DECLARE_AUTOOLE(wxAutoIAdviseSink, IAdviseSink)
+
+class wxActiveX : public wxWindow
+{
+public:
+    wxActiveX(wxWindow * parent, REFIID iid, IUnknown* pUnk);
+    virtual ~wxActiveX();
+
+    void OnSize(wxSizeEvent&);
+    void OnPaint(wxPaintEvent&);
+    void OnSetFocus(wxFocusEvent&);
+    void OnKillFocus(wxFocusEvent&);
+
+protected:
+    friend class FrameSite;
+
+    wxAutoIDispatch            m_Dispatch;
+    wxAutoIOleClientSite      m_clientSite;
+    wxAutoIUnknown         m_ActiveX;
+    wxAutoIOleObject            m_oleObject;
+    wxAutoIOleInPlaceObject    m_oleInPlaceObject;
+    wxAutoIOleInPlaceActiveObject m_oleInPlaceActiveObject;
+    wxAutoIOleDocumentView    m_docView;
+    wxAutoIViewObject            m_viewObject;
+    HWND m_oleObjectHWND;
+    bool m_bAmbientUserMode;
+    DWORD m_docAdviseCookie;
+    wxWindow* m_realparent;
+
+    void CreateActiveX(REFIID, IUnknown*);
+};
+
+#define DECLARE_OLE_UNKNOWN(cls)\
+    private:\
+    class TAutoInitInt\
+    {\
+        public:\
+        LONG l;\
+        TAutoInitInt() : l(0) {}\
+    };\
+    TAutoInitInt refCount, lockCount;\
+    static void _GetInterface(cls *self, REFIID iid, void **_interface, const char *&desc);\
+    public:\
+    LONG GetRefCount();\
+    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void ** ppvObject);\
+    ULONG STDMETHODCALLTYPE AddRef();\
+    ULONG STDMETHODCALLTYPE Release();\
+    ULONG STDMETHODCALLTYPE AddLock();\
+    ULONG STDMETHODCALLTYPE ReleaseLock()
+
+#define DEFINE_OLE_TABLE(cls)\
+    LONG cls::GetRefCount() {return refCount.l;}\
+    HRESULT STDMETHODCALLTYPE cls::QueryInterface(REFIID iid, void ** ppvObject)\
+    {\
+        if (! ppvObject)\
+        {\
+            return E_FAIL;\
+        };\
+        const char *desc = NULL;\
+        cls::_GetInterface(this, iid, ppvObject, desc);\
+        if (! *ppvObject)\
+        {\
+            return E_NOINTERFACE;\
+        };\
+        ((IUnknown * )(*ppvObject))->AddRef();\
+        return S_OK;\
+    };\
+    ULONG STDMETHODCALLTYPE cls::AddRef()\
+    {\
+        InterlockedIncrement(&refCount.l);\
+        return refCount.l;\
+    };\
+    ULONG STDMETHODCALLTYPE cls::Release()\
+    {\
+        if (refCount.l > 0)\
+        {\
+            InterlockedDecrement(&refCount.l);\
+            if (refCount.l == 0)\
+            {\
+                delete this;\
+                return 0;\
+            };\
+            return refCount.l;\
+        }\
+        else\
+            return 0;\
+    }\
+    ULONG STDMETHODCALLTYPE cls::AddLock()\
+    {\
+        InterlockedIncrement(&lockCount.l);\
+        return lockCount.l;\
+    };\
+    ULONG STDMETHODCALLTYPE cls::ReleaseLock()\
+    {\
+        if (lockCount.l > 0)\
+        {\
+            InterlockedDecrement(&lockCount.l);\
+            return lockCount.l;\
+        }\
+        else\
+            return 0;\
+    }\
+    DEFINE_OLE_BASE(cls)
+
+#define DEFINE_OLE_BASE(cls)\
+    void cls::_GetInterface(cls *self, REFIID iid, void **_interface, const char *&desc)\
+    {\
+        *_interface = NULL;\
+        desc = NULL;
+
+#define OLE_INTERFACE(_iid, _type)\
+    if (IsEqualIID(iid, _iid))\
+    {\
+        *_interface = (IUnknown *) (_type *) self;\
+        desc = # _iid;\
+        return;\
+    }
+
+#define OLE_IINTERFACE(_face) OLE_INTERFACE(IID_##_face, _face)
+
+#define OLE_INTERFACE_CUSTOM(func)\
+    if (func(self, iid, _interface, desc))\
+    {\
+        return;\
+    }
+
+#define END_OLE_TABLE\
+    }
+
+
+class FrameSite :
+    public IOleClientSite,
+    public IOleInPlaceSiteEx,
+    public IOleInPlaceFrame,
+    public IOleItemContainer,
+    public IDispatch,
+    public IOleCommandTarget,
+    public IOleDocumentSite,
+    public IAdviseSink,
+    public IOleControlSite
+{
+private:
+    DECLARE_OLE_UNKNOWN(FrameSite);
+
 public:
 public:
-    virtual ExitCode Entry();
+    FrameSite(wxWindow * win, wxActiveX * win2)
+    {
+        m_window = win2;
+        m_bSupportsWindowlessActivation = true;
+        m_bInPlaceLocked = false;
+        m_bUIActive = false;
+        m_bInPlaceActive = false;
+        m_bWindowless = false;
+
+        m_nAmbientLocale = 0;
+        m_clrAmbientForeColor = ::GetSysColor(COLOR_WINDOWTEXT);
+        m_clrAmbientBackColor = ::GetSysColor(COLOR_WINDOW);
+        m_bAmbientShowHatching = true;
+        m_bAmbientShowGrabHandles = true;
+        m_bAmbientAppearance = true;
+
+        m_hDCBuffer = NULL;
+        m_hWndParent = (HWND)win->GetHWND();
+    }
+    virtual ~FrameSite(){}
+    //***************************IDispatch*****************************
+    HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID, OLECHAR ** ,
+                                            unsigned int , LCID ,
+                                            DISPID * )
+    {   return E_NOTIMPL;   }
+    STDMETHOD(GetTypeInfo)(unsigned int, LCID, ITypeInfo **)
+    {   return E_NOTIMPL;   }
+    HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int *)
+    {   return E_NOTIMPL;   }
+    HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID, LCID,
+                            WORD wFlags, DISPPARAMS *,
+                            VARIANT * pVarResult, EXCEPINFO *,
+                            unsigned int *)
+    {
+        if (!(wFlags & DISPATCH_PROPERTYGET))
+            return S_OK;
+
+        if (pVarResult == NULL)
+            return E_INVALIDARG;
 
 
-    class wxAMMediaBackend* pThis;
+        //The most common case is boolean, use as an initial type
+        V_VT(pVarResult) = VT_BOOL;
+
+        switch (dispIdMember)
+        {
+            case DISPID_AMBIENT_MESSAGEREFLECT:
+                V_BOOL(pVarResult)= FALSE;
+                return S_OK;
+
+            case DISPID_AMBIENT_DISPLAYASDEFAULT:
+                V_BOOL(pVarResult)= TRUE;
+                return S_OK;
+
+            case DISPID_AMBIENT_OFFLINEIFNOTCONNECTED:
+                V_BOOL(pVarResult) = TRUE;
+                return S_OK;
+
+            case DISPID_AMBIENT_SILENT:
+                V_BOOL(pVarResult)= TRUE;
+                return S_OK;
+
+            case DISPID_AMBIENT_APPEARANCE:
+                pVarResult->vt = VT_BOOL;
+                pVarResult->boolVal = m_bAmbientAppearance;
+                break;
+
+            case DISPID_AMBIENT_FORECOLOR:
+                pVarResult->vt = VT_I4;
+                pVarResult->lVal = (long) m_clrAmbientForeColor;
+                break;
+
+            case DISPID_AMBIENT_BACKCOLOR:
+                pVarResult->vt = VT_I4;
+                pVarResult->lVal = (long) m_clrAmbientBackColor;
+                break;
+
+            case DISPID_AMBIENT_LOCALEID:
+                pVarResult->vt = VT_I4;
+                pVarResult->lVal = (long) m_nAmbientLocale;
+                break;
+
+            case DISPID_AMBIENT_USERMODE:
+                pVarResult->vt = VT_BOOL;
+                pVarResult->boolVal = m_window->m_bAmbientUserMode;
+                break;
+
+            case DISPID_AMBIENT_SHOWGRABHANDLES:
+                pVarResult->vt = VT_BOOL;
+                pVarResult->boolVal = m_bAmbientShowGrabHandles;
+                break;
+
+            case DISPID_AMBIENT_SHOWHATCHING:
+                pVarResult->vt = VT_BOOL;
+                pVarResult->boolVal = m_bAmbientShowHatching;
+                break;
+
+            default:
+                return DISP_E_MEMBERNOTFOUND;
+        }
+
+        return S_OK;
+    }
+
+    //**************************IOleWindow***************************
+    HRESULT STDMETHODCALLTYPE GetWindow(HWND * phwnd)
+    {
+        if (phwnd == NULL)
+            return E_INVALIDARG;
+        (*phwnd) = m_hWndParent;
+        return S_OK;
+    }
+    HRESULT STDMETHODCALLTYPE ContextSensitiveHelp(BOOL)
+    {return S_OK;}
+    //**************************IOleInPlaceUIWindow*****************
+    HRESULT STDMETHODCALLTYPE GetBorder(LPRECT lprectBorder)
+    {
+        if (lprectBorder == NULL)
+            return E_INVALIDARG;
+        return INPLACE_E_NOTOOLSPACE;
+    }
+    HRESULT STDMETHODCALLTYPE RequestBorderSpace(LPCBORDERWIDTHS pborderwidths)
+    {
+        if (pborderwidths == NULL)
+            return E_INVALIDARG;
+        return INPLACE_E_NOTOOLSPACE;
+    }
+    HRESULT STDMETHODCALLTYPE SetBorderSpace(LPCBORDERWIDTHS)
+    {return S_OK;}
+    HRESULT STDMETHODCALLTYPE SetActiveObject(
+        IOleInPlaceActiveObject *pActiveObject, LPCOLESTR)
+    {
+        if (pActiveObject)
+            pActiveObject->AddRef();
+
+        m_window->m_oleInPlaceActiveObject = pActiveObject;
+        return S_OK;
+    }
+
+    //********************IOleInPlaceFrame************************
+
+    STDMETHOD(InsertMenus)(HMENU, LPOLEMENUGROUPWIDTHS){return S_OK;}
+    STDMETHOD(SetMenu)(HMENU, HOLEMENU, HWND){  return S_OK;}
+    STDMETHOD(RemoveMenus)(HMENU){return S_OK;}
+    STDMETHOD(SetStatusText)(LPCOLESTR){ return S_OK;}
+    HRESULT STDMETHODCALLTYPE EnableModeless(BOOL){return S_OK;}
+    HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG lpmsg, WORD)
+    {
+        // TODO: send an event with this id
+        if (m_window->m_oleInPlaceActiveObject.Ok())
+            m_window->m_oleInPlaceActiveObject->TranslateAccelerator(lpmsg);
+        return S_FALSE;
+    }
+
+    //*******************IOleInPlaceSite**************************
+    HRESULT STDMETHODCALLTYPE CanInPlaceActivate(){return S_OK;}
+    HRESULT STDMETHODCALLTYPE OnInPlaceActivate()
+    {   m_bInPlaceActive = true;    return S_OK;    }
+    HRESULT STDMETHODCALLTYPE OnUIActivate()
+    {   m_bUIActive = true;         return S_OK;    }
+    HRESULT STDMETHODCALLTYPE GetWindowContext(IOleInPlaceFrame **ppFrame,
+                                        IOleInPlaceUIWindow **ppDoc,
+                                        LPRECT lprcPosRect,
+                                        LPRECT lprcClipRect,
+                                        LPOLEINPLACEFRAMEINFO lpFrameInfo)
+    {
+        if (ppFrame == NULL || ppDoc == NULL || lprcPosRect == NULL ||
+            lprcClipRect == NULL || lpFrameInfo == NULL)
+        {
+            if (ppFrame != NULL)
+                (*ppFrame) = NULL;
+            if (ppDoc != NULL)
+                (*ppDoc) = NULL;
+            return E_INVALIDARG;
+        }
+
+        HRESULT hr = QueryInterface(IID_IOleInPlaceFrame, (void **) ppFrame);
+        if (! SUCCEEDED(hr))
+        {
+            return E_UNEXPECTED;
+        };
+
+        hr = QueryInterface(IID_IOleInPlaceUIWindow, (void **) ppDoc);
+        if (! SUCCEEDED(hr))
+        {
+            (*ppFrame)->Release();
+            *ppFrame = NULL;
+            return E_UNEXPECTED;
+        };
+
+        RECT rect;
+        ::GetClientRect(m_hWndParent, &rect);
+        if (lprcPosRect)
+        {
+            lprcPosRect->left = lprcPosRect->top = 0;
+            lprcPosRect->right = rect.right;
+            lprcPosRect->bottom = rect.bottom;
+        };
+        if (lprcClipRect)
+        {
+            lprcClipRect->left = lprcClipRect->top = 0;
+            lprcClipRect->right = rect.right;
+            lprcClipRect->bottom = rect.bottom;
+        };
+
+        memset(lpFrameInfo, 0, sizeof(OLEINPLACEFRAMEINFO));
+        lpFrameInfo->cb = sizeof(OLEINPLACEFRAMEINFO);
+        lpFrameInfo->hwndFrame = m_hWndParent;
+
+        return S_OK;
+    }
+    HRESULT STDMETHODCALLTYPE Scroll(SIZE){return S_OK;}
+    HRESULT STDMETHODCALLTYPE OnUIDeactivate(BOOL)
+    {   m_bUIActive = false;         return S_OK;    }
+    HRESULT STDMETHODCALLTYPE OnInPlaceDeactivate()
+    {   m_bInPlaceActive = false;    return S_OK;    }
+    HRESULT STDMETHODCALLTYPE DiscardUndoState(){return S_OK;}
+    HRESULT STDMETHODCALLTYPE DeactivateAndUndo(){return S_OK; }
+    HRESULT STDMETHODCALLTYPE OnPosRectChange(LPCRECT lprcPosRect)
+    {
+        if (m_window->m_oleInPlaceObject.Ok() && lprcPosRect)
+        {
+            m_window->m_oleInPlaceObject->SetObjectRects(
+                lprcPosRect, lprcPosRect);
+        }
+        return S_OK;
+    }
+    //*************************IOleInPlaceSiteEx***********************
+    HRESULT STDMETHODCALLTYPE OnInPlaceActivateEx(BOOL * pfNoRedraw, DWORD)
+    {
+        OleLockRunning(m_window->m_ActiveX, TRUE, FALSE);
+        if (pfNoRedraw)
+            (*pfNoRedraw) = FALSE;
+        return S_OK;
+    }
+
+    HRESULT STDMETHODCALLTYPE OnInPlaceDeactivateEx(BOOL)
+    {
+        OleLockRunning(m_window->m_ActiveX, FALSE, FALSE);
+        return S_OK;
+    }
+    STDMETHOD(RequestUIActivate)(){ return S_OK;}
+    //*************************IOleClientSite**************************
+    HRESULT STDMETHODCALLTYPE SaveObject(){return S_OK;}
+    const char *OleGetMonikerToStr(DWORD dwAssign)
+    {
+        switch (dwAssign)
+        {
+        case OLEGETMONIKER_ONLYIFTHERE  : return "OLEGETMONIKER_ONLYIFTHERE";
+        case OLEGETMONIKER_FORCEASSIGN  : return "OLEGETMONIKER_FORCEASSIGN";
+        case OLEGETMONIKER_UNASSIGN     : return "OLEGETMONIKER_UNASSIGN";
+        case OLEGETMONIKER_TEMPFORUSER  : return "OLEGETMONIKER_TEMPFORUSER";
+        default                         : return "Bad Enum";
+        };
+    };
+
+    const char *OleGetWhicMonikerStr(DWORD dwWhichMoniker)
+    {
+        switch(dwWhichMoniker)
+        {
+        case OLEWHICHMK_CONTAINER   : return "OLEWHICHMK_CONTAINER";
+        case OLEWHICHMK_OBJREL      : return "OLEWHICHMK_OBJREL";
+        case OLEWHICHMK_OBJFULL     : return "OLEWHICHMK_OBJFULL";
+        default                     : return "Bad Enum";
+        };
+    };
+    STDMETHOD(GetMoniker)(DWORD, DWORD, IMoniker **){return E_FAIL;}
+    HRESULT STDMETHODCALLTYPE GetContainer(LPOLECONTAINER * ppContainer)
+    {
+        if (ppContainer == NULL)
+            return E_INVALIDARG;
+        HRESULT hr = QueryInterface(
+            IID_IOleContainer, (void**)(ppContainer));
+        wxASSERT(SUCCEEDED(hr));
+        return hr;
+    }
+    HRESULT STDMETHODCALLTYPE ShowObject()
+    {
+        if (m_window->m_oleObjectHWND)
+            ::ShowWindow(m_window->m_oleObjectHWND, SW_SHOW);
+        return S_OK;
+    }
+    STDMETHOD(OnShowWindow)(BOOL){return S_OK;}
+    STDMETHOD(RequestNewObjectLayout)(){return E_NOTIMPL;}
+    //********************IParseDisplayName***************************
+    HRESULT STDMETHODCALLTYPE ParseDisplayName(
+        IBindCtx *, LPOLESTR, ULONG *, IMoniker **){return E_NOTIMPL;}
+    //********************IOleContainer*******************************
+    STDMETHOD(EnumObjects)(DWORD, IEnumUnknown **){return E_NOTIMPL;}
+    HRESULT STDMETHODCALLTYPE LockContainer(BOOL){return S_OK;}
+    //********************IOleItemContainer***************************
+    HRESULT STDMETHODCALLTYPE
+    #ifdef _UNICODE
+    GetObjectW
+    #else
+    GetObjectA
+    #endif
+    (LPOLESTR pszItem, DWORD, IBindCtx *, REFIID, void ** ppvObject)
+    {
+        if (pszItem == NULL || ppvObject == NULL)
+            return E_INVALIDARG;
+        *ppvObject = NULL;
+        return MK_E_NOOBJECT;
+    }
+    HRESULT STDMETHODCALLTYPE GetObjectStorage(
+        LPOLESTR pszItem, IBindCtx * , REFIID, void ** ppvStorage)
+    {
+        if (pszItem == NULL || ppvStorage == NULL)
+            return E_INVALIDARG;
+        *ppvStorage = NULL;
+        return MK_E_NOOBJECT;
+    }
+    HRESULT STDMETHODCALLTYPE IsRunning(LPOLESTR pszItem)
+    {
+        if (pszItem == NULL)
+            return E_INVALIDARG;
+        return MK_E_NOOBJECT;
+    }
+    //***********************IOleControlSite*****************************
+    HRESULT STDMETHODCALLTYPE OnControlInfoChanged()
+    {return S_OK;}
+    HRESULT STDMETHODCALLTYPE LockInPlaceActive(BOOL fLock)
+    {
+        m_bInPlaceLocked = (fLock) ? true : false;
+        return S_OK;
+    }
+    HRESULT STDMETHODCALLTYPE GetExtendedControl(IDispatch **)
+    {return E_NOTIMPL;}
+    HRESULT STDMETHODCALLTYPE TransformCoords(
+        POINTL * pPtlHimetric, POINTF * pPtfContainer, DWORD)
+    {
+        if (pPtlHimetric == NULL || pPtfContainer == NULL)
+            return E_INVALIDARG;
+        return E_NOTIMPL;
+    }
+    HRESULT STDMETHODCALLTYPE TranslateAccelerator(LPMSG, DWORD)
+    {return E_NOTIMPL;}
+    HRESULT STDMETHODCALLTYPE OnFocus(BOOL){return S_OK;}
+    HRESULT STDMETHODCALLTYPE ShowPropertyFrame(){return E_NOTIMPL;}
+    //**************************IOleCommandTarget***********************
+    HRESULT STDMETHODCALLTYPE QueryStatus(const GUID *, ULONG cCmds,
+                                OLECMD * prgCmds, OLECMDTEXT *)
+    {
+        if (prgCmds == NULL) return E_INVALIDARG;
+        for (ULONG nCmd = 0; nCmd < cCmds; nCmd++)
+        {
+            // unsupported by default
+            prgCmds[nCmd].cmdf = 0;
+        }
+        return OLECMDERR_E_UNKNOWNGROUP;
+    }
+
+    HRESULT STDMETHODCALLTYPE Exec(const GUID *, DWORD,
+                            DWORD, VARIANTARG *, VARIANTARG *)
+    {return OLECMDERR_E_NOTSUPPORTED;}
+
+    //**********************IAdviseSink************************************
+    void STDMETHODCALLTYPE OnDataChange(FORMATETC *, STGMEDIUM *) {}
+    void STDMETHODCALLTYPE OnViewChange(DWORD, LONG) {}
+    void STDMETHODCALLTYPE OnRename(IMoniker *){}
+    void STDMETHODCALLTYPE OnSave(){}
+    void STDMETHODCALLTYPE OnClose(){}
+
+    //**********************IOleDocumentSite***************************
+    HRESULT STDMETHODCALLTYPE ActivateMe(
+        IOleDocumentView __RPC_FAR *pViewToActivate)
+    {
+        wxAutoIOleInPlaceSite inPlaceSite(
+            IID_IOleInPlaceSite, (IDispatch *) this);
+        if (!inPlaceSite.Ok())
+            return E_FAIL;
+
+        if (pViewToActivate)
+        {
+            m_window->m_docView = pViewToActivate;
+            m_window->m_docView->SetInPlaceSite(inPlaceSite);
+        }
+        else
+        {
+            wxAutoIOleDocument oleDoc(
+                IID_IOleDocument, m_window->m_oleObject);
+            if (! oleDoc.Ok())
+                return E_FAIL;
+
+            HRESULT hr = oleDoc->CreateView(inPlaceSite, NULL,
+                                    0, m_window->m_docView.GetRef());
+            if (hr != S_OK)
+                return E_FAIL;
+
+            m_window->m_docView->SetInPlaceSite(inPlaceSite);
+        };
+
+        m_window->m_docView->UIActivate(TRUE);
+        return S_OK;
+    };
+
+
+protected:
+    wxActiveX * m_window;
+
+    HDC m_hDCBuffer;
+    HWND m_hWndParent;
+
+    bool m_bSupportsWindowlessActivation;
+    bool m_bInPlaceLocked;
+    bool m_bInPlaceActive;
+    bool m_bUIActive;
+    bool m_bWindowless;
+
+    LCID m_nAmbientLocale;
+    COLORREF m_clrAmbientForeColor;
+    COLORREF m_clrAmbientBackColor;
+    bool m_bAmbientShowHatching;
+    bool m_bAmbientShowGrabHandles;
+    bool m_bAmbientAppearance;
 };
 
 };
 
+DEFINE_OLE_TABLE(FrameSite)
+    OLE_INTERFACE(IID_IUnknown, IOleClientSite)
+    OLE_IINTERFACE(IOleClientSite)
+    OLE_INTERFACE(IID_IOleWindow, IOleInPlaceSite)
+    OLE_IINTERFACE(IOleInPlaceSite)
+    OLE_IINTERFACE(IOleInPlaceSiteEx)
+    OLE_IINTERFACE(IOleInPlaceUIWindow)
+    OLE_IINTERFACE(IOleInPlaceFrame)
+    OLE_IINTERFACE(IParseDisplayName)
+    OLE_IINTERFACE(IOleContainer)
+    OLE_IINTERFACE(IOleItemContainer)
+    OLE_IINTERFACE(IDispatch)
+    OLE_IINTERFACE(IOleCommandTarget)
+    OLE_IINTERFACE(IOleDocumentSite)
+    OLE_IINTERFACE(IAdviseSink)
+    OLE_IINTERFACE(IOleControlSite)
+END_OLE_TABLE;
+
+
+wxActiveX::wxActiveX(wxWindow * parent, REFIID iid, IUnknown* pUnk)
+    : m_realparent(parent)
+{
+    m_bAmbientUserMode = true;
+    m_docAdviseCookie = 0;
+    CreateActiveX(iid, pUnk);
+}
+
+wxActiveX::~wxActiveX()
+{
+    // disconnect connection points
+    if (m_oleInPlaceObject.Ok())
+    {
+        m_oleInPlaceObject->InPlaceDeactivate();
+        m_oleInPlaceObject->UIDeactivate();
+    }
+
+    if (m_oleObject.Ok())
+    {
+        if (m_docAdviseCookie != 0)
+            m_oleObject->Unadvise(m_docAdviseCookie);
+
+        m_oleObject->DoVerb(
+            OLEIVERB_HIDE, NULL, m_clientSite, 0, (HWND) GetHWND(), NULL);
+        m_oleObject->Close(OLECLOSE_NOSAVE);
+        m_oleObject->SetClientSite(NULL);
+    }
+}
+
+void wxActiveX::CreateActiveX(REFIID iid, IUnknown* pUnk)
+{
+    HRESULT hret;
+    hret = m_ActiveX.QueryInterface(iid, pUnk);
+    wxASSERT(SUCCEEDED(hret));
+
+    // FrameSite
+    FrameSite *frame = new FrameSite(m_realparent, this);
+    // oleClientSite
+    hret = m_clientSite.QueryInterface(
+        IID_IOleClientSite, (IDispatch *) frame);
+    wxASSERT(SUCCEEDED(hret));
+    // adviseSink
+    wxAutoIAdviseSink adviseSink(IID_IAdviseSink, (IDispatch *) frame);
+    wxASSERT(adviseSink.Ok());
+
+    // Get Dispatch interface
+    hret = m_Dispatch.QueryInterface(IID_IDispatch, m_ActiveX);
+
+    // Get IOleObject interface
+    hret = m_oleObject.QueryInterface(IID_IOleObject, m_ActiveX);
+    wxASSERT(SUCCEEDED(hret));
+
+    // get IViewObject Interface
+    hret = m_viewObject.QueryInterface(IID_IViewObject, m_ActiveX);
+    wxASSERT(SUCCEEDED(hret));
+
+    // document advise
+    m_docAdviseCookie = 0;
+    hret = m_oleObject->Advise(adviseSink, &m_docAdviseCookie);
+    m_oleObject->SetHostNames(L"wxActiveXContainer", NULL);
+    OleSetContainedObject(m_oleObject, TRUE);
+    OleRun(m_oleObject);
+
+
+    // Get IOleInPlaceObject interface
+    hret = m_oleInPlaceObject.QueryInterface(
+        IID_IOleInPlaceObject, m_ActiveX);
+    wxASSERT(SUCCEEDED(hret));
+
+    // status
+    DWORD dwMiscStatus;
+    m_oleObject->GetMiscStatus(DVASPECT_CONTENT, &dwMiscStatus);
+    wxASSERT(SUCCEEDED(hret));
+
+    // set client site first ?
+    if (dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST)
+        m_oleObject->SetClientSite(m_clientSite);
+
+
+    // stream init
+    wxAutoIPersistStreamInit
+        pPersistStreamInit(IID_IPersistStreamInit, m_oleObject);
+
+    if (pPersistStreamInit.Ok())
+    {
+        hret = pPersistStreamInit->InitNew();
+    }
+
+    if (! (dwMiscStatus & OLEMISC_SETCLIENTSITEFIRST))
+        m_oleObject->SetClientSite(m_clientSite);
+
+
+    RECT posRect;
+    ::GetClientRect((HWND)m_realparent->GetHWND(), &posRect);
+
+    m_oleObjectHWND = 0;
+
+    if (m_oleInPlaceObject.Ok())
+    {
+        hret = m_oleInPlaceObject->GetWindow(&m_oleObjectHWND);
+        if (SUCCEEDED(hret))
+            ::SetActiveWindow(m_oleObjectHWND);
+    }
+
+
+    if (! (dwMiscStatus & OLEMISC_INVISIBLEATRUNTIME))
+    {
+        if (posRect.right > 0 && posRect.bottom > 0 &&
+            m_oleInPlaceObject.Ok())
+                m_oleInPlaceObject->SetObjectRects(&posRect, &posRect);
+
+        hret = m_oleObject->DoVerb(OLEIVERB_INPLACEACTIVATE, NULL,
+            m_clientSite, 0, (HWND)m_realparent->GetHWND(), &posRect);
+        hret = m_oleObject->DoVerb(OLEIVERB_SHOW, 0, m_clientSite, 0,
+            (HWND)m_realparent->GetHWND(), &posRect);
+    }
+
+    if (! m_oleObjectHWND && m_oleInPlaceObject.Ok())
+    {
+        hret = m_oleInPlaceObject->GetWindow(&m_oleObjectHWND);
+    }
+
+    if (m_oleObjectHWND)
+    {
+        ::SetActiveWindow(m_oleObjectHWND);
+        ::ShowWindow(m_oleObjectHWND, SW_SHOW);
+
+        this->AssociateHandle(m_oleObjectHWND);
+        this->Reparent(m_realparent);
+
+        wxWindow* pWnd = m_realparent;
+        int id = m_realparent->GetId();
+
+        pWnd->Connect(id, wxEVT_SIZE,
+            wxSizeEventHandler(wxActiveX::OnSize), 0, this);
+        pWnd->Connect(id, wxEVT_SET_FOCUS,
+            wxFocusEventHandler(wxActiveX::OnSetFocus), 0, this);
+        pWnd->Connect(id, wxEVT_KILL_FOCUS,
+            wxFocusEventHandler(wxActiveX::OnKillFocus), 0, this);
+    }
+}
+
+#define HIMETRIC_PER_INCH   2540
+#define MAP_PIX_TO_LOGHIM(x,ppli)   MulDiv(HIMETRIC_PER_INCH, (x), (ppli))
+
+static void PixelsToHimetric(SIZEL &sz)
+{
+    static int logX = 0;
+    static int logY = 0;
+
+    if (logY == 0)
+    {
+        // initaliase
+        HDC dc = GetDC(NULL);
+        logX = GetDeviceCaps(dc, LOGPIXELSX);
+        logY = GetDeviceCaps(dc, LOGPIXELSY);
+        ReleaseDC(NULL, dc);
+    };
+
+#define HIMETRIC_INCH   2540
+#define CONVERT(x, logpixels)   MulDiv(HIMETRIC_INCH, (x), (logpixels))
+
+    sz.cx = CONVERT(sz.cx, logX);
+    sz.cy = CONVERT(sz.cy, logY);
+
+#undef CONVERT
+#undef HIMETRIC_INCH
+}
+
+
+void wxActiveX::OnSize(wxSizeEvent& event)
+{
+    int w, h;
+    GetParent()->GetClientSize(&w, &h);
+
+    RECT posRect;
+    posRect.left = 0;
+    posRect.top = 0;
+    posRect.right = w;
+    posRect.bottom = h;
+
+    if (w <= 0 && h <= 0)
+        return;
+
+    // extents are in HIMETRIC units
+    if (m_oleObject.Ok())
+    {
+        SIZEL sz = {w, h};
+        PixelsToHimetric(sz);
+
+        SIZEL sz2;
+
+        m_oleObject->GetExtent(DVASPECT_CONTENT, &sz2);
+        if (sz2.cx !=  sz.cx || sz.cy != sz2.cy)
+            m_oleObject->SetExtent(DVASPECT_CONTENT, &sz);
+    };
+
+    if (m_oleInPlaceObject.Ok())
+        m_oleInPlaceObject->SetObjectRects(&posRect, &posRect);
+
+    event.Skip();
+}
+
+void wxActiveX::OnPaint(wxPaintEvent& WXUNUSED(event))
+{
+    wxPaintDC dc(this);
+    // Draw only when control is windowless or deactivated
+    if (m_viewObject)
+    {
+        dc.BeginDrawing();
+        int w, h;
+        GetParent()->GetSize(&w, &h);
+        RECT posRect;
+        posRect.left = 0;
+        posRect.top = 0;
+        posRect.right = w;
+        posRect.bottom = h;
+
+        ::RedrawWindow(m_oleObjectHWND, NULL, NULL, RDW_INTERNALPAINT);
+        RECTL *prcBounds = (RECTL *) &posRect;
+        m_viewObject->Draw(DVASPECT_CONTENT, -1, NULL, NULL, NULL,
+            (HDC)dc.GetHDC(), prcBounds, NULL, NULL, 0);
+
+        dc.EndDrawing();
+    }
+
+//  We've got this one I think
+//    event.Skip();
+}
+
+void wxActiveX::OnSetFocus(wxFocusEvent& event)
+{
+    if (m_oleInPlaceActiveObject.Ok())
+        m_oleInPlaceActiveObject->OnFrameWindowActivate(TRUE);
+
+    event.Skip();
+}
+
+void wxActiveX::OnKillFocus(wxFocusEvent& event)
+{
+    if (m_oleInPlaceActiveObject.Ok())
+        m_oleInPlaceActiveObject->OnFrameWindowActivate(FALSE);
+
+    event.Skip();
+}
+
+//###########################################################################
+//
+//
+//  wxAMMediaBackend
+//
+//
+//###########################################################################
+
+typedef BOOL (WINAPI* LPAMGETERRORTEXT)(HRESULT, wxChar *, DWORD);
+
 //cludgy workaround for wx events.  slots would be nice :)
 class WXDLLIMPEXP_MEDIA wxAMMediaEvtHandler : public wxEvtHandler
 {
 //cludgy workaround for wx events.  slots would be nice :)
 class WXDLLIMPEXP_MEDIA wxAMMediaEvtHandler : public wxEvtHandler
 {
@@ -524,14 +1781,12 @@ public:
     void OnEraseBackground(wxEraseEvent&);
 };
 
     void OnEraseBackground(wxEraseEvent&);
 };
 
-typedef BOOL (WINAPI* LPAMGETERRORTEXT)(HRESULT, wxChar *, DWORD);
-
 class WXDLLIMPEXP_MEDIA wxAMMediaBackend : public wxMediaBackend
 {
 public:
     wxAMMediaBackend();
 class WXDLLIMPEXP_MEDIA wxAMMediaBackend : public wxMediaBackend
 {
 public:
     wxAMMediaBackend();
-
     virtual ~wxAMMediaBackend();
     virtual ~wxAMMediaBackend();
+    void Clear();
 
     virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
                                      wxWindowID id,
 
     virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
                                      wxWindowID id,
@@ -547,6 +1802,10 @@ public:
 
     virtual bool Load(const wxString& fileName);
     virtual bool Load(const wxURI& location);
 
     virtual bool Load(const wxString& fileName);
     virtual bool Load(const wxURI& location);
+    virtual bool Load(const wxURI& location, const wxURI& proxy);
+
+    bool DoLoad(const wxString& location);
+    void FinishLoad();
 
     virtual wxMediaState GetState();
 
 
     virtual wxMediaState GetState();
 
@@ -563,37 +1822,35 @@ public:
     virtual double GetVolume();
     virtual bool SetVolume(double);
 
     virtual double GetVolume();
     virtual bool SetVolume(double);
 
+    virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags);
     void Cleanup();
     void Cleanup();
-    void OnStop();
-    bool SetWindowlessMode(IGraphBuilder* pGB,
-                           IVMRWindowlessControl** ppVMC = NULL);
-
-    wxControl* m_ctrl;
-
-    wxMediaState m_state;
-    wxCriticalSection m_rendercs;
 
 
-    IVMRWindowlessControl* m_pVMC;
-    IGraphBuilder* m_pGB;
-    IBasicAudio* m_pBA;
-    IMediaControl* m_pMC;
-    IMediaEvent* m_pME;
-    IMediaPosition* m_pMS;
-    bool m_bVideo;
-
-    wxAMMediaThread* m_pThread;
+    void DoGetDownloadProgress(wxLongLong*, wxLongLong*);
+    virtual wxLongLong GetDownloadProgress()
+    {
+        wxLongLong progress, total;
+        DoGetDownloadProgress(&progress, &total);
+        return progress;
+    }
+    virtual wxLongLong GetDownloadTotal()
+    {
+        wxLongLong progress, total;
+        DoGetDownloadProgress(&progress, &total);
+        return total;
+    }
 
 
+    wxControl* m_ctrl;
+    wxActiveX* m_pAX;
+    IActiveMovie* m_pAM;
+    IMediaPlayer* m_pMP;
+    wxTimer* m_pTimer;
     wxSize m_bestSize;
     wxSize m_bestSize;
-
 #ifdef __WXDEBUG__
     HMODULE m_hQuartzDll;
     LPAMGETERRORTEXT m_lpAMGetErrorText;
     wxString GetErrorString(HRESULT hrdsv);
 #endif
 
 #ifdef __WXDEBUG__
     HMODULE m_hQuartzDll;
     LPAMGETERRORTEXT m_lpAMGetErrorText;
     wxString GetErrorString(HRESULT hrdsv);
 #endif
 
-    friend class wxAMMediaThread;
-    friend class wxAMMediaEvtHandler;
-
     DECLARE_DYNAMIC_CLASS(wxAMMediaBackend)
 };
 
     DECLARE_DYNAMIC_CLASS(wxAMMediaBackend)
 };
 
@@ -663,6 +1920,12 @@ public:
 //
 //  wxQTMediaBackend
 //
 //
 //  wxQTMediaBackend
 //
+// We don't include Quicktime headers here and define all the types
+// ourselves because looking for the quicktime libaries etc. would
+// be tricky to do and making this a dependency for the MSVC projects
+// would be unrealistic.
+//
+// Thanks to Robert Roebling for the wxDL macro/library idea
 //---------------------------------------------------------------------------
 
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 
 //---------------------------------------------------------------------------
@@ -683,6 +1946,7 @@ typedef wxInt32 OSStatus;
 typedef unsigned char                   Str255[256];
 #define StringPtr unsigned char*
 #define newMovieActive 1
 typedef unsigned char                   Str255[256];
 #define StringPtr unsigned char*
 #define newMovieActive 1
+#define newMovieAsyncOK (1 << 8)
 #define Ptr char*
 #define Handle Ptr*
 #define Fixed long
 #define Ptr char*
 #define Handle Ptr*
 #define Fixed long
@@ -690,6 +1954,10 @@ typedef unsigned char                   Str255[256];
 #define CGrafPtr struct GrafPort *
 #define TimeScale long
 #define TimeBase struct TimeBaseRecord *
 #define CGrafPtr struct GrafPort *
 #define TimeScale long
 #define TimeBase struct TimeBaseRecord *
+typedef struct ComponentInstanceRecord * ComponentInstance;
+#define kMovieLoadStatePlayable 10000
+#define Boolean int
+#define MovieController ComponentInstance
 
 #ifndef URLDataHandlerSubType
 #if defined(__WATCOMC__) || defined(__MINGW32__)
 
 #ifndef URLDataHandlerSubType
 #if defined(__WATCOMC__) || defined(__MINGW32__)
@@ -726,6 +1994,27 @@ struct TimeRecord {
     TimeBase   base;
 };
 
     TimeBase   base;
 };
 
+struct Point {
+    short                           v;
+    short                           h;
+};
+
+struct EventRecord {
+    wxUint16                       what;
+    wxUint32                          message;
+    wxUint32                          when;
+    Point                           where;
+    wxUint16                  modifiers;
+};
+
+enum {
+    mcTopLeftMovie              = 1,
+    mcScaleMovieToFit           = 2,
+    mcWithBadge                 = 4,
+    mcNotVisible                = 8,
+    mcWithFrame                 = 16
+};
+
 //---------------------------------------------------------------------------
 //  QT Library
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 //  QT Library
 //---------------------------------------------------------------------------
@@ -746,7 +2035,6 @@ struct TimeRecord {
     if (!success) { wxLog::EnableLogging(bWasLoggingEnabled); return false; }
 
 
     if (!success) { wxLog::EnableLogging(bWasLoggingEnabled); return false; }
 
 
-//Class that utilizes Robert Roeblings Dynamic Library Macros
 class WXDLLIMPEXP_MEDIA wxQuickTimeLibrary
 {
 public:
 class WXDLLIMPEXP_MEDIA wxQuickTimeLibrary
 {
 public:
@@ -824,6 +2112,35 @@ public:
     wxDL_VOIDMETHOD_DEFINE(SetMovieTime, (Movie m, TimeRecord* tr), (m,tr) );
     wxDL_METHOD_DEFINE(short, GetMovieVolume, (Movie m), (m), 0);
     wxDL_VOIDMETHOD_DEFINE(SetMovieVolume, (Movie m, short sVolume), (m,sVolume) );
     wxDL_VOIDMETHOD_DEFINE(SetMovieTime, (Movie m, TimeRecord* tr), (m,tr) );
     wxDL_METHOD_DEFINE(short, GetMovieVolume, (Movie m), (m), 0);
     wxDL_VOIDMETHOD_DEFINE(SetMovieVolume, (Movie m, short sVolume), (m,sVolume) );
+    wxDL_VOIDMETHOD_DEFINE(SetMovieTimeValue, (Movie m, long s), (m,s));
+    wxDL_METHOD_DEFINE(ComponentInstance, NewMovieController, (Movie m, const Rect* mr, long fl), (m,mr,fl), 0);
+    wxDL_VOIDMETHOD_DEFINE(DisposeMovieController, (ComponentInstance ci), (ci));
+    wxDL_METHOD_DEFINE(int, MCSetVisible, (ComponentInstance m, int b), (m, b), 0);
+
+
+    wxDL_VOIDMETHOD_DEFINE(PrePrerollMovie, (Movie m, long t, Fixed r, WXFARPROC p1, void* p2), (m,t,r,p1,p2) );
+    wxDL_VOIDMETHOD_DEFINE(PrerollMovie, (Movie m, long t, Fixed r), (m,t,r) );
+    wxDL_METHOD_DEFINE(Fixed, GetMoviePreferredRate, (Movie m), (m), 0);
+    wxDL_METHOD_DEFINE(long, GetMovieLoadState, (Movie m), (m), 0);
+    wxDL_METHOD_DEFINE(void*, NewRoutineDescriptor, (WXFARPROC f, int l, void* junk), (f, l, junk), 0);
+    wxDL_VOIDMETHOD_DEFINE(DisposeRoutineDescriptor, (void* f), (f));
+    wxDL_METHOD_DEFINE(void*, GetCurrentArchitecture, (), (), 0);
+    wxDL_METHOD_DEFINE(int, MCDoAction, (ComponentInstance ci, long f, void* p), (ci,f,p), 0);
+    wxDL_VOIDMETHOD_DEFINE(MCSetControllerBoundsRect, (ComponentInstance ci, Rect* r), (ci,r));
+    wxDL_VOIDMETHOD_DEFINE(DestroyPortAssociation, (CGrafPtr g), (g));
+    wxDL_VOIDMETHOD_DEFINE(NativeEventToMacEvent, (MSG* p1, EventRecord* p2), (p1,p2));
+    wxDL_VOIDMETHOD_DEFINE(MCIsPlayerEvent, (ComponentInstance ci, EventRecord* p2), (ci, p2));
+    wxDL_METHOD_DEFINE(int, MCSetMovie, (ComponentInstance ci, Movie m, void* p1, Point w),
+                          (ci,m,p1,w),0);
+    wxDL_VOIDMETHOD_DEFINE(MCPositionController,
+        (ComponentInstance ci, Rect* r, void* junk, void* morejunk), (ci,r,junk,morejunk));
+    wxDL_VOIDMETHOD_DEFINE(MCSetActionFilterWithRefCon,
+        (ComponentInstance ci, WXFARPROC cb, void* ref), (ci,cb,ref));
+    wxDL_VOIDMETHOD_DEFINE(MCGetControllerInfo, (MovieController mc, long* flags), (mc,flags));
+    wxDL_VOIDMETHOD_DEFINE(BeginUpdate, (CGrafPtr port), (port));
+    wxDL_VOIDMETHOD_DEFINE(UpdateMovie, (Movie m), (m));
+    wxDL_VOIDMETHOD_DEFINE(EndUpdate, (CGrafPtr port), (port));
+    wxDL_METHOD_DEFINE( OSErr, GetMoviesStickyError, (), (), -1);
 };
 
 bool wxQuickTimeLibrary::Initialize()
 };
 
 bool wxQuickTimeLibrary::Initialize()
@@ -838,43 +2155,61 @@ bool wxQuickTimeLibrary::Initialize()
         return false;
     }
 
         return false;
     }
 
-    bool bOk;   //TODO:  Get rid of this, use m_ok instead (not a biggie)
-
-    wxDL_METHOD_LOAD( m_dll, StartMovie, bOk );
-    wxDL_METHOD_LOAD( m_dll, StopMovie, bOk );
-    wxDL_METHOD_LOAD( m_dll, IsMovieDone, bOk );
-    wxDL_METHOD_LOAD( m_dll, GoToBeginningOfMovie, bOk );
-    wxDL_METHOD_LOAD( m_dll, GetMoviesError, bOk );
-    wxDL_METHOD_LOAD( m_dll, EnterMovies, bOk );
-    wxDL_METHOD_LOAD( m_dll, ExitMovies, bOk );
-    wxDL_METHOD_LOAD( m_dll, InitializeQTML, bOk );
-    wxDL_METHOD_LOAD( m_dll, TerminateQTML, bOk );
-    wxDL_METHOD_LOAD( m_dll, NativePathNameToFSSpec, bOk );
-    wxDL_METHOD_LOAD( m_dll, OpenMovieFile, bOk );
-    wxDL_METHOD_LOAD( m_dll, CloseMovieFile, bOk );
-    wxDL_METHOD_LOAD( m_dll, NewMovieFromFile, bOk );
-    wxDL_METHOD_LOAD( m_dll, GetMovieRate, bOk );
-    wxDL_METHOD_LOAD( m_dll, SetMovieRate, bOk );
-    wxDL_METHOD_LOAD( m_dll, MoviesTask, bOk );
-    wxDL_METHOD_LOAD( m_dll, BlockMove, bOk );
-    wxDL_METHOD_LOAD( m_dll, NewHandleClear, bOk );
-    wxDL_METHOD_LOAD( m_dll, NewMovieFromDataRef, bOk );
-    wxDL_METHOD_LOAD( m_dll, DisposeHandle, bOk );
-    wxDL_METHOD_LOAD( m_dll, GetMovieNaturalBoundsRect, bOk );
-    wxDL_METHOD_LOAD( m_dll, GetMovieIndTrackType, bOk );
-    wxDL_METHOD_LOAD( m_dll, CreatePortAssociation, bOk );
-    wxDL_METHOD_LOAD( m_dll, GetNativeWindowPort, bOk );
-    wxDL_METHOD_LOAD( m_dll, SetMovieGWorld, bOk );
-    wxDL_METHOD_LOAD( m_dll, DisposeMovie, bOk );
-    wxDL_METHOD_LOAD( m_dll, SetMovieBox, bOk );
-    wxDL_METHOD_LOAD( m_dll, SetMovieTimeScale, bOk );
-    wxDL_METHOD_LOAD( m_dll, GetMovieDuration, bOk );
-    wxDL_METHOD_LOAD( m_dll, GetMovieTimeBase, bOk );
-    wxDL_METHOD_LOAD( m_dll, GetMovieTimeScale, bOk );
-    wxDL_METHOD_LOAD( m_dll, GetMovieTime, bOk );
-    wxDL_METHOD_LOAD( m_dll, SetMovieTime, bOk );
-    wxDL_METHOD_LOAD( m_dll, GetMovieVolume, bOk );
-    wxDL_METHOD_LOAD( m_dll, SetMovieVolume, bOk );
+    wxDL_METHOD_LOAD( m_dll, StartMovie, m_ok );
+    wxDL_METHOD_LOAD( m_dll, StopMovie, m_ok );
+    wxDL_METHOD_LOAD( m_dll, IsMovieDone, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GoToBeginningOfMovie, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMoviesError, m_ok );
+    wxDL_METHOD_LOAD( m_dll, EnterMovies, m_ok );
+    wxDL_METHOD_LOAD( m_dll, ExitMovies, m_ok );
+    wxDL_METHOD_LOAD( m_dll, InitializeQTML, m_ok );
+    wxDL_METHOD_LOAD( m_dll, TerminateQTML, m_ok );
+    wxDL_METHOD_LOAD( m_dll, NativePathNameToFSSpec, m_ok );
+    wxDL_METHOD_LOAD( m_dll, OpenMovieFile, m_ok );
+    wxDL_METHOD_LOAD( m_dll, CloseMovieFile, m_ok );
+    wxDL_METHOD_LOAD( m_dll, NewMovieFromFile, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMovieRate, m_ok );
+    wxDL_METHOD_LOAD( m_dll, SetMovieRate, m_ok );
+    wxDL_METHOD_LOAD( m_dll, MoviesTask, m_ok );
+    wxDL_METHOD_LOAD( m_dll, BlockMove, m_ok );
+    wxDL_METHOD_LOAD( m_dll, NewHandleClear, m_ok );
+    wxDL_METHOD_LOAD( m_dll, NewMovieFromDataRef, m_ok );
+    wxDL_METHOD_LOAD( m_dll, DisposeHandle, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMovieNaturalBoundsRect, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMovieIndTrackType, m_ok );
+    wxDL_METHOD_LOAD( m_dll, CreatePortAssociation, m_ok );
+    wxDL_METHOD_LOAD( m_dll, DestroyPortAssociation, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetNativeWindowPort, m_ok );
+    wxDL_METHOD_LOAD( m_dll, SetMovieGWorld, m_ok );
+    wxDL_METHOD_LOAD( m_dll, DisposeMovie, m_ok );
+    wxDL_METHOD_LOAD( m_dll, SetMovieBox, m_ok );
+    wxDL_METHOD_LOAD( m_dll, SetMovieTimeScale, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMovieDuration, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMovieTimeBase, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMovieTimeScale, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMovieTime, m_ok );
+    wxDL_METHOD_LOAD( m_dll, SetMovieTime, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMovieVolume, m_ok );
+    wxDL_METHOD_LOAD( m_dll, SetMovieVolume, m_ok );
+    wxDL_METHOD_LOAD( m_dll, SetMovieTimeValue, m_ok );
+    wxDL_METHOD_LOAD( m_dll, NewMovieController, m_ok );
+    wxDL_METHOD_LOAD( m_dll, DisposeMovieController, m_ok );
+    wxDL_METHOD_LOAD( m_dll, MCSetVisible, m_ok );
+    wxDL_METHOD_LOAD( m_dll, PrePrerollMovie, m_ok );
+    wxDL_METHOD_LOAD( m_dll, PrerollMovie, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMoviePreferredRate, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMovieLoadState, m_ok );
+    wxDL_METHOD_LOAD( m_dll, MCDoAction, m_ok );
+    wxDL_METHOD_LOAD( m_dll, MCSetControllerBoundsRect, m_ok );
+    wxDL_METHOD_LOAD( m_dll, NativeEventToMacEvent, m_ok );
+    wxDL_METHOD_LOAD( m_dll, MCIsPlayerEvent, m_ok );
+    wxDL_METHOD_LOAD( m_dll, MCSetMovie, m_ok );
+    wxDL_METHOD_LOAD( m_dll, MCSetActionFilterWithRefCon, m_ok );
+    wxDL_METHOD_LOAD( m_dll, MCGetControllerInfo, m_ok );
+    wxDL_METHOD_LOAD( m_dll, BeginUpdate, m_ok );
+    wxDL_METHOD_LOAD( m_dll, UpdateMovie, m_ok );
+    wxDL_METHOD_LOAD( m_dll, EndUpdate, m_ok );
+    wxDL_METHOD_LOAD( m_dll, GetMoviesStickyError, m_ok );
 
     wxLog::EnableLogging(bWasLoggingEnabled);
     m_ok = true;
 
     wxLog::EnableLogging(bWasLoggingEnabled);
     m_ok = true;
@@ -882,6 +2217,14 @@ bool wxQuickTimeLibrary::Initialize()
     return true;
 }
 
     return true;
 }
 
+//cludgy workaround for wx events.  slots would be nice :)
+class WXDLLIMPEXP_MEDIA wxQTMediaEvtHandler : public wxEvtHandler
+{
+public:
+    void OnPaint(wxPaintEvent&);
+    void OnEraseBackground(wxEraseEvent&);
+};
+
 class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackend
 {
 public:
 class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackend
 {
 public:
@@ -921,12 +2264,23 @@ public:
     void Cleanup();
     void FinishLoad();
 
     void Cleanup();
     void FinishLoad();
 
+    static void PPRMProc (Movie theMovie, OSErr theErr, void* theRefCon);
+    //TODO: Last param actually long - does this work on 64bit machines?
+    static Boolean MCFilterProc (MovieController theController,
+        short action, void *params, LONG_PTR refCon);
+
+    static LRESULT CALLBACK QTWndProc(HWND, UINT, WPARAM, LPARAM);
+
+    virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags);
+
     wxSize m_bestSize;              //Original movie size
     Movie m_movie;    //QT Movie handle/instance
     wxControl* m_ctrl;              //Parent control
     bool m_bVideo;                  //Whether or not we have video
     wxSize m_bestSize;              //Original movie size
     Movie m_movie;    //QT Movie handle/instance
     wxControl* m_ctrl;              //Parent control
     bool m_bVideo;                  //Whether or not we have video
-    class _wxQTTimer* m_timer;      //Timer for streaming the movie
-    wxQuickTimeLibrary m_lib;
+    bool m_bPlaying;                //Whether or not movie is playing
+    wxTimer* m_timer;               //Load or Play timer
+    wxQuickTimeLibrary m_lib;       //DLL to load functions from
+    ComponentInstance m_pMC;        //Movie Controller
 
     DECLARE_DYNAMIC_CLASS(wxQTMediaBackend)
 };
 
     DECLARE_DYNAMIC_CLASS(wxQTMediaBackend)
 };
@@ -949,7 +2303,6 @@ IMPLEMENT_DYNAMIC_CLASS(wxAMMediaBackend, wxMediaBackend);
 //---------------------------------------------------------------------------
 #ifdef __WXDEBUG__
 #define MAX_ERROR_TEXT_LEN 160
 //---------------------------------------------------------------------------
 #ifdef __WXDEBUG__
 #define MAX_ERROR_TEXT_LEN 160
-#include "wx/log.h"             //wxLogDebug et al.
 
 //Get the error string for Active Movie
 wxString wxAMMediaBackend::GetErrorString(HRESULT hrdsv)
 
 //Get the error string for Active Movie
 wxString wxAMMediaBackend::GetErrorString(HRESULT hrdsv)
@@ -959,49 +2312,227 @@ wxString wxAMMediaBackend::GetErrorString(HRESULT hrdsv)
        (*m_lpAMGetErrorText)(hrdsv, szError, MAX_ERROR_TEXT_LEN) == 0)
     {
         return wxString::Format(wxT("DirectShow error \"%s\" \n")
        (*m_lpAMGetErrorText)(hrdsv, szError, MAX_ERROR_TEXT_LEN) == 0)
     {
         return wxString::Format(wxT("DirectShow error \"%s\" \n")
-                                     wxT("(numeric %i)\n")
-                                     wxT("occured at line %i in ")
-                                     wxT("mediactrl.cpp"),
-                                     szError, (int)hrdsv, __LINE__);
+                                     wxT("(numeric %X)\n")
+                                     wxT("occured"),
+                                     szError, (int)hrdsv);
     }
     else
     {
     }
     else
     {
-        return wxString::Format(wxT("Unknown error (%i) ")
-                                     wxT("occurred at")
-                                     wxT(" line %i in mediactrl.cpp."),
-                                     (int)hrdsv, __LINE__);
+        return wxString::Format(wxT("Unknown error \n")
+                                     wxT("(numeric %X)\n")
+                                     wxT("occured"),
+                                     (int)hrdsv);
     }
 }
 
     }
 }
 
-#define wxAMFAIL(x) wxFAIL_MSG(GetErrorString(x));
-#define wxVERIFY(x) wxASSERT((x))
-#define wxAMLOG(x) wxLogDebug(GetErrorString(x))
-#else
-#define wxAMVERIFY(x) (x)
-#define wxVERIFY(x) (x)
-#define wxAMLOG(x)
-#define wxAMFAIL(x)
-#endif
+#define wxAMFAIL(x) wxFAIL_MSG(GetErrorString(x));
+#define wxVERIFY(x) wxASSERT((x))
+#define wxAMLOG(x) wxLogDebug(GetErrorString(x))
+#else
+#define wxAMVERIFY(x) (x)
+#define wxVERIFY(x) (x)
+#define wxAMLOG(x)
+#define wxAMFAIL(x)
+#endif
+
+//---------------------------------------------------------------------------
+// Standard macros for ease of use
+//---------------------------------------------------------------------------
+#define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
+
+//---------------------------------------------------------------------------
+// wxAMLoadTimer
+//
+// Queries the control periodically to see if it has reached the point
+// in its loading cycle where we can begin playing the media - if so
+// then we finish up some things like getting the original size of the video
+// and then sending the loaded event to our handler
+//---------------------------------------------------------------------------
+class wxAMLoadTimer : public wxTimer
+{
+public:
+    wxAMLoadTimer(wxAMMediaBackend* parent) :
+      m_parent(parent) {}
+
+    void Notify()
+    {
+        if(m_parent->m_pMP)
+        {
+            MPReadyStateConstants nState;
+            m_parent->m_pMP->get_ReadyState(&nState);
+            if(nState != mpReadyStateLoading)
+            {
+                Stop();
+                m_parent->FinishLoad();
+                delete this;
+            }
+        }
+        else
+        {
+            IActiveMovie2* pAM2 = NULL;
+            ReadyStateConstants nState;
+            if(m_parent->m_pAM->QueryInterface(IID_IActiveMovie2,
+                                              (void**)&pAM2) == 0 &&
+                pAM2->get_ReadyState(&nState) == 0)
+            {
+                pAM2->Release();
+                if(nState != amvLoading)
+                {
+                    Stop();
+                    m_parent->FinishLoad();
+                    delete this;
+                }
+            }
+            else
+            {
+                if(pAM2)
+                    pAM2->Release();
+
+                Stop();
+                m_parent->FinishLoad();
+                delete this;
+            }
+        }
+
+    }
+
+protected:
+    wxAMMediaBackend* m_parent;     //Backend pointer
+};
+
+//---------------------------------------------------------------------------
+// wxAMPlayTimer
+//
+// Sets m_hNotifyWnd to NULL to signify that we haven't loaded anything yet
+// Queries the control periodically to see if it has stopped -
+// if it has it sends the stop event
+//---------------------------------------------------------------------------
+class wxAMPlayTimer : public wxTimer
+{
+public:
+    wxAMPlayTimer(wxAMMediaBackend* parent) :
+      m_parent(parent) {}
+
+    void Notify()
+    {
+        if(m_parent->GetState() == wxMEDIASTATE_STOPPED &&
+           //NB:  Stop events could get triggered by the interface
+           //if ShowPlayerControls is enabled,
+           //so we need this hack here to make an attempt
+           //at it not getting sent - but its far from ideal -
+           //they can still get sent in some cases
+           m_parent->GetPosition() == m_parent->GetDuration())
+        {
+            wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
+                                  m_parent->m_ctrl->GetId());
+            m_parent->m_ctrl->ProcessEvent(theEvent);
+
+            if(theEvent.IsAllowed())
+            {
+                //Seek to beginning of movie
+                m_parent->wxAMMediaBackend::SetPosition(0);
+                Stop();
+
+                //send the event to our child
+                wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
+                                      m_parent->m_ctrl->GetId());
+                m_parent->m_ctrl->AddPendingEvent(theEvent);
+            }
+        }
+    }
+
+protected:
+    wxAMMediaBackend* m_parent;     //Backend pointer
+};
+
+
+/*
+// The following is an alternative way - but it doesn't seem
+// to work with the IActiveMovie control - it probably processes
+// its own events
+//---------------------------------------------------------------------------
+// wxAMPlayTimer
+//
+// Query the IMediaEvent interface from the embedded WMP's
+// filtergraph, then process the events from it - sending
+// EC_COMPLETE events as stop events to the media control.
+//---------------------------------------------------------------------------
+class wxAMPlayTimer : public wxTimer
+{
+public:
+    wxAMPlayTimer(wxAMMediaBackend* pBE) : m_pBE(pBE), m_pME(NULL)
+    {
+        HRESULT hr;
+        IUnknown* pGB;
+        hr = m_pBE->m_pAM->get_FilterGraph(&pGB);
+        wxASSERT(SUCCEEDED(hr));
+        hr = pGB->QueryInterface(IID_IMediaEvent, (void**)&m_pME);
+        wxASSERT(SUCCEEDED(hr));
+        pGB->Release();
+    }
+
+    ~wxAMPlayTimer()
+    {
+        SAFE_RELEASE(m_pME);
+    }
+
+    void Notify()
+    {
+        LONG        evCode;
+        LONG_PTR    evParam1,
+                    evParam2;
+
+        //
+        // DirectShow keeps a list of queued events, and we need
+        // to go through them one by one, stopping at (Hopefully only one)
+        // EC_COMPLETE message
+        //
+        while( m_pME->GetEvent(&evCode, &evParam1, &evParam2, 0) == 0 )
+        {
+            // Cleanup memory that GetEvent allocated
+            HRESULT hr = m_pME->FreeEventParams(evCode,
+                                                evParam1, evParam2);
+            if(hr != 0)
+            {
+                //Even though this makes a messagebox this
+                //is windows where we can do gui stuff in seperate
+                //threads :)
+                wxFAIL_MSG(m_pBE->GetErrorString(hr));
+            }
+            // If this is the end of the clip, notify handler
+            else if(1 == evCode) //EC_COMPLETE
+            {
+                wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
+                                    m_pBE->m_ctrl->GetId());
+                m_pBE->m_ctrl->ProcessEvent(theEvent);
+
+                if(theEvent.IsAllowed())
+                {
+                    Stop();
+
+                    //send the event to our child
+                    wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
+                                        m_pBE->m_ctrl->GetId());
+                    m_pBE->m_ctrl->AddPendingEvent(theEvent);
+                }
+            }
+        }
+    }
 
 
-//---------------------------------------------------------------------------
-// Standard macros for ease of use
-//---------------------------------------------------------------------------
-#define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
+protected:
+    wxAMMediaBackend* m_pBE;     //Backend pointer
+    IMediaEvent* m_pME;          //To determine when to send stop event
+};
+*/
 
 //---------------------------------------------------------------------------
 // wxAMMediaBackend Constructor
 
 //---------------------------------------------------------------------------
 // wxAMMediaBackend Constructor
-//
-// Sets m_hNotifyWnd to NULL to signify that we haven't loaded anything yet
 //---------------------------------------------------------------------------
 wxAMMediaBackend::wxAMMediaBackend()
 //---------------------------------------------------------------------------
 wxAMMediaBackend::wxAMMediaBackend()
-                 :m_state(wxMEDIASTATE_STOPPED)
-                 ,m_pVMC(NULL)
-                 ,m_pGB(NULL)
-                 ,m_pBA(NULL)
-                 ,m_pMC(NULL)
-                 ,m_pME(NULL)
-                 ,m_pMS(NULL)
-                 ,m_pThread(NULL)
+                 :m_pAX(NULL),
+                  m_pAM(NULL),
+                  m_pMP(NULL),
+                  m_pTimer(NULL)
 #ifdef __WXDEBUG__
                  ,m_hQuartzDll(NULL)
 #endif
 #ifdef __WXDEBUG__
                  ,m_hQuartzDll(NULL)
 #endif
@@ -1010,13 +2541,20 @@ wxAMMediaBackend::wxAMMediaBackend()
 
 //---------------------------------------------------------------------------
 // wxAMMediaBackend Destructor
 
 //---------------------------------------------------------------------------
 // wxAMMediaBackend Destructor
-//
-// Cleans up everything
 //---------------------------------------------------------------------------
 wxAMMediaBackend::~wxAMMediaBackend()
 {
 //---------------------------------------------------------------------------
 wxAMMediaBackend::~wxAMMediaBackend()
 {
-    if (m_pVMC)
-        Cleanup();
+    Clear(); //Free memory from Load()
+
+    if(m_pAX)
+    {
+        m_pAX->DissociateHandle();
+        delete m_pAX;
+        m_pAM->Release();
+
+        if(m_pMP)
+            m_pMP->Release();
+    }
 #ifdef __WXDEBUG__
     if(m_hQuartzDll)
         ::FreeLibrary(m_hQuartzDll);
 #ifdef __WXDEBUG__
     if(m_hQuartzDll)
         ::FreeLibrary(m_hQuartzDll);
@@ -1024,10 +2562,18 @@ wxAMMediaBackend::~wxAMMediaBackend()
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
-// wxAMMediaBackend::CreateControl
+// wxAMMediaBackend::Clear
 //
 //
-// 1) Check to see if Active Movie supports windowless controls
-// 2) Connect events to the media control and its TLW
+// Free up interfaces and memory allocated by LoadXXX
+//---------------------------------------------------------------------------
+void wxAMMediaBackend::Clear()
+{
+    if(m_pTimer)
+        delete m_pTimer;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::CreateControl
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
                                      wxWindowID id,
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
                                      wxWindowID id,
@@ -1037,6 +2583,8 @@ bool wxAMMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
                                      const wxValidator& validator,
                                      const wxString& name)
 {
                                      const wxValidator& validator,
                                      const wxString& name)
 {
+    // First get the AMGetErrorText procedure in debug
+    // mode for more meaningful messages
 #ifdef __WXDEBUG__
     m_hQuartzDll = ::LoadLibrary(wxT("quartz.dll"));
     if(m_hQuartzDll)
 #ifdef __WXDEBUG__
     m_hQuartzDll = ::LoadLibrary(wxT("quartz.dll"));
     if(m_hQuartzDll)
@@ -1045,7 +2593,7 @@ bool wxAMMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
                 m_hQuartzDll,
             wxString::Format(wxT("AMGetErrorText%s"),
 
                 m_hQuartzDll,
             wxString::Format(wxT("AMGetErrorText%s"),
 
-#ifdef __WXUNICODE__
+#if wxUSE_UNICODE
             wxT("W")
 #else
             wxT("A")
             wxT("W")
 #else
             wxT("A")
@@ -1058,215 +2606,184 @@ bool wxAMMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
                              );
     }
 #endif
                              );
     }
 #endif
-
-    //Make sure a valid windowless video mixing interface exists
-    IGraphBuilder* pGB;
-    if( ::CoCreateInstance(CLSID_FilgraphManager, NULL,
+    // Now determine which (if any) media player interface is
+    // available - IMediaPlayer or IActiveMovie
+    if( ::CoCreateInstance(CLSID_MediaPlayer, NULL,
                                   CLSCTX_INPROC_SERVER,
                                   CLSCTX_INPROC_SERVER,
-                                  IID_IGraphBuilder, (void**)&pGB) != 0 )
-        return false;
-
-    if( !SetWindowlessMode(pGB) )
+                                  IID_IMediaPlayer, (void**)&m_pMP) != 0 )
+    {
+        if( ::CoCreateInstance(CLSID_ActiveMovie, NULL,
+                                  CLSCTX_INPROC_SERVER,
+                                  IID_IActiveMovie, (void**)&m_pAM) != 0 )
         return false;
         return false;
-
-    //clean up
-    pGB->Release();
-
+        m_pAM->QueryInterface(IID_IMediaPlayer, (void**)&m_pMP);
+    }
+    else
+    {
+        m_pMP->QueryInterface(IID_IActiveMovie, (void**)&m_pAM);
+    }
     //
     // Create window
     // By default wxWindow(s) is created with a border -
     //
     // Create window
     // By default wxWindow(s) is created with a border -
-    // so we need to get rid of those, and create with
-    // wxCLIP_CHILDREN, so that if the driver/backend
-    // is a child window, it refreshes properly
+    // so we need to get rid of those
+    //
+    // Since we don't have a child window like most other
+    // backends, we don't need wxCLIP_CHILDREN
     //
     if ( !ctrl->wxControl::Create(parent, id, pos, size,
     //
     if ( !ctrl->wxControl::Create(parent, id, pos, size,
-                            (style & ~wxBORDER_MASK) | wxBORDER_NONE | wxCLIP_CHILDREN,
+                            (style & ~wxBORDER_MASK) | wxBORDER_NONE,
                             validator, name) )
         return false;
 
                             validator, name) )
         return false;
 
-    // My problem with this was only with a previous patch, probably the third rewrite
-    // fixed it as a side-effect. In fact, the erase background style of drawing not
-    // only works now, but is much better than paint-based updates (the paint event
-    // handler flickers if the wxMediaCtrl shares a sizer with another child window,
-    // or is on a notebook)
-    //  - Greg Hazel
-    ctrl->Connect(ctrl->GetId(), wxEVT_ERASE_BACKGROUND,
-        wxEraseEventHandler(wxAMMediaEvtHandler::OnEraseBackground),
-        NULL, (wxEvtHandler*) this);
-
     //
     //
-    // done...
+    // Now create the ActiveX container along with the media player
+    // interface and query them
     //
     m_ctrl = ctrl;
     //
     m_ctrl = ctrl;
-    return true;
-}
-
-//---------------------------------------------------------------------------
-// wxAMMediaBackend::SetWindowlessMode
-//
-// Adds a Video Mixing Renderer to a Filter Graph and obtains the
-// windowless control from it
-//---------------------------------------------------------------------------
-bool wxAMMediaBackend::SetWindowlessMode(IGraphBuilder* pGB,
-                                         IVMRWindowlessControl** ppVMC)
-{
-    HRESULT hr;
-
-    //
-    // Create and add a custom Video Mixing Render to the graph
-    //
-    IBaseFilter* pVMR;
-    if( ::CoCreateInstance(CLSID_VideoMixingRenderer, NULL,
-                CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pVMR) != 0 )
-        return false;
-
-    hr = pGB->AddFilter(pVMR, L"Video Mixing Renderer");
-    if ( hr != 0)
-    {
-        wxAMLOG(hr);
-        pVMR->Release();
-        return false;
-    }
+    m_pAX = new wxActiveX(ctrl,
+                m_pMP ? IID_IMediaPlayer : IID_IActiveMovie,
+                m_pAM);
 
 
-    //
-    // Set the graph to windowless mode
-    //
-    IVMRFilterConfig* pConfig;
-    hr = pVMR->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);
-    if( hr != 0 )
-    {
-        wxAMLOG(hr);
-        pVMR->Release();
-        return false;
-    }
-
-    hr = pConfig->SetRenderingMode(2);
-    if( hr != 0) //2 == VMRMode_Windowless
-    {
-        wxAMLOG(hr);
-        pConfig->Release();
-        pVMR->Release();
-        return false;
-    }
-
-    pConfig->Release();
 
     //
 
     //
-    // Obtain the windowless control
+    //  Here we set up wx-specific stuff for the default
+    //  settings wxMediaCtrl says it will stay to
     //
     //
-    IVMRWindowlessControl* pVMC;
-    hr = pVMR->QueryInterface(IID_IVMRWindowlessControl, (void**)&pVMC);
-    if( hr != 0 )
+    if(m_pMP)
     {
     {
-        wxAMLOG(hr);
-        pVMR->Release();
-        return false;
+        m_pMP->put_DisplaySize(mpFitToSize);
+        // TODO: Unsure what actual effect this has
+        m_pMP->put_WindowlessVideo(VARIANT_TRUE);
     }
     }
-
-    //
-    // Success
-    //
-    if(ppVMC)
-        *ppVMC = pVMC;
     else
     else
-        pVMC->Release();
+        m_pAM->put_MovieWindowSize(amvDoubleOriginalSize);
+
+    //by default true
+    m_pAM->put_AutoStart(VARIANT_FALSE);
+    //by default enabled
+    wxAMMediaBackend::ShowPlayerControls(wxMEDIACTRLPLAYERCONTROLS_NONE);
+    //by default with AM only 0.5
+    wxAMMediaBackend::SetVolume(1.0);
+
+    // My problem with this was only with a previous patch, probably the
+    // third rewrite fixed it as a side-effect. In fact, the erase
+    // background style of drawing not only works now, but is much better
+    // than paint-based updates (the paint event handler flickers if the
+    // wxMediaCtrl shares a sizer with another child window, or is on a
+    // notebook)
+    //  - Greg Hazel
+    m_ctrl->Connect(m_ctrl->GetId(), wxEVT_ERASE_BACKGROUND,
+        wxEraseEventHandler(wxAMMediaEvtHandler::OnEraseBackground),
+        NULL, (wxEvtHandler*) this);
 
 
-    pVMR->Release();
+    // success
     return true;
 }
 
 //---------------------------------------------------------------------------
 // wxAMMediaBackend::Load (file version)
     return true;
 }
 
 //---------------------------------------------------------------------------
 // wxAMMediaBackend::Load (file version)
-//
-// 1) Cleans up previously loaded data
-// 2) Creates a filter graph
-// 3) Add a video mixer, set the graph to windowless mode and clip
-//    output to our media control
-// 4) Query interfaces to use later
-// 5) Get native video size (which becomes our best size)
-// 6) Refresh parent's sizers
-// 7) Start event/rendering thread
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::Load(const wxString& fileName)
 {
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::Load(const wxString& fileName)
 {
-    HRESULT hr;
-
-    //if previously loaded cleanup
-    if(m_pVMC)
-        Cleanup();
+    return DoLoad(fileName);
+}
 
 
-    //Create interfaces - we already checked for success in CreateControl
-    ::CoCreateInstance(CLSID_FilgraphManager, NULL, CLSCTX_INPROC_SERVER,
-                     IID_IGraphBuilder, (void**)&m_pGB);
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::Load (URL Version)
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::Load(const wxURI& location)
+{
+    //  Turn off loading from a proxy as user
+    //  may have set it previously
+    INSPlay* pPlay = NULL;
+    m_pAM->QueryInterface(IID_INSPlay, (void**) &pPlay);
+    if(pPlay)
+    {
+        pPlay->put_UseHTTPProxy(VARIANT_FALSE);
+        pPlay->Release();
+    }
 
 
+    return DoLoad(location.BuildURI());
+}
 
 
-    // Set and clip output
-    SetWindowlessMode(m_pGB, &m_pVMC);
-    hr = m_pVMC->SetVideoClippingWindow((HWND)m_ctrl->GetHandle());
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::Load (URL Version with Proxy)
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::Load(const wxURI& location, const wxURI& proxy)
+{
+    // Set the proxy of the NETSHOW interface
+    INSPlay* pPlay = NULL;
+    m_pAM->QueryInterface(IID_INSPlay, (void**) &pPlay);
 
 
-    if(hr != 0)
+    if(pPlay)
     {
     {
-        m_bestSize.x = m_bestSize.y = 0;
-        wxAMFAIL(hr);
-        return false;
+        pPlay->put_UseHTTPProxy(VARIANT_TRUE);
+        pPlay->put_HTTPProxyHost(wxBasicString(proxy.GetServer()).Get());
+        pPlay->put_HTTPProxyPort(wxAtoi(proxy.GetPort()));
+        pPlay->Release();
     }
 
     }
 
-    //load the graph & render
-    if( m_pGB->RenderFile(fileName.wc_str(wxConvLocal), NULL) != 0 )
-        return false;
+    return DoLoad(location.BuildURI());
+}
 
 
-    //
-    //Get the interfaces, all of them
-    //
-    hr = m_pGB->QueryInterface(IID_IMediaEvent, (void**)&m_pME);
-    if(FAILED(hr))
-    {
-        wxAMLOG(hr);
-        return false;
-    }
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::DoLoad
+//
+// Called by all functions - this actually renders
+// the file and sets up the filter graph
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::DoLoad(const wxString& location)
+{
+    Clear(); //Clear up previously allocated memory
 
 
-    hr = m_pGB->QueryInterface(IID_IMediaControl, (void**)&m_pMC);
-    if(FAILED(hr))
-    {
-        wxAMLOG(hr);
-        return false;
-    }
+    HRESULT hr;
+
+    // Play the movie the normal way through the embedded
+    // WMP.  Supposively Open is better in theory because
+    // the docs say its async and put_FileName is not -
+    // but in practice they both seem to be async anyway
+    if(m_pMP)
+        hr = m_pMP->Open( wxBasicString(location).Get() );
+    else
+        hr = m_pAM->put_FileName( wxBasicString(location).Get() );
 
 
-    hr = m_pGB->QueryInterface(IID_IMediaPosition, (void**)&m_pMS);
     if(FAILED(hr))
     {
         wxAMLOG(hr);
         return false;
     }
 
     if(FAILED(hr))
     {
         wxAMLOG(hr);
         return false;
     }
 
-    hr = m_pGB->QueryInterface(IID_IBasicAudio, (void**)&m_pBA);
-    if(FAILED(hr))
-    {
-        wxAMLOG(hr);
-        //not critical
-    }
+    // In AM playing will FAIL if
+    // the user plays before the media is loaded
+    m_pTimer = new wxAMLoadTimer(this);
+    m_pTimer->Start(20);
+    return true;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::FinishLoad
+//
+// Called by our wxAMLoadTimer when the
+// embedded WMP tells its the media is ready to play.
+//
+// Here we get the original size of the video and
+// send the loaded event to our watcher :).
+//---------------------------------------------------------------------------
+void wxAMMediaBackend::FinishLoad()
+{
+    //Get the original video size
+    m_pAM->get_ImageSourceWidth((long*)&m_bestSize.x);
+    m_pAM->get_ImageSourceHeight((long*)&m_bestSize.y);
 
     //
 
     //
-    // Get original video size
+    //Start the play timer to catch stop events
+    //Previous load timer cleans up itself
     //
     //
-    hr = m_pVMC->GetNativeVideoSize((LONG*)&m_bestSize.x, (LONG*)&m_bestSize.y,
-                                   NULL, NULL);
-    if(hr != 0)
-    {
-        m_bestSize.x = m_bestSize.y = 0;
-        wxAMFAIL(hr);
-        return false;
-    }
-
-    if(m_bestSize.x == 0 && m_bestSize.y == 0)
-        m_bVideo = false;
-    else
-        m_bVideo = true;
+    m_pTimer = new wxAMPlayTimer(this);
 
 
-    //
-    // Force the parent window of this control to recalculate
-    // the size of this if sizers are being used
-    // and render the results immediately
+    //Here, if the parent of the control has a sizer - we
+    //tell it to recalculate the size of this control since
+    //the user opened a separate media file
     //
     m_ctrl->InvalidateBestSize();
     m_ctrl->GetParent()->Layout();
     //
     m_ctrl->InvalidateBestSize();
     m_ctrl->GetParent()->Layout();
@@ -1274,59 +2791,48 @@ bool wxAMMediaBackend::Load(const wxString& fileName)
     m_ctrl->GetParent()->Update();
     m_ctrl->SetSize(m_ctrl->GetSize());
 
     m_ctrl->GetParent()->Update();
     m_ctrl->SetSize(m_ctrl->GetSize());
 
-    //
-    //  Create the event thread
-    //
-    m_pThread = new wxAMMediaThread;
-    m_pThread->pThis = this;
-    m_pThread->Create();
-    m_pThread->Run();
-
-    //
-    //  done
-    //
-    return true;
-}
-
-//---------------------------------------------------------------------------
-// wxAMMediaBackend::Load (URL Version)
-//
-// Loads media from a URL.  Interestingly enough DirectShow
-// appears (?) to escape the URL for us, at least on normal
-// files
-//---------------------------------------------------------------------------
-bool wxAMMediaBackend::Load(const wxURI& location)
-{
-    return Load(location.BuildUnescapedURI());
+    //Send event to our children
+    wxMediaEvent theEvent(wxEVT_MEDIA_LOADED,
+                            m_ctrl->GetId());
+    m_ctrl->AddPendingEvent(theEvent);
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
-// wxAMMediaBackend::Cleanup
-//
-// Releases all the directshow interfaces we use
-// TODO: Maybe only create one instance of IAMMultiMediaStream and reuse it
-// rather than recreating it each time?
+// wxAMMediaBackend::ShowPlayerControls
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-void wxAMMediaBackend::Cleanup()
+bool wxAMMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
 {
 {
-    // RN:  This could be a bad ptr if load failed after
-    // m_pVMC was created
-    if(m_pThread)
+    // Note that IMediaPlayer doesn't have a statusbar by
+    // default but IActiveMovie does - so lets try to keep
+    // the interface consistant
+    if(!flags)
+    {
+        m_pAM->put_Enabled(VARIANT_FALSE);
+        m_pAM->put_ShowControls(VARIANT_FALSE);
+        if(m_pMP)
+            m_pMP->put_ShowStatusBar(VARIANT_FALSE);
+    }
+    else
     {
     {
-        m_pThread->Delete();
-        m_pThread = NULL;
+        m_pAM->put_Enabled(VARIANT_TRUE);
+        m_pAM->put_ShowControls(VARIANT_TRUE);
+
+        m_pAM->put_ShowPositionControls(
+                (flags & wxMEDIACTRLPLAYERCONTROLS_STEP) ?
+                VARIANT_TRUE : VARIANT_FALSE);
+
+        if(m_pMP)
+        {
+            m_pMP->put_ShowStatusBar(VARIANT_TRUE);
+            m_pMP->put_ShowAudioControls(
+                (flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME) ?
+                VARIANT_TRUE : VARIANT_FALSE);
+        }
     }
 
     }
 
-    // Release and zero DirectShow interfaces
-    SAFE_RELEASE(m_pMC);
-    SAFE_RELEASE(m_pME);
-    SAFE_RELEASE(m_pMS);
-    SAFE_RELEASE(m_pBA);
-    SAFE_RELEASE(m_pGB);
-    SAFE_RELEASE(m_pVMC);
+    return true;
 }
 
 }
 
-
 //---------------------------------------------------------------------------
 // wxAMMediaBackend::Play
 //
 //---------------------------------------------------------------------------
 // wxAMMediaBackend::Play
 //
@@ -1337,15 +2843,40 @@ void wxAMMediaBackend::Cleanup()
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::Play()
 {
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::Play()
 {
-    wxCriticalSectionLocker lock(m_rendercs);
+    // if the movie isn't done loading yet
+    // go into an sync getmessage loop until it is :)
+    if(m_pMP)
+    {
+        MPReadyStateConstants nState;
+        m_pMP->get_ReadyState(&nState);
+        while(nState == mpReadyStateLoading && wxYieldIfNeeded())
+        {
+          m_pMP->get_ReadyState(&nState);
+        }
+    }
+    else
+    {
+        IActiveMovie2* pAM2;
+        ReadyStateConstants nState;
+        if(m_pAM->QueryInterface(IID_IActiveMovie2, (void**)&pAM2) == 0 &&
+            pAM2->get_ReadyState(&nState) == 0)
+        {
+            while(nState == amvLoading && wxYieldIfNeeded())
+            {
+                pAM2->get_ReadyState(&nState);
+            }
+            pAM2->Release();
+        }
+    }
 
 
-    if( SUCCEEDED(m_pMC->Run()) )
+    //Actually try to play the movie
+    HRESULT hr = m_pAM->Run();
+    if(SUCCEEDED(hr))
     {
     {
-        m_state = wxMEDIASTATE_PLAYING;
-        m_ctrl->Refresh(); //videoless control finicky about refreshing
+        m_pTimer->Start(20);
         return true;
     }
         return true;
     }
-
+    wxAMLOG(hr);
     return false;
 }
 
     return false;
 }
 
@@ -1356,14 +2887,10 @@ bool wxAMMediaBackend::Play()
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::Pause()
 {
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::Pause()
 {
-    wxCriticalSectionLocker lock(m_rendercs);
-
-    if( SUCCEEDED(m_pMC->Pause()) )
-    {
-        m_state = wxMEDIASTATE_PAUSED;
+    HRESULT hr = m_pAM->Pause();
+    if(SUCCEEDED(hr))
         return true;
         return true;
-    }
-
+    wxAMLOG(hr);
     return false;
 }
 
     return false;
 }
 
@@ -1374,19 +2901,16 @@ bool wxAMMediaBackend::Pause()
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::Stop()
 {
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::Stop()
 {
-    wxCriticalSectionLocker lock(m_rendercs);
-
-    if( SUCCEEDED(m_pMC->Stop()) )
+    HRESULT hr = m_pAM->Stop();
+    if(SUCCEEDED(hr))
     {
     {
-    //We don't care if it can't get to the beginning in directshow -
-    //it could be a non-seeking filter (wince midi) in which case playing
-    //starts all over again
+        //Seek to beginning
         wxAMMediaBackend::SetPosition(0);
         wxAMMediaBackend::SetPosition(0);
-
-        m_state = wxMEDIASTATE_STOPPED;
+        //Stop stop event timer
+        m_pTimer->Stop();
         return true;
     }
         return true;
     }
-
+    wxAMLOG(hr);
     return false;
 }
 
     return false;
 }
 
@@ -1401,7 +2925,7 @@ bool wxAMMediaBackend::Stop()
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::SetPosition(wxLongLong where)
 {
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::SetPosition(wxLongLong where)
 {
-    HRESULT hr = m_pMS->put_CurrentPosition(
+    HRESULT hr = m_pAM->put_CurrentPosition(
                         ((LONGLONG)where.GetValue()) / 1000.0
                                      );
     if(FAILED(hr))
                         ((LONGLONG)where.GetValue()) / 1000.0
                                      );
     if(FAILED(hr))
@@ -1422,7 +2946,7 @@ bool wxAMMediaBackend::SetPosition(wxLongLong where)
 wxLongLong wxAMMediaBackend::GetPosition()
 {
     double outCur;
 wxLongLong wxAMMediaBackend::GetPosition()
 {
     double outCur;
-    HRESULT hr = m_pMS->get_CurrentPosition(&outCur);
+    HRESULT hr = m_pAM->get_CurrentPosition(&outCur);
     if(FAILED(hr))
     {
         wxAMLOG(hr);
     if(FAILED(hr))
     {
         wxAMLOG(hr);
@@ -1446,21 +2970,14 @@ wxLongLong wxAMMediaBackend::GetPosition()
 //---------------------------------------------------------------------------
 double wxAMMediaBackend::GetVolume()
 {
 //---------------------------------------------------------------------------
 double wxAMMediaBackend::GetVolume()
 {
-    if(m_pBA)
-    {
         long lVolume;
         long lVolume;
-        HRESULT hr = m_pBA->get_Volume(&lVolume);
+    HRESULT hr = m_pAM->get_Volume(&lVolume);
         if(FAILED(hr))
         {
             wxAMLOG(hr);
             return 0.0;
         if(FAILED(hr))
         {
             wxAMLOG(hr);
             return 0.0;
-        }
-
-        return (((double)(lVolume + 10000)) / 10000.0);
     }
     }
-
-    wxLogDebug(wxT("No directshow audio interface"));
-    return 0.0;
+    return pow(10.0, lVolume/2000.0);
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
@@ -1472,19 +2989,15 @@ double wxAMMediaBackend::GetVolume()
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::SetVolume(double dVolume)
 {
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::SetVolume(double dVolume)
 {
-    if(m_pBA)
-    {
-        HRESULT hr = m_pBA->put_Volume( (long) ((dVolume-1.0) * 10000.0) );
+    //pow(10.0, -80.0) to correct 0 == -INF
+    long lVolume = (2000.0 * log10(pow(10.0, -80.0)+dVolume));
+    HRESULT hr = m_pAM->put_Volume( lVolume );
         if(FAILED(hr))
         {
             wxAMLOG(hr);
             return false;
         }
         return true;
         if(FAILED(hr))
         {
             wxAMLOG(hr);
             return false;
         }
         return true;
-    }
-
-    wxLogDebug(wxT("No directshow audio interface"));
-    return false;
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
@@ -1500,7 +3013,7 @@ bool wxAMMediaBackend::SetVolume(double dVolume)
 wxLongLong wxAMMediaBackend::GetDuration()
 {
     double outDuration;
 wxLongLong wxAMMediaBackend::GetDuration()
 {
     double outDuration;
-    HRESULT hr = m_pMS->get_Duration(&outDuration);
+    HRESULT hr = m_pAM->get_Duration(&outDuration);
     if(FAILED(hr))
     {
         wxAMLOG(hr);
     if(FAILED(hr))
     {
         wxAMLOG(hr);
@@ -1522,7 +3035,15 @@ wxLongLong wxAMMediaBackend::GetDuration()
 //---------------------------------------------------------------------------
 wxMediaState wxAMMediaBackend::GetState()
 {
 //---------------------------------------------------------------------------
 wxMediaState wxAMMediaBackend::GetState()
 {
-    return m_state;
+    StateConstants nState;
+    HRESULT hr = m_pAM->get_CurrentState(&nState);
+    if(FAILED(hr))
+    {
+        wxAMLOG(hr);
+        return wxMEDIASTATE_STOPPED;
+    }
+
+    return (wxMediaState)nState;
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
@@ -1534,7 +3055,7 @@ wxMediaState wxAMMediaBackend::GetState()
 double wxAMMediaBackend::GetPlaybackRate()
 {
     double dRate;
 double wxAMMediaBackend::GetPlaybackRate()
 {
     double dRate;
-    HRESULT hr = m_pMS->get_Rate(&dRate);
+    HRESULT hr = m_pAM->get_Rate(&dRate);
     if(FAILED(hr))
     {
         wxAMLOG(hr);
     if(FAILED(hr))
     {
         wxAMLOG(hr);
@@ -1550,161 +3071,86 @@ double wxAMMediaBackend::GetPlaybackRate()
 // about this, actually
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::SetPlaybackRate(double dRate)
 // about this, actually
 //---------------------------------------------------------------------------
 bool wxAMMediaBackend::SetPlaybackRate(double dRate)
-{
-    HRESULT hr = m_pMS->put_Rate(dRate);
-    if(FAILED(hr))
-    {
-        wxAMLOG(hr);
-        return false;
-    }
-
-    return true;
-}
-
-//---------------------------------------------------------------------------
-// wxAMMediaBackend::GetVideoSize
-//
-// Obtains the cached original video size
-//---------------------------------------------------------------------------
-wxSize wxAMMediaBackend::GetVideoSize() const
-{
-    return m_bestSize;
-}
-
-//---------------------------------------------------------------------------
-// wxAMMediaBackend::Move
-//
-// We take care of this in our redrawing
-//---------------------------------------------------------------------------
-void wxAMMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y),
-                            int w, int h)
-{
-    //don't use deferred positioning on windows
-    if(m_pVMC && m_bVideo)
-    {
-        RECT srcRect, destRect;
-
-        //portion of video to display in window
-        srcRect.top = 0; srcRect.left = 0;
-        srcRect.bottom = m_bestSize.y; srcRect.right = m_bestSize.x;
-
-        //it happens.
-        if (w < 0)
-        {
-            w = 0;
-        }
-        if (h < 0)
-        {
-            h = 0;
-        }
-
-        //position in window client coordinates to display and stretch to
-        destRect.top = 0; destRect.left = 0;
-        destRect.bottom = h; destRect.right = w;
-
-        //set the windowless control positions
-        HRESULT hr = m_pVMC->SetVideoPosition(&srcRect, &destRect);
-        if(FAILED(hr))
-        {
-            wxAMLOG(hr);
-        }
+{
+    HRESULT hr = m_pAM->put_Rate(dRate);
+    if(FAILED(hr))
+    {
+        wxAMLOG(hr);
+        return false;
     }
     }
+
+    return true;
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
-// wxAMMediaThread::Entry
+// wxAMMediaBackend::GetDownloadXXX
 //
 //
-// Render the current movie frame
+// Queries for and gets the total size of the file and the current
+// progress in downloading that file from the IAMOpenProgress
+// interface from the media player interface's filter graph
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-wxThread::ExitCode wxAMMediaThread::Entry()
+void wxAMMediaBackend::DoGetDownloadProgress(wxLongLong* pLoadProgress,
+                                             wxLongLong* pLoadTotal)
 {
 {
-    while(!TestDestroy())
-    {
-        LONG    evCode,
-                evParam1,
-                evParam2;
-
-        //
-        // DirectShow keeps a list of queued events, and we need
-        // to go through them one by one, stopping at (Hopefully only one)
-        // EC_COMPLETE message
-        //
-        while( pThis->m_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
-                                      (LONG_PTR *) &evParam2, 0) == 0 )
+    LONGLONG loadTotal = 0, loadProgress = 0;
+    IUnknown* pFG;
+    IAMOpenProgress* pOP;
+    HRESULT hr;
+    hr = m_pAM->get_FilterGraph(&pFG);
+    if(SUCCEEDED(hr))
         {
         {
-            // Cleanup memory that GetEvent allocated
-            HRESULT hr = pThis->m_pME->FreeEventParams(evCode,
-                                                evParam1, evParam2);
-            if(hr != 0)
+        hr = pFG->QueryInterface(IID_IAMOpenProgress, (void**)&pOP);
+        if(SUCCEEDED(hr))
+        {
+            hr = pOP->QueryProgress(&loadTotal, &loadProgress);
+            pOP->Release();
+        }
+        pFG->Release();
+    }
+
+    if(SUCCEEDED(hr))
             {
             {
-                //Even though this makes a messagebox this
-                //is windows where we can do gui stuff in seperate
-                //threads :)
-                wxFAIL_MSG(pThis->GetErrorString(hr));
+        *pLoadProgress = loadProgress;
+        *pLoadTotal = loadTotal;
             }
             }
-            // If this is the end of the clip, notify handler
-            else if(1 == evCode) //EC_COMPLETE
+    else
             {
             {
-                pThis->OnStop();
-            }
-        }
-
-        Sleep(10);
+        //When not loading from a URL QueryProgress will return
+        //E_NOINTERFACE or whatever
+        //wxAMFAIL(hr);
+        *pLoadProgress = 0;
+        *pLoadTotal = 0;
     }
     }
-
-    return NULL;
 }
 
 }
 
-
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-// wxAMMediaBackend::OnStop
+// wxAMMediaBackend::GetVideoSize
 //
 //
-// Handle stopping when the stream ends
+// Obtains the cached original video size
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-void wxAMMediaBackend::OnStop()
+wxSize wxAMMediaBackend::GetVideoSize() const
 {
 {
-    //send the event to our child
-    wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId());
-    m_ctrl->ProcessEvent(theEvent);
-
-    //if the user didn't veto it, stop the stream
-    if (theEvent.IsAllowed())
-    {
-        //Interestingly enough, DirectShow does not actually stop
-        //the filters - even when it reaches the end!
-        wxVERIFY( Stop() );
+    return m_bestSize;
+}
 
 
-        //send the event to our child
-        wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
-                              m_ctrl->GetId());
-        m_ctrl->ProcessEvent(theEvent);
-    }
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::Move
+//
+// We take care of this in our redrawing
+//---------------------------------------------------------------------------
+void wxAMMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y),
+                            int WXUNUSED(w), int WXUNUSED(h))
+{
 }
 
 //---------------------------------------------------------------------------
 // wxAMMediaEvtHandler::OnEraseBackground
 //
 // Tell WX not to erase the background of our control window
 }
 
 //---------------------------------------------------------------------------
 // wxAMMediaEvtHandler::OnEraseBackground
 //
 // Tell WX not to erase the background of our control window
+// so that resizing is a bit smoother
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-void wxAMMediaEvtHandler::OnEraseBackground(wxEraseEvent& evt)
+void wxAMMediaEvtHandler::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
 {
 {
-    wxAMMediaBackend* pThis = (wxAMMediaBackend*) this;
-    if(pThis->m_pVMC && pThis->m_bVideo)
-    {
-        //TODO: Use wxClientDC?
-        HDC hdc = ::GetDC((HWND)pThis->m_ctrl->GetHandle());
-        HRESULT hr = pThis->m_pVMC->RepaintVideo((HWND)pThis->m_ctrl->GetHandle(),
-                                        hdc);
-        if(FAILED(hr))
-        {
-            wxFAIL_MSG(pThis->GetErrorString(hr));
-        }
-        ::ReleaseDC((HWND)pThis->m_ctrl->GetHandle(), hdc);
-    }
-    else
-    {
-        evt.Skip();
-    }
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
@@ -1917,15 +3363,13 @@ bool wxMCIMediaBackend::Load(const wxString& fileName)
     if(!m_hNotifyWnd)
     {
         wxLogSysError( wxT("Could not create hidden needed for ")
     if(!m_hNotifyWnd)
     {
         wxLogSysError( wxT("Could not create hidden needed for ")
-                       wxT("registering for DirectShow events!")  );
+                       wxT("registering for MCI events!")  );
 
         return false;
     }
 
     wxSetWindowProc(m_hNotifyWnd, wxMCIMediaBackend::NotifyWndProc);
 
         return false;
     }
 
     wxSetWindowProc(m_hNotifyWnd, wxMCIMediaBackend::NotifyWndProc);
-
-    ::SetWindowLong(m_hNotifyWnd, GWL_USERDATA,
-                       (LONG) this);
+    wxSetWindowUserData(m_hNotifyWnd, this);
 
     //
     //Here, if the parent of the control has a sizer - we
 
     //
     //Here, if the parent of the control has a sizer - we
@@ -1938,6 +3382,11 @@ bool wxMCIMediaBackend::Load(const wxString& fileName)
     m_ctrl->GetParent()->Update();
     m_ctrl->SetSize(m_ctrl->GetSize());
 
     m_ctrl->GetParent()->Update();
     m_ctrl->SetSize(m_ctrl->GetSize());
 
+    //send loaded event
+    wxMediaEvent theEvent(wxEVT_MEDIA_LOADED,
+                            m_ctrl->GetId());
+    m_ctrl->AddPendingEvent(theEvent);
+
     return true;
 }
 
     return true;
 }
 
@@ -2110,7 +3559,8 @@ bool wxMCIMediaBackend::SetVolume(double dVolume)
     audioParms.lpstrQuality = NULL;
 
     if (mciSendCommand(m_hDev, 0x0873, //MCI_SETAUDIO
     audioParms.lpstrQuality = NULL;
 
     if (mciSendCommand(m_hDev, 0x0873, //MCI_SETAUDIO
-                        0x00800000L | 0x01000000L, //MCI_DGV_SETAUDIO+(_ITEM | _VALUE)
+                        //MCI_DGV_SETAUDIO+(_ITEM | _VALUE)
+                        0x00800000L | 0x01000000L,
                        (DWORD)(LPSTR)&audioParms) != 0)
         return false;
     return true;
                        (DWORD)(LPSTR)&audioParms) != 0)
         return false;
     return true;
@@ -2219,13 +3669,8 @@ LRESULT CALLBACK wxMCIMediaBackend::NotifyWndProc(HWND hWnd, UINT nMsg,
                                                   WPARAM wParam,
                                                   LPARAM lParam)
 {
                                                   WPARAM wParam,
                                                   LPARAM lParam)
 {
-    wxMCIMediaBackend* backend = (wxMCIMediaBackend*)
-#ifdef _WIN32
-        ::GetWindowLong(hWnd, GWL_USERDATA);
-#else
-        ::GetWindowLongPtr(hWnd, GWLP_USERDATA);
-#endif
-    wxASSERT(backend);
+    wxMCIMediaBackend* backend =
+        (wxMCIMediaBackend*)wxGetWindowUserData(hWnd);
 
     return backend->OnNotifyWndProc(hWnd, nMsg, wParam, lParam);
 }
 
     return backend->OnNotifyWndProc(hWnd, nMsg, wParam, lParam);
 }
@@ -2256,54 +3701,98 @@ LRESULT CALLBACK wxMCIMediaBackend::OnNotifyWndProc(HWND hWnd, UINT nMsg,
     }
     return DefWindowProc(hWnd, nMsg, wParam, lParam);
 }
     }
     return DefWindowProc(hWnd, nMsg, wParam, lParam);
 }
+
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
 // wxQTMediaBackend
 //
 // TODO: Use a less cludgy way to pause/get state/set state
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 //
 // wxQTMediaBackend
 //
 // TODO: Use a less cludgy way to pause/get state/set state
-// TODO: Dynamically load from qtml.dll
+// FIXME: Greg Hazel reports that sometimes files that cannot be played
+// with this backend are treated as playable anyway - not verifyed though.
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
 
 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
 
-//Time between timer calls
-#define MOVIE_DELAY 100
+//Time between timer calls - this is the Apple recommondation to the TCL
+//team I believe
+#define MOVIE_DELAY 20
 
 #include "wx/timer.h"
 
 
 #include "wx/timer.h"
 
-// --------------------------------------------------------------------------
-//          wxQTTimer - Handle Asyncronous Playing
-// --------------------------------------------------------------------------
-class _wxQTTimer : public wxTimer
+
+//---------------------------------------------------------------------------
+//          wxQTLoadTimer
+//
+//  QT, esp. QT for Windows is very picky about how you go about
+//  async loading.  If you were to go through a Windows message loop
+//  or a MoviesTask or both and then check the movie load state
+//  it would still return 1000 (loading)... even (pre)prerolling doesn't
+//  help.  However, making a load timer like this works
+//---------------------------------------------------------------------------
+class wxQTLoadTimer : public wxTimer
 {
 public:
 {
 public:
-    _wxQTTimer(Movie movie, wxQTMediaBackend* parent, wxQuickTimeLibrary* pLib) :
-        m_movie(movie), m_bPaused(false), m_parent(parent), m_pLib(pLib)
-    {
-    }
+    wxQTLoadTimer(Movie movie, wxQTMediaBackend* parent, wxQuickTimeLibrary* pLib) :
+      m_movie(movie), m_parent(parent), m_pLib(pLib) {}
 
 
-    ~_wxQTTimer()
+    void Notify()
     {
     {
+        m_pLib->MoviesTask(m_movie, 0);
+        //kMovieLoadStatePlayable
+        if(m_pLib->GetMovieLoadState(m_movie) >= 10000)
+    {
+            m_parent->FinishLoad();
+            delete this;
+    }
     }
 
     }
 
-    bool GetPaused() {return m_bPaused;}
-    void SetPaused(bool bPaused) {m_bPaused = bPaused;}
+protected:
+    Movie m_movie;                  //Our movie instance
+    wxQTMediaBackend* m_parent;     //Backend pointer
+    wxQuickTimeLibrary* m_pLib;     //Interfaces
+};
+
+
+// --------------------------------------------------------------------------
+//          wxQTPlayTimer - Handle Asyncronous Playing
+//
+// 1) Checks to see if the movie is done, and if not continues
+//    streaming the movie
+// 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
+//    the movie.
+// --------------------------------------------------------------------------
+class wxQTPlayTimer : public wxTimer
+{
+public:
+    wxQTPlayTimer(Movie movie, wxQTMediaBackend* parent,
+                  wxQuickTimeLibrary* pLib) :
+        m_movie(movie), m_parent(parent), m_pLib(pLib) {}
 
 
-    //-----------------------------------------------------------------------
-    // _wxQTTimer::Notify
-    //
-    // 1) Checks to see if the movie is done, and if not continues
-    //    streaming the movie
-    // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
-    //    the movie.
-    //-----------------------------------------------------------------------
     void Notify()
     {
     void Notify()
     {
-        if (!m_bPaused)
+        //
+        //  OK, a little explaining - basically originally
+        //  we only called MoviesTask if the movie was actually
+        //  playing (not paused or stopped)... this was before
+        //  we realized MoviesTask actually handles repainting
+        //  of the current frame - so if you were to resize
+        //  or something it would previously not redraw that
+        //  portion of the movie.
+        //
+        //  So now we call MoviesTask always so that it repaints
+        //  correctly.
+        //
+        m_pLib->MoviesTask(m_movie, 0);
+
+        //
+        //  Handle the stop event - if the movie has reached
+        //  the end, notify our handler
+        //
+        //  m_bPlaying == !(Stopped | Paused)
+        //
+        if (m_parent->m_bPlaying)
         {
         {
-            if(!m_pLib->IsMovieDone(m_movie))
-                m_pLib->MoviesTask(m_movie, MOVIE_DELAY);
-            else
+            if(m_pLib->IsMovieDone(m_movie))
             {
                 wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
                                       m_parent->m_ctrl->GetId());
             {
                 wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
                                       m_parent->m_ctrl->GetId());
@@ -2311,14 +3800,13 @@ public:
 
                 if(theEvent.IsAllowed())
                 {
 
                 if(theEvent.IsAllowed())
                 {
-                    Stop();
                     m_parent->Stop();
                     wxASSERT(m_pLib->GetMoviesError() == noErr);
 
                     //send the event to our child
                     wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
                                           m_parent->m_ctrl->GetId());
                     m_parent->Stop();
                     wxASSERT(m_pLib->GetMoviesError() == noErr);
 
                     //send the event to our child
                     wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
                                           m_parent->m_ctrl->GetId());
-                    m_parent->m_ctrl->ProcessEvent(theEvent);
+                    m_parent->m_ctrl->AddPendingEvent(theEvent);
                 }
             }
         }
                 }
             }
         }
@@ -2326,17 +3814,43 @@ public:
 
 protected:
     Movie m_movie;                  //Our movie instance
 
 protected:
     Movie m_movie;                  //Our movie instance
-    bool m_bPaused;                 //Whether we are paused or not
     wxQTMediaBackend* m_parent;     //Backend pointer
     wxQuickTimeLibrary* m_pLib;         //Interfaces
 };
 
     wxQTMediaBackend* m_parent;     //Backend pointer
     wxQuickTimeLibrary* m_pLib;         //Interfaces
 };
 
+
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::QTWndProc
+//
+// Forwards events to the Movie Controller so that it can
+// redraw itself/process messages etc..
+//---------------------------------------------------------------------------
+LRESULT CALLBACK wxQTMediaBackend::QTWndProc(HWND hWnd, UINT nMsg,
+                                             WPARAM wParam, LPARAM lParam)
+{
+    wxQTMediaBackend* pThis = (wxQTMediaBackend*)wxGetWindowUserData(hWnd);
+
+    MSG msg;
+    msg.hwnd = hWnd;
+    msg.message = nMsg;
+    msg.wParam = wParam;
+    msg.lParam = lParam;
+    msg.time = 0;
+    msg.pt.x = 0;
+    msg.pt.y = 0;
+    EventRecord theEvent;
+    pThis->m_lib.NativeEventToMacEvent(&msg, &theEvent);
+    pThis->m_lib.MCIsPlayerEvent(pThis->m_pMC, &theEvent);
+    return pThis->m_ctrl->MSWWindowProc(nMsg, wParam, lParam);
+}
+
 //---------------------------------------------------------------------------
 // wxQTMediaBackend Destructor
 //
 // Sets m_timer to NULL signifying we havn't loaded anything yet
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 // wxQTMediaBackend Destructor
 //
 // Sets m_timer to NULL signifying we havn't loaded anything yet
 //---------------------------------------------------------------------------
-wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
+wxQTMediaBackend::wxQTMediaBackend()
+: m_movie(NULL), m_bPlaying(false), m_timer(NULL), m_pMC(NULL)
 {
 }
 
 {
 }
 
@@ -2351,11 +3865,20 @@ wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
 //---------------------------------------------------------------------------
 wxQTMediaBackend::~wxQTMediaBackend()
 {
 //---------------------------------------------------------------------------
 wxQTMediaBackend::~wxQTMediaBackend()
 {
-    if(m_timer)
+    if(m_movie)
         Cleanup();
 
     if(m_lib.IsOk())
     {
         Cleanup();
 
     if(m_lib.IsOk())
     {
+        if(m_pMC)
+        {
+            m_lib.DisposeMovieController(m_pMC);
+        //    m_pMC = NULL;
+        }
+
+        m_lib.DestroyPortAssociation(
+            (CGrafPtr)m_lib.GetNativeWindowPort(m_ctrl->GetHWND()));
+
         //Note that ExitMovies() is not necessary, but
         //the docs are fuzzy on whether or not TerminateQTML is
         m_lib.ExitMovies();
         //Note that ExitMovies() is not necessary, but
         //the docs are fuzzy on whether or not TerminateQTML is
         m_lib.ExitMovies();
@@ -2383,7 +3906,8 @@ bool wxQTMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
     int nError = m_lib.InitializeQTML(0);
     if (nError != noErr)    //-2093 no dll
     {
     int nError = m_lib.InitializeQTML(0);
     if (nError != noErr)    //-2093 no dll
     {
-        wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError));
+        wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"),
+                                    nError));
         return false;
     }
     m_lib.EnterMovies();
         return false;
     }
     m_lib.EnterMovies();
@@ -2401,7 +3925,20 @@ bool wxQTMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
                             validator, name) )
         return false;
 
                             validator, name) )
         return false;
 
-    m_ctrl = ctrl;
+
+    m_ctrl = ctrl; //assign the control to our member
+
+    // Create a port association for our window so we
+    // can use it as a WindowRef
+    m_lib.CreatePortAssociation(m_ctrl->GetHWND(), NULL, 0L);
+
+    //Part of a suggestion from Greg Hazel to repaint
+    //movie when idle
+    m_ctrl->Connect(m_ctrl->GetId(), wxEVT_ERASE_BACKGROUND,
+        wxEraseEventHandler(wxQTMediaEvtHandler::OnEraseBackground),
+        NULL, (wxEvtHandler*) this);
+
+    // done
     return true;
 }
 
     return true;
 }
 
@@ -2411,11 +3948,12 @@ bool wxQTMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
 // 1) Get an FSSpec from the Windows path name
 // 2) Open the movie
 // 3) Obtain the movie instance from the movie resource
 // 1) Get an FSSpec from the Windows path name
 // 2) Open the movie
 // 3) Obtain the movie instance from the movie resource
-// 4)
+// 4) Close the movie resource
+// 5) Finish loading
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::Load(const wxString& fileName)
 {
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::Load(const wxString& fileName)
 {
-    if(m_timer)
+    if(m_movie)
         Cleanup();
 
     short movieResFile = 0; //= 0 because of annoying VC6 warning
         Cleanup();
 
     short movieResFile = 0; //= 0 because of annoying VC6 warning
@@ -2440,24 +3978,59 @@ bool wxQTMediaBackend::Load(const wxString& fileName)
                    NULL
                 ); //wasChanged
 
                    NULL
                 ); //wasChanged
 
+    //m_lib.GetMoviesStickyError() because it may not find the
+    //proper codec and play black video and other strange effects,
+    //not to mention mess up the dynamic backend loading scheme
+    //of wxMediaCtrl - so it just does what the QuickTime player does
+    if(err == noErr  && m_lib.GetMoviesStickyError() == noErr)
+    {
     m_lib.CloseMovieFile (movieResFile);
 
     m_lib.CloseMovieFile (movieResFile);
 
-    if (err != noErr)
+        FinishLoad();
+        return true;
+    }
+    else
         return false;
         return false;
+}
 
 
-    FinishLoad();
 
 
-    return m_lib.GetMoviesError() == noErr;
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::PPRMProc (static)
+//
+// Called when done PrePrerolling the movie.
+// Note that in 99% of the cases this does nothing...
+// Anyway we set up the loading timer here to tell us when the movie is done
+//---------------------------------------------------------------------------
+void wxQTMediaBackend::PPRMProc (Movie theMovie, OSErr theErr, void* theRefCon)
+{
+    wxASSERT( theMovie );
+    wxASSERT( theRefCon );
+    wxASSERT( theErr == noErr );
+
+    wxQTMediaBackend* pBE = (wxQTMediaBackend*) theRefCon;
+
+    long lTime = pBE->m_lib.GetMovieTime(theMovie,NULL);
+    Fixed rate = pBE->m_lib.GetMoviePreferredRate(theMovie);
+    pBE->m_lib.PrerollMovie(theMovie,lTime,rate);
+    pBE->m_timer = new wxQTLoadTimer(pBE->m_movie, pBE, &pBE->m_lib);
+    pBE->m_timer->Start(MOVIE_DELAY);
 }
 
 }
 
+
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::Load (URL Version)
 //
 //
-// TODO
+// 1) Build an escaped URI from location
+// 2) Create a handle to store the URI string
+// 3) Put the URI string inside the handle
+// 4) Make a QuickTime URL data ref from the handle with the URI in it
+// 5) Clean up the URI string handle
+// 6) Do some prerolling
+// 7) Finish Loading
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::Load(const wxURI& location)
 {
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::Load(const wxURI& location)
 {
-    if(m_timer)
+    if(m_movie)
         Cleanup();
 
     wxString theURI = location.BuildURI();
         Cleanup();
 
     wxString theURI = location.BuildURI();
@@ -2468,41 +4041,61 @@ bool wxQTMediaBackend::Load(const wxURI& location)
     m_lib.BlockMove(theURI.mb_str(), *theHandle, theURI.length() + 1);
 
     //create the movie from the handle that refers to the URI
     m_lib.BlockMove(theURI.mb_str(), *theHandle, theURI.length() + 1);
 
     //create the movie from the handle that refers to the URI
-    OSErr err = m_lib.NewMovieFromDataRef(&m_movie, newMovieActive,
+    OSErr err = m_lib.NewMovieFromDataRef(&m_movie, newMovieActive |
+                                                    newMovieAsyncOK
+                                                    /*|newMovieIdleImportOK*/,
                                 NULL, theHandle,
                                 URLDataHandlerSubType);
 
     m_lib.DisposeHandle(theHandle);
 
                                 NULL, theHandle,
                                 URLDataHandlerSubType);
 
     m_lib.DisposeHandle(theHandle);
 
-    if (err != noErr)
-        return false;
-
-    //preroll movie for streaming
-    //TODO:Async this?
- /*
-     TimeValue timeNow;
+    if (err == noErr)
+    {
+        long timeNow;
     Fixed playRate;
     Fixed playRate;
-    timeNow = GetMovieTime(m_movie, NULL);
-    playRate = GetMoviePreferredRate(m_movie);
-    PrePrerollMovie(m_movie, timeNow, playRate, NULL, NULL);
-    PrerollMovie(m_movie, timeNow, playRate);
-    m_lib.SetMovieRate(m_movie, playRate);
-*/
 
 
-    FinishLoad();
+        timeNow = m_lib.GetMovieTime(m_movie, NULL);
+        wxASSERT(m_lib.GetMoviesError() == noErr);
 
 
-    return m_lib.GetMoviesError() == noErr;
+        playRate = m_lib.GetMoviePreferredRate(m_movie);
+        wxASSERT(m_lib.GetMoviesError() == noErr);
+
+        //
+        //  Note that the callback here is optional,
+        //  but without it PrePrerollMovie can be buggy
+        //  (see Apple ml).  Also, some may wonder
+        //  why we need this at all - this is because
+        //  Apple docs say QuickTime streamed movies
+        //  require it if you don't use a Movie Controller,
+        //  which we don't by default.
+        //
+        m_lib.PrePrerollMovie(m_movie, timeNow, playRate,
+                              (WXFARPROC)wxQTMediaBackend::PPRMProc,
+                              (void*)this);
+        return true;
+    }
+    else
+        return false;
 }
 
 }
 
+
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::FinishLoad
 //
 //
-// TODO
+// 1) Create the movie timer
+// 2) Get real size of movie for GetBestSize/sizers
+// 3) Set the movie time scale to something usable so that seeking
+//    etc.  will work correctly
+// 4) Set our Movie Controller to display the movie if it exists,
+//    otherwise set the bounds of the Movie
+// 5) Refresh parent window
 //---------------------------------------------------------------------------
 void wxQTMediaBackend::FinishLoad()
 {
 //---------------------------------------------------------------------------
 void wxQTMediaBackend::FinishLoad()
 {
-    m_timer = new _wxQTTimer(m_movie, (wxQTMediaBackend*) this, &m_lib);
+    // Create the playing/streaming timer
+    m_timer = new wxQTPlayTimer(m_movie, (wxQTMediaBackend*) this, &m_lib);
     wxASSERT(m_timer);
     wxASSERT(m_timer);
+    m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
 
     //get the real size of the movie
     Rect outRect;
 
     //get the real size of the movie
     Rect outRect;
@@ -2513,21 +4106,29 @@ void wxQTMediaBackend::FinishLoad()
     m_bestSize.x = outRect.right - outRect.left;
     m_bestSize.y = outRect.bottom - outRect.top;
 
     m_bestSize.x = outRect.right - outRect.left;
     m_bestSize.y = outRect.bottom - outRect.top;
 
-    //reparent movie/*AudioMediaCharacteristic*/
-    if(m_lib.GetMovieIndTrackType(m_movie, 1,
-                            VisualMediaCharacteristic,
-                            (1 << 1) //movieTrackCharacteristic
-                            | (1 << 2) //movieTrackEnabledOnly
-                            ) != NULL)
+    //
+    // Handle the movie GWorld
+    //
+    if(m_pMC)
+    {
+        Point thePoint;
+        thePoint.h = thePoint.v = 0;
+        m_lib.MCSetMovie(m_pMC, m_movie,
+               m_lib.GetNativeWindowPort(m_ctrl->GetHandle()),
+               thePoint);
+        m_lib.MCSetVisible(m_pMC, true);
+        m_bestSize.y += 16;
+    }
+    else
     {
     {
-        m_lib.CreatePortAssociation(m_ctrl->GetHWND(), NULL, 0L);
-
         m_lib.SetMovieGWorld(m_movie,
                        (CGrafPtr) m_lib.GetNativeWindowPort(m_ctrl->GetHWND()),
                        NULL);
     }
 
         m_lib.SetMovieGWorld(m_movie,
                        (CGrafPtr) m_lib.GetNativeWindowPort(m_ctrl->GetHWND()),
                        NULL);
     }
 
-    //we want millisecond precision
+    //
+    // Set the movie to millisecond precision
+    //
     m_lib.SetMovieTimeScale(m_movie, 1000);
     wxASSERT(m_lib.GetMoviesError() == noErr);
 
     m_lib.SetMovieTimeScale(m_movie, 1000);
     wxASSERT(m_lib.GetMoviesError() == noErr);
 
@@ -2540,43 +4141,58 @@ void wxQTMediaBackend::FinishLoad()
     m_ctrl->GetParent()->Layout();
     m_ctrl->GetParent()->Refresh();
     m_ctrl->GetParent()->Update();
     m_ctrl->GetParent()->Layout();
     m_ctrl->GetParent()->Refresh();
     m_ctrl->GetParent()->Update();
+    m_ctrl->SetSize(m_ctrl->GetSize());
+
+    //loaded - note that MoviesTask must and will be called before this
+    //by the previous timer since this gets appended to the event list after
+    //the timer's first go
+    wxMediaEvent theEvent(wxEVT_MEDIA_LOADED,
+                            m_ctrl->GetId());
+    m_ctrl->AddPendingEvent(theEvent);
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::Play
 //
 //
-// TODO
+// 1) Start the QT movie
+// 2) Start the movie loading timer
+//
+// NOTE:  This will still return success even when
+// the movie is still loading, and as mentioned in wxQTLoadTimer
+// I don't know of a way to force this to be sync - so if its
+// still loading the function will return true but the movie will
+// still be in the stopped state
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::Play()
 {
     m_lib.StartMovie(m_movie);
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::Play()
 {
     m_lib.StartMovie(m_movie);
-    m_timer->SetPaused(false);
-    m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
+    m_bPlaying = true;
     return m_lib.GetMoviesError() == noErr;
 }
 
 //---------------------------------------------------------------------------
     return m_lib.GetMoviesError() == noErr;
 }
 
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::Pause
 //
 //
-// TODO
+// 1) Stop the movie
+// 2) Stop the movie timer
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::Pause()
 {
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::Pause()
 {
+    m_bPlaying = false;
     m_lib.StopMovie(m_movie);
     m_lib.StopMovie(m_movie);
-    m_timer->SetPaused(true);
-    m_timer->Stop();
     return m_lib.GetMoviesError() == noErr;
 }
 
 //---------------------------------------------------------------------------
     return m_lib.GetMoviesError() == noErr;
 }
 
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::Stop
 //
 //
-// TODO
+// 1) Stop the movie
+// 2) Stop the movie timer
+// 3) Seek to the beginning of the movie
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::Stop()
 {
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::Stop()
 {
-    m_timer->SetPaused(false);
-    m_timer->Stop();
+    m_bPlaying = false;
 
     m_lib.StopMovie(m_movie);
     if(m_lib.GetMoviesError() != noErr)
 
     m_lib.StopMovie(m_movie);
     if(m_lib.GetMoviesError() != noErr)
@@ -2587,9 +4203,9 @@ bool wxQTMediaBackend::Stop()
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::GetPlaybackRate
 //
 //
-// TODO
+// 1) Get the movie playback rate from ::GetMovieRate
 //---------------------------------------------------------------------------
 double wxQTMediaBackend::GetPlaybackRate()
 {
 //---------------------------------------------------------------------------
 double wxQTMediaBackend::GetPlaybackRate()
 {
@@ -2597,9 +4213,9 @@ double wxQTMediaBackend::GetPlaybackRate()
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::SetPlaybackRate
 //
 //
-// TODO
+// 1) Convert dRate to Fixed and Set the movie rate through SetMovieRate
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::SetPlaybackRate(double dRate)
 {
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::SetPlaybackRate(double dRate)
 {
@@ -2608,19 +4224,29 @@ bool wxQTMediaBackend::SetPlaybackRate(double dRate)
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::SetPosition
 //
 //
-// TODO
+// 1) Create a time record struct (TimeRecord) with appropriate values
+// 2) Pass struct to SetMovieTime
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::SetPosition(wxLongLong where)
 {
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::SetPosition(wxLongLong where)
 {
+    //NB:  For some reason SetMovieTime does not work
+    //correctly with the Quicktime Windows SDK (6)
+    //From Muskelkatermann at the wxForum
+    //http://www.solidsteel.nl/users/wxwidgets/viewtopic.php?t=2957
+    //RN - note that I have not verified this but there
+    //is no harm in calling SetMovieTimeValue instead
+#if 0
     TimeRecord theTimeRecord;
     memset(&theTimeRecord, 0, sizeof(TimeRecord));
     theTimeRecord.value.lo = where.GetLo();
     theTimeRecord.scale = m_lib.GetMovieTimeScale(m_movie);
     theTimeRecord.base = m_lib.GetMovieTimeBase(m_movie);
     m_lib.SetMovieTime(m_movie, &theTimeRecord);
     TimeRecord theTimeRecord;
     memset(&theTimeRecord, 0, sizeof(TimeRecord));
     theTimeRecord.value.lo = where.GetLo();
     theTimeRecord.scale = m_lib.GetMovieTimeScale(m_movie);
     theTimeRecord.base = m_lib.GetMovieTimeBase(m_movie);
     m_lib.SetMovieTime(m_movie, &theTimeRecord);
-
+#else
+    m_lib.SetMovieTimeValue(m_movie, where.GetLo());
+#endif
     if (m_lib.GetMoviesError() != noErr)
         return false;
 
     if (m_lib.GetMoviesError() != noErr)
         return false;
 
@@ -2656,11 +4282,12 @@ wxLongLong wxQTMediaBackend::GetPosition()
 double wxQTMediaBackend::GetVolume()
 {
     short sVolume = m_lib.GetMovieVolume(m_movie);
 double wxQTMediaBackend::GetVolume()
 {
     short sVolume = m_lib.GetMovieVolume(m_movie);
+    wxASSERT(m_lib.GetMoviesError() == noErr);
 
     if(sVolume & (128 << 8)) //negative - no sound
         return 0.0;
 
 
     if(sVolume & (128 << 8)) //negative - no sound
         return 0.0;
 
-    return (sVolume & (127 << 8)) ? 1.0 : ((double)(sVolume & 255)) / 255.0;
+    return sVolume/256.0;
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
@@ -2680,15 +4307,14 @@ double wxQTMediaBackend::GetVolume()
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::SetVolume(double dVolume)
 {
 //---------------------------------------------------------------------------
 bool wxQTMediaBackend::SetVolume(double dVolume)
 {
-    short sVolume = (short) (dVolume >= .9999 ? 1 << 8 : (dVolume * 255) );
-    m_lib.SetMovieVolume(m_movie, sVolume);
-    return true;
+    m_lib.SetMovieVolume(m_movie, (short) (dVolume * 256));
+    return m_lib.GetMoviesError() == noErr;
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::GetDuration
 //
 //
-// TODO
+// Calls GetMovieDuration
 //---------------------------------------------------------------------------
 wxLongLong wxQTMediaBackend::GetDuration()
 {
 //---------------------------------------------------------------------------
 wxLongLong wxQTMediaBackend::GetDuration()
 {
@@ -2696,40 +4322,174 @@ wxLongLong wxQTMediaBackend::GetDuration()
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::GetState
 //
 //
-// TODO
+// Determines the current state - if we are at the beginning we
+// are stopped
 //---------------------------------------------------------------------------
 wxMediaState wxQTMediaBackend::GetState()
 {
 //---------------------------------------------------------------------------
 wxMediaState wxQTMediaBackend::GetState()
 {
-    if ( !m_timer || (m_timer->IsRunning() == false &&
-                      m_timer->GetPaused() == false) )
-        return wxMEDIASTATE_STOPPED;
-
-    if( m_timer->IsRunning() == true )
+    if (m_bPlaying == true)
         return wxMEDIASTATE_PLAYING;
         return wxMEDIASTATE_PLAYING;
+    else if ( !m_movie || wxQTMediaBackend::GetPosition() == 0)
+        return wxMEDIASTATE_STOPPED;
     else
         return wxMEDIASTATE_PAUSED;
 }
 
 //---------------------------------------------------------------------------
     else
         return wxMEDIASTATE_PAUSED;
 }
 
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::Cleanup
 //
 //
-// TODO
+// Diposes of the movie timer, Disassociates the Movie Controller with
+// movie and hides it if it exists, and stops and disposes
+// of the QT movie
 //---------------------------------------------------------------------------
 void wxQTMediaBackend::Cleanup()
 {
 //---------------------------------------------------------------------------
 void wxQTMediaBackend::Cleanup()
 {
+    m_bPlaying = false;
+
+    if(m_timer)
+    {
     delete m_timer;
     m_timer = NULL;
     delete m_timer;
     m_timer = NULL;
+    }
 
     m_lib.StopMovie(m_movie);
 
     m_lib.StopMovie(m_movie);
+
+    if(m_pMC)
+    {
+        Point thePoint;
+        thePoint.h = thePoint.v = 0;
+        m_lib.MCSetVisible(m_pMC, false);
+        m_lib.MCSetMovie(m_pMC, NULL, NULL, thePoint);
+    }
+
     m_lib.DisposeMovie(m_movie);
     m_lib.DisposeMovie(m_movie);
+    m_movie = NULL;
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
-// wxQTMediaBackend::Move
+// wxQTMediaBackend::ShowPlayerControls
 //
 //
-// TODO
+// Creates a movie controller for the Movie if the user wants it
+//---------------------------------------------------------------------------
+bool wxQTMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
+{
+    if(m_pMC)
+    {
+        //restore old wndproc
+        wxSetWindowProc((HWND)m_ctrl->GetHWND(), wxWndProc);
+        m_lib.DisposeMovieController(m_pMC);
+        m_pMC = NULL;
+        m_bestSize.y -= 16; //movie controller height
+    }
+
+    if(flags && m_movie)
+    {
+        Rect rect;
+        wxRect wxrect = m_ctrl->GetClientRect();
+
+        //make room for controller
+        if(wxrect.width < 320)
+            wxrect.width = 320;
+
+        rect.top = wxrect.y;
+        rect.left = wxrect.x;
+        rect.right = rect.left + wxrect.width;
+        rect.bottom = rect.top + wxrect.height;
+
+        if(!m_pMC)
+        {
+            m_pMC = m_lib.NewMovieController(m_movie, &rect, mcTopLeftMovie |
+                                //                        mcScaleMovieToFit |
+                                //                        mcWithBadge |
+                                                        mcWithFrame);
+            m_lib.MCDoAction(m_pMC, 32, (void*)true); //mcActionSetKeysEnabled
+            m_lib.MCSetActionFilterWithRefCon(m_pMC,
+                (WXFARPROC)wxQTMediaBackend::MCFilterProc, (void*)this);
+            m_bestSize.y += 16; //movie controller height
+
+            //
+            // By default the movie controller uses its own color
+            // pallette for the movie which can be bad on some files -
+            // so turn it off.  Also turn off its frame/border for
+            // the movie
+            //
+            // Also we take care of a couple of the interface flags here
+            //
+            long mcFlags = 0;
+            m_lib.MCDoAction(m_pMC, 39/*mcActionGetFlags*/, (void*)&mcFlags);
+            mcFlags |= (  //(1<<0)/*mcFlagSuppressMovieFrame*/ |
+                 (1<<3)/*mcFlagsUseWindowPalette*/
+                   | ((flags & wxMEDIACTRLPLAYERCONTROLS_STEP)
+                      ? 0 : (1<<1)/*mcFlagSuppressStepButtons*/)
+                   | ((flags & wxMEDIACTRLPLAYERCONTROLS_VOLUME)
+                      ? 0 : (1<<2)/*mcFlagSuppressSpeakerButton*/)
+     //              | (1<<4) /*mcFlagDontInvalidate*/ //if we take care of repainting ourselves
+                      );
+            m_lib.MCDoAction(m_pMC, 38/*mcActionSetFlags*/, (void*)mcFlags);
+
+            //intercept the wndproc of our control window
+            wxSetWindowProc((HWND)m_ctrl->GetHWND(),
+                wxQTMediaBackend::QTWndProc);
+
+            //set the user data of our window
+            wxSetWindowUserData((HWND)m_ctrl->GetHWND(), this);
+        }
+    }
+
+    //
+    //Here, if the parent of the control has a sizer - we
+    //tell it to recalculate the size of this control since
+    //the user opened a separate media file
+    //
+    m_ctrl->InvalidateBestSize();
+    m_ctrl->GetParent()->Layout();
+    m_ctrl->GetParent()->Refresh();
+    m_ctrl->GetParent()->Update();
+    m_ctrl->SetSize(m_ctrl->GetSize());
+
+    return m_lib.GetMoviesError() == noErr;
+}
+
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::MCFilterProc (static)
+//
+// Callback for when the movie controller recieves a message
+//---------------------------------------------------------------------------
+Boolean
+wxQTMediaBackend::MCFilterProc(MovieController WXUNUSED(theController),
+                               short action,
+                               void * WXUNUSED(params),
+                               LONG_PTR refCon)
+{
+    if(action != 1) //don't process idle events
+    {
+        wxQTMediaBackend* pThis = (wxQTMediaBackend*)refCon;
+
+        switch(action)
+        {
+        case 8: //play button triggered - MC will set movie to opposite state
+                //of current - playing ? paused : playing
+            pThis->m_bPlaying = !(pThis->m_bPlaying);
+
+            // NB: Sometimes it doesn't redraw properly -
+            // if you click on the button but don't move the mouse
+            // the button will not change its state until you move
+            // mcActionDraw and Refresh/Update combo do nothing
+            // to help this unfortunately
+            break;
+        default:
+            break;
+        }
+    }
+    return 0;
+}
+
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::GetVideoSize
+//
+// Returns the actual size of the QT movie
 //---------------------------------------------------------------------------
 wxSize wxQTMediaBackend::GetVideoSize() const
 {
 //---------------------------------------------------------------------------
 wxSize wxQTMediaBackend::GetVideoSize() const
 {
@@ -2739,19 +4499,67 @@ wxSize wxQTMediaBackend::GetVideoSize() const
 //---------------------------------------------------------------------------
 // wxQTMediaBackend::Move
 //
 //---------------------------------------------------------------------------
 // wxQTMediaBackend::Move
 //
-// TODO
+// Sets the bounds of either the Movie or Movie Controller
 //---------------------------------------------------------------------------
 void wxQTMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y), int w, int h)
 {
 //---------------------------------------------------------------------------
 void wxQTMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y), int w, int h)
 {
-    if(m_timer)
+    if(m_movie)
     {
     {
-        Rect theRect = {0, 0, (short)h, (short)w};
+        //make room for controller
+        if(m_pMC)
+        {
+            if(w < 320)
+                w = 320;
 
 
+            Rect theRect = {0, 0, (short)h, (short)w};
+            m_lib.MCSetControllerBoundsRect(m_pMC, &theRect);
+        }
+        else
+        {
+            Rect theRect = {0, 0, (short)h, (short)w};
         m_lib.SetMovieBox(m_movie, &theRect);
         m_lib.SetMovieBox(m_movie, &theRect);
+        }
+
         wxASSERT(m_lib.GetMoviesError() == noErr);
     }
 }
 
         wxASSERT(m_lib.GetMoviesError() == noErr);
     }
 }
 
+//---------------------------------------------------------------------------
+// wxQTMediaBackend::OnEraseBackground
+//
+// Suggestion from Greg Hazel to repaint the movie when idle
+// (on pause also)
+//
+// TODO:  We may be repainting too much here - under what exact circumstances
+// do we need this?  I think Move also repaints correctly for the Movie
+// Controller, so in that instance we don't need this either
+//---------------------------------------------------------------------------
+void wxQTMediaEvtHandler::OnEraseBackground(wxEraseEvent& evt)
+{
+    wxQTMediaBackend* qtb = (wxQTMediaBackend*)this;
+    wxQuickTimeLibrary* m_pLib = &(qtb->m_lib);
+
+    if(qtb->m_pMC)
+    {
+        //repaint movie controller
+        m_pLib->MCDoAction(qtb->m_pMC, 2 /*mcActionDraw*/,
+            m_pLib->GetNativeWindowPort(qtb->m_ctrl->GetHWND())
+                           );
+    }
+    else if(qtb->m_movie)
+    {
+        CGrafPtr port = (CGrafPtr)m_pLib->GetNativeWindowPort
+        (qtb->m_ctrl->GetHWND());
+
+        m_pLib->BeginUpdate(port);
+        m_pLib->UpdateMovie(qtb->m_movie);
+        wxASSERT(m_pLib->GetMoviesError() == noErr);
+        m_pLib->EndUpdate(port);
+    }
+
+    evt.Skip(); //repaint with window background (TODO: maybe !m_movie?)
+}
+
 //---------------------------------------------------------------------------
 //  End QT Backend
 //---------------------------------------------------------------------------
 //---------------------------------------------------------------------------
 //  End QT Backend
 //---------------------------------------------------------------------------
index cf20c15e2e63faca32faf2043d48fc4323c02ee5..714775be11729670aa9505a6067b16add64bb34c 100644 (file)
@@ -274,6 +274,8 @@ bool wxGStreamerMediaBackend::TransCapsToVideoSize(wxGStreamerMediaBackend* be,
         gst_structure_get_int (s, "width", &be->m_videoSize.x);
         gst_structure_get_int (s, "height", &be->m_videoSize.y);
 
         gst_structure_get_int (s, "width", &be->m_videoSize.x);
         gst_structure_get_int (s, "height", &be->m_videoSize.y);
 
+        wxLogDebug(wxT("Native video size: [%i,%i]"), be->m_videoSize.x, be->m_videoSize.y);
+
         const GValue *par;
         par = gst_structure_get_value (s, "pixel-aspect-ratio");
 
         const GValue *par;
         par = gst_structure_get_value (s, "pixel-aspect-ratio");
 
@@ -289,6 +291,8 @@ bool wxGStreamerMediaBackend::TransCapsToVideoSize(wxGStreamerMediaBackend* be,
                 be->m_videoSize.y = (int) ((float) den * be->m_videoSize.y / num);
         }
 
                 be->m_videoSize.y = (int) ((float) den * be->m_videoSize.y / num);
         }
 
+        wxLogDebug(wxT("Adjusted video size: [%i,%i]"), be->m_videoSize.x, be->m_videoSize.y);
+
         be->PostRecalcSize();        
         return true;
     }//end if caps
         be->PostRecalcSize();        
         return true;
     }//end if caps
@@ -308,6 +312,7 @@ void wxGStreamerMediaBackend::PostRecalcSize()
         m_ctrl->GetParent()->Layout();
         m_ctrl->GetParent()->Refresh();
         m_ctrl->GetParent()->Update();
         m_ctrl->GetParent()->Layout();
         m_ctrl->GetParent()->Refresh();
         m_ctrl->GetParent()->Update();
+        m_ctrl->SetSize(m_ctrl->GetSize());
 }
 
 //---------------------------------------------------------------------------
 }
 
 //---------------------------------------------------------------------------
@@ -446,6 +451,7 @@ bool wxGStreamerMediaBackend::Load(const wxURI& location)
         if ( ! GST_IS_X_OVERLAY(overlay) )
         {
 #endif
         if ( ! GST_IS_X_OVERLAY(overlay) )
         {
 #endif
+            wxLogDebug(wxT("Could not load Gnome preferences, reverting to xvimagesink for video for gstreamer"));
             videosink = gst_element_factory_make ("xvimagesink", "videosink");
             if ( !GST_IS_OBJECT(videosink) )
                 videosink = gst_element_factory_make ("ximagesink", "videosink");
             videosink = gst_element_factory_make ("xvimagesink", "videosink");
             if ( !GST_IS_OBJECT(videosink) )
                 videosink = gst_element_factory_make ("ximagesink", "videosink");
@@ -502,13 +508,18 @@ bool wxGStreamerMediaBackend::Load(const wxURI& location)
 #endif 
     
     //8
 #endif 
     
     //8
-    
-    wxASSERT(gst_element_set_state (m_player,
-                GST_STATE_PAUSED)    == GST_STATE_SUCCESS);            
+       int nResult = gst_element_set_state (m_player, GST_STATE_PAUSED);
+       if(nResult != GST_STATE_SUCCESS)
+       {
+           wxLogDebug(wxT("Could not set initial state to paused!"));
+           return false;
+       }
 
     const GList *list = NULL;
     g_object_get (G_OBJECT (m_player), "stream-info", &list, NULL);
 
 
     const GList *list = NULL;
     g_object_get (G_OBJECT (m_player), "stream-info", &list, NULL);
 
+    bool bVideoFound = false;
+
     for ( ; list != NULL; list = list->next)
     {
         GObject *info = (GObject *) list->data;
     for ( ; list != NULL; list = list->next)
     {
         GObject *info = (GObject *) list->data;
@@ -546,6 +557,9 @@ bool wxGStreamerMediaBackend::Load(const wxURI& location)
                 G_CALLBACK(wxGStreamerMediaBackend::OnVideoCapsReady),
                 this);
             }
                 G_CALLBACK(wxGStreamerMediaBackend::OnVideoCapsReady),
                 this);
             }
+
+            bVideoFound = true;
+            break;
         }//end if video
         else
         {
         }//end if video
         else
         {
@@ -554,7 +568,17 @@ bool wxGStreamerMediaBackend::Load(const wxURI& location)
         }
     }//end searching through info list    
 
         }
     }//end searching through info list    
 
+    if(!bVideoFound)
+    {
+        wxLogDebug(wxT("No video found for gstreamer stream"));
+    }
     m_nPausedPos = 0;
     m_nPausedPos = 0;
+
+    //send loaded event
+    wxMediaEvent theEvent(wxEVT_MEDIA_LOADED,
+                            m_ctrl->GetId());
+    m_ctrl->AddPendingEvent(theEvent);
+    
     return true;
 }
 
     return true;
 }
 
index ad8db2dcf665da7899db11746c414cbbf69fa3b6..5dc1a520133fea4cc73fca3b54c65f4bc9fd37e8 100644 (file)
 @WX_VERSION_TAG@.2 {
     global:
         *wxDialog*GetEscapeId*;
 @WX_VERSION_TAG@.2 {
     global:
         *wxDialog*GetEscapeId*;
-        *wxLogBuffer*;
+        *wxEVT_MEDIA_LOADED*;
         *wxGenericListCtrl*SetItemFont*wxFont*;
         *wxGenericListCtrl*GetItemFont*;
         *wxImage*HSVValue*;
         *wxImage*RGBValue*;
         *wxImage*RotateHue*;
         *wxGenericListCtrl*SetItemFont*wxFont*;
         *wxGenericListCtrl*GetItemFont*;
         *wxImage*HSVValue*;
         *wxImage*RGBValue*;
         *wxImage*RotateHue*;
+        *wxLogBuffer*;
+        *wxMediaCtrl*Load*wxURI*wxURI*;
+        *wxMediaCtrl*ShowPlayerControls*wxMediaPlayerControls*;
         *wxMessageOutputBest*;
         *wxShadowObject*;
         *wxWizard*FinishLayout*;
         *wxMessageOutputBest*;
         *wxShadowObject*;
         *wxWizard*FinishLayout*;