1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/mediactrl.cpp
3 // Purpose: Built-in Media Backends for Windows
4 // Author: Ryan Norton <wxprojects@comcast.net>
8 // Copyright: (c) Ryan Norton
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 //===========================================================================
14 //===========================================================================
16 //---------------------------------------------------------------------------
17 // Pre-compiled header stuff
18 //---------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "mediactrl.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
31 //---------------------------------------------------------------------------
33 //---------------------------------------------------------------------------
34 #include "wx/mediactrl.h"
36 //---------------------------------------------------------------------------
38 //---------------------------------------------------------------------------
41 #include "wx/dcclient.h"
43 //---------------------------------------------------------------------------
44 // Externals (somewhere in src/msw/app.cpp)
45 //---------------------------------------------------------------------------
46 extern "C" WXDLLIMPEXP_BASE HINSTANCE
wxGetInstance(void);
48 extern WXDLLIMPEXP_CORE wxChar
*wxCanvasClassName
;
50 extern WXDLLIMPEXP_CORE
const wxChar
*wxCanvasClassName
;
53 //===========================================================================
54 // BACKEND DECLARATIONS
55 //===========================================================================
57 //---------------------------------------------------------------------------
61 //---------------------------------------------------------------------------
63 //####################THE BIG DIRECTSHOW OVERVIEW############################
66 // OK... this deserves its own little tutorial. Knowledge of COM and class
67 // factories is assumed throughout this code.
69 // Basically, the way directshow works is that you tell it to render
70 // a file, and it builds and connects a bunch of filters together.
72 // There are many, many ways to do this.
74 // WAYS TO RENDER A FILE (URLS WORK IN DS ALSO)
76 // 1) Create an instance of IGraphBuilder and call RenderFile on it
77 // 2) Create an instance of IMediaControl and call RenderFile on it
78 // 3) Create an instance of IAMMultiMediaStream, call
79 // IAMMultiMediaStream::AddStream and pass an IDirectDraw instance for
80 // the video, and pass an IDirectSound(Buffer?) instance or use the
81 // default sound renderer, then call RenderFile or RenderMoniker
82 // 4) Create a Moniker instance for the file and create and build
83 // all of the filtergraph manually
85 // Our issue here is that we can't use the default representation of 1 and 2
86 // because the IVideoWindow instance hogs a lot of the useful window
87 // messages such as WM_SETCURSOR.
89 // Solution #1 was to use #3 by creating a seperate IDirectDraw instance
90 // for our window and blitting to that through a thread... unfortunately
91 // the blitting resizing is very low quality and its quite slow.
93 // The current way is to use windowless rendering and have directshow
94 // do all the DirectDraw-style clipping to our window
96 // ~~~~~~~~~~~~~~AFTER RENDERING THE FILE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
98 // When done rendering the file, we need to get several interfaces from
99 // either a IMediaControl or IGraphBuilder instance -
101 // IMediaPosition - we can set the rate with this... we can also get
102 // positions and set positions through this with REFTIME (double) instead
103 // of the normal LONGLONG that IAMMultiMediaStream and IMediaControl use
105 // IBasicAudio - we need this for setting/getting the volume
107 // Interfaces that we don't use but might be useful one day -
109 // IDirectDrawVideo - you can get this through the IFilter returned
110 // from L"Video Renderer" filter from FindFilter on the IGraphBuilder.
111 // Through this we can set the IDirectDraw instance DrawShow uses.
113 // ~~~~~~~~~~~~~~STOPPING~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
115 // There are two ways we can do this -
116 // 1) Have a thread compare the current position to the end position
117 // about every 10 milliseconds
118 // 2) Have IMediaSeekingEx send a message to a windowproc or signal a
121 // Note that we can do these both, I.E. if an IMediaSeekingEx interface
122 // is unavailable we can check the position instead of an event
124 //---------------------------------------------------------------------------
126 //---------------------------------------------------------------------------
128 //---------------------------------------------------------------------------
129 #include "wx/msw/ole/oleutils.h" //wxBasicString, IID etc.
130 #include "wx/msw/ole/uuid.h" //IID etc..
132 //---------------------------------------------------------------------------
133 // COM compatability definitions
134 //---------------------------------------------------------------------------
135 #ifndef STDMETHODCALLTYPE
136 #define STDMETHODCALLTYPE __stdcall
139 #define STDMETHOD(funcname) virtual HRESULT STDMETHODCALLTYPE funcname
144 //---------------------------------------------------------------------------
145 // IIDS - used by CoCreateInstance and IUnknown::QueryInterface
146 // Dumped from amstream.idl, quartz.idl, direct draw and with some
147 // confirmation from WINE
149 // Some of these are not used but are kept here for future reference anyway
150 //---------------------------------------------------------------------------
153 const IID LIBID_QuartzTypeLib
= {0x56A868B0,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
154 const IID IID_IAMCollection
= {0x56A868B9,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
155 const IID IID_IMediaControl
= {0x56A868B1,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
156 const IID IID_IMediaEvent
= {0x56A868B6,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
157 const IID IID_IMediaEventEx
= {0x56A868C0,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
158 const IID IID_IMediaPosition
= {0x56A868B2,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
159 const IID IID_IBasicAudio
= {0x56A868B3,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
160 const IID IID_IVideoWindow
= {0x56A868B4,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
161 const IID IID_IBasicVideo
= {0x56A868B5,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
162 const IID IID_IBasicVideo2
= {0x329BB360,0xF6EA,0x11D1,{0x90,0x38,0x00,0xA0,0xC9,0x69,0x72,0x98}};
163 const IID IID_IDeferredCommand
= {0x56A868B8,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
164 const IID IID_IQueueCommand
= {0x56A868B7,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
165 const IID IID_IFilterInfo
= {0x56A868BA,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
166 const IID IID_IRegFilterInfo
= {0x56A868BB,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
167 const IID IID_IMediaTypeInfo
= {0x56A868BC,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
168 const IID IID_IPinInfo
= {0x56A868BD,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
169 const IID IID_IAMStats
= {0xBC9BCF80,0xDCD2,0x11D2,{0xAB,0xF6,0x00,0xA0,0xC9,0x05,0xF3,0x75}};
170 const CLSID CLSID_FilgraphManager
= {0xE436EBB3,0x524F,0x11CE,{0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
173 const CLSID CLSID_AMMultiMediaStream
= {0x49C47CE5, 0x9BA4, 0x11D0,{0x82, 0x12, 0x00, 0xC0, 0x4F, 0xC3, 0x2C, 0x45}};
174 const IID IID_IAMMultiMediaStream
= {0xBEBE595C, 0x9A6F, 0x11D0,{0x8F, 0xDE, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
175 const IID IID_IDirectDrawMediaStream
= {0xF4104FCE, 0x9A70, 0x11D0,{0x8F, 0xDE, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
176 const GUID MSPID_PrimaryVideo
= {0xa35FF56A, 0x9FDA, 0x11D0,{0x8F, 0xDF, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
177 const GUID MSPID_PrimaryAudio
= {0xa35FF56B, 0x9FDA, 0x11D0,{0x8F, 0xDF, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
180 const IID IID_IDirectDraw
= {0x6C14DB80,0xA733,0x11CE,{0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60}};
181 const CLSID CLSID_DirectDraw
= {0xD7B70EE0,0x4340,0x11CF,{0xB0,0x63,0x00,0x20,0xAF,0xC2,0xCD,0x35}};
184 const CLSID CLSID_VideoMixingRenderer
= {0xB87BEB7B, 0x8D29, 0x423F,{0xAE, 0x4D, 0x65, 0x82, 0xC1, 0x01, 0x75, 0xAC}};
185 const IID IID_IVMRWindowlessControl
= {0x0EB1088C, 0x4DCD, 0x46F0,{0x87, 0x8F, 0x39, 0xDA, 0xE8, 0x6A, 0x51, 0xB7}};
186 const IID IID_IFilterGraph
= {0x56A8689F, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
187 const IID IID_IGraphBuilder
= {0x56A868A9, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
188 const IID IID_IVMRFilterConfig
= {0x9E5530C5, 0x7034, 0x48B4,{0xBB, 0x46, 0x0B, 0x8A, 0x6E, 0xFC, 0x8E, 0x36}};
189 const IID IID_IBaseFilter
= {0x56A86895, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
191 //---------------------------------------------------------------------------
192 // DIRECTDRAW COM INTERFACES
193 //---------------------------------------------------------------------------
194 //DDSURFACESDESC - we don't need most of the stuff here, esp. DDPIXELFORMAT,
195 //so just put stubs in
196 struct DDPIXELFORMAT
{DWORD dw1
,dw2
,dw3
,dw4
,dw5
,dw6
,dw7
,dw8
;};
197 struct DDCOLORKEY
{DWORD dwLow
, dwHigh
;};
199 typedef struct IDirectDrawClipper
* LPDIRECTDRAWCLIPPER
;
200 typedef struct IDirectDraw
* LPDIRECTDRAW
;
201 typedef struct IDirectDrawSurface
* LPDIRECTDRAWSURFACE
;
202 typedef struct DDSURFACEDESC
* LPDDSURFACEDESC
;
203 typedef struct IDirectDrawPalette
* LPDIRECTDRAWPALETTE
;
204 typedef struct DDSCAPS
* LPDDSCAPS
;
205 typedef DDCOLORKEY
* LPDDCOLORKEY
;
206 typedef DDPIXELFORMAT
* LPDDPIXELFORMAT
;
207 typedef struct DDCAPS
* LPDDCAPS
;
220 DWORD dwBackBufferCount
;
224 DWORD dwZBufferBitDepth
;
227 DWORD dwAlphaBitDepth
;
230 DDCOLORKEY ddckCKDestOverlay
;
231 DDCOLORKEY ddckCKDestBlt
;
232 DDCOLORKEY ddckCKSrcOverlay
;
233 DDCOLORKEY ddckCKSrcBlt
;
234 DDPIXELFORMAT ddpfPixelFormat
;
235 struct DDSCAPS
{DWORD dwCaps
;} ddsCaps
;
238 struct IDirectDrawClipper
: public IUnknown
240 STDMETHOD(GetClipList
)(LPRECT
, LPRGNDATA
, LPDWORD
) PURE
;
241 STDMETHOD(GetHWnd
)(HWND
*) PURE
;
242 STDMETHOD(Initialize
)(LPDIRECTDRAW
, DWORD
) PURE
;
243 STDMETHOD(IsClipListChanged
)(BOOL
*) PURE
;
244 STDMETHOD(SetClipList
)(LPRGNDATA
,DWORD
) PURE
;
245 STDMETHOD(SetHWnd
)(DWORD
, HWND
) PURE
;
248 struct IDirectDrawSurface
: public IUnknown
250 STDMETHOD(AddAttachedSurface
)(LPDIRECTDRAWSURFACE
) PURE
;
251 STDMETHOD(AddOverlayDirtyRect
)(LPRECT
) PURE
;
252 STDMETHOD(Blt
)(LPRECT
,LPDIRECTDRAWSURFACE
, LPRECT
,DWORD
, struct DDBLTFX
*) PURE
;
253 STDMETHOD(BltBatch
)(struct DDBLTBATCH
*, DWORD
, DWORD
) PURE
;
254 STDMETHOD(BltFast
)(DWORD
,DWORD
,LPDIRECTDRAWSURFACE
, LPRECT
,DWORD
) PURE
;
255 STDMETHOD(DeleteAttachedSurface
)(DWORD
,LPDIRECTDRAWSURFACE
) PURE
;
256 STDMETHOD(EnumAttachedSurfaces
)(LPVOID
, LPVOID
/*LPDDENUMSURFACESCALLBACK*/) PURE
;
257 STDMETHOD(EnumOverlayZOrders
)(DWORD
,LPVOID
,LPVOID
/*LPDDENUMSURFACESCALLBACK*/) PURE
;
258 STDMETHOD(Flip
)(LPDIRECTDRAWSURFACE
, DWORD
) PURE
;
259 STDMETHOD(GetAttachedSurface
)(LPDDSCAPS
, LPDIRECTDRAWSURFACE
*) PURE
;
260 STDMETHOD(GetBltStatus
)(DWORD
) PURE
;
261 STDMETHOD(GetCaps
)(LPDDSCAPS
) PURE
;
262 STDMETHOD(GetClipper
)(LPDIRECTDRAWCLIPPER
*) PURE
;
263 STDMETHOD(GetColorKey
)(DWORD
, LPDDCOLORKEY
) PURE
;
264 STDMETHOD(GetDC
)(HDC
*) PURE
;
265 STDMETHOD(GetFlipStatus
)(DWORD
) PURE
;
266 STDMETHOD(GetOverlayPosition
)(LPLONG
, LPLONG
) PURE
;
267 STDMETHOD(GetPalette
)(LPDIRECTDRAWPALETTE FAR
*) PURE
;
268 STDMETHOD(GetPixelFormat
)(LPDDPIXELFORMAT
) PURE
;
269 STDMETHOD(GetSurfaceDesc
)(LPDDSURFACEDESC
) PURE
;
270 STDMETHOD(Initialize
)(LPDIRECTDRAW
, LPDDSURFACEDESC
) PURE
;
271 STDMETHOD(IsLost
)(THIS
) PURE
;
272 STDMETHOD(Lock
)(LPRECT
,LPDDSURFACEDESC
,DWORD
,HANDLE
) PURE
;
273 STDMETHOD(ReleaseDC
)(HDC
) PURE
;
274 STDMETHOD(Restore
)(THIS
) PURE
;
275 STDMETHOD(SetClipper
)(LPDIRECTDRAWCLIPPER
) PURE
;
276 STDMETHOD(SetColorKey
)(DWORD
, LPDDCOLORKEY
) PURE
;
277 STDMETHOD(SetOverlayPosition
)(LONG
, LONG
) PURE
;
278 STDMETHOD(SetPalette
)(IUnknown
*) PURE
;
279 STDMETHOD(Unlock
)(LPVOID
) PURE
;
280 STDMETHOD(UpdateOverlay
)(LPRECT
, LPDIRECTDRAWSURFACE
,LPRECT
,
281 DWORD
, struct DDOVERLAYFX
*) PURE
;
282 STDMETHOD(UpdateOverlayDisplay
)(DWORD
) PURE
;
283 STDMETHOD(UpdateOverlayZOrder
)(DWORD
, LPDIRECTDRAWSURFACE
) PURE
;
286 struct IDirectDraw
: public IUnknown
288 STDMETHOD(Compact
)() PURE
;
289 STDMETHOD(CreateClipper
)(DWORD
, LPDIRECTDRAWCLIPPER
*, IUnknown
* ) PURE
;
290 STDMETHOD(CreatePalette
)(DWORD
, LPPALETTEENTRY
, LPDIRECTDRAWPALETTE
*, IUnknown
* ) PURE
;
291 STDMETHOD(CreateSurface
)(LPDDSURFACEDESC
, LPDIRECTDRAWSURFACE
*, IUnknown
*) PURE
;
292 STDMETHOD(DuplicateSurface
)(LPDIRECTDRAWSURFACE
, LPDIRECTDRAWSURFACE
* ) PURE
;
293 STDMETHOD(EnumDisplayModes
)(DWORD
, LPDDSURFACEDESC
, LPVOID
, LPVOID
) PURE
;
294 STDMETHOD(EnumSurfaces
)(DWORD
, LPDDSURFACEDESC
, LPVOID
,LPVOID
) PURE
;
295 STDMETHOD(FlipToGDISurface
)() PURE
;
296 STDMETHOD(GetCaps
)(LPDDCAPS
, LPDDCAPS
) PURE
;
297 STDMETHOD(GetDisplayMode
)(LPDDSURFACEDESC
) PURE
;
298 STDMETHOD(GetFourCCCodes
)(LPDWORD
, LPDWORD
) PURE
;
299 STDMETHOD(GetGDISurface
)(LPDIRECTDRAWSURFACE
*) PURE
;
300 STDMETHOD(GetMonitorFrequency
)(LPDWORD
) PURE
;
301 STDMETHOD(GetScanLine
)(LPDWORD
) PURE
;
302 STDMETHOD(GetVerticalBlankStatus
)(LPBOOL
) PURE
;
303 STDMETHOD(Initialize
)(GUID
*) PURE
;
304 STDMETHOD(RestoreDisplayMode
)() PURE
;
305 STDMETHOD(SetCooperativeLevel
)(HWND
, DWORD
) PURE
;
306 STDMETHOD(SetDisplayMode
)(DWORD
, DWORD
,DWORD
, DWORD
, DWORD
) PURE
;
307 STDMETHOD(WaitForVerticalBlank
)(DWORD
, HANDLE
) PURE
;
310 //---------------------------------------------------------------------------
311 // AMMEDIA COM INTERFACES
312 //---------------------------------------------------------------------------
314 struct IMultiMediaStream
;
315 struct IStreamSample
: public IUnknown
318 STDMETHOD(GetMediaStream
)(IMediaStream
**) PURE
;
319 STDMETHOD(GetSampleTimes
)(LONGLONG
*, LONGLONG
*, LONGLONG
*) PURE
;
320 STDMETHOD(SetSampleTimes
)(const LONGLONG
*, const LONGLONG
*) PURE
;
321 STDMETHOD(Update
)(DWORD
, HANDLE
, LPVOID
, DWORD_PTR
) PURE
;
322 STDMETHOD(CompletionStatus
)(DWORD
, DWORD
) PURE
;
325 struct IDirectDrawStreamSample
: public IStreamSample
328 STDMETHOD(GetSurface
)(IDirectDrawSurface
**, RECT
*) PURE
;
329 STDMETHOD(SetRect
)(const RECT
*) PURE
;
332 struct IMediaStream
: public IUnknown
334 STDMETHOD(GetMultiMediaStream
)(IMultiMediaStream
**) PURE
;
335 STDMETHOD(GetInformation
)(GUID
*, int *) PURE
;
336 STDMETHOD(SetSameFormat
)(IMediaStream
*, DWORD
) PURE
;
337 STDMETHOD(AllocateSample
)(DWORD
, IStreamSample
**) PURE
;
338 STDMETHOD(CreateSharedSample
)(IStreamSample
*, DWORD
,
339 IStreamSample
**) PURE
;
340 STDMETHOD(SendEndOfStream
)(DWORD dwFlags
) PURE
;
343 struct IDirectDrawMediaStream
: public IMediaStream
345 STDMETHOD(GetFormat
)(DDSURFACEDESC
*, IDirectDrawPalette
**,
346 DDSURFACEDESC
*, DWORD
*) PURE
;
347 STDMETHOD(SetFormat
)(const DDSURFACEDESC
*, IDirectDrawPalette
*) PURE
;
348 STDMETHOD(GetDirectDraw
)(IDirectDraw
**) PURE
;
349 STDMETHOD(SetDirectDraw
)(IDirectDraw
*) PURE
;
350 STDMETHOD(CreateSample
)(IDirectDrawSurface
*, const RECT
*,
351 DWORD
, IDirectDrawStreamSample
**) PURE
;
352 STDMETHOD(GetTimePerFrame
)(LONGLONG
*) PURE
;
355 struct IMultiMediaStream
: public IUnknown
357 STDMETHOD(GetInformation
)(DWORD
*, int *) PURE
;
358 STDMETHOD(GetMediaStream
)(REFGUID
, IMediaStream
**) PURE
;
359 STDMETHOD(EnumMediaStreams
)(long, IMediaStream
**) PURE
;
360 STDMETHOD(GetState
)(int *pCurrentState
) PURE
;
361 STDMETHOD(SetState
)(int NewState
) PURE
;
362 STDMETHOD(GetTime
)(LONGLONG
*pCurrentTime
) PURE
;
363 STDMETHOD(GetDuration
)(LONGLONG
*pDuration
) PURE
;
364 STDMETHOD(Seek
)(LONGLONG SeekTime
) PURE
;
365 STDMETHOD(GetEndOfStreamEventHandle
)(HANDLE
*phEOS
) PURE
;
368 struct IAMMultiMediaStream
: public IMultiMediaStream
370 STDMETHOD(Initialize
)(int, DWORD
, IUnknown
*) PURE
;
371 STDMETHOD(GetFilterGraph
)(IUnknown
**) PURE
;
372 STDMETHOD(GetFilter
)(IUnknown
**) PURE
;
373 STDMETHOD(AddMediaStream
)(IUnknown
*, const GUID
*, DWORD
,
374 IMediaStream
**) PURE
;
375 STDMETHOD(OpenFile
)(LPCWSTR
, DWORD
) PURE
;
376 STDMETHOD(OpenMoniker
)(IBindCtx
*, IMoniker
*, DWORD
) PURE
;
377 STDMETHOD(Render
)(DWORD
) PURE
;
380 //---------------------------------------------------------------------------
381 // QUARTZ COM INTERFACES (dumped from quartz.idl from MSVC COM Browser)
382 //---------------------------------------------------------------------------
383 struct IAMCollection
: public IDispatch
385 STDMETHOD(get_Count
)(long *) PURE
;
386 STDMETHOD(Item
)(long, IUnknown
**) PURE
;
387 STDMETHOD(get__NewEnum
)(IUnknown
**) PURE
;
390 struct IMediaControl
: public IDispatch
392 STDMETHOD(Run
)() PURE
;
393 STDMETHOD(Pause
)() PURE
;
394 STDMETHOD(Stop
)() PURE
;
395 STDMETHOD(GetState
)(long, long*) PURE
;
396 STDMETHOD(RenderFile
)(BSTR
) PURE
;
397 STDMETHOD(AddSourceFilter
)(BSTR
, IDispatch
**) PURE
;
398 STDMETHOD(get_FilterCollection
)(IDispatch
**) PURE
;
399 STDMETHOD(get_RegFilterCollection
)(IDispatch
**) PURE
;
400 STDMETHOD(StopWhenReady
)() PURE
;
403 struct IMediaEvent
: public IDispatch
405 STDMETHOD(GetEventHandle
)(LONG_PTR
*) PURE
;
406 STDMETHOD(GetEvent
)(long *, LONG_PTR
*, LONG_PTR
*, long) PURE
;
407 STDMETHOD(WaitForCompletion
)(long, long *) PURE
;
408 STDMETHOD(CancelDefaultHandling
)(long) PURE
;
409 STDMETHOD(RestoreDefaultHandling
)(long) PURE
;
410 STDMETHOD(FreeEventParams
)(long, LONG_PTR
, LONG_PTR
) PURE
;
413 struct IMediaEventEx
: public IMediaEvent
415 STDMETHOD(SetNotifyWindow
)(LONG_PTR
, long, LONG_PTR
) PURE
;
416 STDMETHOD(SetNotifyFlags
)(long) PURE
;
417 STDMETHOD(GetNotifyFlags
)(long *) PURE
;
420 struct IMediaPosition
: public IDispatch
422 STDMETHOD(get_Duration
)(double *) PURE
;
423 STDMETHOD(put_CurrentPosition
)(double) PURE
;
424 STDMETHOD(get_CurrentPosition
)(double *) PURE
;
425 STDMETHOD(get_StopTime
)(double *) PURE
;
426 STDMETHOD(put_StopTime
)(double) PURE
;
427 STDMETHOD(get_PrerollTime
)(double *) PURE
;
428 STDMETHOD(put_PrerollTime
)(double) PURE
;
429 STDMETHOD(put_Rate
)(double) PURE
;
430 STDMETHOD(get_Rate
)(double *) PURE
;
431 STDMETHOD(CanSeekForward
)(long *) PURE
;
432 STDMETHOD(CanSeekBackward
)(long *) PURE
;
435 struct IBasicAudio
: public IDispatch
437 STDMETHOD(put_Volume
)(long) PURE
;
438 STDMETHOD(get_Volume
)(long *) PURE
;
439 STDMETHOD(put_Balance
)(long) PURE
;
440 STDMETHOD(get_Balance
)(long *) PURE
;
443 //---------------------------------------------------------------------------
444 // MISC COM INTERFACES
445 //---------------------------------------------------------------------------
446 struct IVMRWindowlessControl
: public IUnknown
448 STDMETHOD(GetNativeVideoSize
)(LONG
*, LONG
*, LONG
*, LONG
*) PURE
;
449 STDMETHOD(GetMinIdealVideoSize
)(LONG
*, LONG
*) PURE
;
450 STDMETHOD(GetMaxIdealVideoSize
)(LONG
*, LONG
*) PURE
;
451 STDMETHOD(SetVideoPosition
)(const LPRECT
,const LPRECT
) PURE
;
452 STDMETHOD(GetVideoPosition
)(LPRECT
, LPRECT
) PURE
;
453 STDMETHOD(GetAspectRatioMode
)(DWORD
*) PURE
;
454 STDMETHOD(SetAspectRatioMode
)(DWORD
) PURE
;
455 STDMETHOD(SetVideoClippingWindow
)(HWND
) PURE
;
456 STDMETHOD(RepaintVideo
)(HWND
, HDC
) PURE
;
457 STDMETHOD(DisplayModeChanged
)() PURE
;
458 STDMETHOD(GetCurrentImage
)(BYTE
**) PURE
;
459 STDMETHOD(SetBorderColor
)(COLORREF
) PURE
;
460 STDMETHOD(GetBorderColor
)(COLORREF
*) PURE
;
461 STDMETHOD(SetColorKey
)(COLORREF
) PURE
;
462 STDMETHOD(GetColorKey
)(COLORREF
*) PURE
;
465 typedef IUnknown IVMRImageCompositor
;
467 struct IVMRFilterConfig
: public IUnknown
469 STDMETHOD(SetImageCompositor
)(IVMRImageCompositor
*) PURE
;
470 STDMETHOD(SetNumberOfStreams
)(DWORD
) PURE
;
471 STDMETHOD(GetNumberOfStreams
)(DWORD
*) PURE
;
472 STDMETHOD(SetRenderingPrefs
)(DWORD
) PURE
;
473 STDMETHOD(GetRenderingPrefs
)(DWORD
*) PURE
;
474 STDMETHOD(SetRenderingMode
)(DWORD
) PURE
;
475 STDMETHOD(GetRenderingMode
)(DWORD
*) PURE
;
478 typedef IUnknown IBaseFilter
;
479 typedef IUnknown IPin
;
480 typedef IUnknown IEnumFilters
;
481 typedef int AM_MEDIA_TYPE
;
483 struct IFilterGraph
: public IUnknown
485 STDMETHOD(AddFilter
)(IBaseFilter
*, LPCWSTR
) PURE
;
486 STDMETHOD(RemoveFilter
)(IBaseFilter
*) PURE
;
487 STDMETHOD(EnumFilters
)(IEnumFilters
**) PURE
;
488 STDMETHOD(FindFilterByName
)(LPCWSTR
, IBaseFilter
**) PURE
;
489 STDMETHOD(ConnectDirect
)(IPin
*, IPin
*, const AM_MEDIA_TYPE
*) PURE
;
490 STDMETHOD(Reconnect
)(IPin
*) PURE
;
491 STDMETHOD(Disconnect
)(IPin
*) PURE
;
492 STDMETHOD(SetDefaultSyncSource
)() PURE
;
495 struct IGraphBuilder
: public IFilterGraph
498 STDMETHOD(Connect
)(IPin
*, IPin
*) PURE
;
499 STDMETHOD(Render
)(IPin
*) PURE
;
500 STDMETHOD(RenderFile
)(LPCWSTR
, LPCWSTR
) PURE
;
501 STDMETHOD(AddSourceFilter
)(LPCWSTR
, LPCWSTR
, IBaseFilter
**) PURE
;
502 STDMETHOD(SetLogFile
)(DWORD_PTR
) PURE
;
503 STDMETHOD(Abort
)() PURE
;
504 STDMETHOD(ShouldOperationContinue
)() PURE
;
507 //------------------------------------------------------------------
508 // wxAMMediaBackend (Active Movie)
509 //------------------------------------------------------------------
510 class WXDLLIMPEXP_MEDIA wxAMMediaThread
: public wxThread
513 virtual ExitCode
Entry();
515 class wxAMMediaBackend
* pThis
;
518 //cludgy workaround for wx events. slots would be nice :)
519 class WXDLLIMPEXP_MEDIA wxAMMediaEvtHandler
: public wxEvtHandler
522 void OnPaint(wxPaintEvent
&);
523 void OnEraseBackground(wxEraseEvent
&);
526 typedef BOOL (WINAPI
* LPAMGETERRORTEXT
)(HRESULT
, wxChar
*, DWORD
);
528 class WXDLLIMPEXP_MEDIA wxAMMediaBackend
: public wxMediaBackend
533 virtual ~wxAMMediaBackend();
535 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
540 const wxValidator
& validator
,
541 const wxString
& name
);
544 virtual bool Pause();
547 virtual bool Load(const wxString
& fileName
);
548 virtual bool Load(const wxURI
& location
);
550 virtual wxMediaState
GetState();
552 virtual bool SetPosition(wxLongLong where
);
553 virtual wxLongLong
GetPosition();
554 virtual wxLongLong
GetDuration();
556 virtual void Move(int x
, int y
, int w
, int h
);
557 wxSize
GetVideoSize() const;
559 virtual double GetPlaybackRate();
560 virtual bool SetPlaybackRate(double);
562 virtual double GetVolume();
563 virtual bool SetVolume(double);
567 bool SetWindowlessMode(IGraphBuilder
* pGB
,
568 IVMRWindowlessControl
** ppVMC
= NULL
);
572 wxMediaState m_state
;
573 wxCriticalSection m_rendercs
;
575 IVMRWindowlessControl
* m_pVMC
;
576 IGraphBuilder
* m_pGB
;
578 IMediaControl
* m_pMC
;
580 IMediaPosition
* m_pMS
;
583 wxAMMediaThread
* m_pThread
;
588 HMODULE m_hQuartzDll
;
589 LPAMGETERRORTEXT m_lpAMGetErrorText
;
590 wxString
GetErrorString(HRESULT hrdsv
);
593 friend class wxAMMediaThread
;
594 friend class wxAMMediaEvtHandler
;
596 DECLARE_DYNAMIC_CLASS(wxAMMediaBackend
)
599 //---------------------------------------------------------------------------
603 //---------------------------------------------------------------------------
605 //---------------------------------------------------------------------------
607 //---------------------------------------------------------------------------
608 #include <mmsystem.h>
610 class WXDLLIMPEXP_MEDIA wxMCIMediaBackend
: public wxMediaBackend
615 ~wxMCIMediaBackend();
617 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
622 const wxValidator
& validator
,
623 const wxString
& name
);
626 virtual bool Pause();
629 virtual bool Load(const wxString
& fileName
);
630 virtual bool Load(const wxURI
& location
);
632 virtual wxMediaState
GetState();
634 virtual bool SetPosition(wxLongLong where
);
635 virtual wxLongLong
GetPosition();
636 virtual wxLongLong
GetDuration();
638 virtual void Move(int x
, int y
, int w
, int h
);
639 wxSize
GetVideoSize() const;
641 virtual double GetPlaybackRate();
642 virtual bool SetPlaybackRate(double dRate
);
644 virtual double GetVolume();
645 virtual bool SetVolume(double);
647 static LRESULT CALLBACK
NotifyWndProc(HWND hWnd
, UINT nMsg
,
648 WPARAM wParam
, LPARAM lParam
);
650 LRESULT CALLBACK
OnNotifyWndProc(HWND hWnd
, UINT nMsg
,
651 WPARAM wParam
, LPARAM lParam
);
653 MCIDEVICEID m_hDev
; //Our MCI Device ID/Handler
654 wxControl
* m_ctrl
; //Parent control
655 HWND m_hNotifyWnd
; //Window to use for MCI events
656 bool m_bVideo
; //Whether or not we have video
658 DECLARE_DYNAMIC_CLASS(wxMCIMediaBackend
)
661 //---------------------------------------------------------------------------
665 //---------------------------------------------------------------------------
667 //---------------------------------------------------------------------------
669 //---------------------------------------------------------------------------
670 //#include <qtml.h> //Windoze QT include
671 //#include <QuickTimeComponents.h> //Standard QT stuff
672 #include "wx/dynlib.h"
674 //---------------------------------------------------------------------------
676 //---------------------------------------------------------------------------
677 typedef struct MovieRecord
* Movie
;
678 typedef wxInt16 OSErr
;
679 typedef wxInt32 OSStatus
;
682 typedef unsigned char Str255
[256];
683 #define StringPtr unsigned char*
684 #define newMovieActive 1
688 #define OSType unsigned long
689 #define CGrafPtr struct GrafPort *
690 #define TimeScale long
691 #define TimeBase struct TimeBaseRecord *
693 #ifndef URLDataHandlerSubType
694 #if defined(__WATCOMC__) || defined(__MINGW32__)
695 // use magic numbers for compilers which complain about multicharacter integers
696 const OSType URLDataHandlerSubType
= 1970433056;
697 const OSType VisualMediaCharacteristic
= 1702454643;
699 const OSType URLDataHandlerSubType
= 'url ';
700 const OSType VisualMediaCharacteristic
= 'eyes';
707 Str255 name
; /*Str63 on mac, Str255 on msw */
723 wide value
; /* units */
724 TimeScale scale
; /* units per second */
728 //---------------------------------------------------------------------------
730 //---------------------------------------------------------------------------
731 #define wxDL_METHOD_DEFINE( rettype, name, args, shortargs, defret ) \
732 typedef rettype (* name ## Type) args ; \
733 name ## Type pfn_ ## name; \
735 { if (m_ok) return pfn_ ## name shortargs ; return defret; }
737 #define wxDL_VOIDMETHOD_DEFINE( name, args, shortargs ) \
738 typedef void (* name ## Type) args ; \
739 name ## Type pfn_ ## name; \
741 { if (m_ok) pfn_ ## name shortargs ; }
743 #define wxDL_METHOD_LOAD( lib, name, success ) \
744 pfn_ ## name = (name ## Type) lib.GetSymbol( wxT(#name), &success ); \
745 if (!success) { wxLog::EnableLogging(true); return false; }
748 //Class that utilizes Robert Roeblings Dynamic Library Macros
749 class WXDLLIMPEXP_MEDIA wxQuickTimeLibrary
752 ~wxQuickTimeLibrary()
759 bool IsOk() const {return m_ok
;}
762 wxDynamicLibrary m_dll
;
766 wxDL_VOIDMETHOD_DEFINE( StartMovie
, (Movie m
), (m
) );
767 wxDL_VOIDMETHOD_DEFINE( StopMovie
, (Movie m
), (m
) );
768 wxDL_METHOD_DEFINE( bool, IsMovieDone
, (Movie m
), (m
), false);
769 wxDL_VOIDMETHOD_DEFINE( GoToBeginningOfMovie
, (Movie m
), (m
) );
770 wxDL_METHOD_DEFINE( OSErr
, GetMoviesError
, (), (), -1);
771 wxDL_METHOD_DEFINE( OSErr
, EnterMovies
, (), (), -1);
772 wxDL_VOIDMETHOD_DEFINE( ExitMovies
, (), () );
773 wxDL_METHOD_DEFINE( OSErr
, InitializeQTML
, (long flags
), (flags
), -1);
774 wxDL_VOIDMETHOD_DEFINE( TerminateQTML
, (), () );
776 wxDL_METHOD_DEFINE( OSErr
, NativePathNameToFSSpec
,
777 (char* inName
, FSSpec
* outFile
, long flags
),
778 (inName
, outFile
, flags
), -1);
780 wxDL_METHOD_DEFINE( OSErr
, OpenMovieFile
,
781 (const FSSpec
* fileSpec
, short * resRefNum
, wxInt8 permission
),
782 (fileSpec
, resRefNum
, permission
), -1 );
784 wxDL_METHOD_DEFINE( OSErr
, CloseMovieFile
,
785 (short resRefNum
), (resRefNum
), -1);
787 wxDL_METHOD_DEFINE( OSErr
, NewMovieFromFile
,
788 (Movie
* theMovie
, short resRefNum
, short * resId
,
789 StringPtr resName
, short newMovieFlags
,
790 bool * dataRefWasChanged
),
791 (theMovie
, resRefNum
, resId
, resName
, newMovieFlags
,
792 dataRefWasChanged
), -1);
794 wxDL_VOIDMETHOD_DEFINE( SetMovieRate
, (Movie m
, Fixed rate
), (m
, rate
) );
795 wxDL_METHOD_DEFINE( Fixed
, GetMovieRate
, (Movie m
), (m
), 0);
796 wxDL_VOIDMETHOD_DEFINE( MoviesTask
, (Movie m
, long maxms
), (m
, maxms
) );
797 wxDL_VOIDMETHOD_DEFINE( BlockMove
,
798 (const char* p1
, const char* p2
, long s
), (p1
,p2
,s
) );
799 wxDL_METHOD_DEFINE( Handle
, NewHandleClear
, (long s
), (s
), NULL
);
801 wxDL_METHOD_DEFINE( OSErr
, NewMovieFromDataRef
,
802 (Movie
* m
, short flags
, short * id
,
803 Handle dataRef
, OSType dataRefType
),
804 (m
,flags
,id
,dataRef
,dataRefType
), -1 );
806 wxDL_VOIDMETHOD_DEFINE( DisposeHandle
, (Handle h
), (h
) );
807 wxDL_VOIDMETHOD_DEFINE( GetMovieNaturalBoundsRect
, (Movie m
, Rect
* r
), (m
,r
) );
808 wxDL_METHOD_DEFINE( void*, GetMovieIndTrackType
,
809 (Movie m
, long index
, OSType type
, long flags
),
810 (m
,index
,type
,flags
), NULL
);
811 wxDL_VOIDMETHOD_DEFINE( CreatePortAssociation
,
812 (void* hWnd
, void* junk
, long morejunk
), (hWnd
, junk
, morejunk
) );
813 wxDL_METHOD_DEFINE(void*, GetNativeWindowPort
, (void* hWnd
), (hWnd
), NULL
);
814 wxDL_VOIDMETHOD_DEFINE(SetMovieGWorld
, (Movie m
, CGrafPtr port
, void* whatever
),
815 (m
, port
, whatever
) );
816 wxDL_VOIDMETHOD_DEFINE(DisposeMovie
, (Movie m
), (m
) );
817 wxDL_VOIDMETHOD_DEFINE(SetMovieBox
, (Movie m
, Rect
* r
), (m
,r
));
818 wxDL_VOIDMETHOD_DEFINE(SetMovieTimeScale
, (Movie m
, long s
), (m
,s
));
819 wxDL_METHOD_DEFINE(long, GetMovieDuration
, (Movie m
), (m
), 0);
820 wxDL_METHOD_DEFINE(TimeBase
, GetMovieTimeBase
, (Movie m
), (m
), 0);
821 wxDL_METHOD_DEFINE(TimeScale
, GetMovieTimeScale
, (Movie m
), (m
), 0);
822 wxDL_METHOD_DEFINE(long, GetMovieTime
, (Movie m
, void* cruft
), (m
,cruft
), 0);
823 wxDL_VOIDMETHOD_DEFINE(SetMovieTime
, (Movie m
, TimeRecord
* tr
), (m
,tr
) );
824 wxDL_METHOD_DEFINE(short, GetMovieVolume
, (Movie m
), (m
), 0);
825 wxDL_VOIDMETHOD_DEFINE(SetMovieVolume
, (Movie m
, short sVolume
), (m
,sVolume
) );
828 bool wxQuickTimeLibrary::Initialize()
832 wxLog::EnableLogging(false); //Turn off the wxDynamicLibrary logging
834 if(!m_dll
.Load(wxT("qtmlClient.dll")))
836 wxLog::EnableLogging(true);
840 bool bOk
; //TODO: Get rid of this, use m_ok instead (not a biggie)
842 wxDL_METHOD_LOAD( m_dll
, StartMovie
, bOk
);
843 wxDL_METHOD_LOAD( m_dll
, StopMovie
, bOk
);
844 wxDL_METHOD_LOAD( m_dll
, IsMovieDone
, bOk
);
845 wxDL_METHOD_LOAD( m_dll
, GoToBeginningOfMovie
, bOk
);
846 wxDL_METHOD_LOAD( m_dll
, GetMoviesError
, bOk
);
847 wxDL_METHOD_LOAD( m_dll
, EnterMovies
, bOk
);
848 wxDL_METHOD_LOAD( m_dll
, ExitMovies
, bOk
);
849 wxDL_METHOD_LOAD( m_dll
, InitializeQTML
, bOk
);
850 wxDL_METHOD_LOAD( m_dll
, TerminateQTML
, bOk
);
851 wxDL_METHOD_LOAD( m_dll
, NativePathNameToFSSpec
, bOk
);
852 wxDL_METHOD_LOAD( m_dll
, OpenMovieFile
, bOk
);
853 wxDL_METHOD_LOAD( m_dll
, CloseMovieFile
, bOk
);
854 wxDL_METHOD_LOAD( m_dll
, NewMovieFromFile
, bOk
);
855 wxDL_METHOD_LOAD( m_dll
, GetMovieRate
, bOk
);
856 wxDL_METHOD_LOAD( m_dll
, SetMovieRate
, bOk
);
857 wxDL_METHOD_LOAD( m_dll
, MoviesTask
, bOk
);
858 wxDL_METHOD_LOAD( m_dll
, BlockMove
, bOk
);
859 wxDL_METHOD_LOAD( m_dll
, NewHandleClear
, bOk
);
860 wxDL_METHOD_LOAD( m_dll
, NewMovieFromDataRef
, bOk
);
861 wxDL_METHOD_LOAD( m_dll
, DisposeHandle
, bOk
);
862 wxDL_METHOD_LOAD( m_dll
, GetMovieNaturalBoundsRect
, bOk
);
863 wxDL_METHOD_LOAD( m_dll
, GetMovieIndTrackType
, bOk
);
864 wxDL_METHOD_LOAD( m_dll
, CreatePortAssociation
, bOk
);
865 wxDL_METHOD_LOAD( m_dll
, GetNativeWindowPort
, bOk
);
866 wxDL_METHOD_LOAD( m_dll
, SetMovieGWorld
, bOk
);
867 wxDL_METHOD_LOAD( m_dll
, DisposeMovie
, bOk
);
868 wxDL_METHOD_LOAD( m_dll
, SetMovieBox
, bOk
);
869 wxDL_METHOD_LOAD( m_dll
, SetMovieTimeScale
, bOk
);
870 wxDL_METHOD_LOAD( m_dll
, GetMovieDuration
, bOk
);
871 wxDL_METHOD_LOAD( m_dll
, GetMovieTimeBase
, bOk
);
872 wxDL_METHOD_LOAD( m_dll
, GetMovieTimeScale
, bOk
);
873 wxDL_METHOD_LOAD( m_dll
, GetMovieTime
, bOk
);
874 wxDL_METHOD_LOAD( m_dll
, SetMovieTime
, bOk
);
875 wxDL_METHOD_LOAD( m_dll
, GetMovieVolume
, bOk
);
876 wxDL_METHOD_LOAD( m_dll
, SetMovieVolume
, bOk
);
878 wxLog::EnableLogging(true);
884 class WXDLLIMPEXP_MEDIA wxQTMediaBackend
: public wxMediaBackend
890 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
895 const wxValidator
& validator
,
896 const wxString
& name
);
899 virtual bool Pause();
902 virtual bool Load(const wxString
& fileName
);
903 virtual bool Load(const wxURI
& location
);
905 virtual wxMediaState
GetState();
907 virtual bool SetPosition(wxLongLong where
);
908 virtual wxLongLong
GetPosition();
909 virtual wxLongLong
GetDuration();
911 virtual void Move(int x
, int y
, int w
, int h
);
912 wxSize
GetVideoSize() const;
914 virtual double GetPlaybackRate();
915 virtual bool SetPlaybackRate(double dRate
);
917 virtual double GetVolume();
918 virtual bool SetVolume(double);
923 wxSize m_bestSize
; //Original movie size
924 Movie m_movie
; //QT Movie handle/instance
925 wxControl
* m_ctrl
; //Parent control
926 bool m_bVideo
; //Whether or not we have video
927 class _wxQTTimer
* m_timer
; //Timer for streaming the movie
928 wxQuickTimeLibrary m_lib
;
930 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
)
934 //===========================================================================
936 //===========================================================================
938 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
942 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
944 IMPLEMENT_DYNAMIC_CLASS(wxAMMediaBackend
, wxMediaBackend
);
946 //---------------------------------------------------------------------------
947 // Usual debugging macros
948 //---------------------------------------------------------------------------
950 #define MAX_ERROR_TEXT_LEN 160
951 #include "wx/log.h" //wxLogDebug et al.
953 //Get the error string for Active Movie
954 wxString
wxAMMediaBackend::GetErrorString(HRESULT hrdsv
)
956 wxChar szError
[MAX_ERROR_TEXT_LEN
];
957 if( m_lpAMGetErrorText
!= NULL
&&
958 (*m_lpAMGetErrorText
)(hrdsv
, szError
, MAX_ERROR_TEXT_LEN
) == 0)
960 return wxString::Format(wxT("DirectShow error \"%s\" \n")
961 wxT("(numeric %i)\n")
962 wxT("occured at line %i in ")
963 wxT("mediactrl.cpp"),
964 (int)hrdsv
, szError
, __LINE__
);
968 return wxString::Format(wxT("Unknown error (%i) ")
970 wxT(" line %i in mediactrl.cpp."),
971 (int)hrdsv
, __LINE__
);
975 #define wxAMFAIL(x) wxFAIL_MSG(GetErrorString(x));
976 #define wxVERIFY(x) wxASSERT((x))
977 #define wxAMLOG(x) wxLogDebug(GetErrorString(x))
979 #define wxAMVERIFY(x) (x)
980 #define wxVERIFY(x) (x)
985 //---------------------------------------------------------------------------
986 // Standard macros for ease of use
987 //---------------------------------------------------------------------------
988 #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
990 //---------------------------------------------------------------------------
991 // wxAMMediaBackend Constructor
993 // Sets m_hNotifyWnd to NULL to signify that we haven't loaded anything yet
994 //---------------------------------------------------------------------------
995 wxAMMediaBackend::wxAMMediaBackend()
996 :m_state(wxMEDIASTATE_STOPPED
)
1010 //---------------------------------------------------------------------------
1011 // wxAMMediaBackend Destructor
1013 // Cleans up everything
1014 //---------------------------------------------------------------------------
1015 wxAMMediaBackend::~wxAMMediaBackend()
1021 ::FreeLibrary(m_hQuartzDll
);
1025 //---------------------------------------------------------------------------
1026 // wxAMMediaBackend::CreateControl
1028 // 1) Check to see if Active Movie supports windowless controls
1029 // 2) Connect events to the media control and its TLW
1030 //---------------------------------------------------------------------------
1031 bool wxAMMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
1036 const wxValidator
& validator
,
1037 const wxString
& name
)
1040 m_hQuartzDll
= ::LoadLibrary(wxT("quartz.dll"));
1043 m_lpAMGetErrorText
= (LPAMGETERRORTEXT
) ::GetProcAddress(
1045 wxString::Format(wxT("AMGetErrorText%s"),
1047 #ifdef __WXUNICODE__
1055 ).mb_str(wxConvLocal
)
1061 //Make sure a valid windowless video mixing interface exists
1063 if( ::CoCreateInstance(CLSID_FilgraphManager
, NULL
,
1064 CLSCTX_INPROC_SERVER
,
1065 IID_IGraphBuilder
, (void**)&pGB
) != 0 )
1068 if( !SetWindowlessMode(pGB
) )
1076 // By default wxWindow(s) is created with a border -
1077 // so we need to get rid of those, and create with
1078 // wxCLIP_CHILDREN, so that if the driver/backend
1079 // is a child window, it refreshes properly
1081 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
1082 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
| wxCLIP_CHILDREN
,
1086 // My problem with this was only with a previous patch, probably the third rewrite
1087 // fixed it as a side-effect. In fact, the erase background style of drawing not
1088 // only works now, but is much better than paint-based updates (the paint event
1089 // handler flickers if the wxMediaCtrl shares a sizer with another child window,
1090 // or is on a notebook)
1092 ctrl
->Connect(ctrl
->GetId(), wxEVT_ERASE_BACKGROUND
,
1093 wxEraseEventHandler(wxAMMediaEvtHandler::OnEraseBackground
),
1094 NULL
, (wxEvtHandler
*) this);
1103 //---------------------------------------------------------------------------
1104 // wxAMMediaBackend::SetWindowlessMode
1106 // Adds a Video Mixing Renderer to a Filter Graph and obtains the
1107 // windowless control from it
1108 //---------------------------------------------------------------------------
1109 bool wxAMMediaBackend::SetWindowlessMode(IGraphBuilder
* pGB
,
1110 IVMRWindowlessControl
** ppVMC
)
1115 // Create and add a custom Video Mixing Render to the graph
1118 if( ::CoCreateInstance(CLSID_VideoMixingRenderer
, NULL
,
1119 CLSCTX_INPROC_SERVER
, IID_IBaseFilter
, (void**)&pVMR
) != 0 )
1122 hr
= pGB
->AddFilter(pVMR
, L
"Video Mixing Renderer");
1131 // Set the graph to windowless mode
1133 IVMRFilterConfig
* pConfig
;
1134 hr
= pVMR
->QueryInterface(IID_IVMRFilterConfig
, (void**)&pConfig
);
1142 hr
= pConfig
->SetRenderingMode(2);
1143 if( hr
!= 0) //2 == VMRMode_Windowless
1154 // Obtain the windowless control
1156 IVMRWindowlessControl
* pVMC
;
1157 hr
= pVMR
->QueryInterface(IID_IVMRWindowlessControl
, (void**)&pVMC
);
1177 //---------------------------------------------------------------------------
1178 // wxAMMediaBackend::Load (file version)
1180 // 1) Cleans up previously loaded data
1181 // 2) Creates a filter graph
1182 // 3) Add a video mixer, set the graph to windowless mode and clip
1183 // output to our media control
1184 // 4) Query interfaces to use later
1185 // 5) Get native video size (which becomes our best size)
1186 // 6) Refresh parent's sizers
1187 // 7) Start event/rendering thread
1188 //---------------------------------------------------------------------------
1189 bool wxAMMediaBackend::Load(const wxString
& fileName
)
1193 //if previously loaded cleanup
1197 //Create interfaces - we already checked for success in CreateControl
1198 ::CoCreateInstance(CLSID_FilgraphManager
, NULL
, CLSCTX_INPROC_SERVER
,
1199 IID_IGraphBuilder
, (void**)&m_pGB
);
1202 // Set and clip output
1203 SetWindowlessMode(m_pGB
, &m_pVMC
);
1204 hr
= m_pVMC
->SetVideoClippingWindow((HWND
)m_ctrl
->GetHandle());
1208 m_bestSize
.x
= m_bestSize
.y
= 0;
1213 //load the graph & render
1214 if( m_pGB
->RenderFile(fileName
.wc_str(wxConvLocal
), NULL
) != 0 )
1218 //Get the interfaces, all of them
1220 hr
= m_pGB
->QueryInterface(IID_IMediaEvent
, (void**)&m_pME
);
1227 hr
= m_pGB
->QueryInterface(IID_IMediaControl
, (void**)&m_pMC
);
1234 hr
= m_pGB
->QueryInterface(IID_IMediaPosition
, (void**)&m_pMS
);
1241 hr
= m_pGB
->QueryInterface(IID_IBasicAudio
, (void**)&m_pBA
);
1249 // Get original video size
1251 hr
= m_pVMC
->GetNativeVideoSize((LONG
*)&m_bestSize
.x
, (LONG
*)&m_bestSize
.y
,
1255 m_bestSize
.x
= m_bestSize
.y
= 0;
1260 if(m_bestSize
.x
== 0 && m_bestSize
.y
== 0)
1266 // Force the parent window of this control to recalculate
1267 // the size of this if sizers are being used
1268 // and render the results immediately
1270 m_ctrl
->InvalidateBestSize();
1271 m_ctrl
->GetParent()->Layout();
1272 m_ctrl
->GetParent()->Refresh();
1273 m_ctrl
->GetParent()->Update();
1274 m_ctrl
->SetSize(m_ctrl
->GetSize());
1277 // Create the event thread
1279 m_pThread
= new wxAMMediaThread
;
1280 m_pThread
->pThis
= this;
1281 m_pThread
->Create();
1290 //---------------------------------------------------------------------------
1291 // wxAMMediaBackend::Load (URL Version)
1293 // Loads media from a URL. Interestingly enough DirectShow
1294 // appears (?) to escape the URL for us, at least on normal
1296 //---------------------------------------------------------------------------
1297 bool wxAMMediaBackend::Load(const wxURI
& location
)
1299 return Load(location
.BuildUnescapedURI());
1302 //---------------------------------------------------------------------------
1303 // wxAMMediaBackend::Cleanup
1305 // Releases all the directshow interfaces we use
1306 // TODO: Maybe only create one instance of IAMMultiMediaStream and reuse it
1307 // rather than recreating it each time?
1308 //---------------------------------------------------------------------------
1309 void wxAMMediaBackend::Cleanup()
1311 // RN: This could be a bad ptr if load failed after
1312 // m_pVMC was created
1315 m_pThread
->Delete();
1319 // Release and zero DirectShow interfaces
1320 SAFE_RELEASE(m_pMC
);
1321 SAFE_RELEASE(m_pME
);
1322 SAFE_RELEASE(m_pMS
);
1323 SAFE_RELEASE(m_pBA
);
1324 SAFE_RELEASE(m_pGB
);
1325 SAFE_RELEASE(m_pVMC
);
1329 //---------------------------------------------------------------------------
1330 // wxAMMediaBackend::Play
1332 // Plays the stream. If it is non-seekable, it will restart it (implicit).
1334 // Note that we use SUCCEEDED here because run/pause/stop tend to be overly
1335 // picky and return warnings on pretty much every call
1336 //---------------------------------------------------------------------------
1337 bool wxAMMediaBackend::Play()
1339 wxCriticalSectionLocker
lock(m_rendercs
);
1341 if( SUCCEEDED(m_pMC
->Run()) )
1343 m_state
= wxMEDIASTATE_PLAYING
;
1344 m_ctrl
->Refresh(); //videoless control finicky about refreshing
1351 //---------------------------------------------------------------------------
1352 // wxAMMediaBackend::Pause
1354 // Pauses the stream.
1355 //---------------------------------------------------------------------------
1356 bool wxAMMediaBackend::Pause()
1358 wxCriticalSectionLocker
lock(m_rendercs
);
1360 if( SUCCEEDED(m_pMC
->Pause()) )
1362 m_state
= wxMEDIASTATE_PAUSED
;
1369 //---------------------------------------------------------------------------
1370 // wxAMMediaBackend::Stop
1372 // Stops the stream.
1373 //---------------------------------------------------------------------------
1374 bool wxAMMediaBackend::Stop()
1376 wxCriticalSectionLocker
lock(m_rendercs
);
1378 if( SUCCEEDED(m_pMC
->Stop()) )
1380 //We don't care if it can't get to the beginning in directshow -
1381 //it could be a non-seeking filter (wince midi) in which case playing
1382 //starts all over again
1383 wxAMMediaBackend::SetPosition(0);
1385 m_state
= wxMEDIASTATE_STOPPED
;
1392 //---------------------------------------------------------------------------
1393 // wxAMMediaBackend::SetPosition
1395 // 1) Translates the current position's time to directshow time,
1396 // which is in a scale of 1 second (in a double)
1397 // 2) Sets the play position of the IMediaSeeking interface -
1398 // passing NULL as the stop position means to keep the old
1400 //---------------------------------------------------------------------------
1401 bool wxAMMediaBackend::SetPosition(wxLongLong where
)
1403 HRESULT hr
= m_pMS
->put_CurrentPosition(
1404 ((LONGLONG
)where
.GetValue()) / 1000.0
1415 //---------------------------------------------------------------------------
1416 // wxAMMediaBackend::GetPosition
1418 // 1) Obtains the current play and stop positions from IMediaSeeking
1419 // 2) Returns the play position translated to our time base
1420 //---------------------------------------------------------------------------
1421 wxLongLong
wxAMMediaBackend::GetPosition()
1424 HRESULT hr
= m_pMS
->get_CurrentPosition(&outCur
);
1431 //h,m,s,milli - outdur is in 1 second (double)
1439 //---------------------------------------------------------------------------
1440 // wxAMMediaBackend::GetVolume
1442 // Gets the volume through the IBasicAudio interface -
1443 // value ranges from 0 (MAX volume) to -10000 (minimum volume).
1444 // -100 per decibel.
1445 //---------------------------------------------------------------------------
1446 double wxAMMediaBackend::GetVolume()
1451 HRESULT hr
= m_pBA
->get_Volume(&lVolume
);
1458 return (((double)(lVolume
+ 10000)) / 10000.0);
1461 wxLogDebug(wxT("No directshow audio interface"));
1465 //---------------------------------------------------------------------------
1466 // wxAMMediaBackend::SetVolume
1468 // Sets the volume through the IBasicAudio interface -
1469 // value ranges from 0 (MAX volume) to -10000 (minimum volume).
1470 // -100 per decibel.
1471 //---------------------------------------------------------------------------
1472 bool wxAMMediaBackend::SetVolume(double dVolume
)
1476 HRESULT hr
= m_pBA
->put_Volume( (long) ((dVolume
-1.0) * 10000.0) );
1485 wxLogDebug(wxT("No directshow audio interface"));
1489 //---------------------------------------------------------------------------
1490 // wxAMMediaBackend::GetDuration
1492 // 1) Obtains the duration of the media from IAMMultiMediaStream
1493 // 2) Converts that value to our time base, and returns it
1495 // NB: With VBR MP3 files the default DirectShow MP3 render does not
1496 // read the Xing header correctly, resulting in skewed values for duration
1498 //---------------------------------------------------------------------------
1499 wxLongLong
wxAMMediaBackend::GetDuration()
1502 HRESULT hr
= m_pMS
->get_Duration(&outDuration
);
1509 //h,m,s,milli - outdur is in 1 second (double)
1510 outDuration
*= 1000;
1512 ll
.Assign(outDuration
);
1517 //---------------------------------------------------------------------------
1518 // wxAMMediaBackend::GetState
1520 // Returns the cached state
1521 //---------------------------------------------------------------------------
1522 wxMediaState
wxAMMediaBackend::GetState()
1527 //---------------------------------------------------------------------------
1528 // wxAMMediaBackend::GetPlaybackRate
1530 // Pretty simple way of obtaining the playback rate from
1531 // the IMediaSeeking interface
1532 //---------------------------------------------------------------------------
1533 double wxAMMediaBackend::GetPlaybackRate()
1536 HRESULT hr
= m_pMS
->get_Rate(&dRate
);
1545 //---------------------------------------------------------------------------
1546 // wxAMMediaBackend::SetPlaybackRate
1548 // Sets the playback rate of the media - DirectShow is pretty good
1549 // about this, actually
1550 //---------------------------------------------------------------------------
1551 bool wxAMMediaBackend::SetPlaybackRate(double dRate
)
1553 HRESULT hr
= m_pMS
->put_Rate(dRate
);
1563 //---------------------------------------------------------------------------
1564 // wxAMMediaBackend::GetVideoSize
1566 // Obtains the cached original video size
1567 //---------------------------------------------------------------------------
1568 wxSize
wxAMMediaBackend::GetVideoSize() const
1573 //---------------------------------------------------------------------------
1574 // wxAMMediaBackend::Move
1576 // We take care of this in our redrawing
1577 //---------------------------------------------------------------------------
1578 void wxAMMediaBackend::Move(int WXUNUSED(x
), int WXUNUSED(y
),
1581 //don't use deferred positioning on windows
1582 if(m_pVMC
&& m_bVideo
)
1584 RECT srcRect
, destRect
;
1586 //portion of video to display in window
1587 srcRect
.top
= 0; srcRect
.left
= 0;
1588 srcRect
.bottom
= m_bestSize
.y
; srcRect
.right
= m_bestSize
.x
;
1600 //position in window client coordinates to display and stretch to
1601 destRect
.top
= 0; destRect
.left
= 0;
1602 destRect
.bottom
= h
; destRect
.right
= w
;
1604 //set the windowless control positions
1605 HRESULT hr
= m_pVMC
->SetVideoPosition(&srcRect
, &destRect
);
1613 //---------------------------------------------------------------------------
1614 // wxAMMediaThread::Entry
1616 // Render the current movie frame
1617 //---------------------------------------------------------------------------
1618 wxThread::ExitCode
wxAMMediaThread::Entry()
1620 while(!TestDestroy())
1627 // DirectShow keeps a list of queued events, and we need
1628 // to go through them one by one, stopping at (Hopefully only one)
1629 // EC_COMPLETE message
1631 while( pThis
->m_pME
->GetEvent(&evCode
, (LONG_PTR
*) &evParam1
,
1632 (LONG_PTR
*) &evParam2
, 0) == 0 )
1634 // Cleanup memory that GetEvent allocated
1635 HRESULT hr
= pThis
->m_pME
->FreeEventParams(evCode
,
1636 evParam1
, evParam2
);
1639 //Even though this makes a messagebox this
1640 //is windows where we can do gui stuff in seperate
1642 wxFAIL_MSG(pThis
->GetErrorString(hr
));
1644 // If this is the end of the clip, notify handler
1645 else if(1 == evCode
) //EC_COMPLETE
1658 //---------------------------------------------------------------------------
1659 // wxAMMediaBackend::OnStop
1661 // Handle stopping when the stream ends
1662 //---------------------------------------------------------------------------
1663 void wxAMMediaBackend::OnStop()
1665 //send the event to our child
1666 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
, m_ctrl
->GetId());
1667 m_ctrl
->ProcessEvent(theEvent
);
1669 //if the user didn't veto it, stop the stream
1670 if (theEvent
.IsAllowed())
1672 //Interestingly enough, DirectShow does not actually stop
1673 //the filters - even when it reaches the end!
1676 //send the event to our child
1677 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
1679 m_ctrl
->ProcessEvent(theEvent
);
1683 //---------------------------------------------------------------------------
1684 // wxAMMediaEvtHandler::OnEraseBackground
1686 // Tell WX not to erase the background of our control window
1687 //---------------------------------------------------------------------------
1688 void wxAMMediaEvtHandler::OnEraseBackground(wxEraseEvent
& evt
)
1690 wxAMMediaBackend
* pThis
= (wxAMMediaBackend
*) this;
1691 if(pThis
->m_pVMC
&& pThis
->m_bVideo
)
1693 //TODO: Use wxClientDC?
1694 HDC hdc
= ::GetDC((HWND
)pThis
->m_ctrl
->GetHandle());
1695 HRESULT hr
= pThis
->m_pVMC
->RepaintVideo((HWND
)pThis
->m_ctrl
->GetHandle(),
1699 wxFAIL_MSG(pThis
->GetErrorString(hr
));
1701 ::ReleaseDC((HWND
)pThis
->m_ctrl
->GetHandle(), hdc
);
1709 //---------------------------------------------------------------------------
1710 // End of wxAMMediaBackend
1711 //---------------------------------------------------------------------------
1713 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1715 // wxMCIMediaBackend
1717 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1719 IMPLEMENT_DYNAMIC_CLASS(wxMCIMediaBackend
, wxMediaBackend
);
1721 //---------------------------------------------------------------------------
1722 // Usual debugging macros for MCI returns
1723 //---------------------------------------------------------------------------
1726 #define wxMCIVERIFY(arg) \
1729 if ( (nRet = (arg)) != 0) \
1732 mciGetErrorString(nRet, sz, 5000); \
1733 wxFAIL_MSG(wxString::Format(_T("MCI Error:%s"), sz)); \
1737 #define wxMCIVERIFY(arg) (arg);
1740 //---------------------------------------------------------------------------
1741 // Simulation for <digitalv.h>
1743 // Mingw and possibly other compilers don't have the digitalv.h header
1744 // that is needed to have some essential features of mci work with
1745 // windows - so we provide the declarations for the types we use here
1746 //---------------------------------------------------------------------------
1749 DWORD_PTR dwCallback
;
1750 #ifdef MCI_USE_OFFEXT
1756 } MCI_DGV_RECT_PARMS
;
1759 DWORD_PTR dwCallback
;
1769 } MCI_DGV_WINDOW_PARMS
;
1772 DWORD_PTR dwCallback
;
1777 } MCI_DGV_SET_PARMS
;
1780 DWORD_PTR dwCallback
;
1784 wxChar
* lpstrAlgorithm
;
1785 wxChar
* lpstrQuality
;
1786 } MCI_DGV_SETAUDIO_PARMS
;
1788 //---------------------------------------------------------------------------
1789 // wxMCIMediaBackend Constructor
1791 // Here we don't need to do much except say we don't have any video :)
1792 //---------------------------------------------------------------------------
1793 wxMCIMediaBackend::wxMCIMediaBackend() : m_hNotifyWnd(NULL
), m_bVideo(false)
1797 //---------------------------------------------------------------------------
1798 // wxMCIMediaBackend Destructor
1800 // We close the mci device - note that there may not be an mci device here,
1801 // or it may fail - but we don't really care, since we're destructing
1802 //---------------------------------------------------------------------------
1803 wxMCIMediaBackend::~wxMCIMediaBackend()
1807 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
1808 DestroyWindow(m_hNotifyWnd
);
1809 m_hNotifyWnd
= NULL
;
1813 //---------------------------------------------------------------------------
1814 // wxMCIMediaBackend::Create
1816 // Here we just tell wxMediaCtrl that mci does exist (which it does, on all
1817 // msw systems, at least in some form dating back to win16 days)
1818 //---------------------------------------------------------------------------
1819 bool wxMCIMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
1824 const wxValidator
& validator
,
1825 const wxString
& name
)
1829 // By default wxWindow(s) is created with a border -
1830 // so we need to get rid of those, and create with
1831 // wxCLIP_CHILDREN, so that if the driver/backend
1832 // is a child window, it refereshes properly
1834 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
1835 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
| wxCLIP_CHILDREN
,
1843 //---------------------------------------------------------------------------
1844 // wxMCIMediaBackend::Load (file version)
1846 // Here we have MCI load a file and device, set the time format to our
1847 // default (milliseconds), and set the video (if any) to play in the control
1848 //---------------------------------------------------------------------------
1849 bool wxMCIMediaBackend::Load(const wxString
& fileName
)
1852 //if the user already called load close the previous MCI device
1856 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
1857 DestroyWindow(m_hNotifyWnd
);
1858 m_hNotifyWnd
= NULL
;
1862 //Opens a file and has MCI select a device. Normally you'd put
1863 //MCI_OPEN_TYPE in addition to MCI_OPEN_ELEMENT - however if you
1864 //omit this it tells MCI to select the device instead. This is
1865 //good because we have no reliable way of "enumerating" the devices
1868 MCI_OPEN_PARMS openParms
;
1869 openParms
.lpstrElementName
= (wxChar
*) fileName
.c_str();
1871 if ( mciSendCommand(0, MCI_OPEN
, MCI_OPEN_ELEMENT
,
1872 (DWORD
)(LPVOID
)&openParms
) != 0)
1875 m_hDev
= openParms
.wDeviceID
;
1878 //Now set the time format for the device to milliseconds
1880 MCI_SET_PARMS setParms
;
1881 setParms
.dwCallback
= 0;
1882 setParms
.dwTimeFormat
= MCI_FORMAT_MILLISECONDS
;
1884 if (mciSendCommand(m_hDev
, MCI_SET
, MCI_SET_TIME_FORMAT
,
1885 (DWORD
)(LPVOID
)&setParms
) != 0)
1889 //Now tell the MCI device to display the video in our wxMediaCtrl
1891 MCI_DGV_WINDOW_PARMS windowParms
;
1892 windowParms
.hWnd
= (HWND
)m_ctrl
->GetHandle();
1894 m_bVideo
= (mciSendCommand(m_hDev
, MCI_WINDOW
,
1895 0x00010000L
, //MCI_DGV_WINDOW_HWND
1896 (DWORD
)(LPVOID
)&windowParms
) == 0);
1899 // Create a hidden window and register to handle
1901 // Note that wxCanvasClassName is already registered
1902 // and used by all wxWindows and normal wxControls
1904 m_hNotifyWnd
= ::CreateWindow
1918 wxLogSysError( wxT("Could not create hidden needed for ")
1919 wxT("registering for DirectShow events!") );
1924 wxSetWindowProc(m_hNotifyWnd
, wxMCIMediaBackend::NotifyWndProc
);
1926 ::SetWindowLong(m_hNotifyWnd
, GWL_USERDATA
,
1930 //Here, if the parent of the control has a sizer - we
1931 //tell it to recalculate the size of this control since
1932 //the user opened a separate media file
1934 m_ctrl
->InvalidateBestSize();
1935 m_ctrl
->GetParent()->Layout();
1936 m_ctrl
->GetParent()->Refresh();
1937 m_ctrl
->GetParent()->Update();
1938 m_ctrl
->SetSize(m_ctrl
->GetSize());
1943 //---------------------------------------------------------------------------
1944 // wxMCIMediaBackend::Load (URL version)
1946 // MCI doesn't support URLs directly (?)
1948 // TODO: Use wxURL/wxFileSystem and mmioInstallProc
1949 //---------------------------------------------------------------------------
1950 bool wxMCIMediaBackend::Load(const wxURI
& WXUNUSED(location
))
1955 //---------------------------------------------------------------------------
1956 // wxMCIMediaBackend::Play
1958 // Plays/Resumes the MCI device... a couple notes:
1959 // 1) Certain drivers will crash and burn if we don't pass them an
1960 // MCI_PLAY_PARMS, despite the documentation that says otherwise...
1961 // 2) There is a MCI_RESUME command, but MCI_PLAY does the same thing
1962 // and will resume from a stopped state also, so there's no need to
1963 // call both, for example
1964 //---------------------------------------------------------------------------
1965 bool wxMCIMediaBackend::Play()
1967 MCI_PLAY_PARMS playParms
;
1968 playParms
.dwCallback
= (DWORD
)m_hNotifyWnd
;
1970 bool bOK
= ( mciSendCommand(m_hDev
, MCI_PLAY
, MCI_NOTIFY
,
1971 (DWORD
)(LPVOID
)&playParms
) == 0 );
1974 m_ctrl
->Show(m_bVideo
);
1979 //---------------------------------------------------------------------------
1980 // wxMCIMediaBackend::Pause
1982 // Pauses the MCI device - nothing special
1983 //---------------------------------------------------------------------------
1984 bool wxMCIMediaBackend::Pause()
1986 return (mciSendCommand(m_hDev
, MCI_PAUSE
, MCI_WAIT
, 0) == 0);
1989 //---------------------------------------------------------------------------
1990 // wxMCIMediaBackend::Stop
1992 // Stops the MCI device & seeks to the beginning as wxMediaCtrl docs outline
1993 //---------------------------------------------------------------------------
1994 bool wxMCIMediaBackend::Stop()
1996 return (mciSendCommand(m_hDev
, MCI_STOP
, MCI_WAIT
, 0) == 0) &&
1997 (mciSendCommand(m_hDev
, MCI_SEEK
, MCI_SEEK_TO_START
, 0) == 0);
2000 //---------------------------------------------------------------------------
2001 // wxMCIMediaBackend::GetState
2003 // Here we get the state and convert it to a wxMediaState -
2004 // since we use direct comparisons with MCI_MODE_PLAY and
2005 // MCI_MODE_PAUSE, we don't care if the MCI_STATUS call
2007 //---------------------------------------------------------------------------
2008 wxMediaState
wxMCIMediaBackend::GetState()
2010 MCI_STATUS_PARMS statusParms
;
2011 statusParms
.dwItem
= MCI_STATUS_MODE
;
2013 mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2014 (DWORD
)(LPVOID
)&statusParms
);
2016 if(statusParms
.dwReturn
== MCI_MODE_PAUSE
)
2017 return wxMEDIASTATE_PAUSED
;
2018 else if(statusParms
.dwReturn
== MCI_MODE_PLAY
)
2019 return wxMEDIASTATE_PLAYING
;
2021 return wxMEDIASTATE_STOPPED
;
2024 //---------------------------------------------------------------------------
2025 // wxMCIMediaBackend::SetPosition
2027 // Here we set the position of the device in the stream.
2028 // Note that MCI actually stops the device after you seek it if the
2029 // device is playing/paused, so we need to play the file after
2030 // MCI seeks like normal APIs would
2031 //---------------------------------------------------------------------------
2032 bool wxMCIMediaBackend::SetPosition(wxLongLong where
)
2034 MCI_SEEK_PARMS seekParms
;
2035 seekParms
.dwCallback
= 0;
2036 #if wxUSE_LONGLONG_NATIVE && !wxUSE_LONGLONG_WX
2037 seekParms
.dwTo
= (DWORD
)where
.GetValue();
2038 #else /* wxUSE_LONGLONG_WX */
2039 /* no way to return it in one piece */
2040 wxASSERT( where
.GetHi()==0 );
2041 seekParms
.dwTo
= (DWORD
)where
.GetLo();
2042 #endif /* wxUSE_LONGLONG_* */
2044 //device was playing?
2045 bool bReplay
= GetState() == wxMEDIASTATE_PLAYING
;
2047 if( mciSendCommand(m_hDev
, MCI_SEEK
, MCI_TO
,
2048 (DWORD
)(LPVOID
)&seekParms
) != 0)
2051 //If the device was playing, resume it
2058 //---------------------------------------------------------------------------
2059 // wxMCIMediaBackend::GetPosition
2061 // Gets the position of the device in the stream using the current
2062 // time format... nothing special here...
2063 //---------------------------------------------------------------------------
2064 wxLongLong
wxMCIMediaBackend::GetPosition()
2066 MCI_STATUS_PARMS statusParms
;
2067 statusParms
.dwItem
= MCI_STATUS_POSITION
;
2069 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2070 (DWORD
)(LPSTR
)&statusParms
) != 0)
2073 return statusParms
.dwReturn
;
2076 //---------------------------------------------------------------------------
2077 // wxMCIMediaBackend::GetVolume
2079 // Gets the volume of the current media via the MCI_DGV_STATUS_VOLUME
2080 // message. Value ranges from 0 (minimum) to 1000 (maximum volume).
2081 //---------------------------------------------------------------------------
2082 double wxMCIMediaBackend::GetVolume()
2084 MCI_STATUS_PARMS statusParms
;
2085 statusParms
.dwCallback
= 0;
2086 statusParms
.dwItem
= 0x4019; //MCI_DGV_STATUS_VOLUME
2088 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2089 (DWORD
)(LPSTR
)&statusParms
) != 0)
2092 return ((double)statusParms
.dwReturn
) / 1000.0;
2095 //---------------------------------------------------------------------------
2096 // wxMCIMediaBackend::SetVolume
2098 // Sets the volume of the current media via the MCI_DGV_SETAUDIO_VOLUME
2099 // message. Value ranges from 0 (minimum) to 1000 (maximum volume).
2100 //---------------------------------------------------------------------------
2101 bool wxMCIMediaBackend::SetVolume(double dVolume
)
2103 MCI_DGV_SETAUDIO_PARMS audioParms
;
2104 audioParms
.dwCallback
= 0;
2105 audioParms
.dwItem
= 0x4002; //MCI_DGV_SETAUDIO_VOLUME
2106 audioParms
.dwValue
= (DWORD
) (dVolume
* 1000.0);
2107 audioParms
.dwOver
= 0;
2108 audioParms
.lpstrAlgorithm
= NULL
;
2109 audioParms
.lpstrQuality
= NULL
;
2111 if (mciSendCommand(m_hDev
, 0x0873, //MCI_SETAUDIO
2112 0x00800000L
| 0x01000000L
, //MCI_DGV_SETAUDIO+(_ITEM | _VALUE)
2113 (DWORD
)(LPSTR
)&audioParms
) != 0)
2118 //---------------------------------------------------------------------------
2119 // wxMCIMediaBackend::GetDuration
2121 // Gets the duration of the stream... nothing special
2122 //---------------------------------------------------------------------------
2123 wxLongLong
wxMCIMediaBackend::GetDuration()
2125 MCI_STATUS_PARMS statusParms
;
2126 statusParms
.dwItem
= MCI_STATUS_LENGTH
;
2128 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2129 (DWORD
)(LPSTR
)&statusParms
) != 0)
2132 return statusParms
.dwReturn
;
2135 //---------------------------------------------------------------------------
2136 // wxMCIMediaBackend::Move
2138 // Moves the window to a location
2139 //---------------------------------------------------------------------------
2140 void wxMCIMediaBackend::Move(int WXUNUSED(x
), int WXUNUSED(y
),
2143 if (m_hNotifyWnd
&& m_bVideo
)
2145 MCI_DGV_RECT_PARMS putParms
; //ifdefed MCI_DGV_PUT_PARMS
2146 memset(&putParms
, 0, sizeof(MCI_DGV_RECT_PARMS
));
2147 putParms
.rc
.bottom
= h
;
2148 putParms
.rc
.right
= w
;
2150 //wxStackWalker will crash and burn here on assert
2151 //and mci doesn't like 0 and 0 for some reason (out of range )
2152 //so just don't it in that case
2155 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_PUT
,
2156 0x00040000L
, //MCI_DGV_PUT_DESTINATION
2157 (DWORD
)(LPSTR
)&putParms
) );
2162 //---------------------------------------------------------------------------
2163 // wxMCIMediaBackend::GetVideoSize
2165 // Gets the original size of the movie for sizers
2166 //---------------------------------------------------------------------------
2167 wxSize
wxMCIMediaBackend::GetVideoSize() const
2171 MCI_DGV_RECT_PARMS whereParms
; //ifdefed MCI_DGV_WHERE_PARMS
2173 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_WHERE
,
2174 0x00020000L
, //MCI_DGV_WHERE_SOURCE
2175 (DWORD
)(LPSTR
)&whereParms
) );
2177 return wxSize(whereParms
.rc
.right
, whereParms
.rc
.bottom
);
2182 //---------------------------------------------------------------------------
2183 // wxMCIMediaBackend::GetPlaybackRate
2186 //---------------------------------------------------------------------------
2187 double wxMCIMediaBackend::GetPlaybackRate()
2192 //---------------------------------------------------------------------------
2193 // wxMCIMediaBackend::SetPlaybackRate
2196 //---------------------------------------------------------------------------
2197 bool wxMCIMediaBackend::SetPlaybackRate(double WXUNUSED(dRate
))
2200 MCI_WAVE_SET_SAMPLESPERSEC
2201 MCI_DGV_SET_PARMS setParms;
2202 setParms.dwSpeed = (DWORD) (dRate * 1000.0);
2204 return (mciSendCommand(m_hDev, MCI_SET,
2205 0x00020000L, //MCI_DGV_SET_SPEED
2206 (DWORD)(LPSTR)&setParms) == 0);
2211 //---------------------------------------------------------------------------
2212 // [static] wxMCIMediaBackend::MSWWindowProc
2214 // Here we process a message when MCI reaches the stopping point
2216 //---------------------------------------------------------------------------
2217 LRESULT CALLBACK
wxMCIMediaBackend::NotifyWndProc(HWND hWnd
, UINT nMsg
,
2221 wxMCIMediaBackend
* backend
= (wxMCIMediaBackend
*)
2223 ::GetWindowLong(hWnd
, GWL_USERDATA
);
2225 ::GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
2229 return backend
->OnNotifyWndProc(hWnd
, nMsg
, wParam
, lParam
);
2232 LRESULT CALLBACK
wxMCIMediaBackend::OnNotifyWndProc(HWND hWnd
, UINT nMsg
,
2236 if(nMsg
== MM_MCINOTIFY
)
2238 wxASSERT(lParam
== (LPARAM
) m_hDev
);
2239 if(wParam
== MCI_NOTIFY_SUCCESSFUL
&& lParam
== (LPARAM
)m_hDev
)
2241 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
, m_ctrl
->GetId());
2242 m_ctrl
->ProcessEvent(theEvent
);
2244 if(theEvent
.IsAllowed())
2246 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_SEEK
,
2247 MCI_SEEK_TO_START
, 0) );
2249 //send the event to our child
2250 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
2252 m_ctrl
->ProcessEvent(theEvent
);
2256 return DefWindowProc(hWnd
, nMsg
, wParam
, lParam
);
2258 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2262 // TODO: Use a less cludgy way to pause/get state/set state
2263 // TODO: Dynamically load from qtml.dll
2264 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2266 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
);
2268 //Time between timer calls
2269 #define MOVIE_DELAY 100
2271 #include "wx/timer.h"
2273 // --------------------------------------------------------------------------
2274 // wxQTTimer - Handle Asyncronous Playing
2275 // --------------------------------------------------------------------------
2276 class _wxQTTimer
: public wxTimer
2279 _wxQTTimer(Movie movie
, wxQTMediaBackend
* parent
, wxQuickTimeLibrary
* pLib
) :
2280 m_movie(movie
), m_bPaused(false), m_parent(parent
), m_pLib(pLib
)
2288 bool GetPaused() {return m_bPaused
;}
2289 void SetPaused(bool bPaused
) {m_bPaused
= bPaused
;}
2291 //-----------------------------------------------------------------------
2292 // _wxQTTimer::Notify
2294 // 1) Checks to see if the movie is done, and if not continues
2295 // streaming the movie
2296 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
2298 //-----------------------------------------------------------------------
2303 if(!m_pLib
->IsMovieDone(m_movie
))
2304 m_pLib
->MoviesTask(m_movie
, MOVIE_DELAY
);
2307 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
,
2308 m_parent
->m_ctrl
->GetId());
2309 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
2311 if(theEvent
.IsAllowed())
2315 wxASSERT(m_pLib
->GetMoviesError() == noErr
);
2317 //send the event to our child
2318 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
2319 m_parent
->m_ctrl
->GetId());
2320 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
2327 Movie m_movie
; //Our movie instance
2328 bool m_bPaused
; //Whether we are paused or not
2329 wxQTMediaBackend
* m_parent
; //Backend pointer
2330 wxQuickTimeLibrary
* m_pLib
; //Interfaces
2333 //---------------------------------------------------------------------------
2334 // wxQTMediaBackend Destructor
2336 // Sets m_timer to NULL signifying we havn't loaded anything yet
2337 //---------------------------------------------------------------------------
2338 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL
)
2342 //---------------------------------------------------------------------------
2343 // wxQTMediaBackend Destructor
2345 // 1) Cleans up the QuickTime movie instance
2346 // 2) Decrements the QuickTime reference counter - if this reaches
2347 // 0, QuickTime shuts down
2348 // 3) Decrements the QuickTime Windows Media Layer reference counter -
2349 // if this reaches 0, QuickTime shuts down the Windows Media Layer
2350 //---------------------------------------------------------------------------
2351 wxQTMediaBackend::~wxQTMediaBackend()
2358 //Note that ExitMovies() is not necessary, but
2359 //the docs are fuzzy on whether or not TerminateQTML is
2361 m_lib
.TerminateQTML();
2365 //---------------------------------------------------------------------------
2366 // wxQTMediaBackend::CreateControl
2368 // 1) Intializes QuickTime
2369 // 2) Creates the control window
2370 //---------------------------------------------------------------------------
2371 bool wxQTMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
2376 const wxValidator
& validator
,
2377 const wxString
& name
)
2379 if(!m_lib
.Initialize())
2382 int nError
= m_lib
.InitializeQTML(0);
2383 if (nError
!= noErr
) //-2093 no dll
2385 wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError
));
2388 m_lib
.EnterMovies();
2392 // By default wxWindow(s) is created with a border -
2393 // so we need to get rid of those
2395 // Since we don't have a child window like most other
2396 // backends, we don't need wxCLIP_CHILDREN
2398 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
2399 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
,
2407 //---------------------------------------------------------------------------
2408 // wxQTMediaBackend::Load (file version)
2410 // 1) Get an FSSpec from the Windows path name
2411 // 2) Open the movie
2412 // 3) Obtain the movie instance from the movie resource
2414 //---------------------------------------------------------------------------
2415 bool wxQTMediaBackend::Load(const wxString
& fileName
)
2420 short movieResFile
= 0; //= 0 because of annoying VC6 warning
2423 if (m_lib
.NativePathNameToFSSpec ((char*) (const char*) fileName
.mb_str(),
2424 &sfFile
, 0) != noErr
)
2427 if (m_lib
.OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
2430 short movieResID
= 0;
2433 OSErr err
= m_lib
.NewMovieFromFile (
2442 m_lib
.CloseMovieFile (movieResFile
);
2449 return m_lib
.GetMoviesError() == noErr
;
2452 //---------------------------------------------------------------------------
2453 // wxQTMediaBackend::Move
2456 //---------------------------------------------------------------------------
2457 bool wxQTMediaBackend::Load(const wxURI
& location
)
2462 wxString theURI
= location
.BuildURI();
2464 Handle theHandle
= m_lib
.NewHandleClear(theURI
.length() + 1);
2465 wxASSERT(theHandle
);
2467 m_lib
.BlockMove(theURI
.mb_str(), *theHandle
, theURI
.length() + 1);
2469 //create the movie from the handle that refers to the URI
2470 OSErr err
= m_lib
.NewMovieFromDataRef(&m_movie
, newMovieActive
,
2472 URLDataHandlerSubType
);
2474 m_lib
.DisposeHandle(theHandle
);
2479 //preroll movie for streaming
2484 timeNow = GetMovieTime(m_movie, NULL);
2485 playRate = GetMoviePreferredRate(m_movie);
2486 PrePrerollMovie(m_movie, timeNow, playRate, NULL, NULL);
2487 PrerollMovie(m_movie, timeNow, playRate);
2488 m_lib.SetMovieRate(m_movie, playRate);
2493 return m_lib
.GetMoviesError() == noErr
;
2496 //---------------------------------------------------------------------------
2497 // wxQTMediaBackend::Move
2500 //---------------------------------------------------------------------------
2501 void wxQTMediaBackend::FinishLoad()
2503 m_timer
= new _wxQTTimer(m_movie
, (wxQTMediaBackend
*) this, &m_lib
);
2506 //get the real size of the movie
2508 memset(&outRect
, 0, sizeof(Rect
)); //for annoying VC6 warning
2509 m_lib
.GetMovieNaturalBoundsRect (m_movie
, &outRect
);
2510 wxASSERT(m_lib
.GetMoviesError() == noErr
);
2512 m_bestSize
.x
= outRect
.right
- outRect
.left
;
2513 m_bestSize
.y
= outRect
.bottom
- outRect
.top
;
2515 //reparent movie/*AudioMediaCharacteristic*/
2516 if(m_lib
.GetMovieIndTrackType(m_movie
, 1,
2517 VisualMediaCharacteristic
,
2518 (1 << 1) //movieTrackCharacteristic
2519 | (1 << 2) //movieTrackEnabledOnly
2522 m_lib
.CreatePortAssociation(m_ctrl
->GetHWND(), NULL
, 0L);
2524 m_lib
.SetMovieGWorld(m_movie
,
2525 (CGrafPtr
) m_lib
.GetNativeWindowPort(m_ctrl
->GetHWND()),
2529 //we want millisecond precision
2530 m_lib
.SetMovieTimeScale(m_movie
, 1000);
2531 wxASSERT(m_lib
.GetMoviesError() == noErr
);
2534 //Here, if the parent of the control has a sizer - we
2535 //tell it to recalculate the size of this control since
2536 //the user opened a separate media file
2538 m_ctrl
->InvalidateBestSize();
2539 m_ctrl
->GetParent()->Layout();
2540 m_ctrl
->GetParent()->Refresh();
2541 m_ctrl
->GetParent()->Update();
2544 //---------------------------------------------------------------------------
2545 // wxQTMediaBackend::Move
2548 //---------------------------------------------------------------------------
2549 bool wxQTMediaBackend::Play()
2551 m_lib
.StartMovie(m_movie
);
2552 m_timer
->SetPaused(false);
2553 m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
2554 return m_lib
.GetMoviesError() == noErr
;
2557 //---------------------------------------------------------------------------
2558 // wxQTMediaBackend::Move
2561 //---------------------------------------------------------------------------
2562 bool wxQTMediaBackend::Pause()
2564 m_lib
.StopMovie(m_movie
);
2565 m_timer
->SetPaused(true);
2567 return m_lib
.GetMoviesError() == noErr
;
2570 //---------------------------------------------------------------------------
2571 // wxQTMediaBackend::Move
2574 //---------------------------------------------------------------------------
2575 bool wxQTMediaBackend::Stop()
2577 m_timer
->SetPaused(false);
2580 m_lib
.StopMovie(m_movie
);
2581 if(m_lib
.GetMoviesError() != noErr
)
2584 m_lib
.GoToBeginningOfMovie(m_movie
);
2585 return m_lib
.GetMoviesError() == noErr
;
2588 //---------------------------------------------------------------------------
2589 // wxQTMediaBackend::Move
2592 //---------------------------------------------------------------------------
2593 double wxQTMediaBackend::GetPlaybackRate()
2595 return ( ((double)m_lib
.GetMovieRate(m_movie
)) / 0x10000);
2598 //---------------------------------------------------------------------------
2599 // wxQTMediaBackend::Move
2602 //---------------------------------------------------------------------------
2603 bool wxQTMediaBackend::SetPlaybackRate(double dRate
)
2605 m_lib
.SetMovieRate(m_movie
, (Fixed
) (dRate
* 0x10000));
2606 return m_lib
.GetMoviesError() == noErr
;
2609 //---------------------------------------------------------------------------
2610 // wxQTMediaBackend::Move
2613 //---------------------------------------------------------------------------
2614 bool wxQTMediaBackend::SetPosition(wxLongLong where
)
2616 TimeRecord theTimeRecord
;
2617 memset(&theTimeRecord
, 0, sizeof(TimeRecord
));
2618 theTimeRecord
.value
.lo
= where
.GetLo();
2619 theTimeRecord
.scale
= m_lib
.GetMovieTimeScale(m_movie
);
2620 theTimeRecord
.base
= m_lib
.GetMovieTimeBase(m_movie
);
2621 m_lib
.SetMovieTime(m_movie
, &theTimeRecord
);
2623 if (m_lib
.GetMoviesError() != noErr
)
2629 //---------------------------------------------------------------------------
2630 // wxQTMediaBackend::GetPosition
2632 // 1) Calls GetMovieTime to get the position we are in in the movie
2633 // in milliseconds (we called
2634 //---------------------------------------------------------------------------
2635 wxLongLong
wxQTMediaBackend::GetPosition()
2637 return m_lib
.GetMovieTime(m_movie
, NULL
);
2640 //---------------------------------------------------------------------------
2641 // wxQTMediaBackend::GetVolume
2643 // Gets the volume through GetMovieVolume - which returns a 16 bit short -
2645 // +--------+--------+
2647 // +--------+--------+
2649 // (1) first 8 bits are value before decimal
2650 // (2) second 8 bits are value after decimal
2652 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
2653 // 1 (full gain and sound)
2654 //---------------------------------------------------------------------------
2655 double wxQTMediaBackend::GetVolume()
2657 short sVolume
= m_lib
.GetMovieVolume(m_movie
);
2659 if(sVolume
& (128 << 8)) //negative - no sound
2662 return (sVolume
& (127 << 8)) ? 1.0 : ((double)(sVolume
& 255)) / 255.0;
2665 //---------------------------------------------------------------------------
2666 // wxQTMediaBackend::SetVolume
2668 // Sets the volume through SetMovieVolume - which takes a 16 bit short -
2670 // +--------+--------+
2672 // +--------+--------+
2674 // (1) first 8 bits are value before decimal
2675 // (2) second 8 bits are value after decimal
2677 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
2678 // 1 (full gain and sound)
2679 //---------------------------------------------------------------------------
2680 bool wxQTMediaBackend::SetVolume(double dVolume
)
2682 short sVolume
= (short) (dVolume
>= .9999 ? 1 << 8 : (dVolume
* 255) );
2683 m_lib
.SetMovieVolume(m_movie
, sVolume
);
2687 //---------------------------------------------------------------------------
2688 // wxQTMediaBackend::Move
2691 //---------------------------------------------------------------------------
2692 wxLongLong
wxQTMediaBackend::GetDuration()
2694 return m_lib
.GetMovieDuration(m_movie
);
2697 //---------------------------------------------------------------------------
2698 // wxQTMediaBackend::Move
2701 //---------------------------------------------------------------------------
2702 wxMediaState
wxQTMediaBackend::GetState()
2704 if ( !m_timer
|| (m_timer
->IsRunning() == false &&
2705 m_timer
->GetPaused() == false) )
2706 return wxMEDIASTATE_STOPPED
;
2708 if( m_timer
->IsRunning() == true )
2709 return wxMEDIASTATE_PLAYING
;
2711 return wxMEDIASTATE_PAUSED
;
2714 //---------------------------------------------------------------------------
2715 // wxQTMediaBackend::Move
2718 //---------------------------------------------------------------------------
2719 void wxQTMediaBackend::Cleanup()
2724 m_lib
.StopMovie(m_movie
);
2725 m_lib
.DisposeMovie(m_movie
);
2728 //---------------------------------------------------------------------------
2729 // wxQTMediaBackend::Move
2732 //---------------------------------------------------------------------------
2733 wxSize
wxQTMediaBackend::GetVideoSize() const
2738 //---------------------------------------------------------------------------
2739 // wxQTMediaBackend::Move
2742 //---------------------------------------------------------------------------
2743 void wxQTMediaBackend::Move(int WXUNUSED(x
), int WXUNUSED(y
), int w
, int h
)
2747 Rect theRect
= {0, 0, (short)h
, (short)w
};
2749 m_lib
.SetMovieBox(m_movie
, &theRect
);
2750 wxASSERT(m_lib
.GetMoviesError() == noErr
);
2754 //---------------------------------------------------------------------------
2756 //---------------------------------------------------------------------------
2758 //in source file that contains stuff you don't directly use
2759 #include <wx/html/forcelnk.h>
2760 FORCE_LINK_ME(basewxmediabackends
);
2762 //---------------------------------------------------------------------------
2763 // End wxMediaCtrl Compilation Guard and this file
2764 //---------------------------------------------------------------------------
2765 #endif //wxUSE_MEDIACTRL