+//
+//####################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;
+};
+
+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;
+};
+
+//---------------------------------------------------------------------------
+// AMMEDIA COM INTERFACES
+//---------------------------------------------------------------------------
+struct IMediaStream;
+struct IMultiMediaStream;
+struct IStreamSample : public IUnknown
+{
+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;
+};
+
+struct IDirectDrawStreamSample : public IStreamSample
+{
+public:
+ STDMETHOD(GetSurface)(IDirectDrawSurface **, RECT *) PURE;
+ STDMETHOD(SetRect)(const RECT *) PURE;
+};
+
+struct IMediaStream : public IUnknown
+{
+ 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;
+};
+
+struct IDirectDrawMediaStream : public IMediaStream
+{
+ 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;
+};
+
+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 IAMMultiMediaStream : public IMultiMediaStream
+{
+ 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;
+};