winealsa.drv: Rewrite channel counting for additional readability and circumvention...
[wine.git] / dlls / strmbase / transform.c
blob54f4aac72aa0e0fdd72c55eedfab6cd80fd57fb1
1 /*
2 * Transform Filter (Base for decoders, etc...)
4 * Copyright 2005 Christian Costa
5 * Copyright 2010 Aric Stewart, CodeWeavers
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
21 #include "config.h"
22 #include <stdarg.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "dshow.h"
29 #include "amvideo.h"
30 #include "strmif.h"
31 #include "vfw.h"
33 #include <assert.h>
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
37 #include "wine/strmbase.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(strmbase);
41 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
42 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
44 static const IBaseFilterVtbl TransformFilter_Vtbl;
45 static const IPinVtbl TransformFilter_InputPin_Vtbl;
46 static const IPinVtbl TransformFilter_OutputPin_Vtbl;
48 static HRESULT WINAPI TransformFilter_Input_CheckMediaType(IPin *iface, const AM_MEDIA_TYPE * pmt)
50 BaseInputPin* This = (BaseInputPin*) iface;
51 TransformFilter * pTransform;
53 TRACE("%p\n", iface);
54 pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
56 if (pTransform->pFuncsTable->pfnCheckInputType)
57 return pTransform->pFuncsTable->pfnCheckInputType(pTransform, pmt);
58 /* Assume OK if there's no query method (the connection will fail if
59 needed) */
60 return S_OK;
63 static HRESULT WINAPI TransformFilter_Input_Receive(IPin *iface, IMediaSample *pInSample)
65 HRESULT hr = S_FALSE;
66 BaseInputPin* This = (BaseInputPin*) iface;
67 TransformFilter * pTransform;
68 TRACE("%p\n", iface);
69 pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
71 EnterCriticalSection(&pTransform->filter.csFilter);
72 if (pTransform->filter.state == State_Stopped)
74 LeaveCriticalSection(&pTransform->filter.csFilter);
75 return VFW_E_WRONG_STATE;
78 if (This->end_of_stream || This->flushing)
80 LeaveCriticalSection(&pTransform->filter.csFilter);
81 return S_FALSE;
83 LeaveCriticalSection(&pTransform->filter.csFilter);
85 if (pTransform->pFuncsTable->pfnReceive)
86 hr = pTransform->pFuncsTable->pfnReceive(pTransform, pInSample);
87 else
88 hr = S_FALSE;
90 return hr;
93 static HRESULT WINAPI TransformFilter_Output_QueryAccept(IPin *iface, const AM_MEDIA_TYPE * pmt)
95 BasePin *This = (BasePin *)iface;
96 TransformFilter *pTransformFilter = (TransformFilter *)This->pinInfo.pFilter;
97 AM_MEDIA_TYPE* outpmt = &pTransformFilter->pmt;
98 TRACE("%p\n", iface);
100 if (IsEqualIID(&pmt->majortype, &outpmt->majortype)
101 && (IsEqualIID(&pmt->subtype, &outpmt->subtype) || IsEqualIID(&outpmt->subtype, &GUID_NULL)))
102 return S_OK;
103 return S_FALSE;
106 static IPin* WINAPI TransformFilter_GetPin(IBaseFilter *iface, int pos)
108 TransformFilter *This = (TransformFilter *)iface;
110 if (pos >= This->npins || pos < 0)
111 return NULL;
113 IPin_AddRef(This->ppPins[pos]);
114 return This->ppPins[pos];
117 static LONG WINAPI TransformFilter_GetPinCount(IBaseFilter *iface)
119 TransformFilter *This = (TransformFilter *)iface;
121 return (This->npins+1);
124 static HRESULT TransformFilter_Init(const IBaseFilterVtbl *pVtbl, const CLSID* pClsid, const TransformFilterFuncTable* pFuncsTable, TransformFilter* pTransformFilter)
126 HRESULT hr;
127 PIN_INFO piInput;
128 PIN_INFO piOutput;
130 BaseFilter_Init(&pTransformFilter->filter, pVtbl, pClsid, (DWORD_PTR)(__FILE__ ": TransformFilter.csFilter"), TransformFilter_GetPin, TransformFilter_GetPinCount);
132 /* pTransformFilter is already allocated */
133 pTransformFilter->pFuncsTable = pFuncsTable;
134 ZeroMemory(&pTransformFilter->pmt, sizeof(pTransformFilter->pmt));
135 pTransformFilter->npins = 2;
137 pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
139 /* construct input pin */
140 piInput.dir = PINDIR_INPUT;
141 piInput.pFilter = (IBaseFilter *)pTransformFilter;
142 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
143 piOutput.dir = PINDIR_OUTPUT;
144 piOutput.pFilter = (IBaseFilter *)pTransformFilter;
145 lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
147 hr = BaseInputPin_Construct(&TransformFilter_InputPin_Vtbl, &piInput, TransformFilter_Input_CheckMediaType, TransformFilter_Input_Receive, &pTransformFilter->filter.csFilter, NULL, &pTransformFilter->ppPins[0]);
149 if (SUCCEEDED(hr))
151 ALLOCATOR_PROPERTIES props;
152 props.cbAlign = 1;
153 props.cbPrefix = 0;
154 props.cbBuffer = 0; /* Will be updated at connection time */
155 props.cBuffers = 1;
157 hr = BaseOutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(BaseOutputPin), &piOutput, &props, NULL, &pTransformFilter->filter.csFilter, &pTransformFilter->ppPins[1]);
159 if (FAILED(hr))
160 ERR("Cannot create output pin (%x)\n", hr);
162 if (FAILED(hr))
164 CoTaskMemFree(pTransformFilter->ppPins);
165 BaseFilterImpl_Release((IBaseFilter*)pTransformFilter);
168 return hr;
171 HRESULT TransformFilter_Construct(const IBaseFilterVtbl *pVtbl, LONG filter_size, const CLSID* pClsid, const TransformFilterFuncTable* pFuncsTable, IBaseFilter ** ppTransformFilter)
173 TransformFilter* pTf;
175 *ppTransformFilter = NULL;
177 assert(filter_size >= sizeof(TransformFilter));
179 pTf = CoTaskMemAlloc(filter_size);
180 ZeroMemory(pTf, filter_size);
182 if (!pTf)
183 return E_OUTOFMEMORY;
185 if (SUCCEEDED(TransformFilter_Init(pVtbl, pClsid, pFuncsTable, pTf)))
187 *ppTransformFilter = (IBaseFilter*)(&pTf->filter.lpVtbl);
188 return S_OK;
191 CoTaskMemFree(pTf);
192 return E_FAIL;
195 HRESULT WINAPI TransformFilterImpl_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
197 HRESULT hr;
198 TransformFilter *This = (TransformFilter *)iface;
199 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
201 hr = BaseFilterImpl_QueryInterface(iface, riid, ppv);
203 if (FAILED(hr) && (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow)))
204 FIXME("No interface for %s!\n", debugstr_guid(riid));
206 return hr;
209 ULONG WINAPI TransformFilterImpl_Release(IBaseFilter * iface)
211 TransformFilter *This = (TransformFilter *)iface;
212 ULONG refCount = BaseFilterImpl_Release(iface);
214 TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
216 if (!refCount)
218 ULONG i;
220 for (i = 0; i < This->npins; i++)
222 IPin *pConnectedTo;
224 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
226 IPin_Disconnect(pConnectedTo);
227 IPin_Release(pConnectedTo);
229 IPin_Disconnect(This->ppPins[i]);
231 IPin_Release(This->ppPins[i]);
234 CoTaskMemFree(This->ppPins);
236 TRACE("Destroying transform filter\n");
237 FreeMediaType(&This->pmt);
238 CoTaskMemFree(This);
240 return 0;
242 else
243 return refCount;
246 /** IMediaFilter methods **/
248 HRESULT WINAPI TransformFilterImpl_Stop(IBaseFilter * iface)
250 TransformFilter *This = (TransformFilter *)iface;
251 HRESULT hr = S_OK;
253 TRACE("(%p/%p)\n", This, iface);
255 EnterCriticalSection(&This->filter.csFilter);
257 This->filter.state = State_Stopped;
258 if (This->pFuncsTable->pfnStopStreaming)
259 hr = This->pFuncsTable->pfnStopStreaming(This);
261 LeaveCriticalSection(&This->filter.csFilter);
263 return hr;
266 HRESULT WINAPI TransformFilterImpl_Pause(IBaseFilter * iface)
268 TransformFilter *This = (TransformFilter *)iface;
269 HRESULT hr;
271 TRACE("(%p/%p)->()\n", This, iface);
273 EnterCriticalSection(&This->filter.csFilter);
275 if (This->filter.state == State_Stopped)
276 hr = IBaseFilter_Run(iface, -1);
277 else
278 hr = S_OK;
280 if (SUCCEEDED(hr))
281 This->filter.state = State_Paused;
283 LeaveCriticalSection(&This->filter.csFilter);
285 return hr;
288 HRESULT WINAPI TransformFilterImpl_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
290 HRESULT hr = S_OK;
291 TransformFilter *This = (TransformFilter *)iface;
293 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
295 EnterCriticalSection(&This->filter.csFilter);
297 if (This->filter.state == State_Stopped)
299 ((BaseInputPin *)This->ppPins[0])->end_of_stream = 0;
300 if (This->pFuncsTable->pfnStartStreaming)
301 hr = This->pFuncsTable->pfnStartStreaming(This);
302 if (SUCCEEDED(hr))
303 hr = BaseOutputPinImpl_Active((BaseOutputPin *)This->ppPins[1]);
306 if (SUCCEEDED(hr))
308 This->filter.rtStreamStart = tStart;
309 This->filter.state = State_Running;
312 LeaveCriticalSection(&This->filter.csFilter);
314 return hr;
317 /** IBaseFilter implementation **/
319 HRESULT WINAPI TransformFilterImpl_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
321 TransformFilter *This = (TransformFilter *)iface;
323 TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
325 return E_NOTIMPL;
328 static const IBaseFilterVtbl TransformFilter_Vtbl =
330 TransformFilterImpl_QueryInterface,
331 BaseFilterImpl_AddRef,
332 TransformFilterImpl_Release,
333 BaseFilterImpl_GetClassID,
334 TransformFilterImpl_Stop,
335 TransformFilterImpl_Pause,
336 TransformFilterImpl_Run,
337 BaseFilterImpl_GetState,
338 BaseFilterImpl_SetSyncSource,
339 BaseFilterImpl_GetSyncSource,
340 BaseFilterImpl_EnumPins,
341 TransformFilterImpl_FindPin,
342 BaseFilterImpl_QueryFilterInfo,
343 BaseFilterImpl_JoinFilterGraph,
344 BaseFilterImpl_QueryVendorInfo
347 static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface)
349 BaseInputPin* This = (BaseInputPin*) iface;
350 TransformFilter* pTransform;
351 IPin* ppin;
352 HRESULT hr;
354 TRACE("(%p)->()\n", iface);
356 /* Since we process samples synchronously, just forward notification downstream */
357 pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
358 if (!pTransform)
359 hr = E_FAIL;
360 else
361 hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin);
362 if (SUCCEEDED(hr))
364 hr = IPin_EndOfStream(ppin);
365 IPin_Release(ppin);
368 if (FAILED(hr))
369 ERR("%x\n", hr);
370 return hr;
373 static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
375 BaseInputPin* This = (BaseInputPin*) iface;
376 TransformFilter* pTransform;
377 HRESULT hr = S_OK;
379 TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt);
381 pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
383 if (pTransform->pFuncsTable->pfnSetMediaType)
384 hr = pTransform->pFuncsTable->pfnSetMediaType(pTransform, PINDIR_INPUT, pmt);
386 if (SUCCEEDED(hr) && pTransform->pFuncsTable->pfnCompleteConnect)
387 hr = pTransform->pFuncsTable->pfnCompleteConnect(pTransform, PINDIR_INPUT, pReceivePin);
389 if (SUCCEEDED(hr))
391 hr = BaseInputPinImpl_ReceiveConnection(iface, pReceivePin, pmt);
392 if (FAILED(hr) && pTransform->pFuncsTable->pfnBreakConnect)
393 pTransform->pFuncsTable->pfnBreakConnect(pTransform, PINDIR_INPUT);
396 return hr;
399 static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface)
401 BaseInputPin* This = (BaseInputPin*) iface;
402 TransformFilter* pTransform;
404 TRACE("(%p)->()\n", iface);
406 pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
407 if (pTransform->pFuncsTable->pfnBreakConnect)
408 pTransform->pFuncsTable->pfnBreakConnect(pTransform, PINDIR_INPUT);
410 return BasePinImpl_Disconnect(iface);
413 static HRESULT WINAPI TransformFilter_InputPin_BeginFlush(IPin * iface)
415 BaseInputPin* This = (BaseInputPin*) iface;
416 TransformFilter* pTransform;
417 HRESULT hr = S_OK;
419 TRACE("(%p)->()\n", iface);
421 pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
422 EnterCriticalSection(&pTransform->filter.csFilter);
423 if (pTransform->pFuncsTable->pfnBeginFlush)
424 hr = pTransform->pFuncsTable->pfnBeginFlush(pTransform);
425 if (SUCCEEDED(hr))
426 hr = BaseInputPinImpl_BeginFlush(iface);
427 LeaveCriticalSection(&pTransform->filter.csFilter);
428 return hr;
431 static HRESULT WINAPI TransformFilter_InputPin_EndFlush(IPin * iface)
433 BaseInputPin* This = (BaseInputPin*) iface;
434 TransformFilter* pTransform;
435 HRESULT hr = S_OK;
437 TRACE("(%p)->()\n", iface);
439 pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
440 EnterCriticalSection(&pTransform->filter.csFilter);
441 if (pTransform->pFuncsTable->pfnEndFlush)
442 hr = pTransform->pFuncsTable->pfnEndFlush(pTransform);
443 if (SUCCEEDED(hr))
444 hr = BaseInputPinImpl_EndFlush(iface);
445 LeaveCriticalSection(&pTransform->filter.csFilter);
446 return hr;
449 static HRESULT WINAPI TransformFilter_InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
451 BaseInputPin* This = (BaseInputPin*) iface;
452 TransformFilter* pTransform;
453 HRESULT hr = S_OK;
455 TRACE("(%p)->()\n", iface);
457 pTransform = (TransformFilter*)This->pin.pinInfo.pFilter;
458 EnterCriticalSection(&pTransform->filter.csFilter);
459 if (pTransform->pFuncsTable->pfnNewSegment)
460 hr = pTransform->pFuncsTable->pfnNewSegment(pTransform, tStart, tStop, dRate);
461 if (SUCCEEDED(hr))
462 hr = BaseInputPinImpl_NewSegment(iface, tStart, tStop, dRate);
463 LeaveCriticalSection(&pTransform->filter.csFilter);
464 return hr;
467 static const IPinVtbl TransformFilter_InputPin_Vtbl =
469 BaseInputPinImpl_QueryInterface,
470 BasePinImpl_AddRef,
471 BaseInputPinImpl_Release,
472 BaseInputPinImpl_Connect,
473 TransformFilter_InputPin_ReceiveConnection,
474 TransformFilter_InputPin_Disconnect,
475 BasePinImpl_ConnectedTo,
476 BasePinImpl_ConnectionMediaType,
477 BasePinImpl_QueryPinInfo,
478 BasePinImpl_QueryDirection,
479 BasePinImpl_QueryId,
480 BaseInputPinImpl_QueryAccept,
481 BasePinImpl_EnumMediaTypes,
482 BasePinImpl_QueryInternalConnections,
483 TransformFilter_InputPin_EndOfStream,
484 TransformFilter_InputPin_BeginFlush,
485 TransformFilter_InputPin_EndFlush,
486 TransformFilter_InputPin_NewSegment
489 static HRESULT WINAPI TransformFilter_Output_GetMediaType(IPin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
491 BasePin *This = (BasePin *)iface;
492 TransformFilter *pTransform = (TransformFilter *)This->pinInfo.pFilter;
494 if (iPosition < 0)
495 return E_INVALIDARG;
496 if (iPosition > 0)
497 return VFW_S_NO_MORE_ITEMS;
498 CopyMediaType(pmt, &pTransform->pmt);
499 return S_OK;
502 static HRESULT WINAPI TransformFilter_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
504 BasePin *This = (BasePin *)iface;
505 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
507 return EnumMediaTypes_Construct(iface, TransformFilter_Output_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum);
510 static const IPinVtbl TransformFilter_OutputPin_Vtbl =
512 BaseOutputPinImpl_QueryInterface,
513 BasePinImpl_AddRef,
514 BaseOutputPinImpl_Release,
515 BaseOutputPinImpl_Connect,
516 BaseOutputPinImpl_ReceiveConnection,
517 BaseOutputPinImpl_Disconnect,
518 BasePinImpl_ConnectedTo,
519 BasePinImpl_ConnectionMediaType,
520 BasePinImpl_QueryPinInfo,
521 BasePinImpl_QueryDirection,
522 BasePinImpl_QueryId,
523 TransformFilter_Output_QueryAccept,
524 TransformFilter_Output_EnumMediaTypes,
525 BasePinImpl_QueryInternalConnections,
526 BaseOutputPinImpl_EndOfStream,
527 BaseOutputPinImpl_BeginFlush,
528 BaseOutputPinImpl_EndFlush,
529 BaseOutputPinImpl_NewSegment