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