+#include "wx/dcclient.h"
+#include "wx/thread.h"
+
+//---------------------------------------------------------------------------
+// Externals (somewhere in src/msw/app.cpp)
+//---------------------------------------------------------------------------
+extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance(void);
+#ifdef __WXWINCE__
+extern WXDLLIMPEXP_CORE wxChar *wxCanvasClassName;
+#else
+extern WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName;
+#endif
+
+//===========================================================================
+// BACKEND DECLARATIONS
+//===========================================================================
+
+//---------------------------------------------------------------------------
+//
+// 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 compatability definitions
+//---------------------------------------------------------------------------
+#ifndef STDMETHODCALLTYPE
+#define STDMETHODCALLTYPE __stdcall
+#endif
+#ifndef STDMETHOD
+#define STDMETHOD(funcname) virtual HRESULT STDMETHODCALLTYPE funcname
+#endif
+#ifndef PURE
+#define PURE = 0
+#endif
+//---------------------------------------------------------------------------
+// IIDS - used by CoCreateInstance and IUnknown::QueryInterface
+// Dumped from amstream.idl, quartz.idl, direct draw and with some
+// confirmation from WINE
+//
+// Some of these are not used but are kept here for future reference anyway
+//---------------------------------------------------------------------------
+
+//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}};
+
+//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}};
+
+//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}};
+
+//?? 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 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_IBaseFilter = {0x56A86895, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
+
+//---------------------------------------------------------------------------
+// DIRECTDRAW COM INTERFACES
+//---------------------------------------------------------------------------
+//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 DDSURFACEDESC
+{
+ 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;
+};
+
+struct IDirectDrawClipper : public IUnknown
+{
+ 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;
+};
+
+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;
+};