amstream: Handle AMMSF_RENDERALLSTREAMS in IAMMultiMediaStream::OpenFile().
[wine.git] / dlls / amstream / multimedia.c
blob98ffc95a54a3e70c5ac4eb951c23c2805141ead1
1 /*
2 * Multimedia stream object
4 * Copyright 2004, 2012 Christian Costa
5 * Copyright 2006 Ivan Leo Puoti
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.
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.
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
22 #include "wine/debug.h"
24 #define COBJMACROS
26 #include "winbase.h"
27 #include "wingdi.h"
29 #include "amstream_private.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(amstream);
33 struct multimedia_stream
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;
48 static inline struct multimedia_stream *impl_from_IAMMultiMediaStream(IAMMultiMediaStream *iface)
50 return CONTAINING_RECORD(iface, struct multimedia_stream, IAMMultiMediaStream_iface);
53 /*** IUnknown methods ***/
54 static HRESULT WINAPI multimedia_stream_QueryInterface(IAMMultiMediaStream *iface,
55 REFIID riid, void **ppvObject)
57 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
59 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
61 if (IsEqualGUID(riid, &IID_IUnknown) ||
62 IsEqualGUID(riid, &IID_IMultiMediaStream) ||
63 IsEqualGUID(riid, &IID_IAMMultiMediaStream))
65 IAMMultiMediaStream_AddRef(iface);
66 *ppvObject = iface;
67 return S_OK;
70 ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
72 return E_NOINTERFACE;
75 static ULONG WINAPI multimedia_stream_AddRef(IAMMultiMediaStream *iface)
77 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
79 TRACE("(%p/%p)\n", iface, This);
81 return InterlockedIncrement(&This->ref);
84 static ULONG WINAPI multimedia_stream_Release(IAMMultiMediaStream *iface)
86 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
87 ULONG ref = InterlockedDecrement(&This->ref);
89 TRACE("(%p/%p)\n", iface, This);
91 if (!ref)
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 HeapFree(GetProcessHeap(), 0, This);
106 return ref;
109 /*** IMultiMediaStream methods ***/
110 static HRESULT WINAPI multimedia_stream_GetInformation(IAMMultiMediaStream *iface,
111 DWORD *pdwFlags, STREAM_TYPE *pStreamType)
113 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
115 FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, pdwFlags, pStreamType);
117 return E_NOTIMPL;
120 static HRESULT WINAPI multimedia_stream_GetMediaStream(IAMMultiMediaStream *iface,
121 REFMSPID id, IMediaStream **stream)
123 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
125 TRACE("mmstream %p, id %s, stream %p.\n", mmstream, debugstr_guid(id), stream);
127 return IMediaStreamFilter_GetMediaStream(mmstream->filter, id, stream);
130 static HRESULT WINAPI multimedia_stream_EnumMediaStreams(IAMMultiMediaStream *iface,
131 LONG index, IMediaStream **stream)
133 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
135 TRACE("mmstream %p, index %d, stream %p.\n", mmstream, index, stream);
137 return IMediaStreamFilter_EnumMediaStreams(mmstream->filter, index, stream);
140 static HRESULT WINAPI multimedia_stream_GetState(IAMMultiMediaStream *iface, STREAM_STATE *state)
142 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
144 TRACE("mmstream %p, state %p.\n", mmstream, state);
146 *state = mmstream->state;
148 return S_OK;
151 static HRESULT WINAPI multimedia_stream_SetState(IAMMultiMediaStream *iface, STREAM_STATE new_state)
153 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
154 HRESULT hr = E_INVALIDARG;
156 TRACE("(%p/%p)->(%u)\n", This, iface, new_state);
158 if (new_state == STREAMSTATE_RUN)
160 hr = IMediaControl_Run(This->media_control);
161 if (SUCCEEDED(hr))
163 FILTER_STATE state;
164 IMediaControl_GetState(This->media_control, INFINITE, (OAFilterState *)&state);
165 hr = S_OK;
168 else if (new_state == STREAMSTATE_STOP)
169 hr = IMediaControl_Stop(This->media_control);
171 if (SUCCEEDED(hr))
172 This->state = new_state;
174 return hr;
177 static HRESULT WINAPI multimedia_stream_GetTime(IAMMultiMediaStream *iface, STREAM_TIME *time)
179 struct multimedia_stream *stream = impl_from_IAMMultiMediaStream(iface);
181 TRACE("stream %p, time %p.\n", stream, time);
183 return IMediaStreamFilter_GetCurrentStreamTime(stream->filter, time);
186 static HRESULT WINAPI multimedia_stream_GetDuration(IAMMultiMediaStream *iface, STREAM_TIME *duration)
188 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
190 TRACE("mmstream %p, duration %p.\n", mmstream, duration);
192 if (!mmstream->media_seeking)
193 return E_NOINTERFACE;
195 if (IMediaSeeking_GetDuration(mmstream->media_seeking, duration) != S_OK)
196 return S_FALSE;
198 return S_OK;
201 static HRESULT WINAPI multimedia_stream_Seek(IAMMultiMediaStream *iface, STREAM_TIME seek_time)
203 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
205 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(seek_time));
207 return IMediaSeeking_SetPositions(This->media_seeking, &seek_time, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
210 static HRESULT WINAPI multimedia_stream_GetEndOfStream(IAMMultiMediaStream *iface, HANDLE *eos)
212 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
214 TRACE("mmstream %p, eos %p.\n", mmstream, eos);
216 if (!eos)
217 return E_POINTER;
219 *eos = (HANDLE)mmstream->event;
221 return S_OK;
224 static HRESULT create_graph(struct multimedia_stream *mmstream, IGraphBuilder *graph)
226 IMediaEventEx *eventsrc;
227 HRESULT hr;
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;
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))
244 hr = IMediaEventEx_GetEventHandle(eventsrc, &mmstream->event);
245 if (SUCCEEDED(hr))
246 hr = IMediaEventEx_SetNotifyFlags(eventsrc, AM_MEDIAEVENT_NONOTIFY);
247 IMediaEventEx_Release(eventsrc);
250 if (FAILED(hr))
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;
263 return hr;
266 static HRESULT WINAPI multimedia_stream_Initialize(IAMMultiMediaStream *iface,
267 STREAM_TYPE type, DWORD flags, IGraphBuilder *graph)
269 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
270 HRESULT hr;
272 TRACE("mmstream %p, type %u, flags %#x, graph %p.\n", mmstream, type, flags, graph);
274 if (graph && mmstream->graph)
276 WARN("Graph already initialized, returning E_INVALIDARG.\n");
277 return E_INVALIDARG;
280 if (mmstream->initialized && type != mmstream->type)
282 WARN("Attempt to change type from %u, returning E_INVALIDARG.\n", mmstream->type);
283 return E_INVALIDARG;
286 if (graph && FAILED(hr = create_graph(mmstream, graph)))
287 return hr;
289 mmstream->type = type;
290 mmstream->initialized = TRUE;
292 return S_OK;
295 static HRESULT WINAPI multimedia_stream_GetFilterGraph(IAMMultiMediaStream *iface, IGraphBuilder **graph)
297 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
299 TRACE("mmstream %p, graph %p.\n", mmstream, graph);
301 if (!graph)
302 return E_POINTER;
304 if (mmstream->graph)
305 IGraphBuilder_AddRef(*graph = mmstream->graph);
306 else
307 *graph = NULL;
309 return S_OK;
312 static HRESULT WINAPI multimedia_stream_GetFilter(IAMMultiMediaStream *iface,
313 IMediaStreamFilter **filter)
315 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
317 TRACE("mmstream %p, filter %p.\n", mmstream, filter);
319 if (!filter)
320 return E_POINTER;
322 IMediaStreamFilter_AddRef(*filter = mmstream->filter);
324 return S_OK;
327 static void add_stream(struct multimedia_stream *mmstream, IAMMediaStream *stream, IMediaStream **ret_stream)
329 IMediaStreamFilter_AddMediaStream(mmstream->filter, stream);
330 IAMMediaStream_JoinAMMultiMediaStream(stream, &mmstream->IAMMultiMediaStream_iface);
331 if (ret_stream)
333 *ret_stream = (IMediaStream *)stream;
334 IMediaStream_AddRef(*ret_stream);
338 static HRESULT WINAPI multimedia_stream_AddMediaStream(IAMMultiMediaStream *iface,
339 IUnknown *stream_object, const MSPID *PurposeId, DWORD dwFlags, IMediaStream **ret_stream)
341 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
342 HRESULT hr;
343 IAMMediaStream* pStream;
344 IMediaStream *stream;
346 TRACE("mmstream %p, stream_object %p, id %s, flags %#x, ret_stream %p.\n",
347 This, stream_object, debugstr_guid(PurposeId), dwFlags, ret_stream);
349 if (IMediaStreamFilter_GetMediaStream(This->filter, PurposeId, &stream) == S_OK)
351 IMediaStream_Release(stream);
352 return MS_E_PURPOSEID;
355 if (!This->graph && FAILED(hr = create_graph(This, NULL)))
356 return hr;
358 if (dwFlags & AMMSF_ADDDEFAULTRENDERER)
360 IBaseFilter *dsound_render;
362 if (ret_stream)
363 return E_INVALIDARG;
365 if (!IsEqualGUID(PurposeId, &MSPID_PrimaryAudio))
367 WARN("AMMSF_ADDDEFAULTRENDERER requested with id %s, returning MS_E_PURPOSEID.\n", debugstr_guid(PurposeId));
368 return MS_E_PURPOSEID;
371 if (SUCCEEDED(hr = CoCreateInstance(&CLSID_DSoundRender, NULL,
372 CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&dsound_render)))
374 hr = IGraphBuilder_AddFilter(This->graph, dsound_render, NULL);
375 IBaseFilter_Release(dsound_render);
377 return hr;
380 if (stream_object)
382 hr = IUnknown_QueryInterface(stream_object, &IID_IAMMediaStream, (void **)&pStream);
383 if (SUCCEEDED(hr))
385 MSPID stream_id;
386 hr = IAMMediaStream_GetInformation(pStream, &stream_id, NULL);
387 if (SUCCEEDED(hr))
389 if (IsEqualGUID(PurposeId, &stream_id))
391 add_stream(This, pStream, ret_stream);
392 hr = S_OK;
394 else
396 hr = MS_E_PURPOSEID;
400 IAMMediaStream_Release(pStream);
402 return hr;
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;
413 if (FAILED(hr))
414 return hr;
416 hr = IAMMediaStream_Initialize(pStream, stream_object, dwFlags, PurposeId, This->type);
417 if (FAILED(hr))
419 IAMMediaStream_Release(pStream);
420 return hr;
423 add_stream(This, pStream, ret_stream);
424 IAMMediaStream_Release(pStream);
426 return S_OK;
429 static HRESULT WINAPI multimedia_stream_OpenFile(IAMMultiMediaStream *iface,
430 const WCHAR *filename, DWORD flags)
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;
439 TRACE("(%p/%p)->(%s,%x)\n", This, iface, debugstr_w(filename), flags);
441 if (!filename)
442 return E_POINTER;
444 /* If Initialize was not called before, we do it here */
445 if (!This->graph)
447 ret = IAMMultiMediaStream_Initialize(iface, STREAMTYPE_READ, 0, NULL);
448 if (SUCCEEDED(ret))
449 ret = create_graph(This, NULL);
452 if (SUCCEEDED(ret))
453 ret = IGraphBuilder_AddSourceFilter(This->graph, filename, L"Source", &BaseFilter);
455 if (SUCCEEDED(ret))
456 ret = IBaseFilter_EnumPins(BaseFilter, &EnumPins);
458 if (SUCCEEDED(ret))
459 ret = IEnumPins_Next(EnumPins, 1, &ipin, NULL);
461 if (SUCCEEDED(ret))
463 ret = IPin_QueryDirection(ipin, &pin_direction);
464 if (ret == S_OK && pin_direction == PINDIR_OUTPUT)
465 This->ipin = ipin;
468 if (SUCCEEDED(ret) && !(flags & AMMSF_NORENDER))
470 IFilterGraph2 *graph;
472 if (SUCCEEDED(ret = IGraphBuilder_QueryInterface(This->graph, &IID_IFilterGraph2, (void **)&graph)))
474 DWORD renderflags = (flags & AMMSF_RENDERALLSTREAMS) ? 0 : AM_RENDEREX_RENDERTOEXISTINGRENDERERS;
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;
480 IFilterGraph2_Release(graph);
482 else
484 FIXME("Failed to get IFilterGraph2 interface, hr %#x.\n", ret);
485 ret = IGraphBuilder_Render(This->graph, This->ipin);
489 if (SUCCEEDED(ret) && (flags & AMMSF_NOCLOCK))
491 IMediaFilter *media_filter;
493 if (SUCCEEDED(ret = IGraphBuilder_QueryInterface(This->graph, &IID_IMediaFilter, (void **)&media_filter)))
495 ret = IMediaFilter_SetSyncSource(media_filter, NULL);
496 IMediaFilter_Release(media_filter);
500 IMediaStreamFilter_SupportSeeking(This->filter, This->type == STREAMTYPE_READ);
502 if (SUCCEEDED(ret) && (flags & AMMSF_RUN))
503 ret = IAMMultiMediaStream_SetState(iface, STREAMSTATE_RUN);
505 if (EnumPins)
506 IEnumPins_Release(EnumPins);
507 if (BaseFilter)
508 IBaseFilter_Release(BaseFilter);
509 return ret;
512 static HRESULT WINAPI multimedia_stream_OpenMoniker(IAMMultiMediaStream *iface,
513 IBindCtx *pCtx, IMoniker *pMoniker, DWORD dwFlags)
515 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
517 FIXME("(%p/%p)->(%p,%p,%x) stub!\n", This, iface, pCtx, pMoniker, dwFlags);
519 return E_NOTIMPL;
522 static HRESULT WINAPI multimedia_stream_Render(IAMMultiMediaStream *iface, DWORD dwFlags)
524 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
526 FIXME("(%p/%p)->(%x) partial stub!\n", This, iface, dwFlags);
528 if(dwFlags != AMMSF_NOCLOCK)
529 return E_INVALIDARG;
531 return IGraphBuilder_Render(This->graph, This->ipin);
534 static const IAMMultiMediaStreamVtbl multimedia_stream_vtbl =
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
557 HRESULT multimedia_stream_create(IUnknown *outer, void **out)
559 struct multimedia_stream *object;
560 HRESULT hr;
562 if (outer)
563 return CLASS_E_NOAGGREGATION;
565 if (!(object = heap_alloc_zero(sizeof(*object))))
566 return E_OUTOFMEMORY;
568 object->IAMMultiMediaStream_iface.lpVtbl = &multimedia_stream_vtbl;
569 object->ref = 1;
571 if (FAILED(hr = CoCreateInstance(&CLSID_MediaStreamFilter, NULL,
572 CLSCTX_INPROC_SERVER, &IID_IMediaStreamFilter, (void **)&object->filter)))
574 ERR("Failed to create stream filter, hr %#x.\n", hr);
575 heap_free(object);
576 return hr;
579 /* The stream takes an additional reference to the filter. */
580 IMediaStreamFilter_AddRef(object->filter);
582 TRACE("Created multimedia stream %p.\n", object);
583 *out = &object->IAMMultiMediaStream_iface;
585 return S_OK;