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
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
;
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
63 static HRESULT WINAPI
TransformFilter_Input_Receive(IPin
*iface
, IMediaSample
*pInSample
)
66 BaseInputPin
* This
= (BaseInputPin
*) iface
;
67 TransformFilter
* pTransform
;
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
);
83 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
85 if (pTransform
->pFuncsTable
->pfnReceive
)
86 hr
= pTransform
->pFuncsTable
->pfnReceive(pTransform
, pInSample
);
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
;
100 if (IsEqualIID(&pmt
->majortype
, &outpmt
->majortype
)
101 && (IsEqualIID(&pmt
->subtype
, &outpmt
->subtype
) || IsEqualIID(&outpmt
->subtype
, &GUID_NULL
)))
106 static IPin
* WINAPI
TransformFilter_GetPin(IBaseFilter
*iface
, int pos
)
108 TransformFilter
*This
= (TransformFilter
*)iface
;
110 if (pos
>= This
->npins
|| pos
< 0)
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
)
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]);
151 ALLOCATOR_PROPERTIES props
;
154 props
.cbBuffer
= 0; /* Will be updated at connection time */
157 hr
= BaseOutputPin_Construct(&TransformFilter_OutputPin_Vtbl
, sizeof(BaseOutputPin
), &piOutput
, &props
, NULL
, &pTransformFilter
->filter
.csFilter
, &pTransformFilter
->ppPins
[1]);
160 ERR("Cannot create output pin (%x)\n", hr
);
164 CoTaskMemFree(pTransformFilter
->ppPins
);
165 BaseFilterImpl_Release((IBaseFilter
*)pTransformFilter
);
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
);
183 return E_OUTOFMEMORY
;
185 if (SUCCEEDED(TransformFilter_Init(pVtbl
, pClsid
, pFuncsTable
, pTf
)))
187 *ppTransformFilter
= (IBaseFilter
*)(&pTf
->filter
.lpVtbl
);
195 HRESULT WINAPI
TransformFilterImpl_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
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
));
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);
220 for (i
= 0; i
< This
->npins
; i
++)
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
);
246 /** IMediaFilter methods **/
248 HRESULT WINAPI
TransformFilterImpl_Stop(IBaseFilter
* iface
)
250 TransformFilter
*This
= (TransformFilter
*)iface
;
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
);
266 HRESULT WINAPI
TransformFilterImpl_Pause(IBaseFilter
* iface
)
268 TransformFilter
*This
= (TransformFilter
*)iface
;
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);
281 This
->filter
.state
= State_Paused
;
283 LeaveCriticalSection(&This
->filter
.csFilter
);
288 HRESULT WINAPI
TransformFilterImpl_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
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
);
303 hr
= BaseOutputPinImpl_Active((BaseOutputPin
*)This
->ppPins
[1]);
308 This
->filter
.rtStreamStart
= tStart
;
309 This
->filter
.state
= State_Running
;
312 LeaveCriticalSection(&This
->filter
.csFilter
);
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
);
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
;
354 TRACE("(%p)->()\n", iface
);
356 /* Since we process samples synchronously, just forward notification downstream */
357 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
361 hr
= IPin_ConnectedTo(pTransform
->ppPins
[1], &ppin
);
364 hr
= IPin_EndOfStream(ppin
);
373 static HRESULT WINAPI
TransformFilter_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
375 BaseInputPin
* This
= (BaseInputPin
*) iface
;
376 TransformFilter
* pTransform
;
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
);
391 hr
= BaseInputPinImpl_ReceiveConnection(iface
, pReceivePin
, pmt
);
392 if (FAILED(hr
) && pTransform
->pFuncsTable
->pfnBreakConnect
)
393 pTransform
->pFuncsTable
->pfnBreakConnect(pTransform
, PINDIR_INPUT
);
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
;
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
);
426 hr
= BaseInputPinImpl_BeginFlush(iface
);
427 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
431 static HRESULT WINAPI
TransformFilter_InputPin_EndFlush(IPin
* iface
)
433 BaseInputPin
* This
= (BaseInputPin
*) iface
;
434 TransformFilter
* pTransform
;
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
);
444 hr
= BaseInputPinImpl_EndFlush(iface
);
445 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
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
;
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
);
462 hr
= BaseInputPinImpl_NewSegment(iface
, tStart
, tStop
, dRate
);
463 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
467 static const IPinVtbl TransformFilter_InputPin_Vtbl
=
469 BaseInputPinImpl_QueryInterface
,
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
,
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
;
497 return VFW_S_NO_MORE_ITEMS
;
498 CopyMediaType(pmt
, &pTransform
->pmt
);
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
,
514 BaseOutputPinImpl_Release
,
515 BaseOutputPinImpl_Connect
,
516 BaseOutputPinImpl_ReceiveConnection
,
517 BaseOutputPinImpl_Disconnect
,
518 BasePinImpl_ConnectedTo
,
519 BasePinImpl_ConnectionMediaType
,
520 BasePinImpl_QueryPinInfo
,
521 BasePinImpl_QueryDirection
,
523 TransformFilter_Output_QueryAccept
,
524 TransformFilter_Output_EnumMediaTypes
,
525 BasePinImpl_QueryInternalConnections
,
526 BaseOutputPinImpl_EndOfStream
,
527 BaseOutputPinImpl_BeginFlush
,
528 BaseOutputPinImpl_EndFlush
,
529 BaseOutputPinImpl_NewSegment