[AMSTREAM] We don't need to define WIDL_C_INLINE_WRAPPERS here anymore.
[reactos.git] / dll / directx / wine / amstream / mediastreamfilter.c
1 /*
2 * Implementation of MediaStream Filter
3 *
4 * Copyright 2008, 2012 Christian Costa
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "amstream_private.h"
22
23 #include <wine/strmbase.h>
24
25 typedef struct MediaStreamFilter_InputPin
26 {
27 BaseInputPin pin;
28 } MediaStreamFilter_InputPin;
29
30 static const IPinVtbl MediaStreamFilter_InputPin_Vtbl =
31 {
32 BaseInputPinImpl_QueryInterface,
33 BasePinImpl_AddRef,
34 BaseInputPinImpl_Release,
35 BaseInputPinImpl_Connect,
36 BaseInputPinImpl_ReceiveConnection,
37 BasePinImpl_Disconnect,
38 BasePinImpl_ConnectedTo,
39 BasePinImpl_ConnectionMediaType,
40 BasePinImpl_QueryPinInfo,
41 BasePinImpl_QueryDirection,
42 BasePinImpl_QueryId,
43 BasePinImpl_QueryAccept,
44 BasePinImpl_EnumMediaTypes,
45 BasePinImpl_QueryInternalConnections,
46 BaseInputPinImpl_EndOfStream,
47 BaseInputPinImpl_BeginFlush,
48 BaseInputPinImpl_EndFlush,
49 BasePinImpl_NewSegment
50 };
51
52 typedef struct {
53 BaseFilter filter;
54 ULONG nb_streams;
55 IMediaStream** streams;
56 IPin** pins;
57 } IMediaStreamFilterImpl;
58
59 static inline IMediaStreamFilterImpl *impl_from_IMediaStreamFilter(IMediaStreamFilter *iface)
60 {
61 return CONTAINING_RECORD((IBaseFilter *)iface, IMediaStreamFilterImpl, filter.IBaseFilter_iface);
62 }
63
64 static HRESULT WINAPI BasePinImpl_CheckMediaType(BasePin *This, const AM_MEDIA_TYPE *pmt)
65 {
66 IMediaStreamFilterImpl *filter = impl_from_IMediaStreamFilter((IMediaStreamFilter*)This->pinInfo.pFilter);
67 MSPID purpose_id;
68 ULONG i;
69
70 TRACE("Checking media type %s - %s\n", debugstr_guid(&pmt->majortype), debugstr_guid(&pmt->subtype));
71
72 /* Find which stream is associated with the pin */
73 for (i = 0; i < filter->nb_streams; i++)
74 if (&This->IPin_iface == filter->pins[i])
75 break;
76
77 if (i == filter->nb_streams)
78 return S_FALSE;
79
80 if (FAILED(IMediaStream_GetInformation(filter->streams[i], &purpose_id, NULL)))
81 return S_FALSE;
82
83 TRACE("Checking stream with purpose id %s\n", debugstr_guid(&purpose_id));
84
85 if (IsEqualGUID(&purpose_id, &MSPID_PrimaryVideo) && IsEqualGUID(&pmt->majortype, &MEDIATYPE_Video))
86 {
87 if (IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_RGB1) ||
88 IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_RGB4) ||
89 IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_RGB8) ||
90 IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_RGB565) ||
91 IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_RGB555) ||
92 IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_RGB24) ||
93 IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_RGB32))
94 {
95 TRACE("Video sub-type %s matches\n", debugstr_guid(&pmt->subtype));
96 return S_OK;
97 }
98 }
99 else if (IsEqualGUID(&purpose_id, &MSPID_PrimaryAudio) && IsEqualGUID(&pmt->majortype, &MEDIATYPE_Audio))
100 {
101 if (IsEqualGUID(&pmt->subtype, &MEDIASUBTYPE_PCM))
102 {
103 TRACE("Audio sub-type %s matches\n", debugstr_guid(&pmt->subtype));
104 return S_OK;
105 }
106 }
107
108 return S_FALSE;
109 }
110
111 static LONG WINAPI BasePinImp_GetMediaTypeVersion(BasePin *This)
112 {
113 return 0;
114 }
115
116 static HRESULT WINAPI BasePinImp_GetMediaType(BasePin *This, int index, AM_MEDIA_TYPE *amt)
117 {
118 IMediaStreamFilterImpl *filter = (IMediaStreamFilterImpl*)This->pinInfo.pFilter;
119 MSPID purpose_id;
120 ULONG i;
121
122 /* FIXME: Reset structure as we only fill majortype and minortype for now */
123 ZeroMemory(amt, sizeof(*amt));
124
125 /* Find which stream is associated with the pin */
126 for (i = 0; i < filter->nb_streams; i++)
127 if (&This->IPin_iface == filter->pins[i])
128 break;
129
130 if (i == filter->nb_streams)
131 return S_FALSE;
132
133 if (FAILED(IMediaStream_GetInformation(filter->streams[i], &purpose_id, NULL)))
134 return S_FALSE;
135
136 TRACE("Processing stream with purpose id %s\n", debugstr_guid(&purpose_id));
137
138 if (IsEqualGUID(&purpose_id, &MSPID_PrimaryVideo))
139 {
140 amt->majortype = MEDIATYPE_Video;
141
142 switch (index)
143 {
144 case 0:
145 amt->subtype = MEDIASUBTYPE_RGB1;
146 break;
147 case 1:
148 amt->subtype = MEDIASUBTYPE_RGB4;
149 break;
150 case 2:
151 amt->subtype = MEDIASUBTYPE_RGB8;
152 break;
153 case 3:
154 amt->subtype = MEDIASUBTYPE_RGB565;
155 break;
156 case 4:
157 amt->subtype = MEDIASUBTYPE_RGB555;
158 break;
159 case 5:
160 amt->subtype = MEDIASUBTYPE_RGB24;
161 break;
162 case 6:
163 amt->subtype = MEDIASUBTYPE_RGB32;
164 break;
165 default:
166 return S_FALSE;
167 }
168 }
169 else if (IsEqualGUID(&purpose_id, &MSPID_PrimaryAudio))
170 {
171 if (index)
172 return S_FALSE;
173
174 amt->majortype = MEDIATYPE_Audio;
175 amt->subtype = MEDIASUBTYPE_PCM;
176 }
177
178 return S_OK;
179 }
180
181 static const BaseInputPinFuncTable input_BaseInputFuncTable = {
182 {
183 BasePinImpl_CheckMediaType,
184 NULL,
185 BasePinImp_GetMediaTypeVersion,
186 BasePinImp_GetMediaType
187 },
188 NULL
189 };
190
191 /*** IUnknown methods ***/
192
193 static HRESULT WINAPI MediaStreamFilterImpl_QueryInterface(IMediaStreamFilter *iface, REFIID riid, void **ret_iface)
194 {
195 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ret_iface);
196
197 *ret_iface = NULL;
198
199 if (IsEqualIID(riid, &IID_IUnknown) ||
200 IsEqualIID(riid, &IID_IPersist) ||
201 IsEqualIID(riid, &IID_IMediaFilter) ||
202 IsEqualIID(riid, &IID_IBaseFilter) ||
203 IsEqualIID(riid, &IID_IMediaStreamFilter))
204 *ret_iface = iface;
205
206 if (*ret_iface)
207 {
208 IMediaStreamFilter_AddRef(*ret_iface);
209 return S_OK;
210 }
211
212 return E_NOINTERFACE;
213 }
214
215 static ULONG WINAPI MediaStreamFilterImpl_AddRef(IMediaStreamFilter *iface)
216 {
217 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
218 ULONG ref = BaseFilterImpl_AddRef(&This->filter.IBaseFilter_iface);
219
220 TRACE("(%p)->(): new ref = %u\n", iface, ref);
221
222 return ref;
223 }
224
225 static ULONG WINAPI MediaStreamFilterImpl_Release(IMediaStreamFilter *iface)
226 {
227 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
228 ULONG ref = InterlockedDecrement(&This->filter.refCount);
229
230 TRACE("(%p)->(): new ref = %u\n", iface, ref);
231
232 if (!ref)
233 {
234 ULONG i;
235 for (i = 0; i < This->nb_streams; i++)
236 {
237 IMediaStream_Release(This->streams[i]);
238 IPin_Release(This->pins[i]);
239 }
240 CoTaskMemFree(This->streams);
241 CoTaskMemFree(This->pins);
242 BaseFilter_Destroy(&This->filter);
243 HeapFree(GetProcessHeap(), 0, This);
244 }
245
246 return ref;
247 }
248
249 /*** IPersist methods ***/
250
251 static HRESULT WINAPI MediaStreamFilterImpl_GetClassID(IMediaStreamFilter *iface, CLSID *clsid)
252 {
253 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
254 return BaseFilterImpl_GetClassID(&This->filter.IBaseFilter_iface, clsid);
255 }
256
257 /*** IBaseFilter methods ***/
258
259 static HRESULT WINAPI MediaStreamFilterImpl_Stop(IMediaStreamFilter *iface)
260 {
261 FIXME("(%p)->(): Stub!\n", iface);
262
263 return E_NOTIMPL;
264 }
265
266 static HRESULT WINAPI MediaStreamFilterImpl_Pause(IMediaStreamFilter *iface)
267 {
268 FIXME("(%p)->(): Stub!\n", iface);
269
270 return E_NOTIMPL;
271 }
272
273 static HRESULT WINAPI MediaStreamFilterImpl_Run(IMediaStreamFilter *iface, REFERENCE_TIME start)
274 {
275 FIXME("(%p)->(%s): Stub!\n", iface, wine_dbgstr_longlong(start));
276
277 return E_NOTIMPL;
278 }
279
280 static HRESULT WINAPI MediaStreamFilterImpl_GetState(IMediaStreamFilter *iface, DWORD ms_timeout, FILTER_STATE *state)
281 {
282 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
283 return BaseFilterImpl_GetState(&This->filter.IBaseFilter_iface, ms_timeout, state);
284 }
285
286 static HRESULT WINAPI MediaStreamFilterImpl_SetSyncSource(IMediaStreamFilter *iface, IReferenceClock *clock)
287 {
288 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
289 return BaseFilterImpl_SetSyncSource(&This->filter.IBaseFilter_iface, clock);
290 }
291
292 static HRESULT WINAPI MediaStreamFilterImpl_GetSyncSource(IMediaStreamFilter *iface, IReferenceClock **clock)
293 {
294 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
295 return BaseFilterImpl_GetSyncSource(&This->filter.IBaseFilter_iface, clock);
296 }
297
298 static HRESULT WINAPI MediaStreamFilterImpl_EnumPins(IMediaStreamFilter *iface, IEnumPins **enum_pins)
299 {
300 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
301 return BaseFilterImpl_EnumPins(&This->filter.IBaseFilter_iface, enum_pins);
302 }
303
304 static HRESULT WINAPI MediaStreamFilterImpl_FindPin(IMediaStreamFilter *iface, LPCWSTR id, IPin **pin)
305 {
306 FIXME("(%p)->(%s,%p): Stub!\n", iface, debugstr_w(id), pin);
307
308 return E_NOTIMPL;
309 }
310
311 static HRESULT WINAPI MediaStreamFilterImpl_QueryFilterInfo(IMediaStreamFilter *iface, FILTER_INFO *info)
312 {
313 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
314 return BaseFilterImpl_QueryFilterInfo(&This->filter.IBaseFilter_iface, info);
315 }
316
317 static HRESULT WINAPI MediaStreamFilterImpl_JoinFilterGraph(IMediaStreamFilter *iface, IFilterGraph *graph, LPCWSTR name)
318 {
319 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
320 return BaseFilterImpl_JoinFilterGraph(&This->filter.IBaseFilter_iface, graph, name);
321 }
322
323 static HRESULT WINAPI MediaStreamFilterImpl_QueryVendorInfo(IMediaStreamFilter *iface, LPWSTR *vendor_info)
324 {
325 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
326 return BaseFilterImpl_QueryVendorInfo(&This->filter.IBaseFilter_iface, vendor_info);
327 }
328
329 /*** IMediaStreamFilter methods ***/
330
331 static HRESULT WINAPI MediaStreamFilterImpl_AddMediaStream(IMediaStreamFilter* iface, IAMMediaStream *pAMMediaStream)
332 {
333 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
334 IMediaStream** streams;
335 IPin** pins;
336 MediaStreamFilter_InputPin* pin;
337 HRESULT hr;
338 PIN_INFO info;
339 MSPID purpose_id;
340
341 TRACE("(%p)->(%p)\n", iface, pAMMediaStream);
342
343 streams = CoTaskMemRealloc(This->streams, (This->nb_streams + 1) * sizeof(IMediaStream*));
344 if (!streams)
345 return E_OUTOFMEMORY;
346 This->streams = streams;
347 pins = CoTaskMemRealloc(This->pins, (This->nb_streams + 1) * sizeof(IPin*));
348 if (!pins)
349 return E_OUTOFMEMORY;
350 This->pins = pins;
351 info.pFilter = &This->filter.IBaseFilter_iface;
352 info.dir = PINDIR_INPUT;
353 hr = IAMMediaStream_GetInformation(pAMMediaStream, &purpose_id, NULL);
354 if (FAILED(hr))
355 return hr;
356 /* Pin name is "I{guid MSPID_PrimaryVideo or MSPID_PrimaryAudio}" */
357 info.achName[0] = 'I';
358 StringFromGUID2(&purpose_id, info.achName + 1, 40);
359 hr = BaseInputPin_Construct(&MediaStreamFilter_InputPin_Vtbl, sizeof(BaseInputPin), &info,
360 &input_BaseInputFuncTable, &This->filter.csFilter, NULL, &This->pins[This->nb_streams]);
361 if (FAILED(hr))
362 return hr;
363
364 pin = (MediaStreamFilter_InputPin*)This->pins[This->nb_streams];
365 pin->pin.pin.pinInfo.pFilter = &This->filter.IBaseFilter_iface;
366 This->streams[This->nb_streams] = (IMediaStream*)pAMMediaStream;
367 This->nb_streams++;
368
369 IAMMediaStream_AddRef(pAMMediaStream);
370
371 return S_OK;
372 }
373
374 static HRESULT WINAPI MediaStreamFilterImpl_GetMediaStream(IMediaStreamFilter* iface, REFMSPID idPurpose, IMediaStream **ppMediaStream)
375 {
376 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
377 MSPID purpose_id;
378 unsigned int i;
379
380 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(idPurpose), ppMediaStream);
381
382 for (i = 0; i < This->nb_streams; i++)
383 {
384 IMediaStream_GetInformation(This->streams[i], &purpose_id, NULL);
385 if (IsEqualIID(&purpose_id, idPurpose))
386 {
387 *ppMediaStream = This->streams[i];
388 IMediaStream_AddRef(*ppMediaStream);
389 return S_OK;
390 }
391 }
392
393 return MS_E_NOSTREAM;
394 }
395
396 static HRESULT WINAPI MediaStreamFilterImpl_EnumMediaStreams(IMediaStreamFilter* iface, LONG Index, IMediaStream **ppMediaStream)
397 {
398 FIXME("(%p)->(%d,%p): Stub!\n", iface, Index, ppMediaStream);
399
400 return E_NOTIMPL;
401 }
402
403 static HRESULT WINAPI MediaStreamFilterImpl_SupportSeeking(IMediaStreamFilter* iface, BOOL bRenderer)
404 {
405 FIXME("(%p)->(%d): Stub!\n", iface, bRenderer);
406
407 return E_NOTIMPL;
408 }
409
410 static HRESULT WINAPI MediaStreamFilterImpl_ReferenceTimeToStreamTime(IMediaStreamFilter* iface, REFERENCE_TIME *pTime)
411 {
412 FIXME("(%p)->(%p): Stub!\n", iface, pTime);
413
414 return E_NOTIMPL;
415 }
416
417 static HRESULT WINAPI MediaStreamFilterImpl_GetCurrentStreamTime(IMediaStreamFilter* iface, REFERENCE_TIME *pCurrentStreamTime)
418 {
419 FIXME("(%p)->(%p): Stub!\n", iface, pCurrentStreamTime);
420
421 return E_NOTIMPL;
422 }
423
424 static HRESULT WINAPI MediaStreamFilterImpl_WaitUntil(IMediaStreamFilter* iface, REFERENCE_TIME WaitStreamTime)
425 {
426 FIXME("(%p)->(%s): Stub!\n", iface, wine_dbgstr_longlong(WaitStreamTime));
427
428 return E_NOTIMPL;
429 }
430
431 static HRESULT WINAPI MediaStreamFilterImpl_Flush(IMediaStreamFilter* iface, BOOL bCancelEOS)
432 {
433 FIXME("(%p)->(%d): Stub!\n", iface, bCancelEOS);
434
435 return E_NOTIMPL;
436 }
437
438 static HRESULT WINAPI MediaStreamFilterImpl_EndOfStream(IMediaStreamFilter* iface)
439 {
440 FIXME("(%p)->(): Stub!\n", iface);
441
442 return E_NOTIMPL;
443 }
444
445 static const IMediaStreamFilterVtbl MediaStreamFilter_Vtbl =
446 {
447 MediaStreamFilterImpl_QueryInterface,
448 MediaStreamFilterImpl_AddRef,
449 MediaStreamFilterImpl_Release,
450 MediaStreamFilterImpl_GetClassID,
451 MediaStreamFilterImpl_Stop,
452 MediaStreamFilterImpl_Pause,
453 MediaStreamFilterImpl_Run,
454 MediaStreamFilterImpl_GetState,
455 MediaStreamFilterImpl_SetSyncSource,
456 MediaStreamFilterImpl_GetSyncSource,
457 MediaStreamFilterImpl_EnumPins,
458 MediaStreamFilterImpl_FindPin,
459 MediaStreamFilterImpl_QueryFilterInfo,
460 MediaStreamFilterImpl_JoinFilterGraph,
461 MediaStreamFilterImpl_QueryVendorInfo,
462 MediaStreamFilterImpl_AddMediaStream,
463 MediaStreamFilterImpl_GetMediaStream,
464 MediaStreamFilterImpl_EnumMediaStreams,
465 MediaStreamFilterImpl_SupportSeeking,
466 MediaStreamFilterImpl_ReferenceTimeToStreamTime,
467 MediaStreamFilterImpl_GetCurrentStreamTime,
468 MediaStreamFilterImpl_WaitUntil,
469 MediaStreamFilterImpl_Flush,
470 MediaStreamFilterImpl_EndOfStream
471 };
472
473 static IPin* WINAPI MediaStreamFilterImpl_GetPin(BaseFilter *iface, int pos)
474 {
475 IMediaStreamFilterImpl* This = (IMediaStreamFilterImpl*)iface;
476
477 if (pos < This->nb_streams)
478 {
479 IPin_AddRef(This->pins[pos]);
480 return This->pins[pos];
481 }
482
483 return NULL;
484 }
485
486 static LONG WINAPI MediaStreamFilterImpl_GetPinCount(BaseFilter *iface)
487 {
488 IMediaStreamFilterImpl* This = (IMediaStreamFilterImpl*)iface;
489
490 return This->nb_streams;
491 }
492
493 static const BaseFilterFuncTable BaseFuncTable = {
494 MediaStreamFilterImpl_GetPin,
495 MediaStreamFilterImpl_GetPinCount
496 };
497
498 HRESULT MediaStreamFilter_create(IUnknown *pUnkOuter, void **ppObj)
499 {
500 IMediaStreamFilterImpl* object;
501
502 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
503
504 if( pUnkOuter )
505 return CLASS_E_NOAGGREGATION;
506
507 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMediaStreamFilterImpl));
508 if (!object)
509 return E_OUTOFMEMORY;
510
511 BaseFilter_Init(&object->filter, (IBaseFilterVtbl*)&MediaStreamFilter_Vtbl, &CLSID_MediaStreamFilter, (DWORD_PTR)(__FILE__ ": MediaStreamFilterImpl.csFilter"), &BaseFuncTable);
512
513 *ppObj = &object->filter.IBaseFilter_iface;
514
515 return S_OK;
516 }