winegstreamer: Move the "flip" field to struct wg_parser_stream.
[wine/zf.git] / dlls / amstream / multimedia.c
blobb34634d89d2a3ca6e84dd62f0d718bb9eaaa6ba2
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 *phEOS)
212 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
214 FIXME("(%p/%p)->(%p) stub!\n", This, iface, phEOS);
216 return E_NOTIMPL;
219 static HRESULT create_graph(struct multimedia_stream *mmstream, IGraphBuilder *graph)
221 IMediaEventEx *eventsrc;
222 HRESULT hr;
224 if (graph)
225 IGraphBuilder_AddRef(mmstream->graph = graph);
226 else if (FAILED(hr = CoCreateInstance(&CLSID_FilterGraph, NULL,
227 CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (void **)&mmstream->graph)))
228 return hr;
230 hr = IGraphBuilder_QueryInterface(mmstream->graph, &IID_IMediaSeeking, (void **)&mmstream->media_seeking);
231 if (SUCCEEDED(hr))
232 hr = IGraphBuilder_QueryInterface(mmstream->graph, &IID_IMediaControl, (void **)&mmstream->media_control);
233 if (SUCCEEDED(hr))
234 hr = IGraphBuilder_AddFilter(mmstream->graph, (IBaseFilter *)mmstream->filter, L"MediaStreamFilter");
235 if (SUCCEEDED(hr))
236 hr = IGraphBuilder_QueryInterface(mmstream->graph, &IID_IMediaEventEx, (void **)&eventsrc);
237 if (SUCCEEDED(hr))
239 hr = IMediaEventEx_GetEventHandle(eventsrc, &mmstream->event);
240 if (SUCCEEDED(hr))
241 hr = IMediaEventEx_SetNotifyFlags(eventsrc, AM_MEDIAEVENT_NONOTIFY);
242 IMediaEventEx_Release(eventsrc);
245 if (FAILED(hr))
247 if (mmstream->media_seeking)
248 IMediaSeeking_Release(mmstream->media_seeking);
249 mmstream->media_seeking = NULL;
250 if (mmstream->media_control)
251 IMediaControl_Release(mmstream->media_control);
252 mmstream->media_control = NULL;
253 if (mmstream->graph)
254 IGraphBuilder_Release(mmstream->graph);
255 mmstream->graph = NULL;
258 return hr;
261 static HRESULT WINAPI multimedia_stream_Initialize(IAMMultiMediaStream *iface,
262 STREAM_TYPE type, DWORD flags, IGraphBuilder *graph)
264 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
265 HRESULT hr;
267 TRACE("mmstream %p, type %u, flags %#x, graph %p.\n", mmstream, type, flags, graph);
269 if (graph && mmstream->graph)
271 WARN("Graph already initialized, returning E_INVALIDARG.\n");
272 return E_INVALIDARG;
275 if (mmstream->initialized && type != mmstream->type)
277 WARN("Attempt to change type from %u, returning E_INVALIDARG.\n", mmstream->type);
278 return E_INVALIDARG;
281 if (graph && FAILED(hr = create_graph(mmstream, graph)))
282 return hr;
284 mmstream->type = type;
285 mmstream->initialized = TRUE;
287 return S_OK;
290 static HRESULT WINAPI multimedia_stream_GetFilterGraph(IAMMultiMediaStream *iface, IGraphBuilder **graph)
292 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
294 TRACE("mmstream %p, graph %p.\n", mmstream, graph);
296 if (!graph)
297 return E_POINTER;
299 if (mmstream->graph)
300 IGraphBuilder_AddRef(*graph = mmstream->graph);
301 else
302 *graph = NULL;
304 return S_OK;
307 static HRESULT WINAPI multimedia_stream_GetFilter(IAMMultiMediaStream *iface,
308 IMediaStreamFilter **filter)
310 struct multimedia_stream *mmstream = impl_from_IAMMultiMediaStream(iface);
312 TRACE("mmstream %p, filter %p.\n", mmstream, filter);
314 if (!filter)
315 return E_POINTER;
317 IMediaStreamFilter_AddRef(*filter = mmstream->filter);
319 return S_OK;
322 static void add_stream(struct multimedia_stream *mmstream, IAMMediaStream *stream, IMediaStream **ret_stream)
324 IMediaStreamFilter_AddMediaStream(mmstream->filter, stream);
325 IAMMediaStream_JoinAMMultiMediaStream(stream, &mmstream->IAMMultiMediaStream_iface);
326 if (ret_stream)
328 *ret_stream = (IMediaStream *)stream;
329 IMediaStream_AddRef(*ret_stream);
333 static HRESULT WINAPI multimedia_stream_AddMediaStream(IAMMultiMediaStream *iface,
334 IUnknown *stream_object, const MSPID *PurposeId, DWORD dwFlags, IMediaStream **ret_stream)
336 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
337 HRESULT hr;
338 IAMMediaStream* pStream;
339 IMediaStream *stream;
341 TRACE("mmstream %p, stream_object %p, id %s, flags %#x, ret_stream %p.\n",
342 This, stream_object, debugstr_guid(PurposeId), dwFlags, ret_stream);
344 if (IMediaStreamFilter_GetMediaStream(This->filter, PurposeId, &stream) == S_OK)
346 IMediaStream_Release(stream);
347 return MS_E_PURPOSEID;
350 if (!This->graph && FAILED(hr = create_graph(This, NULL)))
351 return hr;
353 if (dwFlags & AMMSF_ADDDEFAULTRENDERER)
355 IBaseFilter *dsound_render;
357 if (ret_stream)
358 return E_INVALIDARG;
360 if (!IsEqualGUID(PurposeId, &MSPID_PrimaryAudio))
362 WARN("AMMSF_ADDDEFAULTRENDERER requested with id %s, returning MS_E_PURPOSEID.\n", debugstr_guid(PurposeId));
363 return MS_E_PURPOSEID;
366 if (SUCCEEDED(hr = CoCreateInstance(&CLSID_DSoundRender, NULL,
367 CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (void **)&dsound_render)))
369 hr = IGraphBuilder_AddFilter(This->graph, dsound_render, NULL);
370 IBaseFilter_Release(dsound_render);
372 return hr;
375 if (stream_object)
377 hr = IUnknown_QueryInterface(stream_object, &IID_IAMMediaStream, (void **)&pStream);
378 if (SUCCEEDED(hr))
380 MSPID stream_id;
381 hr = IAMMediaStream_GetInformation(pStream, &stream_id, NULL);
382 if (SUCCEEDED(hr))
384 if (IsEqualGUID(PurposeId, &stream_id))
386 add_stream(This, pStream, ret_stream);
387 hr = S_OK;
389 else
391 hr = MS_E_PURPOSEID;
395 IAMMediaStream_Release(pStream);
397 return hr;
401 if (IsEqualGUID(PurposeId, &MSPID_PrimaryVideo))
402 hr = ddraw_stream_create(NULL, (void **)&pStream);
403 else if (IsEqualGUID(PurposeId, &MSPID_PrimaryAudio))
404 hr = audio_stream_create(NULL, (void **)&pStream);
405 else
406 return MS_E_PURPOSEID;
408 if (FAILED(hr))
409 return hr;
411 hr = IAMMediaStream_Initialize(pStream, stream_object, dwFlags, PurposeId, This->type);
412 if (FAILED(hr))
414 IAMMediaStream_Release(pStream);
415 return hr;
418 add_stream(This, pStream, ret_stream);
419 IAMMediaStream_Release(pStream);
421 return S_OK;
424 static HRESULT WINAPI multimedia_stream_OpenFile(IAMMultiMediaStream *iface,
425 const WCHAR *filename, DWORD flags)
427 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
428 HRESULT ret = S_OK;
429 IBaseFilter *BaseFilter = NULL;
430 IEnumPins *EnumPins = NULL;
431 IPin *ipin;
432 PIN_DIRECTION pin_direction;
434 TRACE("(%p/%p)->(%s,%x)\n", This, iface, debugstr_w(filename), flags);
436 if (!filename)
437 return E_POINTER;
439 /* If Initialize was not called before, we do it here */
440 if (!This->graph)
442 ret = IAMMultiMediaStream_Initialize(iface, STREAMTYPE_READ, 0, NULL);
443 if (SUCCEEDED(ret))
444 ret = create_graph(This, NULL);
447 if (SUCCEEDED(ret))
448 ret = IGraphBuilder_AddSourceFilter(This->graph, filename, L"Source", &BaseFilter);
450 if (SUCCEEDED(ret))
451 ret = IBaseFilter_EnumPins(BaseFilter, &EnumPins);
453 if (SUCCEEDED(ret))
454 ret = IEnumPins_Next(EnumPins, 1, &ipin, NULL);
456 if (SUCCEEDED(ret))
458 ret = IPin_QueryDirection(ipin, &pin_direction);
459 if (ret == S_OK && pin_direction == PINDIR_OUTPUT)
460 This->ipin = ipin;
463 if (SUCCEEDED(ret) && !(flags & AMMSF_NORENDER))
465 IFilterGraph2 *graph;
467 if (SUCCEEDED(ret = IGraphBuilder_QueryInterface(This->graph, &IID_IFilterGraph2, (void **)&graph)))
469 ret = IFilterGraph2_RenderEx(graph, This->ipin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
470 if (ret == VFW_E_CANNOT_RENDER) ret = VFW_E_CANNOT_CONNECT;
471 else if (ret == VFW_S_PARTIAL_RENDER) ret = S_OK;
472 IFilterGraph2_Release(graph);
474 else
476 FIXME("Failed to get IFilterGraph2 interface, hr %#x.\n", ret);
477 ret = IGraphBuilder_Render(This->graph, This->ipin);
481 if (SUCCEEDED(ret) && (flags & AMMSF_NOCLOCK))
483 IMediaFilter *media_filter;
485 if (SUCCEEDED(ret = IGraphBuilder_QueryInterface(This->graph, &IID_IMediaFilter, (void **)&media_filter)))
487 ret = IMediaFilter_SetSyncSource(media_filter, NULL);
488 IMediaFilter_Release(media_filter);
492 IMediaStreamFilter_SupportSeeking(This->filter, This->type == STREAMTYPE_READ);
494 if (SUCCEEDED(ret) && (flags & AMMSF_RUN))
495 ret = IAMMultiMediaStream_SetState(iface, STREAMSTATE_RUN);
497 if (EnumPins)
498 IEnumPins_Release(EnumPins);
499 if (BaseFilter)
500 IBaseFilter_Release(BaseFilter);
501 return ret;
504 static HRESULT WINAPI multimedia_stream_OpenMoniker(IAMMultiMediaStream *iface,
505 IBindCtx *pCtx, IMoniker *pMoniker, DWORD dwFlags)
507 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
509 FIXME("(%p/%p)->(%p,%p,%x) stub!\n", This, iface, pCtx, pMoniker, dwFlags);
511 return E_NOTIMPL;
514 static HRESULT WINAPI multimedia_stream_Render(IAMMultiMediaStream *iface, DWORD dwFlags)
516 struct multimedia_stream *This = impl_from_IAMMultiMediaStream(iface);
518 FIXME("(%p/%p)->(%x) partial stub!\n", This, iface, dwFlags);
520 if(dwFlags != AMMSF_NOCLOCK)
521 return E_INVALIDARG;
523 return IGraphBuilder_Render(This->graph, This->ipin);
526 static const IAMMultiMediaStreamVtbl multimedia_stream_vtbl =
528 multimedia_stream_QueryInterface,
529 multimedia_stream_AddRef,
530 multimedia_stream_Release,
531 multimedia_stream_GetInformation,
532 multimedia_stream_GetMediaStream,
533 multimedia_stream_EnumMediaStreams,
534 multimedia_stream_GetState,
535 multimedia_stream_SetState,
536 multimedia_stream_GetTime,
537 multimedia_stream_GetDuration,
538 multimedia_stream_Seek,
539 multimedia_stream_GetEndOfStream,
540 multimedia_stream_Initialize,
541 multimedia_stream_GetFilterGraph,
542 multimedia_stream_GetFilter,
543 multimedia_stream_AddMediaStream,
544 multimedia_stream_OpenFile,
545 multimedia_stream_OpenMoniker,
546 multimedia_stream_Render
549 HRESULT multimedia_stream_create(IUnknown *outer, void **out)
551 struct multimedia_stream *object;
552 HRESULT hr;
554 if (outer)
555 return CLASS_E_NOAGGREGATION;
557 if (!(object = heap_alloc_zero(sizeof(*object))))
558 return E_OUTOFMEMORY;
560 object->IAMMultiMediaStream_iface.lpVtbl = &multimedia_stream_vtbl;
561 object->ref = 1;
563 if (FAILED(hr = CoCreateInstance(&CLSID_MediaStreamFilter, NULL,
564 CLSCTX_INPROC_SERVER, &IID_IMediaStreamFilter, (void **)&object->filter)))
566 ERR("Failed to create stream filter, hr %#x.\n", hr);
567 heap_free(object);
568 return hr;
571 /* The stream takes an additional reference to the filter. */
572 IMediaStreamFilter_AddRef(object->filter);
574 TRACE("Created multimedia stream %p.\n", object);
575 *out = &object->IAMMultiMediaStream_iface;
577 return S_OK;