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