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 OnMove(wxMoveEvent
&);
524 void OnSize(wxSizeEvent
&);
525 void OnEraseBackground(wxEraseEvent
&);
528 typedef BOOL (WINAPI
* LPAMGETERRORTEXT
)(HRESULT
, wxChar
*, DWORD
);
530 class WXDLLIMPEXP_MEDIA wxAMMediaBackend
: public wxMediaBackend
535 virtual ~wxAMMediaBackend();
537 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
542 const wxValidator
& validator
,
543 const wxString
& name
);
546 virtual bool Pause();
549 virtual bool Load(const wxString
& fileName
);
550 virtual bool Load(const wxURI
& location
);
552 virtual wxMediaState
GetState();
554 virtual bool SetPosition(wxLongLong where
);
555 virtual wxLongLong
GetPosition();
556 virtual wxLongLong
GetDuration();
558 virtual void Move(int x
, int y
, int w
, int h
);
559 wxSize
GetVideoSize() const;
561 virtual double GetPlaybackRate();
562 virtual bool SetPlaybackRate(double);
564 virtual double GetVolume();
565 virtual bool SetVolume(double);
569 bool SetWindowlessMode(IGraphBuilder
* pGB
,
570 IVMRWindowlessControl
** ppVMC
= NULL
);
574 wxMediaState m_state
;
575 wxCriticalSection m_rendercs
;
577 IVMRWindowlessControl
* m_pVMC
;
578 IGraphBuilder
* m_pGB
;
580 IMediaControl
* m_pMC
;
582 IMediaPosition
* m_pMS
;
585 wxAMMediaThread
* m_pThread
;
590 HMODULE m_hQuartzDll
;
591 LPAMGETERRORTEXT m_lpAMGetErrorText
;
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) 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 if(!m_dll
.Load(wxT("qtmlClient.dll")))
837 wxDL_METHOD_LOAD( m_dll
, StartMovie
, bOk
);
838 wxDL_METHOD_LOAD( m_dll
, StopMovie
, bOk
);
839 wxDL_METHOD_LOAD( m_dll
, IsMovieDone
, bOk
);
840 wxDL_METHOD_LOAD( m_dll
, GoToBeginningOfMovie
, bOk
);
841 wxDL_METHOD_LOAD( m_dll
, GetMoviesError
, bOk
);
842 wxDL_METHOD_LOAD( m_dll
, EnterMovies
, bOk
);
843 wxDL_METHOD_LOAD( m_dll
, ExitMovies
, bOk
);
844 wxDL_METHOD_LOAD( m_dll
, InitializeQTML
, bOk
);
845 wxDL_METHOD_LOAD( m_dll
, TerminateQTML
, bOk
);
846 wxDL_METHOD_LOAD( m_dll
, NativePathNameToFSSpec
, bOk
);
847 wxDL_METHOD_LOAD( m_dll
, OpenMovieFile
, bOk
);
848 wxDL_METHOD_LOAD( m_dll
, CloseMovieFile
, bOk
);
849 wxDL_METHOD_LOAD( m_dll
, NewMovieFromFile
, bOk
);
850 wxDL_METHOD_LOAD( m_dll
, GetMovieRate
, bOk
);
851 wxDL_METHOD_LOAD( m_dll
, SetMovieRate
, bOk
);
852 wxDL_METHOD_LOAD( m_dll
, MoviesTask
, bOk
);
853 wxDL_METHOD_LOAD( m_dll
, BlockMove
, bOk
);
854 wxDL_METHOD_LOAD( m_dll
, NewHandleClear
, bOk
);
855 wxDL_METHOD_LOAD( m_dll
, NewMovieFromDataRef
, bOk
);
856 wxDL_METHOD_LOAD( m_dll
, DisposeHandle
, bOk
);
857 wxDL_METHOD_LOAD( m_dll
, GetMovieNaturalBoundsRect
, bOk
);
858 wxDL_METHOD_LOAD( m_dll
, GetMovieIndTrackType
, bOk
);
859 wxDL_METHOD_LOAD( m_dll
, CreatePortAssociation
, bOk
);
860 wxDL_METHOD_LOAD( m_dll
, GetNativeWindowPort
, bOk
);
861 wxDL_METHOD_LOAD( m_dll
, SetMovieGWorld
, bOk
);
862 wxDL_METHOD_LOAD( m_dll
, DisposeMovie
, bOk
);
863 wxDL_METHOD_LOAD( m_dll
, SetMovieBox
, bOk
);
864 wxDL_METHOD_LOAD( m_dll
, SetMovieTimeScale
, bOk
);
865 wxDL_METHOD_LOAD( m_dll
, GetMovieDuration
, bOk
);
866 wxDL_METHOD_LOAD( m_dll
, GetMovieTimeBase
, bOk
);
867 wxDL_METHOD_LOAD( m_dll
, GetMovieTimeScale
, bOk
);
868 wxDL_METHOD_LOAD( m_dll
, GetMovieTime
, bOk
);
869 wxDL_METHOD_LOAD( m_dll
, SetMovieTime
, bOk
);
870 wxDL_METHOD_LOAD( m_dll
, GetMovieVolume
, bOk
);
871 wxDL_METHOD_LOAD( m_dll
, SetMovieVolume
, bOk
);
878 class WXDLLIMPEXP_MEDIA wxQTMediaBackend
: public wxMediaBackend
884 virtual bool CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
889 const wxValidator
& validator
,
890 const wxString
& name
);
893 virtual bool Pause();
896 virtual bool Load(const wxString
& fileName
);
897 virtual bool Load(const wxURI
& location
);
899 virtual wxMediaState
GetState();
901 virtual bool SetPosition(wxLongLong where
);
902 virtual wxLongLong
GetPosition();
903 virtual wxLongLong
GetDuration();
905 virtual void Move(int x
, int y
, int w
, int h
);
906 wxSize
GetVideoSize() const;
908 virtual double GetPlaybackRate();
909 virtual bool SetPlaybackRate(double dRate
);
911 virtual double GetVolume();
912 virtual bool SetVolume(double);
917 wxSize m_bestSize
; //Original movie size
918 Movie m_movie
; //QT Movie handle/instance
919 wxControl
* m_ctrl
; //Parent control
920 bool m_bVideo
; //Whether or not we have video
921 class _wxQTTimer
* m_timer
; //Timer for streaming the movie
922 wxQuickTimeLibrary m_lib
;
924 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend
)
928 //===========================================================================
930 //===========================================================================
932 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
936 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
938 IMPLEMENT_DYNAMIC_CLASS(wxAMMediaBackend
, wxMediaBackend
);
940 //---------------------------------------------------------------------------
941 // Usual debugging macros
942 //---------------------------------------------------------------------------
944 #include "wx/msgdlg.h"
945 #define MAX_ERROR_TEXT_LEN 160
947 // FIXME : Just use wxASSERT_MSG here instead of msgdlg - but
948 // stackwalker still crashes win2k, so do msgdlg for now...
950 #define wxAMVERIFY(x) \
952 HRESULT hrdsv = (x); \
953 if ( FAILED(hrdsv) ) \
955 wxChar szError[MAX_ERROR_TEXT_LEN]; \
956 if( m_lpAMGetErrorText != NULL && \
957 (*m_lpAMGetErrorText)(hrdsv, szError, MAX_ERROR_TEXT_LEN) == 0) \
959 wxMessageBox( wxString::Format(wxT("DirectShow error \"%s\" \n")\
960 wxT("(numeric %i)\n")\
961 wxT("occured at line %i in ") \
962 wxT("mediactrl.cpp"), \
963 (int)hrdsv, szError, __LINE__) ); \
968 wxMessageBox( wxString::Format(wxT("Unknown error (%i) ") \
970 wxT(" line %i in mediactrl.cpp."), \
971 (int)hrdsv, __LINE__) ); \
976 #define wxVERIFY(x) wxASSERT((x))
978 #define wxAMVERIFY(x) (x)
979 #define wxVERIFY(x) (x)
982 //---------------------------------------------------------------------------
983 // Standard macros for ease of use
984 //---------------------------------------------------------------------------
985 #define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
987 //---------------------------------------------------------------------------
988 // wxAMMediaBackend Constructor
990 // Sets m_hNotifyWnd to NULL to signify that we haven't loaded anything yet
991 //---------------------------------------------------------------------------
992 wxAMMediaBackend::wxAMMediaBackend() : m_state(wxMEDIASTATE_STOPPED
),
1000 //---------------------------------------------------------------------------
1001 // wxAMMediaBackend Destructor
1003 // Cleans up everything
1004 //---------------------------------------------------------------------------
1005 wxAMMediaBackend::~wxAMMediaBackend()
1011 ::FreeLibrary(m_hQuartzDll
);
1015 //---------------------------------------------------------------------------
1016 // wxAMMediaBackend::CreateControl
1018 // 1) Check to see if Active Movie supports windowless controls
1019 // 2) Connect events to the media control and its TLW
1020 //---------------------------------------------------------------------------
1021 bool wxAMMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
1026 const wxValidator
& validator
,
1027 const wxString
& name
)
1030 m_hQuartzDll
= ::LoadLibrary(wxT("quartz.dll"));
1033 m_lpAMGetErrorText
= (LPAMGETERRORTEXT
) ::GetProcAddress(
1035 wxString::Format(wxT("AMGetErrorText%s"),
1037 #ifdef __WXUNICODE__
1045 ).mb_str(wxConvLocal
)
1051 //Make sure a valid windowless video mixing interface exists
1053 if( CoCreateInstance(CLSID_FilgraphManager
, NULL
,
1054 CLSCTX_INPROC_SERVER
,
1055 IID_IGraphBuilder
, (void**)&pGB
) != 0 )
1058 if( !SetWindowlessMode(pGB
) )
1066 // By default wxWindow(s) is created with a border -
1067 // so we need to get rid of those, and create with
1068 // wxCLIP_CHILDREN, so that if the driver/backend
1069 // is a child window, it refreshes properly
1071 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
1072 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
| wxCLIP_CHILDREN
,
1081 //TODO: Greg Hazel reports problems with this... but win2k seems fine on mine...
1082 //-------------------------------------------------------------------------------
1083 // My problem with this was only with a previous patch, probably the third rewrite
1084 // fixed it as a side-effect. In fact, the erase background style of drawing not
1085 // only works now, but is much better than paint-based updates (the paint event
1086 // handler flickers if the wxMediaCtrl shares a sizer with another child window,
1087 // or is on a notebook)
1089 m_ctrl
->Connect(m_ctrl
->GetId(), wxEVT_ERASE_BACKGROUND
,
1090 wxEraseEventHandler(wxAMMediaEvtHandler::OnEraseBackground
),
1091 NULL
, (wxEvtHandler
*) this);
1092 //m_ctrl->Connect(m_ctrl->GetId(), wxEVT_PAINT,
1093 // wxPaintEventHandler(wxAMMediaEvtHandler::OnPaint),
1094 // NULL, (wxEvtHandler*) this);
1097 // As noted below, we need to catch the Top Level Window's
1098 // move events because they are not sent to us if the media control
1099 // size remains the same but it actually moves in window coordinates
1101 wxWindow
* pTheTLW
= m_ctrl
->GetParent();
1102 while( pTheTLW
->GetParent() )
1103 pTheTLW
= pTheTLW
->GetParent();
1106 // FIXMEHACKFIXMEHACKFIXME
1107 // This is really nasty... basically the deal is not only above
1108 // but the repainting is messed up when the parent is maximized
1109 // too, so we've got to catch all 4 events!
1111 m_ctrl
->Connect(m_ctrl
->GetId(), wxEVT_MOVE
,
1112 wxMoveEventHandler(wxAMMediaEvtHandler::OnMove
),
1113 NULL
, (wxEvtHandler
*) this);
1114 m_ctrl
->Connect(m_ctrl
->GetId(), wxEVT_SIZE
,
1115 wxSizeEventHandler(wxAMMediaEvtHandler::OnSize
),
1116 NULL
, (wxEvtHandler
*) this);
1118 pTheTLW
->Connect(pTheTLW
->GetId(), wxEVT_MOVE
,
1119 wxMoveEventHandler(wxAMMediaEvtHandler::OnMove
),
1120 NULL
, (wxEvtHandler
*) this);
1121 pTheTLW
->Connect(pTheTLW
->GetId(), wxEVT_SIZE
,
1122 wxSizeEventHandler(wxAMMediaEvtHandler::OnSize
),
1123 NULL
, (wxEvtHandler
*) this);
1131 //---------------------------------------------------------------------------
1132 // wxAMMediaBackend::SetWindowlessMode
1134 // Adds a Video Mixing Renderer to a Filter Graph and obtains the
1135 // windowless control from it
1136 //---------------------------------------------------------------------------
1137 bool wxAMMediaBackend::SetWindowlessMode(IGraphBuilder
* pGB
,
1138 IVMRWindowlessControl
** ppVMC
)
1141 // Create and add a custom Video Mixing Render to the graph
1144 if( CoCreateInstance(CLSID_VideoMixingRenderer
, NULL
, CLSCTX_INPROC_SERVER
,
1145 IID_IBaseFilter
, (void**)&pVMR
) != 0 )
1148 if ( pGB
->AddFilter(pVMR
, L
"Video Mixing Renderer") != 0)
1155 // Set the graph to windowless mode
1157 IVMRFilterConfig
* pConfig
;
1158 if( pVMR
->QueryInterface(IID_IVMRFilterConfig
, (void**)&pConfig
) != 0 )
1164 if( pConfig
->SetRenderingMode(2) != 0) //2 == VMRMode_Windowless
1174 // Obtain the windowless control
1176 IVMRWindowlessControl
* pVMC
;
1177 if( pVMR
->QueryInterface(IID_IVMRWindowlessControl
, (void**)&pVMC
) != 0 )
1195 //---------------------------------------------------------------------------
1196 // wxAMMediaBackend::Load (file version)
1198 // 1) Cleans up previously loaded data
1199 // 2) Creates a filter graph
1200 // 3) Add a video mixer, set the graph to windowless mode and clip
1201 // output to our media control
1202 // 4) Query interfaces to use later
1203 // 5) Get native video size (which becomes our best size)
1204 // 6) Refresh parent's sizers
1205 // 7) Start event/rendering thread
1206 //---------------------------------------------------------------------------
1207 bool wxAMMediaBackend::Load(const wxString
& fileName
)
1209 //if previously loaded cleanup
1213 //Create interfaces - we already checked for success in CreateControl
1214 CoCreateInstance(CLSID_FilgraphManager
, NULL
, CLSCTX_INPROC_SERVER
,
1215 IID_IGraphBuilder
, (void**)&m_pGB
);
1218 // Set and clip output
1219 SetWindowlessMode(m_pGB
, &m_pVMC
);
1220 if( m_pVMC
->SetVideoClippingWindow((HWND
)m_ctrl
->GetHandle()) != 0 )
1222 m_bestSize
.x
= m_bestSize
.y
= 0;
1226 //load the graph & render
1227 if( m_pGB
->RenderFile(fileName
.wc_str(wxConvLocal
), NULL
) != 0 )
1230 //Get the interfaces, all of them
1231 wxAMVERIFY( m_pGB
->QueryInterface(IID_IMediaEvent
, (void**)&m_pME
) );
1232 wxAMVERIFY( m_pGB
->QueryInterface(IID_IMediaControl
, (void**)&m_pMC
) );
1233 wxAMVERIFY( m_pGB
->QueryInterface(IID_IMediaPosition
, (void**)&m_pMS
) );
1234 wxAMVERIFY( m_pGB
->QueryInterface(IID_IBasicAudio
, (void**)&m_pBA
) );
1236 // Get original video size
1237 if( m_pVMC
->GetNativeVideoSize((LONG
*)&m_bestSize
.x
, (LONG
*)&m_bestSize
.y
,
1240 m_bestSize
.x
= m_bestSize
.y
= 0;
1244 if(m_bestSize
.x
== 0 && m_bestSize
.y
== 0)
1250 // Force the parent window of this control to recalculate
1251 // the size of this if sizers are being used
1252 // and render the results immediately
1254 m_ctrl
->InvalidateBestSize();
1255 m_ctrl
->GetParent()->Layout();
1256 m_ctrl
->GetParent()->Refresh();
1257 m_ctrl
->GetParent()->Update();
1258 m_ctrl
->SetSize(m_ctrl
->GetSize());
1260 m_pThread
= new wxAMMediaThread
;
1261 m_pThread
->pThis
= this;
1262 m_pThread
->Create();
1268 //---------------------------------------------------------------------------
1269 // wxAMMediaBackend::Load (URL Version)
1271 // Loads media from a URL. Interestingly enough DirectShow
1272 // appears (?) to escape the URL for us, at least on normal
1274 //---------------------------------------------------------------------------
1275 bool wxAMMediaBackend::Load(const wxURI
& location
)
1277 return Load(location
.BuildUnescapedURI());
1280 //---------------------------------------------------------------------------
1281 // wxAMMediaBackend::Play
1283 // Plays the stream. If it is non-seekable, it will restart it (implicit).
1285 // Note that we use SUCCEEDED here because run/pause/stop tend to be overly
1286 // picky and return warnings on pretty much every call
1287 //---------------------------------------------------------------------------
1288 bool wxAMMediaBackend::Play()
1290 wxCriticalSectionLocker
lock(m_rendercs
);
1292 if( SUCCEEDED(m_pMC
->Run()) )
1294 m_state
= wxMEDIASTATE_PLAYING
;
1295 m_ctrl
->Refresh(); //videoless control finicky about refreshing
1302 //---------------------------------------------------------------------------
1303 // wxAMMediaBackend::Pause
1305 // Pauses the stream.
1306 //---------------------------------------------------------------------------
1307 bool wxAMMediaBackend::Pause()
1309 wxCriticalSectionLocker
lock(m_rendercs
);
1311 if( SUCCEEDED(m_pMC
->Pause()) )
1313 m_state
= wxMEDIASTATE_PAUSED
;
1320 //---------------------------------------------------------------------------
1321 // wxAMMediaBackend::Stop
1323 // Stops the stream.
1324 //---------------------------------------------------------------------------
1325 bool wxAMMediaBackend::Stop()
1327 wxCriticalSectionLocker
lock(m_rendercs
);
1329 if( SUCCEEDED(m_pMC
->Stop()) )
1331 //We don't care if it can't get to the beginning in directshow -
1332 //it could be a non-seeking filter (wince midi) in which case playing
1333 //starts all over again
1334 wxAMMediaBackend::SetPosition(0);
1336 m_state
= wxMEDIASTATE_STOPPED
;
1343 //---------------------------------------------------------------------------
1344 // wxAMMediaBackend::SetPosition
1346 // 1) Translates the current position's time to directshow time,
1347 // which is in a scale of 1 second (in a double)
1348 // 2) Sets the play position of the IMediaSeeking interface -
1349 // passing NULL as the stop position means to keep the old
1351 //---------------------------------------------------------------------------
1352 bool wxAMMediaBackend::SetPosition(wxLongLong where
)
1354 return SUCCEEDED( m_pMS
->put_CurrentPosition(
1355 ((LONGLONG
)where
.GetValue()) / 1000.0
1359 //---------------------------------------------------------------------------
1360 // wxAMMediaBackend::GetPosition
1362 // 1) Obtains the current play and stop positions from IMediaSeeking
1363 // 2) Returns the play position translated to our time base
1364 //---------------------------------------------------------------------------
1365 wxLongLong
wxAMMediaBackend::GetPosition()
1368 wxAMVERIFY( m_pMS
->get_CurrentPosition(&outCur
) );
1370 //h,m,s,milli - outdur is in 1 second (double)
1378 //---------------------------------------------------------------------------
1379 // wxAMMediaBackend::SetVolume
1381 // Sets the volume through the IBasicAudio interface -
1382 // value ranges from 0 (MAX volume) to -10000 (minimum volume).
1383 // -100 per decibel.
1384 //---------------------------------------------------------------------------
1385 bool wxAMMediaBackend::SetVolume(double dVolume
)
1387 return SUCCEEDED(m_pBA
->put_Volume( (long) ((dVolume
-1.0) * 10000.0) ) );
1390 //---------------------------------------------------------------------------
1391 // wxAMMediaBackend::GetVolume
1393 // Gets the volume through the IBasicAudio interface -
1394 // value ranges from 0 (MAX volume) to -10000 (minimum volume).
1395 // -100 per decibel.
1396 //---------------------------------------------------------------------------
1397 double wxAMMediaBackend::GetVolume()
1400 if ( SUCCEEDED( m_pBA
->get_Volume(&lVolume
) ) )
1401 return (((double)(lVolume
+ 10000)) / 10000.0);
1405 //---------------------------------------------------------------------------
1406 // wxAMMediaBackend::GetDuration
1408 // 1) Obtains the duration of the media from IAMMultiMediaStream
1409 // 2) Converts that value to our time base, and returns it
1411 // NB: With VBR MP3 files the default DirectShow MP3 render does not
1412 // read the Xing header correctly, resulting in skewed values for duration
1414 //---------------------------------------------------------------------------
1415 wxLongLong
wxAMMediaBackend::GetDuration()
1418 wxAMVERIFY( m_pMS
->get_Duration(&outDuration
) );
1420 //h,m,s,milli - outdur is in 1 second (double)
1421 outDuration
*= 1000;
1423 ll
.Assign(outDuration
);
1428 //---------------------------------------------------------------------------
1429 // wxAMMediaBackend::GetState
1431 // Returns the cached state
1432 //---------------------------------------------------------------------------
1433 wxMediaState
wxAMMediaBackend::GetState()
1438 //---------------------------------------------------------------------------
1439 // wxAMMediaBackend::GetPlaybackRate
1441 // Pretty simple way of obtaining the playback rate from
1442 // the IMediaSeeking interface
1443 //---------------------------------------------------------------------------
1444 double wxAMMediaBackend::GetPlaybackRate()
1447 wxAMVERIFY( m_pMS
->get_Rate(&dRate
) );
1451 //---------------------------------------------------------------------------
1452 // wxAMMediaBackend::SetPlaybackRate
1454 // Sets the playback rate of the media - DirectShow is pretty good
1455 // about this, actually
1456 //---------------------------------------------------------------------------
1457 bool wxAMMediaBackend::SetPlaybackRate(double dRate
)
1459 return m_pMS
->put_Rate(dRate
) == 0;
1462 //---------------------------------------------------------------------------
1463 // wxAMMediaBackend::Cleanup
1465 // Releases all the directshow interfaces we use
1466 // TODO: Maybe only create one instance of IAMMultiMediaStream and reuse it
1467 // rather than recreating it each time?
1468 //---------------------------------------------------------------------------
1469 void wxAMMediaBackend::Cleanup()
1471 m_pThread
->Delete();
1474 // Release and zero DirectShow interfaces
1475 SAFE_RELEASE(m_pMC
);
1476 SAFE_RELEASE(m_pME
);
1477 SAFE_RELEASE(m_pMS
);
1478 SAFE_RELEASE(m_pBA
);
1479 SAFE_RELEASE(m_pGB
);
1480 SAFE_RELEASE(m_pVMC
);
1484 //---------------------------------------------------------------------------
1485 // wxAMMediaBackend::GetVideoSize
1487 // Obtains the cached original video size
1488 //---------------------------------------------------------------------------
1489 wxSize
wxAMMediaBackend::GetVideoSize() const
1494 //---------------------------------------------------------------------------
1495 // wxAMMediaBackend::Move
1497 // We take care of this in our redrawing
1498 //---------------------------------------------------------------------------
1499 void wxAMMediaBackend::Move(int WXUNUSED(x
), int WXUNUSED(y
),
1502 if(m_pVMC
&& m_bVideo
)
1504 RECT srcRect
, destRect
;
1506 //portion of video to display in window
1507 srcRect
.top
= 0; srcRect
.left
= 0;
1508 srcRect
.bottom
= m_bestSize
.y
; srcRect
.right
= m_bestSize
.x
;
1520 //position in window client coordinates to display and stretch to
1521 destRect
.top
= 0; destRect
.left
= 0;
1522 destRect
.bottom
= h
; destRect
.right
= w
;
1524 //set the windowless control positions
1525 if( m_pVMC
->SetVideoPosition(&srcRect
, &destRect
) != 0 )
1527 wxASSERT_MSG(false, wxT("Could not set video position!"));
1531 //oddly enough, it doesn't redraw the frame after moving...
1532 //TODO: Use wxClientDC?
1533 HDC hdc = ::GetDC((HWND)m_ctrl->GetHandle());
1534 if( m_pVMC->RepaintVideo((HWND)m_ctrl->GetHandle(),
1539 ::ReleaseDC((HWND)m_ctrl->GetHandle(), hdc);
1544 //---------------------------------------------------------------------------
1545 // wxAMMediaEvtHandler::OnMove
1547 // Oddly enough Move isn't called on MSW when the parent moves
1548 // and the child (us) doesn't, so we have to do it twice I guess :(
1549 //---------------------------------------------------------------------------
1550 void wxAMMediaEvtHandler::OnMove(wxMoveEvent
& evt
)
1552 wxAMMediaBackend
* pThis
= (wxAMMediaBackend
*) this;
1553 pThis
->Move(pThis
->m_ctrl
->GetPosition().x
,
1554 pThis
->m_ctrl
->GetPosition().y
,
1555 pThis
->m_ctrl
->GetSize().x
,
1556 pThis
->m_ctrl
->GetSize().y
);
1559 void wxAMMediaEvtHandler::OnSize(wxSizeEvent
& evt
)
1561 wxAMMediaBackend
* pThis
= (wxAMMediaBackend
*) this;
1562 pThis
->Move(pThis
->m_ctrl
->GetPosition().x
,
1563 pThis
->m_ctrl
->GetPosition().y
,
1564 pThis
->m_ctrl
->GetSize().x
,
1565 pThis
->m_ctrl
->GetSize().y
);
1569 //---------------------------------------------------------------------------
1570 // wxAMMediaThread::Entry
1572 // Render the current movie frame
1573 //---------------------------------------------------------------------------
1574 wxThread::ExitCode
wxAMMediaThread::Entry()
1576 while(!TestDestroy())
1583 // DirectShow keeps a list of queued events, and we need
1584 // to go through them one by one, stopping at (Hopefully only one)
1585 // EC_COMPLETE message
1587 while( pThis
->m_pME
->GetEvent(&evCode
, (LONG_PTR
*) &evParam1
,
1588 (LONG_PTR
*) &evParam2
, 0) == 0 )
1590 // Cleanup memory that GetEvent allocated
1591 if( pThis
->m_pME
->FreeEventParams(evCode
, evParam1
, evParam2
) != 0 )
1596 // If this is the end of the clip, notify handler
1597 if(1 == evCode
) //EC_COMPLETE
1610 //---------------------------------------------------------------------------
1611 // wxAMMediaBackend::OnStop
1613 // Handle stopping when the stream ends
1614 //---------------------------------------------------------------------------
1615 void wxAMMediaBackend::OnStop()
1617 //send the event to our child
1618 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
, m_ctrl
->GetId());
1619 m_ctrl
->ProcessEvent(theEvent
);
1621 //if the user didn't veto it, stop the stream
1622 if (theEvent
.IsAllowed())
1624 //Interestingly enough, DirectShow does not actually stop
1625 //the filters - even when it reaches the end!
1628 //send the event to our child
1629 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
1631 m_ctrl
->ProcessEvent(theEvent
);
1635 //---------------------------------------------------------------------------
1636 // wxAMMediaEvtHandler::OnEraseBackground
1638 // Tell WX not to erase the background of our control window
1639 //---------------------------------------------------------------------------
1640 void wxAMMediaEvtHandler::OnEraseBackground(wxEraseEvent
& evt
)
1642 wxAMMediaBackend
* pThis
= (wxAMMediaBackend
*) this;
1643 if(pThis
->m_pVMC
&& pThis
->m_bVideo
)
1645 //TODO: Use wxClientDC?
1646 HDC hdc
= ::GetDC((HWND
)pThis
->m_ctrl
->GetHandle());
1647 if( pThis
->m_pVMC
->RepaintVideo((HWND
)pThis
->m_ctrl
->GetHandle(),
1652 ::ReleaseDC((HWND
)pThis
->m_ctrl
->GetHandle(), hdc
);
1660 //---------------------------------------------------------------------------
1661 // wxAMMediaEvtHandler::OnPaint
1664 //---------------------------------------------------------------------------
1665 void wxAMMediaEvtHandler::OnPaint(wxPaintEvent
& WXUNUSED(evt
))
1667 wxAMMediaBackend
* pThis
= (wxAMMediaBackend
*) this;
1668 wxPaintDC
dc(pThis
->m_ctrl
);
1669 if( pThis
->m_pVMC
&& pThis
->m_bVideo
)
1671 if( pThis
->m_pVMC
->RepaintVideo((HWND
)pThis
->m_ctrl
->GetHandle(),
1672 (HDC
)dc
.GetHDC()) != 0 )
1679 //---------------------------------------------------------------------------
1680 // End of wxAMMediaBackend
1681 //---------------------------------------------------------------------------
1683 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1685 // wxMCIMediaBackend
1687 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1689 IMPLEMENT_DYNAMIC_CLASS(wxMCIMediaBackend
, wxMediaBackend
);
1691 //---------------------------------------------------------------------------
1692 // Usual debugging macros for MCI returns
1693 //---------------------------------------------------------------------------
1696 #define wxMCIVERIFY(arg) \
1699 if ( (nRet = (arg)) != 0) \
1702 mciGetErrorString(nRet, sz, 5000); \
1703 wxFAIL_MSG(wxString::Format(_T("MCI Error:%s"), sz)); \
1707 #define wxMCIVERIFY(arg) (arg);
1710 //---------------------------------------------------------------------------
1711 // Simulation for <digitalv.h>
1713 // Mingw and possibly other compilers don't have the digitalv.h header
1714 // that is needed to have some essential features of mci work with
1715 // windows - so we provide the declarations for the types we use here
1716 //---------------------------------------------------------------------------
1719 DWORD_PTR dwCallback
;
1720 #ifdef MCI_USE_OFFEXT
1726 } MCI_DGV_RECT_PARMS
;
1729 DWORD_PTR dwCallback
;
1739 } MCI_DGV_WINDOW_PARMS
;
1742 DWORD_PTR dwCallback
;
1747 } MCI_DGV_SET_PARMS
;
1750 DWORD_PTR dwCallback
;
1754 wxChar
* lpstrAlgorithm
;
1755 wxChar
* lpstrQuality
;
1756 } MCI_DGV_SETAUDIO_PARMS
;
1758 //---------------------------------------------------------------------------
1759 // wxMCIMediaBackend Constructor
1761 // Here we don't need to do much except say we don't have any video :)
1762 //---------------------------------------------------------------------------
1763 wxMCIMediaBackend::wxMCIMediaBackend() : m_hNotifyWnd(NULL
), m_bVideo(false)
1767 //---------------------------------------------------------------------------
1768 // wxMCIMediaBackend Destructor
1770 // We close the mci device - note that there may not be an mci device here,
1771 // or it may fail - but we don't really care, since we're destructing
1772 //---------------------------------------------------------------------------
1773 wxMCIMediaBackend::~wxMCIMediaBackend()
1777 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
1778 DestroyWindow(m_hNotifyWnd
);
1779 m_hNotifyWnd
= NULL
;
1783 //---------------------------------------------------------------------------
1784 // wxMCIMediaBackend::Create
1786 // Here we just tell wxMediaCtrl that mci does exist (which it does, on all
1787 // msw systems, at least in some form dating back to win16 days)
1788 //---------------------------------------------------------------------------
1789 bool wxMCIMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
1794 const wxValidator
& validator
,
1795 const wxString
& name
)
1799 // By default wxWindow(s) is created with a border -
1800 // so we need to get rid of those, and create with
1801 // wxCLIP_CHILDREN, so that if the driver/backend
1802 // is a child window, it refereshes properly
1804 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
1805 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
| wxCLIP_CHILDREN
,
1813 //---------------------------------------------------------------------------
1814 // wxMCIMediaBackend::Load (file version)
1816 // Here we have MCI load a file and device, set the time format to our
1817 // default (milliseconds), and set the video (if any) to play in the control
1818 //---------------------------------------------------------------------------
1819 bool wxMCIMediaBackend::Load(const wxString
& fileName
)
1822 //if the user already called load close the previous MCI device
1826 mciSendCommand(m_hDev
, MCI_CLOSE
, 0, 0);
1827 DestroyWindow(m_hNotifyWnd
);
1828 m_hNotifyWnd
= NULL
;
1832 //Opens a file and has MCI select a device. Normally you'd put
1833 //MCI_OPEN_TYPE in addition to MCI_OPEN_ELEMENT - however if you
1834 //omit this it tells MCI to select the device instead. This is
1835 //good because we have no reliable way of "enumerating" the devices
1838 MCI_OPEN_PARMS openParms
;
1839 openParms
.lpstrElementName
= (wxChar
*) fileName
.c_str();
1841 if ( mciSendCommand(0, MCI_OPEN
, MCI_OPEN_ELEMENT
,
1842 (DWORD
)(LPVOID
)&openParms
) != 0)
1845 m_hDev
= openParms
.wDeviceID
;
1848 //Now set the time format for the device to milliseconds
1850 MCI_SET_PARMS setParms
;
1851 setParms
.dwCallback
= 0;
1852 setParms
.dwTimeFormat
= MCI_FORMAT_MILLISECONDS
;
1854 if (mciSendCommand(m_hDev
, MCI_SET
, MCI_SET_TIME_FORMAT
,
1855 (DWORD
)(LPVOID
)&setParms
) != 0)
1859 //Now tell the MCI device to display the video in our wxMediaCtrl
1861 MCI_DGV_WINDOW_PARMS windowParms
;
1862 windowParms
.hWnd
= (HWND
)m_ctrl
->GetHandle();
1864 m_bVideo
= (mciSendCommand(m_hDev
, MCI_WINDOW
,
1865 0x00010000L
, //MCI_DGV_WINDOW_HWND
1866 (DWORD
)(LPVOID
)&windowParms
) == 0);
1869 // Create a hidden window and register to handle
1871 // Note that wxCanvasClassName is already registered
1872 // and used by all wxWindows and normal wxControls
1874 m_hNotifyWnd
= ::CreateWindow
1888 wxLogSysError( wxT("Could not create hidden needed for ")
1889 wxT("registering for DirectShow events!") );
1894 wxSetWindowProc(m_hNotifyWnd
, wxMCIMediaBackend::NotifyWndProc
);
1896 ::SetWindowLong(m_hNotifyWnd
, GWL_USERDATA
,
1900 //Here, if the parent of the control has a sizer - we
1901 //tell it to recalculate the size of this control since
1902 //the user opened a separate media file
1904 m_ctrl
->InvalidateBestSize();
1905 m_ctrl
->GetParent()->Layout();
1906 m_ctrl
->GetParent()->Refresh();
1907 m_ctrl
->GetParent()->Update();
1908 m_ctrl
->SetSize(m_ctrl
->GetSize());
1913 //---------------------------------------------------------------------------
1914 // wxMCIMediaBackend::Load (URL version)
1916 // MCI doesn't support URLs directly (?)
1918 // TODO: Use wxURL/wxFileSystem and mmioInstallProc
1919 //---------------------------------------------------------------------------
1920 bool wxMCIMediaBackend::Load(const wxURI
& WXUNUSED(location
))
1925 //---------------------------------------------------------------------------
1926 // wxMCIMediaBackend::Play
1928 // Plays/Resumes the MCI device... a couple notes:
1929 // 1) Certain drivers will crash and burn if we don't pass them an
1930 // MCI_PLAY_PARMS, despite the documentation that says otherwise...
1931 // 2) There is a MCI_RESUME command, but MCI_PLAY does the same thing
1932 // and will resume from a stopped state also, so there's no need to
1933 // call both, for example
1934 //---------------------------------------------------------------------------
1935 bool wxMCIMediaBackend::Play()
1937 MCI_PLAY_PARMS playParms
;
1938 playParms
.dwCallback
= (DWORD
)m_hNotifyWnd
;
1940 bool bOK
= ( mciSendCommand(m_hDev
, MCI_PLAY
, MCI_NOTIFY
,
1941 (DWORD
)(LPVOID
)&playParms
) == 0 );
1944 m_ctrl
->Show(m_bVideo
);
1949 //---------------------------------------------------------------------------
1950 // wxMCIMediaBackend::Pause
1952 // Pauses the MCI device - nothing special
1953 //---------------------------------------------------------------------------
1954 bool wxMCIMediaBackend::Pause()
1956 return (mciSendCommand(m_hDev
, MCI_PAUSE
, MCI_WAIT
, 0) == 0);
1959 //---------------------------------------------------------------------------
1960 // wxMCIMediaBackend::Stop
1962 // Stops the MCI device & seeks to the beginning as wxMediaCtrl docs outline
1963 //---------------------------------------------------------------------------
1964 bool wxMCIMediaBackend::Stop()
1966 return (mciSendCommand(m_hDev
, MCI_STOP
, MCI_WAIT
, 0) == 0) &&
1967 (mciSendCommand(m_hDev
, MCI_SEEK
, MCI_SEEK_TO_START
, 0) == 0);
1970 //---------------------------------------------------------------------------
1971 // wxMCIMediaBackend::GetState
1973 // Here we get the state and convert it to a wxMediaState -
1974 // since we use direct comparisons with MCI_MODE_PLAY and
1975 // MCI_MODE_PAUSE, we don't care if the MCI_STATUS call
1977 //---------------------------------------------------------------------------
1978 wxMediaState
wxMCIMediaBackend::GetState()
1980 MCI_STATUS_PARMS statusParms
;
1981 statusParms
.dwItem
= MCI_STATUS_MODE
;
1983 mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
1984 (DWORD
)(LPVOID
)&statusParms
);
1986 if(statusParms
.dwReturn
== MCI_MODE_PAUSE
)
1987 return wxMEDIASTATE_PAUSED
;
1988 else if(statusParms
.dwReturn
== MCI_MODE_PLAY
)
1989 return wxMEDIASTATE_PLAYING
;
1991 return wxMEDIASTATE_STOPPED
;
1994 //---------------------------------------------------------------------------
1995 // wxMCIMediaBackend::SetPosition
1997 // Here we set the position of the device in the stream.
1998 // Note that MCI actually stops the device after you seek it if the
1999 // device is playing/paused, so we need to play the file after
2000 // MCI seeks like normal APIs would
2001 //---------------------------------------------------------------------------
2002 bool wxMCIMediaBackend::SetPosition(wxLongLong where
)
2004 MCI_SEEK_PARMS seekParms
;
2005 seekParms
.dwCallback
= 0;
2006 #if wxUSE_LONGLONG_NATIVE && !wxUSE_LONGLONG_WX
2007 seekParms
.dwTo
= (DWORD
)where
.GetValue();
2008 #else /* wxUSE_LONGLONG_WX */
2009 /* no way to return it in one piece */
2010 wxASSERT( where
.GetHi()==0 );
2011 seekParms
.dwTo
= (DWORD
)where
.GetLo();
2012 #endif /* wxUSE_LONGLONG_* */
2014 //device was playing?
2015 bool bReplay
= GetState() == wxMEDIASTATE_PLAYING
;
2017 if( mciSendCommand(m_hDev
, MCI_SEEK
, MCI_TO
,
2018 (DWORD
)(LPVOID
)&seekParms
) != 0)
2021 //If the device was playing, resume it
2028 //---------------------------------------------------------------------------
2029 // wxMCIMediaBackend::GetPosition
2031 // Gets the position of the device in the stream using the current
2032 // time format... nothing special here...
2033 //---------------------------------------------------------------------------
2034 wxLongLong
wxMCIMediaBackend::GetPosition()
2036 MCI_STATUS_PARMS statusParms
;
2037 statusParms
.dwItem
= MCI_STATUS_POSITION
;
2039 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2040 (DWORD
)(LPSTR
)&statusParms
) != 0)
2043 return statusParms
.dwReturn
;
2046 //---------------------------------------------------------------------------
2047 // wxMCIMediaBackend::GetVolume
2049 // Gets the volume of the current media via the MCI_DGV_STATUS_VOLUME
2050 // message. Value ranges from 0 (minimum) to 1000 (maximum volume).
2051 //---------------------------------------------------------------------------
2052 double wxMCIMediaBackend::GetVolume()
2054 MCI_STATUS_PARMS statusParms
;
2055 statusParms
.dwCallback
= 0;
2056 statusParms
.dwItem
= 0x4019; //MCI_DGV_STATUS_VOLUME
2058 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2059 (DWORD
)(LPSTR
)&statusParms
) != 0)
2062 return ((double)statusParms
.dwReturn
) / 1000.0;
2065 //---------------------------------------------------------------------------
2066 // wxMCIMediaBackend::SetVolume
2068 // Sets the volume of the current media via the MCI_DGV_SETAUDIO_VOLUME
2069 // message. Value ranges from 0 (minimum) to 1000 (maximum volume).
2070 //---------------------------------------------------------------------------
2071 bool wxMCIMediaBackend::SetVolume(double dVolume
)
2073 MCI_DGV_SETAUDIO_PARMS audioParms
;
2074 audioParms
.dwCallback
= 0;
2075 audioParms
.dwItem
= 0x4002; //MCI_DGV_SETAUDIO_VOLUME
2076 audioParms
.dwValue
= (DWORD
) (dVolume
* 1000.0);
2077 audioParms
.dwOver
= 0;
2078 audioParms
.lpstrAlgorithm
= NULL
;
2079 audioParms
.lpstrQuality
= NULL
;
2081 if (mciSendCommand(m_hDev
, 0x0873, //MCI_SETAUDIO
2082 0x00800000L
| 0x01000000L
, //MCI_DGV_SETAUDIO+(_ITEM | _VALUE)
2083 (DWORD
)(LPSTR
)&audioParms
) != 0)
2088 //---------------------------------------------------------------------------
2089 // wxMCIMediaBackend::GetDuration
2091 // Gets the duration of the stream... nothing special
2092 //---------------------------------------------------------------------------
2093 wxLongLong
wxMCIMediaBackend::GetDuration()
2095 MCI_STATUS_PARMS statusParms
;
2096 statusParms
.dwItem
= MCI_STATUS_LENGTH
;
2098 if (mciSendCommand(m_hDev
, MCI_STATUS
, MCI_STATUS_ITEM
,
2099 (DWORD
)(LPSTR
)&statusParms
) != 0)
2102 return statusParms
.dwReturn
;
2105 //---------------------------------------------------------------------------
2106 // wxMCIMediaBackend::Move
2108 // Moves the window to a location
2109 //---------------------------------------------------------------------------
2110 void wxMCIMediaBackend::Move(int WXUNUSED(x
), int WXUNUSED(y
),
2113 if (m_hNotifyWnd
&& m_bVideo
)
2115 MCI_DGV_RECT_PARMS putParms
; //ifdefed MCI_DGV_PUT_PARMS
2116 memset(&putParms
, 0, sizeof(MCI_DGV_RECT_PARMS
));
2117 putParms
.rc
.bottom
= h
;
2118 putParms
.rc
.right
= w
;
2120 //wxStackWalker will crash and burn here on assert
2121 //and mci doesn't like 0 and 0 for some reason (out of range )
2122 //so just don't it in that case
2125 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_PUT
,
2126 0x00040000L
, //MCI_DGV_PUT_DESTINATION
2127 (DWORD
)(LPSTR
)&putParms
) );
2132 //---------------------------------------------------------------------------
2133 // wxMCIMediaBackend::GetVideoSize
2135 // Gets the original size of the movie for sizers
2136 //---------------------------------------------------------------------------
2137 wxSize
wxMCIMediaBackend::GetVideoSize() const
2141 MCI_DGV_RECT_PARMS whereParms
; //ifdefed MCI_DGV_WHERE_PARMS
2143 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_WHERE
,
2144 0x00020000L
, //MCI_DGV_WHERE_SOURCE
2145 (DWORD
)(LPSTR
)&whereParms
) );
2147 return wxSize(whereParms
.rc
.right
, whereParms
.rc
.bottom
);
2152 //---------------------------------------------------------------------------
2153 // wxMCIMediaBackend::GetPlaybackRate
2156 //---------------------------------------------------------------------------
2157 double wxMCIMediaBackend::GetPlaybackRate()
2162 //---------------------------------------------------------------------------
2163 // wxMCIMediaBackend::SetPlaybackRate
2166 //---------------------------------------------------------------------------
2167 bool wxMCIMediaBackend::SetPlaybackRate(double WXUNUSED(dRate
))
2170 MCI_WAVE_SET_SAMPLESPERSEC
2171 MCI_DGV_SET_PARMS setParms;
2172 setParms.dwSpeed = (DWORD) (dRate * 1000.0);
2174 return (mciSendCommand(m_hDev, MCI_SET,
2175 0x00020000L, //MCI_DGV_SET_SPEED
2176 (DWORD)(LPSTR)&setParms) == 0);
2181 //---------------------------------------------------------------------------
2182 // [static] wxMCIMediaBackend::MSWWindowProc
2184 // Here we process a message when MCI reaches the stopping point
2186 //---------------------------------------------------------------------------
2187 LRESULT CALLBACK
wxMCIMediaBackend::NotifyWndProc(HWND hWnd
, UINT nMsg
,
2191 wxMCIMediaBackend
* backend
= (wxMCIMediaBackend
*)
2193 ::GetWindowLong(hWnd
, GWL_USERDATA
);
2195 ::GetWindowLongPtr(hWnd
, GWLP_USERDATA
);
2199 return backend
->OnNotifyWndProc(hWnd
, nMsg
, wParam
, lParam
);
2202 LRESULT CALLBACK
wxMCIMediaBackend::OnNotifyWndProc(HWND hWnd
, UINT nMsg
,
2206 if(nMsg
== MM_MCINOTIFY
)
2208 wxASSERT(lParam
== (LPARAM
) m_hDev
);
2209 if(wParam
== MCI_NOTIFY_SUCCESSFUL
&& lParam
== (LPARAM
)m_hDev
)
2211 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
, m_ctrl
->GetId());
2212 m_ctrl
->ProcessEvent(theEvent
);
2214 if(theEvent
.IsAllowed())
2216 wxMCIVERIFY( mciSendCommand(m_hDev
, MCI_SEEK
,
2217 MCI_SEEK_TO_START
, 0) );
2219 //send the event to our child
2220 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
2222 m_ctrl
->ProcessEvent(theEvent
);
2226 return DefWindowProc(hWnd
, nMsg
, wParam
, lParam
);
2228 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2232 // TODO: Use a less cludgy way to pause/get state/set state
2233 // TODO: Dynamically load from qtml.dll
2234 //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2236 IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend
, wxMediaBackend
);
2238 //Time between timer calls
2239 #define MOVIE_DELAY 100
2241 #include "wx/timer.h"
2243 // --------------------------------------------------------------------------
2244 // wxQTTimer - Handle Asyncronous Playing
2245 // --------------------------------------------------------------------------
2246 class _wxQTTimer
: public wxTimer
2249 _wxQTTimer(Movie movie
, wxQTMediaBackend
* parent
, wxQuickTimeLibrary
* pLib
) :
2250 m_movie(movie
), m_bPaused(false), m_parent(parent
), m_pLib(pLib
)
2258 bool GetPaused() {return m_bPaused
;}
2259 void SetPaused(bool bPaused
) {m_bPaused
= bPaused
;}
2261 //-----------------------------------------------------------------------
2262 // _wxQTTimer::Notify
2264 // 1) Checks to see if the movie is done, and if not continues
2265 // streaming the movie
2266 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
2268 //-----------------------------------------------------------------------
2273 if(!m_pLib
->IsMovieDone(m_movie
))
2274 m_pLib
->MoviesTask(m_movie
, MOVIE_DELAY
);
2277 wxMediaEvent
theEvent(wxEVT_MEDIA_STOP
,
2278 m_parent
->m_ctrl
->GetId());
2279 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
2281 if(theEvent
.IsAllowed())
2285 wxASSERT(m_pLib
->GetMoviesError() == noErr
);
2287 //send the event to our child
2288 wxMediaEvent
theEvent(wxEVT_MEDIA_FINISHED
,
2289 m_parent
->m_ctrl
->GetId());
2290 m_parent
->m_ctrl
->ProcessEvent(theEvent
);
2297 Movie m_movie
; //Our movie instance
2298 bool m_bPaused
; //Whether we are paused or not
2299 wxQTMediaBackend
* m_parent
; //Backend pointer
2300 wxQuickTimeLibrary
* m_pLib
; //Interfaces
2303 //---------------------------------------------------------------------------
2304 // wxQTMediaBackend Destructor
2306 // Sets m_timer to NULL signifying we havn't loaded anything yet
2307 //---------------------------------------------------------------------------
2308 wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL
)
2312 //---------------------------------------------------------------------------
2313 // wxQTMediaBackend Destructor
2315 // 1) Cleans up the QuickTime movie instance
2316 // 2) Decrements the QuickTime reference counter - if this reaches
2317 // 0, QuickTime shuts down
2318 // 3) Decrements the QuickTime Windows Media Layer reference counter -
2319 // if this reaches 0, QuickTime shuts down the Windows Media Layer
2320 //---------------------------------------------------------------------------
2321 wxQTMediaBackend::~wxQTMediaBackend()
2328 //Note that ExitMovies() is not necessary, but
2329 //the docs are fuzzy on whether or not TerminateQTML is
2331 m_lib
.TerminateQTML();
2335 //---------------------------------------------------------------------------
2336 // wxQTMediaBackend::CreateControl
2338 // 1) Intializes QuickTime
2339 // 2) Creates the control window
2340 //---------------------------------------------------------------------------
2341 bool wxQTMediaBackend::CreateControl(wxControl
* ctrl
, wxWindow
* parent
,
2346 const wxValidator
& validator
,
2347 const wxString
& name
)
2349 if(!m_lib
.Initialize())
2352 int nError
= m_lib
.InitializeQTML(0);
2353 if (nError
!= noErr
) //-2093 no dll
2355 wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError
));
2358 m_lib
.EnterMovies();
2362 // By default wxWindow(s) is created with a border -
2363 // so we need to get rid of those
2365 // Since we don't have a child window like most other
2366 // backends, we don't need wxCLIP_CHILDREN
2368 if ( !ctrl
->wxControl::Create(parent
, id
, pos
, size
,
2369 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
,
2377 //---------------------------------------------------------------------------
2378 // wxQTMediaBackend::Load (file version)
2380 // 1) Get an FSSpec from the Windows path name
2381 // 2) Open the movie
2382 // 3) Obtain the movie instance from the movie resource
2384 //---------------------------------------------------------------------------
2385 bool wxQTMediaBackend::Load(const wxString
& fileName
)
2390 short movieResFile
= 0; //= 0 because of annoying VC6 warning
2393 if (m_lib
.NativePathNameToFSSpec ((char*) (const char*) fileName
.mb_str(),
2394 &sfFile
, 0) != noErr
)
2397 if (m_lib
.OpenMovieFile (&sfFile
, &movieResFile
, fsRdPerm
) != noErr
)
2400 short movieResID
= 0;
2403 OSErr err
= m_lib
.NewMovieFromFile (
2412 m_lib
.CloseMovieFile (movieResFile
);
2419 return m_lib
.GetMoviesError() == noErr
;
2422 //---------------------------------------------------------------------------
2423 // wxQTMediaBackend::Move
2426 //---------------------------------------------------------------------------
2427 bool wxQTMediaBackend::Load(const wxURI
& location
)
2432 wxString theURI
= location
.BuildURI();
2434 Handle theHandle
= m_lib
.NewHandleClear(theURI
.length() + 1);
2435 wxASSERT(theHandle
);
2437 m_lib
.BlockMove(theURI
.mb_str(), *theHandle
, theURI
.length() + 1);
2439 //create the movie from the handle that refers to the URI
2440 OSErr err
= m_lib
.NewMovieFromDataRef(&m_movie
, newMovieActive
,
2442 URLDataHandlerSubType
);
2444 m_lib
.DisposeHandle(theHandle
);
2449 //preroll movie for streaming
2454 timeNow = GetMovieTime(m_movie, NULL);
2455 playRate = GetMoviePreferredRate(m_movie);
2456 PrePrerollMovie(m_movie, timeNow, playRate, NULL, NULL);
2457 PrerollMovie(m_movie, timeNow, playRate);
2458 m_lib.SetMovieRate(m_movie, playRate);
2463 return m_lib
.GetMoviesError() == noErr
;
2466 //---------------------------------------------------------------------------
2467 // wxQTMediaBackend::Move
2470 //---------------------------------------------------------------------------
2471 void wxQTMediaBackend::FinishLoad()
2473 m_timer
= new _wxQTTimer(m_movie
, (wxQTMediaBackend
*) this, &m_lib
);
2476 //get the real size of the movie
2478 memset(&outRect
, 0, sizeof(Rect
)); //for annoying VC6 warning
2479 m_lib
.GetMovieNaturalBoundsRect (m_movie
, &outRect
);
2480 wxASSERT(m_lib
.GetMoviesError() == noErr
);
2482 m_bestSize
.x
= outRect
.right
- outRect
.left
;
2483 m_bestSize
.y
= outRect
.bottom
- outRect
.top
;
2485 //reparent movie/*AudioMediaCharacteristic*/
2486 if(m_lib
.GetMovieIndTrackType(m_movie
, 1,
2487 VisualMediaCharacteristic
,
2488 (1 << 1) //movieTrackCharacteristic
2489 | (1 << 2) //movieTrackEnabledOnly
2492 m_lib
.CreatePortAssociation(m_ctrl
->GetHWND(), NULL
, 0L);
2494 m_lib
.SetMovieGWorld(m_movie
,
2495 (CGrafPtr
) m_lib
.GetNativeWindowPort(m_ctrl
->GetHWND()),
2499 //we want millisecond precision
2500 m_lib
.SetMovieTimeScale(m_movie
, 1000);
2501 wxASSERT(m_lib
.GetMoviesError() == noErr
);
2504 //Here, if the parent of the control has a sizer - we
2505 //tell it to recalculate the size of this control since
2506 //the user opened a separate media file
2508 m_ctrl
->InvalidateBestSize();
2509 m_ctrl
->GetParent()->Layout();
2510 m_ctrl
->GetParent()->Refresh();
2511 m_ctrl
->GetParent()->Update();
2514 //---------------------------------------------------------------------------
2515 // wxQTMediaBackend::Move
2518 //---------------------------------------------------------------------------
2519 bool wxQTMediaBackend::Play()
2521 m_lib
.StartMovie(m_movie
);
2522 m_timer
->SetPaused(false);
2523 m_timer
->Start(MOVIE_DELAY
, wxTIMER_CONTINUOUS
);
2524 return m_lib
.GetMoviesError() == noErr
;
2527 //---------------------------------------------------------------------------
2528 // wxQTMediaBackend::Move
2531 //---------------------------------------------------------------------------
2532 bool wxQTMediaBackend::Pause()
2534 m_lib
.StopMovie(m_movie
);
2535 m_timer
->SetPaused(true);
2537 return m_lib
.GetMoviesError() == noErr
;
2540 //---------------------------------------------------------------------------
2541 // wxQTMediaBackend::Move
2544 //---------------------------------------------------------------------------
2545 bool wxQTMediaBackend::Stop()
2547 m_timer
->SetPaused(false);
2550 m_lib
.StopMovie(m_movie
);
2551 if(m_lib
.GetMoviesError() != noErr
)
2554 m_lib
.GoToBeginningOfMovie(m_movie
);
2555 return m_lib
.GetMoviesError() == noErr
;
2558 //---------------------------------------------------------------------------
2559 // wxQTMediaBackend::Move
2562 //---------------------------------------------------------------------------
2563 double wxQTMediaBackend::GetPlaybackRate()
2565 return ( ((double)m_lib
.GetMovieRate(m_movie
)) / 0x10000);
2568 //---------------------------------------------------------------------------
2569 // wxQTMediaBackend::Move
2572 //---------------------------------------------------------------------------
2573 bool wxQTMediaBackend::SetPlaybackRate(double dRate
)
2575 m_lib
.SetMovieRate(m_movie
, (Fixed
) (dRate
* 0x10000));
2576 return m_lib
.GetMoviesError() == noErr
;
2579 //---------------------------------------------------------------------------
2580 // wxQTMediaBackend::Move
2583 //---------------------------------------------------------------------------
2584 bool wxQTMediaBackend::SetPosition(wxLongLong where
)
2586 TimeRecord theTimeRecord
;
2587 memset(&theTimeRecord
, 0, sizeof(TimeRecord
));
2588 theTimeRecord
.value
.lo
= where
.GetLo();
2589 theTimeRecord
.scale
= m_lib
.GetMovieTimeScale(m_movie
);
2590 theTimeRecord
.base
= m_lib
.GetMovieTimeBase(m_movie
);
2591 m_lib
.SetMovieTime(m_movie
, &theTimeRecord
);
2593 if (m_lib
.GetMoviesError() != noErr
)
2599 //---------------------------------------------------------------------------
2600 // wxQTMediaBackend::GetPosition
2602 // 1) Calls GetMovieTime to get the position we are in in the movie
2603 // in milliseconds (we called
2604 //---------------------------------------------------------------------------
2605 wxLongLong
wxQTMediaBackend::GetPosition()
2607 return m_lib
.GetMovieTime(m_movie
, NULL
);
2610 //---------------------------------------------------------------------------
2611 // wxQTMediaBackend::GetVolume
2613 // Gets the volume through GetMovieVolume - which returns a 16 bit short -
2615 // +--------+--------+
2617 // +--------+--------+
2619 // (1) first 8 bits are value before decimal
2620 // (2) second 8 bits are value after decimal
2622 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
2623 // 1 (full gain and sound)
2624 //---------------------------------------------------------------------------
2625 double wxQTMediaBackend::GetVolume()
2627 short sVolume
= m_lib
.GetMovieVolume(m_movie
);
2629 if(sVolume
& (128 << 8)) //negative - no sound
2632 return (sVolume
& (127 << 8)) ? 1.0 : ((double)(sVolume
& 255)) / 255.0;
2635 //---------------------------------------------------------------------------
2636 // wxQTMediaBackend::SetVolume
2638 // Sets the volume through SetMovieVolume - which takes a 16 bit short -
2640 // +--------+--------+
2642 // +--------+--------+
2644 // (1) first 8 bits are value before decimal
2645 // (2) second 8 bits are value after decimal
2647 // Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
2648 // 1 (full gain and sound)
2649 //---------------------------------------------------------------------------
2650 bool wxQTMediaBackend::SetVolume(double dVolume
)
2652 short sVolume
= (short) (dVolume
>= .9999 ? 1 << 8 : (dVolume
* 255) );
2653 m_lib
.SetMovieVolume(m_movie
, sVolume
);
2657 //---------------------------------------------------------------------------
2658 // wxQTMediaBackend::Move
2661 //---------------------------------------------------------------------------
2662 wxLongLong
wxQTMediaBackend::GetDuration()
2664 return m_lib
.GetMovieDuration(m_movie
);
2667 //---------------------------------------------------------------------------
2668 // wxQTMediaBackend::Move
2671 //---------------------------------------------------------------------------
2672 wxMediaState
wxQTMediaBackend::GetState()
2674 if ( !m_timer
|| (m_timer
->IsRunning() == false &&
2675 m_timer
->GetPaused() == false) )
2676 return wxMEDIASTATE_STOPPED
;
2678 if( m_timer
->IsRunning() == true )
2679 return wxMEDIASTATE_PLAYING
;
2681 return wxMEDIASTATE_PAUSED
;
2684 //---------------------------------------------------------------------------
2685 // wxQTMediaBackend::Move
2688 //---------------------------------------------------------------------------
2689 void wxQTMediaBackend::Cleanup()
2694 m_lib
.StopMovie(m_movie
);
2695 m_lib
.DisposeMovie(m_movie
);
2698 //---------------------------------------------------------------------------
2699 // wxQTMediaBackend::Move
2702 //---------------------------------------------------------------------------
2703 wxSize
wxQTMediaBackend::GetVideoSize() const
2708 //---------------------------------------------------------------------------
2709 // wxQTMediaBackend::Move
2712 //---------------------------------------------------------------------------
2713 void wxQTMediaBackend::Move(int WXUNUSED(x
), int WXUNUSED(y
), int w
, int h
)
2717 Rect theRect
= {0, 0, (short)h
, (short)w
};
2719 m_lib
.SetMovieBox(m_movie
, &theRect
);
2720 wxASSERT(m_lib
.GetMoviesError() == noErr
);
2724 //---------------------------------------------------------------------------
2726 //---------------------------------------------------------------------------
2728 //in source file that contains stuff you don't directly use
2729 #include <wx/html/forcelnk.h>
2730 FORCE_LINK_ME(basewxmediabackends
);
2732 //---------------------------------------------------------------------------
2733 // End wxMediaCtrl Compilation Guard and this file
2734 //---------------------------------------------------------------------------
2735 #endif //wxUSE_MEDIACTRL