[AMSTREAM]
[reactos.git] / reactos / 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(iface, IMediaStreamFilterImpl, filter);
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 BaseFilter_Destroy(&This->filter);
241 HeapFree(GetProcessHeap(), 0, This);
242 }
243
244 return ref;
245 }
246
247 /*** IPersist methods ***/
248
249 static HRESULT WINAPI MediaStreamFilterImpl_GetClassID(IMediaStreamFilter *iface, CLSID *clsid)
250 {
251 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
252 return BaseFilterImpl_GetClassID(&This->filter.IBaseFilter_iface, clsid);
253 }
254
255 /*** IBaseFilter methods ***/
256
257 static HRESULT WINAPI MediaStreamFilterImpl_Stop(IMediaStreamFilter *iface)
258 {
259 FIXME("(%p)->(): Stub!\n", iface);
260
261 return E_NOTIMPL;
262 }
263
264 static HRESULT WINAPI MediaStreamFilterImpl_Pause(IMediaStreamFilter *iface)
265 {
266 FIXME("(%p)->(): Stub!\n", iface);
267
268 return E_NOTIMPL;
269 }
270
271 static HRESULT WINAPI MediaStreamFilterImpl_Run(IMediaStreamFilter *iface, REFERENCE_TIME start)
272 {
273 FIXME("(%p)->(%s): Stub!\n", iface, wine_dbgstr_longlong(start));
274
275 return E_NOTIMPL;
276 }
277
278 static HRESULT WINAPI MediaStreamFilterImpl_GetState(IMediaStreamFilter *iface, DWORD ms_timeout, FILTER_STATE *state)
279 {
280 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
281 return BaseFilterImpl_GetState(&This->filter.IBaseFilter_iface, ms_timeout, state);
282 }
283
284 static HRESULT WINAPI MediaStreamFilterImpl_SetSyncSource(IMediaStreamFilter *iface, IReferenceClock *clock)
285 {
286 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
287 return BaseFilterImpl_SetSyncSource(&This->filter.IBaseFilter_iface, clock);
288 }
289
290 static HRESULT WINAPI MediaStreamFilterImpl_GetSyncSource(IMediaStreamFilter *iface, IReferenceClock **clock)
291 {
292 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
293 return BaseFilterImpl_GetSyncSource(&This->filter.IBaseFilter_iface, clock);
294 }
295
296 static HRESULT WINAPI MediaStreamFilterImpl_EnumPins(IMediaStreamFilter *iface, IEnumPins **enum_pins)
297 {
298 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
299 return BaseFilterImpl_EnumPins(&This->filter.IBaseFilter_iface, enum_pins);
300 }
301
302 static HRESULT WINAPI MediaStreamFilterImpl_FindPin(IMediaStreamFilter *iface, LPCWSTR id, IPin **pin)
303 {
304 FIXME("(%p)->(%s,%p): Stub!\n", iface, debugstr_w(id), pin);
305
306 return E_NOTIMPL;
307 }
308
309 static HRESULT WINAPI MediaStreamFilterImpl_QueryFilterInfo(IMediaStreamFilter *iface, FILTER_INFO *info)
310 {
311 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
312 return BaseFilterImpl_QueryFilterInfo(&This->filter.IBaseFilter_iface, info);
313 }
314
315 static HRESULT WINAPI MediaStreamFilterImpl_JoinFilterGraph(IMediaStreamFilter *iface, IFilterGraph *graph, LPCWSTR name)
316 {
317 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
318 return BaseFilterImpl_JoinFilterGraph(&This->filter.IBaseFilter_iface, graph, name);
319 }
320
321 static HRESULT WINAPI MediaStreamFilterImpl_QueryVendorInfo(IMediaStreamFilter *iface, LPWSTR *vendor_info)
322 {
323 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
324 return BaseFilterImpl_QueryVendorInfo(&This->filter.IBaseFilter_iface, vendor_info);
325 }
326
327 /*** IMediaStreamFilter methods ***/
328
329 static HRESULT WINAPI MediaStreamFilterImpl_AddMediaStream(IMediaStreamFilter* iface, IAMMediaStream *pAMMediaStream)
330 {
331 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
332 IMediaStream** streams;
333 IPin** pins;
334 MediaStreamFilter_InputPin* pin;
335 HRESULT hr;
336 PIN_INFO info;
337 MSPID purpose_id;
338
339 TRACE("(%p)->(%p)\n", iface, pAMMediaStream);
340
341 streams = CoTaskMemRealloc(This->streams, (This->nb_streams + 1) * sizeof(IMediaStream*));
342 if (!streams)
343 return E_OUTOFMEMORY;
344 This->streams = streams;
345 pins = CoTaskMemRealloc(This->pins, (This->nb_streams + 1) * sizeof(IPin*));
346 if (!pins)
347 return E_OUTOFMEMORY;
348 This->pins = pins;
349 info.pFilter = (IBaseFilter*)&This->filter;
350 info.dir = PINDIR_INPUT;
351 hr = IAMMediaStream_GetInformation(pAMMediaStream, &purpose_id, NULL);
352 if (FAILED(hr))
353 return hr;
354 /* Pin name is "I{guid MSPID_PrimaryVideo or MSPID_PrimaryAudio}" */
355 info.achName[0] = 'I';
356 StringFromGUID2(&purpose_id, info.achName + 1, 40);
357 hr = BaseInputPin_Construct(&MediaStreamFilter_InputPin_Vtbl, sizeof(BaseInputPin), &info,
358 &input_BaseInputFuncTable, &This->filter.csFilter, NULL, &This->pins[This->nb_streams]);
359 if (FAILED(hr))
360 return hr;
361
362 pin = (MediaStreamFilter_InputPin*)This->pins[This->nb_streams];
363 pin->pin.pin.pinInfo.pFilter = (LPVOID)This;
364 This->streams[This->nb_streams] = (IMediaStream*)pAMMediaStream;
365 This->nb_streams++;
366
367 IMediaStream_AddRef((IMediaStream*)pAMMediaStream);
368
369 return S_OK;
370 }
371
372 static HRESULT WINAPI MediaStreamFilterImpl_GetMediaStream(IMediaStreamFilter* iface, REFMSPID idPurpose, IMediaStream **ppMediaStream)
373 {
374 IMediaStreamFilterImpl *This = impl_from_IMediaStreamFilter(iface);
375 MSPID purpose_id;
376 unsigned int i;
377
378 TRACE("(%p)->(%s,%p)\n", iface, debugstr_guid(idPurpose), ppMediaStream);
379
380 for (i = 0; i < This->nb_streams; i++)
381 {
382 IMediaStream_GetInformation(This->streams[i], &purpose_id, NULL);
383 if (IsEqualIID(&purpose_id, idPurpose))
384 {
385 *ppMediaStream = This->streams[i];
386 IMediaStream_AddRef(*ppMediaStream);
387 return S_OK;
388 }
389 }
390
391 return MS_E_NOSTREAM;
392 }
393
394 static HRESULT WINAPI MediaStreamFilterImpl_EnumMediaStreams(IMediaStreamFilter* iface, LONG Index, IMediaStream **ppMediaStream)
395 {
396 FIXME("(%p)->(%d,%p): Stub!\n", iface, Index, ppMediaStream);
397
398 return E_NOTIMPL;
399 }
400
401 static HRESULT WINAPI MediaStreamFilterImpl_SupportSeeking(IMediaStreamFilter* iface, BOOL bRenderer)
402 {
403 FIXME("(%p)->(%d): Stub!\n", iface, bRenderer);
404
405 return E_NOTIMPL;
406 }
407
408 static HRESULT WINAPI MediaStreamFilterImpl_ReferenceTimeToStreamTime(IMediaStreamFilter* iface, REFERENCE_TIME *pTime)
409 {
410 FIXME("(%p)->(%p): Stub!\n", iface, pTime);
411
412 return E_NOTIMPL;
413 }
414
415 static HRESULT WINAPI MediaStreamFilterImpl_GetCurrentStreamTime(IMediaStreamFilter* iface, REFERENCE_TIME *pCurrentStreamTime)
416 {
417 FIXME("(%p)->(%p): Stub!\n", iface, pCurrentStreamTime);
418
419 return E_NOTIMPL;
420 }
421
422 static HRESULT WINAPI MediaStreamFilterImpl_WaitUntil(IMediaStreamFilter* iface, REFERENCE_TIME WaitStreamTime)
423 {
424 FIXME("(%p)->(%s): Stub!\n", iface, wine_dbgstr_longlong(WaitStreamTime));
425
426 return E_NOTIMPL;
427 }
428
429 static HRESULT WINAPI MediaStreamFilterImpl_Flush(IMediaStreamFilter* iface, BOOL bCancelEOS)
430 {
431 FIXME("(%p)->(%d): Stub!\n", iface, bCancelEOS);
432
433 return E_NOTIMPL;
434 }
435
436 static HRESULT WINAPI MediaStreamFilterImpl_EndOfStream(IMediaStreamFilter* iface)
437 {
438 FIXME("(%p)->(): Stub!\n", iface);
439
440 return E_NOTIMPL;
441 }
442
443 static const IMediaStreamFilterVtbl MediaStreamFilter_Vtbl =
444 {
445 MediaStreamFilterImpl_QueryInterface,
446 MediaStreamFilterImpl_AddRef,
447 MediaStreamFilterImpl_Release,
448 MediaStreamFilterImpl_GetClassID,
449 MediaStreamFilterImpl_Stop,
450 MediaStreamFilterImpl_Pause,
451 MediaStreamFilterImpl_Run,
452 MediaStreamFilterImpl_GetState,
453 MediaStreamFilterImpl_SetSyncSource,
454 MediaStreamFilterImpl_GetSyncSource,
455 MediaStreamFilterImpl_EnumPins,
456 MediaStreamFilterImpl_FindPin,
457 MediaStreamFilterImpl_QueryFilterInfo,
458 MediaStreamFilterImpl_JoinFilterGraph,
459 MediaStreamFilterImpl_QueryVendorInfo,
460 MediaStreamFilterImpl_AddMediaStream,
461 MediaStreamFilterImpl_GetMediaStream,
462 MediaStreamFilterImpl_EnumMediaStreams,
463 MediaStreamFilterImpl_SupportSeeking,
464 MediaStreamFilterImpl_ReferenceTimeToStreamTime,
465 MediaStreamFilterImpl_GetCurrentStreamTime,
466 MediaStreamFilterImpl_WaitUntil,
467 MediaStreamFilterImpl_Flush,
468 MediaStreamFilterImpl_EndOfStream
469 };
470
471 static IPin* WINAPI MediaStreamFilterImpl_GetPin(BaseFilter *iface, int pos)
472 {
473 IMediaStreamFilterImpl* This = (IMediaStreamFilterImpl*)iface;
474
475 if (pos < This->nb_streams)
476 {
477 IPin_AddRef(This->pins[pos]);
478 return This->pins[pos];
479 }
480
481 return NULL;
482 }
483
484 static LONG WINAPI MediaStreamFilterImpl_GetPinCount(BaseFilter *iface)
485 {
486 IMediaStreamFilterImpl* This = (IMediaStreamFilterImpl*)iface;
487
488 return This->nb_streams;
489 }
490
491 static const BaseFilterFuncTable BaseFuncTable = {
492 MediaStreamFilterImpl_GetPin,
493 MediaStreamFilterImpl_GetPinCount
494 };
495
496 HRESULT MediaStreamFilter_create(IUnknown *pUnkOuter, void **ppObj)
497 {
498 IMediaStreamFilterImpl* object;
499
500 TRACE("(%p,%p)\n", pUnkOuter, ppObj);
501
502 if( pUnkOuter )
503 return CLASS_E_NOAGGREGATION;
504
505 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IMediaStreamFilterImpl));
506 if (!object)
507 return E_OUTOFMEMORY;
508
509 BaseFilter_Init(&object->filter, (IBaseFilterVtbl*)&MediaStreamFilter_Vtbl, &CLSID_MediaStreamFilter, (DWORD_PTR)(__FILE__ ": MediaStreamFilterImpl.csFilter"), &BaseFuncTable);
510
511 *ppObj = object;
512
513 return S_OK;
514 }