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