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"
42 #include "wx/thread.h"
44 //---------------------------------------------------------------------------
45 // Externals (somewhere in src/msw/app.cpp)
46 //---------------------------------------------------------------------------
47 extern "C" WXDLLIMPEXP_BASE HINSTANCE
wxGetInstance(void);
49 extern WXDLLIMPEXP_CORE wxChar
*wxCanvasClassName
;
51 extern WXDLLIMPEXP_CORE
const wxChar
*wxCanvasClassName
;
54 //===========================================================================
55 // BACKEND DECLARATIONS
56 //===========================================================================
58 //---------------------------------------------------------------------------
62 //---------------------------------------------------------------------------
64 //####################THE BIG DIRECTSHOW OVERVIEW############################
67 // OK... this deserves its own little tutorial. Knowledge of COM and class
68 // factories is assumed throughout this code.
70 // Basically, the way directshow works is that you tell it to render
71 // a file, and it builds and connects a bunch of filters together.
73 // There are many, many ways to do this.
75 // WAYS TO RENDER A FILE (URLS WORK IN DS ALSO)
77 // 1) Create an instance of IGraphBuilder and call RenderFile on it
78 // 2) Create an instance of IMediaControl and call RenderFile on it
79 // 3) Create an instance of IAMMultiMediaStream, call
80 // IAMMultiMediaStream::AddStream and pass an IDirectDraw instance for
81 // the video, and pass an IDirectSound(Buffer?) instance or use the
82 // default sound renderer, then call RenderFile or RenderMoniker
83 // 4) Create a Moniker instance for the file and create and build
84 // all of the filtergraph manually
86 // Our issue here is that we can't use the default representation of 1 and 2
87 // because the IVideoWindow instance hogs a lot of the useful window
88 // messages such as WM_SETCURSOR.
90 // Solution #1 was to use #3 by creating a seperate IDirectDraw instance
91 // for our window and blitting to that through a thread... unfortunately
92 // the blitting resizing is very low quality and its quite slow.
94 // The current way is to use windowless rendering and have directshow
95 // do all the DirectDraw-style clipping to our window
97 // ~~~~~~~~~~~~~~AFTER RENDERING THE FILE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99 // When done rendering the file, we need to get several interfaces from
100 // either a IMediaControl or IGraphBuilder instance -
102 // IMediaPosition - we can set the rate with this... we can also get
103 // positions and set positions through this with REFTIME (double) instead
104 // of the normal LONGLONG that IAMMultiMediaStream and IMediaControl use
106 // IBasicAudio - we need this for setting/getting the volume
108 // Interfaces that we don't use but might be useful one day -
110 // IDirectDrawVideo - you can get this through the IFilter returned
111 // from L"Video Renderer" filter from FindFilter on the IGraphBuilder.
112 // Through this we can set the IDirectDraw instance DrawShow uses.
114 // ~~~~~~~~~~~~~~STOPPING~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
116 // There are two ways we can do this -
117 // 1) Have a thread compare the current position to the end position
118 // about every 10 milliseconds
119 // 2) Have IMediaSeekingEx send a message to a windowproc or signal a
122 // Note that we can do these both, I.E. if an IMediaSeekingEx interface
123 // is unavailable we can check the position instead of an event
125 //---------------------------------------------------------------------------
127 //---------------------------------------------------------------------------
129 //---------------------------------------------------------------------------
130 #include "wx/msw/ole/oleutils.h" //wxBasicString, IID etc.
131 #include "wx/msw/ole/uuid.h" //IID etc..
133 //---------------------------------------------------------------------------
134 // COM compatability definitions
135 //---------------------------------------------------------------------------
136 #ifndef STDMETHODCALLTYPE
137 #define STDMETHODCALLTYPE __stdcall
140 #define STDMETHOD(funcname) virtual HRESULT STDMETHODCALLTYPE funcname
145 //---------------------------------------------------------------------------
146 // IIDS - used by CoCreateInstance and IUnknown::QueryInterface
147 // Dumped from amstream.idl, quartz.idl, direct draw and with some
148 // confirmation from WINE
150 // Some of these are not used but are kept here for future reference anyway
151 //---------------------------------------------------------------------------
154 const IID LIBID_QuartzTypeLib
= {0x56A868B0,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
155 const IID IID_IAMCollection
= {0x56A868B9,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
156 const IID IID_IMediaControl
= {0x56A868B1,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
157 const IID IID_IMediaEvent
= {0x56A868B6,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
158 const IID IID_IMediaEventEx
= {0x56A868C0,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
159 const IID IID_IMediaPosition
= {0x56A868B2,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
160 const IID IID_IBasicAudio
= {0x56A868B3,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
161 const IID IID_IVideoWindow
= {0x56A868B4,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
162 const IID IID_IBasicVideo
= {0x56A868B5,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
163 const IID IID_IBasicVideo2
= {0x329BB360,0xF6EA,0x11D1,{0x90,0x38,0x00,0xA0,0xC9,0x69,0x72,0x98}};
164 const IID IID_IDeferredCommand
= {0x56A868B8,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
165 const IID IID_IQueueCommand
= {0x56A868B7,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
166 const IID IID_IFilterInfo
= {0x56A868BA,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
167 const IID IID_IRegFilterInfo
= {0x56A868BB,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
168 const IID IID_IMediaTypeInfo
= {0x56A868BC,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
169 const IID IID_IPinInfo
= {0x56A868BD,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
170 const IID IID_IAMStats
= {0xBC9BCF80,0xDCD2,0x11D2,{0xAB,0xF6,0x00,0xA0,0xC9,0x05,0xF3,0x75}};
171 const CLSID CLSID_FilgraphManager
= {0xE436EBB3,0x524F,0x11CE,{0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
174 const CLSID CLSID_AMMultiMediaStream
= {0x49C47CE5, 0x9BA4, 0x11D0,{0x82, 0x12, 0x00, 0xC0, 0x4F, 0xC3, 0x2C, 0x45}};
175 const IID IID_IAMMultiMediaStream
= {0xBEBE595C, 0x9A6F, 0x11D0,{0x8F, 0xDE, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
176 const IID IID_IDirectDrawMediaStream
= {0xF4104FCE, 0x9A70, 0x11D0,{0x8F, 0xDE, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
177 const GUID MSPID_PrimaryVideo
= {0xa35FF56A, 0x9FDA, 0x11D0,{0x8F, 0xDF, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
178 const GUID MSPID_PrimaryAudio
= {0xa35FF56B, 0x9FDA, 0x11D0,{0x8F, 0xDF, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
181 const IID IID_IDirectDraw
= {0x6C14DB80,0xA733,0x11CE,{0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60}};
182 const CLSID CLSID_DirectDraw
= {0xD7B70EE0,0x4340,0x11CF,{0xB0,0x63,0x00,0x20,0xAF,0xC2,0xCD,0x35}};
185 const CLSID CLSID_VideoMixingRenderer
= {0xB87BEB7B, 0x8D29, 0x423F,{0xAE, 0x4D, 0x65, 0x82, 0xC1, 0x01, 0x75, 0xAC}};
186 const IID IID_IVMRWindowlessControl
= {0x0EB1088C, 0x4DCD, 0x46F0,{0x87, 0x8F, 0x39, 0xDA, 0xE8, 0x6A, 0x51, 0xB7}};
187 const IID IID_IFilterGraph
= {0x56A8689F, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
188 const IID IID_IGraphBuilder
= {0x56A868A9, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
189 const IID IID_IVMRFilterConfig
= {0x9E5530C5, 0x7034, 0x48B4,{0xBB, 0x46, 0x0B, 0x8A, 0x6E, 0xFC, 0x8E, 0x36}};
190 const IID IID_IBaseFilter
= {0x56A86895, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
192 //---------------------------------------------------------------------------
193 // DIRECTDRAW COM INTERFACES
194 //---------------------------------------------------------------------------
195 //DDSURFACESDESC - we don't need most of the stuff here, esp. DDPIXELFORMAT,
196 //so just put stubs in
197 struct DDPIXELFORMAT
{DWORD dw1
,dw2
,dw3
,dw4
,dw5
,dw6
,dw7
,dw8
;};
198 struct DDCOLORKEY
{DWORD dwLow
, dwHigh
;};
200 typedef struct IDirectDrawClipper
* LPDIRECTDRAWCLIPPER
;
201 typedef struct IDirectDraw
* LPDIRECTDRAW
;
202 typedef struct IDirectDrawSurface
* LPDIRECTDRAWSURFACE
;
203 typedef struct DDSURFACEDESC
* LPDDSURFACEDESC
;
204 typedef struct IDirectDrawPalette
* LPDIRECTDRAWPALETTE
;
205 typedef struct DDSCAPS
* LPDDSCAPS
;
206 typedef DDCOLORKEY
* LPDDCOLORKEY
;
207 typedef DDPIXELFORMAT
* LPDDPIXELFORMAT
;
208 typedef struct DDCAPS
* LPDDCAPS
;
221 DWORD dwBackBufferCount
;
225 DWORD dwZBufferBitDepth
;
228 DWORD dwAlphaBitDepth
;
231 DDCOLORKEY ddckCKDestOverlay
;
232 DDCOLORKEY ddckCKDestBlt
;
233 DDCOLORKEY ddckCKSrcOverlay
;
234 DDCOLORKEY ddckCKSrcBlt
;
235 DDPIXELFORMAT ddpfPixelFormat
;
236 struct DDSCAPS
{DWORD dwCaps
;} ddsCaps
;
239 struct IDirectDrawClipper
: public IUnknown
241 STDMETHOD(GetClipList
)(LPRECT
, LPRGNDATA
, LPDWORD
) PURE
;
242 STDMETHOD(GetHWnd
)(HWND
*) PURE
;
243 STDMETHOD(Initialize
)(LPDIRECTDRAW
, DWORD
) PURE
;
244 STDMETHOD(IsClipListChanged
)(BOOL
*) PURE
;
245 STDMETHOD(SetClipList
)(LPRGNDATA
,DWORD
) PURE
;
246 STDMETHOD(SetHWnd
)(DWORD
, HWND
) PURE
;
249 struct IDirectDrawSurface
: public IUnknown
251 STDMETHOD(AddAttachedSurface
)(LPDIRECTDRAWSURFACE
) PURE
;
252 STDMETHOD(AddOverlayDirtyRect
)(LPRECT
) PURE
;
253 STDMETHOD(Blt
)(LPRECT
,LPDIRECTDRAWSURFACE
, LPRECT
,DWORD
, struct DDBLTFX
*) PURE
;
254 STDMETHOD(BltBatch
)(struct DDBLTBATCH
*, DWORD
, DWORD
) PURE
;
255 STDMETHOD(BltFast
)(DWORD
,DWORD
,LPDIRECTDRAWSURFACE
, LPRECT
,DWORD
) PURE
;
256 STDMETHOD(DeleteAttachedSurface
)(DWORD
,LPDIRECTDRAWSURFACE
) PURE
;
257 STDMETHOD(EnumAttachedSurfaces
)(LPVOID
, LPVOID
/*LPDDENUMSURFACESCALLBACK*/) PURE
;
258 STDMETHOD(EnumOverlayZOrders
)(DWORD
,LPVOID
,LPVOID
/*LPDDENUMSURFACESCALLBACK*/) PURE
;
259 STDMETHOD(Flip
)(LPDIRECTDRAWSURFACE
, DWORD
) PURE
;
260 STDMETHOD(GetAttachedSurface
)(LPDDSCAPS
, LPDIRECTDRAWSURFACE
*) PURE
;
261 STDMETHOD(GetBltStatus
)(DWORD
) PURE
;
262 STDMETHOD(GetCaps
)(LPDDSCAPS
) PURE
;
263 STDMETHOD(GetClipper
)(LPDIRECTDRAWCLIPPER
*) PURE
;
264 STDMETHOD(GetColorKey
)(DWORD
, LPDDCOLORKEY
) PURE
;
265 STDMETHOD(GetDC
)(HDC
*) PURE
;
266 STDMETHOD(GetFlipStatus
)(DWORD
) PURE
;
267 STDMETHOD(GetOverlayPosition
)(LPLONG
, LPLONG
) PURE
;
268 STDMETHOD(GetPalette
)(LPDIRECTDRAWPALETTE FAR
*) PURE
;
269 STDMETHOD(GetPixelFormat
)(LPDDPIXELFORMAT
) PURE
;
270 STDMETHOD(GetSurfaceDesc
)(LPDDSURFACEDESC
) PURE
;
271 STDMETHOD(Initialize
)(LPDIRECTDRAW
, LPDDSURFACEDESC
) PURE
;
272 STDMETHOD(IsLost
)(THIS
) PURE
;
273 STDMETHOD(Lock
)(LPRECT
,LPDDSURFACEDESC
,DWORD
,HANDLE
) PURE
;
274 STDMETHOD(ReleaseDC
)(HDC
) PURE
;
275 STDMETHOD(Restore
)(THIS
) PURE
;
276 STDMETHOD(SetClipper
)(LPDIRECTDRAWCLIPPER
) PURE
;
277 STDMETHOD(SetColorKey
)(DWORD
, LPDDCOLORKEY
) PURE
;
278 STDMETHOD(SetOverlayPosition
)(LONG
, LONG
) PURE
;
279 STDMETHOD(SetPalette
)(IUnknown
*) PURE
;
280 STDMETHOD(Unlock
)(LPVOID
) PURE
;
281 STDMETHOD(UpdateOverlay
)(LPRECT
, LPDIRECTDRAWSURFACE
,LPRECT
,
282 DWORD
, struct DDOVERLAYFX
*) PURE
;
283 STDMETHOD(UpdateOverlayDisplay
)(DWORD
) PURE
;
284 STDMETHOD(UpdateOverlayZOrder
)(DWORD
, LPDIRECTDRAWSURFACE
) PURE
;
287 struct IDirectDraw
: public IUnknown
289 STDMETHOD(Compact
)() PURE
;
290 STDMETHOD(CreateClipper
)(DWORD
, LPDIRECTDRAWCLIPPER
*, IUnknown
* ) PURE
;
291 STDMETHOD(CreatePalette
)(DWORD
, LPPALETTEENTRY
, LPDIRECTDRAWPALETTE
*, IUnknown
* ) PURE
;
292 STDMETHOD(CreateSurface
)(LPDDSURFACEDESC
, LPDIRECTDRAWSURFACE
*, IUnknown
*) PURE
;
293 STDMETHOD(DuplicateSurface
)(LPDIRECTDRAWSURFACE
, LPDIRECTDRAWSURFACE
* ) PURE
;
294 STDMETHOD(EnumDisplayModes
)(DWORD
, LPDDSURFACEDESC
, LPVOID
, LPVOID
) PURE
;
295 STDMETHOD(EnumSurfaces
)(DWORD
, LPDDSURFACEDESC
, LPVOID
,LPVOID
) PURE
;
296 STDMETHOD(FlipToGDISurface
)() PURE
;
297 STDMETHOD(GetCaps
)(LPDDCAPS
, LPDDCAPS
) PURE
;
298 STDMETHOD(GetDisplayMode
)(LPDDSURFACEDESC
) PURE
;
299 STDMETHOD(GetFourCCCodes
)(LPDWORD
, LPDWORD
) PURE
;
300 STDMETHOD(GetGDISurface
)(LPDIRECTDRAWSURFACE
*) PURE
;
301 STDMETHOD(GetMonitorFrequency
)(LPDWORD
) PURE
;
302 STDMETHOD(GetScanLine
)(LPDWORD
) PURE
;
303 STDMETHOD(GetVerticalBlankStatus
)(LPBOOL
) PURE
;
304 STDMETHOD(Initialize
)(GUID
*) PURE
;
305 STDMETHOD(RestoreDisplayMode
)() PURE
;
306 STDMETHOD(SetCooperativeLevel
)(HWND
, DWORD
) PURE
;
307 STDMETHOD(SetDisplayMode
)(DWORD
, DWORD
,DWORD
, DWORD
, DWORD
) PURE
;
308 STDMETHOD(WaitForVerticalBlank
)(DWORD
, HANDLE
) PURE
;
311 //---------------------------------------------------------------------------
312 // AMMEDIA COM INTERFACES
313 //---------------------------------------------------------------------------
315 struct IMultiMediaStream
;
316 struct IStreamSample
: public IUnknown
319 STDMETHOD(GetMediaStream
)(IMediaStream
**) PURE
;
320 STDMETHOD(GetSampleTimes
)(LONGLONG
*, LONGLONG
*, LONGLONG
*) PURE
;
321 STDMETHOD(SetSampleTimes
)(const LONGLONG
*, const LONGLONG
*) PURE
;
322 STDMETHOD(Update
)(DWORD
, HANDLE
, LPVOID
, DWORD_PTR
) PURE
;
323 STDMETHOD(CompletionStatus
)(DWORD
, DWORD
) PURE
;
326 struct IDirectDrawStreamSample
: public IStreamSample
329 STDMETHOD(GetSurface
)(IDirectDrawSurface
**, RECT
*) PURE
;
330 STDMETHOD(SetRect
)(const RECT
*) PURE
;
333 struct IMediaStream
: public IUnknown
335 STDMETHOD(GetMultiMediaStream
)(IMultiMediaStream
**) PURE
;
336 STDMETHOD(GetInformation
)(GUID
*, int *) PURE
;
337 STDMETHOD(SetSameFormat
)(IMediaStream
*, DWORD
) PURE
;
338 STDMETHOD(AllocateSample
)(DWORD
, IStreamSample
**) PURE
;
339 STDMETHOD(CreateSharedSample
)(IStreamSample
*, DWORD
,
340 IStreamSample
**) PURE
;
341 STDMETHOD(SendEndOfStream
)(DWORD dwFlags
) PURE
;
344 struct IDirectDrawMediaStream
: public IMediaStream
346 STDMETHOD(GetFormat
)(DDSURFACEDESC
*, IDirectDrawPalette
**,
347 DDSURFACEDESC
*, DWORD
*) PURE
;
348 STDMETHOD(SetFormat
)(const DDSURFACEDESC
*, IDirectDrawPalette
*) PURE
;
349 STDMETHOD(GetDirectDraw
)(IDirectDraw
**) PURE
;
350 STDMETHOD(SetDirectDraw
)(IDirectDraw
*) PURE
;
351 STDMETHOD(CreateSample
)(IDirectDrawSurface
*, const RECT
*,
352 DWORD
, IDirectDrawStreamSample
**) PURE
;
353 STDMETHOD(GetTimePerFrame
)(LONGLONG
*) PURE
;
356 struct IMultiMediaStream
: public IUnknown
358 STDMETHOD(GetInformation
)(DWORD
*, int *) PURE
;
359 STDMETHOD(GetMediaStream
)(REFGUID
, IMediaStream
**) PURE
;
360 STDMETHOD(EnumMediaStreams
)(long, IMediaStream
**) PURE
;
361 STDMETHOD(GetState
)(int *pCurrentState
) PURE
;
362 STDMETHOD(SetState
)(int NewState
) PURE
;
363 STDMETHOD(GetTime
)(LONGLONG
*pCurrentTime
) PURE
;
364 STDMETHOD(GetDuration
)(LONGLONG
*pDuration
) PURE
;
365 STDMETHOD(Seek
)(LONGLONG SeekTime
) PURE
;
366 STDMETHOD(GetEndOfStreamEventHandle
)(HANDLE
*phEOS
) PURE
;
369 struct IAMMultiMediaStream
: public IMultiMediaStream
371 STDMETHOD(Initialize
)(int, DWORD
, IUnknown
*) PURE
;
372 STDMETHOD(GetFilterGraph
)(IUnknown
**) PURE
;
373 STDMETHOD(GetFilter
)(IUnknown
**) PURE
;
374 STDMETHOD(AddMediaStream
)(IUnknown
*, const GUID
*, DWORD
,
375 IMediaStream
**) PURE
;
376 STDMETHOD(OpenFile
)(LPCWSTR
, DWORD
) PURE
;
377 STDMETHOD(OpenMoniker
)(IBindCtx
*, IMoniker
*, DWORD
) PURE
;
378 STDMETHOD(Render
)(DWORD
) PURE
;
381 //---------------------------------------------------------------------------
382 // QUARTZ COM INTERFACES (dumped from quartz.idl from MSVC COM Browser)
383 //---------------------------------------------------------------------------
384 struct IAMCollection
: public IDispatch
386 STDMETHOD(get_Count
)(long *) PURE
;
387 STDMETHOD(Item
)(long, IUnknown
**) PURE
;
388 STDMETHOD(get__NewEnum
)(IUnknown
**) PURE
;
391 struct IMediaControl
: public IDispatch
393 STDMETHOD(Run
)() PURE
;
394 STDMETHOD(Pause
)() PURE
;
395 STDMETHOD(Stop
)() PURE
;
396 STDMETHOD(GetState
)(long, long*) PURE
;
397 STDMETHOD(RenderFile
)(BSTR
) PURE
;
398 STDMETHOD(AddSourceFilter
)(BSTR
, IDispatch
**) PURE
;
399 STDMETHOD(get_FilterCollection
)(IDispatch
**) PURE
;
400 STDMETHOD(get_RegFilterCollection
)(IDispatch
**) PURE
;
401 STDMETHOD(StopWhenReady
)() PURE
;
404 struct IMediaEvent
: public IDispatch
406 STDMETHOD(GetEventHandle
)(LONG_PTR
*) PURE
;
407 STDMETHOD(GetEvent
)(long *, LONG_PTR
*, LONG_PTR
*, long) PURE
;
408 STDMETHOD(WaitForCompletion
)(long, long *) PURE
;
409 STDMETHOD(CancelDefaultHandling
)(long) PURE
;
410 STDMETHOD(RestoreDefaultHandling
)(long) PURE
;
411 STDMETHOD(FreeEventParams
)(long, LONG_PTR
, LONG_PTR
) PURE
;
414 struct IMediaEventEx
: public IMediaEvent
416 STDMETHOD(SetNotifyWindow
)(LONG_PTR
, long, LONG_PTR
) PURE
;
417 STDMETHOD(SetNotifyFlags
)(long) PURE
;
418 STDMETHOD(GetNotifyFlags
)(long *) PURE
;
421 struct IMediaPosition
: public IDispatch
423 STDMETHOD(get_Duration
)(double *) PURE
;
424 STDMETHOD(put_CurrentPosition
)(double) PURE
;
425 STDMETHOD(get_CurrentPosition
)(double *) PURE
;
426 STDMETHOD(get_StopTime
)(double *) PURE
;
427 STDMETHOD(put_StopTime
)(double) PURE
;
428 STDMETHOD(get_PrerollTime
)(double *) PURE
;
429 STDMETHOD(put_PrerollTime
)(double) PURE
;
430 STDMETHOD(put_Rate
)(double) PURE
;
431 STDMETHOD(get_Rate
)(double *) PURE
;
432 STDMETHOD(CanSeekForward
)(long *) PURE
;
433 STDMETHOD(CanSeekBackward
)(long *) PURE
;
436 struct IBasicAudio
: public IDispatch
438 STDMETHOD(put_Volume
)(long) PURE
;
439 STDMETHOD(get_Volume
)(long *) PURE
;
440 STDMETHOD(put_Balance
)(long) PURE
;
441 STDMETHOD(get_Balance
)(long *) PURE
;
444 //---------------------------------------------------------------------------
445 // MISC COM INTERFACES
446 //---------------------------------------------------------------------------
447 struct IVMRWindowlessControl
: public IUnknown
449 STDMETHOD(GetNativeVideoSize
)(LONG
*, LONG
*, LONG
*, LONG
*) PURE
;
450 STDMETHOD(GetMinIdealVideoSize
)(LONG
*, LONG
*) PURE
;
451 STDMETHOD(GetMaxIdealVideoSize
)(LONG
*, LONG
*) PURE
;
452 STDMETHOD(SetVideoPosition
)(const LPRECT
,const LPRECT
) PURE
;
453 STDMETHOD(GetVideoPosition
)(LPRECT
, LPRECT
) PURE
;
454 STDMETHOD(GetAspectRatioMode
)(DWORD
*) PURE
;
455 STDMETHOD(SetAspectRatioMode
)(DWORD
) PURE
;
456 STDMETHOD(SetVideoClippingWindow
)(HWND
) PURE
;
457 STDMETHOD(RepaintVideo
)(HWND
, HDC
) PURE
;
458 STDMETHOD(DisplayModeChanged
)() PURE
;
459 STDMETHOD(GetCurrentImage
)(BYTE
**) PURE
;
460 STDMETHOD(SetBorderColor
)(COLORREF
) PURE
;
461 STDMETHOD(GetBorderColor
)(COLORREF
*) PURE
;
462 STDMETHOD(SetColorKey
)(COLORREF
) PURE
;
463 STDMETHOD(GetColorKey
)(COLORREF
*) PURE
;
466 typedef IUnknown IVMRImageCompositor
;
468 struct IVMRFilterConfig
: public IUnknown
470 STDMETHOD(SetImageCompositor
)(IVMRImageCompositor
*) PURE
;
471 STDMETHOD(SetNumberOfStreams
)(DWORD
) PURE
;
472 STDMETHOD(GetNumberOfStreams
)(DWORD
*) PURE
;
473 STDMETHOD(SetRenderingPrefs
)(DWORD
) PURE
;
474 STDMETHOD(GetRenderingPrefs
)(DWORD
*) PURE
;
475 STDMETHOD(SetRenderingMode
)(DWORD
) PURE
;
476 STDMETHOD(GetRenderingMode
)(DWORD
*) PURE
;
479 typedef IUnknown IBaseFilter
;
480 typedef IUnknown IPin
;
481 typedef IUnknown IEnumFilters
;
482 typedef int AM_MEDIA_TYPE
;
484 struct IFilterGraph
: public IUnknown
486 STDMETHOD(AddFilter
)(IBaseFilter
*, LPCWSTR
) PURE
;
487 STDMETHOD(RemoveFilter
)(IBaseFilter
*) PURE
;
488 STDMETHOD(EnumFilters
)(IEnumFilters
**) PURE
;
489 STDMETHOD(FindFilterByName
)(LPCWSTR
, IBaseFilter
**) PURE
;
490 STDMETHOD(ConnectDirect
)(IPin
*, IPin
*, const AM_MEDIA_TYPE
*) PURE
;
491 STDMETHOD(Reconnect
)(IPin
*) PURE
;
492 STDMETHOD(Disconnect
)(IPin
*) PURE
;
493 STDMETHOD(SetDefaultSyncSource
)() PURE
;
496 struct IGraphBuilder
: public IFilterGraph
499 STDMETHOD(Connect
)(IPin
*, IPin
*) PURE
;
500 STDMETHOD(Render
)(IPin
*) PURE
;
501 STDMETHOD(RenderFile
)(LPCWSTR
, LPCWSTR
) PURE
;
502 STDMETHOD(AddSourceFilter
)(LPCWSTR
, LPCWSTR
, IBaseFilter
**) PURE
;
503 STDMETHOD(SetLogFile
)(DWORD_PTR
) PURE
;
504 STDMETHOD(Abort
)() PURE
;
505 STDMETHOD(ShouldOperationContinue
)() PURE
;
508 //------------------------------------------------------------------
509 // wxAMMediaBackend (Active Movie)
510 //------------------------------------------------------------------
511 class WXDLLIMPEXP_MEDIA wxAMMediaThread
: public wxThread
514 virtual ExitCode
Entry();
516 class wxAMMediaBackend
* pThis
;
519 //cludgy workaround for wx events. slots would be nice :)
520 class WXDLLIMPEXP_MEDIA wxAMMediaEvtHandler
: public wxEvtHandler
523 void OnPaint(wxPaintEvent
&);
524 void OnEraseBackground(wxEraseEvent
&);
527 typedef BOOL (WINAPI
* LPAMGETERRORTEXT
)(HRESULT
, wxChar
*, DWORD
);
529 class WXDLLIMPEXP_MEDIA wxAMMediaBackend
: public wxMediaBackend
534 virtual ~wxAMMediaBackend();
536 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
541 const wxValidator
& validator
,
542 const wxString
& name
);
545 virtual bool Pause();
548 virtual bool Load(const wxString
& fileName
);
549 virtual bool Load(const wxURI
& location
);
551 virtual wxMediaState
GetState();
553 virtual bool SetPosition(wxLongLong where
);
554 virtual wxLongLong
GetPosition();
555 virtual wxLongLong
GetDuration();
557 virtual void Move(int x
, int y
, int w
, int h
);
558 wxSize
GetVideoSize() const;
560 virtual double GetPlaybackRate();
561 virtual bool SetPlaybackRate(double);
563 virtual double GetVolume();
564 virtual bool SetVolume(double);
568 bool SetWindowlessMode(IGraphBuilder
* pGB
,
569 IVMRWindowlessControl
** ppVMC
= NULL
);
573 wxMediaState m_state
;
574 wxCriticalSection m_rendercs
;
576 IVMRWindowlessControl
* m_pVMC
;
577 IGraphBuilder
* m_pGB
;
579 IMediaControl
* m_pMC
;
581 IMediaPosition
* m_pMS
;
584 wxAMMediaThread
* m_pThread
;
589 HMODULE m_hQuartzDll
;
590 LPAMGETERRORTEXT m_lpAMGetErrorText
;
591 wxString
GetErrorString(HRESULT hrdsv
);
594 friend class wxAMMediaThread
;
595 friend class wxAMMediaEvtHandler
;
597 DECLARE_DYNAMIC_CLASS(wxAMMediaBackend
)
600 //---------------------------------------------------------------------------
604 //---------------------------------------------------------------------------
606 //---------------------------------------------------------------------------
608 //---------------------------------------------------------------------------
609 #include <mmsystem.h>
611 class WXDLLIMPEXP_MEDIA wxMCIMediaBackend
: public wxMediaBackend
616 ~wxMCIMediaBackend();
618 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
623 const wxValidator
& validator
,
624 const wxString
& name
);
627 virtual bool Pause();
630 virtual bool Load(const wxString
& fileName
);
631 virtual bool Load(const wxURI
& location
);
633 virtual wxMediaState
GetState();
635 virtual bool SetPosition(wxLongLong where
);
636 virtual wxLongLong
GetPosition();
637 virtual wxLongLong
GetDuration();
639 virtual void Move(int x
, int y
, int w
, int h
);
640 wxSize
GetVideoSize() const;
642 virtual double GetPlaybackRate();
643 virtual bool SetPlaybackRate(double dRate
);
645 virtual double GetVolume();
646 virtual bool SetVolume(double);
648 static LRESULT CALLBACK
NotifyWndProc(HWND hWnd
, UINT nMsg
,
649 WPARAM wParam
, LPARAM lParam
);
651 LRESULT CALLBACK
OnNotifyWndProc(HWND hWnd
, UINT nMsg
,
652 WPARAM wParam
, LPARAM lParam
);
654 MCIDEVICEID m_hDev
; //Our MCI Device ID/Handler
655 wxControl
* m_ctrl
; //Parent control
656 HWND m_hNotifyWnd
; //Window to use for MCI events
657 bool m_bVideo
; //Whether or not we have video
659 DECLARE_DYNAMIC_CLASS(wxMCIMediaBackend
)
662 //---------------------------------------------------------------------------
666 //---------------------------------------------------------------------------
668 //---------------------------------------------------------------------------
670 //---------------------------------------------------------------------------
671 //#include <qtml.h> //Windoze QT include
672 //#include <QuickTimeComponents.h> //Standard QT stuff
673 #include "wx/dynlib.h"
675 //---------------------------------------------------------------------------
677 //---------------------------------------------------------------------------
678 typedef struct MovieRecord
* Movie
;
679 typedef wxInt16 OSErr
;
680 typedef wxInt32 OSStatus
;
683 typedef unsigned char Str255
[256];
684 #define StringPtr unsigned char*
685 #define newMovieActive 1
689 #define OSType unsigned long
690 #define CGrafPtr struct GrafPort *
691 #define TimeScale long
692 #define TimeBase struct TimeBaseRecord *
694 #ifndef URLDataHandlerSubType
695 #if defined(__WATCOMC__) || defined(__MINGW32__)
696 // use magic numbers for compilers which complain about multicharacter integers
697 const OSType URLDataHandlerSubType
= 1970433056;
698 const OSType VisualMediaCharacteristic
= 1702454643;
700 const OSType URLDataHandlerSubType
= 'url ';
701 const OSType VisualMediaCharacteristic
= 'eyes';
708 Str255 name
; /*Str63 on mac, Str255 on msw */
724 wide value
; /* units */
725 TimeScale scale
; /* units per second */
729 //---------------------------------------------------------------------------
731 //---------------------------------------------------------------------------
732 #define wxDL_METHOD_DEFINE( rettype, name, args, shortargs, defret ) \
733 typedef rettype (* name ## Type) args ; \
734 name ## Type pfn_ ## name; \
736 { if (m_ok) return pfn_ ## name shortargs ; return defret; }
738 #define wxDL_VOIDMETHOD_DEFINE( name, args, shortargs ) \
739 typedef void (* name ## Type) args ; \
740 name ## Type pfn_ ## name; \
742 { if (m_ok) pfn_ ## name shortargs ; }
744 #define wxDL_METHOD_LOAD( lib, name, success ) \
745 pfn_ ## name = (name ## Type) lib.GetSymbol( wxT(#name), &success ); \
746 if (!success) { wxLog::EnableLogging(bWasLoggingEnabled); return false; }
749 //Class that utilizes Robert Roeblings Dynamic Library Macros
750 class WXDLLIMPEXP_MEDIA wxQuickTimeLibrary
753 ~wxQuickTimeLibrary()
760 bool IsOk() const {return m_ok
;}
763 wxDynamicLibrary m_dll
;
767 wxDL_VOIDMETHOD_DEFINE( StartMovie
, (Movie m
), (m
) );
768 wxDL_VOIDMETHOD_DEFINE( StopMovie
, (Movie m
), (m
) );
769 wxDL_METHOD_DEFINE( bool, IsMovieDone
, (Movie m
), (m
), false);
770 wxDL_VOIDMETHOD_DEFINE( GoToBeginningOfMovie
, (Movie m
), (m
) );
771 wxDL_METHOD_DEFINE( OSErr
, GetMoviesError
, (), (), -1);
772 wxDL_METHOD_DEFINE( OSErr
, EnterMovies
, (), (), -1);
773 wxDL_VOIDMETHOD_DEFINE( ExitMovies
, (), () );
774 wxDL_METHOD_DEFINE( OSErr
, InitializeQTML
, (long flags
), (flags
), -1);
775 wxDL_VOIDMETHOD_DEFINE( TerminateQTML
, (), () );
777 wxDL_METHOD_DEFINE( OSErr
, NativePathNameToFSSpec
,
778 (char* inName
, FSSpec
* outFile
, long flags
),
779 (inName
, outFile
, flags
), -1);
781 wxDL_METHOD_DEFINE( OSErr
, OpenMovieFile
,
782 (const FSSpec
* fileSpec
, short * resRefNum
, wxInt8 permission
),
783 (fileSpec
, resRefNum
, permission
), -1 );
785 wxDL_METHOD_DEFINE( OSErr
, CloseMovieFile
,
786 (short resRefNum
), (resRefNum
), -1);
788 wxDL_METHOD_DEFINE( OSErr
, NewMovieFromFile
,
789 (Movie
* theMovie
, short resRefNum
, short * resId
,
790 StringPtr resName
, short newMovieFlags
,
791 bool * dataRefWasChanged
),
792 (theMovie
, resRefNum
, resId
, resName
, newMovieFlags
,
793 dataRefWasChanged
), -1);
795 wxDL_VOIDMETHOD_DEFINE( SetMovieRate
, (Movie m
, Fixed rate
), (m
, rate
) );
796 wxDL_METHOD_DEFINE( Fixed
, GetMovieRate
, (Movie m
), (m
), 0);
797 wxDL_VOIDMETHOD_DEFINE( MoviesTask
, (Movie m
, long maxms
), (m
, maxms
) );
798 wxDL_VOIDMETHOD_DEFINE( BlockMove
,
799 (const char* p1
, const char* p2
, long s
), (p1
,p2
,s
) );
800 wxDL_METHOD_DEFINE( Handle
, NewHandleClear
, (long s
), (s
), NULL
);
802 wxDL_METHOD_DEFINE( OSErr
, NewMovieFromDataRef
,
803 (Movie
* m
, short flags
, short * id
,
804 Handle dataRef
, OSType dataRefType
),
805 (m
,flags
,id
,dataRef
,dataRefType
), -1 );
807 wxDL_VOIDMETHOD_DEFINE( DisposeHandle
, (Handle h
), (h
) );
808 wxDL_VOIDMETHOD_DEFINE( GetMovieNaturalBoundsRect
, (Movie m
, Rect
* r
), (m
,r
) );
809 wxDL_METHOD_DEFINE( void*, GetMovieIndTrackType
,
810 (Movie m
, long index
, OSType type
, long flags
),
811 (m
,index
,type
,flags
), NULL
);
812 wxDL_VOIDMETHOD_DEFINE( CreatePortAssociation
,
813 (void* hWnd
, void* junk
, long morejunk
), (hWnd
, junk
, morejunk
) );
814 wxDL_METHOD_DEFINE(void*, GetNativeWindowPort
, (void* hWnd
), (hWnd
), NULL
);
815 wxDL_VOIDMETHOD_DEFINE(SetMovieGWorld
, (Movie m
, CGrafPtr port
, void* whatever
),
816 (m
, port
, whatever
) );
817 wxDL_VOIDMETHOD_DEFINE(DisposeMovie
, (Movie m
), (m
) );
818 wxDL_VOIDMETHOD_DEFINE(SetMovieBox
, (Movie m
, Rect
* r
), (m
,r
));
819 wxDL_VOIDMETHOD_DEFINE(SetMovieTimeScale
, (Movie m
, long s
), (m
,s
));
820 wxDL_METHOD_DEFINE(long, GetMovieDuration
, (Movie m
), (m
), 0);
821 wxDL_METHOD_DEFINE(TimeBase
, GetMovieTimeBase
, (Movie m
), (m
), 0);
822 wxDL_METHOD_DEFINE(TimeScale
, GetMovieTimeScale
, (Movie m
), (m
), 0);
823 wxDL_METHOD_DEFINE(long, GetMovieTime
, (Movie m
, void* cruft
), (m
,cruft
), 0);
824 wxDL_VOIDMETHOD_DEFINE(SetMovieTime
, (Movie m
, TimeRecord
* tr
), (m
,tr
) );
825 wxDL_METHOD_DEFINE(short, GetMovieVolume
, (Movie m
), (m
), 0);
826 wxDL_VOIDMETHOD_DEFINE(SetMovieVolume
, (Movie m
, short sVolume
), (m
,sVolume
) );
829 bool wxQuickTimeLibrary::Initialize()
833 bool bWasLoggingEnabled
= wxLog::EnableLogging(false); //Turn off the wxDynamicLibrary logging
835 if(!m_dll
.Load(wxT("qtmlClient.dll")))
837 wxLog::EnableLogging(bWasLoggingEnabled
);
841 bool bOk
; //TODO: Get rid of this, use m_ok instead (not a biggie)
843 wxDL_METHOD_LOAD( m_dll
, StartMovie
, bOk
);
844 wxDL_METHOD_LOAD( m_dll
, StopMovie
, bOk
);
845 wxDL_METHOD_LOAD( m_dll
, IsMovieDone
, bOk
);
846 wxDL_METHOD_LOAD( m_dll
, GoToBeginningOfMovie
, bOk
);
847 wxDL_METHOD_LOAD( m_dll
, GetMoviesError
, bOk
);
848 wxDL_METHOD_LOAD( m_dll
, EnterMovies
, bOk
);
849 wxDL_METHOD_LOAD( m_dll
, ExitMovies
, bOk
);
850 wxDL_METHOD_LOAD( m_dll
, InitializeQTML
, bOk
);
851 wxDL_METHOD_LOAD( m_dll
, TerminateQTML
, bOk
);
852 wxDL_METHOD_LOAD( m_dll
, NativePathNameToFSSpec
, bOk
);
853 wxDL_METHOD_LOAD( m_dll
, OpenMovieFile
, bOk
);
854 wxDL_METHOD_LOAD( m_dll
, CloseMovieFile
, bOk
);
855 wxDL_METHOD_LOAD( m_dll
, NewMovieFromFile
, bOk
);
856 wxDL_METHOD_LOAD( m_dll
, GetMovieRate
, bOk
);
857 wxDL_METHOD_LOAD( m_dll
, SetMovieRate
, bOk
);
858 wxDL_METHOD_LOAD( m_dll
, MoviesTask
, bOk
);
859 wxDL_METHOD_LOAD( m_dll
, BlockMove
, bOk
);
860 wxDL_METHOD_LOAD( m_dll
, NewHandleClear
, bOk
);
861 wxDL_METHOD_LOAD( m_dll
, NewMovieFromDataRef
, bOk
);
862 wxDL_METHOD_LOAD( m_dll
, DisposeHandle
, bOk
);
863 wxDL_METHOD_LOAD( m_dll
, GetMovieNaturalBoundsRect
, bOk
);
864 wxDL_METHOD_LOAD( m_dll
, GetMovieIndTrackType
, bOk
);
865 wxDL_METHOD_LOAD( m_dll
, CreatePortAssociation
, bOk
);
866 wxDL_METHOD_LOAD( m_dll
, GetNativeWindowPort
, bOk
);
867 wxDL_METHOD_LOAD( m_dll
, SetMovieGWorld
, bOk
);
868 wxDL_METHOD_LOAD( m_dll
, DisposeMovie
, bOk
);
869 wxDL_METHOD_LOAD( m_dll
, SetMovieBox
, bOk
);
870 wxDL_METHOD_LOAD( m_dll
, SetMovieTimeScale
, bOk
);
871 wxDL_METHOD_LOAD( m_dll
, GetMovieDuration
, bOk
);
872 wxDL_METHOD_LOAD( m_dll
, GetMovieTimeBase
, bOk
);
873 wxDL_METHOD_LOAD( m_dll
, GetMovieTimeScale
, bOk
);
874 wxDL_METHOD_LOAD( m_dll
, GetMovieTime
, bOk
);
875 wxDL_METHOD_LOAD( m_dll
, SetMovieTime
, bOk
);
876 wxDL_METHOD_LOAD( m_dll
, GetMovieVolume
, bOk
);
877 wxDL_METHOD_LOAD( m_dll
, SetMovieVolume
, bOk
);
879 wxLog::EnableLogging(bWasLoggingEnabled
);
885 class WXDLLIMPEXP_MEDIA wxQTMediaBackend
: public wxMediaBackend
891 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
896 const wxValidator
& validator
,
897 const wxString
& name
);
900 virtual bool Pause();
903 virtual bool Load(const wxString
& fileName
);
904 virtual bool Load(const wxURI
& location
);
906 virtual wxMediaState
GetState();
908 virtual bool SetPosition(wxLongLong where
);
909 virtual wxLongLong
GetPosition();
910 virtual wxLongLong
GetDuration();
912 virtual void Move(int x
, int y
, int w
, int h
);
913 wxSize
GetVideoSize() const;
915 virtual double GetPlaybackRate();
916 virtual bool SetPlaybackRate(double dRate
);
918 virtual double GetVolume();
919 virtual bool SetVolume(double);
924 wxSize m_bestSize
; //Original movie size
925 Movie m_movie
; //QT Movie handle/instance
926 wxControl
* m_ctrl
; //Parent control
927 bool m_bVideo
; //Whether or not we have video
928 class _wxQTTimer
* m_timer
; //Timer for streaming the movie
929 wxQuickTimeLibrary m_lib
;
931 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
)
935 //===========================================================================
937 //===========================================================================
939 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
943 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
945 IMPLEMENT_DYNAMIC_CLASS(wxAMMediaBackend
, wxMediaBackend
);
947 //---------------------------------------------------------------------------
948 // Usual debugging macros
949 //---------------------------------------------------------------------------
951 #define MAX_ERROR_TEXT_LEN 160
952 #include "wx/log.h" //wxLogDebug et al.
954 //Get the error string for Active Movie
955 wxString
wxAMMediaBackend::GetErrorString(HRESULT hrdsv
)
957 wxChar szError
[MAX_ERROR_TEXT_LEN
];
958 if( m_lpAMGetErrorText
!= NULL
&&
959 (*m_lpAMGetErrorText
)(hrdsv
, szError
, MAX_ERROR_TEXT_LEN
) == 0)
961 return wxString::Format(wxT("DirectShow error \"%s\" \n")
962 wxT("(numeric %i)\n")
963 wxT("occured at line %i in ")
964 wxT("mediactrl.cpp"),
965 szError
, (int)hrdsv
, __LINE__
);
969 return wxString::Format(wxT("Unknown error (%i) ")
971 wxT(" line %i in mediactrl.cpp."),
972 (int)hrdsv
, __LINE__
);
976 #define wxAMFAIL(x) wxFAIL_MSG(GetErrorString(x));
977 #define wxVERIFY(x) wxASSERT((x))
978 #define wxAMLOG(x) wxLogDebug(GetErrorString(x))
980 #define wxAMVERIFY(x) (x)
981 #define wxVERIFY(x) (x)
986 //---------------------------------------------------------------------------
987 // Standard macros for ease of use
988 //---------------------------------------------------------------------------
989 #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
991 //---------------------------------------------------------------------------
992 // wxAMMediaBackend Constructor
994 // Sets m_hNotifyWnd to NULL to signify that we haven't loaded anything yet
995 //---------------------------------------------------------------------------
996 wxAMMediaBackend::wxAMMediaBackend()
997 :m_state(wxMEDIASTATE_STOPPED
)
1011 //---------------------------------------------------------------------------
1012 // wxAMMediaBackend Destructor
1014 // Cleans up everything
1015 //---------------------------------------------------------------------------
1016 wxAMMediaBackend::~wxAMMediaBackend()
1022 ::FreeLibrary(m_hQuartzDll
);
1026 //---------------------------------------------------------------------------
1027 // wxAMMediaBackend::CreateControl
1029 // 1) Check to see if Active Movie supports windowless controls
1030 // 2) Connect events to the media control and its TLW
1031 //---------------------------------------------------------------------------
1032 bool wxAMMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
1037 const wxValidator
& validator
,
1038 const wxString
& name
)
1041 m_hQuartzDll
= ::LoadLibrary(wxT("quartz.dll"));
1044 m_lpAMGetErrorText
= (LPAMGETERRORTEXT
) ::GetProcAddress(
1046 wxString::Format(wxT("AMGetErrorText%s"),
1048 #ifdef __WXUNICODE__
1056 ).mb_str(wxConvLocal
)
1062 //Make sure a valid windowless video mixing interface exists
1064 if( ::CoCreateInstance(CLSID_FilgraphManager
, NULL
,
1065 CLSCTX_INPROC_SERVER
,
1066 IID_IGraphBuilder
, (void**)&pGB
) != 0 )
1069 if( !SetWindowlessMode(pGB
) )
1077 // By default wxWindow(s) is created with a border -
1078 // so we need to get rid of those, and create with
1079 // wxCLIP_CHILDREN, so that if the driver/backend
1080 // is a child window, it refreshes properly
1082 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
1083 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
| wxCLIP_CHILDREN
,
1087 // My problem with this was only with a previous patch, probably the third rewrite
1088 // fixed it as a side-effect. In fact, the erase background style of drawing not
1089 // only works now, but is much better than paint-based updates (the paint event
1090 // handler flickers if the wxMediaCtrl shares a sizer with another child window,
1091 // or is on a notebook)
1093 ctrl
->Connect(ctrl
->GetId(), wxEVT_ERASE_BACKGROUND
,
1094 wxEraseEventHandler(wxAMMediaEvtHandler::OnEraseBackground
),
1095 NULL
, (wxEvtHandler
*) this);
1104 //---------------------------------------------------------------------------
1105 // wxAMMediaBackend::SetWindowlessMode
1107 // Adds a Video Mixing Renderer to a Filter Graph and obtains the
1108 // windowless control from it
1109 //---------------------------------------------------------------------------
1110 bool wxAMMediaBackend::SetWindowlessMode(IGraphBuilder
* pGB
,
1111 IVMRWindowlessControl
** ppVMC
)
1116 // Create and add a custom Video Mixing Render to the graph
1119 if( ::CoCreateInstance(CLSID_VideoMixingRenderer
, NULL
,
1120 CLSCTX_INPROC_SERVER
, IID_IBaseFilter
, (void**)&pVMR
) != 0 )
1123 hr
= pGB
->AddFilter(pVMR
, L
"Video Mixing Renderer");
1132 // Set the graph to windowless mode
1134 IVMRFilterConfig
* pConfig
;
1135 hr
= pVMR
->QueryInterface(IID_IVMRFilterConfig
, (void**)&pConfig
);
1143 hr
= pConfig
->SetRenderingMode(2);
1144 if( hr
!= 0) //2 == VMRMode_Windowless
1155 // Obtain the windowless control
1157 IVMRWindowlessControl
* pVMC
;
1158 hr
= pVMR
->QueryInterface(IID_IVMRWindowlessControl
, (void**)&pVMC
);
1178 //---------------------------------------------------------------------------
1179 // wxAMMediaBackend::Load (file version)
1181 // 1) Cleans up previously loaded data
1182 // 2) Creates a filter graph
1183 // 3) Add a video mixer, set the graph to windowless mode and clip
1184 // output to our media control
1185 // 4) Query interfaces to use later
1186 // 5) Get native video size (which becomes our best size)
1187 // 6) Refresh parent's sizers
1188 // 7) Start event/rendering thread
1189 //---------------------------------------------------------------------------
1190 bool wxAMMediaBackend::Load(const wxString
& fileName
)
1194 //if previously loaded cleanup
1198 //Create interfaces - we already checked for success in CreateControl
1199 ::CoCreateInstance(CLSID_FilgraphManager
, NULL
, CLSCTX_INPROC_SERVER
,
1200 IID_IGraphBuilder
, (void**)&m_pGB
);
1203 // Set and clip output
1204 SetWindowlessMode(m_pGB
, &m_pVMC
);
1205 hr
= m_pVMC
->SetVideoClippingWindow((HWND
)m_ctrl
->GetHandle());
1209 m_bestSize
.x
= m_bestSize
.y
= 0;
1214 //load the graph & render
1215 if( m_pGB
->RenderFile(fileName
.wc_str(wxConvLocal
), NULL
) != 0 )
1219 //Get the interfaces, all of them
1221 hr
= m_pGB
->QueryInterface(IID_IMediaEvent
, (void**)&m_pME
);
1228 hr
= m_pGB
->QueryInterface(IID_IMediaControl
, (void**)&m_pMC
);
1235 hr
= m_pGB
->QueryInterface(IID_IMediaPosition
, (void**)&m_pMS
);
1242 hr
= m_pGB
->QueryInterface(IID_IBasicAudio
, (void**)&m_pBA
);
1250 // Get original video size
1252 hr
= m_pVMC
->GetNativeVideoSize((LONG
*)&m_bestSize
.x
, (LONG
*)&m_bestSize
.y
,
1256 m_bestSize
.x
= m_bestSize
.y
= 0;
1261 if(m_bestSize
.x
== 0 && m_bestSize
.y
== 0)
1267 // Force the parent window of this control to recalculate
1268 // the size of this if sizers are being used
1269 // and render the results immediately
1271 m_ctrl
->InvalidateBestSize();
1272 m_ctrl
->GetParent()->Layout();
1273 m_ctrl
->GetParent()->Refresh();
1274 m_ctrl
->GetParent()->Update();
1275 m_ctrl
->SetSize(m_ctrl
->GetSize());
1278 // Create the event thread
1280 m_pThread
= new wxAMMediaThread
;
1281 m_pThread
->pThis
= this;
1282 m_pThread
->Create();
1291 //---------------------------------------------------------------------------
1292 // wxAMMediaBackend::Load (URL Version)
1294 // Loads media from a URL. Interestingly enough DirectShow
1295 // appears (?) to escape the URL for us, at least on normal
1297 //---------------------------------------------------------------------------
1298 bool wxAMMediaBackend::Load(const wxURI
& location
)
1300 return Load(location
.BuildUnescapedURI());
1303 //---------------------------------------------------------------------------
1304 // wxAMMediaBackend::Cleanup
1306 // Releases all the directshow interfaces we use
1307 // TODO: Maybe only create one instance of IAMMultiMediaStream and reuse it
1308 // rather than recreating it each time?
1309 //---------------------------------------------------------------------------
1310 void wxAMMediaBackend::Cleanup()
1312 // RN: This could be a bad ptr if load failed after
1313 // m_pVMC was created
1316 m_pThread
->Delete();
1320 // Release and zero DirectShow interfaces
1321 SAFE_RELEASE(m_pMC
);
1322 SAFE_RELEASE(m_pME
);
1323 SAFE_RELEASE(m_pMS
);
1324 SAFE_RELEASE(m_pBA
);
1325 SAFE_RELEASE(m_pGB
);
1326 SAFE_RELEASE(m_pVMC
);
1330 //---------------------------------------------------------------------------
1331 // wxAMMediaBackend::Play
1333 // Plays the stream. If it is non-seekable, it will restart it (implicit).
1335 // Note that we use SUCCEEDED here because run/pause/stop tend to be overly
1336 // picky and return warnings on pretty much every call
1337 //---------------------------------------------------------------------------
1338 bool wxAMMediaBackend::Play()
1340 wxCriticalSectionLocker
lock(m_rendercs
);
1342 if( SUCCEEDED(m_pMC
->Run()) )
1344 m_state
= wxMEDIASTATE_PLAYING
;
1345 m_ctrl
->Refresh(); //videoless control finicky about refreshing
1352 //---------------------------------------------------------------------------
1353 // wxAMMediaBackend::Pause
1355 // Pauses the stream.
1356 //---------------------------------------------------------------------------
1357 bool wxAMMediaBackend::Pause()
1359 wxCriticalSectionLocker
lock(m_rendercs
);
1361 if( SUCCEEDED(m_pMC
->Pause()) )
1363 m_state
= wxMEDIASTATE_PAUSED
;
1370 //---------------------------------------------------------------------------
1371 // wxAMMediaBackend::Stop
1373 // Stops the stream.
1374 //---------------------------------------------------------------------------
1375 bool wxAMMediaBackend::Stop()
1377 wxCriticalSectionLocker
lock(m_rendercs
);
1379 if( SUCCEEDED(m_pMC
->Stop()) )
1381 //We don't care if it can't get to the beginning in directshow -
1382 //it could be a non-seeking filter (wince midi) in which case playing
1383 //starts all over again
1384 wxAMMediaBackend::SetPosition(0);
1386 m_state
= wxMEDIASTATE_STOPPED
;
1393 //---------------------------------------------------------------------------
1394 // wxAMMediaBackend::SetPosition
1396 // 1) Translates the current position's time to directshow time,
1397 // which is in a scale of 1 second (in a double)
1398 // 2) Sets the play position of the IMediaSeeking interface -
1399 // passing NULL as the stop position means to keep the old
1401 //---------------------------------------------------------------------------
1402 bool wxAMMediaBackend::SetPosition(wxLongLong where
)
1404 HRESULT hr
= m_pMS
->put_CurrentPosition(
1405 ((LONGLONG
)where
.GetValue()) / 1000.0
1416 //---------------------------------------------------------------------------
1417 // wxAMMediaBackend::GetPosition
1419 // 1) Obtains the current play and stop positions from IMediaSeeking
1420 // 2) Returns the play position translated to our time base
1421 //---------------------------------------------------------------------------
1422 wxLongLong
wxAMMediaBackend::GetPosition()
1425 HRESULT hr
= m_pMS
->get_CurrentPosition(&outCur
);
1432 //h,m,s,milli - outdur is in 1 second (double)
1440 //---------------------------------------------------------------------------
1441 // wxAMMediaBackend::GetVolume
1443 // Gets the volume through the IBasicAudio interface -
1444 // value ranges from 0 (MAX volume) to -10000 (minimum volume).
1445 // -100 per decibel.
1446 //---------------------------------------------------------------------------
1447 double wxAMMediaBackend::GetVolume()
1452 HRESULT hr
= m_pBA
->get_Volume(&lVolume
);
1459 return (((double)(lVolume
+ 10000)) / 10000.0);
1462 wxLogDebug(wxT("No directshow audio interface"));
1466 //---------------------------------------------------------------------------
1467 // wxAMMediaBackend::SetVolume
1469 // Sets the volume through the IBasicAudio interface -
1470 // value ranges from 0 (MAX volume) to -10000 (minimum volume).
1471 // -100 per decibel.
1472 //---------------------------------------------------------------------------
1473 bool wxAMMediaBackend::SetVolume(double dVolume
)
1477 HRESULT hr
= m_pBA
->put_Volume( (long) ((dVolume
-1.0) * 10000.0) );
1486 wxLogDebug(wxT("No directshow audio interface"));
1490 //---------------------------------------------------------------------------
1491 // wxAMMediaBackend::GetDuration
1493 // 1) Obtains the duration of the media from IAMMultiMediaStream
1494 // 2) Converts that value to our time base, and returns it
1496 // NB: With VBR MP3 files the default DirectShow MP3 render does not
1497 // read the Xing header correctly, resulting in skewed values for duration
1499 //---------------------------------------------------------------------------
1500 wxLongLong
wxAMMediaBackend::GetDuration()
1503 HRESULT hr
= m_pMS
->get_Duration(&outDuration
);
1510 //h,m,s,milli - outdur is in 1 second (double)
1511 outDuration
*= 1000;
1513 ll
.Assign(outDuration
);
1518 //---------------------------------------------------------------------------
1519 // wxAMMediaBackend::GetState
1521 // Returns the cached state
1522 //---------------------------------------------------------------------------
1523 wxMediaState
wxAMMediaBackend::GetState()
1528 //---------------------------------------------------------------------------
1529 // wxAMMediaBackend::GetPlaybackRate
1531 // Pretty simple way of obtaining the playback rate from
1532 // the IMediaSeeking interface
1533 //---------------------------------------------------------------------------
1534 double wxAMMediaBackend::GetPlaybackRate()
1537 HRESULT hr
= m_pMS
->get_Rate(&dRate
);
1546 //---------------------------------------------------------------------------
1547 // wxAMMediaBackend::SetPlaybackRate
1549 // Sets the playback rate of the media - DirectShow is pretty good
1550 // about this, actually
1551 //---------------------------------------------------------------------------
1552 bool wxAMMediaBackend::SetPlaybackRate(double dRate
)
1554 HRESULT hr
= m_pMS
->put_Rate(dRate
);
1564 //---------------------------------------------------------------------------
1565 // wxAMMediaBackend::GetVideoSize
1567 // Obtains the cached original video size
1568 //---------------------------------------------------------------------------
1569 wxSize
wxAMMediaBackend::GetVideoSize() const
1574 //---------------------------------------------------------------------------
1575 // wxAMMediaBackend::Move
1577 // We take care of this in our redrawing
1578 //---------------------------------------------------------------------------
1579 void wxAMMediaBackend::Move(int WXUNUSED(x
), int WXUNUSED(y
),
1582 //don't use deferred positioning on windows
1583 if(m_pVMC
&& m_bVideo
)
1585 RECT srcRect
, destRect
;
1587 //portion of video to display in window
1588 srcRect
.top
= 0; srcRect
.left
= 0;
1589 srcRect
.bottom
= m_bestSize
.y
; srcRect
.right
= m_bestSize
.x
;
1601 //position in window client coordinates to display and stretch to
1602 destRect
.top
= 0; destRect
.left
= 0;
1603 destRect
.bottom
= h
; destRect
.right
= w
;
1605 //set the windowless control positions
1606 HRESULT hr
= m_pVMC
->SetVideoPosition(&srcRect
, &destRect
);
1614 //---------------------------------------------------------------------------
1615 // wxAMMediaThread::Entry
1617 // Render the current movie frame
1618 //---------------------------------------------------------------------------
1619 wxThread::ExitCode
wxAMMediaThread::Entry()
1621 while(!TestDestroy())
1628 // DirectShow keeps a list of queued events, and we need
1629 // to go through them one by one, stopping at (Hopefully only one)
1630 // EC_COMPLETE message
1632 while( pThis
->m_pME
->GetEvent(&evCode
, (LONG_PTR
*) &evParam1
,
1633 (LONG_PTR
*) &evParam2
, 0) == 0 )
1635 // Cleanup memory that GetEvent allocated
1636 HRESULT hr
= pThis
->m_pME
->FreeEventParams(evCode
,
1637 evParam1
, evParam2
);
1640 //Even though this makes a messagebox this
1641 //is windows where we can do gui stuff in seperate
1643 wxFAIL_MSG(pThis
->GetErrorString(hr
));
1645 // If this is the end of the clip, notify handler
1646 else if(1 == evCode
) //EC_COMPLETE
1659 //---------------------------------------------------------------------------
1660 // wxAMMediaBackend::OnStop
1662 // Handle stopping when the stream ends
1663 //---------------------------------------------------------------------------
1664 void wxAMMediaBackend::OnStop()
1666 //send the event to our child
1667 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
, m_ctrl
->GetId());
1668 m_ctrl
->ProcessEvent(theEvent
);
1670 //if the user didn't veto it, stop the stream
1671 if (theEvent
.IsAllowed())
1673 //Interestingly enough, DirectShow does not actually stop
1674 //the filters - even when it reaches the end!
1677 //send the event to our child
1678 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
1680 m_ctrl
->ProcessEvent(theEvent
);
1684 //---------------------------------------------------------------------------
1685 // wxAMMediaEvtHandler::OnEraseBackground
1687 // Tell WX not to erase the background of our control window
1688 //---------------------------------------------------------------------------
1689 void wxAMMediaEvtHandler::OnEraseBackground(wxEraseEvent
& evt
)
1691 wxAMMediaBackend
* pThis
= (wxAMMediaBackend
*) this;
1692 if(pThis
->m_pVMC
&& pThis
->m_bVideo
)
1694 //TODO: Use wxClientDC?
1695 HDC hdc
= ::GetDC((HWND
)pThis
->m_ctrl
->GetHandle());
1696 HRESULT hr
= pThis
->m_pVMC
->RepaintVideo((HWND
)pThis
->m_ctrl
->GetHandle(),
1700 wxFAIL_MSG(pThis
->GetErrorString(hr
));
1702 ::ReleaseDC((HWND
)pThis
->m_ctrl
->GetHandle(), hdc
);
1710 //---------------------------------------------------------------------------
1711 // End of wxAMMediaBackend
1712 //---------------------------------------------------------------------------
1714 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1716 // wxMCIMediaBackend
1718 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1720 IMPLEMENT_DYNAMIC_CLASS(wxMCIMediaBackend
, wxMediaBackend
);
1722 //---------------------------------------------------------------------------
1723 // Usual debugging macros for MCI returns
1724 //---------------------------------------------------------------------------
1727 #define wxMCIVERIFY(arg) \
1730 if ( (nRet = (arg)) != 0) \
1733 mciGetErrorString(nRet, sz, 5000); \
1734 wxFAIL_MSG(wxString::Format(_T("MCI Error:%s"), sz)); \
1738 #define wxMCIVERIFY(arg) (arg);
1741 //---------------------------------------------------------------------------
1742 // Simulation for <digitalv.h>
1744 // Mingw and possibly other compilers don't have the digitalv.h header
1745 // that is needed to have some essential features of mci work with
1746 // windows - so we provide the declarations for the types we use here
1747 //---------------------------------------------------------------------------
1750 DWORD_PTR dwCallback
;
1751 #ifdef MCI_USE_OFFEXT
1757 } MCI_DGV_RECT_PARMS
;
1760 DWORD_PTR dwCallback
;
1770 } MCI_DGV_WINDOW_PARMS
;
1773 DWORD_PTR dwCallback
;
1778 } MCI_DGV_SET_PARMS
;
1781 DWORD_PTR dwCallback
;
1785 wxChar
* lpstrAlgorithm
;
1786 wxChar
* lpstrQuality
;
1787 } MCI_DGV_SETAUDIO_PARMS
;
1789 //---------------------------------------------------------------------------
1790 // wxMCIMediaBackend Constructor
1792 // Here we don't need to do much except say we don't have any video :)
1793 //---------------------------------------------------------------------------
1794 wxMCIMediaBackend::wxMCIMediaBackend() : m_hNotifyWnd(NULL
), m_bVideo(false)
1798 //---------------------------------------------------------------------------
1799 // wxMCIMediaBackend Destructor
1801 // We close the mci device - note that there may not be an mci device here,
1802 // or it may fail - but we don't really care, since we're destructing
1803 //---------------------------------------------------------------------------
1804 wxMCIMediaBackend::~wxMCIMediaBackend()
1808 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
1809 DestroyWindow(m_hNotifyWnd
);
1810 m_hNotifyWnd
= NULL
;
1814 //---------------------------------------------------------------------------
1815 // wxMCIMediaBackend::Create
1817 // Here we just tell wxMediaCtrl that mci does exist (which it does, on all
1818 // msw systems, at least in some form dating back to win16 days)
1819 //---------------------------------------------------------------------------
1820 bool wxMCIMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
1825 const wxValidator
& validator
,
1826 const wxString
& name
)
1830 // By default wxWindow(s) is created with a border -
1831 // so we need to get rid of those, and create with
1832 // wxCLIP_CHILDREN, so that if the driver/backend
1833 // is a child window, it refereshes properly
1835 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
1836 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
| wxCLIP_CHILDREN
,
1844 //---------------------------------------------------------------------------
1845 // wxMCIMediaBackend::Load (file version)
1847 // Here we have MCI load a file and device, set the time format to our
1848 // default (milliseconds), and set the video (if any) to play in the control
1849 //---------------------------------------------------------------------------
1850 bool wxMCIMediaBackend::Load(const wxString
& fileName
)
1853 //if the user already called load close the previous MCI device
1857 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
1858 DestroyWindow(m_hNotifyWnd
);
1859 m_hNotifyWnd
= NULL
;
1863 //Opens a file and has MCI select a device. Normally you'd put
1864 //MCI_OPEN_TYPE in addition to MCI_OPEN_ELEMENT - however if you
1865 //omit this it tells MCI to select the device instead. This is
1866 //good because we have no reliable way of "enumerating" the devices
1869 MCI_OPEN_PARMS openParms
;
1870 openParms
.lpstrElementName
= (wxChar
*) fileName
.c_str();
1872 if ( mciSendCommand(0, MCI_OPEN
, MCI_OPEN_ELEMENT
,
1873 (DWORD
)(LPVOID
)&openParms
) != 0)
1876 m_hDev
= openParms
.wDeviceID
;
1879 //Now set the time format for the device to milliseconds
1881 MCI_SET_PARMS setParms
;
1882 setParms
.dwCallback
= 0;
1883 setParms
.dwTimeFormat
= MCI_FORMAT_MILLISECONDS
;
1885 if (mciSendCommand(m_hDev
, MCI_SET
, MCI_SET_TIME_FORMAT
,
1886 (DWORD
)(LPVOID
)&setParms
) != 0)
1890 //Now tell the MCI device to display the video in our wxMediaCtrl
1892 MCI_DGV_WINDOW_PARMS windowParms
;
1893 windowParms
.hWnd
= (HWND
)m_ctrl
->GetHandle();
1895 m_bVideo
= (mciSendCommand(m_hDev
, MCI_WINDOW
,
1896 0x00010000L
, //MCI_DGV_WINDOW_HWND
1897 (DWORD
)(LPVOID
)&windowParms
) == 0);
1900 // Create a hidden window and register to handle
1902 // Note that wxCanvasClassName is already registered
1903 // and used by all wxWindows and normal wxControls
1905 m_hNotifyWnd
= ::CreateWindow
1919 wxLogSysError( wxT("Could not create hidden needed for ")
1920 wxT("registering for DirectShow events!") );
1925 wxSetWindowProc(m_hNotifyWnd
, wxMCIMediaBackend::NotifyWndProc
);
1927 ::SetWindowLong(m_hNotifyWnd
, GWL_USERDATA
,
1931 //Here, if the parent of the control has a sizer - we
1932 //tell it to recalculate the size of this control since
1933 //the user opened a separate media file
1935 m_ctrl
->InvalidateBestSize();
1936 m_ctrl
->GetParent()->Layout();
1937 m_ctrl
->GetParent()->Refresh();
1938 m_ctrl
->GetParent()->Update();
1939 m_ctrl
->SetSize(m_ctrl
->GetSize());
1944 //---------------------------------------------------------------------------
1945 // wxMCIMediaBackend::Load (URL version)
1947 // MCI doesn't support URLs directly (?)
1949 // TODO: Use wxURL/wxFileSystem and mmioInstallProc
1950 //---------------------------------------------------------------------------
1951 bool wxMCIMediaBackend::Load(const wxURI
& WXUNUSED(location
))
1956 //---------------------------------------------------------------------------
1957 // wxMCIMediaBackend::Play
1959 // Plays/Resumes the MCI device... a couple notes:
1960 // 1) Certain drivers will crash and burn if we don't pass them an
1961 // MCI_PLAY_PARMS, despite the documentation that says otherwise...
1962 // 2) There is a MCI_RESUME command, but MCI_PLAY does the same thing
1963 // and will resume from a stopped state also, so there's no need to
1964 // call both, for example
1965 //---------------------------------------------------------------------------
1966 bool wxMCIMediaBackend::Play()
1968 MCI_PLAY_PARMS playParms
;
1969 playParms
.dwCallback
= (DWORD
)m_hNotifyWnd
;
1971 bool bOK
= ( mciSendCommand(m_hDev
, MCI_PLAY
, MCI_NOTIFY
,
1972 (DWORD
)(LPVOID
)&playParms
) == 0 );
1975 m_ctrl
->Show(m_bVideo
);
1980 //---------------------------------------------------------------------------
1981 // wxMCIMediaBackend::Pause
1983 // Pauses the MCI device - nothing special
1984 //---------------------------------------------------------------------------
1985 bool wxMCIMediaBackend::Pause()
1987 return (mciSendCommand(m_hDev
, MCI_PAUSE
, MCI_WAIT
, 0) == 0);
1990 //---------------------------------------------------------------------------
1991 // wxMCIMediaBackend::Stop
1993 // Stops the MCI device & seeks to the beginning as wxMediaCtrl docs outline
1994 //---------------------------------------------------------------------------
1995 bool wxMCIMediaBackend::Stop()
1997 return (mciSendCommand(m_hDev
, MCI_STOP
, MCI_WAIT
, 0) == 0) &&
1998 (mciSendCommand(m_hDev
, MCI_SEEK
, MCI_SEEK_TO_START
, 0) == 0);
2001 //---------------------------------------------------------------------------
2002 // wxMCIMediaBackend::GetState
2004 // Here we get the state and convert it to a wxMediaState -
2005 // since we use direct comparisons with MCI_MODE_PLAY and
2006 // MCI_MODE_PAUSE, we don't care if the MCI_STATUS call
2008 //---------------------------------------------------------------------------
2009 wxMediaState
wxMCIMediaBackend::GetState()
2011 MCI_STATUS_PARMS statusParms
;
2012 statusParms
.dwItem
= MCI_STATUS_MODE
;
2014 mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2015 (DWORD
)(LPVOID
)&statusParms
);
2017 if(statusParms
.dwReturn
== MCI_MODE_PAUSE
)
2018 return wxMEDIASTATE_PAUSED
;
2019 else if(statusParms
.dwReturn
== MCI_MODE_PLAY
)
2020 return wxMEDIASTATE_PLAYING
;
2022 return wxMEDIASTATE_STOPPED
;
2025 //---------------------------------------------------------------------------
2026 // wxMCIMediaBackend::SetPosition
2028 // Here we set the position of the device in the stream.
2029 // Note that MCI actually stops the device after you seek it if the
2030 // device is playing/paused, so we need to play the file after
2031 // MCI seeks like normal APIs would
2032 //---------------------------------------------------------------------------
2033 bool wxMCIMediaBackend::SetPosition(wxLongLong where
)
2035 MCI_SEEK_PARMS seekParms
;
2036 seekParms
.dwCallback
= 0;
2037 #if wxUSE_LONGLONG_NATIVE && !wxUSE_LONGLONG_WX
2038 seekParms
.dwTo
= (DWORD
)where
.GetValue();
2039 #else /* wxUSE_LONGLONG_WX */
2040 /* no way to return it in one piece */
2041 wxASSERT( where
.GetHi()==0 );
2042 seekParms
.dwTo
= (DWORD
)where
.GetLo();
2043 #endif /* wxUSE_LONGLONG_* */
2045 //device was playing?
2046 bool bReplay
= GetState() == wxMEDIASTATE_PLAYING
;
2048 if( mciSendCommand(m_hDev
, MCI_SEEK
, MCI_TO
,
2049 (DWORD
)(LPVOID
)&seekParms
) != 0)
2052 //If the device was playing, resume it
2059 //---------------------------------------------------------------------------
2060 // wxMCIMediaBackend::GetPosition
2062 // Gets the position of the device in the stream using the current
2063 // time format... nothing special here...
2064 //---------------------------------------------------------------------------
2065 wxLongLong
wxMCIMediaBackend::GetPosition()
2067 MCI_STATUS_PARMS statusParms
;
2068 statusParms
.dwItem
= MCI_STATUS_POSITION
;
2070 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2071 (DWORD
)(LPSTR
)&statusParms
) != 0)
2074 return statusParms
.dwReturn
;
2077 //---------------------------------------------------------------------------
2078 // wxMCIMediaBackend::GetVolume
2080 // Gets the volume of the current media via the MCI_DGV_STATUS_VOLUME
2081 // message. Value ranges from 0 (minimum) to 1000 (maximum volume).
2082 //---------------------------------------------------------------------------
2083 double wxMCIMediaBackend::GetVolume()
2085 MCI_STATUS_PARMS statusParms
;
2086 statusParms
.dwCallback
= 0;
2087 statusParms
.dwItem
= 0x4019; //MCI_DGV_STATUS_VOLUME
2089 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2090 (DWORD
)(LPSTR
)&statusParms
) != 0)
2093 return ((double)statusParms
.dwReturn
) / 1000.0;
2096 //---------------------------------------------------------------------------
2097 // wxMCIMediaBackend::SetVolume
2099 // Sets the volume of the current media via the MCI_DGV_SETAUDIO_VOLUME
2100 // message. Value ranges from 0 (minimum) to 1000 (maximum volume).
2101 //---------------------------------------------------------------------------
2102 bool wxMCIMediaBackend::SetVolume(double dVolume
)
2104 MCI_DGV_SETAUDIO_PARMS audioParms
;
2105 audioParms
.dwCallback
= 0;
2106 audioParms
.dwItem
= 0x4002; //MCI_DGV_SETAUDIO_VOLUME
2107 audioParms
.dwValue
= (DWORD
) (dVolume
* 1000.0);
2108 audioParms
.dwOver
= 0;
2109 audioParms
.lpstrAlgorithm
= NULL
;
2110 audioParms
.lpstrQuality
= NULL
;
2112 if (mciSendCommand(m_hDev
, 0x0873, //MCI_SETAUDIO
2113 0x00800000L
| 0x01000000L
, //MCI_DGV_SETAUDIO+(_ITEM | _VALUE)
2114 (DWORD
)(LPSTR
)&audioParms
) != 0)
2119 //---------------------------------------------------------------------------
2120 // wxMCIMediaBackend::GetDuration
2122 // Gets the duration of the stream... nothing special
2123 //---------------------------------------------------------------------------
2124 wxLongLong
wxMCIMediaBackend::GetDuration()
2126 MCI_STATUS_PARMS statusParms
;
2127 statusParms
.dwItem
= MCI_STATUS_LENGTH
;
2129 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2130 (DWORD
)(LPSTR
)&statusParms
) != 0)
2133 return statusParms
.dwReturn
;
2136 //---------------------------------------------------------------------------
2137 // wxMCIMediaBackend::Move
2139 // Moves the window to a location
2140 //---------------------------------------------------------------------------
2141 void wxMCIMediaBackend::Move(int WXUNUSED(x
), int WXUNUSED(y
),
2144 if (m_hNotifyWnd
&& m_bVideo
)
2146 MCI_DGV_RECT_PARMS putParms
; //ifdefed MCI_DGV_PUT_PARMS
2147 memset(&putParms
, 0, sizeof(MCI_DGV_RECT_PARMS
));
2148 putParms
.rc
.bottom
= h
;
2149 putParms
.rc
.right
= w
;
2151 //wxStackWalker will crash and burn here on assert
2152 //and mci doesn't like 0 and 0 for some reason (out of range )
2153 //so just don't it in that case
2156 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_PUT
,
2157 0x00040000L
, //MCI_DGV_PUT_DESTINATION
2158 (DWORD
)(LPSTR
)&putParms
) );
2163 //---------------------------------------------------------------------------
2164 // wxMCIMediaBackend::GetVideoSize
2166 // Gets the original size of the movie for sizers
2167 //---------------------------------------------------------------------------
2168 wxSize
wxMCIMediaBackend::GetVideoSize() const
2172 MCI_DGV_RECT_PARMS whereParms
; //ifdefed MCI_DGV_WHERE_PARMS
2174 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_WHERE
,
2175 0x00020000L
, //MCI_DGV_WHERE_SOURCE
2176 (DWORD
)(LPSTR
)&whereParms
) );
2178 return wxSize(whereParms
.rc
.right
, whereParms
.rc
.bottom
);
2183 //---------------------------------------------------------------------------
2184 // wxMCIMediaBackend::GetPlaybackRate
2187 //---------------------------------------------------------------------------
2188 double wxMCIMediaBackend::GetPlaybackRate()
2193 //---------------------------------------------------------------------------
2194 // wxMCIMediaBackend::SetPlaybackRate
2197 //---------------------------------------------------------------------------
2198 bool wxMCIMediaBackend::SetPlaybackRate(double WXUNUSED(dRate
))
2201 MCI_WAVE_SET_SAMPLESPERSEC
2202 MCI_DGV_SET_PARMS setParms;
2203 setParms.dwSpeed = (DWORD) (dRate * 1000.0);
2205 return (mciSendCommand(m_hDev, MCI_SET,
2206 0x00020000L, //MCI_DGV_SET_SPEED
2207 (DWORD)(LPSTR)&setParms) == 0);
2212 //---------------------------------------------------------------------------
2213 // [static] wxMCIMediaBackend::MSWWindowProc
2215 // Here we process a message when MCI reaches the stopping point
2217 //---------------------------------------------------------------------------
2218 LRESULT CALLBACK
wxMCIMediaBackend::NotifyWndProc(HWND hWnd
, UINT nMsg
,
2222 wxMCIMediaBackend
* backend
= (wxMCIMediaBackend
*)
2224 ::GetWindowLong(hWnd
, GWL_USERDATA
);
2226 ::GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
2230 return backend
->OnNotifyWndProc(hWnd
, nMsg
, wParam
, lParam
);
2233 LRESULT CALLBACK
wxMCIMediaBackend::OnNotifyWndProc(HWND hWnd
, UINT nMsg
,
2237 if(nMsg
== MM_MCINOTIFY
)
2239 wxASSERT(lParam
== (LPARAM
) m_hDev
);
2240 if(wParam
== MCI_NOTIFY_SUCCESSFUL
&& lParam
== (LPARAM
)m_hDev
)
2242 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
, m_ctrl
->GetId());
2243 m_ctrl
->ProcessEvent(theEvent
);
2245 if(theEvent
.IsAllowed())
2247 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_SEEK
,
2248 MCI_SEEK_TO_START
, 0) );
2250 //send the event to our child
2251 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
2253 m_ctrl
->ProcessEvent(theEvent
);
2257 return DefWindowProc(hWnd
, nMsg
, wParam
, lParam
);
2259 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2263 // TODO: Use a less cludgy way to pause/get state/set state
2264 // TODO: Dynamically load from qtml.dll
2265 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2267 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
);
2269 //Time between timer calls
2270 #define MOVIE_DELAY 100
2272 #include "wx/timer.h"
2274 // --------------------------------------------------------------------------
2275 // wxQTTimer - Handle Asyncronous Playing
2276 // --------------------------------------------------------------------------
2277 class _wxQTTimer
: public wxTimer
2280 _wxQTTimer(Movie movie
, wxQTMediaBackend
* parent
, wxQuickTimeLibrary
* pLib
) :
2281 m_movie(movie
), m_bPaused(false), m_parent(parent
), m_pLib(pLib
)
2289 bool GetPaused() {return m_bPaused
;}
2290 void SetPaused(bool bPaused
) {m_bPaused
= bPaused
;}
2292 //-----------------------------------------------------------------------
2293 // _wxQTTimer::Notify
2295 // 1) Checks to see if the movie is done, and if not continues
2296 // streaming the movie
2297 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
2299 //-----------------------------------------------------------------------
2304 if(!m_pLib
->IsMovieDone(m_movie
))
2305 m_pLib
->MoviesTask(m_movie
, MOVIE_DELAY
);
2308 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
,
2309 m_parent
->m_ctrl
->GetId());
2310 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
2312 if(theEvent
.IsAllowed())
2316 wxASSERT(m_pLib
->GetMoviesError() == noErr
);
2318 //send the event to our child
2319 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
2320 m_parent
->m_ctrl
->GetId());
2321 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
2328 Movie m_movie
; //Our movie instance
2329 bool m_bPaused
; //Whether we are paused or not
2330 wxQTMediaBackend
* m_parent
; //Backend pointer
2331 wxQuickTimeLibrary
* m_pLib
; //Interfaces
2334 //---------------------------------------------------------------------------
2335 // wxQTMediaBackend Destructor
2337 // Sets m_timer to NULL signifying we havn't loaded anything yet
2338 //---------------------------------------------------------------------------
2339 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL
)
2343 //---------------------------------------------------------------------------
2344 // wxQTMediaBackend Destructor
2346 // 1) Cleans up the QuickTime movie instance
2347 // 2) Decrements the QuickTime reference counter - if this reaches
2348 // 0, QuickTime shuts down
2349 // 3) Decrements the QuickTime Windows Media Layer reference counter -
2350 // if this reaches 0, QuickTime shuts down the Windows Media Layer
2351 //---------------------------------------------------------------------------
2352 wxQTMediaBackend::~wxQTMediaBackend()
2359 //Note that ExitMovies() is not necessary, but
2360 //the docs are fuzzy on whether or not TerminateQTML is
2362 m_lib
.TerminateQTML();
2366 //---------------------------------------------------------------------------
2367 // wxQTMediaBackend::CreateControl
2369 // 1) Intializes QuickTime
2370 // 2) Creates the control window
2371 //---------------------------------------------------------------------------
2372 bool wxQTMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
2377 const wxValidator
& validator
,
2378 const wxString
& name
)
2380 if(!m_lib
.Initialize())
2383 int nError
= m_lib
.InitializeQTML(0);
2384 if (nError
!= noErr
) //-2093 no dll
2386 wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError
));
2389 m_lib
.EnterMovies();
2393 // By default wxWindow(s) is created with a border -
2394 // so we need to get rid of those
2396 // Since we don't have a child window like most other
2397 // backends, we don't need wxCLIP_CHILDREN
2399 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
2400 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
,
2408 //---------------------------------------------------------------------------
2409 // wxQTMediaBackend::Load (file version)
2411 // 1) Get an FSSpec from the Windows path name
2412 // 2) Open the movie
2413 // 3) Obtain the movie instance from the movie resource
2415 //---------------------------------------------------------------------------
2416 bool wxQTMediaBackend::Load(const wxString
& fileName
)
2421 short movieResFile
= 0; //= 0 because of annoying VC6 warning
2424 if (m_lib
.NativePathNameToFSSpec ((char*) (const char*) fileName
.mb_str(),
2425 &sfFile
, 0) != noErr
)
2428 if (m_lib
.OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
2431 short movieResID
= 0;
2434 OSErr err
= m_lib
.NewMovieFromFile (
2443 m_lib
.CloseMovieFile (movieResFile
);
2450 return m_lib
.GetMoviesError() == noErr
;
2453 //---------------------------------------------------------------------------
2454 // wxQTMediaBackend::Move
2457 //---------------------------------------------------------------------------
2458 bool wxQTMediaBackend::Load(const wxURI
& location
)
2463 wxString theURI
= location
.BuildURI();
2465 Handle theHandle
= m_lib
.NewHandleClear(theURI
.length() + 1);
2466 wxASSERT(theHandle
);
2468 m_lib
.BlockMove(theURI
.mb_str(), *theHandle
, theURI
.length() + 1);
2470 //create the movie from the handle that refers to the URI
2471 OSErr err
= m_lib
.NewMovieFromDataRef(&m_movie
, newMovieActive
,
2473 URLDataHandlerSubType
);
2475 m_lib
.DisposeHandle(theHandle
);
2480 //preroll movie for streaming
2485 timeNow = GetMovieTime(m_movie, NULL);
2486 playRate = GetMoviePreferredRate(m_movie);
2487 PrePrerollMovie(m_movie, timeNow, playRate, NULL, NULL);
2488 PrerollMovie(m_movie, timeNow, playRate);
2489 m_lib.SetMovieRate(m_movie, playRate);
2494 return m_lib
.GetMoviesError() == noErr
;
2497 //---------------------------------------------------------------------------
2498 // wxQTMediaBackend::Move
2501 //---------------------------------------------------------------------------
2502 void wxQTMediaBackend::FinishLoad()
2504 m_timer
= new _wxQTTimer(m_movie
, (wxQTMediaBackend
*) this, &m_lib
);
2507 //get the real size of the movie
2509 memset(&outRect
, 0, sizeof(Rect
)); //for annoying VC6 warning
2510 m_lib
.GetMovieNaturalBoundsRect (m_movie
, &outRect
);
2511 wxASSERT(m_lib
.GetMoviesError() == noErr
);
2513 m_bestSize
.x
= outRect
.right
- outRect
.left
;
2514 m_bestSize
.y
= outRect
.bottom
- outRect
.top
;
2516 //reparent movie/*AudioMediaCharacteristic*/
2517 if(m_lib
.GetMovieIndTrackType(m_movie
, 1,
2518 VisualMediaCharacteristic
,
2519 (1 << 1) //movieTrackCharacteristic
2520 | (1 << 2) //movieTrackEnabledOnly
2523 m_lib
.CreatePortAssociation(m_ctrl
->GetHWND(), NULL
, 0L);
2525 m_lib
.SetMovieGWorld(m_movie
,
2526 (CGrafPtr
) m_lib
.GetNativeWindowPort(m_ctrl
->GetHWND()),
2530 //we want millisecond precision
2531 m_lib
.SetMovieTimeScale(m_movie
, 1000);
2532 wxASSERT(m_lib
.GetMoviesError() == noErr
);
2535 //Here, if the parent of the control has a sizer - we
2536 //tell it to recalculate the size of this control since
2537 //the user opened a separate media file
2539 m_ctrl
->InvalidateBestSize();
2540 m_ctrl
->GetParent()->Layout();
2541 m_ctrl
->GetParent()->Refresh();
2542 m_ctrl
->GetParent()->Update();
2545 //---------------------------------------------------------------------------
2546 // wxQTMediaBackend::Move
2549 //---------------------------------------------------------------------------
2550 bool wxQTMediaBackend::Play()
2552 m_lib
.StartMovie(m_movie
);
2553 m_timer
->SetPaused(false);
2554 m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
2555 return m_lib
.GetMoviesError() == noErr
;
2558 //---------------------------------------------------------------------------
2559 // wxQTMediaBackend::Move
2562 //---------------------------------------------------------------------------
2563 bool wxQTMediaBackend::Pause()
2565 m_lib
.StopMovie(m_movie
);
2566 m_timer
->SetPaused(true);
2568 return m_lib
.GetMoviesError() == noErr
;
2571 //---------------------------------------------------------------------------
2572 // wxQTMediaBackend::Move
2575 //---------------------------------------------------------------------------
2576 bool wxQTMediaBackend::Stop()
2578 m_timer
->SetPaused(false);
2581 m_lib
.StopMovie(m_movie
);
2582 if(m_lib
.GetMoviesError() != noErr
)
2585 m_lib
.GoToBeginningOfMovie(m_movie
);
2586 return m_lib
.GetMoviesError() == noErr
;
2589 //---------------------------------------------------------------------------
2590 // wxQTMediaBackend::Move
2593 //---------------------------------------------------------------------------
2594 double wxQTMediaBackend::GetPlaybackRate()
2596 return ( ((double)m_lib
.GetMovieRate(m_movie
)) / 0x10000);
2599 //---------------------------------------------------------------------------
2600 // wxQTMediaBackend::Move
2603 //---------------------------------------------------------------------------
2604 bool wxQTMediaBackend::SetPlaybackRate(double dRate
)
2606 m_lib
.SetMovieRate(m_movie
, (Fixed
) (dRate
* 0x10000));
2607 return m_lib
.GetMoviesError() == noErr
;
2610 //---------------------------------------------------------------------------
2611 // wxQTMediaBackend::Move
2614 //---------------------------------------------------------------------------
2615 bool wxQTMediaBackend::SetPosition(wxLongLong where
)
2617 TimeRecord theTimeRecord
;
2618 memset(&theTimeRecord
, 0, sizeof(TimeRecord
));
2619 theTimeRecord
.value
.lo
= where
.GetLo();
2620 theTimeRecord
.scale
= m_lib
.GetMovieTimeScale(m_movie
);
2621 theTimeRecord
.base
= m_lib
.GetMovieTimeBase(m_movie
);
2622 m_lib
.SetMovieTime(m_movie
, &theTimeRecord
);
2624 if (m_lib
.GetMoviesError() != noErr
)
2630 //---------------------------------------------------------------------------
2631 // wxQTMediaBackend::GetPosition
2633 // 1) Calls GetMovieTime to get the position we are in in the movie
2634 // in milliseconds (we called
2635 //---------------------------------------------------------------------------
2636 wxLongLong
wxQTMediaBackend::GetPosition()
2638 return m_lib
.GetMovieTime(m_movie
, NULL
);
2641 //---------------------------------------------------------------------------
2642 // wxQTMediaBackend::GetVolume
2644 // Gets the volume through GetMovieVolume - which returns a 16 bit short -
2646 // +--------+--------+
2648 // +--------+--------+
2650 // (1) first 8 bits are value before decimal
2651 // (2) second 8 bits are value after decimal
2653 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
2654 // 1 (full gain and sound)
2655 //---------------------------------------------------------------------------
2656 double wxQTMediaBackend::GetVolume()
2658 short sVolume
= m_lib
.GetMovieVolume(m_movie
);
2660 if(sVolume
& (128 << 8)) //negative - no sound
2663 return (sVolume
& (127 << 8)) ? 1.0 : ((double)(sVolume
& 255)) / 255.0;
2666 //---------------------------------------------------------------------------
2667 // wxQTMediaBackend::SetVolume
2669 // Sets the volume through SetMovieVolume - which takes a 16 bit short -
2671 // +--------+--------+
2673 // +--------+--------+
2675 // (1) first 8 bits are value before decimal
2676 // (2) second 8 bits are value after decimal
2678 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
2679 // 1 (full gain and sound)
2680 //---------------------------------------------------------------------------
2681 bool wxQTMediaBackend::SetVolume(double dVolume
)
2683 short sVolume
= (short) (dVolume
>= .9999 ? 1 << 8 : (dVolume
* 255) );
2684 m_lib
.SetMovieVolume(m_movie
, sVolume
);
2688 //---------------------------------------------------------------------------
2689 // wxQTMediaBackend::Move
2692 //---------------------------------------------------------------------------
2693 wxLongLong
wxQTMediaBackend::GetDuration()
2695 return m_lib
.GetMovieDuration(m_movie
);
2698 //---------------------------------------------------------------------------
2699 // wxQTMediaBackend::Move
2702 //---------------------------------------------------------------------------
2703 wxMediaState
wxQTMediaBackend::GetState()
2705 if ( !m_timer
|| (m_timer
->IsRunning() == false &&
2706 m_timer
->GetPaused() == false) )
2707 return wxMEDIASTATE_STOPPED
;
2709 if( m_timer
->IsRunning() == true )
2710 return wxMEDIASTATE_PLAYING
;
2712 return wxMEDIASTATE_PAUSED
;
2715 //---------------------------------------------------------------------------
2716 // wxQTMediaBackend::Move
2719 //---------------------------------------------------------------------------
2720 void wxQTMediaBackend::Cleanup()
2725 m_lib
.StopMovie(m_movie
);
2726 m_lib
.DisposeMovie(m_movie
);
2729 //---------------------------------------------------------------------------
2730 // wxQTMediaBackend::Move
2733 //---------------------------------------------------------------------------
2734 wxSize
wxQTMediaBackend::GetVideoSize() const
2739 //---------------------------------------------------------------------------
2740 // wxQTMediaBackend::Move
2743 //---------------------------------------------------------------------------
2744 void wxQTMediaBackend::Move(int WXUNUSED(x
), int WXUNUSED(y
), int w
, int h
)
2748 Rect theRect
= {0, 0, (short)h
, (short)w
};
2750 m_lib
.SetMovieBox(m_movie
, &theRect
);
2751 wxASSERT(m_lib
.GetMoviesError() == noErr
);
2755 //---------------------------------------------------------------------------
2757 //---------------------------------------------------------------------------
2759 //in source file that contains stuff you don't directly use
2760 #include <wx/html/forcelnk.h>
2761 FORCE_LINK_ME(basewxmediabackends
);
2763 //---------------------------------------------------------------------------
2764 // End wxMediaCtrl Compilation Guard and this file
2765 //---------------------------------------------------------------------------
2766 #endif //wxUSE_MEDIACTRL