+ 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);
+
+class WXDLLIMPEXP_MEDIA wxAMMediaBackend : public wxMediaBackendCommonBase
+{
+public:
+ wxAMMediaBackend();
+ virtual ~wxAMMediaBackend();
+ void Clear();
+
+ virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxValidator& validator,
+ const wxString& name);
+
+ virtual bool Play();
+ virtual bool Pause();
+ virtual bool Stop();
+
+ 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 bool SetPosition(wxLongLong where);
+ virtual wxLongLong GetPosition();
+ virtual wxLongLong GetDuration();
+
+ virtual void Move(int x, int y, int w, int h);
+ wxSize GetVideoSize() const;
+
+ virtual double GetPlaybackRate();
+ virtual bool SetPlaybackRate(double);
+
+ virtual double GetVolume();
+ virtual bool SetVolume(double);
+
+ virtual bool ShowPlayerControls(wxMediaCtrlPlayerControls flags);
+ void Cleanup();
+
+ 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;
+ }
+
+ wxActiveX* m_pAX;
+ IActiveMovie* m_pAM;
+ IMediaPlayer* m_pMP;
+ wxTimer* m_pTimer;
+ wxSize m_bestSize;
+
+#ifdef __WXDEBUG__
+ wxDynamicLibrary m_dllQuartz;
+ LPAMGETERRORTEXT m_lpAMGetErrorText;
+ wxString GetErrorString(HRESULT hrdsv);
+#endif // __WXDEBUG__
+
+ DECLARE_DYNAMIC_CLASS(wxAMMediaBackend)
+};
+
+//---------------------------------------------------------------------------
+//
+// wxMCIMediaBackend
+//
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+// MCI Includes
+//---------------------------------------------------------------------------
+#include <mmsystem.h>
+
+class WXDLLIMPEXP_MEDIA wxMCIMediaBackend : public wxMediaBackendCommonBase
+{
+public:
+
+ wxMCIMediaBackend();
+ ~wxMCIMediaBackend();
+
+ virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxValidator& validator,
+ const wxString& name);
+
+ virtual bool Play();
+ virtual bool Pause();
+ virtual bool Stop();
+
+ virtual bool Load(const wxURI& location,
+ const wxURI& proxy)
+ { return wxMediaBackend::Load(location, proxy); }
+
+ virtual bool Load(const wxString& fileName);
+ virtual bool Load(const wxURI& location);
+
+ virtual wxMediaState GetState();
+
+ virtual bool SetPosition(wxLongLong where);
+ virtual wxLongLong GetPosition();
+ virtual wxLongLong GetDuration();
+
+ virtual void Move(int x, int y, int w, int h);
+ wxSize GetVideoSize() const;
+
+ virtual double GetPlaybackRate();
+ virtual bool SetPlaybackRate(double dRate);
+
+ virtual double GetVolume();
+ virtual bool SetVolume(double);
+
+ static LRESULT CALLBACK NotifyWndProc(HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam);
+
+ LRESULT CALLBACK OnNotifyWndProc(HWND hWnd, UINT nMsg,
+ WPARAM wParam, LPARAM lParam);
+
+ MCIDEVICEID m_hDev; //Our MCI Device ID/Handler
+ HWND m_hNotifyWnd; //Window to use for MCI events
+ bool m_bVideo; //Whether or not we have video
+
+ DECLARE_DYNAMIC_CLASS(wxMCIMediaBackend)
+};
+
+//---------------------------------------------------------------------------
+//
+// 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
+//---------------------------------------------------------------------------
+
+//---------------------------------------------------------------------------
+// QT Includes
+//---------------------------------------------------------------------------
+//#include <qtml.h> //Windoze QT include
+//#include <QuickTimeComponents.h> //Standard QT stuff
+#include "wx/dynlib.h"
+
+//---------------------------------------------------------------------------
+// QT Types
+//---------------------------------------------------------------------------
+typedef struct MovieRecord* Movie;
+typedef wxInt16 OSErr;
+typedef wxInt32 OSStatus;
+#define noErr 0
+#define fsRdPerm 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 OSType unsigned long
+#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__)
+// use magic numbers for compilers which complain about multicharacter integers
+const OSType URLDataHandlerSubType = 1970433056;
+const OSType VisualMediaCharacteristic = 1702454643;
+#else
+const OSType URLDataHandlerSubType = 'url ';
+const OSType VisualMediaCharacteristic = 'eyes';
+#endif
+#endif
+
+struct FSSpec {
+ short vRefNum;
+ long parID;
+ Str255 name; /*Str63 on mac, Str255 on msw */
+};
+
+struct Rect {
+ short top;
+ short left;
+ short bottom;
+ short right;
+};
+
+struct wide {
+ wxInt32 hi;
+ wxUint32 lo;
+};
+
+struct TimeRecord {
+ wide value; /* units */
+ TimeScale scale; /* units per second */
+ 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
+//---------------------------------------------------------------------------
+#define wxDL_METHOD_DEFINE( rettype, name, args, shortargs, defret ) \
+ typedef rettype (* name ## Type) args ; \
+ name ## Type pfn_ ## name; \
+ rettype name args \
+ { if (m_ok) return pfn_ ## name shortargs ; return defret; }
+
+#define wxDL_VOIDMETHOD_DEFINE( name, args, shortargs ) \
+ typedef void (* name ## Type) args ; \
+ name ## Type pfn_ ## name; \
+ void name args \
+ { if (m_ok) pfn_ ## name shortargs ; }
+
+#define wxDL_METHOD_LOAD( lib, name, success ) \
+ pfn_ ## name = (name ## Type) lib.GetSymbol( wxT(#name), &success ); \
+ if (!success) { wxLog::EnableLogging(bWasLoggingEnabled); return false; }
+
+
+class WXDLLIMPEXP_MEDIA wxQuickTimeLibrary
+{
+public:
+ ~wxQuickTimeLibrary()
+ {
+ if(m_dll.IsLoaded())
+ m_dll.Unload();
+ }
+
+ bool Initialize();
+ bool IsOk() const {return m_ok;}
+
+protected:
+ wxDynamicLibrary m_dll;
+ bool m_ok;
+
+public:
+ wxDL_VOIDMETHOD_DEFINE( StartMovie, (Movie m), (m) );
+ wxDL_VOIDMETHOD_DEFINE( StopMovie, (Movie m), (m) );
+ wxDL_METHOD_DEFINE( bool, IsMovieDone, (Movie m), (m), false);
+ wxDL_VOIDMETHOD_DEFINE( GoToBeginningOfMovie, (Movie m), (m) );
+ wxDL_METHOD_DEFINE( OSErr, GetMoviesError, (), (), -1);
+ wxDL_METHOD_DEFINE( OSErr, EnterMovies, (), (), -1);
+ wxDL_VOIDMETHOD_DEFINE( ExitMovies, (), () );
+ wxDL_METHOD_DEFINE( OSErr, InitializeQTML, (long flags), (flags), -1);
+ wxDL_VOIDMETHOD_DEFINE( TerminateQTML, (), () );
+
+ wxDL_METHOD_DEFINE( OSErr, NativePathNameToFSSpec,
+ (char* inName, FSSpec* outFile, long flags),
+ (inName, outFile, flags), -1);
+
+ wxDL_METHOD_DEFINE( OSErr, OpenMovieFile,
+ (const FSSpec * fileSpec, short * resRefNum, wxInt8 permission),
+ (fileSpec, resRefNum, permission), -1 );
+
+ wxDL_METHOD_DEFINE( OSErr, CloseMovieFile,
+ (short resRefNum), (resRefNum), -1);
+
+ wxDL_METHOD_DEFINE( OSErr, NewMovieFromFile,
+ (Movie * theMovie, short resRefNum, short * resId,
+ StringPtr resName, short newMovieFlags,
+ bool * dataRefWasChanged),
+ (theMovie, resRefNum, resId, resName, newMovieFlags,
+ dataRefWasChanged), -1);
+
+ wxDL_VOIDMETHOD_DEFINE( SetMovieRate, (Movie m, Fixed rate), (m, rate) );
+ wxDL_METHOD_DEFINE( Fixed, GetMovieRate, (Movie m), (m), 0);
+ wxDL_VOIDMETHOD_DEFINE( MoviesTask, (Movie m, long maxms), (m, maxms) );
+ wxDL_VOIDMETHOD_DEFINE( BlockMove,
+ (const char* p1, const char* p2, long s), (p1,p2,s) );
+ wxDL_METHOD_DEFINE( Handle, NewHandleClear, (long s), (s), NULL );
+
+ wxDL_METHOD_DEFINE( OSErr, NewMovieFromDataRef,
+ (Movie * m, short flags, short * id,
+ Handle dataRef, OSType dataRefType),
+ (m,flags,id,dataRef,dataRefType), -1 );
+
+ wxDL_VOIDMETHOD_DEFINE( DisposeHandle, (Handle h), (h) );
+ wxDL_VOIDMETHOD_DEFINE( GetMovieNaturalBoundsRect, (Movie m, Rect* r), (m,r) );
+ wxDL_METHOD_DEFINE( void*, GetMovieIndTrackType,
+ (Movie m, long index, OSType type, long flags),
+ (m,index,type,flags), NULL );
+ wxDL_VOIDMETHOD_DEFINE( CreatePortAssociation,
+ (void* hWnd, void* junk, long morejunk), (hWnd, junk, morejunk) );
+ wxDL_METHOD_DEFINE(void*, GetNativeWindowPort, (void* hWnd), (hWnd), NULL);
+ wxDL_VOIDMETHOD_DEFINE(SetMovieGWorld, (Movie m, CGrafPtr port, void* whatever),
+ (m, port, whatever) );
+ wxDL_VOIDMETHOD_DEFINE(DisposeMovie, (Movie m), (m) );
+ wxDL_VOIDMETHOD_DEFINE(SetMovieBox, (Movie m, Rect* r), (m,r));
+ wxDL_VOIDMETHOD_DEFINE(SetMovieTimeScale, (Movie m, long s), (m,s));
+ wxDL_METHOD_DEFINE(long, GetMovieDuration, (Movie m), (m), 0);
+ wxDL_METHOD_DEFINE(TimeBase, GetMovieTimeBase, (Movie m), (m), 0);
+ wxDL_METHOD_DEFINE(TimeScale, GetMovieTimeScale, (Movie m), (m), 0);
+ wxDL_METHOD_DEFINE(long, GetMovieTime, (Movie m, void* cruft), (m,cruft), 0);
+ 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()
+{
+ m_ok = false;
+
+ bool bWasLoggingEnabled = wxLog::EnableLogging(false); //Turn off the wxDynamicLibrary logging
+
+ if(!m_dll.Load(wxT("qtmlClient.dll")))
+ {
+ wxLog::EnableLogging(bWasLoggingEnabled);
+ return false;
+ }
+
+ 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;
+
+ return true;
+}
+
+class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackendCommonBase
+{
+public:
+ wxQTMediaBackend();
+ ~wxQTMediaBackend();
+
+ virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
+ wxWindowID id,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxValidator& validator,
+ const wxString& name);
+
+ virtual bool Play();
+ virtual bool Pause();
+ virtual bool Stop();
+
+ virtual bool Load(const wxURI& location,
+ const wxURI& proxy)
+ { return wxMediaBackend::Load(location, proxy); }
+
+ virtual bool Load(const wxString& fileName);
+ virtual bool Load(const wxURI& location);
+
+ virtual wxMediaState GetState();
+
+ virtual bool SetPosition(wxLongLong where);
+ virtual wxLongLong GetPosition();
+ virtual wxLongLong GetDuration();
+
+ virtual void Move(int x, int y, int w, int h);
+ wxSize GetVideoSize() const;
+
+ virtual double GetPlaybackRate();
+ virtual bool SetPlaybackRate(double dRate);
+
+ virtual double GetVolume();
+ virtual bool SetVolume(double);
+
+ 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
+ bool m_bVideo; //Whether or not we have video
+ 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)
+};
+
+// helper to hijack background erasing for the QT window
+class WXDLLIMPEXP_MEDIA wxQTMediaEvtHandler : public wxEvtHandler
+{
+public:
+ wxQTMediaEvtHandler(wxQTMediaBackend *qtb, WXHWND hwnd)
+ {
+ m_qtb = qtb;
+ m_hwnd = hwnd;
+ }
+
+ void OnEraseBackground(wxEraseEvent& event);
+
+private:
+ wxQTMediaBackend *m_qtb;
+ WXHWND m_hwnd;
+
+ DECLARE_NO_COPY_CLASS(wxQTMediaEvtHandler)
+};
+
+
+//===========================================================================
+// IMPLEMENTATION
+//===========================================================================
+
+// ----------------------------------------------------------------------------
+// wxMediaBackendCommonBase
+// ----------------------------------------------------------------------------
+
+void wxMediaBackendCommonBase::NotifyMovieSizeChanged()
+{
+ // our best size changed after opening a new file
+ m_ctrl->InvalidateBestSize();
+ m_ctrl->SetSize(m_ctrl->GetSize());
+
+ // if the parent of the control has a sizer ask it to refresh our size
+ wxWindow * const parent = m_ctrl->GetParent();
+ if ( parent->GetSizer() )
+ {
+ m_ctrl->GetParent()->Layout();
+ m_ctrl->GetParent()->Refresh();
+ m_ctrl->GetParent()->Update();
+ }
+}
+
+void wxMediaBackendCommonBase::NotifyMovieLoaded()
+{
+ NotifyMovieSizeChanged();
+
+ // notify about movie being fully loaded
+ QueueEvent(wxEVT_MEDIA_LOADED);
+}
+
+bool wxMediaBackendCommonBase::SendStopEvent()
+{
+ wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId());
+
+ return !m_ctrl->ProcessEvent(theEvent) || theEvent.IsAllowed();
+}
+
+void wxMediaBackendCommonBase::QueueEvent(wxEventType evtType)
+{
+ wxMediaEvent theEvent(evtType, m_ctrl->GetId());
+ m_ctrl->AddPendingEvent(theEvent);
+}
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// wxAMMediaBackend
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+IMPLEMENT_DYNAMIC_CLASS(wxAMMediaBackend, wxMediaBackend);
+
+//---------------------------------------------------------------------------
+// Usual debugging macros
+//---------------------------------------------------------------------------
+#ifdef __WXDEBUG__
+#define MAX_ERROR_TEXT_LEN 160
+
+//Get the error string for Active Movie
+wxString wxAMMediaBackend::GetErrorString(HRESULT hrdsv)
+{
+ wxChar szError[MAX_ERROR_TEXT_LEN];
+ if( m_lpAMGetErrorText != NULL &&
+ (*m_lpAMGetErrorText)(hrdsv, szError, MAX_ERROR_TEXT_LEN) == 0)
+ {
+ return wxString::Format(wxT("DirectShow error \"%s\" \n")
+ wxT("(numeric %X)\n")
+ wxT("occured"),
+ szError, (int)hrdsv);
+ }
+ else
+ {
+ 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
+
+//---------------------------------------------------------------------------
+// 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())
+ {
+ if ( m_parent->SendStopEvent() )
+ {
+ //Seek to beginning of movie
+ m_parent->wxAMMediaBackend::SetPosition(0);
+ Stop();
+
+ //send the event to our child
+ m_parent->QueueFinishEvent();
+ }
+ }
+ }
+
+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
+ {
+ if ( m_pBE->SendStopEvent() )
+ {
+ Stop();
+
+ m_pBE->QueueFinishEvent();
+ }
+ }
+ }
+ }
+
+protected:
+ wxAMMediaBackend* m_pBE; //Backend pointer
+ IMediaEvent* m_pME; //To determine when to send stop event
+};
+*/
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend Constructor
+//---------------------------------------------------------------------------
+wxAMMediaBackend::wxAMMediaBackend()
+ :m_pAX(NULL),
+ m_pAM(NULL),
+ m_pMP(NULL),
+ m_pTimer(NULL)
+{
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend Destructor
+//---------------------------------------------------------------------------
+wxAMMediaBackend::~wxAMMediaBackend()
+{
+ Clear(); //Free memory from Load()
+
+ if(m_pAX)
+ {
+ m_pAX->DissociateHandle();
+ delete m_pAX;
+ m_pAM->Release();
+
+ if(m_pMP)
+ m_pMP->Release();
+ }
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::Clear
+//
+// 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,
+ const wxPoint& pos,
+ const wxSize& size,
+ long style,
+ const wxValidator& validator,
+ const wxString& name)
+{
+ // First get the AMGetErrorText procedure in debug
+ // mode for more meaningful messages
+#ifdef __WXDEBUG__
+ if ( m_dllQuartz.Load(_T("quartz.dll"), wxDL_VERBATIM) )
+ {
+ m_lpAMGetErrorText = (LPAMGETERRORTEXT)
+ m_dllQuartz.GetSymbolAorW(wxT("AMGetErrorText"));
+ }
+#endif // __WXDEBUG__
+
+ // Now determine which (if any) media player interface is
+ // available - IMediaPlayer or IActiveMovie
+ if( ::CoCreateInstance(CLSID_MediaPlayer, NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IMediaPlayer, (void**)&m_pMP) != 0 )
+ {
+ if( ::CoCreateInstance(CLSID_ActiveMovie, NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IActiveMovie, (void**)&m_pAM) != 0 )
+ return false;
+ 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 -
+ // 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,
+ (style & ~wxBORDER_MASK) | wxBORDER_NONE,
+ validator, name) )
+ return false;
+
+ //
+ // Now create the ActiveX container along with the media player
+ // interface and query them
+ //
+ m_ctrl = ctrl;
+ m_pAX = new wxActiveX(ctrl,
+ m_pMP ? IID_IMediaPlayer : IID_IActiveMovie,
+ m_pAM);
+
+
+ //
+ // Here we set up wx-specific stuff for the default
+ // settings wxMediaCtrl says it will stay to
+ //
+ if(m_pMP)
+ {
+ m_pMP->put_DisplaySize(mpFitToSize);
+ // TODO: Unsure what actual effect this has
+ m_pMP->put_WindowlessVideo(VARIANT_TRUE);
+ }
+ else
+ 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);
+
+ // don't erase the background of our control window so that resizing is a
+ // bit smoother
+ m_ctrl->SetBackgroundStyle(wxBG_STYLE_CUSTOM);
+
+ // success
+ return true;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::Load (file version)
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::Load(const wxString& fileName)
+{
+ return DoLoad(fileName);
+}
+
+//---------------------------------------------------------------------------
+// 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());
+}
+
+//---------------------------------------------------------------------------
+// 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(pPlay)
+ {
+ pPlay->put_UseHTTPProxy(VARIANT_TRUE);
+ pPlay->put_HTTPProxyHost(wxBasicString(proxy.GetServer()).Get());
+ pPlay->put_HTTPProxyPort(wxAtoi(proxy.GetPort()));
+ pPlay->Release();
+ }
+
+ return DoLoad(location.BuildURI());
+}
+
+//---------------------------------------------------------------------------
+// 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
+
+ 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() );
+
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return false;
+ }
+
+ // 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);
+
+ //
+ //Start the play timer to catch stop events
+ //Previous load timer cleans up itself
+ //
+ m_pTimer = new wxAMPlayTimer(this);
+
+ NotifyMovieLoaded();
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::ShowPlayerControls
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::ShowPlayerControls(wxMediaCtrlPlayerControls flags)
+{
+ // 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_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);
+ }
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::Play
+//
+// Plays the stream. If it is non-seekable, it will restart it (implicit).
+//
+// Note that we use SUCCEEDED here because run/pause/stop tend to be overly
+// picky and return warnings on pretty much every call
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::Play()
+{
+ // 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();
+ }
+ }
+
+ //Actually try to play the movie
+ HRESULT hr = m_pAM->Run();
+ if(SUCCEEDED(hr))
+ {
+ m_pTimer->Start(20);
+ return true;
+ }
+ wxAMLOG(hr);
+ return false;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::Pause
+//
+// Pauses the stream.
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::Pause()
+{
+ HRESULT hr = m_pAM->Pause();
+ if(SUCCEEDED(hr))
+ return true;
+ wxAMLOG(hr);
+ return false;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::Stop
+//
+// Stops the stream.
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::Stop()
+{
+ HRESULT hr = m_pAM->Stop();
+ if(SUCCEEDED(hr))
+ {
+ //Seek to beginning
+ wxAMMediaBackend::SetPosition(0);
+ //Stop stop event timer
+ m_pTimer->Stop();
+ return true;
+ }
+ wxAMLOG(hr);
+ return false;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::SetPosition
+//
+// 1) Translates the current position's time to directshow time,
+// which is in a scale of 1 second (in a double)
+// 2) Sets the play position of the IMediaSeeking interface -
+// passing NULL as the stop position means to keep the old
+// stop position
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::SetPosition(wxLongLong where)
+{
+ HRESULT hr = m_pAM->put_CurrentPosition(
+ ((LONGLONG)where.GetValue()) / 1000.0
+ );
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return false;
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::GetPosition
+//
+// 1) Obtains the current play and stop positions from IMediaSeeking
+// 2) Returns the play position translated to our time base
+//---------------------------------------------------------------------------
+wxLongLong wxAMMediaBackend::GetPosition()
+{
+ double outCur;
+ HRESULT hr = m_pAM->get_CurrentPosition(&outCur);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return 0;
+ }
+
+ //h,m,s,milli - outdur is in 1 second (double)
+ outCur *= 1000;
+ wxLongLong ll;
+ ll.Assign(outCur);
+
+ return ll;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::GetVolume
+//
+// Gets the volume through the IBasicAudio interface -
+// value ranges from 0 (MAX volume) to -10000 (minimum volume).
+// -100 per decibel.
+//---------------------------------------------------------------------------
+double wxAMMediaBackend::GetVolume()
+{
+ long lVolume;
+ HRESULT hr = m_pAM->get_Volume(&lVolume);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return 0.0;
+ }
+ return pow(10.0, lVolume/2000.0);
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::SetVolume
+//
+// Sets the volume through the IBasicAudio interface -
+// value ranges from 0 (MAX volume) to -10000 (minimum volume).
+// -100 per decibel.
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::SetVolume(double dVolume)
+{
+ //pow(10.0, -80.0) to correct 0 == -INF
+ long lVolume = (long)(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;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::GetDuration
+//
+// 1) Obtains the duration of the media from IAMMultiMediaStream
+// 2) Converts that value to our time base, and returns it
+//
+// NB: With VBR MP3 files the default DirectShow MP3 render does not
+// read the Xing header correctly, resulting in skewed values for duration
+// and seeking
+//---------------------------------------------------------------------------
+wxLongLong wxAMMediaBackend::GetDuration()
+{
+ double outDuration;
+ HRESULT hr = m_pAM->get_Duration(&outDuration);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return 0;
+ }
+
+ //h,m,s,milli - outdur is in 1 second (double)
+ outDuration *= 1000;
+ wxLongLong ll;
+ ll.Assign(outDuration);
+
+ return ll;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::GetState
+//
+// Returns the cached state
+//---------------------------------------------------------------------------
+wxMediaState wxAMMediaBackend::GetState()
+{
+ StateConstants nState;
+ HRESULT hr = m_pAM->get_CurrentState(&nState);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return wxMEDIASTATE_STOPPED;
+ }
+
+ return (wxMediaState)nState;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::GetPlaybackRate
+//
+// Pretty simple way of obtaining the playback rate from
+// the IMediaSeeking interface
+//---------------------------------------------------------------------------
+double wxAMMediaBackend::GetPlaybackRate()
+{
+ double dRate;
+ HRESULT hr = m_pAM->get_Rate(&dRate);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return 0.0;
+ }
+ return dRate;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::SetPlaybackRate
+//
+// Sets the playback rate of the media - DirectShow is pretty good
+// about this, actually
+//---------------------------------------------------------------------------
+bool wxAMMediaBackend::SetPlaybackRate(double dRate)
+{
+ HRESULT hr = m_pAM->put_Rate(dRate);
+ if(FAILED(hr))
+ {
+ wxAMLOG(hr);
+ return false;
+ }
+
+ return true;
+}
+
+//---------------------------------------------------------------------------
+// wxAMMediaBackend::GetDownloadXXX
+//
+// 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
+//---------------------------------------------------------------------------
+void wxAMMediaBackend::DoGetDownloadProgress(wxLongLong* pLoadProgress,
+ wxLongLong* pLoadTotal)
+{
+ LONGLONG loadTotal = 0, loadProgress = 0;
+ IUnknown* pFG;
+ IAMOpenProgress* pOP;
+ HRESULT hr;
+ hr = m_pAM->get_FilterGraph(&pFG);
+ if(SUCCEEDED(hr))
+ {
+ hr = pFG->QueryInterface(IID_IAMOpenProgress, (void**)&pOP);
+ if(SUCCEEDED(hr))
+ {
+ hr = pOP->QueryProgress(&loadTotal, &loadProgress);
+ pOP->Release();
+ }
+ pFG->Release();
+ }
+
+ if(SUCCEEDED(hr))
+ {
+ *pLoadProgress = loadProgress;
+ *pLoadTotal = loadTotal;
+ }
+ else
+ {
+ //When not loading from a URL QueryProgress will return
+ //E_NOINTERFACE or whatever
+ //wxAMFAIL(hr);
+ *pLoadProgress = 0;
+ *pLoadTotal = 0;
+ }
+}
+
+//---------------------------------------------------------------------------
+// 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 WXUNUSED(w), int WXUNUSED(h))
+{
+}
+
+//---------------------------------------------------------------------------
+// End of wxAMMediaBackend
+//---------------------------------------------------------------------------
+
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+//
+// wxMCIMediaBackend
+//
+//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+IMPLEMENT_DYNAMIC_CLASS(wxMCIMediaBackend, wxMediaBackend);
+
+//---------------------------------------------------------------------------
+// Usual debugging macros for MCI returns
+//---------------------------------------------------------------------------
+
+#ifdef __WXDEBUG__
+#define wxMCIVERIFY(arg) \
+{ \
+ DWORD nRet; \
+ if ( (nRet = (arg)) != 0) \
+ { \
+ TCHAR sz[5000]; \
+ mciGetErrorString(nRet, sz, 5000); \
+ wxFAIL_MSG(wxString::Format(_T("MCI Error:%s"), sz)); \
+ } \
+}
+#else
+#define wxMCIVERIFY(arg) (arg);
+#endif
+
+//---------------------------------------------------------------------------
+// Simulation for <digitalv.h>
+//
+// Mingw and possibly other compilers don't have the digitalv.h header
+// that is needed to have some essential features of mci work with
+// windows - so we provide the declarations for the types we use here
+//---------------------------------------------------------------------------
+
+typedef struct {
+ DWORD_PTR dwCallback;
+#ifdef MCI_USE_OFFEXT
+ POINT ptOffset;
+ POINT ptExtent;
+#else
+ RECT rc;
+#endif
+} MCI_DGV_RECT_PARMS;
+
+typedef struct {
+ DWORD_PTR dwCallback;
+ HWND hWnd;
+#ifndef _WIN32
+ WORD wReserved1;
+#endif
+ UINT nCmdShow;
+#ifndef _WIN32
+ WORD wReserved2;
+#endif
+ wxChar* lpstrText;
+} MCI_DGV_WINDOW_PARMS;
+
+typedef struct {
+ DWORD_PTR dwCallback;
+ DWORD dwTimeFormat;
+ DWORD dwAudio;
+ DWORD dwFileFormat;
+ DWORD dwSpeed;
+} MCI_DGV_SET_PARMS;
+
+typedef struct {
+ DWORD_PTR dwCallback;
+ DWORD dwItem;
+ DWORD dwValue;
+ DWORD dwOver;
+ wxChar* lpstrAlgorithm;
+ wxChar* lpstrQuality;
+} MCI_DGV_SETAUDIO_PARMS;
+
+//---------------------------------------------------------------------------
+// wxMCIMediaBackend Constructor
+//
+// Here we don't need to do much except say we don't have any video :)
+//---------------------------------------------------------------------------
+wxMCIMediaBackend::wxMCIMediaBackend() : m_hNotifyWnd(NULL), m_bVideo(false)
+{
+}
+
+//---------------------------------------------------------------------------
+// wxMCIMediaBackend Destructor
+//
+// We close the mci device - note that there may not be an mci device here,
+// or it may fail - but we don't really care, since we're destructing
+//---------------------------------------------------------------------------
+wxMCIMediaBackend::~wxMCIMediaBackend()