]> git.saurik.com Git - wxWidgets.git/blame - src/msw/mediactrl.cpp
reSWIGged
[wxWidgets.git] / src / msw / mediactrl.cpp
CommitLineData
1a680109
RN
1/////////////////////////////////////////////////////////////////////////////
2// Name: msw/mediactrl.cpp
ff4aedc5 3// Purpose: Built-in Media Backends for Windows
1a680109 4// Author: Ryan Norton <wxprojects@comcast.net>
72259e00 5// Modified by:
1a680109
RN
6// Created: 11/07/04
7// RCS-ID: $Id$
8// Copyright: (c) Ryan Norton
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
ff4aedc5
RN
12//===========================================================================
13// DECLARATIONS
14//===========================================================================
15
1a680109 16//---------------------------------------------------------------------------
ff4aedc5 17// Pre-compiled header stuff
1a680109
RN
18//---------------------------------------------------------------------------
19
ff4aedc5
RN
20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21#pragma implementation "mediactrl.h"
22#endif
1a680109
RN
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28#pragma hdrstop
29#endif
30
ff4aedc5
RN
31//---------------------------------------------------------------------------
32// Includes
33//---------------------------------------------------------------------------
1a680109
RN
34#include "wx/mediactrl.h"
35
ff4aedc5
RN
36//---------------------------------------------------------------------------
37// Compilation guard
38//---------------------------------------------------------------------------
1a680109
RN
39#if wxUSE_MEDIACTRL
40
1a680109 41//---------------------------------------------------------------------------
ff4aedc5 42// Externals (somewhere in src/msw/app.cpp)
1a680109 43//---------------------------------------------------------------------------
ff4aedc5
RN
44extern "C" WXDLLIMPEXP_BASE HINSTANCE wxGetInstance(void);
45#ifdef __WXWINCE__
7a4d2469 46extern WXDLLIMPEXP_CORE wxChar *wxCanvasClassName;
ff4aedc5 47#else
316d19ac 48extern WXDLLIMPEXP_CORE const wxChar *wxCanvasClassName;
ff4aedc5 49#endif
1a680109 50
ff4aedc5
RN
51//===========================================================================
52// BACKEND DECLARATIONS
53//===========================================================================
1a680109
RN
54
55//---------------------------------------------------------------------------
ff4aedc5
RN
56//
57// wxAMMediaBackend
58//
1a680109 59//---------------------------------------------------------------------------
920a7c15
JS
60//
61//####################THE BIG DIRECTSHOW OVERVIEW############################
62//
63//
64// OK... this deserves its own little tutorial. Knowledge of COM and class
65// factories is assumed throughout this code.
66//
67// Basically, the way directshow works is that you tell it to render
68// a file, and it builds and connects a bunch of filters together.
69//
70// There are many, many ways to do this.
71//
72// WAYS TO RENDER A FILE (URLS WORK IN DS ALSO)
73//
74// 1) Create an instance of IGraphBuilder and call RenderFile on it
75// 2) Create an instance of IMediaControl and call RenderFile on it
76// 3) Create an instance of IAMMultiMediaStream, call
77// IAMMultiMediaStream::AddStream and pass an IDirectDraw instance for
78// the video, and pass an IDirectSound(Buffer?) instance or use the
79// default sound renderer, then call RenderFile or RenderMoniker
80// 4) Create a Moniker instance for the file and create and build
81// all of the filtergraph manually
82//
83// Our issue here is that we can't use the default representation of 1 and 2
84// because the IVideoWindow instance hogs a lot of the useful window
85// messages such as WM_SETCURSOR.
86//
87// Solution #1 was to use #3 by creating a seperate IDirectDraw instance
88// for our window and blitting to that through a thread... unfortunately
89// the blitting resizing is very low quality and its quite slow.
90//
91// The current way is to use windowless rendering and have directshow
92// do all the DirectDraw-style clipping to our window
93//
94// ~~~~~~~~~~~~~~AFTER RENDERING THE FILE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
95//
96// When done rendering the file, we need to get several interfaces from
97// either a IMediaControl or IGraphBuilder instance -
98//
99// IMediaPosition - we can set the rate with this... we can also get
100// positions and set positions through this with REFTIME (double) instead
101// of the normal LONGLONG that IAMMultiMediaStream and IMediaControl use
102//
103// IBasicAudio - we need this for setting/getting the volume
104//
105// Interfaces that we don't use but might be useful one day -
106//
107// IDirectDrawVideo - you can get this through the IFilter returned
108// from L"Video Renderer" filter from FindFilter on the IGraphBuilder.
109// Through this we can set the IDirectDraw instance DrawShow uses.
110//
111// ~~~~~~~~~~~~~~STOPPING~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
112//
113// There are two ways we can do this -
114// 1) Have a thread compare the current position to the end position
115// about every 10 milliseconds
116// 2) Have IMediaSeekingEx send a message to a windowproc or signal a
117// windows event
118//
119// Note that we can do these both, I.E. if an IMediaSeekingEx interface
120// is unavailable we can check the position instead of an event
121//
122//---------------------------------------------------------------------------
1a680109 123
ff4aedc5 124//---------------------------------------------------------------------------
a2a444e3
RN
125// COM includes
126//---------------------------------------------------------------------------
127#include "wx/msw/ole/oleutils.h" //wxBasicString, IID etc.
128#include "wx/msw/ole/uuid.h" //IID etc..
129
920a7c15
JS
130//---------------------------------------------------------------------------
131// COM compatability definitions
132//---------------------------------------------------------------------------
133#ifndef STDMETHODCALLTYPE
134#define STDMETHODCALLTYPE __stdcall
135#endif
136#ifndef STDMETHOD
137#define STDMETHOD(funcname) virtual HRESULT STDMETHODCALLTYPE funcname
138#endif
139#ifndef PURE
140#define PURE = 0
141#endif
a2a444e3
RN
142//---------------------------------------------------------------------------
143// IIDS - used by CoCreateInstance and IUnknown::QueryInterface
920a7c15
JS
144// Dumped from amstream.idl, quartz.idl, direct draw and with some
145// confirmation from WINE
146//
147// Some of these are not used but are kept here for future reference anyway
a2a444e3 148//---------------------------------------------------------------------------
920a7c15
JS
149
150//QUARTZ
a2a444e3
RN
151const IID LIBID_QuartzTypeLib = {0x56A868B0,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
152const IID IID_IAMCollection = {0x56A868B9,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
153const IID IID_IMediaControl = {0x56A868B1,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
154const IID IID_IMediaEvent = {0x56A868B6,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
155const IID IID_IMediaEventEx = {0x56A868C0,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
156const IID IID_IMediaPosition = {0x56A868B2,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
157const IID IID_IBasicAudio = {0x56A868B3,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
158const IID IID_IVideoWindow = {0x56A868B4,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
159const IID IID_IBasicVideo = {0x56A868B5,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
160const IID IID_IBasicVideo2 = {0x329BB360,0xF6EA,0x11D1,{0x90,0x38,0x00,0xA0,0xC9,0x69,0x72,0x98}};
161const IID IID_IDeferredCommand = {0x56A868B8,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
162const IID IID_IQueueCommand = {0x56A868B7,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
163const IID IID_IFilterInfo = {0x56A868BA,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
164const IID IID_IRegFilterInfo = {0x56A868BB,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
165const IID IID_IMediaTypeInfo = {0x56A868BC,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
166const IID IID_IPinInfo = {0x56A868BD,0x0AD4,0x11CE,{0xB0,0x3A,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
167const IID IID_IAMStats = {0xBC9BCF80,0xDCD2,0x11D2,{0xAB,0xF6,0x00,0xA0,0xC9,0x05,0xF3,0x75}};
a2a444e3
RN
168const CLSID CLSID_FilgraphManager = {0xE436EBB3,0x524F,0x11CE,{0x9F,0x53,0x00,0x20,0xAF,0x0B,0xA7,0x70}};
169
920a7c15
JS
170//AMSTREAM
171const CLSID CLSID_AMMultiMediaStream = {0x49C47CE5, 0x9BA4, 0x11D0,{0x82, 0x12, 0x00, 0xC0, 0x4F, 0xC3, 0x2C, 0x45}};
172const IID IID_IAMMultiMediaStream = {0xBEBE595C, 0x9A6F, 0x11D0,{0x8F, 0xDE, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
173const IID IID_IDirectDrawMediaStream = {0xF4104FCE, 0x9A70, 0x11D0,{0x8F, 0xDE, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
174const GUID MSPID_PrimaryVideo = {0xa35FF56A, 0x9FDA, 0x11D0,{0x8F, 0xDF, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
175const GUID MSPID_PrimaryAudio = {0xa35FF56B, 0x9FDA, 0x11D0,{0x8F, 0xDF, 0x00, 0xC0, 0x4F, 0xD9, 0x18, 0x9D}};
176
177//DDRAW
178const IID IID_IDirectDraw = {0x6C14DB80,0xA733,0x11CE,{0xA5,0x21,0x00,0x20,0xAF,0x0B,0xE5,0x60}};
179const CLSID CLSID_DirectDraw = {0xD7B70EE0,0x4340,0x11CF,{0xB0,0x63,0x00,0x20,0xAF,0xC2,0xCD,0x35}};
180
181//?? QUARTZ Also?
182const CLSID CLSID_VideoMixingRenderer = {0xB87BEB7B, 0x8D29, 0x423F,{0xAE, 0x4D, 0x65, 0x82, 0xC1, 0x01, 0x75, 0xAC}};
183const IID IID_IVMRWindowlessControl = {0x0EB1088C, 0x4DCD, 0x46F0,{0x87, 0x8F, 0x39, 0xDA, 0xE8, 0x6A, 0x51, 0xB7}};
184const IID IID_IFilterGraph = {0x56A8689F, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
185const IID IID_IGraphBuilder = {0x56A868A9, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
186const IID IID_IVMRFilterConfig = {0x9E5530C5, 0x7034, 0x48B4,{0xBB, 0x46, 0x0B, 0x8A, 0x6E, 0xFC, 0x8E, 0x36}};
187const IID IID_IBaseFilter = {0x56A86895, 0x0AD4, 0x11CE,{0xB0, 0x3A, 0x00, 0x20, 0xAF, 0x0B, 0xA7, 0x70}};
188
189//---------------------------------------------------------------------------
190// DIRECTDRAW COM INTERFACES
191//---------------------------------------------------------------------------
192//DDSURFACESDESC - we don't need most of the stuff here, esp. DDPIXELFORMAT,
193//so just put stubs in
194struct DDPIXELFORMAT {DWORD dw1,dw2,dw3,dw4,dw5,dw6,dw7,dw8;};
195struct DDCOLORKEY {DWORD dwLow, dwHigh;};
196
197typedef struct IDirectDrawClipper* LPDIRECTDRAWCLIPPER;
198typedef struct IDirectDraw* LPDIRECTDRAW;
199typedef struct IDirectDrawSurface* LPDIRECTDRAWSURFACE;
200typedef struct DDSURFACEDESC* LPDDSURFACEDESC;
201typedef struct IDirectDrawPalette* LPDIRECTDRAWPALETTE;
202typedef struct DDSCAPS* LPDDSCAPS;
203typedef DDCOLORKEY* LPDDCOLORKEY;
204typedef DDPIXELFORMAT* LPDDPIXELFORMAT;
205typedef struct DDCAPS* LPDDCAPS;
206
207struct DDSURFACEDESC
208{
209 DWORD dwSize;
210 DWORD dwFlags;
211 DWORD dwHeight;
212 DWORD dwWidth;
213 union
214 {
215 LONG lPitch;
216 DWORD dwLinearSize;
217 };
218 DWORD dwBackBufferCount;
219 union
220 {
221 DWORD dwMipMapCount;
222 DWORD dwZBufferBitDepth;
223 DWORD dwRefreshRate;
224 };
225 DWORD dwAlphaBitDepth;
226 DWORD dwReserved;
227 LPVOID lpSurface;
228 DDCOLORKEY ddckCKDestOverlay;
229 DDCOLORKEY ddckCKDestBlt;
230 DDCOLORKEY ddckCKSrcOverlay;
231 DDCOLORKEY ddckCKSrcBlt;
232 DDPIXELFORMAT ddpfPixelFormat;
233 struct DDSCAPS {DWORD dwCaps;} ddsCaps;
a2a444e3
RN
234};
235
920a7c15 236struct IDirectDrawClipper : public IUnknown
a2a444e3 237{
920a7c15
JS
238 STDMETHOD(GetClipList)(LPRECT, LPRGNDATA, LPDWORD) PURE;
239 STDMETHOD(GetHWnd)(HWND*) PURE;
240 STDMETHOD(Initialize)(LPDIRECTDRAW, DWORD) PURE;
241 STDMETHOD(IsClipListChanged)(BOOL*) PURE;
242 STDMETHOD(SetClipList)(LPRGNDATA,DWORD) PURE;
243 STDMETHOD(SetHWnd)(DWORD, HWND) PURE;
a2a444e3
RN
244};
245
920a7c15
JS
246struct IDirectDrawSurface : public IUnknown
247{
248 STDMETHOD(AddAttachedSurface)(LPDIRECTDRAWSURFACE) PURE;
249 STDMETHOD(AddOverlayDirtyRect)(LPRECT) PURE;
250 STDMETHOD(Blt)(LPRECT,LPDIRECTDRAWSURFACE, LPRECT,DWORD, struct DDBLTFX*) PURE;
251 STDMETHOD(BltBatch)(struct DDBLTBATCH*, DWORD, DWORD ) PURE;
252 STDMETHOD(BltFast)(DWORD,DWORD,LPDIRECTDRAWSURFACE, LPRECT,DWORD) PURE;
253 STDMETHOD(DeleteAttachedSurface)(DWORD,LPDIRECTDRAWSURFACE) PURE;
254 STDMETHOD(EnumAttachedSurfaces)(LPVOID, LPVOID/*LPDDENUMSURFACESCALLBACK*/) PURE;
255 STDMETHOD(EnumOverlayZOrders)(DWORD,LPVOID,LPVOID/*LPDDENUMSURFACESCALLBACK*/) PURE;
256 STDMETHOD(Flip)(LPDIRECTDRAWSURFACE, DWORD) PURE;
257 STDMETHOD(GetAttachedSurface)(LPDDSCAPS, LPDIRECTDRAWSURFACE*) PURE;
258 STDMETHOD(GetBltStatus)(DWORD) PURE;
259 STDMETHOD(GetCaps)(LPDDSCAPS) PURE;
260 STDMETHOD(GetClipper)(LPDIRECTDRAWCLIPPER*) PURE;
261 STDMETHOD(GetColorKey)(DWORD, LPDDCOLORKEY) PURE;
262 STDMETHOD(GetDC)(HDC *) PURE;
263 STDMETHOD(GetFlipStatus)(DWORD) PURE;
264 STDMETHOD(GetOverlayPosition)(LPLONG, LPLONG ) PURE;
265 STDMETHOD(GetPalette)(LPDIRECTDRAWPALETTE FAR*) PURE;
266 STDMETHOD(GetPixelFormat)(LPDDPIXELFORMAT) PURE;
267 STDMETHOD(GetSurfaceDesc)(LPDDSURFACEDESC) PURE;
268 STDMETHOD(Initialize)(LPDIRECTDRAW, LPDDSURFACEDESC) PURE;
269 STDMETHOD(IsLost)(THIS) PURE;
270 STDMETHOD(Lock)(LPRECT,LPDDSURFACEDESC,DWORD,HANDLE) PURE;
271 STDMETHOD(ReleaseDC)(HDC) PURE;
272 STDMETHOD(Restore)(THIS) PURE;
273 STDMETHOD(SetClipper)(LPDIRECTDRAWCLIPPER) PURE;
274 STDMETHOD(SetColorKey)(DWORD, LPDDCOLORKEY) PURE;
275 STDMETHOD(SetOverlayPosition)(LONG, LONG ) PURE;
276 STDMETHOD(SetPalette)(IUnknown*) PURE;
277 STDMETHOD(Unlock)(LPVOID) PURE;
278 STDMETHOD(UpdateOverlay)(LPRECT, LPDIRECTDRAWSURFACE,LPRECT,
279 DWORD, struct DDOVERLAYFX*) PURE;
280 STDMETHOD(UpdateOverlayDisplay)(DWORD) PURE;
281 STDMETHOD(UpdateOverlayZOrder)(DWORD, LPDIRECTDRAWSURFACE) PURE;
a2a444e3
RN
282};
283
920a7c15
JS
284struct IDirectDraw : public IUnknown
285{
286 STDMETHOD(Compact)() PURE;
287 STDMETHOD(CreateClipper)(DWORD, LPDIRECTDRAWCLIPPER*, IUnknown * ) PURE;
288 STDMETHOD(CreatePalette)(DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE *, IUnknown * ) PURE;
289 STDMETHOD(CreateSurface)(LPDDSURFACEDESC, LPDIRECTDRAWSURFACE *, IUnknown *) PURE;
290 STDMETHOD(DuplicateSurface)(LPDIRECTDRAWSURFACE, LPDIRECTDRAWSURFACE * ) PURE;
291 STDMETHOD(EnumDisplayModes)(DWORD, LPDDSURFACEDESC, LPVOID, LPVOID ) PURE;
292 STDMETHOD(EnumSurfaces)(DWORD, LPDDSURFACEDESC, LPVOID,LPVOID ) PURE;
293 STDMETHOD(FlipToGDISurface)() PURE;
294 STDMETHOD(GetCaps)(LPDDCAPS, LPDDCAPS) PURE;
295 STDMETHOD(GetDisplayMode)(LPDDSURFACEDESC) PURE;
296 STDMETHOD(GetFourCCCodes)(LPDWORD, LPDWORD ) PURE;
297 STDMETHOD(GetGDISurface)(LPDIRECTDRAWSURFACE *) PURE;
298 STDMETHOD(GetMonitorFrequency)(LPDWORD) PURE;
299 STDMETHOD(GetScanLine)(LPDWORD) PURE;
300 STDMETHOD(GetVerticalBlankStatus)(LPBOOL ) PURE;
301 STDMETHOD(Initialize)(GUID *) PURE;
302 STDMETHOD(RestoreDisplayMode)() PURE;
303 STDMETHOD(SetCooperativeLevel)(HWND, DWORD) PURE;
304 STDMETHOD(SetDisplayMode)(DWORD, DWORD,DWORD, DWORD, DWORD) PURE;
305 STDMETHOD(WaitForVerticalBlank)(DWORD, HANDLE ) PURE;
306};
307
308//---------------------------------------------------------------------------
309// AMMEDIA COM INTERFACES
310//---------------------------------------------------------------------------
311struct IMediaStream;
312struct IMultiMediaStream;
313struct IStreamSample : public IUnknown
a2a444e3
RN
314{
315public:
920a7c15
JS
316 STDMETHOD(GetMediaStream)(IMediaStream **) PURE;
317 STDMETHOD(GetSampleTimes)(LONGLONG *, LONGLONG *, LONGLONG *) PURE;
318 STDMETHOD(SetSampleTimes)(const LONGLONG *, const LONGLONG *) PURE;
319 STDMETHOD(Update)(DWORD, HANDLE, LPVOID, DWORD_PTR) PURE;
320 STDMETHOD(CompletionStatus)(DWORD, DWORD) PURE;
a2a444e3 321};
b11eba7e 322
920a7c15 323struct IDirectDrawStreamSample : public IStreamSample
a2a444e3
RN
324{
325public:
920a7c15
JS
326 STDMETHOD(GetSurface)(IDirectDrawSurface **, RECT *) PURE;
327 STDMETHOD(SetRect)(const RECT *) PURE;
a2a444e3
RN
328};
329
920a7c15 330struct IMediaStream : public IUnknown
a2a444e3 331{
920a7c15
JS
332 STDMETHOD(GetMultiMediaStream)(IMultiMediaStream **) PURE;
333 STDMETHOD(GetInformation)(GUID *, int *) PURE;
334 STDMETHOD(SetSameFormat)(IMediaStream *, DWORD) PURE;
335 STDMETHOD(AllocateSample)(DWORD, IStreamSample **) PURE;
336 STDMETHOD(CreateSharedSample)(IStreamSample *, DWORD,
337 IStreamSample **) PURE;
338 STDMETHOD(SendEndOfStream)(DWORD dwFlags) PURE;
a2a444e3 339};
b11eba7e 340
920a7c15 341struct IDirectDrawMediaStream : public IMediaStream
a2a444e3 342{
920a7c15
JS
343 STDMETHOD(GetFormat)(DDSURFACEDESC *, IDirectDrawPalette **,
344 DDSURFACEDESC *, DWORD *) PURE;
345 STDMETHOD(SetFormat)(const DDSURFACEDESC *, IDirectDrawPalette *) PURE;
346 STDMETHOD(GetDirectDraw)(IDirectDraw **) PURE;
347 STDMETHOD(SetDirectDraw)(IDirectDraw *) PURE;
348 STDMETHOD(CreateSample)(IDirectDrawSurface *, const RECT *,
349 DWORD, IDirectDrawStreamSample **) PURE;
350 STDMETHOD(GetTimePerFrame)(LONGLONG *) PURE;
351};
b11eba7e 352
920a7c15
JS
353struct IMultiMediaStream : public IUnknown
354{
355 STDMETHOD(GetInformation)(DWORD *, int *) PURE;
356 STDMETHOD(GetMediaStream)(REFGUID, IMediaStream **) PURE;
357 STDMETHOD(EnumMediaStreams)(long, IMediaStream **) PURE;
358 STDMETHOD(GetState)(int *pCurrentState) PURE;
359 STDMETHOD(SetState)(int NewState) PURE;
360 STDMETHOD(GetTime)(LONGLONG *pCurrentTime) PURE;
361 STDMETHOD(GetDuration)(LONGLONG *pDuration) PURE;
362 STDMETHOD(Seek)(LONGLONG SeekTime) PURE;
363 STDMETHOD(GetEndOfStreamEventHandle)(HANDLE *phEOS) PURE;
a2a444e3 364};
1a680109 365
920a7c15 366struct IAMMultiMediaStream : public IMultiMediaStream
a2a444e3 367{
920a7c15
JS
368 STDMETHOD(Initialize)(int, DWORD, IUnknown *) PURE;
369 STDMETHOD(GetFilterGraph)(IUnknown **) PURE;
370 STDMETHOD(GetFilter)(IUnknown **) PURE;
371 STDMETHOD(AddMediaStream)(IUnknown *, const GUID*, DWORD,
372 IMediaStream **) PURE;
373 STDMETHOD(OpenFile)(LPCWSTR, DWORD) PURE;
374 STDMETHOD(OpenMoniker)(IBindCtx *, IMoniker *, DWORD) PURE;
375 STDMETHOD(Render)(DWORD) PURE;
a2a444e3 376};
b11eba7e 377
920a7c15
JS
378//---------------------------------------------------------------------------
379// QUARTZ COM INTERFACES (dumped from quartz.idl from MSVC COM Browser)
380//---------------------------------------------------------------------------
381struct IAMCollection : public IDispatch
a2a444e3 382{
920a7c15
JS
383 STDMETHOD(get_Count)(long *) PURE;
384 STDMETHOD(Item)(long, IUnknown **) PURE;
385 STDMETHOD(get__NewEnum)(IUnknown **) PURE;
386};
b11eba7e 387
920a7c15
JS
388struct IMediaControl : public IDispatch
389{
390 STDMETHOD(Run)() PURE;
391 STDMETHOD(Pause)() PURE;
392 STDMETHOD(Stop)() PURE;
393 STDMETHOD(GetState)(long, long*) PURE;
394 STDMETHOD(RenderFile)(BSTR) PURE;
395 STDMETHOD(AddSourceFilter)(BSTR, IDispatch **) PURE;
396 STDMETHOD(get_FilterCollection)(IDispatch **) PURE;
397 STDMETHOD(get_RegFilterCollection)(IDispatch **) PURE;
398 STDMETHOD(StopWhenReady)() PURE;
a2a444e3 399};
b11eba7e 400
920a7c15 401struct IMediaEvent : public IDispatch
a2a444e3 402{
920a7c15
JS
403 STDMETHOD(GetEventHandle)(LONG_PTR *) PURE;
404 STDMETHOD(GetEvent)(long *, LONG_PTR *, LONG_PTR *, long) PURE;
405 STDMETHOD(WaitForCompletion)(long, long *) PURE;
406 STDMETHOD(CancelDefaultHandling)(long) PURE;
407 STDMETHOD(RestoreDefaultHandling)(long) PURE;
408 STDMETHOD(FreeEventParams)(long, LONG_PTR, LONG_PTR) PURE;
a2a444e3
RN
409};
410
920a7c15 411struct IMediaEventEx : public IMediaEvent
a2a444e3 412{
920a7c15
JS
413 STDMETHOD(SetNotifyWindow)(LONG_PTR, long, LONG_PTR) PURE;
414 STDMETHOD(SetNotifyFlags)(long) PURE;
415 STDMETHOD(GetNotifyFlags)(long *) PURE;
416};
b11eba7e 417
920a7c15
JS
418struct IMediaPosition : public IDispatch
419{
420 STDMETHOD(get_Duration)(double *) PURE;
421 STDMETHOD(put_CurrentPosition)(double) PURE;
422 STDMETHOD(get_CurrentPosition)(double *) PURE;
423 STDMETHOD(get_StopTime)(double *) PURE;
424 STDMETHOD(put_StopTime)(double) PURE;
425 STDMETHOD(get_PrerollTime)(double *) PURE;
426 STDMETHOD(put_PrerollTime)(double) PURE;
427 STDMETHOD(put_Rate)(double) PURE;
428 STDMETHOD(get_Rate)(double *) PURE;
429 STDMETHOD(CanSeekForward)(long *) PURE;
430 STDMETHOD(CanSeekBackward)(long *) PURE;
a2a444e3 431};
b11eba7e 432
920a7c15 433struct IBasicAudio : public IDispatch
a2a444e3 434{
920a7c15
JS
435 STDMETHOD(put_Volume)(long) PURE;
436 STDMETHOD(get_Volume)(long *) PURE;
437 STDMETHOD(put_Balance)(long) PURE;
438 STDMETHOD(get_Balance)(long *) PURE;
a2a444e3 439};
b11eba7e 440
920a7c15
JS
441//---------------------------------------------------------------------------
442// MISC COM INTERFACES
443//---------------------------------------------------------------------------
444struct IVMRWindowlessControl : public IUnknown
445{
446 STDMETHOD(GetNativeVideoSize)(LONG *, LONG *, LONG *, LONG *) PURE;
447 STDMETHOD(GetMinIdealVideoSize)(LONG *, LONG *) PURE;
448 STDMETHOD(GetMaxIdealVideoSize)(LONG *, LONG *) PURE;
449 STDMETHOD(SetVideoPosition)(const LPRECT,const LPRECT) PURE;
450 STDMETHOD(GetVideoPosition)(LPRECT, LPRECT) PURE;
451 STDMETHOD(GetAspectRatioMode)(DWORD *) PURE;
452 STDMETHOD(SetAspectRatioMode)(DWORD) PURE;
453 STDMETHOD(SetVideoClippingWindow)(HWND) PURE;
454 STDMETHOD(RepaintVideo)(HWND, HDC) PURE;
455 STDMETHOD(DisplayModeChanged)() PURE;
456 STDMETHOD(GetCurrentImage)(BYTE **) PURE;
457 STDMETHOD(SetBorderColor)(COLORREF) PURE;
458 STDMETHOD(GetBorderColor)(COLORREF *) PURE;
459 STDMETHOD(SetColorKey)(COLORREF) PURE;
460 STDMETHOD(GetColorKey)(COLORREF *) PURE;
461};
b11eba7e 462
920a7c15 463typedef IUnknown IVMRImageCompositor;
b11eba7e 464
920a7c15
JS
465struct IVMRFilterConfig : public IUnknown
466{
467 STDMETHOD(SetImageCompositor)(IVMRImageCompositor *) PURE;
468 STDMETHOD(SetNumberOfStreams)(DWORD) PURE;
469 STDMETHOD(GetNumberOfStreams)(DWORD *) PURE;
470 STDMETHOD(SetRenderingPrefs)(DWORD) PURE;
471 STDMETHOD(GetRenderingPrefs)(DWORD *) PURE;
472 STDMETHOD(SetRenderingMode)(DWORD) PURE;
473 STDMETHOD(GetRenderingMode)(DWORD *) PURE;
474};
475
476typedef IUnknown IBaseFilter;
477typedef IUnknown IPin;
478typedef IUnknown IEnumFilters;
479typedef int AM_MEDIA_TYPE;
480
481struct IFilterGraph : public IUnknown
482{
483 STDMETHOD(AddFilter)(IBaseFilter *, LPCWSTR) PURE;
484 STDMETHOD(RemoveFilter)(IBaseFilter *) PURE;
485 STDMETHOD(EnumFilters)(IEnumFilters **) PURE;
486 STDMETHOD(FindFilterByName)(LPCWSTR, IBaseFilter **) PURE;
487 STDMETHOD(ConnectDirect)(IPin *, IPin *, const AM_MEDIA_TYPE *) PURE;
488 STDMETHOD(Reconnect)(IPin *) PURE;
489 STDMETHOD(Disconnect)(IPin *) PURE;
490 STDMETHOD(SetDefaultSyncSource)() PURE;
a2a444e3 491};
b11eba7e 492
920a7c15 493struct IGraphBuilder : public IFilterGraph
a2a444e3
RN
494{
495public:
920a7c15
JS
496 STDMETHOD(Connect)(IPin *, IPin *) PURE;
497 STDMETHOD(Render)(IPin *) PURE;
498 STDMETHOD(RenderFile)(LPCWSTR, LPCWSTR) PURE;
499 STDMETHOD(AddSourceFilter)(LPCWSTR, LPCWSTR, IBaseFilter **) PURE;
500 STDMETHOD(SetLogFile)(DWORD_PTR) PURE;
501 STDMETHOD(Abort)() PURE;
502 STDMETHOD(ShouldOperationContinue)() PURE;
a2a444e3 503};
b11eba7e 504
920a7c15
JS
505//------------------------------------------------------------------
506// wxAMMediaBackend (Active Movie)
507//------------------------------------------------------------------
508class WXDLLIMPEXP_MEDIA wxAMMediaThread : public wxThread
a2a444e3
RN
509{
510public:
920a7c15 511 virtual ExitCode Entry();
b11eba7e 512
920a7c15 513 class wxAMMediaBackend* pThis;
a2a444e3
RN
514};
515
920a7c15
JS
516//cludgy workaround for wx events. slots would be nice :)
517class WXDLLIMPEXP_MEDIA wxAMMediaEvtHandler : public wxEvtHandler
a2a444e3
RN
518{
519public:
920a7c15
JS
520 void OnPaint(wxPaintEvent&);
521 void OnMove(wxMoveEvent&);
522 void OnSize(wxSizeEvent&);
523 void OnEraseBackground(wxEraseEvent&);
a2a444e3
RN
524};
525
920a7c15
JS
526typedef BOOL (WINAPI* LPAMGETERRORTEXT)(HRESULT, wxChar *, DWORD);
527
ff2b312f 528class WXDLLIMPEXP_MEDIA wxAMMediaBackend : public wxMediaBackend
1a680109
RN
529{
530public:
ff4aedc5 531 wxAMMediaBackend();
1a680109 532
ff4aedc5 533 virtual ~wxAMMediaBackend();
1a680109 534
226ec5a7 535 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 536 wxWindowID id,
226ec5a7 537 const wxPoint& pos,
ff4aedc5 538 const wxSize& size,
226ec5a7 539 long style,
ff4aedc5
RN
540 const wxValidator& validator,
541 const wxString& name);
1a680109
RN
542
543 virtual bool Play();
544 virtual bool Pause();
545 virtual bool Stop();
546
547 virtual bool Load(const wxString& fileName);
548 virtual bool Load(const wxURI& location);
549
550 virtual wxMediaState GetState();
551
ff4aedc5
RN
552 virtual bool SetPosition(wxLongLong where);
553 virtual wxLongLong GetPosition();
554 virtual wxLongLong GetDuration();
1a680109 555
ff4aedc5
RN
556 virtual void Move(int x, int y, int w, int h);
557 wxSize GetVideoSize() const;
1a680109
RN
558
559 virtual double GetPlaybackRate();
560 virtual bool SetPlaybackRate(double);
561
6f8c67e7
JS
562 virtual double GetVolume();
563 virtual bool SetVolume(double);
564
1a680109 565 void Cleanup();
920a7c15
JS
566 void OnStop();
567 bool SetWindowlessMode(IGraphBuilder* pGB,
568 IVMRWindowlessControl** ppVMC = NULL);
1a680109 569
ff4aedc5 570 wxControl* m_ctrl;
1a680109 571
920a7c15
JS
572 wxMediaState m_state;
573 wxCriticalSection m_rendercs;
574
575 IVMRWindowlessControl* m_pVMC;
576 IGraphBuilder* m_pGB;
a2a444e3 577 IBasicAudio* m_pBA;
1a680109 578 IMediaControl* m_pMC;
920a7c15 579 IMediaEvent* m_pME;
a2a444e3 580 IMediaPosition* m_pMS;
920a7c15
JS
581
582 wxAMMediaThread* m_pThread;
1a680109
RN
583
584 wxSize m_bestSize;
ff4aedc5 585
920a7c15
JS
586#ifdef __WXDEBUG__
587 HMODULE m_hQuartzDll;
588 LPAMGETERRORTEXT m_lpAMGetErrorText;
589#endif
590
591 friend class wxAMMediaThread;
592 friend class wxAMMediaEvtHandler;
593
19b6f122 594 DECLARE_DYNAMIC_CLASS(wxAMMediaBackend)
1a680109
RN
595};
596
1a680109 597//---------------------------------------------------------------------------
ff4aedc5
RN
598//
599// wxMCIMediaBackend
600//
1a680109
RN
601//---------------------------------------------------------------------------
602
ff4aedc5
RN
603//---------------------------------------------------------------------------
604// MCI Includes
605//---------------------------------------------------------------------------
1a680109 606#include <mmsystem.h>
1a680109 607
ff2b312f 608class WXDLLIMPEXP_MEDIA wxMCIMediaBackend : public wxMediaBackend
1a680109
RN
609{
610public:
3f9a3bf9 611
ff4aedc5
RN
612 wxMCIMediaBackend();
613 ~wxMCIMediaBackend();
1a680109 614
226ec5a7 615 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 616 wxWindowID id,
226ec5a7 617 const wxPoint& pos,
ff4aedc5 618 const wxSize& size,
226ec5a7 619 long style,
ff4aedc5
RN
620 const wxValidator& validator,
621 const wxString& name);
1a680109
RN
622
623 virtual bool Play();
624 virtual bool Pause();
625 virtual bool Stop();
626
627 virtual bool Load(const wxString& fileName);
628 virtual bool Load(const wxURI& location);
629
630 virtual wxMediaState GetState();
631
ff4aedc5
RN
632 virtual bool SetPosition(wxLongLong where);
633 virtual wxLongLong GetPosition();
634 virtual wxLongLong GetDuration();
1a680109 635
ff4aedc5
RN
636 virtual void Move(int x, int y, int w, int h);
637 wxSize GetVideoSize() const;
1a680109
RN
638
639 virtual double GetPlaybackRate();
ff4aedc5 640 virtual bool SetPlaybackRate(double dRate);
3f9a3bf9 641
6f8c67e7
JS
642 virtual double GetVolume();
643 virtual bool SetVolume(double);
644
226ec5a7 645 static LRESULT CALLBACK NotifyWndProc(HWND hWnd, UINT nMsg,
ff4aedc5 646 WPARAM wParam, LPARAM lParam);
5987f174 647
226ec5a7 648 LRESULT CALLBACK OnNotifyWndProc(HWND hWnd, UINT nMsg,
ff4aedc5 649 WPARAM wParam, LPARAM lParam);
1a680109 650
ff4aedc5
RN
651 MCIDEVICEID m_hDev; //Our MCI Device ID/Handler
652 wxControl* m_ctrl; //Parent control
653 HWND m_hNotifyWnd; //Window to use for MCI events
654 bool m_bVideo; //Whether or not we have video
655
3839f37e 656 DECLARE_DYNAMIC_CLASS(wxMCIMediaBackend)
ff4aedc5 657};
1a680109
RN
658
659//---------------------------------------------------------------------------
660//
ff4aedc5 661// wxQTMediaBackend
1a680109
RN
662//
663//---------------------------------------------------------------------------
664
ff4aedc5
RN
665//---------------------------------------------------------------------------
666// QT Includes
667//---------------------------------------------------------------------------
d7a9c895
RN
668//#include <qtml.h> //Windoze QT include
669//#include <QuickTimeComponents.h> //Standard QT stuff
670#include "wx/dynlib.h"
671
672//---------------------------------------------------------------------------
673// QT Types
674//---------------------------------------------------------------------------
675typedef struct MovieRecord* Movie;
676typedef wxInt16 OSErr;
677typedef wxInt32 OSStatus;
678#define noErr 0
679#define fsRdPerm 1
680typedef unsigned char Str255[256];
681#define StringPtr unsigned char*
682#define newMovieActive 1
b11eba7e 683#define Ptr char*
d7a9c895
RN
684#define Handle Ptr*
685#define Fixed long
686#define OSType unsigned long
b11eba7e 687#define CGrafPtr struct GrafPort *
d7a9c895 688#define TimeScale long
b11eba7e 689#define TimeBase struct TimeBaseRecord *
d7a9c895 690
19b6f122
WS
691#ifndef URLDataHandlerSubType
692#if defined(__WATCOMC__) || defined(__MINGW32__)
693// use magic numbers for compilers which complain about multicharacter integers
694const OSType URLDataHandlerSubType = 1970433056;
695const OSType VisualMediaCharacteristic = 1702454643;
696#else
697const OSType URLDataHandlerSubType = 'url ';
698const OSType VisualMediaCharacteristic = 'eyes';
699#endif
700#endif
701
d7a9c895 702struct FSSpec {
600ffb32
WS
703 short vRefNum;
704 long parID;
705 Str255 name; /*Str63 on mac, Str255 on msw */
d7a9c895
RN
706};
707
708struct Rect {
600ffb32
WS
709 short top;
710 short left;
711 short bottom;
712 short right;
d7a9c895
RN
713};
714
715struct wide {
600ffb32
WS
716 wxInt32 hi;
717 wxUint32 lo;
d7a9c895
RN
718};
719
720struct TimeRecord {
600ffb32
WS
721 wide value; /* units */
722 TimeScale scale; /* units per second */
723 TimeBase base;
d7a9c895
RN
724};
725
726//---------------------------------------------------------------------------
727// QT Library
728//---------------------------------------------------------------------------
729#define wxDL_METHOD_DEFINE( rettype, name, args, shortargs, defret ) \
730 typedef rettype (* name ## Type) args ; \
731 name ## Type pfn_ ## name; \
732 rettype name args \
733 { if (m_ok) return pfn_ ## name shortargs ; return defret; }
b11eba7e 734
d7a9c895
RN
735#define wxDL_VOIDMETHOD_DEFINE( name, args, shortargs ) \
736 typedef void (* name ## Type) args ; \
737 name ## Type pfn_ ## name; \
738 void name args \
739 { if (m_ok) pfn_ ## name shortargs ; }
740
741#define wxDL_METHOD_LOAD( lib, name, success ) \
742 pfn_ ## name = (name ## Type) lib.GetSymbol( wxT(#name), &success ); \
743 if (!success) return false;
744
745//Class that utilizes Robert Roeblings Dynamic Library Macros
b11eba7e 746class WXDLLIMPEXP_MEDIA wxQuickTimeLibrary
d7a9c895
RN
747{
748public:
749 ~wxQuickTimeLibrary()
b11eba7e 750 {
d7a9c895
RN
751 if(m_dll.IsLoaded())
752 m_dll.Unload();
753 }
754
755 bool Initialize();
756 bool IsOk() const {return m_ok;}
757
758protected:
759 wxDynamicLibrary m_dll;
760 bool m_ok;
761
762public:
763 wxDL_VOIDMETHOD_DEFINE( StartMovie, (Movie m), (m) );
764 wxDL_VOIDMETHOD_DEFINE( StopMovie, (Movie m), (m) );
765 wxDL_METHOD_DEFINE( bool, IsMovieDone, (Movie m), (m), false);
766 wxDL_VOIDMETHOD_DEFINE( GoToBeginningOfMovie, (Movie m), (m) );
767 wxDL_METHOD_DEFINE( OSErr, GetMoviesError, (), (), -1);
768 wxDL_METHOD_DEFINE( OSErr, EnterMovies, (), (), -1);
769 wxDL_VOIDMETHOD_DEFINE( ExitMovies, (), () );
770 wxDL_METHOD_DEFINE( OSErr, InitializeQTML, (long flags), (flags), -1);
771 wxDL_VOIDMETHOD_DEFINE( TerminateQTML, (), () );
772
b11eba7e
WS
773 wxDL_METHOD_DEFINE( OSErr, NativePathNameToFSSpec,
774 (char* inName, FSSpec* outFile, long flags),
d7a9c895
RN
775 (inName, outFile, flags), -1);
776
b11eba7e 777 wxDL_METHOD_DEFINE( OSErr, OpenMovieFile,
d7a9c895
RN
778 (const FSSpec * fileSpec, short * resRefNum, wxInt8 permission),
779 (fileSpec, resRefNum, permission), -1 );
780
781 wxDL_METHOD_DEFINE( OSErr, CloseMovieFile,
782 (short resRefNum), (resRefNum), -1);
783
784 wxDL_METHOD_DEFINE( OSErr, NewMovieFromFile,
785 (Movie * theMovie, short resRefNum, short * resId,
786 StringPtr resName, short newMovieFlags,
b11eba7e 787 bool * dataRefWasChanged),
d7a9c895
RN
788 (theMovie, resRefNum, resId, resName, newMovieFlags,
789 dataRefWasChanged), -1);
790
791 wxDL_VOIDMETHOD_DEFINE( SetMovieRate, (Movie m, Fixed rate), (m, rate) );
792 wxDL_METHOD_DEFINE( Fixed, GetMovieRate, (Movie m), (m), 0);
793 wxDL_VOIDMETHOD_DEFINE( MoviesTask, (Movie m, long maxms), (m, maxms) );
b11eba7e 794 wxDL_VOIDMETHOD_DEFINE( BlockMove,
d7a9c895
RN
795 (const char* p1, const char* p2, long s), (p1,p2,s) );
796 wxDL_METHOD_DEFINE( Handle, NewHandleClear, (long s), (s), NULL );
797
b11eba7e 798 wxDL_METHOD_DEFINE( OSErr, NewMovieFromDataRef,
d7a9c895
RN
799 (Movie * m, short flags, short * id,
800 Handle dataRef, OSType dataRefType),
801 (m,flags,id,dataRef,dataRefType), -1 );
802
803 wxDL_VOIDMETHOD_DEFINE( DisposeHandle, (Handle h), (h) );
804 wxDL_VOIDMETHOD_DEFINE( GetMovieNaturalBoundsRect, (Movie m, Rect* r), (m,r) );
b11eba7e
WS
805 wxDL_METHOD_DEFINE( void*, GetMovieIndTrackType,
806 (Movie m, long index, OSType type, long flags),
d7a9c895 807 (m,index,type,flags), NULL );
b11eba7e 808 wxDL_VOIDMETHOD_DEFINE( CreatePortAssociation,
d7a9c895
RN
809 (void* hWnd, void* junk, long morejunk), (hWnd, junk, morejunk) );
810 wxDL_METHOD_DEFINE(void*, GetNativeWindowPort, (void* hWnd), (hWnd), NULL);
811 wxDL_VOIDMETHOD_DEFINE(SetMovieGWorld, (Movie m, CGrafPtr port, void* whatever),
812 (m, port, whatever) );
813 wxDL_VOIDMETHOD_DEFINE(DisposeMovie, (Movie m), (m) );
814 wxDL_VOIDMETHOD_DEFINE(SetMovieBox, (Movie m, Rect* r), (m,r));
815 wxDL_VOIDMETHOD_DEFINE(SetMovieTimeScale, (Movie m, long s), (m,s));
816 wxDL_METHOD_DEFINE(long, GetMovieDuration, (Movie m), (m), 0);
817 wxDL_METHOD_DEFINE(TimeBase, GetMovieTimeBase, (Movie m), (m), 0);
818 wxDL_METHOD_DEFINE(TimeScale, GetMovieTimeScale, (Movie m), (m), 0);
819 wxDL_METHOD_DEFINE(long, GetMovieTime, (Movie m, void* cruft), (m,cruft), 0);
820 wxDL_VOIDMETHOD_DEFINE(SetMovieTime, (Movie m, TimeRecord* tr), (m,tr) );
6f8c67e7
JS
821 wxDL_METHOD_DEFINE(short, GetMovieVolume, (Movie m), (m), 0);
822 wxDL_VOIDMETHOD_DEFINE(SetMovieVolume, (Movie m, short sVolume), (m,sVolume) );
d7a9c895
RN
823};
824
825bool wxQuickTimeLibrary::Initialize()
826{
827 m_ok = false;
828
829 if(!m_dll.Load(wxT("qtmlClient.dll")))
830 return false;
831
832 bool bOk;
833
834 wxDL_METHOD_LOAD( m_dll, StartMovie, bOk );
835 wxDL_METHOD_LOAD( m_dll, StopMovie, bOk );
836 wxDL_METHOD_LOAD( m_dll, IsMovieDone, bOk );
837 wxDL_METHOD_LOAD( m_dll, GoToBeginningOfMovie, bOk );
838 wxDL_METHOD_LOAD( m_dll, GetMoviesError, bOk );
839 wxDL_METHOD_LOAD( m_dll, EnterMovies, bOk );
840 wxDL_METHOD_LOAD( m_dll, ExitMovies, bOk );
841 wxDL_METHOD_LOAD( m_dll, InitializeQTML, bOk );
842 wxDL_METHOD_LOAD( m_dll, TerminateQTML, bOk );
843 wxDL_METHOD_LOAD( m_dll, NativePathNameToFSSpec, bOk );
844 wxDL_METHOD_LOAD( m_dll, OpenMovieFile, bOk );
845 wxDL_METHOD_LOAD( m_dll, CloseMovieFile, bOk );
846 wxDL_METHOD_LOAD( m_dll, NewMovieFromFile, bOk );
847 wxDL_METHOD_LOAD( m_dll, GetMovieRate, bOk );
848 wxDL_METHOD_LOAD( m_dll, SetMovieRate, bOk );
849 wxDL_METHOD_LOAD( m_dll, MoviesTask, bOk );
850 wxDL_METHOD_LOAD( m_dll, BlockMove, bOk );
851 wxDL_METHOD_LOAD( m_dll, NewHandleClear, bOk );
852 wxDL_METHOD_LOAD( m_dll, NewMovieFromDataRef, bOk );
853 wxDL_METHOD_LOAD( m_dll, DisposeHandle, bOk );
854 wxDL_METHOD_LOAD( m_dll, GetMovieNaturalBoundsRect, bOk );
855 wxDL_METHOD_LOAD( m_dll, GetMovieIndTrackType, bOk );
856 wxDL_METHOD_LOAD( m_dll, CreatePortAssociation, bOk );
857 wxDL_METHOD_LOAD( m_dll, GetNativeWindowPort, bOk );
858 wxDL_METHOD_LOAD( m_dll, SetMovieGWorld, bOk );
859 wxDL_METHOD_LOAD( m_dll, DisposeMovie, bOk );
860 wxDL_METHOD_LOAD( m_dll, SetMovieBox, bOk );
861 wxDL_METHOD_LOAD( m_dll, SetMovieTimeScale, bOk );
862 wxDL_METHOD_LOAD( m_dll, GetMovieDuration, bOk );
863 wxDL_METHOD_LOAD( m_dll, GetMovieTimeBase, bOk );
864 wxDL_METHOD_LOAD( m_dll, GetMovieTimeScale, bOk );
865 wxDL_METHOD_LOAD( m_dll, GetMovieTime, bOk );
866 wxDL_METHOD_LOAD( m_dll, SetMovieTime, bOk );
6f8c67e7
JS
867 wxDL_METHOD_LOAD( m_dll, GetMovieVolume, bOk );
868 wxDL_METHOD_LOAD( m_dll, SetMovieVolume, bOk );
b11eba7e 869
d7a9c895
RN
870 m_ok = true;
871
872 return true;
873}
1a680109 874
ff2b312f 875class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackend
ff4aedc5
RN
876{
877public:
ff4aedc5
RN
878 wxQTMediaBackend();
879 ~wxQTMediaBackend();
1a680109 880
226ec5a7 881 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 882 wxWindowID id,
226ec5a7 883 const wxPoint& pos,
ff4aedc5 884 const wxSize& size,
226ec5a7 885 long style,
ff4aedc5
RN
886 const wxValidator& validator,
887 const wxString& name);
1a680109 888
ff4aedc5
RN
889 virtual bool Play();
890 virtual bool Pause();
891 virtual bool Stop();
1a680109 892
ff4aedc5
RN
893 virtual bool Load(const wxString& fileName);
894 virtual bool Load(const wxURI& location);
1a680109 895
ff4aedc5 896 virtual wxMediaState GetState();
1a680109 897
ff4aedc5
RN
898 virtual bool SetPosition(wxLongLong where);
899 virtual wxLongLong GetPosition();
900 virtual wxLongLong GetDuration();
1a680109 901
ff4aedc5
RN
902 virtual void Move(int x, int y, int w, int h);
903 wxSize GetVideoSize() const;
1a680109 904
ff4aedc5
RN
905 virtual double GetPlaybackRate();
906 virtual bool SetPlaybackRate(double dRate);
1a680109 907
6f8c67e7
JS
908 virtual double GetVolume();
909 virtual bool SetVolume(double);
910
ff4aedc5
RN
911 void Cleanup();
912 void FinishLoad();
1a680109 913
ff4aedc5 914 wxSize m_bestSize; //Original movie size
d7a9c895 915 Movie m_movie; //QT Movie handle/instance
ff4aedc5
RN
916 wxControl* m_ctrl; //Parent control
917 bool m_bVideo; //Whether or not we have video
918 class _wxQTTimer* m_timer; //Timer for streaming the movie
d7a9c895
RN
919 wxQuickTimeLibrary m_lib;
920
19b6f122 921 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend)
ff4aedc5 922};
1a680109 923
1a680109 924
ff4aedc5
RN
925//===========================================================================
926// IMPLEMENTATION
927//===========================================================================
1a680109 928
ff4aedc5
RN
929//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
930//
931// wxAMMediaBackend
932//
933//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1a680109 934
ff4aedc5 935IMPLEMENT_DYNAMIC_CLASS(wxAMMediaBackend, wxMediaBackend);
1a680109 936
ff4aedc5
RN
937//---------------------------------------------------------------------------
938// Usual debugging macros
939//---------------------------------------------------------------------------
940#ifdef __WXDEBUG__
920a7c15
JS
941#include "wx/msgdlg.h"
942#define MAX_ERROR_TEXT_LEN 160
943//
944// FIXME : Just use wxASSERT_MSG here instead of msgdlg - but
945// stackwalker still crashes win2k, so do msgdlg for now...
946//
ff4aedc5
RN
947#define wxAMVERIFY(x) \
948{ \
949 HRESULT hrdsv = (x); \
950 if ( FAILED(hrdsv) ) \
951 { \
920a7c15
JS
952 wxChar szError[MAX_ERROR_TEXT_LEN]; \
953 if( m_lpAMGetErrorText != NULL && \
954 (*m_lpAMGetErrorText)(hrdsv, szError, MAX_ERROR_TEXT_LEN) == 0) \
955 { \
956 wxMessageBox( wxString::Format(wxT("DirectShow error \"%s\" \n")\
957 wxT("(numeric %i)\n")\
958 wxT("occured at line %i in ") \
959 wxT("mediactrl.cpp"), \
960 (int)hrdsv, szError, __LINE__) ); \
961 wxASSERT(false);\
962 } \
963 else \
964 { \
965 wxMessageBox( wxString::Format(wxT("Unknown error (%i) ") \
3103e8a9 966 wxT("occurred at") \
ff4aedc5
RN
967 wxT(" line %i in mediactrl.cpp."), \
968 (int)hrdsv, __LINE__) ); \
920a7c15
JS
969 wxASSERT(false);\
970 } \
ff4aedc5 971 } \
1a680109 972}
ff4aedc5
RN
973#define wxVERIFY(x) wxASSERT((x))
974#else
975#define wxAMVERIFY(x) (x)
976#define wxVERIFY(x) (x)
977#endif
1a680109 978
ff4aedc5
RN
979//---------------------------------------------------------------------------
980// Standard macros for ease of use
981//---------------------------------------------------------------------------
982#define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
1a680109 983
ff4aedc5
RN
984//---------------------------------------------------------------------------
985// wxAMMediaBackend Constructor
986//
987// Sets m_hNotifyWnd to NULL to signify that we haven't loaded anything yet
226ec5a7 988//---------------------------------------------------------------------------
920a7c15
JS
989wxAMMediaBackend::wxAMMediaBackend() : m_state(wxMEDIASTATE_STOPPED),
990m_pVMC(NULL)
991 #ifdef __WXDEBUG__
992 , m_hQuartzDll(NULL)
993 #endif
1a680109 994{
1a680109
RN
995}
996
ff4aedc5
RN
997//---------------------------------------------------------------------------
998// wxAMMediaBackend Destructor
999//
226ec5a7
WS
1000// Cleans up everything
1001//---------------------------------------------------------------------------
ff4aedc5 1002wxAMMediaBackend::~wxAMMediaBackend()
1a680109 1003{
920a7c15 1004 if (m_pVMC)
ff4aedc5 1005 Cleanup();
920a7c15
JS
1006#ifdef __WXDEBUG__
1007 if(m_hQuartzDll)
1008 ::FreeLibrary(m_hQuartzDll);
1009#endif
1a680109
RN
1010}
1011
1a680109 1012//---------------------------------------------------------------------------
ff4aedc5 1013// wxAMMediaBackend::CreateControl
1a680109 1014//
920a7c15
JS
1015// 1) Check to see if Active Movie supports windowless controls
1016// 2) Connect events to the media control and its TLW
226ec5a7
WS
1017//---------------------------------------------------------------------------
1018bool wxAMMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 1019 wxWindowID id,
226ec5a7 1020 const wxPoint& pos,
ff4aedc5 1021 const wxSize& size,
226ec5a7 1022 long style,
ff4aedc5
RN
1023 const wxValidator& validator,
1024 const wxString& name)
226ec5a7 1025{
920a7c15
JS
1026#ifdef __WXDEBUG__
1027 m_hQuartzDll = ::LoadLibrary(wxT("quartz.dll"));
1028 if(m_hQuartzDll)
1029 {
1030 m_lpAMGetErrorText = (LPAMGETERRORTEXT) ::GetProcAddress(
1031 m_hQuartzDll,
1032 wxString::Format(wxT("AMGetErrorText%s"),
1a680109 1033
920a7c15
JS
1034#ifdef __WXUNICODE__
1035 wxT("W")
1036#else
1037 wxT("A")
1038#endif
1039#ifdef __WXWINCE__
1040 )
1041#else
1042 ).mb_str(wxConvLocal)
1043#endif
1044 );
1045 }
1046#endif
1047
1048 //Make sure a valid windowless video mixing interface exists
1049 IGraphBuilder* pGB;
1050 if( CoCreateInstance(CLSID_FilgraphManager, NULL,
1051 CLSCTX_INPROC_SERVER,
1052 IID_IGraphBuilder, (void**)&pGB) != 0 )
1053 return false;
1054
1055 if( !SetWindowlessMode(pGB) )
1a680109
RN
1056 return false;
1057
920a7c15
JS
1058 //clean up
1059 pGB->Release();
ff4aedc5
RN
1060
1061 //
1062 // Create window
1063 // By default wxWindow(s) is created with a border -
1064 // so we need to get rid of those, and create with
1065 // wxCLIP_CHILDREN, so that if the driver/backend
3103e8a9 1066 // is a child window, it refreshes properly
ff4aedc5
RN
1067 //
1068 if ( !ctrl->wxControl::Create(parent, id, pos, size,
11085e4b 1069 (style & ~wxBORDER_MASK) | wxBORDER_NONE | wxCLIP_CHILDREN,
ff4aedc5
RN
1070 validator, name) )
1071 return false;
1a680109 1072
ff4aedc5 1073 m_ctrl = ctrl;
920a7c15
JS
1074
1075 //
1076 // Connect Events
1077 //
b81383bb
JS
1078 //TODO: Greg Hazel reports problems with this... but win2k seems fine on mine...
1079 //-------------------------------------------------------------------------------
1080 // My problem with this was only with a previous patch, probably the third rewrite
1081 // fixed it as a side-effect. In fact, the erase background style of drawing not
1082 // only works now, but is much better than paint-based updates (the paint event
1083 // handler flickers if the wxMediaCtrl shares a sizer with another child window,
1084 // or is on a notebook)
1085 // - Greg Hazel
1086 m_ctrl->Connect(m_ctrl->GetId(), wxEVT_ERASE_BACKGROUND,
1087 wxEraseEventHandler(wxAMMediaEvtHandler::OnEraseBackground),
920a7c15 1088 NULL, (wxEvtHandler*) this);
b81383bb
JS
1089 //m_ctrl->Connect(m_ctrl->GetId(), wxEVT_PAINT,
1090 // wxPaintEventHandler(wxAMMediaEvtHandler::OnPaint),
1091 // NULL, (wxEvtHandler*) this);
920a7c15
JS
1092
1093 //
1094 // As noted below, we need to catch the Top Level Window's
1095 // move events because they are not sent to us if the media control
1096 // size remains the same but it actually moves in window coordinates
1097 //
1098 wxWindow* pTheTLW = m_ctrl->GetParent();
1099 while( pTheTLW->GetParent() )
1100 pTheTLW = pTheTLW->GetParent();
1101
1102 //
1103 // FIXMEHACKFIXMEHACKFIXME
1104 // This is really nasty... basically the deal is not only above
1105 // but the repainting is messed up when the parent is maximized
1106 // too, so we've got to catch all 4 events!
1107 //
1108 m_ctrl->Connect(m_ctrl->GetId(), wxEVT_MOVE,
1109 wxMoveEventHandler(wxAMMediaEvtHandler::OnMove),
1110 NULL, (wxEvtHandler*) this);
1111 m_ctrl->Connect(m_ctrl->GetId(), wxEVT_SIZE,
1112 wxSizeEventHandler(wxAMMediaEvtHandler::OnSize),
1113 NULL, (wxEvtHandler*) this);
1114
1115 pTheTLW->Connect(pTheTLW->GetId(), wxEVT_MOVE,
1116 wxMoveEventHandler(wxAMMediaEvtHandler::OnMove),
1117 NULL, (wxEvtHandler*) this);
1118 pTheTLW->Connect(pTheTLW->GetId(), wxEVT_SIZE,
1119 wxSizeEventHandler(wxAMMediaEvtHandler::OnSize),
1120 NULL, (wxEvtHandler*) this);
1121
1122 //
1123 // done...
1124 //
1a680109
RN
1125 return true;
1126}
1127
ff4aedc5 1128//---------------------------------------------------------------------------
920a7c15 1129// wxAMMediaBackend::SetWindowlessMode
ff4aedc5 1130//
920a7c15
JS
1131// Adds a Video Mixing Renderer to a Filter Graph and obtains the
1132// windowless control from it
226ec5a7 1133//---------------------------------------------------------------------------
920a7c15
JS
1134bool wxAMMediaBackend::SetWindowlessMode(IGraphBuilder* pGB,
1135 IVMRWindowlessControl** ppVMC)
1a680109 1136{
920a7c15
JS
1137 //
1138 // Create and add a custom Video Mixing Render to the graph
1139 //
1140 IBaseFilter* pVMR;
1141 if( CoCreateInstance(CLSID_VideoMixingRenderer, NULL, CLSCTX_INPROC_SERVER,
1142 IID_IBaseFilter, (void**)&pVMR) != 0 )
1a680109
RN
1143 return false;
1144
920a7c15
JS
1145 if ( pGB->AddFilter(pVMR, L"Video Mixing Renderer") != 0)
1146 {
1147 pVMR->Release();
1148 return false;
1149 }
ff4aedc5
RN
1150
1151 //
920a7c15 1152 // Set the graph to windowless mode
ff4aedc5 1153 //
920a7c15
JS
1154 IVMRFilterConfig* pConfig;
1155 if( pVMR->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig) != 0 )
1156 {
1157 pVMR->Release();
1158 return false;
1159 }
ff4aedc5 1160
920a7c15
JS
1161 if( pConfig->SetRenderingMode(2) != 0) //2 == VMRMode_Windowless
1162 {
1163 pConfig->Release();
1164 pVMR->Release();
1165 return false;
1166 }
ff4aedc5 1167
920a7c15 1168 pConfig->Release();
ff4aedc5
RN
1169
1170 //
920a7c15 1171 // Obtain the windowless control
ff4aedc5 1172 //
920a7c15
JS
1173 IVMRWindowlessControl* pVMC;
1174 if( pVMR->QueryInterface(IID_IVMRWindowlessControl, (void**)&pVMC) != 0 )
1a680109 1175 {
920a7c15
JS
1176 pVMR->Release();
1177 return false;
1a680109
RN
1178 }
1179
ff4aedc5 1180 //
920a7c15 1181 // Success
226ec5a7 1182 //
920a7c15
JS
1183 if(ppVMC)
1184 *ppVMC = pVMC;
1185 else
1186 pVMC->Release();
ff4aedc5 1187
920a7c15
JS
1188 pVMR->Release();
1189 return true;
1190}
1a680109 1191
920a7c15
JS
1192//---------------------------------------------------------------------------
1193// wxAMMediaBackend::Load (file version)
1194//
1195// 1) Cleans up previously loaded data
1196// 2) Creates a filter graph
1197// 3) Add a video mixer, set the graph to windowless mode and clip
1198// output to our media control
1199// 4) Query interfaces to use later
1200// 5) Get native video size (which becomes our best size)
1201// 6) Refresh parent's sizers
1202// 7) Start event/rendering thread
1203//---------------------------------------------------------------------------
1204bool wxAMMediaBackend::Load(const wxString& fileName)
1205{
1206 //if previously loaded cleanup
1207 if(m_pVMC)
1208 Cleanup();
1209
1210 //Create interfaces - we already checked for success in CreateControl
1211 CoCreateInstance(CLSID_FilgraphManager, NULL, CLSCTX_INPROC_SERVER,
1212 IID_IGraphBuilder, (void**)&m_pGB);
1213
1214
1215 // Set and clip output
1216 SetWindowlessMode(m_pGB, &m_pVMC);
1217 if( m_pVMC->SetVideoClippingWindow((HWND)m_ctrl->GetHandle()) != 0 )
1218 {
1219 m_bestSize.x = m_bestSize.y = 0;
1220 wxASSERT(false);
ff4aedc5 1221 }
226ec5a7 1222
920a7c15
JS
1223 //load the graph & render
1224 if( m_pGB->RenderFile(fileName.wc_str(wxConvLocal), NULL) != 0 )
1225 return false;
1a680109 1226
920a7c15
JS
1227 //Get the interfaces, all of them
1228 wxAMVERIFY( m_pGB->QueryInterface(IID_IMediaEvent, (void**)&m_pME) );
1229 wxAMVERIFY( m_pGB->QueryInterface(IID_IMediaControl, (void**)&m_pMC) );
1230 wxAMVERIFY( m_pGB->QueryInterface(IID_IMediaPosition, (void**)&m_pMS) );
1231 wxAMVERIFY( m_pGB->QueryInterface(IID_IBasicAudio, (void**)&m_pBA) );
1a680109 1232
920a7c15
JS
1233 // Get original video size
1234 if( m_pVMC->GetNativeVideoSize((LONG*)&m_bestSize.x, (LONG*)&m_bestSize.y,
1235 NULL, NULL) != 0 )
1236 {
1237 m_bestSize.x = m_bestSize.y = 0;
1238 wxASSERT(false);
1239 }
3f9a3bf9 1240
ff4aedc5
RN
1241 //
1242 // Force the parent window of this control to recalculate
1243 // the size of this if sizers are being used
1244 // and render the results immediately
1245 //
3f9a3bf9
RN
1246 m_ctrl->InvalidateBestSize();
1247 m_ctrl->GetParent()->Layout();
1a680109
RN
1248 m_ctrl->GetParent()->Refresh();
1249 m_ctrl->GetParent()->Update();
b11eba7e 1250 m_ctrl->SetSize(m_ctrl->GetSize());
1a680109 1251
920a7c15
JS
1252 m_pThread = new wxAMMediaThread;
1253 m_pThread->pThis = this;
1254 m_pThread->Create();
1255 m_pThread->Run();
1256
1a680109
RN
1257 return true;
1258}
1259
ff4aedc5
RN
1260//---------------------------------------------------------------------------
1261// wxAMMediaBackend::Load (URL Version)
1262//
1263// Loads media from a URL. Interestingly enough DirectShow
1264// appears (?) to escape the URL for us, at least on normal
1265// files
226ec5a7 1266//---------------------------------------------------------------------------
ff4aedc5 1267bool wxAMMediaBackend::Load(const wxURI& location)
1a680109
RN
1268{
1269 return Load(location.BuildUnescapedURI());
1270}
1271
ff4aedc5
RN
1272//---------------------------------------------------------------------------
1273// wxAMMediaBackend::Play
1274//
920a7c15
JS
1275// Plays the stream. If it is non-seekable, it will restart it (implicit).
1276//
1277// Note that we use SUCCEEDED here because run/pause/stop tend to be overly
1278// picky and return warnings on pretty much every call
226ec5a7 1279//---------------------------------------------------------------------------
ff4aedc5 1280bool wxAMMediaBackend::Play()
1a680109 1281{
920a7c15
JS
1282 wxCriticalSectionLocker lock(m_rendercs);
1283
1284 if( SUCCEEDED(m_pMC->Run()) )
1285 {
1286 m_state = wxMEDIASTATE_PLAYING;
1287 m_ctrl->Refresh(); //videoless control finicky about refreshing
1288 return true;
1289 }
1290
1291 return false;
1a680109
RN
1292}
1293
ff4aedc5
RN
1294//---------------------------------------------------------------------------
1295// wxAMMediaBackend::Pause
1296//
1297// Pauses the stream.
226ec5a7 1298//---------------------------------------------------------------------------
ff4aedc5 1299bool wxAMMediaBackend::Pause()
1a680109 1300{
920a7c15
JS
1301 wxCriticalSectionLocker lock(m_rendercs);
1302
1303 if( SUCCEEDED(m_pMC->Pause()) )
1304 {
1305 m_state = wxMEDIASTATE_PAUSED;
1306 return true;
1307 }
1308
1309 return false;
1a680109
RN
1310}
1311
ff4aedc5
RN
1312//---------------------------------------------------------------------------
1313// wxAMMediaBackend::Stop
1314//
1315// Stops the stream.
226ec5a7 1316//---------------------------------------------------------------------------
ff4aedc5 1317bool wxAMMediaBackend::Stop()
1a680109 1318{
920a7c15 1319 wxCriticalSectionLocker lock(m_rendercs);
e4b12a53 1320
920a7c15
JS
1321 if( SUCCEEDED(m_pMC->Stop()) )
1322 {
e4b12a53
RN
1323 //We don't care if it can't get to the beginning in directshow -
1324 //it could be a non-seeking filter (wince midi) in which case playing
1325 //starts all over again
920a7c15
JS
1326 wxAMMediaBackend::SetPosition(0);
1327
1328 m_state = wxMEDIASTATE_STOPPED;
1329 return true;
1330 }
1331
1332 return false;
1a680109
RN
1333}
1334
ff4aedc5
RN
1335//---------------------------------------------------------------------------
1336// wxAMMediaBackend::SetPosition
1337//
226ec5a7 1338// 1) Translates the current position's time to directshow time,
a2a444e3 1339// which is in a scale of 1 second (in a double)
ff4aedc5
RN
1340// 2) Sets the play position of the IMediaSeeking interface -
1341// passing NULL as the stop position means to keep the old
1342// stop position
226ec5a7 1343//---------------------------------------------------------------------------
ff4aedc5 1344bool wxAMMediaBackend::SetPosition(wxLongLong where)
1a680109 1345{
a2a444e3 1346 return SUCCEEDED( m_pMS->put_CurrentPosition(
920a7c15
JS
1347 ((LONGLONG)where.GetValue()) / 1000.0
1348 ) );
1a680109
RN
1349}
1350
ff4aedc5
RN
1351//---------------------------------------------------------------------------
1352// wxAMMediaBackend::GetPosition
1353//
1354// 1) Obtains the current play and stop positions from IMediaSeeking
1355// 2) Returns the play position translated to our time base
226ec5a7 1356//---------------------------------------------------------------------------
ff4aedc5 1357wxLongLong wxAMMediaBackend::GetPosition()
1a680109 1358{
a2a444e3
RN
1359 double outCur;
1360 wxAMVERIFY( m_pMS->get_CurrentPosition(&outCur) );
1a680109 1361
a2a444e3 1362 //h,m,s,milli - outdur is in 1 second (double)
600ffb32
WS
1363 outCur *= 1000;
1364 wxLongLong ll;
1365 ll.Assign(outCur);
1366
1367 return ll;
1a680109
RN
1368}
1369
6f8c67e7
JS
1370//---------------------------------------------------------------------------
1371// wxAMMediaBackend::SetVolume
1372//
1373// Sets the volume through the IBasicAudio interface -
1374// value ranges from 0 (MAX volume) to -10000 (minimum volume).
1375// -100 per decibel.
1376//---------------------------------------------------------------------------
b11eba7e
WS
1377bool wxAMMediaBackend::SetVolume(double dVolume)
1378{
920a7c15 1379 return SUCCEEDED(m_pBA->put_Volume( (long) ((dVolume-1.0) * 10000.0) ) );
b11eba7e 1380}
6f8c67e7
JS
1381
1382//---------------------------------------------------------------------------
1383// wxAMMediaBackend::GetVolume
1384//
1385// Gets the volume through the IBasicAudio interface -
1386// value ranges from 0 (MAX volume) to -10000 (minimum volume).
1387// -100 per decibel.
1388//---------------------------------------------------------------------------
1389double wxAMMediaBackend::GetVolume()
1390{
1391 long lVolume;
920a7c15 1392 if ( SUCCEEDED( m_pBA->get_Volume(&lVolume) ) )
6f8c67e7
JS
1393 return (((double)(lVolume + 10000)) / 10000.0);
1394 return 0.0;
1395}
b11eba7e 1396
ff4aedc5
RN
1397//---------------------------------------------------------------------------
1398// wxAMMediaBackend::GetDuration
1399//
920a7c15 1400// 1) Obtains the duration of the media from IAMMultiMediaStream
ff4aedc5 1401// 2) Converts that value to our time base, and returns it
920a7c15
JS
1402//
1403// NB: With VBR MP3 files the default DirectShow MP3 render does not
1404// read the Xing header correctly, resulting in skewed values for duration
1405// and seeking
226ec5a7 1406//---------------------------------------------------------------------------
ff4aedc5 1407wxLongLong wxAMMediaBackend::GetDuration()
1a680109 1408{
a2a444e3
RN
1409 double outDuration;
1410 wxAMVERIFY( m_pMS->get_Duration(&outDuration) );
1a680109 1411
a2a444e3 1412 //h,m,s,milli - outdur is in 1 second (double)
600ffb32
WS
1413 outDuration *= 1000;
1414 wxLongLong ll;
1415 ll.Assign(outDuration);
1416
1417 return ll;
1a680109
RN
1418}
1419
ff4aedc5
RN
1420//---------------------------------------------------------------------------
1421// wxAMMediaBackend::GetState
1422//
920a7c15 1423// Returns the cached state
226ec5a7 1424//---------------------------------------------------------------------------
ff4aedc5 1425wxMediaState wxAMMediaBackend::GetState()
1a680109 1426{
920a7c15 1427 return m_state;
1a680109
RN
1428}
1429
ff4aedc5
RN
1430//---------------------------------------------------------------------------
1431// wxAMMediaBackend::GetPlaybackRate
1432//
1433// Pretty simple way of obtaining the playback rate from
1434// the IMediaSeeking interface
226ec5a7 1435//---------------------------------------------------------------------------
ff4aedc5 1436double wxAMMediaBackend::GetPlaybackRate()
1a680109
RN
1437{
1438 double dRate;
a2a444e3 1439 wxAMVERIFY( m_pMS->get_Rate(&dRate) );
1a680109
RN
1440 return dRate;
1441}
1442
ff4aedc5
RN
1443//---------------------------------------------------------------------------
1444// wxAMMediaBackend::SetPlaybackRate
1445//
1446// Sets the playback rate of the media - DirectShow is pretty good
1447// about this, actually
226ec5a7 1448//---------------------------------------------------------------------------
ff4aedc5 1449bool wxAMMediaBackend::SetPlaybackRate(double dRate)
1a680109 1450{
920a7c15 1451 return m_pMS->put_Rate(dRate) == 0;
1a680109
RN
1452}
1453
ff4aedc5 1454//---------------------------------------------------------------------------
920a7c15 1455// wxAMMediaBackend::Cleanup
ff4aedc5 1456//
920a7c15
JS
1457// Releases all the directshow interfaces we use
1458// TODO: Maybe only create one instance of IAMMultiMediaStream and reuse it
1459// rather than recreating it each time?
226ec5a7 1460//---------------------------------------------------------------------------
920a7c15 1461void wxAMMediaBackend::Cleanup()
ff4aedc5 1462{
920a7c15
JS
1463 m_pThread->Delete();
1464 m_pThread = NULL;
ff4aedc5 1465
920a7c15
JS
1466 // Release and zero DirectShow interfaces
1467 SAFE_RELEASE(m_pMC);
1468 SAFE_RELEASE(m_pME);
1469 SAFE_RELEASE(m_pMS);
1470 SAFE_RELEASE(m_pBA);
1471 SAFE_RELEASE(m_pGB);
1472 SAFE_RELEASE(m_pVMC);
1473}
1474
1475
1476//---------------------------------------------------------------------------
1477// wxAMMediaBackend::GetVideoSize
1478//
1479// Obtains the cached original video size
1480//---------------------------------------------------------------------------
1481wxSize wxAMMediaBackend::GetVideoSize() const
1482{
1483 return m_bestSize;
1484}
1485
1486//---------------------------------------------------------------------------
1487// wxAMMediaBackend::Move
1488//
1489// We take care of this in our redrawing
1490//---------------------------------------------------------------------------
1491void wxAMMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y),
1492 int w, int h)
1493{
1494 if(m_pVMC)
1495 {
1496 RECT srcRect, destRect;
1497
1498 //portion of video to display in window
1499 srcRect.top = 0; srcRect.left = 0;
1500 srcRect.bottom = m_bestSize.y; srcRect.right = m_bestSize.x;
1501
b81383bb
JS
1502 //it happens.
1503 if (w < 0)
1504 {
1505 w = 0;
1506 }
1507 if (h < 0)
1508 {
1509 h = 0;
1510 }
1511
920a7c15
JS
1512 //position in window client coordinates to display and stretch to
1513 destRect.top = 0; destRect.left = 0;
1514 destRect.bottom = h; destRect.right = w;
1515
1516 //set the windowless control positions
1517 if( m_pVMC->SetVideoPosition(&srcRect, &destRect) != 0 )
1518 {
1519 wxASSERT_MSG(false, wxT("Could not set video position!"));
1520 }
1521
1522/*
1523 //oddly enough, it doesn't redraw the frame after moving...
1524 //TODO: Use wxClientDC?
1525 HDC hdc = ::GetDC((HWND)m_ctrl->GetHandle());
1526 if( m_pVMC->RepaintVideo((HWND)m_ctrl->GetHandle(),
1527 hdc) != 0 )
1528 {
1529 wxASSERT(false);
1530 }
1531 ::ReleaseDC((HWND)m_ctrl->GetHandle(), hdc);
1532*/
1533 }
1534}
1535
1536//---------------------------------------------------------------------------
1537// wxAMMediaEvtHandler::OnMove
1538//
1539// Oddly enough Move isn't called on MSW when the parent moves
1540// and the child (us) doesn't, so we have to do it twice I guess :(
1541//---------------------------------------------------------------------------
1542void wxAMMediaEvtHandler::OnMove(wxMoveEvent& evt)
1543{
1544 wxAMMediaBackend* pThis = (wxAMMediaBackend*) this;
1545 pThis->Move(pThis->m_ctrl->GetPosition().x,
1546 pThis->m_ctrl->GetPosition().y,
1547 pThis->m_ctrl->GetSize().x,
1548 pThis->m_ctrl->GetSize().y );
1549 evt.Skip();
1550}
1551void wxAMMediaEvtHandler::OnSize(wxSizeEvent& evt)
1552{
1553 wxAMMediaBackend* pThis = (wxAMMediaBackend*) this;
1554 pThis->Move(pThis->m_ctrl->GetPosition().x,
1555 pThis->m_ctrl->GetPosition().y,
1556 pThis->m_ctrl->GetSize().x,
1557 pThis->m_ctrl->GetSize().y );
1558 evt.Skip();
ff4aedc5
RN
1559}
1560
920a7c15
JS
1561//---------------------------------------------------------------------------
1562// wxAMMediaThread::Entry
1563//
1564// Render the current movie frame
1565//---------------------------------------------------------------------------
1566wxThread::ExitCode wxAMMediaThread::Entry()
1a680109 1567{
920a7c15 1568 while(!TestDestroy())
1a680109 1569 {
226ec5a7
WS
1570 LONG evCode,
1571 evParam1,
ff4aedc5
RN
1572 evParam2;
1573
1574 //
1575 // DirectShow keeps a list of queued events, and we need
1576 // to go through them one by one, stopping at (Hopefully only one)
1577 // EC_COMPLETE message
1578 //
920a7c15
JS
1579 while( pThis->m_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
1580 (LONG_PTR *) &evParam2, 0) == 0 )
1a680109 1581 {
ff4aedc5 1582 // Cleanup memory that GetEvent allocated
920a7c15
JS
1583 if( pThis->m_pME->FreeEventParams(evCode, evParam1, evParam2) != 0 )
1584 {
1585 wxASSERT(false);
1586 }
1a680109
RN
1587
1588 // If this is the end of the clip, notify handler
a2a444e3 1589 if(1 == evCode) //EC_COMPLETE
1a680109 1590 {
920a7c15
JS
1591 pThis->OnStop();
1592 }
1593 }
1594
1595 Sleep(10);
1596 }
1597
1598 return NULL;
1599}
1600
1601
1602//---------------------------------------------------------------------------
1603// wxAMMediaBackend::OnStop
1604//
1605// Handle stopping when the stream ends
1606//---------------------------------------------------------------------------
1607void wxAMMediaBackend::OnStop()
1608{
b81383bb
JS
1609 //send the event to our child
1610 wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId());
1611 m_ctrl->ProcessEvent(theEvent);
1612
1613 //if the user didn't veto it, stop the stream
1614 if (theEvent.IsAllowed())
1615 {
1616 //Interestingly enough, DirectShow does not actually stop
1617 //the filters - even when it reaches the end!
1618 wxVERIFY( Stop() );
1619
1620 //send the event to our child
1621 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
1622 m_ctrl->GetId());
1623 m_ctrl->ProcessEvent(theEvent);
1624 }
1a680109
RN
1625}
1626
ff4aedc5 1627//---------------------------------------------------------------------------
920a7c15 1628// wxAMMediaEvtHandler::OnEraseBackground
ff4aedc5 1629//
920a7c15 1630// Tell WX not to erase the background of our control window
226ec5a7 1631//---------------------------------------------------------------------------
920a7c15 1632void wxAMMediaEvtHandler::OnEraseBackground(wxEraseEvent& evt)
1a680109 1633{
920a7c15
JS
1634 wxAMMediaBackend* pThis = (wxAMMediaBackend*) this;
1635 if(pThis->m_pVMC)
1a680109 1636 {
920a7c15
JS
1637 //TODO: Use wxClientDC?
1638 HDC hdc = ::GetDC((HWND)pThis->m_ctrl->GetHandle());
1639 if( pThis->m_pVMC->RepaintVideo((HWND)pThis->m_ctrl->GetHandle(),
b81383bb 1640 hdc) != 0 )
920a7c15
JS
1641 {
1642 wxASSERT(false);
b81383bb 1643 }
920a7c15
JS
1644 ::ReleaseDC((HWND)pThis->m_ctrl->GetHandle(), hdc);
1645 }
1646 else
b81383bb 1647 {
920a7c15 1648 evt.Skip();
b81383bb 1649 }
1a680109
RN
1650}
1651
ff4aedc5 1652//---------------------------------------------------------------------------
920a7c15 1653// wxAMMediaEvtHandler::OnPaint
ff4aedc5 1654//
920a7c15 1655// Handle redrawing
226ec5a7 1656//---------------------------------------------------------------------------
920a7c15 1657void wxAMMediaEvtHandler::OnPaint(wxPaintEvent& WXUNUSED(evt))
1a680109 1658{
920a7c15
JS
1659 wxAMMediaBackend* pThis = (wxAMMediaBackend*) this;
1660 wxPaintDC dc(pThis->m_ctrl);
19c1b67d 1661 if( pThis->m_pVMC )
1a680109 1662 {
19c1b67d
JS
1663 if( pThis->m_pVMC->RepaintVideo((HWND)pThis->m_ctrl->GetHandle(),
1664 (HDC)dc.GetHDC()) != 0 )
1665 {
1666 wxASSERT(false);
1667 }
1a680109
RN
1668 }
1669}
1670
ff4aedc5
RN
1671//---------------------------------------------------------------------------
1672// End of wxAMMediaBackend
1673//---------------------------------------------------------------------------
1a680109 1674
ff4aedc5 1675//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1a680109 1676//
ff4aedc5 1677// wxMCIMediaBackend
226ec5a7 1678//
ff4aedc5
RN
1679//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1680
ff4aedc5
RN
1681IMPLEMENT_DYNAMIC_CLASS(wxMCIMediaBackend, wxMediaBackend);
1682
1683//---------------------------------------------------------------------------
1684// Usual debugging macros for MCI returns
1a680109
RN
1685//---------------------------------------------------------------------------
1686
ff4aedc5
RN
1687#ifdef __WXDEBUG__
1688#define wxMCIVERIFY(arg) \
1689{ \
1690 DWORD nRet; \
1691 if ( (nRet = (arg)) != 0) \
1692 { \
1693 TCHAR sz[5000]; \
1694 mciGetErrorString(nRet, sz, 5000); \
1695 wxFAIL_MSG(wxString::Format(_T("MCI Error:%s"), sz)); \
1696 } \
1697}
1698#else
1699#define wxMCIVERIFY(arg) (arg);
1700#endif
1701
1702//---------------------------------------------------------------------------
1703// Simulation for <digitalv.h>
33d8e2fc 1704//
ff4aedc5 1705// Mingw and possibly other compilers don't have the digitalv.h header
226ec5a7 1706// that is needed to have some essential features of mci work with
ff4aedc5
RN
1707// windows - so we provide the declarations for the types we use here
1708//---------------------------------------------------------------------------
33d8e2fc
RN
1709
1710typedef struct {
1711 DWORD_PTR dwCallback;
1712#ifdef MCI_USE_OFFEXT
1713 POINT ptOffset;
1714 POINT ptExtent;
226ec5a7 1715#else
33d8e2fc
RN
1716 RECT rc;
1717#endif
1718} MCI_DGV_RECT_PARMS;
1719
1720typedef struct {
1721 DWORD_PTR dwCallback;
1722 HWND hWnd;
1723#ifndef _WIN32
1724 WORD wReserved1;
1725#endif
1726 UINT nCmdShow;
1727#ifndef _WIN32
1728 WORD wReserved2;
1729#endif
ff4aedc5
RN
1730 wxChar* lpstrText;
1731} MCI_DGV_WINDOW_PARMS;
33d8e2fc
RN
1732
1733typedef struct {
226ec5a7
WS
1734 DWORD_PTR dwCallback;
1735 DWORD dwTimeFormat;
1736 DWORD dwAudio;
1737 DWORD dwFileFormat;
1738 DWORD dwSpeed;
1739} MCI_DGV_SET_PARMS;
33d8e2fc 1740
6f8c67e7
JS
1741typedef struct {
1742 DWORD_PTR dwCallback;
1743 DWORD dwItem;
1744 DWORD dwValue;
1745 DWORD dwOver;
1746 wxChar* lpstrAlgorithm;
1747 wxChar* lpstrQuality;
1748} MCI_DGV_SETAUDIO_PARMS;
1749
ff4aedc5
RN
1750//---------------------------------------------------------------------------
1751// wxMCIMediaBackend Constructor
1752//
1753// Here we don't need to do much except say we don't have any video :)
1754//---------------------------------------------------------------------------
1755wxMCIMediaBackend::wxMCIMediaBackend() : m_hNotifyWnd(NULL), m_bVideo(false)
1756{
3f9a3bf9
RN
1757}
1758
ff4aedc5
RN
1759//---------------------------------------------------------------------------
1760// wxMCIMediaBackend Destructor
1761//
1762// We close the mci device - note that there may not be an mci device here,
1763// or it may fail - but we don't really care, since we're destructing
1764//---------------------------------------------------------------------------
1765wxMCIMediaBackend::~wxMCIMediaBackend()
3f9a3bf9 1766{
ff4aedc5
RN
1767 if(m_hNotifyWnd)
1768 {
1769 mciSendCommand(m_hDev, MCI_CLOSE, 0, 0);
1770 DestroyWindow(m_hNotifyWnd);
1771 m_hNotifyWnd = NULL;
1772 }
3f9a3bf9
RN
1773}
1774
ff4aedc5
RN
1775//---------------------------------------------------------------------------
1776// wxMCIMediaBackend::Create
1777//
1778// Here we just tell wxMediaCtrl that mci does exist (which it does, on all
1779// msw systems, at least in some form dating back to win16 days)
1780//---------------------------------------------------------------------------
226ec5a7 1781bool wxMCIMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 1782 wxWindowID id,
226ec5a7 1783 const wxPoint& pos,
ff4aedc5 1784 const wxSize& size,
226ec5a7 1785 long style,
ff4aedc5
RN
1786 const wxValidator& validator,
1787 const wxString& name)
72259e00 1788{
ff4aedc5
RN
1789 //
1790 // Create window
1791 // By default wxWindow(s) is created with a border -
1792 // so we need to get rid of those, and create with
1793 // wxCLIP_CHILDREN, so that if the driver/backend
1794 // is a child window, it refereshes properly
1795 //
1796 if ( !ctrl->wxControl::Create(parent, id, pos, size,
11085e4b 1797 (style & ~wxBORDER_MASK) | wxBORDER_NONE | wxCLIP_CHILDREN,
ff4aedc5
RN
1798 validator, name) )
1799 return false;
1800
3f9a3bf9
RN
1801 m_ctrl = ctrl;
1802 return true;
1803}
1804
ff4aedc5
RN
1805//---------------------------------------------------------------------------
1806// wxMCIMediaBackend::Load (file version)
1807//
1808// Here we have MCI load a file and device, set the time format to our
1809// default (milliseconds), and set the video (if any) to play in the control
1810//---------------------------------------------------------------------------
1811bool wxMCIMediaBackend::Load(const wxString& fileName)
3f9a3bf9 1812{
ff4aedc5
RN
1813 //
1814 //if the user already called load close the previous MCI device
1815 //
1816 if(m_hNotifyWnd)
1817 {
3f9a3bf9 1818 mciSendCommand(m_hDev, MCI_CLOSE, 0, 0);
ff4aedc5
RN
1819 DestroyWindow(m_hNotifyWnd);
1820 m_hNotifyWnd = NULL;
1821 }
3f9a3bf9 1822
ff4aedc5
RN
1823 //
1824 //Opens a file and has MCI select a device. Normally you'd put
1825 //MCI_OPEN_TYPE in addition to MCI_OPEN_ELEMENT - however if you
226ec5a7 1826 //omit this it tells MCI to select the device instead. This is
ff4aedc5
RN
1827 //good because we have no reliable way of "enumerating" the devices
1828 //in MCI
1829 //
3f9a3bf9 1830 MCI_OPEN_PARMS openParms;
3f9a3bf9
RN
1831 openParms.lpstrElementName = (wxChar*) fileName.c_str();
1832
226ec5a7 1833 if ( mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT,
ff4aedc5
RN
1834 (DWORD)(LPVOID)&openParms) != 0)
1835 return false;
3f9a3bf9
RN
1836
1837 m_hDev = openParms.wDeviceID;
1838
ff4aedc5
RN
1839 //
1840 //Now set the time format for the device to milliseconds
1841 //
1842 MCI_SET_PARMS setParms;
3f9a3bf9
RN
1843 setParms.dwCallback = 0;
1844 setParms.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
1845
1846 if (mciSendCommand(m_hDev, MCI_SET, MCI_SET_TIME_FORMAT,
1847 (DWORD)(LPVOID)&setParms) != 0)
1848 return false;
1849
ff4aedc5
RN
1850 //
1851 //Now tell the MCI device to display the video in our wxMediaCtrl
1852 //
3f9a3bf9 1853 MCI_DGV_WINDOW_PARMS windowParms;
5987f174 1854 windowParms.hWnd = (HWND)m_ctrl->GetHandle();
3f9a3bf9 1855
226ec5a7 1856 m_bVideo = (mciSendCommand(m_hDev, MCI_WINDOW,
ff4aedc5
RN
1857 0x00010000L, //MCI_DGV_WINDOW_HWND
1858 (DWORD)(LPVOID)&windowParms) == 0);
1859
1860 //
1861 // Create a hidden window and register to handle
1862 // MCI events
226ec5a7 1863 // Note that wxCanvasClassName is already registered
ff4aedc5 1864 // and used by all wxWindows and normal wxControls
226ec5a7 1865 //
ff4aedc5
RN
1866 m_hNotifyWnd = ::CreateWindow
1867 (
1868 wxCanvasClassName,
1869 NULL,
1870 0, 0, 0, 0,
1871 0,
1872 (HWND) NULL,
1873 (HMENU)NULL,
1874 wxGetInstance(),
1875 (LPVOID) NULL
1876 );
1877
1878 if(!m_hNotifyWnd)
1879 {
1880 wxLogSysError( wxT("Could not create hidden needed for ")
1881 wxT("registering for DirectShow events!") );
1882
1883 return false;
1884 }
226ec5a7 1885
1146983c 1886 wxSetWindowProc(m_hNotifyWnd, wxMCIMediaBackend::NotifyWndProc);
ff4aedc5
RN
1887
1888 ::SetWindowLong(m_hNotifyWnd, GWL_USERDATA,
1889 (LONG) this);
1890
1891 //
1892 //Here, if the parent of the control has a sizer - we
1893 //tell it to recalculate the size of this control since
3103e8a9 1894 //the user opened a separate media file
ff4aedc5 1895 //
5987f174
RN
1896 m_ctrl->InvalidateBestSize();
1897 m_ctrl->GetParent()->Layout();
1898 m_ctrl->GetParent()->Refresh();
1899 m_ctrl->GetParent()->Update();
b11eba7e 1900 m_ctrl->SetSize(m_ctrl->GetSize());
72259e00 1901
3f9a3bf9
RN
1902 return true;
1903}
1904
ff4aedc5
RN
1905//---------------------------------------------------------------------------
1906// wxMCIMediaBackend::Load (URL version)
1907//
1908// MCI doesn't support URLs directly (?)
1909//
1910// TODO: Use wxURL/wxFileSystem and mmioInstallProc
1911//---------------------------------------------------------------------------
1912bool wxMCIMediaBackend::Load(const wxURI& WXUNUSED(location))
3f9a3bf9
RN
1913{
1914 return false;
1915}
1916
ff4aedc5
RN
1917//---------------------------------------------------------------------------
1918// wxMCIMediaBackend::Play
1919//
1920// Plays/Resumes the MCI device... a couple notes:
1921// 1) Certain drivers will crash and burn if we don't pass them an
1922// MCI_PLAY_PARMS, despite the documentation that says otherwise...
1923// 2) There is a MCI_RESUME command, but MCI_PLAY does the same thing
226ec5a7 1924// and will resume from a stopped state also, so there's no need to
ff4aedc5
RN
1925// call both, for example
1926//---------------------------------------------------------------------------
1927bool wxMCIMediaBackend::Play()
5987f174 1928{
5987f174 1929 MCI_PLAY_PARMS playParms;
ff4aedc5
RN
1930 playParms.dwCallback = (DWORD)m_hNotifyWnd;
1931
11219c9e 1932 bool bOK = ( mciSendCommand(m_hDev, MCI_PLAY, MCI_NOTIFY,
ff4aedc5 1933 (DWORD)(LPVOID)&playParms) == 0 );
11219c9e
RN
1934
1935 if(bOK)
1936 m_ctrl->Show(m_bVideo);
1937
1938 return bOK;
5987f174
RN
1939}
1940
ff4aedc5
RN
1941//---------------------------------------------------------------------------
1942// wxMCIMediaBackend::Pause
1943//
1944// Pauses the MCI device - nothing special
226ec5a7 1945//---------------------------------------------------------------------------
ff4aedc5 1946bool wxMCIMediaBackend::Pause()
5987f174
RN
1947{
1948 return (mciSendCommand(m_hDev, MCI_PAUSE, MCI_WAIT, 0) == 0);
1949}
1950
ff4aedc5
RN
1951//---------------------------------------------------------------------------
1952// wxMCIMediaBackend::Stop
1953//
1954// Stops the MCI device & seeks to the beginning as wxMediaCtrl docs outline
226ec5a7 1955//---------------------------------------------------------------------------
ff4aedc5 1956bool wxMCIMediaBackend::Stop()
5987f174
RN
1957{
1958 return (mciSendCommand(m_hDev, MCI_STOP, MCI_WAIT, 0) == 0) &&
1959 (mciSendCommand(m_hDev, MCI_SEEK, MCI_SEEK_TO_START, 0) == 0);
1960}
1961
ff4aedc5
RN
1962//---------------------------------------------------------------------------
1963// wxMCIMediaBackend::GetState
1964//
1965// Here we get the state and convert it to a wxMediaState -
1966// since we use direct comparisons with MCI_MODE_PLAY and
1967// MCI_MODE_PAUSE, we don't care if the MCI_STATUS call
1968// fails or not
226ec5a7 1969//---------------------------------------------------------------------------
ff4aedc5 1970wxMediaState wxMCIMediaBackend::GetState()
3f9a3bf9
RN
1971{
1972 MCI_STATUS_PARMS statusParms;
1973 statusParms.dwItem = MCI_STATUS_MODE;
ff4aedc5 1974
3f9a3bf9
RN
1975 mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
1976 (DWORD)(LPVOID)&statusParms);
1977
1978 if(statusParms.dwReturn == MCI_MODE_PAUSE)
1979 return wxMEDIASTATE_PAUSED;
1980 else if(statusParms.dwReturn == MCI_MODE_PLAY)
1981 return wxMEDIASTATE_PLAYING;
1982 else
1983 return wxMEDIASTATE_STOPPED;
1984}
1985
ff4aedc5
RN
1986//---------------------------------------------------------------------------
1987// wxMCIMediaBackend::SetPosition
1988//
1989// Here we set the position of the device in the stream.
226ec5a7 1990// Note that MCI actually stops the device after you seek it if the
ff4aedc5 1991// device is playing/paused, so we need to play the file after
226ec5a7
WS
1992// MCI seeks like normal APIs would
1993//---------------------------------------------------------------------------
ff4aedc5 1994bool wxMCIMediaBackend::SetPosition(wxLongLong where)
3f9a3bf9
RN
1995{
1996 MCI_SEEK_PARMS seekParms;
1997 seekParms.dwCallback = 0;
e70fda0e 1998#if wxUSE_LONGLONG_NATIVE && !wxUSE_LONGLONG_WX
226ec5a7 1999 seekParms.dwTo = (DWORD)where.GetValue();
e70fda0e
WS
2000#else /* wxUSE_LONGLONG_WX */
2001 /* no way to return it in one piece */
2002 wxASSERT( where.GetHi()==0 );
2003 seekParms.dwTo = (DWORD)where.GetLo();
2004#endif /* wxUSE_LONGLONG_* */
3f9a3bf9 2005
ff4aedc5 2006 //device was playing?
3f9a3bf9
RN
2007 bool bReplay = GetState() == wxMEDIASTATE_PLAYING;
2008
226ec5a7 2009 if( mciSendCommand(m_hDev, MCI_SEEK, MCI_TO,
ff4aedc5 2010 (DWORD)(LPVOID)&seekParms) != 0)
3f9a3bf9 2011 return false;
3f9a3bf9 2012
ff4aedc5 2013 //If the device was playing, resume it
3f9a3bf9
RN
2014 if (bReplay)
2015 return Play();
2016 else
2017 return true;
2018}
2019
ff4aedc5
RN
2020//---------------------------------------------------------------------------
2021// wxMCIMediaBackend::GetPosition
2022//
2023// Gets the position of the device in the stream using the current
2024// time format... nothing special here...
226ec5a7 2025//---------------------------------------------------------------------------
ff4aedc5 2026wxLongLong wxMCIMediaBackend::GetPosition()
3f9a3bf9
RN
2027{
2028 MCI_STATUS_PARMS statusParms;
72259e00 2029 statusParms.dwItem = MCI_STATUS_POSITION;
ff4aedc5 2030
72259e00 2031 if (mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
ff4aedc5 2032 (DWORD)(LPSTR)&statusParms) != 0)
3f9a3bf9
RN
2033 return 0;
2034
2035 return statusParms.dwReturn;
2036}
2037
6f8c67e7
JS
2038//---------------------------------------------------------------------------
2039// wxMCIMediaBackend::GetVolume
2040//
2041// Gets the volume of the current media via the MCI_DGV_STATUS_VOLUME
2042// message. Value ranges from 0 (minimum) to 1000 (maximum volume).
2043//---------------------------------------------------------------------------
2044double wxMCIMediaBackend::GetVolume()
2045{
2046 MCI_STATUS_PARMS statusParms;
600ffb32 2047 statusParms.dwCallback = 0;
6f8c67e7
JS
2048 statusParms.dwItem = 0x4019; //MCI_DGV_STATUS_VOLUME
2049
2050 if (mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
2051 (DWORD)(LPSTR)&statusParms) != 0)
2052 return 0;
2053
2054 return ((double)statusParms.dwReturn) / 1000.0;
2055}
2056
2057//---------------------------------------------------------------------------
2058// wxMCIMediaBackend::SetVolume
2059//
2060// Sets the volume of the current media via the MCI_DGV_SETAUDIO_VOLUME
2061// message. Value ranges from 0 (minimum) to 1000 (maximum volume).
2062//---------------------------------------------------------------------------
2063bool wxMCIMediaBackend::SetVolume(double dVolume)
2064{
2065 MCI_DGV_SETAUDIO_PARMS audioParms;
600ffb32 2066 audioParms.dwCallback = 0;
6f8c67e7
JS
2067 audioParms.dwItem = 0x4002; //MCI_DGV_SETAUDIO_VOLUME
2068 audioParms.dwValue = (DWORD) (dVolume * 1000.0);
2069 audioParms.dwOver = 0;
2070 audioParms.lpstrAlgorithm = NULL;
2071 audioParms.lpstrQuality = NULL;
2072
b11eba7e 2073 if (mciSendCommand(m_hDev, 0x0873, //MCI_SETAUDIO
6f8c67e7
JS
2074 0x00800000L | 0x01000000L, //MCI_DGV_SETAUDIO+(_ITEM | _VALUE)
2075 (DWORD)(LPSTR)&audioParms) != 0)
2076 return false;
2077 return true;
2078}
2079
ff4aedc5
RN
2080//---------------------------------------------------------------------------
2081// wxMCIMediaBackend::GetDuration
2082//
2083// Gets the duration of the stream... nothing special
226ec5a7 2084//---------------------------------------------------------------------------
ff4aedc5 2085wxLongLong wxMCIMediaBackend::GetDuration()
3f9a3bf9
RN
2086{
2087 MCI_STATUS_PARMS statusParms;
72259e00 2088 statusParms.dwItem = MCI_STATUS_LENGTH;
ff4aedc5 2089
72259e00 2090 if (mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
ff4aedc5 2091 (DWORD)(LPSTR)&statusParms) != 0)
3f9a3bf9
RN
2092 return 0;
2093
2094 return statusParms.dwReturn;
2095}
2096
ff4aedc5
RN
2097//---------------------------------------------------------------------------
2098// wxMCIMediaBackend::Move
2099//
2100// Moves the window to a location
226ec5a7
WS
2101//---------------------------------------------------------------------------
2102void wxMCIMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y),
ff4aedc5 2103 int w, int h)
3f9a3bf9 2104{
ff4aedc5
RN
2105 if (m_hNotifyWnd && m_bVideo)
2106 {
2107 MCI_DGV_RECT_PARMS putParms; //ifdefed MCI_DGV_PUT_PARMS
b11eba7e 2108 memset(&putParms, 0, sizeof(MCI_DGV_RECT_PARMS));
ff4aedc5 2109 putParms.rc.bottom = h;
b11eba7e 2110 putParms.rc.right = w;
7c4a4505 2111
b11eba7e
WS
2112 //wxStackWalker will crash and burn here on assert
2113 //and mci doesn't like 0 and 0 for some reason (out of range )
2114 //so just don't it in that case
2115 if(w || h)
2116 {
7c4a4505 2117 wxMCIVERIFY( mciSendCommand(m_hDev, MCI_PUT,
ff4aedc5
RN
2118 0x00040000L, //MCI_DGV_PUT_DESTINATION
2119 (DWORD)(LPSTR)&putParms) );
7c4a4505 2120 }
ff4aedc5 2121 }
3f9a3bf9
RN
2122}
2123
ff4aedc5
RN
2124//---------------------------------------------------------------------------
2125// wxMCIMediaBackend::GetVideoSize
2126//
2127// Gets the original size of the movie for sizers
226ec5a7 2128//---------------------------------------------------------------------------
ff4aedc5 2129wxSize wxMCIMediaBackend::GetVideoSize() const
3f9a3bf9
RN
2130{
2131 if(m_bVideo)
2132 {
ff4aedc5 2133 MCI_DGV_RECT_PARMS whereParms; //ifdefed MCI_DGV_WHERE_PARMS
3f9a3bf9 2134
226ec5a7 2135 wxMCIVERIFY( mciSendCommand(m_hDev, MCI_WHERE,
ff4aedc5
RN
2136 0x00020000L, //MCI_DGV_WHERE_SOURCE
2137 (DWORD)(LPSTR)&whereParms) );
226ec5a7 2138
ff4aedc5 2139 return wxSize(whereParms.rc.right, whereParms.rc.bottom);
3f9a3bf9 2140 }
c47addef 2141 return wxSize(0,0);
3f9a3bf9
RN
2142}
2143
ff4aedc5
RN
2144//---------------------------------------------------------------------------
2145// wxMCIMediaBackend::GetPlaybackRate
2146//
2147// TODO
226ec5a7 2148//---------------------------------------------------------------------------
ff4aedc5 2149double wxMCIMediaBackend::GetPlaybackRate()
3f9a3bf9
RN
2150{
2151 return 1.0;
2152}
2153
ff4aedc5
RN
2154//---------------------------------------------------------------------------
2155// wxMCIMediaBackend::SetPlaybackRate
2156//
2157// TODO
226ec5a7 2158//---------------------------------------------------------------------------
ff4aedc5 2159bool wxMCIMediaBackend::SetPlaybackRate(double WXUNUSED(dRate))
3f9a3bf9 2160{
ff4aedc5
RN
2161/*
2162 MCI_WAVE_SET_SAMPLESPERSEC
2163 MCI_DGV_SET_PARMS setParms;
2164 setParms.dwSpeed = (DWORD) (dRate * 1000.0);
2165
226ec5a7 2166 return (mciSendCommand(m_hDev, MCI_SET,
ff4aedc5
RN
2167 0x00020000L, //MCI_DGV_SET_SPEED
2168 (DWORD)(LPSTR)&setParms) == 0);
2169*/
3f9a3bf9
RN
2170 return false;
2171}
2172
ff4aedc5
RN
2173//---------------------------------------------------------------------------
2174// [static] wxMCIMediaBackend::MSWWindowProc
2175//
226ec5a7 2176// Here we process a message when MCI reaches the stopping point
ff4aedc5 2177// in the stream
226ec5a7
WS
2178//---------------------------------------------------------------------------
2179LRESULT CALLBACK wxMCIMediaBackend::NotifyWndProc(HWND hWnd, UINT nMsg,
2180 WPARAM wParam,
ff4aedc5
RN
2181 LPARAM lParam)
2182{
2183 wxMCIMediaBackend* backend = (wxMCIMediaBackend*)
106d80ad 2184#ifdef _WIN32
ff4aedc5 2185 ::GetWindowLong(hWnd, GWL_USERDATA);
106d80ad
JS
2186#else
2187 ::GetWindowLongPtr(hWnd, GWLP_USERDATA);
b11eba7e 2188#endif
ff4aedc5
RN
2189 wxASSERT(backend);
2190
2191 return backend->OnNotifyWndProc(hWnd, nMsg, wParam, lParam);
2192}
2193
226ec5a7
WS
2194LRESULT CALLBACK wxMCIMediaBackend::OnNotifyWndProc(HWND hWnd, UINT nMsg,
2195 WPARAM wParam,
ff4aedc5 2196 LPARAM lParam)
3f9a3bf9 2197{
5987f174
RN
2198 if(nMsg == MM_MCINOTIFY)
2199 {
ff4aedc5
RN
2200 wxASSERT(lParam == (LPARAM) m_hDev);
2201 if(wParam == MCI_NOTIFY_SUCCESSFUL && lParam == (LPARAM)m_hDev)
5987f174 2202 {
ff4aedc5
RN
2203 wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId());
2204 m_ctrl->ProcessEvent(theEvent);
2205
2206 if(theEvent.IsAllowed())
2207 {
226ec5a7 2208 wxMCIVERIFY( mciSendCommand(m_hDev, MCI_SEEK,
ff4aedc5 2209 MCI_SEEK_TO_START, 0) );
3f9a3bf9 2210
ff4aedc5 2211 //send the event to our child
226ec5a7 2212 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
ff4aedc5
RN
2213 m_ctrl->GetId());
2214 m_ctrl->ProcessEvent(theEvent);
2215 }
5987f174 2216 }
5987f174 2217 }
ff4aedc5 2218 return DefWindowProc(hWnd, nMsg, wParam, lParam);
3f9a3bf9 2219}
ff4aedc5
RN
2220//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2221//
2222// wxQTMediaBackend
226ec5a7 2223//
ff4aedc5
RN
2224// TODO: Use a less cludgy way to pause/get state/set state
2225// TODO: Dynamically load from qtml.dll
2226//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2227
ff4aedc5
RN
2228IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
2229
2230//Time between timer calls
2231#define MOVIE_DELAY 100
2232
2233#include "wx/timer.h"
2234
2235// --------------------------------------------------------------------------
2236// wxQTTimer - Handle Asyncronous Playing
2237// --------------------------------------------------------------------------
2238class _wxQTTimer : public wxTimer
2239{
2240public:
d7a9c895
RN
2241 _wxQTTimer(Movie movie, wxQTMediaBackend* parent, wxQuickTimeLibrary* pLib) :
2242 m_movie(movie), m_bPaused(false), m_parent(parent), m_pLib(pLib)
ff4aedc5
RN
2243 {
2244 }
2245
2246 ~_wxQTTimer()
2247 {
2248 }
2249
2250 bool GetPaused() {return m_bPaused;}
2251 void SetPaused(bool bPaused) {m_bPaused = bPaused;}
2252
2253 //-----------------------------------------------------------------------
2254 // _wxQTTimer::Notify
2255 //
2256 // 1) Checks to see if the movie is done, and if not continues
2257 // streaming the movie
2258 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
2259 // the movie.
2260 //-----------------------------------------------------------------------
2261 void Notify()
2262 {
2263 if (!m_bPaused)
2264 {
d7a9c895
RN
2265 if(!m_pLib->IsMovieDone(m_movie))
2266 m_pLib->MoviesTask(m_movie, MOVIE_DELAY);
ff4aedc5
RN
2267 else
2268 {
226ec5a7 2269 wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
ff4aedc5
RN
2270 m_parent->m_ctrl->GetId());
2271 m_parent->m_ctrl->ProcessEvent(theEvent);
2272
2273 if(theEvent.IsAllowed())
2274 {
2275 Stop();
2276 m_parent->Stop();
d7a9c895 2277 wxASSERT(m_pLib->GetMoviesError() == noErr);
ff4aedc5
RN
2278
2279 //send the event to our child
226ec5a7 2280 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
ff4aedc5
RN
2281 m_parent->m_ctrl->GetId());
2282 m_parent->m_ctrl->ProcessEvent(theEvent);
2283 }
2284 }
2285 }
2286 }
2287
2288protected:
2289 Movie m_movie; //Our movie instance
2290 bool m_bPaused; //Whether we are paused or not
2291 wxQTMediaBackend* m_parent; //Backend pointer
d7a9c895 2292 wxQuickTimeLibrary* m_pLib; //Interfaces
ff4aedc5
RN
2293};
2294
2295//---------------------------------------------------------------------------
2296// wxQTMediaBackend Destructor
2297//
2298// Sets m_timer to NULL signifying we havn't loaded anything yet
2299//---------------------------------------------------------------------------
2300wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
2301{
2302}
2303
2304//---------------------------------------------------------------------------
2305// wxQTMediaBackend Destructor
2306//
2307// 1) Cleans up the QuickTime movie instance
2308// 2) Decrements the QuickTime reference counter - if this reaches
2309// 0, QuickTime shuts down
2310// 3) Decrements the QuickTime Windows Media Layer reference counter -
2311// if this reaches 0, QuickTime shuts down the Windows Media Layer
2312//---------------------------------------------------------------------------
2313wxQTMediaBackend::~wxQTMediaBackend()
2314{
2315 if(m_timer)
2316 Cleanup();
2317
d7a9c895
RN
2318 if(m_lib.IsOk())
2319 {
3103e8a9 2320 //Note that ExitMovies() is not necessary, but
d7a9c895
RN
2321 //the docs are fuzzy on whether or not TerminateQTML is
2322 m_lib.ExitMovies();
2323 m_lib.TerminateQTML();
2324 }
ff4aedc5
RN
2325}
2326
2327//---------------------------------------------------------------------------
2328// wxQTMediaBackend::CreateControl
2329//
2330// 1) Intializes QuickTime
2331// 2) Creates the control window
2332//---------------------------------------------------------------------------
226ec5a7 2333bool wxQTMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 2334 wxWindowID id,
226ec5a7 2335 const wxPoint& pos,
ff4aedc5 2336 const wxSize& size,
226ec5a7 2337 long style,
ff4aedc5
RN
2338 const wxValidator& validator,
2339 const wxString& name)
2340{
d7a9c895
RN
2341 if(!m_lib.Initialize())
2342 return false;
b11eba7e 2343
600ffb32
WS
2344 int nError = m_lib.InitializeQTML(0);
2345 if (nError != noErr) //-2093 no dll
ff4aedc5
RN
2346 {
2347 wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError));
2348 return false;
2349 }
d7a9c895 2350 m_lib.EnterMovies();
ff4aedc5
RN
2351
2352 //
2353 // Create window
2354 // By default wxWindow(s) is created with a border -
2355 // so we need to get rid of those
2356 //
2357 // Since we don't have a child window like most other
2358 // backends, we don't need wxCLIP_CHILDREN
2359 //
2360 if ( !ctrl->wxControl::Create(parent, id, pos, size,
11085e4b 2361 (style & ~wxBORDER_MASK) | wxBORDER_NONE,
ff4aedc5
RN
2362 validator, name) )
2363 return false;
2364
ff4aedc5
RN
2365 m_ctrl = ctrl;
2366 return true;
2367}
2368
2369//---------------------------------------------------------------------------
2370// wxQTMediaBackend::Load (file version)
2371//
2372// 1) Get an FSSpec from the Windows path name
2373// 2) Open the movie
2374// 3) Obtain the movie instance from the movie resource
226ec5a7 2375// 4)
ff4aedc5
RN
2376//---------------------------------------------------------------------------
2377bool wxQTMediaBackend::Load(const wxString& fileName)
2378{
2379 if(m_timer)
2380 Cleanup();
3f9a3bf9 2381
920a7c15 2382 short movieResFile = 0; //= 0 because of annoying VC6 warning
ff4aedc5
RN
2383 FSSpec sfFile;
2384
d7a9c895 2385 if (m_lib.NativePathNameToFSSpec ((char*) (const char*) fileName.mb_str(),
78450975 2386 &sfFile, 0) != noErr)
ff4aedc5 2387 return false;
226ec5a7 2388
d7a9c895 2389 if (m_lib.OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr)
ff4aedc5
RN
2390 return false;
2391
2392 short movieResID = 0;
2393 Str255 movieName;
2394
600ffb32
WS
2395 OSErr err = m_lib.NewMovieFromFile (
2396 &m_movie,
2397 movieResFile,
2398 &movieResID,
2399 movieName,
2400 newMovieActive,
2401 NULL
2402 ); //wasChanged
ff4aedc5 2403
d7a9c895 2404 m_lib.CloseMovieFile (movieResFile);
ff4aedc5
RN
2405
2406 if (err != noErr)
2407 return false;
2408
2409 FinishLoad();
2410
d7a9c895 2411 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2412}
2413
2414//---------------------------------------------------------------------------
2415// wxQTMediaBackend::Move
2416//
2417// TODO
2418//---------------------------------------------------------------------------
2419bool wxQTMediaBackend::Load(const wxURI& location)
2420{
2421 if(m_timer)
2422 Cleanup();
2423
2424 wxString theURI = location.BuildURI();
2425
d7a9c895 2426 Handle theHandle = m_lib.NewHandleClear(theURI.length() + 1);
ff4aedc5
RN
2427 wxASSERT(theHandle);
2428
d7a9c895 2429 m_lib.BlockMove(theURI.mb_str(), *theHandle, theURI.length() + 1);
ff4aedc5
RN
2430
2431 //create the movie from the handle that refers to the URI
600ffb32 2432 OSErr err = m_lib.NewMovieFromDataRef(&m_movie, newMovieActive,
226ec5a7 2433 NULL, theHandle,
19b6f122 2434 URLDataHandlerSubType);
ff4aedc5 2435
d7a9c895 2436 m_lib.DisposeHandle(theHandle);
ff4aedc5
RN
2437
2438 if (err != noErr)
2439 return false;
2440
2441 //preroll movie for streaming
2442 //TODO:Async this?
d7a9c895
RN
2443 /*
2444 TimeValue timeNow;
ff4aedc5
RN
2445 Fixed playRate;
2446 timeNow = GetMovieTime(m_movie, NULL);
2447 playRate = GetMoviePreferredRate(m_movie);
2448 PrePrerollMovie(m_movie, timeNow, playRate, NULL, NULL);
b11eba7e 2449 PrerollMovie(m_movie, timeNow, playRate);
d7a9c895
RN
2450 m_lib.SetMovieRate(m_movie, playRate);
2451*/
ff4aedc5
RN
2452
2453 FinishLoad();
2454
d7a9c895 2455 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2456}
2457
2458//---------------------------------------------------------------------------
2459// wxQTMediaBackend::Move
2460//
2461// TODO
2462//---------------------------------------------------------------------------
2463void wxQTMediaBackend::FinishLoad()
2464{
d7a9c895 2465 m_timer = new _wxQTTimer(m_movie, (wxQTMediaBackend*) this, &m_lib);
ff4aedc5
RN
2466 wxASSERT(m_timer);
2467
2468 //get the real size of the movie
2469 Rect outRect;
920a7c15 2470 memset(&outRect, 0, sizeof(Rect)); //for annoying VC6 warning
d7a9c895
RN
2471 m_lib.GetMovieNaturalBoundsRect (m_movie, &outRect);
2472 wxASSERT(m_lib.GetMoviesError() == noErr);
ff4aedc5
RN
2473
2474 m_bestSize.x = outRect.right - outRect.left;
2475 m_bestSize.y = outRect.bottom - outRect.top;
226ec5a7 2476
ff4aedc5 2477 //reparent movie/*AudioMediaCharacteristic*/
d7a9c895 2478 if(m_lib.GetMovieIndTrackType(m_movie, 1,
19b6f122 2479 VisualMediaCharacteristic,
b11eba7e 2480 (1 << 1) //movieTrackCharacteristic
d7a9c895
RN
2481 | (1 << 2) //movieTrackEnabledOnly
2482 ) != NULL)
ff4aedc5 2483 {
d7a9c895 2484 m_lib.CreatePortAssociation(m_ctrl->GetHWND(), NULL, 0L);
226ec5a7 2485
d7a9c895
RN
2486 m_lib.SetMovieGWorld(m_movie,
2487 (CGrafPtr) m_lib.GetNativeWindowPort(m_ctrl->GetHWND()),
2488 NULL);
ff4aedc5
RN
2489 }
2490
2491 //we want millisecond precision
d7a9c895
RN
2492 m_lib.SetMovieTimeScale(m_movie, 1000);
2493 wxASSERT(m_lib.GetMoviesError() == noErr);
ff4aedc5
RN
2494
2495 //
2496 //Here, if the parent of the control has a sizer - we
2497 //tell it to recalculate the size of this control since
3103e8a9 2498 //the user opened a separate media file
ff4aedc5
RN
2499 //
2500 m_ctrl->InvalidateBestSize();
2501 m_ctrl->GetParent()->Layout();
2502 m_ctrl->GetParent()->Refresh();
2503 m_ctrl->GetParent()->Update();
2504}
2505
2506//---------------------------------------------------------------------------
2507// wxQTMediaBackend::Move
2508//
2509// TODO
2510//---------------------------------------------------------------------------
2511bool wxQTMediaBackend::Play()
2512{
d7a9c895 2513 m_lib.StartMovie(m_movie);
ff4aedc5
RN
2514 m_timer->SetPaused(false);
2515 m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
d7a9c895 2516 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2517}
2518
2519//---------------------------------------------------------------------------
2520// wxQTMediaBackend::Move
2521//
2522// TODO
2523//---------------------------------------------------------------------------
2524bool wxQTMediaBackend::Pause()
2525{
d7a9c895 2526 m_lib.StopMovie(m_movie);
ff4aedc5
RN
2527 m_timer->SetPaused(true);
2528 m_timer->Stop();
d7a9c895 2529 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2530}
2531
2532//---------------------------------------------------------------------------
2533// wxQTMediaBackend::Move
2534//
2535// TODO
2536//---------------------------------------------------------------------------
2537bool wxQTMediaBackend::Stop()
2538{
2539 m_timer->SetPaused(false);
2540 m_timer->Stop();
2541
d7a9c895
RN
2542 m_lib.StopMovie(m_movie);
2543 if(m_lib.GetMoviesError() != noErr)
ff4aedc5 2544 return false;
226ec5a7 2545
d7a9c895
RN
2546 m_lib.GoToBeginningOfMovie(m_movie);
2547 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2548}
2549
2550//---------------------------------------------------------------------------
2551// wxQTMediaBackend::Move
2552//
2553// TODO
2554//---------------------------------------------------------------------------
2555double wxQTMediaBackend::GetPlaybackRate()
2556{
d7a9c895 2557 return ( ((double)m_lib.GetMovieRate(m_movie)) / 0x10000);
ff4aedc5
RN
2558}
2559
2560//---------------------------------------------------------------------------
2561// wxQTMediaBackend::Move
2562//
2563// TODO
2564//---------------------------------------------------------------------------
2565bool wxQTMediaBackend::SetPlaybackRate(double dRate)
2566{
d7a9c895
RN
2567 m_lib.SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
2568 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2569}
2570
2571//---------------------------------------------------------------------------
2572// wxQTMediaBackend::Move
2573//
2574// TODO
2575//---------------------------------------------------------------------------
2576bool wxQTMediaBackend::SetPosition(wxLongLong where)
2577{
2578 TimeRecord theTimeRecord;
2579 memset(&theTimeRecord, 0, sizeof(TimeRecord));
600ffb32 2580 theTimeRecord.value.lo = where.GetLo();
d7a9c895
RN
2581 theTimeRecord.scale = m_lib.GetMovieTimeScale(m_movie);
2582 theTimeRecord.base = m_lib.GetMovieTimeBase(m_movie);
2583 m_lib.SetMovieTime(m_movie, &theTimeRecord);
ff4aedc5 2584
d7a9c895 2585 if (m_lib.GetMoviesError() != noErr)
ff4aedc5
RN
2586 return false;
2587
2588 return true;
2589}
2590
2591//---------------------------------------------------------------------------
e163773d 2592// wxQTMediaBackend::GetPosition
ff4aedc5 2593//
e163773d 2594// 1) Calls GetMovieTime to get the position we are in in the movie
8b5d5223 2595// in milliseconds (we called
ff4aedc5
RN
2596//---------------------------------------------------------------------------
2597wxLongLong wxQTMediaBackend::GetPosition()
2598{
d7a9c895 2599 return m_lib.GetMovieTime(m_movie, NULL);
ff4aedc5
RN
2600}
2601
6f8c67e7
JS
2602//---------------------------------------------------------------------------
2603// wxQTMediaBackend::GetVolume
2604//
2605// Gets the volume through GetMovieVolume - which returns a 16 bit short -
2606//
2607// +--------+--------+
2608// + (1) + (2) +
2609// +--------+--------+
2610//
2611// (1) first 8 bits are value before decimal
2612// (2) second 8 bits are value after decimal
2613//
2614// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
2615// 1 (full gain and sound)
2616//---------------------------------------------------------------------------
2617double wxQTMediaBackend::GetVolume()
2618{
2619 short sVolume = m_lib.GetMovieVolume(m_movie);
b11eba7e 2620
6f8c67e7
JS
2621 if(sVolume & (128 << 8)) //negative - no sound
2622 return 0.0;
2623
2624 return (sVolume & (127 << 8)) ? 1.0 : ((double)(sVolume & 255)) / 255.0;
2625}
2626
2627//---------------------------------------------------------------------------
2628// wxQTMediaBackend::SetVolume
2629//
2630// Sets the volume through SetMovieVolume - which takes a 16 bit short -
2631//
2632// +--------+--------+
2633// + (1) + (2) +
2634// +--------+--------+
2635//
2636// (1) first 8 bits are value before decimal
2637// (2) second 8 bits are value after decimal
2638//
2639// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
2640// 1 (full gain and sound)
2641//---------------------------------------------------------------------------
2642bool wxQTMediaBackend::SetVolume(double dVolume)
2643{
600ffb32 2644 short sVolume = (short) (dVolume >= .9999 ? 1 << 8 : (dVolume * 255) );
6f8c67e7
JS
2645 m_lib.SetMovieVolume(m_movie, sVolume);
2646 return true;
2647}
2648
ff4aedc5
RN
2649//---------------------------------------------------------------------------
2650// wxQTMediaBackend::Move
2651//
2652// TODO
2653//---------------------------------------------------------------------------
2654wxLongLong wxQTMediaBackend::GetDuration()
2655{
d7a9c895 2656 return m_lib.GetMovieDuration(m_movie);
ff4aedc5
RN
2657}
2658
2659//---------------------------------------------------------------------------
2660// wxQTMediaBackend::Move
2661//
2662// TODO
2663//---------------------------------------------------------------------------
2664wxMediaState wxQTMediaBackend::GetState()
2665{
226ec5a7 2666 if ( !m_timer || (m_timer->IsRunning() == false &&
ff4aedc5
RN
2667 m_timer->GetPaused() == false) )
2668 return wxMEDIASTATE_STOPPED;
2669
2670 if( m_timer->IsRunning() == true )
2671 return wxMEDIASTATE_PLAYING;
2672 else
2673 return wxMEDIASTATE_PAUSED;
2674}
2675
2676//---------------------------------------------------------------------------
2677// wxQTMediaBackend::Move
2678//
2679// TODO
2680//---------------------------------------------------------------------------
2681void wxQTMediaBackend::Cleanup()
2682{
2683 delete m_timer;
2684 m_timer = NULL;
2685
d7a9c895
RN
2686 m_lib.StopMovie(m_movie);
2687 m_lib.DisposeMovie(m_movie);
ff4aedc5
RN
2688}
2689
2690//---------------------------------------------------------------------------
2691// wxQTMediaBackend::Move
2692//
2693// TODO
2694//---------------------------------------------------------------------------
2695wxSize wxQTMediaBackend::GetVideoSize() const
2696{
2697 return m_bestSize;
2698}
2699
2700//---------------------------------------------------------------------------
2701// wxQTMediaBackend::Move
2702//
2703// TODO
2704//---------------------------------------------------------------------------
d7a9c895 2705void wxQTMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y), int w, int h)
ff4aedc5
RN
2706{
2707 if(m_timer)
2708 {
600ffb32 2709 Rect theRect = {0, 0, (short)h, (short)w};
ff4aedc5 2710
d7a9c895
RN
2711 m_lib.SetMovieBox(m_movie, &theRect);
2712 wxASSERT(m_lib.GetMoviesError() == noErr);
ff4aedc5
RN
2713 }
2714}
2715
2716//---------------------------------------------------------------------------
1146983c 2717// End QT Backend
ff4aedc5 2718//---------------------------------------------------------------------------
ff4aedc5
RN
2719
2720//in source file that contains stuff you don't directly use
2721#include <wx/html/forcelnk.h>
2722FORCE_LINK_ME(basewxmediabackends);
2723
2724//---------------------------------------------------------------------------
2725// End wxMediaCtrl Compilation Guard and this file
2726//---------------------------------------------------------------------------
72259e00
RL
2727#endif //wxUSE_MEDIACTRL
2728
ff4aedc5 2729