[AMSTREAM]
[reactos.git] / reactos / dll / directx / wine / amstream / amstream.c
1 /*
2 * Implementation of IAMMultiMediaStream Interface
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 "amstream_private.h"
23
24 typedef struct {
25 IAMMultiMediaStream IAMMultiMediaStream_iface;
26 LONG ref;
27 IGraphBuilder* pFilterGraph;
28 IMediaSeeking* media_seeking;
29 IMediaControl* media_control;
30 IBaseFilter* media_stream_filter;
31 IPin* ipin;
32 ULONG nbStreams;
33 IMediaStream** pStreams;
34 STREAM_TYPE StreamType;
35 OAEVENT event;
36 } IAMMultiMediaStreamImpl;
37
38 static inline IAMMultiMediaStreamImpl *impl_from_IAMMultiMediaStream(IAMMultiMediaStream *iface)
39 {
40 return CONTAINING_RECORD(iface, IAMMultiMediaStreamImpl, IAMMultiMediaStream_iface);
41 }
42
43 static const struct IAMMultiMediaStreamVtbl AM_Vtbl;
44
45 HRESULT AM_create(IUnknown *pUnkOuter, LPVOID *ppObj)
46 {
47 IAMMultiMediaStreamImpl* object;
48
49 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
50
51 if( pUnkOuter )
52 return CLASS_E_NOAGGREGATION;
53
54 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAMMultiMediaStreamImpl));
55 if (!object)
56 return E_OUTOFMEMORY;
57
58 object->IAMMultiMediaStream_iface.lpVtbl = &AM_Vtbl;
59 object->ref = 1;
60
61 *ppObj = object;
62
63 return S_OK;
64 }
65
66 /*** IUnknown methods ***/
67 static HRESULT WINAPI IAMMultiMediaStreamImpl_QueryInterface(IAMMultiMediaStream* iface, REFIID riid, void** ppvObject)
68 {
69 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
70
71 TRACE("(%p/%p)->(%s,%p)\n", iface, This, debugstr_guid(riid), ppvObject);
72
73 if (IsEqualGUID(riid, &IID_IUnknown) ||
74 IsEqualGUID(riid, &IID_IMultiMediaStream) ||
75 IsEqualGUID(riid, &IID_IAMMultiMediaStream))
76 {
77 IAMMultiMediaStream_AddRef(iface);
78 *ppvObject = iface;
79 return S_OK;
80 }
81
82 ERR("(%p)->(%s,%p),not found\n",This,debugstr_guid(riid),ppvObject);
83
84 return E_NOINTERFACE;
85 }
86
87 static ULONG WINAPI IAMMultiMediaStreamImpl_AddRef(IAMMultiMediaStream* iface)
88 {
89 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
90
91 TRACE("(%p/%p)\n", iface, This);
92
93 return InterlockedIncrement(&This->ref);
94 }
95
96 static ULONG WINAPI IAMMultiMediaStreamImpl_Release(IAMMultiMediaStream* iface)
97 {
98 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
99 ULONG ref = InterlockedDecrement(&This->ref);
100 ULONG i;
101
102 TRACE("(%p/%p)\n", iface, This);
103
104 if (!ref)
105 {
106 for(i = 0; i < This->nbStreams; i++)
107 IMediaStream_Release(This->pStreams[i]);
108 if (This->ipin)
109 IPin_Release(This->ipin);
110 if (This->media_stream_filter)
111 IBaseFilter_Release(This->media_stream_filter);
112 if (This->media_seeking)
113 IMediaSeeking_Release(This->media_seeking);
114 if (This->media_control)
115 IMediaControl_Release(This->media_control);
116 if (This->pFilterGraph)
117 IGraphBuilder_Release(This->pFilterGraph);
118 HeapFree(GetProcessHeap(), 0, This);
119 }
120
121 return ref;
122 }
123
124 /*** IMultiMediaStream methods ***/
125 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetInformation(IAMMultiMediaStream* iface, DWORD* pdwFlags, STREAM_TYPE* pStreamType)
126 {
127 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
128
129 FIXME("(%p/%p)->(%p,%p) stub!\n", This, iface, pdwFlags, pStreamType);
130
131 return E_NOTIMPL;
132 }
133
134 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetMediaStream(IAMMultiMediaStream* iface, REFMSPID idPurpose, IMediaStream** ppMediaStream)
135 {
136 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
137 MSPID PurposeId;
138 unsigned int i;
139
140 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_guid(idPurpose), ppMediaStream);
141
142 for (i = 0; i < This->nbStreams; i++)
143 {
144 IMediaStream_GetInformation(This->pStreams[i], &PurposeId, NULL);
145 if (IsEqualIID(&PurposeId, idPurpose))
146 {
147 *ppMediaStream = This->pStreams[i];
148 IMediaStream_AddRef(*ppMediaStream);
149 return S_OK;
150 }
151 }
152
153 return MS_E_NOSTREAM;
154 }
155
156 static HRESULT WINAPI IAMMultiMediaStreamImpl_EnumMediaStreams(IAMMultiMediaStream* iface, LONG Index, IMediaStream** ppMediaStream)
157 {
158 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
159
160 FIXME("(%p/%p)->(%d,%p) stub!\n", This, iface, Index, ppMediaStream);
161
162 return E_NOTIMPL;
163 }
164
165 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetState(IAMMultiMediaStream* iface, STREAM_STATE* pCurrentState)
166 {
167 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
168
169 FIXME("(%p/%p)->(%p) stub!\n", This, iface, pCurrentState);
170
171 return E_NOTIMPL;
172 }
173
174 static HRESULT WINAPI IAMMultiMediaStreamImpl_SetState(IAMMultiMediaStream* iface, STREAM_STATE new_state)
175 {
176 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
177 HRESULT hr = E_INVALIDARG;
178
179 TRACE("(%p/%p)->(%u)\n", This, iface, new_state);
180
181 if (new_state == STREAMSTATE_RUN)
182 hr = IMediaControl_Run(This->media_control);
183 else if (new_state == STREAMSTATE_STOP)
184 hr = IMediaControl_Stop(This->media_control);
185
186 return hr;
187 }
188
189 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetTime(IAMMultiMediaStream* iface, STREAM_TIME* pCurrentTime)
190 {
191 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
192
193 FIXME("(%p/%p)->(%p) stub!\n", This, iface, pCurrentTime);
194
195 return E_NOTIMPL;
196 }
197
198 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetDuration(IAMMultiMediaStream* iface, STREAM_TIME* pDuration)
199 {
200 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
201
202 FIXME("(%p/%p)->(%p) stub!\n", This, iface, pDuration);
203
204 return E_NOTIMPL;
205 }
206
207 static HRESULT WINAPI IAMMultiMediaStreamImpl_Seek(IAMMultiMediaStream* iface, STREAM_TIME seek_time)
208 {
209 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
210
211 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(seek_time));
212
213 return IMediaSeeking_SetPositions(This->media_seeking, &seek_time, AM_SEEKING_AbsolutePositioning, NULL, AM_SEEKING_NoPositioning);
214 }
215
216 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetEndOfStream(IAMMultiMediaStream* iface, HANDLE* phEOS)
217 {
218 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
219
220 FIXME("(%p/%p)->(%p) stub!\n", This, iface, phEOS);
221
222 return E_NOTIMPL;
223 }
224
225 /*** IAMMultiMediaStream methods ***/
226 static HRESULT WINAPI IAMMultiMediaStreamImpl_Initialize(IAMMultiMediaStream* iface, STREAM_TYPE StreamType, DWORD dwFlags, IGraphBuilder* pFilterGraph)
227 {
228 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
229 HRESULT hr = S_OK;
230 const WCHAR filternameW[] = {'M','e','d','i','a','S','t','r','e','a','m','F','i','l','t','e','r',0};
231
232 TRACE("(%p/%p)->(%x,%x,%p)\n", This, iface, (DWORD)StreamType, dwFlags, pFilterGraph);
233
234 if (pFilterGraph)
235 {
236 This->pFilterGraph = pFilterGraph;
237 IGraphBuilder_AddRef(This->pFilterGraph);
238 }
239 else
240 {
241 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, &IID_IGraphBuilder, (LPVOID*)&This->pFilterGraph);
242 }
243
244 if (SUCCEEDED(hr))
245 {
246 This->StreamType = StreamType;
247 hr = IGraphBuilder_QueryInterface(This->pFilterGraph, &IID_IMediaSeeking, (void**)&This->media_seeking);
248 if (SUCCEEDED(hr))
249 IGraphBuilder_QueryInterface(This->pFilterGraph, &IID_IMediaControl, (void**)&This->media_control);
250 if (SUCCEEDED(hr))
251 hr = CoCreateInstance(&CLSID_MediaStreamFilter, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&This->media_stream_filter);
252 if (SUCCEEDED(hr))
253 IGraphBuilder_AddFilter(This->pFilterGraph, This->media_stream_filter, filternameW);
254 if (SUCCEEDED(hr))
255 {
256 IMediaEventEx* media_event = NULL;
257 hr = IGraphBuilder_QueryInterface(This->pFilterGraph, &IID_IMediaEventEx, (void**)&media_event);
258 if (SUCCEEDED(hr))
259 hr = IMediaEventEx_GetEventHandle(media_event, &This->event);
260 if (SUCCEEDED(hr))
261 hr = IMediaEventEx_SetNotifyFlags(media_event, AM_MEDIAEVENT_NONOTIFY);
262 if (media_event)
263 IMediaEventEx_Release(media_event);
264 }
265 }
266
267 if (FAILED(hr))
268 {
269 if (This->media_stream_filter)
270 IBaseFilter_Release(This->media_stream_filter);
271 This->media_stream_filter = NULL;
272 if (This->media_seeking)
273 IMediaSeeking_Release(This->media_seeking);
274 This->media_seeking = NULL;
275 if (This->media_control)
276 IMediaControl_Release(This->media_control);
277 This->media_control = NULL;
278 if (This->pFilterGraph)
279 IGraphBuilder_Release(This->pFilterGraph);
280 This->pFilterGraph = NULL;
281 }
282
283 return hr;
284 }
285
286 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetFilterGraph(IAMMultiMediaStream* iface, IGraphBuilder** ppGraphBuilder)
287 {
288 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
289
290 TRACE("(%p/%p)->(%p)\n", This, iface, ppGraphBuilder);
291
292 if (!ppGraphBuilder)
293 return E_POINTER;
294
295 if (This->pFilterGraph)
296 return IGraphBuilder_QueryInterface(This->pFilterGraph, &IID_IGraphBuilder, (void**)ppGraphBuilder);
297 else
298 *ppGraphBuilder = NULL;
299
300 return S_OK;
301 }
302
303 static HRESULT WINAPI IAMMultiMediaStreamImpl_GetFilter(IAMMultiMediaStream* iface, IMediaStreamFilter** ppFilter)
304 {
305 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
306 HRESULT hr = S_OK;
307
308 TRACE("(%p/%p)->(%p)\n", This, iface, ppFilter);
309
310 if (!ppFilter)
311 return E_POINTER;
312
313 *ppFilter = NULL;
314
315 if (This->media_stream_filter)
316 hr = IBaseFilter_QueryInterface(This->media_stream_filter, &IID_IMediaStreamFilter, (LPVOID*)ppFilter);
317
318 return hr;
319 }
320
321 static HRESULT WINAPI IAMMultiMediaStreamImpl_AddMediaStream(IAMMultiMediaStream* iface, IUnknown* stream_object, const MSPID* PurposeId,
322 DWORD dwFlags, IMediaStream** ppNewStream)
323 {
324 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
325 HRESULT hr;
326 IMediaStream* pStream;
327 IMediaStream** pNewStreams;
328
329 TRACE("(%p/%p)->(%p,%s,%x,%p)\n", This, iface, stream_object, debugstr_guid(PurposeId), dwFlags, ppNewStream);
330
331 if (!IsEqualGUID(PurposeId, &MSPID_PrimaryVideo) && !IsEqualGUID(PurposeId, &MSPID_PrimaryAudio))
332 return MS_E_PURPOSEID;
333
334 if (stream_object)
335 FIXME("Specifying a stream object in params is not yet supported\n");
336
337 if (dwFlags & AMMSF_ADDDEFAULTRENDERER)
338 {
339 if (IsEqualGUID(PurposeId, &MSPID_PrimaryVideo))
340 {
341 /* Default renderer not supported by video stream */
342 return MS_E_PURPOSEID;
343 }
344 else
345 {
346 IBaseFilter* dsoundrender_filter;
347
348 /* Create the default renderer for audio */
349 hr = CoCreateInstance(&CLSID_DSoundRender, NULL, CLSCTX_INPROC_SERVER, &IID_IBaseFilter, (LPVOID*)&dsoundrender_filter);
350 if (SUCCEEDED(hr))
351 {
352 hr = IGraphBuilder_AddFilter(This->pFilterGraph, dsoundrender_filter, NULL);
353 IBaseFilter_Release(dsoundrender_filter);
354 }
355
356 /* No media stream created when the default renderer is used */
357 return hr;
358 }
359 }
360
361 if (IsEqualGUID(PurposeId, &MSPID_PrimaryVideo))
362 hr = ddrawmediastream_create((IMultiMediaStream*)iface, PurposeId, This->StreamType, &pStream);
363 else
364 hr = audiomediastream_create((IMultiMediaStream*)iface, PurposeId, This->StreamType, &pStream);
365 if (SUCCEEDED(hr))
366 {
367 pNewStreams = CoTaskMemRealloc(This->pStreams, (This->nbStreams+1) * sizeof(IMediaStream*));
368 if (!pNewStreams)
369 {
370 IMediaStream_Release(pStream);
371 return E_OUTOFMEMORY;
372 }
373 This->pStreams = pNewStreams;
374 This->pStreams[This->nbStreams] = pStream;
375 This->nbStreams++;
376
377 if (ppNewStream)
378 *ppNewStream = pStream;
379 }
380
381 if (SUCCEEDED(hr))
382 {
383 /* Add stream to the media stream filter */
384 IMediaStreamFilter_AddMediaStream((IMediaStreamFilter*)This->media_stream_filter, (IAMMediaStream*)pStream);
385 }
386
387 return hr;
388 }
389
390 static HRESULT WINAPI IAMMultiMediaStreamImpl_OpenFile(IAMMultiMediaStream* iface, LPCWSTR filename, DWORD flags)
391 {
392 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
393 HRESULT ret = S_OK;
394 IBaseFilter *BaseFilter = NULL;
395 IEnumPins *EnumPins = NULL;
396 IPin *ipin;
397 PIN_DIRECTION pin_direction;
398 const WCHAR sourceW[] = {'S','o','u','r','c','e',0};
399
400 TRACE("(%p/%p)->(%s,%x)\n", This, iface, debugstr_w(filename), flags);
401
402 if (!filename)
403 return E_POINTER;
404
405 /* If Initialize was not called before, we do it here */
406 if (!This->pFilterGraph)
407 ret = IAMMultiMediaStream_Initialize(iface, STREAMTYPE_READ, 0, NULL);
408
409 if (SUCCEEDED(ret))
410 ret = IGraphBuilder_AddSourceFilter(This->pFilterGraph, filename, sourceW, &BaseFilter);
411
412 if (SUCCEEDED(ret))
413 ret = IBaseFilter_EnumPins(BaseFilter, &EnumPins);
414
415 if (SUCCEEDED(ret))
416 ret = IEnumPins_Next(EnumPins, 1, &ipin, NULL);
417
418 if (SUCCEEDED(ret))
419 {
420 ret = IPin_QueryDirection(ipin, &pin_direction);
421 if (ret == S_OK && pin_direction == PINDIR_OUTPUT)
422 This->ipin = ipin;
423 }
424
425 if (SUCCEEDED(ret) && !(flags & AMMSF_NORENDER))
426 ret = IGraphBuilder_Render(This->pFilterGraph, This->ipin);
427
428 if (EnumPins)
429 IEnumPins_Release(EnumPins);
430 if (BaseFilter)
431 IBaseFilter_Release(BaseFilter);
432 return ret;
433 }
434
435 static HRESULT WINAPI IAMMultiMediaStreamImpl_OpenMoniker(IAMMultiMediaStream* iface, IBindCtx* pCtx, IMoniker* pMoniker, DWORD dwFlags)
436 {
437 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
438
439 FIXME("(%p/%p)->(%p,%p,%x) stub!\n", This, iface, pCtx, pMoniker, dwFlags);
440
441 return E_NOTIMPL;
442 }
443
444 static HRESULT WINAPI IAMMultiMediaStreamImpl_Render(IAMMultiMediaStream* iface, DWORD dwFlags)
445 {
446 IAMMultiMediaStreamImpl *This = impl_from_IAMMultiMediaStream(iface);
447
448 FIXME("(%p/%p)->(%x) partial stub!\n", This, iface, dwFlags);
449
450 if(dwFlags != AMMSF_NOCLOCK)
451 return E_INVALIDARG;
452
453 return IGraphBuilder_Render(This->pFilterGraph, This->ipin);
454 }
455
456 static const IAMMultiMediaStreamVtbl AM_Vtbl =
457 {
458 IAMMultiMediaStreamImpl_QueryInterface,
459 IAMMultiMediaStreamImpl_AddRef,
460 IAMMultiMediaStreamImpl_Release,
461 IAMMultiMediaStreamImpl_GetInformation,
462 IAMMultiMediaStreamImpl_GetMediaStream,
463 IAMMultiMediaStreamImpl_EnumMediaStreams,
464 IAMMultiMediaStreamImpl_GetState,
465 IAMMultiMediaStreamImpl_SetState,
466 IAMMultiMediaStreamImpl_GetTime,
467 IAMMultiMediaStreamImpl_GetDuration,
468 IAMMultiMediaStreamImpl_Seek,
469 IAMMultiMediaStreamImpl_GetEndOfStream,
470 IAMMultiMediaStreamImpl_Initialize,
471 IAMMultiMediaStreamImpl_GetFilterGraph,
472 IAMMultiMediaStreamImpl_GetFilter,
473 IAMMultiMediaStreamImpl_AddMediaStream,
474 IAMMultiMediaStreamImpl_OpenFile,
475 IAMMultiMediaStreamImpl_OpenMoniker,
476 IAMMultiMediaStreamImpl_Render
477 };