Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/amstream/multimedia.c
4388 views
1
/*
2
* Multimedia stream object
3
*
4
* Copyright 2004, 2012 Christian Costa
5
* Copyright 2006 Ivan Leo Puoti
6
*
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
11
*
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
16
*
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20
*/
21
22
#include "wine/debug.h"
23
24
#define COBJMACROS
25
26
#include "winbase.h"
27
#include "wingdi.h"
28
29
#include "amstream_private.h"
30
31
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
32
33
struct multimedia_stream
34
{
35
IAMMultiMediaStream IAMMultiMediaStream_iface;
36
LONG ref;
37
IGraphBuilder *graph;
38
IMediaSeeking* media_seeking;
39
IMediaControl* media_control;
40
IMediaStreamFilter *filter;
41
IPin* ipin;
42
BOOL initialized;
43
STREAM_TYPE type;
44
OAEVENT event;
45
STREAM_STATE state;
46
};
47
48
static inline struct multimedia_stream *impl_from_IAMMultiMediaStream(IAMMultiMediaStream *iface)
49
{
50
return CONTAINING_RECORD(iface, struct multimedia_stream, IAMMultiMediaStream_iface);
51
}
52
53
/*** IUnknown methods ***/
54
static HRESULT WINAPI multimedia_stream_QueryInterface(IAMMultiMediaStream *iface,
55
REFIID riid, void **ppvObject)
56
{
57
struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
58
59
TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
60
61
if (IsEqualGUID(riid, &IID_IUnknown) ||
62
IsEqualGUID(riid, &IID_IMultiMediaStream) ||
63
IsEqualGUID(riid, &IID_IAMMultiMediaStream))
64
{
65
IAMMultiMediaStream_AddRef(iface);
66
*ppvObject = iface;
67
return S_OK;
68
}
69
70
ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
71
72
return E_NOINTERFACE;
73
}
74
75
static ULONG WINAPI multimedia_stream_AddRef(IAMMultiMediaStream *iface)
76
{
77
struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
78
79
TRACE("(%p/%p)\n", iface, This);
80
81
return InterlockedIncrement(&This->ref);
82
}
83
84
static ULONG WINAPI multimedia_stream_Release(IAMMultiMediaStream *iface)
85
{
86
struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
87
ULONG ref = InterlockedDecrement(&This->ref);
88
89
TRACE("(%p/%p)\n", iface, This);
90
91
if (!ref)
92
{
93
if (This->ipin)
94
IPin_Release(This->ipin);
95
IMediaStreamFilter_Release(This->filter);
96
IMediaStreamFilter_Release(This->filter);
97
if (This->media_seeking)
98
IMediaSeeking_Release(This->media_seeking);
99
if (This->media_control)
100
IMediaControl_Release(This->media_control);
101
if (This->graph)
102
IGraphBuilder_Release(This->graph);
103
free(This);
104
}
105
106
return ref;
107
}
108
109
/*** IMultiMediaStream methods ***/
110
static HRESULT WINAPI multimedia_stream_GetInformation(IAMMultiMediaStream *iface,
111
DWORD *pdwFlags, STREAM_TYPE *pStreamType)
112
{
113
struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
114
115
FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, pdwFlags, pStreamType);
116
117
return E_NOTIMPL;
118
}
119
120
static HRESULT WINAPI multimedia_stream_GetMediaStream(IAMMultiMediaStream *iface,
121
REFMSPID id, IMediaStream **stream)
122
{
123
struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
124
125
TRACE("mmstream %p, id %s, stream %p.\n", mmstream, debugstr_guid(id), stream);
126
127
return IMediaStreamFilter_GetMediaStream(mmstream->filter, id, stream);
128
}
129
130
static HRESULT WINAPI multimedia_stream_EnumMediaStreams(IAMMultiMediaStream *iface,
131
LONG index, IMediaStream **stream)
132
{
133
struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
134
135
TRACE("mmstream %p, index %ld, stream %p.\n", mmstream, index, stream);
136
137
return IMediaStreamFilter_EnumMediaStreams(mmstream->filter, index, stream);
138
}
139
140
static HRESULT WINAPI multimedia_stream_GetState(IAMMultiMediaStream *iface, STREAM_STATE *state)
141
{
142
struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
143
144
TRACE("mmstream %p, state %p.\n", mmstream, state);
145
146
*state = mmstream->state;
147
148
return S_OK;
149
}
150
151
static HRESULT WINAPI multimedia_stream_SetState(IAMMultiMediaStream *iface, STREAM_STATE new_state)
152
{
153
struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
154
HRESULT hr = E_INVALIDARG;
155
156
TRACE("(%p/%p)->(%u)\n", This, iface, new_state);
157
158
if (new_state == STREAMSTATE_RUN)
159
{
160
hr = IMediaControl_Run(This->media_control);
161
if (SUCCEEDED(hr))
162
{
163
FILTER_STATE state;
164
IMediaControl_GetState(This->media_control, INFINITE, (OAFilterState *)&state);
165
hr = S_OK;
166
}
167
}
168
else if (new_state == STREAMSTATE_STOP)
169
hr = IMediaControl_Stop(This->media_control);
170
171
if (SUCCEEDED(hr))
172
This->state = new_state;
173
174
return hr;
175
}
176
177
static HRESULT WINAPI multimedia_stream_GetTime(IAMMultiMediaStream *iface, STREAM_TIME *time)
178
{
179
struct multimedia_stream *stream = impl_from_IAMMultiMediaStream(iface);
180
181
TRACE("stream %p, time %p.\n", stream, time);
182
183
return IMediaStreamFilter_GetCurrentStreamTime(stream->filter, time);
184
}
185
186
static HRESULT WINAPI multimedia_stream_GetDuration(IAMMultiMediaStream *iface, STREAM_TIME *duration)
187
{
188
struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
189
190
TRACE("mmstream %p, duration %p.\n", mmstream, duration);
191
192
if (!mmstream->media_seeking)
193
return E_NOINTERFACE;
194
195
if (IMediaSeeking_GetDuration(mmstream->media_seeking, duration) != S_OK)
196
return S_FALSE;
197
198
return S_OK;
199
}
200
201
static HRESULT WINAPI multimedia_stream_Seek(IAMMultiMediaStream *iface, STREAM_TIME seek_time)
202
{
203
struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
204
205
TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(seek_time));
206
207
return IMediaSeeking_SetPositions(This->media_seeking, &seek_time, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
208
}
209
210
static HRESULT WINAPI multimedia_stream_GetEndOfStream(IAMMultiMediaStream *iface, HANDLE *eos)
211
{
212
struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
213
214
TRACE("mmstream %p, eos %p.\n", mmstream, eos);
215
216
if (!eos)
217
return E_POINTER;
218
219
*eos = (HANDLE)mmstream->event;
220
221
return S_OK;
222
}
223
224
static HRESULT create_graph(struct multimedia_stream *mmstream, IGraphBuilder *graph)
225
{
226
IMediaEventEx *eventsrc;
227
HRESULT hr;
228
229
if (graph)
230
IGraphBuilder_AddRef(mmstream->graph = graph);
231
else if (FAILED(hr = CoCreateInstance(&CLSID_FilterGraph, NULL,
232
CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&mmstream->graph)))
233
return hr;
234
235
hr = IGraphBuilder_QueryInterface(mmstream->graph, &IID_IMediaSeeking, (void **)&mmstream->media_seeking);
236
if (SUCCEEDED(hr))
237
hr = IGraphBuilder_QueryInterface(mmstream->graph, &IID_IMediaControl, (void **)&mmstream->media_control);
238
if (SUCCEEDED(hr))
239
hr = IGraphBuilder_AddFilter(mmstream->graph, (IBaseFilter *)mmstream->filter, L"MediaStreamFilter");
240
if (SUCCEEDED(hr))
241
hr = IGraphBuilder_QueryInterface(mmstream->graph, &IID_IMediaEventEx, (void **)&eventsrc);
242
if (SUCCEEDED(hr))
243
{
244
hr = IMediaEventEx_GetEventHandle(eventsrc, &mmstream->event);
245
if (SUCCEEDED(hr))
246
hr = IMediaEventEx_SetNotifyFlags(eventsrc, AM_MEDIAEVENT_NONOTIFY);
247
IMediaEventEx_Release(eventsrc);
248
}
249
250
if (FAILED(hr))
251
{
252
if (mmstream->media_seeking)
253
IMediaSeeking_Release(mmstream->media_seeking);
254
mmstream->media_seeking = NULL;
255
if (mmstream->media_control)
256
IMediaControl_Release(mmstream->media_control);
257
mmstream->media_control = NULL;
258
if (mmstream->graph)
259
IGraphBuilder_Release(mmstream->graph);
260
mmstream->graph = NULL;
261
}
262
263
return hr;
264
}
265
266
static HRESULT WINAPI multimedia_stream_Initialize(IAMMultiMediaStream *iface,
267
STREAM_TYPE type, DWORD flags, IGraphBuilder *graph)
268
{
269
struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
270
HRESULT hr;
271
272
TRACE("mmstream %p, type %u, flags %#lx, graph %p.\n", mmstream, type, flags, graph);
273
274
if (graph && mmstream->graph)
275
{
276
WARN("Graph already initialized, returning E_INVALIDARG.\n");
277
return E_INVALIDARG;
278
}
279
280
if (mmstream->initialized && type != mmstream->type)
281
{
282
WARN("Attempt to change type from %u, returning E_INVALIDARG.\n", mmstream->type);
283
return E_INVALIDARG;
284
}
285
286
if (graph && FAILED(hr = create_graph(mmstream, graph)))
287
return hr;
288
289
mmstream->type = type;
290
mmstream->initialized = TRUE;
291
292
return S_OK;
293
}
294
295
static HRESULT WINAPI multimedia_stream_GetFilterGraph(IAMMultiMediaStream *iface, IGraphBuilder **graph)
296
{
297
struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
298
299
TRACE("mmstream %p, graph %p.\n", mmstream, graph);
300
301
if (!graph)
302
return E_POINTER;
303
304
if (mmstream->graph)
305
IGraphBuilder_AddRef(*graph = mmstream->graph);
306
else
307
*graph = NULL;
308
309
return S_OK;
310
}
311
312
static HRESULT WINAPI multimedia_stream_GetFilter(IAMMultiMediaStream *iface,
313
IMediaStreamFilter **filter)
314
{
315
struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
316
317
TRACE("mmstream %p, filter %p.\n", mmstream, filter);
318
319
if (!filter)
320
return E_POINTER;
321
322
IMediaStreamFilter_AddRef(*filter = mmstream->filter);
323
324
return S_OK;
325
}
326
327
static void add_stream(struct multimedia_stream *mmstream, IAMMediaStream *stream, IMediaStream **ret_stream)
328
{
329
IMediaStreamFilter_AddMediaStream(mmstream->filter, stream);
330
IAMMediaStream_JoinAMMultiMediaStream(stream, &mmstream->IAMMultiMediaStream_iface);
331
if (ret_stream)
332
{
333
*ret_stream = (IMediaStream *)stream;
334
IMediaStream_AddRef(*ret_stream);
335
}
336
}
337
338
static HRESULT WINAPI multimedia_stream_AddMediaStream(IAMMultiMediaStream *iface,
339
IUnknown *stream_object, const MSPID *PurposeId, DWORD dwFlags, IMediaStream **ret_stream)
340
{
341
struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
342
HRESULT hr;
343
IAMMediaStream* pStream;
344
IMediaStream *stream;
345
346
TRACE("mmstream %p, stream_object %p, id %s, flags %#lx, ret_stream %p.\n",
347
This, stream_object, debugstr_guid(PurposeId), dwFlags, ret_stream);
348
349
if (IMediaStreamFilter_GetMediaStream(This->filter, PurposeId, &stream) == S_OK)
350
{
351
IMediaStream_Release(stream);
352
return MS_E_PURPOSEID;
353
}
354
355
if (!This->graph && FAILED(hr = create_graph(This, NULL)))
356
return hr;
357
358
if (dwFlags & AMMSF_ADDDEFAULTRENDERER)
359
{
360
IBaseFilter *dsound_render;
361
362
if (ret_stream)
363
return E_INVALIDARG;
364
365
if (!IsEqualGUID(PurposeId, &MSPID_PrimaryAudio))
366
{
367
WARN("AMMSF_ADDDEFAULTRENDERER requested with id %s, returning MS_E_PURPOSEID.\n", debugstr_guid(PurposeId));
368
return MS_E_PURPOSEID;
369
}
370
371
if (SUCCEEDED(hr = CoCreateInstance(&CLSID_DSoundRender, NULL,
372
CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&dsound_render)))
373
{
374
hr = IGraphBuilder_AddFilter(This->graph, dsound_render, NULL);
375
IBaseFilter_Release(dsound_render);
376
}
377
return hr;
378
}
379
380
if (stream_object)
381
{
382
hr = IUnknown_QueryInterface(stream_object, &IID_IAMMediaStream, (void **)&pStream);
383
if (SUCCEEDED(hr))
384
{
385
MSPID stream_id;
386
hr = IAMMediaStream_GetInformation(pStream, &stream_id, NULL);
387
if (SUCCEEDED(hr))
388
{
389
if (IsEqualGUID(PurposeId, &stream_id))
390
{
391
add_stream(This, pStream, ret_stream);
392
hr = S_OK;
393
}
394
else
395
{
396
hr = MS_E_PURPOSEID;
397
}
398
}
399
400
IAMMediaStream_Release(pStream);
401
402
return hr;
403
}
404
}
405
406
if (IsEqualGUID(PurposeId, &MSPID_PrimaryVideo))
407
hr = ddraw_stream_create(NULL, (void **)&pStream);
408
else if (IsEqualGUID(PurposeId, &MSPID_PrimaryAudio))
409
hr = audio_stream_create(NULL, (void **)&pStream);
410
else
411
return MS_E_PURPOSEID;
412
413
if (FAILED(hr))
414
return hr;
415
416
hr = IAMMediaStream_Initialize(pStream, stream_object, dwFlags, PurposeId, This->type);
417
if (FAILED(hr))
418
{
419
IAMMediaStream_Release(pStream);
420
return hr;
421
}
422
423
add_stream(This, pStream, ret_stream);
424
IAMMediaStream_Release(pStream);
425
426
return S_OK;
427
}
428
429
static HRESULT WINAPI multimedia_stream_OpenFile(IAMMultiMediaStream *iface,
430
const WCHAR *filename, DWORD flags)
431
{
432
struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
433
HRESULT ret = S_OK;
434
IBaseFilter *BaseFilter = NULL;
435
IEnumPins *EnumPins = NULL;
436
IPin *ipin;
437
PIN_DIRECTION pin_direction;
438
439
TRACE("(%p/%p)->(%s,%lx)\n", This, iface, debugstr_w(filename), flags);
440
441
if (!filename)
442
return E_POINTER;
443
444
/* If Initialize was not called before, we do it here */
445
if (!This->graph)
446
{
447
ret = IAMMultiMediaStream_Initialize(iface, STREAMTYPE_READ, 0, NULL);
448
if (SUCCEEDED(ret))
449
ret = create_graph(This, NULL);
450
}
451
452
if (SUCCEEDED(ret))
453
ret = IGraphBuilder_AddSourceFilter(This->graph, filename, L"Source", &BaseFilter);
454
455
if (SUCCEEDED(ret))
456
ret = IBaseFilter_EnumPins(BaseFilter, &EnumPins);
457
458
if (SUCCEEDED(ret))
459
ret = IEnumPins_Next(EnumPins, 1, &ipin, NULL);
460
461
if (SUCCEEDED(ret))
462
{
463
ret = IPin_QueryDirection(ipin, &pin_direction);
464
if (ret == S_OK && pin_direction == PINDIR_OUTPUT)
465
This->ipin = ipin;
466
}
467
468
if (SUCCEEDED(ret) && !(flags & AMMSF_NORENDER))
469
{
470
IFilterGraph2 *graph;
471
472
if (SUCCEEDED(ret = IGraphBuilder_QueryInterface(This->graph, &IID_IFilterGraph2, (void **)&graph)))
473
{
474
DWORD renderflags = (flags & AMMSF_RENDERALLSTREAMS) ? 0 : AM_RENDEREX_RENDERTOEXISTINGRENDERERS;
475
476
ret = IFilterGraph2_RenderEx(graph, This->ipin, renderflags, NULL);
477
if (ret == VFW_E_CANNOT_RENDER) ret = VFW_E_CANNOT_CONNECT;
478
else if (ret == VFW_S_PARTIAL_RENDER) ret = S_OK;
479
480
IFilterGraph2_Release(graph);
481
}
482
else
483
{
484
FIXME("Failed to get IFilterGraph2 interface, hr %#lx.\n", ret);
485
ret = IGraphBuilder_Render(This->graph, This->ipin);
486
}
487
}
488
489
if (SUCCEEDED(ret) && (flags & AMMSF_NOCLOCK))
490
{
491
IMediaFilter *media_filter;
492
493
if (SUCCEEDED(ret = IGraphBuilder_QueryInterface(This->graph, &IID_IMediaFilter, (void **)&media_filter)))
494
{
495
ret = IMediaFilter_SetSyncSource(media_filter, NULL);
496
IMediaFilter_Release(media_filter);
497
}
498
}
499
500
IMediaStreamFilter_SupportSeeking(This->filter, This->type == STREAMTYPE_READ);
501
502
if (SUCCEEDED(ret) && (flags & AMMSF_RUN))
503
ret = IAMMultiMediaStream_SetState(iface, STREAMSTATE_RUN);
504
505
if (EnumPins)
506
IEnumPins_Release(EnumPins);
507
if (BaseFilter)
508
IBaseFilter_Release(BaseFilter);
509
return ret;
510
}
511
512
static HRESULT WINAPI multimedia_stream_OpenMoniker(IAMMultiMediaStream *iface,
513
IBindCtx *pCtx, IMoniker *pMoniker, DWORD dwFlags)
514
{
515
struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
516
517
FIXME("(%p/%p)->(%p,%p,%lx) stub!\n", This, iface, pCtx, pMoniker, dwFlags);
518
519
return E_NOTIMPL;
520
}
521
522
static HRESULT WINAPI multimedia_stream_Render(IAMMultiMediaStream *iface, DWORD dwFlags)
523
{
524
struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
525
526
FIXME("(%p/%p)->(%lx) partial stub!\n", This, iface, dwFlags);
527
528
if(dwFlags != AMMSF_NOCLOCK)
529
return E_INVALIDARG;
530
531
return IGraphBuilder_Render(This->graph, This->ipin);
532
}
533
534
static const IAMMultiMediaStreamVtbl multimedia_stream_vtbl =
535
{
536
multimedia_stream_QueryInterface,
537
multimedia_stream_AddRef,
538
multimedia_stream_Release,
539
multimedia_stream_GetInformation,
540
multimedia_stream_GetMediaStream,
541
multimedia_stream_EnumMediaStreams,
542
multimedia_stream_GetState,
543
multimedia_stream_SetState,
544
multimedia_stream_GetTime,
545
multimedia_stream_GetDuration,
546
multimedia_stream_Seek,
547
multimedia_stream_GetEndOfStream,
548
multimedia_stream_Initialize,
549
multimedia_stream_GetFilterGraph,
550
multimedia_stream_GetFilter,
551
multimedia_stream_AddMediaStream,
552
multimedia_stream_OpenFile,
553
multimedia_stream_OpenMoniker,
554
multimedia_stream_Render
555
};
556
557
HRESULT multimedia_stream_create(IUnknown *outer, void **out)
558
{
559
struct multimedia_stream *object;
560
HRESULT hr;
561
562
if (outer)
563
return CLASS_E_NOAGGREGATION;
564
565
if (!(object = calloc(1, sizeof(*object))))
566
return E_OUTOFMEMORY;
567
568
object->IAMMultiMediaStream_iface.lpVtbl = &multimedia_stream_vtbl;
569
object->ref = 1;
570
571
if (FAILED(hr = CoCreateInstance(&CLSID_MediaStreamFilter, NULL,
572
CLSCTX_INPROC_SERVER, &IID_IMediaStreamFilter, (void **)&object->filter)))
573
{
574
ERR("Failed to create stream filter, hr %#lx.\n", hr);
575
free(object);
576
return hr;
577
}
578
579
/* The stream takes an additional reference to the filter. */
580
IMediaStreamFilter_AddRef(object->filter);
581
582
TRACE("Created multimedia stream %p.\n", object);
583
*out = &object->IAMMultiMediaStream_iface;
584
585
return S_OK;
586
}
587
588