]> git.saurik.com Git - wxWidgets.git/blame - src/msw/mediactrl.cpp
use a constant instead of hardcoded value
[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//
32f65e50 72// There are many, many ways to do this.
920a7c15
JS
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
32f65e50 78// 3) Create an instance of IAMMultiMediaStream, call
920a7c15 79// IAMMultiMediaStream::AddStream and pass an IDirectDraw instance for
32f65e50 80// the video, and pass an IDirectSound(Buffer?) instance or use the
920a7c15
JS
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
32f65e50 86// because the IVideoWindow instance hogs a lot of the useful window
920a7c15
JS
87// messages such as WM_SETCURSOR.
88//
32f65e50 89// Solution #1 was to use #3 by creating a seperate IDirectDraw instance
920a7c15
JS
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//
32f65e50 93// The current way is to use windowless rendering and have directshow
920a7c15
JS
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//
32f65e50 101// IMediaPosition - we can set the rate with this... we can also get
920a7c15
JS
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//
32f65e50 109// IDirectDrawVideo - you can get this through the IFilter returned
920a7c15
JS
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
32f65e50 118// 2) Have IMediaSeekingEx send a message to a windowproc or signal a
920a7c15
JS
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
32f65e50 146// Dumped from amstream.idl, quartz.idl, direct draw and with some
920a7c15
JS
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{
32f65e50
WS
211 DWORD dwSize;
212 DWORD dwFlags;
213 DWORD dwHeight;
214 DWORD dwWidth;
920a7c15
JS
215 union
216 {
32f65e50
WS
217 LONG lPitch;
218 DWORD dwLinearSize;
920a7c15 219 };
32f65e50 220 DWORD dwBackBufferCount;
920a7c15
JS
221 union
222 {
32f65e50
WS
223 DWORD dwMipMapCount;
224 DWORD dwZBufferBitDepth;
225 DWORD dwRefreshRate;
920a7c15 226 };
32f65e50
WS
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;
32f65e50 265 STDMETHOD(GetFlipStatus)(DWORD) PURE;
920a7c15
JS
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;
32f65e50 278 STDMETHOD(SetPalette)(IUnknown*) PURE;
920a7c15
JS
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};
32f65e50 309
920a7c15 310//---------------------------------------------------------------------------
32f65e50 311// AMMEDIA COM INTERFACES
920a7c15
JS
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 334 STDMETHOD(GetMultiMediaStream)(IMultiMediaStream **) PURE;
32f65e50 335 STDMETHOD(GetInformation)(GUID *, int *) PURE;
920a7c15
JS
336 STDMETHOD(SetSameFormat)(IMediaStream *, DWORD) PURE;
337 STDMETHOD(AllocateSample)(DWORD, IStreamSample **) PURE;
32f65e50 338 STDMETHOD(CreateSharedSample)(IStreamSample *, DWORD,
920a7c15
JS
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;
32f65e50 358 STDMETHOD(GetMediaStream)(REFGUID, IMediaStream **) PURE;
920a7c15
JS
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;
32f65e50 373 STDMETHOD(AddMediaStream)(IUnknown *, const GUID*, DWORD,
920a7c15
JS
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;
32f65e50 451 STDMETHOD(SetVideoPosition)(const LPRECT,const LPRECT) PURE;
920a7c15
JS
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;
32f65e50 475 STDMETHOD(GetRenderingMode)(DWORD *) PURE;
920a7c15 476};
32f65e50 477
920a7c15
JS
478typedef IUnknown IBaseFilter;
479typedef IUnknown IPin;
480typedef IUnknown IEnumFilters;
32f65e50 481typedef int AM_MEDIA_TYPE;
920a7c15
JS
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 522 void OnPaint(wxPaintEvent&);
920a7c15 523 void OnEraseBackground(wxEraseEvent&);
a2a444e3
RN
524};
525
920a7c15
JS
526typedef BOOL (WINAPI* LPAMGETERRORTEXT)(HRESULT, wxChar *, DWORD);
527
ff2b312f 528class WXDLLIMPEXP_MEDIA wxAMMediaBackend : public wxMediaBackend
1a680109
RN
529{
530public:
ff4aedc5 531 wxAMMediaBackend();
1a680109 532
ff4aedc5 533 virtual ~wxAMMediaBackend();
1a680109 534
226ec5a7 535 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 536 wxWindowID id,
226ec5a7 537 const wxPoint& pos,
ff4aedc5 538 const wxSize& size,
226ec5a7 539 long style,
ff4aedc5
RN
540 const wxValidator& validator,
541 const wxString& name);
1a680109
RN
542
543 virtual bool Play();
544 virtual bool Pause();
545 virtual bool Stop();
546
547 virtual bool Load(const wxString& fileName);
548 virtual bool Load(const wxURI& location);
549
550 virtual wxMediaState GetState();
551
ff4aedc5
RN
552 virtual bool SetPosition(wxLongLong where);
553 virtual wxLongLong GetPosition();
554 virtual wxLongLong GetDuration();
1a680109 555
ff4aedc5
RN
556 virtual void Move(int x, int y, int w, int h);
557 wxSize GetVideoSize() const;
1a680109
RN
558
559 virtual double GetPlaybackRate();
560 virtual bool SetPlaybackRate(double);
561
6f8c67e7
JS
562 virtual double GetVolume();
563 virtual bool SetVolume(double);
564
1a680109 565 void Cleanup();
920a7c15 566 void OnStop();
32f65e50 567 bool SetWindowlessMode(IGraphBuilder* pGB,
920a7c15 568 IVMRWindowlessControl** ppVMC = NULL);
1a680109 569
ff4aedc5 570 wxControl* m_ctrl;
1a680109 571
920a7c15
JS
572 wxMediaState m_state;
573 wxCriticalSection m_rendercs;
574
575 IVMRWindowlessControl* m_pVMC;
576 IGraphBuilder* m_pGB;
a2a444e3 577 IBasicAudio* m_pBA;
1a680109 578 IMediaControl* m_pMC;
920a7c15 579 IMediaEvent* m_pME;
a2a444e3 580 IMediaPosition* m_pMS;
96339a78 581 bool m_bVideo;
32f65e50 582
920a7c15 583 wxAMMediaThread* m_pThread;
1a680109
RN
584
585 wxSize m_bestSize;
ff4aedc5 586
920a7c15
JS
587#ifdef __WXDEBUG__
588 HMODULE m_hQuartzDll;
589 LPAMGETERRORTEXT m_lpAMGetErrorText;
a3c1ce50 590 wxString GetErrorString(HRESULT hrdsv);
920a7c15
JS
591#endif
592
593 friend class wxAMMediaThread;
594 friend class wxAMMediaEvtHandler;
595
19b6f122 596 DECLARE_DYNAMIC_CLASS(wxAMMediaBackend)
1a680109
RN
597};
598
1a680109 599//---------------------------------------------------------------------------
ff4aedc5
RN
600//
601// wxMCIMediaBackend
602//
1a680109
RN
603//---------------------------------------------------------------------------
604
ff4aedc5
RN
605//---------------------------------------------------------------------------
606// MCI Includes
607//---------------------------------------------------------------------------
1a680109 608#include <mmsystem.h>
1a680109 609
ff2b312f 610class WXDLLIMPEXP_MEDIA wxMCIMediaBackend : public wxMediaBackend
1a680109
RN
611{
612public:
3f9a3bf9 613
ff4aedc5
RN
614 wxMCIMediaBackend();
615 ~wxMCIMediaBackend();
1a680109 616
226ec5a7 617 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 618 wxWindowID id,
226ec5a7 619 const wxPoint& pos,
ff4aedc5 620 const wxSize& size,
226ec5a7 621 long style,
ff4aedc5
RN
622 const wxValidator& validator,
623 const wxString& name);
1a680109
RN
624
625 virtual bool Play();
626 virtual bool Pause();
627 virtual bool Stop();
628
629 virtual bool Load(const wxString& fileName);
630 virtual bool Load(const wxURI& location);
631
632 virtual wxMediaState GetState();
633
ff4aedc5
RN
634 virtual bool SetPosition(wxLongLong where);
635 virtual wxLongLong GetPosition();
636 virtual wxLongLong GetDuration();
1a680109 637
ff4aedc5
RN
638 virtual void Move(int x, int y, int w, int h);
639 wxSize GetVideoSize() const;
1a680109
RN
640
641 virtual double GetPlaybackRate();
ff4aedc5 642 virtual bool SetPlaybackRate(double dRate);
3f9a3bf9 643
6f8c67e7
JS
644 virtual double GetVolume();
645 virtual bool SetVolume(double);
646
226ec5a7 647 static LRESULT CALLBACK NotifyWndProc(HWND hWnd, UINT nMsg,
ff4aedc5 648 WPARAM wParam, LPARAM lParam);
5987f174 649
226ec5a7 650 LRESULT CALLBACK OnNotifyWndProc(HWND hWnd, UINT nMsg,
ff4aedc5 651 WPARAM wParam, LPARAM lParam);
1a680109 652
ff4aedc5
RN
653 MCIDEVICEID m_hDev; //Our MCI Device ID/Handler
654 wxControl* m_ctrl; //Parent control
655 HWND m_hNotifyWnd; //Window to use for MCI events
656 bool m_bVideo; //Whether or not we have video
657
3839f37e 658 DECLARE_DYNAMIC_CLASS(wxMCIMediaBackend)
ff4aedc5 659};
1a680109
RN
660
661//---------------------------------------------------------------------------
662//
ff4aedc5 663// wxQTMediaBackend
1a680109
RN
664//
665//---------------------------------------------------------------------------
666
ff4aedc5
RN
667//---------------------------------------------------------------------------
668// QT Includes
669//---------------------------------------------------------------------------
d7a9c895
RN
670//#include <qtml.h> //Windoze QT include
671//#include <QuickTimeComponents.h> //Standard QT stuff
672#include "wx/dynlib.h"
673
674//---------------------------------------------------------------------------
675// QT Types
676//---------------------------------------------------------------------------
677typedef struct MovieRecord* Movie;
678typedef wxInt16 OSErr;
679typedef wxInt32 OSStatus;
680#define noErr 0
681#define fsRdPerm 1
682typedef unsigned char Str255[256];
683#define StringPtr unsigned char*
684#define newMovieActive 1
b11eba7e 685#define Ptr char*
d7a9c895
RN
686#define Handle Ptr*
687#define Fixed long
688#define OSType unsigned long
b11eba7e 689#define CGrafPtr struct GrafPort *
d7a9c895 690#define TimeScale long
b11eba7e 691#define TimeBase struct TimeBaseRecord *
d7a9c895 692
19b6f122
WS
693#ifndef URLDataHandlerSubType
694#if defined(__WATCOMC__) || defined(__MINGW32__)
695// use magic numbers for compilers which complain about multicharacter integers
696const OSType URLDataHandlerSubType = 1970433056;
697const OSType VisualMediaCharacteristic = 1702454643;
698#else
699const OSType URLDataHandlerSubType = 'url ';
700const OSType VisualMediaCharacteristic = 'eyes';
701#endif
702#endif
703
d7a9c895 704struct FSSpec {
600ffb32
WS
705 short vRefNum;
706 long parID;
707 Str255 name; /*Str63 on mac, Str255 on msw */
d7a9c895
RN
708};
709
710struct Rect {
600ffb32
WS
711 short top;
712 short left;
713 short bottom;
714 short right;
d7a9c895
RN
715};
716
717struct wide {
600ffb32
WS
718 wxInt32 hi;
719 wxUint32 lo;
d7a9c895
RN
720};
721
722struct TimeRecord {
600ffb32
WS
723 wide value; /* units */
724 TimeScale scale; /* units per second */
725 TimeBase base;
d7a9c895
RN
726};
727
728//---------------------------------------------------------------------------
729// QT Library
730//---------------------------------------------------------------------------
731#define wxDL_METHOD_DEFINE( rettype, name, args, shortargs, defret ) \
732 typedef rettype (* name ## Type) args ; \
733 name ## Type pfn_ ## name; \
734 rettype name args \
735 { if (m_ok) return pfn_ ## name shortargs ; return defret; }
b11eba7e 736
d7a9c895
RN
737#define wxDL_VOIDMETHOD_DEFINE( name, args, shortargs ) \
738 typedef void (* name ## Type) args ; \
739 name ## Type pfn_ ## name; \
740 void name args \
741 { if (m_ok) pfn_ ## name shortargs ; }
742
743#define wxDL_METHOD_LOAD( lib, name, success ) \
744 pfn_ ## name = (name ## Type) lib.GetSymbol( wxT(#name), &success ); \
3131207f 745 if (!success) { wxLog::EnableLogging(bWasLoggingEnabled); return false; }
32f65e50 746
d7a9c895
RN
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
3131207f 832 bool bWasLoggingEnabled = wxLog::EnableLogging(false); //Turn off the wxDynamicLibrary logging
32f65e50 833
d7a9c895 834 if(!m_dll.Load(wxT("qtmlClient.dll")))
32f65e50 835 {
3131207f 836 wxLog::EnableLogging(bWasLoggingEnabled);
d7a9c895 837 return false;
32f65e50 838 }
d7a9c895 839
32f65e50 840 bool bOk; //TODO: Get rid of this, use m_ok instead (not a biggie)
d7a9c895
RN
841
842 wxDL_METHOD_LOAD( m_dll, StartMovie, bOk );
843 wxDL_METHOD_LOAD( m_dll, StopMovie, bOk );
844 wxDL_METHOD_LOAD( m_dll, IsMovieDone, bOk );
845 wxDL_METHOD_LOAD( m_dll, GoToBeginningOfMovie, bOk );
846 wxDL_METHOD_LOAD( m_dll, GetMoviesError, bOk );
847 wxDL_METHOD_LOAD( m_dll, EnterMovies, bOk );
848 wxDL_METHOD_LOAD( m_dll, ExitMovies, bOk );
849 wxDL_METHOD_LOAD( m_dll, InitializeQTML, bOk );
850 wxDL_METHOD_LOAD( m_dll, TerminateQTML, bOk );
851 wxDL_METHOD_LOAD( m_dll, NativePathNameToFSSpec, bOk );
852 wxDL_METHOD_LOAD( m_dll, OpenMovieFile, bOk );
853 wxDL_METHOD_LOAD( m_dll, CloseMovieFile, bOk );
854 wxDL_METHOD_LOAD( m_dll, NewMovieFromFile, bOk );
855 wxDL_METHOD_LOAD( m_dll, GetMovieRate, bOk );
856 wxDL_METHOD_LOAD( m_dll, SetMovieRate, bOk );
857 wxDL_METHOD_LOAD( m_dll, MoviesTask, bOk );
858 wxDL_METHOD_LOAD( m_dll, BlockMove, bOk );
859 wxDL_METHOD_LOAD( m_dll, NewHandleClear, bOk );
860 wxDL_METHOD_LOAD( m_dll, NewMovieFromDataRef, bOk );
861 wxDL_METHOD_LOAD( m_dll, DisposeHandle, bOk );
862 wxDL_METHOD_LOAD( m_dll, GetMovieNaturalBoundsRect, bOk );
863 wxDL_METHOD_LOAD( m_dll, GetMovieIndTrackType, bOk );
864 wxDL_METHOD_LOAD( m_dll, CreatePortAssociation, bOk );
865 wxDL_METHOD_LOAD( m_dll, GetNativeWindowPort, bOk );
866 wxDL_METHOD_LOAD( m_dll, SetMovieGWorld, bOk );
867 wxDL_METHOD_LOAD( m_dll, DisposeMovie, bOk );
868 wxDL_METHOD_LOAD( m_dll, SetMovieBox, bOk );
869 wxDL_METHOD_LOAD( m_dll, SetMovieTimeScale, bOk );
870 wxDL_METHOD_LOAD( m_dll, GetMovieDuration, bOk );
871 wxDL_METHOD_LOAD( m_dll, GetMovieTimeBase, bOk );
872 wxDL_METHOD_LOAD( m_dll, GetMovieTimeScale, bOk );
873 wxDL_METHOD_LOAD( m_dll, GetMovieTime, bOk );
874 wxDL_METHOD_LOAD( m_dll, SetMovieTime, bOk );
6f8c67e7
JS
875 wxDL_METHOD_LOAD( m_dll, GetMovieVolume, bOk );
876 wxDL_METHOD_LOAD( m_dll, SetMovieVolume, bOk );
b11eba7e 877
3131207f 878 wxLog::EnableLogging(bWasLoggingEnabled);
d7a9c895
RN
879 m_ok = true;
880
881 return true;
882}
1a680109 883
ff2b312f 884class WXDLLIMPEXP_MEDIA wxQTMediaBackend : public wxMediaBackend
ff4aedc5
RN
885{
886public:
ff4aedc5
RN
887 wxQTMediaBackend();
888 ~wxQTMediaBackend();
1a680109 889
226ec5a7 890 virtual bool CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 891 wxWindowID id,
226ec5a7 892 const wxPoint& pos,
ff4aedc5 893 const wxSize& size,
226ec5a7 894 long style,
ff4aedc5
RN
895 const wxValidator& validator,
896 const wxString& name);
1a680109 897
ff4aedc5
RN
898 virtual bool Play();
899 virtual bool Pause();
900 virtual bool Stop();
1a680109 901
ff4aedc5
RN
902 virtual bool Load(const wxString& fileName);
903 virtual bool Load(const wxURI& location);
1a680109 904
ff4aedc5 905 virtual wxMediaState GetState();
1a680109 906
ff4aedc5
RN
907 virtual bool SetPosition(wxLongLong where);
908 virtual wxLongLong GetPosition();
909 virtual wxLongLong GetDuration();
1a680109 910
ff4aedc5
RN
911 virtual void Move(int x, int y, int w, int h);
912 wxSize GetVideoSize() const;
1a680109 913
ff4aedc5
RN
914 virtual double GetPlaybackRate();
915 virtual bool SetPlaybackRate(double dRate);
1a680109 916
6f8c67e7
JS
917 virtual double GetVolume();
918 virtual bool SetVolume(double);
919
ff4aedc5
RN
920 void Cleanup();
921 void FinishLoad();
1a680109 922
ff4aedc5 923 wxSize m_bestSize; //Original movie size
d7a9c895 924 Movie m_movie; //QT Movie handle/instance
ff4aedc5
RN
925 wxControl* m_ctrl; //Parent control
926 bool m_bVideo; //Whether or not we have video
927 class _wxQTTimer* m_timer; //Timer for streaming the movie
d7a9c895
RN
928 wxQuickTimeLibrary m_lib;
929
19b6f122 930 DECLARE_DYNAMIC_CLASS(wxQTMediaBackend)
ff4aedc5 931};
1a680109 932
1a680109 933
ff4aedc5
RN
934//===========================================================================
935// IMPLEMENTATION
936//===========================================================================
1a680109 937
ff4aedc5
RN
938//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
939//
940// wxAMMediaBackend
941//
942//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1a680109 943
ff4aedc5 944IMPLEMENT_DYNAMIC_CLASS(wxAMMediaBackend, wxMediaBackend);
1a680109 945
ff4aedc5
RN
946//---------------------------------------------------------------------------
947// Usual debugging macros
948//---------------------------------------------------------------------------
949#ifdef __WXDEBUG__
920a7c15 950#define MAX_ERROR_TEXT_LEN 160
a3c1ce50
JS
951#include "wx/log.h" //wxLogDebug et al.
952
953//Get the error string for Active Movie
954wxString wxAMMediaBackend::GetErrorString(HRESULT hrdsv)
955{
32f65e50
WS
956 wxChar szError[MAX_ERROR_TEXT_LEN];
957 if( m_lpAMGetErrorText != NULL &&
958 (*m_lpAMGetErrorText)(hrdsv, szError, MAX_ERROR_TEXT_LEN) == 0)
959 {
a3c1ce50
JS
960 return wxString::Format(wxT("DirectShow error \"%s\" \n")
961 wxT("(numeric %i)\n")
32f65e50
WS
962 wxT("occured at line %i in ")
963 wxT("mediactrl.cpp"),
964 (int)hrdsv, szError, __LINE__);
965 }
966 else
967 {
968 return wxString::Format(wxT("Unknown error (%i) ")
969 wxT("occurred at")
970 wxT(" line %i in mediactrl.cpp."),
971 (int)hrdsv, __LINE__);
972 }
1a680109 973}
a3c1ce50 974
32f65e50 975#define wxAMFAIL(x) wxFAIL_MSG(GetErrorString(x));
ff4aedc5 976#define wxVERIFY(x) wxASSERT((x))
a3c1ce50 977#define wxAMLOG(x) wxLogDebug(GetErrorString(x))
ff4aedc5
RN
978#else
979#define wxAMVERIFY(x) (x)
980#define wxVERIFY(x) (x)
32f65e50
WS
981#define wxAMLOG(x)
982#define wxAMFAIL(x)
ff4aedc5 983#endif
1a680109 984
ff4aedc5
RN
985//---------------------------------------------------------------------------
986// Standard macros for ease of use
987//---------------------------------------------------------------------------
988#define SAFE_RELEASE(x) { if (x) x->Release(); x = NULL; }
1a680109 989
ff4aedc5
RN
990//---------------------------------------------------------------------------
991// wxAMMediaBackend Constructor
992//
993// Sets m_hNotifyWnd to NULL to signify that we haven't loaded anything yet
226ec5a7 994//---------------------------------------------------------------------------
32f65e50
WS
995wxAMMediaBackend::wxAMMediaBackend()
996 :m_state(wxMEDIASTATE_STOPPED)
997 ,m_pVMC(NULL)
998 ,m_pGB(NULL)
999 ,m_pBA(NULL)
1000 ,m_pMC(NULL)
1001 ,m_pME(NULL)
1002 ,m_pMS(NULL)
1003 ,m_pThread(NULL)
1004#ifdef __WXDEBUG__
1005 ,m_hQuartzDll(NULL)
1006#endif
1a680109 1007{
1a680109
RN
1008}
1009
ff4aedc5
RN
1010//---------------------------------------------------------------------------
1011// wxAMMediaBackend Destructor
1012//
226ec5a7
WS
1013// Cleans up everything
1014//---------------------------------------------------------------------------
ff4aedc5 1015wxAMMediaBackend::~wxAMMediaBackend()
1a680109 1016{
920a7c15 1017 if (m_pVMC)
ff4aedc5 1018 Cleanup();
920a7c15
JS
1019#ifdef __WXDEBUG__
1020 if(m_hQuartzDll)
1021 ::FreeLibrary(m_hQuartzDll);
1022#endif
1a680109
RN
1023}
1024
1a680109 1025//---------------------------------------------------------------------------
ff4aedc5 1026// wxAMMediaBackend::CreateControl
1a680109 1027//
920a7c15
JS
1028// 1) Check to see if Active Movie supports windowless controls
1029// 2) Connect events to the media control and its TLW
226ec5a7
WS
1030//---------------------------------------------------------------------------
1031bool wxAMMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 1032 wxWindowID id,
226ec5a7 1033 const wxPoint& pos,
ff4aedc5 1034 const wxSize& size,
226ec5a7 1035 long style,
ff4aedc5
RN
1036 const wxValidator& validator,
1037 const wxString& name)
226ec5a7 1038{
920a7c15
JS
1039#ifdef __WXDEBUG__
1040 m_hQuartzDll = ::LoadLibrary(wxT("quartz.dll"));
1041 if(m_hQuartzDll)
1042 {
1043 m_lpAMGetErrorText = (LPAMGETERRORTEXT) ::GetProcAddress(
1044 m_hQuartzDll,
1045 wxString::Format(wxT("AMGetErrorText%s"),
1a680109 1046
920a7c15
JS
1047#ifdef __WXUNICODE__
1048 wxT("W")
1049#else
1050 wxT("A")
1051#endif
1052#ifdef __WXWINCE__
1053 )
1054#else
1055 ).mb_str(wxConvLocal)
1056#endif
1057 );
1058 }
1059#endif
1060
1061 //Make sure a valid windowless video mixing interface exists
1062 IGraphBuilder* pGB;
32f65e50 1063 if( ::CoCreateInstance(CLSID_FilgraphManager, NULL,
920a7c15
JS
1064 CLSCTX_INPROC_SERVER,
1065 IID_IGraphBuilder, (void**)&pGB) != 0 )
1066 return false;
1067
1068 if( !SetWindowlessMode(pGB) )
1a680109
RN
1069 return false;
1070
920a7c15
JS
1071 //clean up
1072 pGB->Release();
ff4aedc5
RN
1073
1074 //
1075 // Create window
1076 // By default wxWindow(s) is created with a border -
1077 // so we need to get rid of those, and create with
1078 // wxCLIP_CHILDREN, so that if the driver/backend
3103e8a9 1079 // is a child window, it refreshes properly
ff4aedc5
RN
1080 //
1081 if ( !ctrl->wxControl::Create(parent, id, pos, size,
11085e4b 1082 (style & ~wxBORDER_MASK) | wxBORDER_NONE | wxCLIP_CHILDREN,
ff4aedc5
RN
1083 validator, name) )
1084 return false;
1a680109 1085
b81383bb 1086 // My problem with this was only with a previous patch, probably the third rewrite
32f65e50
WS
1087 // fixed it as a side-effect. In fact, the erase background style of drawing not
1088 // only works now, but is much better than paint-based updates (the paint event
1089 // handler flickers if the wxMediaCtrl shares a sizer with another child window,
b81383bb
JS
1090 // or is on a notebook)
1091 // - Greg Hazel
32f65e50 1092 ctrl->Connect(ctrl->GetId(), wxEVT_ERASE_BACKGROUND,
b81383bb 1093 wxEraseEventHandler(wxAMMediaEvtHandler::OnEraseBackground),
920a7c15 1094 NULL, (wxEvtHandler*) this);
32f65e50 1095
920a7c15
JS
1096 //
1097 // done...
1098 //
a3c1ce50 1099 m_ctrl = ctrl;
1a680109
RN
1100 return true;
1101}
1102
ff4aedc5 1103//---------------------------------------------------------------------------
920a7c15 1104// wxAMMediaBackend::SetWindowlessMode
ff4aedc5 1105//
920a7c15
JS
1106// Adds a Video Mixing Renderer to a Filter Graph and obtains the
1107// windowless control from it
226ec5a7 1108//---------------------------------------------------------------------------
32f65e50 1109bool wxAMMediaBackend::SetWindowlessMode(IGraphBuilder* pGB,
920a7c15 1110 IVMRWindowlessControl** ppVMC)
1a680109 1111{
a3c1ce50
JS
1112 HRESULT hr;
1113
920a7c15
JS
1114 //
1115 // Create and add a custom Video Mixing Render to the graph
1116 //
1117 IBaseFilter* pVMR;
32f65e50 1118 if( ::CoCreateInstance(CLSID_VideoMixingRenderer, NULL,
a3c1ce50 1119 CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void**)&pVMR) != 0 )
1a680109
RN
1120 return false;
1121
a3c1ce50 1122 hr = pGB->AddFilter(pVMR, L"Video Mixing Renderer");
32f65e50 1123 if ( hr != 0)
920a7c15 1124 {
a3c1ce50 1125 wxAMLOG(hr);
920a7c15
JS
1126 pVMR->Release();
1127 return false;
1128 }
ff4aedc5
RN
1129
1130 //
920a7c15 1131 // Set the graph to windowless mode
ff4aedc5 1132 //
32f65e50 1133 IVMRFilterConfig* pConfig;
a3c1ce50 1134 hr = pVMR->QueryInterface(IID_IVMRFilterConfig, (void**)&pConfig);
32f65e50 1135 if( hr != 0 )
920a7c15 1136 {
a3c1ce50 1137 wxAMLOG(hr);
920a7c15
JS
1138 pVMR->Release();
1139 return false;
1140 }
ff4aedc5 1141
a3c1ce50
JS
1142 hr = pConfig->SetRenderingMode(2);
1143 if( hr != 0) //2 == VMRMode_Windowless
920a7c15 1144 {
a3c1ce50 1145 wxAMLOG(hr);
32f65e50 1146 pConfig->Release();
920a7c15
JS
1147 pVMR->Release();
1148 return false;
1149 }
ff4aedc5 1150
32f65e50 1151 pConfig->Release();
ff4aedc5
RN
1152
1153 //
920a7c15 1154 // Obtain the windowless control
ff4aedc5 1155 //
920a7c15 1156 IVMRWindowlessControl* pVMC;
a3c1ce50
JS
1157 hr = pVMR->QueryInterface(IID_IVMRWindowlessControl, (void**)&pVMC);
1158 if( hr != 0 )
1a680109 1159 {
a3c1ce50 1160 wxAMLOG(hr);
32f65e50 1161 pVMR->Release();
920a7c15 1162 return false;
1a680109
RN
1163 }
1164
ff4aedc5 1165 //
920a7c15 1166 // Success
226ec5a7 1167 //
920a7c15
JS
1168 if(ppVMC)
1169 *ppVMC = pVMC;
1170 else
1171 pVMC->Release();
ff4aedc5 1172
32f65e50
WS
1173 pVMR->Release();
1174 return true;
920a7c15 1175}
1a680109 1176
920a7c15
JS
1177//---------------------------------------------------------------------------
1178// wxAMMediaBackend::Load (file version)
1179//
1180// 1) Cleans up previously loaded data
1181// 2) Creates a filter graph
1182// 3) Add a video mixer, set the graph to windowless mode and clip
1183// output to our media control
1184// 4) Query interfaces to use later
1185// 5) Get native video size (which becomes our best size)
1186// 6) Refresh parent's sizers
1187// 7) Start event/rendering thread
1188//---------------------------------------------------------------------------
1189bool wxAMMediaBackend::Load(const wxString& fileName)
1190{
a3c1ce50
JS
1191 HRESULT hr;
1192
920a7c15
JS
1193 //if previously loaded cleanup
1194 if(m_pVMC)
1195 Cleanup();
1196
1197 //Create interfaces - we already checked for success in CreateControl
a3c1ce50 1198 ::CoCreateInstance(CLSID_FilgraphManager, NULL, CLSCTX_INPROC_SERVER,
920a7c15
JS
1199 IID_IGraphBuilder, (void**)&m_pGB);
1200
1201
1202 // Set and clip output
1203 SetWindowlessMode(m_pGB, &m_pVMC);
a3c1ce50
JS
1204 hr = m_pVMC->SetVideoClippingWindow((HWND)m_ctrl->GetHandle());
1205
1206 if(hr != 0)
920a7c15
JS
1207 {
1208 m_bestSize.x = m_bestSize.y = 0;
a3c1ce50
JS
1209 wxAMFAIL(hr);
1210 return false;
ff4aedc5 1211 }
226ec5a7 1212
920a7c15
JS
1213 //load the graph & render
1214 if( m_pGB->RenderFile(fileName.wc_str(wxConvLocal), NULL) != 0 )
1215 return false;
1a680109 1216
a3c1ce50 1217 //
920a7c15 1218 //Get the interfaces, all of them
a3c1ce50
JS
1219 //
1220 hr = m_pGB->QueryInterface(IID_IMediaEvent, (void**)&m_pME);
1221 if(FAILED(hr))
1222 {
1223 wxAMLOG(hr);
1224 return false;
1225 }
1226
1227 hr = m_pGB->QueryInterface(IID_IMediaControl, (void**)&m_pMC);
1228 if(FAILED(hr))
1229 {
1230 wxAMLOG(hr);
1231 return false;
1232 }
1233
1234 hr = m_pGB->QueryInterface(IID_IMediaPosition, (void**)&m_pMS);
1235 if(FAILED(hr))
1236 {
1237 wxAMLOG(hr);
1238 return false;
1239 }
1240
1241 hr = m_pGB->QueryInterface(IID_IBasicAudio, (void**)&m_pBA);
1242 if(FAILED(hr))
1243 {
1244 wxAMLOG(hr);
1245 //not critical
1246 }
1a680109 1247
a3c1ce50 1248 //
920a7c15 1249 // Get original video size
a3c1ce50 1250 //
32f65e50 1251 hr = m_pVMC->GetNativeVideoSize((LONG*)&m_bestSize.x, (LONG*)&m_bestSize.y,
a3c1ce50
JS
1252 NULL, NULL);
1253 if(hr != 0)
920a7c15
JS
1254 {
1255 m_bestSize.x = m_bestSize.y = 0;
a3c1ce50
JS
1256 wxAMFAIL(hr);
1257 return false;
920a7c15 1258 }
3f9a3bf9 1259
96339a78
JS
1260 if(m_bestSize.x == 0 && m_bestSize.y == 0)
1261 m_bVideo = false;
1262 else
1263 m_bVideo = true;
1264
ff4aedc5
RN
1265 //
1266 // Force the parent window of this control to recalculate
1267 // the size of this if sizers are being used
1268 // and render the results immediately
1269 //
3f9a3bf9
RN
1270 m_ctrl->InvalidateBestSize();
1271 m_ctrl->GetParent()->Layout();
1a680109
RN
1272 m_ctrl->GetParent()->Refresh();
1273 m_ctrl->GetParent()->Update();
b11eba7e 1274 m_ctrl->SetSize(m_ctrl->GetSize());
1a680109 1275
a3c1ce50
JS
1276 //
1277 // Create the event thread
1278 //
920a7c15
JS
1279 m_pThread = new wxAMMediaThread;
1280 m_pThread->pThis = this;
1281 m_pThread->Create();
1282 m_pThread->Run();
1283
a3c1ce50
JS
1284 //
1285 // done
1286 //
1a680109
RN
1287 return true;
1288}
1289
ff4aedc5
RN
1290//---------------------------------------------------------------------------
1291// wxAMMediaBackend::Load (URL Version)
1292//
1293// Loads media from a URL. Interestingly enough DirectShow
1294// appears (?) to escape the URL for us, at least on normal
1295// files
226ec5a7 1296//---------------------------------------------------------------------------
ff4aedc5 1297bool wxAMMediaBackend::Load(const wxURI& location)
1a680109
RN
1298{
1299 return Load(location.BuildUnescapedURI());
1300}
1301
a3c1ce50
JS
1302//---------------------------------------------------------------------------
1303// wxAMMediaBackend::Cleanup
1304//
1305// Releases all the directshow interfaces we use
1306// TODO: Maybe only create one instance of IAMMultiMediaStream and reuse it
1307// rather than recreating it each time?
1308//---------------------------------------------------------------------------
1309void wxAMMediaBackend::Cleanup()
1310{
1311 // RN: This could be a bad ptr if load failed after
1312 // m_pVMC was created
1313 if(m_pThread)
1314 {
1315 m_pThread->Delete();
1316 m_pThread = NULL;
1317 }
1318
1319 // Release and zero DirectShow interfaces
1320 SAFE_RELEASE(m_pMC);
1321 SAFE_RELEASE(m_pME);
1322 SAFE_RELEASE(m_pMS);
1323 SAFE_RELEASE(m_pBA);
1324 SAFE_RELEASE(m_pGB);
1325 SAFE_RELEASE(m_pVMC);
1326}
1327
1328
ff4aedc5
RN
1329//---------------------------------------------------------------------------
1330// wxAMMediaBackend::Play
1331//
920a7c15
JS
1332// Plays the stream. If it is non-seekable, it will restart it (implicit).
1333//
1334// Note that we use SUCCEEDED here because run/pause/stop tend to be overly
1335// picky and return warnings on pretty much every call
226ec5a7 1336//---------------------------------------------------------------------------
ff4aedc5 1337bool wxAMMediaBackend::Play()
1a680109 1338{
920a7c15
JS
1339 wxCriticalSectionLocker lock(m_rendercs);
1340
1341 if( SUCCEEDED(m_pMC->Run()) )
1342 {
1343 m_state = wxMEDIASTATE_PLAYING;
1344 m_ctrl->Refresh(); //videoless control finicky about refreshing
1345 return true;
1346 }
1347
1348 return false;
1a680109
RN
1349}
1350
ff4aedc5
RN
1351//---------------------------------------------------------------------------
1352// wxAMMediaBackend::Pause
1353//
1354// Pauses the stream.
226ec5a7 1355//---------------------------------------------------------------------------
ff4aedc5 1356bool wxAMMediaBackend::Pause()
1a680109 1357{
920a7c15
JS
1358 wxCriticalSectionLocker lock(m_rendercs);
1359
1360 if( SUCCEEDED(m_pMC->Pause()) )
1361 {
1362 m_state = wxMEDIASTATE_PAUSED;
1363 return true;
1364 }
1365
1366 return false;
1a680109
RN
1367}
1368
ff4aedc5
RN
1369//---------------------------------------------------------------------------
1370// wxAMMediaBackend::Stop
1371//
1372// Stops the stream.
226ec5a7 1373//---------------------------------------------------------------------------
ff4aedc5 1374bool wxAMMediaBackend::Stop()
1a680109 1375{
920a7c15 1376 wxCriticalSectionLocker lock(m_rendercs);
e4b12a53 1377
920a7c15
JS
1378 if( SUCCEEDED(m_pMC->Stop()) )
1379 {
e4b12a53
RN
1380 //We don't care if it can't get to the beginning in directshow -
1381 //it could be a non-seeking filter (wince midi) in which case playing
1382 //starts all over again
920a7c15
JS
1383 wxAMMediaBackend::SetPosition(0);
1384
1385 m_state = wxMEDIASTATE_STOPPED;
1386 return true;
1387 }
1388
1389 return false;
1a680109
RN
1390}
1391
ff4aedc5
RN
1392//---------------------------------------------------------------------------
1393// wxAMMediaBackend::SetPosition
1394//
226ec5a7 1395// 1) Translates the current position's time to directshow time,
a2a444e3 1396// which is in a scale of 1 second (in a double)
ff4aedc5
RN
1397// 2) Sets the play position of the IMediaSeeking interface -
1398// passing NULL as the stop position means to keep the old
1399// stop position
226ec5a7 1400//---------------------------------------------------------------------------
ff4aedc5 1401bool wxAMMediaBackend::SetPosition(wxLongLong where)
1a680109 1402{
a3c1ce50 1403 HRESULT hr = m_pMS->put_CurrentPosition(
920a7c15 1404 ((LONGLONG)where.GetValue()) / 1000.0
a3c1ce50
JS
1405 );
1406 if(FAILED(hr))
1407 {
1408 wxAMLOG(hr);
1409 return false;
1410 }
1411
1412 return true;
1a680109
RN
1413}
1414
ff4aedc5
RN
1415//---------------------------------------------------------------------------
1416// wxAMMediaBackend::GetPosition
1417//
1418// 1) Obtains the current play and stop positions from IMediaSeeking
1419// 2) Returns the play position translated to our time base
226ec5a7 1420//---------------------------------------------------------------------------
ff4aedc5 1421wxLongLong wxAMMediaBackend::GetPosition()
1a680109 1422{
a2a444e3 1423 double outCur;
a3c1ce50
JS
1424 HRESULT hr = m_pMS->get_CurrentPosition(&outCur);
1425 if(FAILED(hr))
1426 {
1427 wxAMLOG(hr);
1428 return 0;
1429 }
1a680109 1430
a2a444e3 1431 //h,m,s,milli - outdur is in 1 second (double)
600ffb32
WS
1432 outCur *= 1000;
1433 wxLongLong ll;
1434 ll.Assign(outCur);
1435
1436 return ll;
1a680109
RN
1437}
1438
6f8c67e7 1439//---------------------------------------------------------------------------
a3c1ce50 1440// wxAMMediaBackend::GetVolume
6f8c67e7 1441//
a3c1ce50 1442// Gets the volume through the IBasicAudio interface -
6f8c67e7
JS
1443// value ranges from 0 (MAX volume) to -10000 (minimum volume).
1444// -100 per decibel.
1445//---------------------------------------------------------------------------
a3c1ce50 1446double wxAMMediaBackend::GetVolume()
b11eba7e 1447{
a3c1ce50
JS
1448 if(m_pBA)
1449 {
1450 long lVolume;
1451 HRESULT hr = m_pBA->get_Volume(&lVolume);
1452 if(FAILED(hr))
1453 {
1454 wxAMLOG(hr);
1455 return 0.0;
1456 }
1457
1458 return (((double)(lVolume + 10000)) / 10000.0);
1459 }
1460
1461 wxLogDebug(wxT("No directshow audio interface"));
1462 return 0.0;
b11eba7e 1463}
6f8c67e7
JS
1464
1465//---------------------------------------------------------------------------
a3c1ce50 1466// wxAMMediaBackend::SetVolume
6f8c67e7 1467//
a3c1ce50 1468// Sets the volume through the IBasicAudio interface -
6f8c67e7
JS
1469// value ranges from 0 (MAX volume) to -10000 (minimum volume).
1470// -100 per decibel.
1471//---------------------------------------------------------------------------
a3c1ce50 1472bool wxAMMediaBackend::SetVolume(double dVolume)
6f8c67e7 1473{
a3c1ce50
JS
1474 if(m_pBA)
1475 {
1476 HRESULT hr = m_pBA->put_Volume( (long) ((dVolume-1.0) * 10000.0) );
1477 if(FAILED(hr))
1478 {
1479 wxAMLOG(hr);
1480 return false;
1481 }
1482 return true;
1483 }
1484
1485 wxLogDebug(wxT("No directshow audio interface"));
1486 return false;
6f8c67e7 1487}
b11eba7e 1488
ff4aedc5
RN
1489//---------------------------------------------------------------------------
1490// wxAMMediaBackend::GetDuration
1491//
920a7c15 1492// 1) Obtains the duration of the media from IAMMultiMediaStream
ff4aedc5 1493// 2) Converts that value to our time base, and returns it
920a7c15 1494//
32f65e50 1495// NB: With VBR MP3 files the default DirectShow MP3 render does not
920a7c15
JS
1496// read the Xing header correctly, resulting in skewed values for duration
1497// and seeking
226ec5a7 1498//---------------------------------------------------------------------------
ff4aedc5 1499wxLongLong wxAMMediaBackend::GetDuration()
1a680109 1500{
a2a444e3 1501 double outDuration;
a3c1ce50
JS
1502 HRESULT hr = m_pMS->get_Duration(&outDuration);
1503 if(FAILED(hr))
1504 {
1505 wxAMLOG(hr);
1506 return 0;
1507 }
1a680109 1508
a2a444e3 1509 //h,m,s,milli - outdur is in 1 second (double)
600ffb32
WS
1510 outDuration *= 1000;
1511 wxLongLong ll;
1512 ll.Assign(outDuration);
1513
1514 return ll;
1a680109
RN
1515}
1516
ff4aedc5
RN
1517//---------------------------------------------------------------------------
1518// wxAMMediaBackend::GetState
1519//
920a7c15 1520// Returns the cached state
226ec5a7 1521//---------------------------------------------------------------------------
ff4aedc5 1522wxMediaState wxAMMediaBackend::GetState()
1a680109 1523{
920a7c15 1524 return m_state;
1a680109
RN
1525}
1526
ff4aedc5
RN
1527//---------------------------------------------------------------------------
1528// wxAMMediaBackend::GetPlaybackRate
1529//
1530// Pretty simple way of obtaining the playback rate from
1531// the IMediaSeeking interface
226ec5a7 1532//---------------------------------------------------------------------------
ff4aedc5 1533double wxAMMediaBackend::GetPlaybackRate()
1a680109
RN
1534{
1535 double dRate;
a3c1ce50
JS
1536 HRESULT hr = m_pMS->get_Rate(&dRate);
1537 if(FAILED(hr))
1538 {
1539 wxAMLOG(hr);
1540 return 0.0;
1541 }
1a680109
RN
1542 return dRate;
1543}
1544
ff4aedc5
RN
1545//---------------------------------------------------------------------------
1546// wxAMMediaBackend::SetPlaybackRate
1547//
1548// Sets the playback rate of the media - DirectShow is pretty good
1549// about this, actually
226ec5a7 1550//---------------------------------------------------------------------------
ff4aedc5 1551bool wxAMMediaBackend::SetPlaybackRate(double dRate)
1a680109 1552{
a3c1ce50
JS
1553 HRESULT hr = m_pMS->put_Rate(dRate);
1554 if(FAILED(hr))
1555 {
1556 wxAMLOG(hr);
1557 return false;
1558 }
ff4aedc5 1559
a3c1ce50 1560 return true;
920a7c15
JS
1561}
1562
920a7c15
JS
1563//---------------------------------------------------------------------------
1564// wxAMMediaBackend::GetVideoSize
1565//
1566// Obtains the cached original video size
1567//---------------------------------------------------------------------------
1568wxSize wxAMMediaBackend::GetVideoSize() const
1569{
1570 return m_bestSize;
1571}
1572
1573//---------------------------------------------------------------------------
1574// wxAMMediaBackend::Move
1575//
1576// We take care of this in our redrawing
1577//---------------------------------------------------------------------------
32f65e50 1578void wxAMMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y),
920a7c15
JS
1579 int w, int h)
1580{
a3c1ce50 1581 //don't use deferred positioning on windows
96339a78 1582 if(m_pVMC && m_bVideo)
920a7c15
JS
1583 {
1584 RECT srcRect, destRect;
32f65e50 1585
920a7c15
JS
1586 //portion of video to display in window
1587 srcRect.top = 0; srcRect.left = 0;
1588 srcRect.bottom = m_bestSize.y; srcRect.right = m_bestSize.x;
1589
b81383bb
JS
1590 //it happens.
1591 if (w < 0)
1592 {
1593 w = 0;
1594 }
1595 if (h < 0)
1596 {
1597 h = 0;
1598 }
1599
920a7c15
JS
1600 //position in window client coordinates to display and stretch to
1601 destRect.top = 0; destRect.left = 0;
1602 destRect.bottom = h; destRect.right = w;
1603
1604 //set the windowless control positions
a3c1ce50
JS
1605 HRESULT hr = m_pVMC->SetVideoPosition(&srcRect, &destRect);
1606 if(FAILED(hr))
920a7c15 1607 {
a3c1ce50 1608 wxAMLOG(hr);
920a7c15 1609 }
920a7c15
JS
1610 }
1611}
1612
920a7c15
JS
1613//---------------------------------------------------------------------------
1614// wxAMMediaThread::Entry
1615//
1616// Render the current movie frame
1617//---------------------------------------------------------------------------
1618wxThread::ExitCode wxAMMediaThread::Entry()
1a680109 1619{
920a7c15 1620 while(!TestDestroy())
1a680109 1621 {
226ec5a7
WS
1622 LONG evCode,
1623 evParam1,
ff4aedc5
RN
1624 evParam2;
1625
1626 //
1627 // DirectShow keeps a list of queued events, and we need
1628 // to go through them one by one, stopping at (Hopefully only one)
1629 // EC_COMPLETE message
1630 //
920a7c15
JS
1631 while( pThis->m_pME->GetEvent(&evCode, (LONG_PTR *) &evParam1,
1632 (LONG_PTR *) &evParam2, 0) == 0 )
1a680109 1633 {
ff4aedc5 1634 // Cleanup memory that GetEvent allocated
32f65e50 1635 HRESULT hr = pThis->m_pME->FreeEventParams(evCode,
a3c1ce50
JS
1636 evParam1, evParam2);
1637 if(hr != 0)
920a7c15 1638 {
32f65e50 1639 //Even though this makes a messagebox this
a3c1ce50
JS
1640 //is windows where we can do gui stuff in seperate
1641 //threads :)
1642 wxFAIL_MSG(pThis->GetErrorString(hr));
920a7c15 1643 }
1a680109 1644 // If this is the end of the clip, notify handler
a3c1ce50 1645 else if(1 == evCode) //EC_COMPLETE
1a680109 1646 {
920a7c15
JS
1647 pThis->OnStop();
1648 }
1649 }
1650
1651 Sleep(10);
1652 }
1653
1654 return NULL;
1655}
1656
1657
1658//---------------------------------------------------------------------------
1659// wxAMMediaBackend::OnStop
1660//
1661// Handle stopping when the stream ends
1662//---------------------------------------------------------------------------
1663void wxAMMediaBackend::OnStop()
1664{
b81383bb
JS
1665 //send the event to our child
1666 wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId());
1667 m_ctrl->ProcessEvent(theEvent);
1668
1669 //if the user didn't veto it, stop the stream
1670 if (theEvent.IsAllowed())
1671 {
1672 //Interestingly enough, DirectShow does not actually stop
1673 //the filters - even when it reaches the end!
1674 wxVERIFY( Stop() );
1675
1676 //send the event to our child
1677 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
1678 m_ctrl->GetId());
1679 m_ctrl->ProcessEvent(theEvent);
1680 }
1a680109
RN
1681}
1682
ff4aedc5 1683//---------------------------------------------------------------------------
920a7c15 1684// wxAMMediaEvtHandler::OnEraseBackground
ff4aedc5 1685//
920a7c15 1686// Tell WX not to erase the background of our control window
226ec5a7 1687//---------------------------------------------------------------------------
920a7c15 1688void wxAMMediaEvtHandler::OnEraseBackground(wxEraseEvent& evt)
1a680109 1689{
920a7c15 1690 wxAMMediaBackend* pThis = (wxAMMediaBackend*) this;
96339a78 1691 if(pThis->m_pVMC && pThis->m_bVideo)
1a680109 1692 {
920a7c15
JS
1693 //TODO: Use wxClientDC?
1694 HDC hdc = ::GetDC((HWND)pThis->m_ctrl->GetHandle());
32f65e50 1695 HRESULT hr = pThis->m_pVMC->RepaintVideo((HWND)pThis->m_ctrl->GetHandle(),
a3c1ce50
JS
1696 hdc);
1697 if(FAILED(hr))
920a7c15 1698 {
a3c1ce50 1699 wxFAIL_MSG(pThis->GetErrorString(hr));
b81383bb 1700 }
920a7c15
JS
1701 ::ReleaseDC((HWND)pThis->m_ctrl->GetHandle(), hdc);
1702 }
1703 else
b81383bb 1704 {
920a7c15 1705 evt.Skip();
b81383bb 1706 }
1a680109
RN
1707}
1708
ff4aedc5
RN
1709//---------------------------------------------------------------------------
1710// End of wxAMMediaBackend
1711//---------------------------------------------------------------------------
1a680109 1712
ff4aedc5 1713//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1a680109 1714//
ff4aedc5 1715// wxMCIMediaBackend
226ec5a7 1716//
ff4aedc5
RN
1717//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1718
ff4aedc5
RN
1719IMPLEMENT_DYNAMIC_CLASS(wxMCIMediaBackend, wxMediaBackend);
1720
1721//---------------------------------------------------------------------------
1722// Usual debugging macros for MCI returns
1a680109
RN
1723//---------------------------------------------------------------------------
1724
ff4aedc5
RN
1725#ifdef __WXDEBUG__
1726#define wxMCIVERIFY(arg) \
1727{ \
1728 DWORD nRet; \
1729 if ( (nRet = (arg)) != 0) \
1730 { \
1731 TCHAR sz[5000]; \
1732 mciGetErrorString(nRet, sz, 5000); \
1733 wxFAIL_MSG(wxString::Format(_T("MCI Error:%s"), sz)); \
1734 } \
1735}
1736#else
1737#define wxMCIVERIFY(arg) (arg);
1738#endif
1739
1740//---------------------------------------------------------------------------
1741// Simulation for <digitalv.h>
33d8e2fc 1742//
ff4aedc5 1743// Mingw and possibly other compilers don't have the digitalv.h header
226ec5a7 1744// that is needed to have some essential features of mci work with
ff4aedc5
RN
1745// windows - so we provide the declarations for the types we use here
1746//---------------------------------------------------------------------------
33d8e2fc
RN
1747
1748typedef struct {
1749 DWORD_PTR dwCallback;
1750#ifdef MCI_USE_OFFEXT
1751 POINT ptOffset;
1752 POINT ptExtent;
226ec5a7 1753#else
33d8e2fc
RN
1754 RECT rc;
1755#endif
1756} MCI_DGV_RECT_PARMS;
1757
1758typedef struct {
1759 DWORD_PTR dwCallback;
1760 HWND hWnd;
1761#ifndef _WIN32
1762 WORD wReserved1;
1763#endif
1764 UINT nCmdShow;
1765#ifndef _WIN32
1766 WORD wReserved2;
1767#endif
ff4aedc5
RN
1768 wxChar* lpstrText;
1769} MCI_DGV_WINDOW_PARMS;
33d8e2fc
RN
1770
1771typedef struct {
226ec5a7
WS
1772 DWORD_PTR dwCallback;
1773 DWORD dwTimeFormat;
1774 DWORD dwAudio;
1775 DWORD dwFileFormat;
1776 DWORD dwSpeed;
1777} MCI_DGV_SET_PARMS;
33d8e2fc 1778
6f8c67e7
JS
1779typedef struct {
1780 DWORD_PTR dwCallback;
1781 DWORD dwItem;
1782 DWORD dwValue;
1783 DWORD dwOver;
1784 wxChar* lpstrAlgorithm;
1785 wxChar* lpstrQuality;
1786} MCI_DGV_SETAUDIO_PARMS;
1787
ff4aedc5
RN
1788//---------------------------------------------------------------------------
1789// wxMCIMediaBackend Constructor
1790//
1791// Here we don't need to do much except say we don't have any video :)
1792//---------------------------------------------------------------------------
1793wxMCIMediaBackend::wxMCIMediaBackend() : m_hNotifyWnd(NULL), m_bVideo(false)
1794{
3f9a3bf9
RN
1795}
1796
ff4aedc5
RN
1797//---------------------------------------------------------------------------
1798// wxMCIMediaBackend Destructor
1799//
1800// We close the mci device - note that there may not be an mci device here,
1801// or it may fail - but we don't really care, since we're destructing
1802//---------------------------------------------------------------------------
1803wxMCIMediaBackend::~wxMCIMediaBackend()
3f9a3bf9 1804{
ff4aedc5
RN
1805 if(m_hNotifyWnd)
1806 {
1807 mciSendCommand(m_hDev, MCI_CLOSE, 0, 0);
1808 DestroyWindow(m_hNotifyWnd);
1809 m_hNotifyWnd = NULL;
1810 }
3f9a3bf9
RN
1811}
1812
ff4aedc5
RN
1813//---------------------------------------------------------------------------
1814// wxMCIMediaBackend::Create
1815//
1816// Here we just tell wxMediaCtrl that mci does exist (which it does, on all
1817// msw systems, at least in some form dating back to win16 days)
1818//---------------------------------------------------------------------------
226ec5a7 1819bool wxMCIMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 1820 wxWindowID id,
226ec5a7 1821 const wxPoint& pos,
ff4aedc5 1822 const wxSize& size,
226ec5a7 1823 long style,
ff4aedc5
RN
1824 const wxValidator& validator,
1825 const wxString& name)
72259e00 1826{
ff4aedc5
RN
1827 //
1828 // Create window
1829 // By default wxWindow(s) is created with a border -
1830 // so we need to get rid of those, and create with
1831 // wxCLIP_CHILDREN, so that if the driver/backend
1832 // is a child window, it refereshes properly
1833 //
1834 if ( !ctrl->wxControl::Create(parent, id, pos, size,
11085e4b 1835 (style & ~wxBORDER_MASK) | wxBORDER_NONE | wxCLIP_CHILDREN,
ff4aedc5
RN
1836 validator, name) )
1837 return false;
1838
3f9a3bf9
RN
1839 m_ctrl = ctrl;
1840 return true;
1841}
1842
ff4aedc5
RN
1843//---------------------------------------------------------------------------
1844// wxMCIMediaBackend::Load (file version)
1845//
1846// Here we have MCI load a file and device, set the time format to our
1847// default (milliseconds), and set the video (if any) to play in the control
1848//---------------------------------------------------------------------------
1849bool wxMCIMediaBackend::Load(const wxString& fileName)
3f9a3bf9 1850{
ff4aedc5
RN
1851 //
1852 //if the user already called load close the previous MCI device
1853 //
1854 if(m_hNotifyWnd)
1855 {
3f9a3bf9 1856 mciSendCommand(m_hDev, MCI_CLOSE, 0, 0);
ff4aedc5
RN
1857 DestroyWindow(m_hNotifyWnd);
1858 m_hNotifyWnd = NULL;
1859 }
3f9a3bf9 1860
ff4aedc5
RN
1861 //
1862 //Opens a file and has MCI select a device. Normally you'd put
1863 //MCI_OPEN_TYPE in addition to MCI_OPEN_ELEMENT - however if you
226ec5a7 1864 //omit this it tells MCI to select the device instead. This is
ff4aedc5
RN
1865 //good because we have no reliable way of "enumerating" the devices
1866 //in MCI
1867 //
3f9a3bf9 1868 MCI_OPEN_PARMS openParms;
3f9a3bf9
RN
1869 openParms.lpstrElementName = (wxChar*) fileName.c_str();
1870
226ec5a7 1871 if ( mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT,
ff4aedc5
RN
1872 (DWORD)(LPVOID)&openParms) != 0)
1873 return false;
3f9a3bf9
RN
1874
1875 m_hDev = openParms.wDeviceID;
1876
ff4aedc5
RN
1877 //
1878 //Now set the time format for the device to milliseconds
1879 //
1880 MCI_SET_PARMS setParms;
3f9a3bf9
RN
1881 setParms.dwCallback = 0;
1882 setParms.dwTimeFormat = MCI_FORMAT_MILLISECONDS;
1883
1884 if (mciSendCommand(m_hDev, MCI_SET, MCI_SET_TIME_FORMAT,
1885 (DWORD)(LPVOID)&setParms) != 0)
1886 return false;
1887
ff4aedc5
RN
1888 //
1889 //Now tell the MCI device to display the video in our wxMediaCtrl
1890 //
3f9a3bf9 1891 MCI_DGV_WINDOW_PARMS windowParms;
5987f174 1892 windowParms.hWnd = (HWND)m_ctrl->GetHandle();
3f9a3bf9 1893
226ec5a7 1894 m_bVideo = (mciSendCommand(m_hDev, MCI_WINDOW,
ff4aedc5
RN
1895 0x00010000L, //MCI_DGV_WINDOW_HWND
1896 (DWORD)(LPVOID)&windowParms) == 0);
1897
1898 //
1899 // Create a hidden window and register to handle
1900 // MCI events
226ec5a7 1901 // Note that wxCanvasClassName is already registered
ff4aedc5 1902 // and used by all wxWindows and normal wxControls
226ec5a7 1903 //
ff4aedc5
RN
1904 m_hNotifyWnd = ::CreateWindow
1905 (
1906 wxCanvasClassName,
1907 NULL,
1908 0, 0, 0, 0,
1909 0,
1910 (HWND) NULL,
1911 (HMENU)NULL,
1912 wxGetInstance(),
1913 (LPVOID) NULL
1914 );
1915
1916 if(!m_hNotifyWnd)
1917 {
1918 wxLogSysError( wxT("Could not create hidden needed for ")
1919 wxT("registering for DirectShow events!") );
1920
1921 return false;
1922 }
226ec5a7 1923
1146983c 1924 wxSetWindowProc(m_hNotifyWnd, wxMCIMediaBackend::NotifyWndProc);
ff4aedc5
RN
1925
1926 ::SetWindowLong(m_hNotifyWnd, GWL_USERDATA,
1927 (LONG) this);
1928
1929 //
1930 //Here, if the parent of the control has a sizer - we
1931 //tell it to recalculate the size of this control since
3103e8a9 1932 //the user opened a separate media file
ff4aedc5 1933 //
5987f174
RN
1934 m_ctrl->InvalidateBestSize();
1935 m_ctrl->GetParent()->Layout();
1936 m_ctrl->GetParent()->Refresh();
1937 m_ctrl->GetParent()->Update();
b11eba7e 1938 m_ctrl->SetSize(m_ctrl->GetSize());
72259e00 1939
3f9a3bf9
RN
1940 return true;
1941}
1942
ff4aedc5
RN
1943//---------------------------------------------------------------------------
1944// wxMCIMediaBackend::Load (URL version)
1945//
1946// MCI doesn't support URLs directly (?)
1947//
1948// TODO: Use wxURL/wxFileSystem and mmioInstallProc
1949//---------------------------------------------------------------------------
1950bool wxMCIMediaBackend::Load(const wxURI& WXUNUSED(location))
3f9a3bf9
RN
1951{
1952 return false;
1953}
1954
ff4aedc5
RN
1955//---------------------------------------------------------------------------
1956// wxMCIMediaBackend::Play
1957//
1958// Plays/Resumes the MCI device... a couple notes:
1959// 1) Certain drivers will crash and burn if we don't pass them an
1960// MCI_PLAY_PARMS, despite the documentation that says otherwise...
1961// 2) There is a MCI_RESUME command, but MCI_PLAY does the same thing
226ec5a7 1962// and will resume from a stopped state also, so there's no need to
ff4aedc5
RN
1963// call both, for example
1964//---------------------------------------------------------------------------
1965bool wxMCIMediaBackend::Play()
5987f174 1966{
5987f174 1967 MCI_PLAY_PARMS playParms;
ff4aedc5
RN
1968 playParms.dwCallback = (DWORD)m_hNotifyWnd;
1969
11219c9e 1970 bool bOK = ( mciSendCommand(m_hDev, MCI_PLAY, MCI_NOTIFY,
ff4aedc5 1971 (DWORD)(LPVOID)&playParms) == 0 );
11219c9e
RN
1972
1973 if(bOK)
1974 m_ctrl->Show(m_bVideo);
1975
1976 return bOK;
5987f174
RN
1977}
1978
ff4aedc5
RN
1979//---------------------------------------------------------------------------
1980// wxMCIMediaBackend::Pause
1981//
1982// Pauses the MCI device - nothing special
226ec5a7 1983//---------------------------------------------------------------------------
ff4aedc5 1984bool wxMCIMediaBackend::Pause()
5987f174
RN
1985{
1986 return (mciSendCommand(m_hDev, MCI_PAUSE, MCI_WAIT, 0) == 0);
1987}
1988
ff4aedc5
RN
1989//---------------------------------------------------------------------------
1990// wxMCIMediaBackend::Stop
1991//
1992// Stops the MCI device & seeks to the beginning as wxMediaCtrl docs outline
226ec5a7 1993//---------------------------------------------------------------------------
ff4aedc5 1994bool wxMCIMediaBackend::Stop()
5987f174
RN
1995{
1996 return (mciSendCommand(m_hDev, MCI_STOP, MCI_WAIT, 0) == 0) &&
1997 (mciSendCommand(m_hDev, MCI_SEEK, MCI_SEEK_TO_START, 0) == 0);
1998}
1999
ff4aedc5
RN
2000//---------------------------------------------------------------------------
2001// wxMCIMediaBackend::GetState
2002//
2003// Here we get the state and convert it to a wxMediaState -
2004// since we use direct comparisons with MCI_MODE_PLAY and
2005// MCI_MODE_PAUSE, we don't care if the MCI_STATUS call
2006// fails or not
226ec5a7 2007//---------------------------------------------------------------------------
ff4aedc5 2008wxMediaState wxMCIMediaBackend::GetState()
3f9a3bf9
RN
2009{
2010 MCI_STATUS_PARMS statusParms;
2011 statusParms.dwItem = MCI_STATUS_MODE;
ff4aedc5 2012
3f9a3bf9
RN
2013 mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
2014 (DWORD)(LPVOID)&statusParms);
2015
2016 if(statusParms.dwReturn == MCI_MODE_PAUSE)
2017 return wxMEDIASTATE_PAUSED;
2018 else if(statusParms.dwReturn == MCI_MODE_PLAY)
2019 return wxMEDIASTATE_PLAYING;
2020 else
2021 return wxMEDIASTATE_STOPPED;
2022}
2023
ff4aedc5
RN
2024//---------------------------------------------------------------------------
2025// wxMCIMediaBackend::SetPosition
2026//
2027// Here we set the position of the device in the stream.
226ec5a7 2028// Note that MCI actually stops the device after you seek it if the
ff4aedc5 2029// device is playing/paused, so we need to play the file after
226ec5a7
WS
2030// MCI seeks like normal APIs would
2031//---------------------------------------------------------------------------
ff4aedc5 2032bool wxMCIMediaBackend::SetPosition(wxLongLong where)
3f9a3bf9
RN
2033{
2034 MCI_SEEK_PARMS seekParms;
2035 seekParms.dwCallback = 0;
e70fda0e 2036#if wxUSE_LONGLONG_NATIVE && !wxUSE_LONGLONG_WX
226ec5a7 2037 seekParms.dwTo = (DWORD)where.GetValue();
e70fda0e
WS
2038#else /* wxUSE_LONGLONG_WX */
2039 /* no way to return it in one piece */
2040 wxASSERT( where.GetHi()==0 );
2041 seekParms.dwTo = (DWORD)where.GetLo();
2042#endif /* wxUSE_LONGLONG_* */
3f9a3bf9 2043
ff4aedc5 2044 //device was playing?
3f9a3bf9
RN
2045 bool bReplay = GetState() == wxMEDIASTATE_PLAYING;
2046
226ec5a7 2047 if( mciSendCommand(m_hDev, MCI_SEEK, MCI_TO,
ff4aedc5 2048 (DWORD)(LPVOID)&seekParms) != 0)
3f9a3bf9 2049 return false;
3f9a3bf9 2050
ff4aedc5 2051 //If the device was playing, resume it
3f9a3bf9
RN
2052 if (bReplay)
2053 return Play();
2054 else
2055 return true;
2056}
2057
ff4aedc5
RN
2058//---------------------------------------------------------------------------
2059// wxMCIMediaBackend::GetPosition
2060//
2061// Gets the position of the device in the stream using the current
2062// time format... nothing special here...
226ec5a7 2063//---------------------------------------------------------------------------
ff4aedc5 2064wxLongLong wxMCIMediaBackend::GetPosition()
3f9a3bf9
RN
2065{
2066 MCI_STATUS_PARMS statusParms;
72259e00 2067 statusParms.dwItem = MCI_STATUS_POSITION;
ff4aedc5 2068
72259e00 2069 if (mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
ff4aedc5 2070 (DWORD)(LPSTR)&statusParms) != 0)
3f9a3bf9
RN
2071 return 0;
2072
2073 return statusParms.dwReturn;
2074}
2075
6f8c67e7
JS
2076//---------------------------------------------------------------------------
2077// wxMCIMediaBackend::GetVolume
2078//
2079// Gets the volume of the current media via the MCI_DGV_STATUS_VOLUME
2080// message. Value ranges from 0 (minimum) to 1000 (maximum volume).
2081//---------------------------------------------------------------------------
2082double wxMCIMediaBackend::GetVolume()
2083{
2084 MCI_STATUS_PARMS statusParms;
600ffb32 2085 statusParms.dwCallback = 0;
6f8c67e7
JS
2086 statusParms.dwItem = 0x4019; //MCI_DGV_STATUS_VOLUME
2087
2088 if (mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
2089 (DWORD)(LPSTR)&statusParms) != 0)
2090 return 0;
2091
2092 return ((double)statusParms.dwReturn) / 1000.0;
2093}
2094
2095//---------------------------------------------------------------------------
2096// wxMCIMediaBackend::SetVolume
2097//
2098// Sets the volume of the current media via the MCI_DGV_SETAUDIO_VOLUME
2099// message. Value ranges from 0 (minimum) to 1000 (maximum volume).
2100//---------------------------------------------------------------------------
2101bool wxMCIMediaBackend::SetVolume(double dVolume)
2102{
2103 MCI_DGV_SETAUDIO_PARMS audioParms;
600ffb32 2104 audioParms.dwCallback = 0;
6f8c67e7
JS
2105 audioParms.dwItem = 0x4002; //MCI_DGV_SETAUDIO_VOLUME
2106 audioParms.dwValue = (DWORD) (dVolume * 1000.0);
2107 audioParms.dwOver = 0;
2108 audioParms.lpstrAlgorithm = NULL;
2109 audioParms.lpstrQuality = NULL;
2110
b11eba7e 2111 if (mciSendCommand(m_hDev, 0x0873, //MCI_SETAUDIO
6f8c67e7
JS
2112 0x00800000L | 0x01000000L, //MCI_DGV_SETAUDIO+(_ITEM | _VALUE)
2113 (DWORD)(LPSTR)&audioParms) != 0)
2114 return false;
2115 return true;
2116}
2117
ff4aedc5
RN
2118//---------------------------------------------------------------------------
2119// wxMCIMediaBackend::GetDuration
2120//
2121// Gets the duration of the stream... nothing special
226ec5a7 2122//---------------------------------------------------------------------------
ff4aedc5 2123wxLongLong wxMCIMediaBackend::GetDuration()
3f9a3bf9
RN
2124{
2125 MCI_STATUS_PARMS statusParms;
72259e00 2126 statusParms.dwItem = MCI_STATUS_LENGTH;
ff4aedc5 2127
72259e00 2128 if (mciSendCommand(m_hDev, MCI_STATUS, MCI_STATUS_ITEM,
ff4aedc5 2129 (DWORD)(LPSTR)&statusParms) != 0)
3f9a3bf9
RN
2130 return 0;
2131
2132 return statusParms.dwReturn;
2133}
2134
ff4aedc5
RN
2135//---------------------------------------------------------------------------
2136// wxMCIMediaBackend::Move
2137//
2138// Moves the window to a location
226ec5a7
WS
2139//---------------------------------------------------------------------------
2140void wxMCIMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y),
ff4aedc5 2141 int w, int h)
3f9a3bf9 2142{
ff4aedc5
RN
2143 if (m_hNotifyWnd && m_bVideo)
2144 {
2145 MCI_DGV_RECT_PARMS putParms; //ifdefed MCI_DGV_PUT_PARMS
b11eba7e 2146 memset(&putParms, 0, sizeof(MCI_DGV_RECT_PARMS));
ff4aedc5 2147 putParms.rc.bottom = h;
b11eba7e 2148 putParms.rc.right = w;
7c4a4505 2149
b11eba7e
WS
2150 //wxStackWalker will crash and burn here on assert
2151 //and mci doesn't like 0 and 0 for some reason (out of range )
2152 //so just don't it in that case
2153 if(w || h)
2154 {
7c4a4505 2155 wxMCIVERIFY( mciSendCommand(m_hDev, MCI_PUT,
ff4aedc5
RN
2156 0x00040000L, //MCI_DGV_PUT_DESTINATION
2157 (DWORD)(LPSTR)&putParms) );
7c4a4505 2158 }
ff4aedc5 2159 }
3f9a3bf9
RN
2160}
2161
ff4aedc5
RN
2162//---------------------------------------------------------------------------
2163// wxMCIMediaBackend::GetVideoSize
2164//
2165// Gets the original size of the movie for sizers
226ec5a7 2166//---------------------------------------------------------------------------
ff4aedc5 2167wxSize wxMCIMediaBackend::GetVideoSize() const
3f9a3bf9
RN
2168{
2169 if(m_bVideo)
2170 {
ff4aedc5 2171 MCI_DGV_RECT_PARMS whereParms; //ifdefed MCI_DGV_WHERE_PARMS
3f9a3bf9 2172
226ec5a7 2173 wxMCIVERIFY( mciSendCommand(m_hDev, MCI_WHERE,
ff4aedc5
RN
2174 0x00020000L, //MCI_DGV_WHERE_SOURCE
2175 (DWORD)(LPSTR)&whereParms) );
226ec5a7 2176
ff4aedc5 2177 return wxSize(whereParms.rc.right, whereParms.rc.bottom);
3f9a3bf9 2178 }
c47addef 2179 return wxSize(0,0);
3f9a3bf9
RN
2180}
2181
ff4aedc5
RN
2182//---------------------------------------------------------------------------
2183// wxMCIMediaBackend::GetPlaybackRate
2184//
2185// TODO
226ec5a7 2186//---------------------------------------------------------------------------
ff4aedc5 2187double wxMCIMediaBackend::GetPlaybackRate()
3f9a3bf9
RN
2188{
2189 return 1.0;
2190}
2191
ff4aedc5
RN
2192//---------------------------------------------------------------------------
2193// wxMCIMediaBackend::SetPlaybackRate
2194//
2195// TODO
226ec5a7 2196//---------------------------------------------------------------------------
ff4aedc5 2197bool wxMCIMediaBackend::SetPlaybackRate(double WXUNUSED(dRate))
3f9a3bf9 2198{
ff4aedc5
RN
2199/*
2200 MCI_WAVE_SET_SAMPLESPERSEC
2201 MCI_DGV_SET_PARMS setParms;
2202 setParms.dwSpeed = (DWORD) (dRate * 1000.0);
2203
226ec5a7 2204 return (mciSendCommand(m_hDev, MCI_SET,
ff4aedc5
RN
2205 0x00020000L, //MCI_DGV_SET_SPEED
2206 (DWORD)(LPSTR)&setParms) == 0);
2207*/
3f9a3bf9
RN
2208 return false;
2209}
2210
ff4aedc5
RN
2211//---------------------------------------------------------------------------
2212// [static] wxMCIMediaBackend::MSWWindowProc
2213//
226ec5a7 2214// Here we process a message when MCI reaches the stopping point
ff4aedc5 2215// in the stream
226ec5a7
WS
2216//---------------------------------------------------------------------------
2217LRESULT CALLBACK wxMCIMediaBackend::NotifyWndProc(HWND hWnd, UINT nMsg,
2218 WPARAM wParam,
ff4aedc5
RN
2219 LPARAM lParam)
2220{
2221 wxMCIMediaBackend* backend = (wxMCIMediaBackend*)
106d80ad 2222#ifdef _WIN32
ff4aedc5 2223 ::GetWindowLong(hWnd, GWL_USERDATA);
106d80ad
JS
2224#else
2225 ::GetWindowLongPtr(hWnd, GWLP_USERDATA);
b11eba7e 2226#endif
ff4aedc5
RN
2227 wxASSERT(backend);
2228
2229 return backend->OnNotifyWndProc(hWnd, nMsg, wParam, lParam);
2230}
2231
226ec5a7
WS
2232LRESULT CALLBACK wxMCIMediaBackend::OnNotifyWndProc(HWND hWnd, UINT nMsg,
2233 WPARAM wParam,
ff4aedc5 2234 LPARAM lParam)
3f9a3bf9 2235{
5987f174
RN
2236 if(nMsg == MM_MCINOTIFY)
2237 {
ff4aedc5
RN
2238 wxASSERT(lParam == (LPARAM) m_hDev);
2239 if(wParam == MCI_NOTIFY_SUCCESSFUL && lParam == (LPARAM)m_hDev)
5987f174 2240 {
ff4aedc5
RN
2241 wxMediaEvent theEvent(wxEVT_MEDIA_STOP, m_ctrl->GetId());
2242 m_ctrl->ProcessEvent(theEvent);
2243
2244 if(theEvent.IsAllowed())
2245 {
226ec5a7 2246 wxMCIVERIFY( mciSendCommand(m_hDev, MCI_SEEK,
ff4aedc5 2247 MCI_SEEK_TO_START, 0) );
3f9a3bf9 2248
ff4aedc5 2249 //send the event to our child
226ec5a7 2250 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
ff4aedc5
RN
2251 m_ctrl->GetId());
2252 m_ctrl->ProcessEvent(theEvent);
2253 }
5987f174 2254 }
5987f174 2255 }
ff4aedc5 2256 return DefWindowProc(hWnd, nMsg, wParam, lParam);
3f9a3bf9 2257}
ff4aedc5
RN
2258//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2259//
2260// wxQTMediaBackend
226ec5a7 2261//
ff4aedc5
RN
2262// TODO: Use a less cludgy way to pause/get state/set state
2263// TODO: Dynamically load from qtml.dll
2264//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2265
ff4aedc5
RN
2266IMPLEMENT_DYNAMIC_CLASS(wxQTMediaBackend, wxMediaBackend);
2267
2268//Time between timer calls
2269#define MOVIE_DELAY 100
2270
2271#include "wx/timer.h"
2272
2273// --------------------------------------------------------------------------
2274// wxQTTimer - Handle Asyncronous Playing
2275// --------------------------------------------------------------------------
2276class _wxQTTimer : public wxTimer
2277{
2278public:
d7a9c895
RN
2279 _wxQTTimer(Movie movie, wxQTMediaBackend* parent, wxQuickTimeLibrary* pLib) :
2280 m_movie(movie), m_bPaused(false), m_parent(parent), m_pLib(pLib)
ff4aedc5
RN
2281 {
2282 }
2283
2284 ~_wxQTTimer()
2285 {
2286 }
2287
2288 bool GetPaused() {return m_bPaused;}
2289 void SetPaused(bool bPaused) {m_bPaused = bPaused;}
2290
2291 //-----------------------------------------------------------------------
2292 // _wxQTTimer::Notify
2293 //
2294 // 1) Checks to see if the movie is done, and if not continues
2295 // streaming the movie
2296 // 2) Sends the wxEVT_MEDIA_STOP event if we have reached the end of
2297 // the movie.
2298 //-----------------------------------------------------------------------
2299 void Notify()
2300 {
2301 if (!m_bPaused)
2302 {
d7a9c895
RN
2303 if(!m_pLib->IsMovieDone(m_movie))
2304 m_pLib->MoviesTask(m_movie, MOVIE_DELAY);
ff4aedc5
RN
2305 else
2306 {
226ec5a7 2307 wxMediaEvent theEvent(wxEVT_MEDIA_STOP,
ff4aedc5
RN
2308 m_parent->m_ctrl->GetId());
2309 m_parent->m_ctrl->ProcessEvent(theEvent);
2310
2311 if(theEvent.IsAllowed())
2312 {
2313 Stop();
2314 m_parent->Stop();
d7a9c895 2315 wxASSERT(m_pLib->GetMoviesError() == noErr);
ff4aedc5
RN
2316
2317 //send the event to our child
226ec5a7 2318 wxMediaEvent theEvent(wxEVT_MEDIA_FINISHED,
ff4aedc5
RN
2319 m_parent->m_ctrl->GetId());
2320 m_parent->m_ctrl->ProcessEvent(theEvent);
2321 }
2322 }
2323 }
2324 }
2325
2326protected:
2327 Movie m_movie; //Our movie instance
2328 bool m_bPaused; //Whether we are paused or not
2329 wxQTMediaBackend* m_parent; //Backend pointer
d7a9c895 2330 wxQuickTimeLibrary* m_pLib; //Interfaces
ff4aedc5
RN
2331};
2332
2333//---------------------------------------------------------------------------
2334// wxQTMediaBackend Destructor
2335//
2336// Sets m_timer to NULL signifying we havn't loaded anything yet
2337//---------------------------------------------------------------------------
2338wxQTMediaBackend::wxQTMediaBackend() : m_timer(NULL)
2339{
2340}
2341
2342//---------------------------------------------------------------------------
2343// wxQTMediaBackend Destructor
2344//
2345// 1) Cleans up the QuickTime movie instance
2346// 2) Decrements the QuickTime reference counter - if this reaches
2347// 0, QuickTime shuts down
2348// 3) Decrements the QuickTime Windows Media Layer reference counter -
2349// if this reaches 0, QuickTime shuts down the Windows Media Layer
2350//---------------------------------------------------------------------------
2351wxQTMediaBackend::~wxQTMediaBackend()
2352{
2353 if(m_timer)
2354 Cleanup();
2355
d7a9c895
RN
2356 if(m_lib.IsOk())
2357 {
3103e8a9 2358 //Note that ExitMovies() is not necessary, but
d7a9c895
RN
2359 //the docs are fuzzy on whether or not TerminateQTML is
2360 m_lib.ExitMovies();
2361 m_lib.TerminateQTML();
2362 }
ff4aedc5
RN
2363}
2364
2365//---------------------------------------------------------------------------
2366// wxQTMediaBackend::CreateControl
2367//
2368// 1) Intializes QuickTime
2369// 2) Creates the control window
2370//---------------------------------------------------------------------------
226ec5a7 2371bool wxQTMediaBackend::CreateControl(wxControl* ctrl, wxWindow* parent,
ff4aedc5 2372 wxWindowID id,
226ec5a7 2373 const wxPoint& pos,
ff4aedc5 2374 const wxSize& size,
226ec5a7 2375 long style,
ff4aedc5
RN
2376 const wxValidator& validator,
2377 const wxString& name)
2378{
d7a9c895
RN
2379 if(!m_lib.Initialize())
2380 return false;
b11eba7e 2381
600ffb32
WS
2382 int nError = m_lib.InitializeQTML(0);
2383 if (nError != noErr) //-2093 no dll
ff4aedc5
RN
2384 {
2385 wxFAIL_MSG(wxString::Format(wxT("Couldn't Initialize Quicktime-%i"), nError));
2386 return false;
2387 }
d7a9c895 2388 m_lib.EnterMovies();
ff4aedc5
RN
2389
2390 //
2391 // Create window
2392 // By default wxWindow(s) is created with a border -
2393 // so we need to get rid of those
2394 //
2395 // Since we don't have a child window like most other
2396 // backends, we don't need wxCLIP_CHILDREN
2397 //
2398 if ( !ctrl->wxControl::Create(parent, id, pos, size,
11085e4b 2399 (style & ~wxBORDER_MASK) | wxBORDER_NONE,
ff4aedc5
RN
2400 validator, name) )
2401 return false;
2402
ff4aedc5
RN
2403 m_ctrl = ctrl;
2404 return true;
2405}
2406
2407//---------------------------------------------------------------------------
2408// wxQTMediaBackend::Load (file version)
2409//
2410// 1) Get an FSSpec from the Windows path name
2411// 2) Open the movie
2412// 3) Obtain the movie instance from the movie resource
226ec5a7 2413// 4)
ff4aedc5
RN
2414//---------------------------------------------------------------------------
2415bool wxQTMediaBackend::Load(const wxString& fileName)
2416{
2417 if(m_timer)
2418 Cleanup();
3f9a3bf9 2419
920a7c15 2420 short movieResFile = 0; //= 0 because of annoying VC6 warning
ff4aedc5
RN
2421 FSSpec sfFile;
2422
d7a9c895 2423 if (m_lib.NativePathNameToFSSpec ((char*) (const char*) fileName.mb_str(),
78450975 2424 &sfFile, 0) != noErr)
ff4aedc5 2425 return false;
226ec5a7 2426
d7a9c895 2427 if (m_lib.OpenMovieFile (&sfFile, &movieResFile, fsRdPerm) != noErr)
ff4aedc5
RN
2428 return false;
2429
2430 short movieResID = 0;
2431 Str255 movieName;
2432
600ffb32
WS
2433 OSErr err = m_lib.NewMovieFromFile (
2434 &m_movie,
2435 movieResFile,
2436 &movieResID,
2437 movieName,
2438 newMovieActive,
2439 NULL
2440 ); //wasChanged
ff4aedc5 2441
d7a9c895 2442 m_lib.CloseMovieFile (movieResFile);
ff4aedc5
RN
2443
2444 if (err != noErr)
2445 return false;
2446
2447 FinishLoad();
2448
d7a9c895 2449 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2450}
2451
2452//---------------------------------------------------------------------------
2453// wxQTMediaBackend::Move
2454//
2455// TODO
2456//---------------------------------------------------------------------------
2457bool wxQTMediaBackend::Load(const wxURI& location)
2458{
2459 if(m_timer)
2460 Cleanup();
2461
2462 wxString theURI = location.BuildURI();
2463
d7a9c895 2464 Handle theHandle = m_lib.NewHandleClear(theURI.length() + 1);
ff4aedc5
RN
2465 wxASSERT(theHandle);
2466
d7a9c895 2467 m_lib.BlockMove(theURI.mb_str(), *theHandle, theURI.length() + 1);
ff4aedc5
RN
2468
2469 //create the movie from the handle that refers to the URI
600ffb32 2470 OSErr err = m_lib.NewMovieFromDataRef(&m_movie, newMovieActive,
226ec5a7 2471 NULL, theHandle,
19b6f122 2472 URLDataHandlerSubType);
ff4aedc5 2473
d7a9c895 2474 m_lib.DisposeHandle(theHandle);
ff4aedc5
RN
2475
2476 if (err != noErr)
2477 return false;
2478
2479 //preroll movie for streaming
2480 //TODO:Async this?
d7a9c895
RN
2481 /*
2482 TimeValue timeNow;
ff4aedc5
RN
2483 Fixed playRate;
2484 timeNow = GetMovieTime(m_movie, NULL);
2485 playRate = GetMoviePreferredRate(m_movie);
2486 PrePrerollMovie(m_movie, timeNow, playRate, NULL, NULL);
b11eba7e 2487 PrerollMovie(m_movie, timeNow, playRate);
d7a9c895
RN
2488 m_lib.SetMovieRate(m_movie, playRate);
2489*/
ff4aedc5
RN
2490
2491 FinishLoad();
2492
d7a9c895 2493 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2494}
2495
2496//---------------------------------------------------------------------------
2497// wxQTMediaBackend::Move
2498//
2499// TODO
2500//---------------------------------------------------------------------------
2501void wxQTMediaBackend::FinishLoad()
2502{
d7a9c895 2503 m_timer = new _wxQTTimer(m_movie, (wxQTMediaBackend*) this, &m_lib);
ff4aedc5
RN
2504 wxASSERT(m_timer);
2505
2506 //get the real size of the movie
2507 Rect outRect;
920a7c15 2508 memset(&outRect, 0, sizeof(Rect)); //for annoying VC6 warning
d7a9c895
RN
2509 m_lib.GetMovieNaturalBoundsRect (m_movie, &outRect);
2510 wxASSERT(m_lib.GetMoviesError() == noErr);
ff4aedc5
RN
2511
2512 m_bestSize.x = outRect.right - outRect.left;
2513 m_bestSize.y = outRect.bottom - outRect.top;
226ec5a7 2514
ff4aedc5 2515 //reparent movie/*AudioMediaCharacteristic*/
d7a9c895 2516 if(m_lib.GetMovieIndTrackType(m_movie, 1,
19b6f122 2517 VisualMediaCharacteristic,
b11eba7e 2518 (1 << 1) //movieTrackCharacteristic
d7a9c895
RN
2519 | (1 << 2) //movieTrackEnabledOnly
2520 ) != NULL)
ff4aedc5 2521 {
d7a9c895 2522 m_lib.CreatePortAssociation(m_ctrl->GetHWND(), NULL, 0L);
226ec5a7 2523
d7a9c895
RN
2524 m_lib.SetMovieGWorld(m_movie,
2525 (CGrafPtr) m_lib.GetNativeWindowPort(m_ctrl->GetHWND()),
2526 NULL);
ff4aedc5
RN
2527 }
2528
2529 //we want millisecond precision
d7a9c895
RN
2530 m_lib.SetMovieTimeScale(m_movie, 1000);
2531 wxASSERT(m_lib.GetMoviesError() == noErr);
ff4aedc5
RN
2532
2533 //
2534 //Here, if the parent of the control has a sizer - we
2535 //tell it to recalculate the size of this control since
3103e8a9 2536 //the user opened a separate media file
ff4aedc5
RN
2537 //
2538 m_ctrl->InvalidateBestSize();
2539 m_ctrl->GetParent()->Layout();
2540 m_ctrl->GetParent()->Refresh();
2541 m_ctrl->GetParent()->Update();
2542}
2543
2544//---------------------------------------------------------------------------
2545// wxQTMediaBackend::Move
2546//
2547// TODO
2548//---------------------------------------------------------------------------
2549bool wxQTMediaBackend::Play()
2550{
d7a9c895 2551 m_lib.StartMovie(m_movie);
ff4aedc5
RN
2552 m_timer->SetPaused(false);
2553 m_timer->Start(MOVIE_DELAY, wxTIMER_CONTINUOUS);
d7a9c895 2554 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2555}
2556
2557//---------------------------------------------------------------------------
2558// wxQTMediaBackend::Move
2559//
2560// TODO
2561//---------------------------------------------------------------------------
2562bool wxQTMediaBackend::Pause()
2563{
d7a9c895 2564 m_lib.StopMovie(m_movie);
ff4aedc5
RN
2565 m_timer->SetPaused(true);
2566 m_timer->Stop();
d7a9c895 2567 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2568}
2569
2570//---------------------------------------------------------------------------
2571// wxQTMediaBackend::Move
2572//
2573// TODO
2574//---------------------------------------------------------------------------
2575bool wxQTMediaBackend::Stop()
2576{
2577 m_timer->SetPaused(false);
2578 m_timer->Stop();
2579
d7a9c895
RN
2580 m_lib.StopMovie(m_movie);
2581 if(m_lib.GetMoviesError() != noErr)
ff4aedc5 2582 return false;
226ec5a7 2583
d7a9c895
RN
2584 m_lib.GoToBeginningOfMovie(m_movie);
2585 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2586}
2587
2588//---------------------------------------------------------------------------
2589// wxQTMediaBackend::Move
2590//
2591// TODO
2592//---------------------------------------------------------------------------
2593double wxQTMediaBackend::GetPlaybackRate()
2594{
d7a9c895 2595 return ( ((double)m_lib.GetMovieRate(m_movie)) / 0x10000);
ff4aedc5
RN
2596}
2597
2598//---------------------------------------------------------------------------
2599// wxQTMediaBackend::Move
2600//
2601// TODO
2602//---------------------------------------------------------------------------
2603bool wxQTMediaBackend::SetPlaybackRate(double dRate)
2604{
d7a9c895
RN
2605 m_lib.SetMovieRate(m_movie, (Fixed) (dRate * 0x10000));
2606 return m_lib.GetMoviesError() == noErr;
ff4aedc5
RN
2607}
2608
2609//---------------------------------------------------------------------------
2610// wxQTMediaBackend::Move
2611//
2612// TODO
2613//---------------------------------------------------------------------------
2614bool wxQTMediaBackend::SetPosition(wxLongLong where)
2615{
2616 TimeRecord theTimeRecord;
2617 memset(&theTimeRecord, 0, sizeof(TimeRecord));
600ffb32 2618 theTimeRecord.value.lo = where.GetLo();
d7a9c895
RN
2619 theTimeRecord.scale = m_lib.GetMovieTimeScale(m_movie);
2620 theTimeRecord.base = m_lib.GetMovieTimeBase(m_movie);
2621 m_lib.SetMovieTime(m_movie, &theTimeRecord);
ff4aedc5 2622
d7a9c895 2623 if (m_lib.GetMoviesError() != noErr)
ff4aedc5
RN
2624 return false;
2625
2626 return true;
2627}
2628
2629//---------------------------------------------------------------------------
e163773d 2630// wxQTMediaBackend::GetPosition
ff4aedc5 2631//
e163773d 2632// 1) Calls GetMovieTime to get the position we are in in the movie
8b5d5223 2633// in milliseconds (we called
ff4aedc5
RN
2634//---------------------------------------------------------------------------
2635wxLongLong wxQTMediaBackend::GetPosition()
2636{
d7a9c895 2637 return m_lib.GetMovieTime(m_movie, NULL);
ff4aedc5
RN
2638}
2639
6f8c67e7
JS
2640//---------------------------------------------------------------------------
2641// wxQTMediaBackend::GetVolume
2642//
2643// Gets the volume through GetMovieVolume - which returns a 16 bit short -
2644//
2645// +--------+--------+
2646// + (1) + (2) +
2647// +--------+--------+
2648//
2649// (1) first 8 bits are value before decimal
2650// (2) second 8 bits are value after decimal
2651//
2652// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
2653// 1 (full gain and sound)
2654//---------------------------------------------------------------------------
2655double wxQTMediaBackend::GetVolume()
2656{
2657 short sVolume = m_lib.GetMovieVolume(m_movie);
b11eba7e 2658
6f8c67e7
JS
2659 if(sVolume & (128 << 8)) //negative - no sound
2660 return 0.0;
2661
2662 return (sVolume & (127 << 8)) ? 1.0 : ((double)(sVolume & 255)) / 255.0;
2663}
2664
2665//---------------------------------------------------------------------------
2666// wxQTMediaBackend::SetVolume
2667//
2668// Sets the volume through SetMovieVolume - which takes a 16 bit short -
2669//
2670// +--------+--------+
2671// + (1) + (2) +
2672// +--------+--------+
2673//
2674// (1) first 8 bits are value before decimal
2675// (2) second 8 bits are value after decimal
2676//
2677// Volume ranges from -1.0 (gain but no sound), 0 (no sound and no gain) to
2678// 1 (full gain and sound)
2679//---------------------------------------------------------------------------
2680bool wxQTMediaBackend::SetVolume(double dVolume)
2681{
600ffb32 2682 short sVolume = (short) (dVolume >= .9999 ? 1 << 8 : (dVolume * 255) );
6f8c67e7
JS
2683 m_lib.SetMovieVolume(m_movie, sVolume);
2684 return true;
2685}
2686
ff4aedc5
RN
2687//---------------------------------------------------------------------------
2688// wxQTMediaBackend::Move
2689//
2690// TODO
2691//---------------------------------------------------------------------------
2692wxLongLong wxQTMediaBackend::GetDuration()
2693{
d7a9c895 2694 return m_lib.GetMovieDuration(m_movie);
ff4aedc5
RN
2695}
2696
2697//---------------------------------------------------------------------------
2698// wxQTMediaBackend::Move
2699//
2700// TODO
2701//---------------------------------------------------------------------------
2702wxMediaState wxQTMediaBackend::GetState()
2703{
226ec5a7 2704 if ( !m_timer || (m_timer->IsRunning() == false &&
ff4aedc5
RN
2705 m_timer->GetPaused() == false) )
2706 return wxMEDIASTATE_STOPPED;
2707
2708 if( m_timer->IsRunning() == true )
2709 return wxMEDIASTATE_PLAYING;
2710 else
2711 return wxMEDIASTATE_PAUSED;
2712}
2713
2714//---------------------------------------------------------------------------
2715// wxQTMediaBackend::Move
2716//
2717// TODO
2718//---------------------------------------------------------------------------
2719void wxQTMediaBackend::Cleanup()
2720{
2721 delete m_timer;
2722 m_timer = NULL;
2723
d7a9c895
RN
2724 m_lib.StopMovie(m_movie);
2725 m_lib.DisposeMovie(m_movie);
ff4aedc5
RN
2726}
2727
2728//---------------------------------------------------------------------------
2729// wxQTMediaBackend::Move
2730//
2731// TODO
2732//---------------------------------------------------------------------------
2733wxSize wxQTMediaBackend::GetVideoSize() const
2734{
2735 return m_bestSize;
2736}
2737
2738//---------------------------------------------------------------------------
2739// wxQTMediaBackend::Move
2740//
2741// TODO
2742//---------------------------------------------------------------------------
d7a9c895 2743void wxQTMediaBackend::Move(int WXUNUSED(x), int WXUNUSED(y), int w, int h)
ff4aedc5
RN
2744{
2745 if(m_timer)
2746 {
600ffb32 2747 Rect theRect = {0, 0, (short)h, (short)w};
ff4aedc5 2748
d7a9c895
RN
2749 m_lib.SetMovieBox(m_movie, &theRect);
2750 wxASSERT(m_lib.GetMoviesError() == noErr);
ff4aedc5
RN
2751 }
2752}
2753
2754//---------------------------------------------------------------------------
1146983c 2755// End QT Backend
ff4aedc5 2756//---------------------------------------------------------------------------
ff4aedc5
RN
2757
2758//in source file that contains stuff you don't directly use
2759#include <wx/html/forcelnk.h>
2760FORCE_LINK_ME(basewxmediabackends);
2761
2762//---------------------------------------------------------------------------
2763// End wxMediaCtrl Compilation Guard and this file
2764//---------------------------------------------------------------------------
72259e00
RL
2765#endif //wxUSE_MEDIACTRL
2766
ff4aedc5 2767