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
;
47 static const IQualityControlVtbl TransformFilter_QualityControl_Vtbl
;
49 static HRESULT WINAPI
TransformFilter_Input_CheckMediaType(BasePin
*iface
, const AM_MEDIA_TYPE
* pmt
)
51 BaseInputPin
* This
= (BaseInputPin
*) iface
;
52 TransformFilter
* pTransform
;
55 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
57 if (pTransform
->pFuncsTable
->pfnCheckInputType
)
58 return pTransform
->pFuncsTable
->pfnCheckInputType(pTransform
, pmt
);
59 /* Assume OK if there's no query method (the connection will fail if
64 static HRESULT WINAPI
TransformFilter_Input_Receive(BaseInputPin
*This
, IMediaSample
*pInSample
)
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 HRESULT WINAPI
TransformFilter_Output_DecideBufferSize(BaseOutputPin
*This
, IMemAllocator
*pAlloc
, ALLOCATOR_PROPERTIES
*ppropInputRequest
)
108 TransformFilter
*pTransformFilter
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
109 return pTransformFilter
->pFuncsTable
->pfnDecideBufferSize(pTransformFilter
, pAlloc
, ppropInputRequest
);
112 static HRESULT WINAPI
TransformFilter_Output_GetMediaType(BasePin
*This
, int iPosition
, AM_MEDIA_TYPE
*pmt
)
114 TransformFilter
*pTransform
= (TransformFilter
*)This
->pinInfo
.pFilter
;
119 return VFW_S_NO_MORE_ITEMS
;
120 CopyMediaType(pmt
, &pTransform
->pmt
);
124 static IPin
* WINAPI
TransformFilter_GetPin(BaseFilter
*iface
, int pos
)
126 TransformFilter
*This
= (TransformFilter
*)iface
;
128 if (pos
>= This
->npins
|| pos
< 0)
131 IPin_AddRef(This
->ppPins
[pos
]);
132 return This
->ppPins
[pos
];
135 static LONG WINAPI
TransformFilter_GetPinCount(BaseFilter
*iface
)
137 TransformFilter
*This
= (TransformFilter
*)iface
;
139 return (This
->npins
+1);
142 static const BaseFilterFuncTable tfBaseFuncTable
= {
143 TransformFilter_GetPin
,
144 TransformFilter_GetPinCount
147 static const BasePinFuncTable tf_input_BaseFuncTable
= {
148 TransformFilter_Input_CheckMediaType
,
150 BasePinImpl_GetMediaTypeVersion
,
151 BasePinImpl_GetMediaType
154 static const BaseInputPinFuncTable tf_input_BaseInputFuncTable
= {
155 TransformFilter_Input_Receive
158 static const BasePinFuncTable tf_output_BaseFuncTable
= {
160 BaseOutputPinImpl_AttemptConnection
,
161 BasePinImpl_GetMediaTypeVersion
,
162 TransformFilter_Output_GetMediaType
165 static const BaseOutputPinFuncTable tf_output_BaseOutputFuncTable
= {
166 TransformFilter_Output_DecideBufferSize
,
167 BaseOutputPinImpl_DecideAllocator
,
168 BaseOutputPinImpl_BreakConnect
171 static HRESULT
TransformFilter_Init(const IBaseFilterVtbl
*pVtbl
, const CLSID
* pClsid
, const TransformFilterFuncTable
* pFuncsTable
, TransformFilter
* pTransformFilter
)
177 BaseFilter_Init(&pTransformFilter
->filter
, pVtbl
, pClsid
, (DWORD_PTR
)(__FILE__
": TransformFilter.csFilter"), &tfBaseFuncTable
);
179 /* pTransformFilter is already allocated */
180 pTransformFilter
->pFuncsTable
= pFuncsTable
;
181 ZeroMemory(&pTransformFilter
->pmt
, sizeof(pTransformFilter
->pmt
));
182 pTransformFilter
->npins
= 2;
184 pTransformFilter
->ppPins
= CoTaskMemAlloc(2 * sizeof(IPin
*));
186 /* construct input pin */
187 piInput
.dir
= PINDIR_INPUT
;
188 piInput
.pFilter
= (IBaseFilter
*)pTransformFilter
;
189 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
190 piOutput
.dir
= PINDIR_OUTPUT
;
191 piOutput
.pFilter
= (IBaseFilter
*)pTransformFilter
;
192 lstrcpynW(piOutput
.achName
, wcsOutputPinName
, sizeof(piOutput
.achName
) / sizeof(piOutput
.achName
[0]));
194 hr
= BaseInputPin_Construct(&TransformFilter_InputPin_Vtbl
, &piInput
, &tf_input_BaseFuncTable
, &tf_input_BaseInputFuncTable
, &pTransformFilter
->filter
.csFilter
, NULL
, &pTransformFilter
->ppPins
[0]);
198 hr
= BaseOutputPin_Construct(&TransformFilter_OutputPin_Vtbl
, sizeof(BaseOutputPin
), &piOutput
, &tf_output_BaseFuncTable
, &tf_output_BaseOutputFuncTable
, &pTransformFilter
->filter
.csFilter
, &pTransformFilter
->ppPins
[1]);
201 ERR("Cannot create output pin (%x)\n", hr
);
203 QualityControlImpl_init(&pTransformFilter
->qcimpl
, (IPin
*)pTransformFilter
->ppPins
[0], (IBaseFilter
*)pTransformFilter
);
204 pTransformFilter
->qcimpl
.lpVtbl
= &TransformFilter_QualityControl_Vtbl
;
209 CoTaskMemFree(pTransformFilter
->ppPins
);
210 BaseFilterImpl_Release((IBaseFilter
*)pTransformFilter
);
216 HRESULT
TransformFilter_Construct(const IBaseFilterVtbl
*pVtbl
, LONG filter_size
, const CLSID
* pClsid
, const TransformFilterFuncTable
* pFuncsTable
, IBaseFilter
** ppTransformFilter
)
218 TransformFilter
* pTf
;
220 *ppTransformFilter
= NULL
;
222 assert(filter_size
>= sizeof(TransformFilter
));
224 pTf
= CoTaskMemAlloc(filter_size
);
227 return E_OUTOFMEMORY
;
229 ZeroMemory(pTf
, filter_size
);
231 if (SUCCEEDED(TransformFilter_Init(pVtbl
, pClsid
, pFuncsTable
, pTf
)))
233 *ppTransformFilter
= (IBaseFilter
*)(&pTf
->filter
.lpVtbl
);
241 HRESULT WINAPI
TransformFilterImpl_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
244 TransformFilter
*This
= (TransformFilter
*)iface
;
245 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, debugstr_guid(riid
), ppv
);
247 if (IsEqualIID(riid
, &IID_IQualityControl
)) {
248 *ppv
= (IQualityControl
*)&This
->qcimpl
;
249 IUnknown_AddRef((IUnknown
*)*ppv
);
252 hr
= BaseFilterImpl_QueryInterface(iface
, riid
, ppv
);
254 if (FAILED(hr
) && !IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
) &&
255 !IsEqualIID(riid
, &IID_IAMFilterMiscFlags
))
256 FIXME("No interface for %s!\n", debugstr_guid(riid
));
261 ULONG WINAPI
TransformFilterImpl_Release(IBaseFilter
* iface
)
263 TransformFilter
*This
= (TransformFilter
*)iface
;
264 ULONG refCount
= BaseFilterImpl_Release(iface
);
266 TRACE("(%p/%p)->() Release from %d\n", This
, iface
, refCount
+ 1);
272 for (i
= 0; i
< This
->npins
; i
++)
276 if (SUCCEEDED(IPin_ConnectedTo(This
->ppPins
[i
], &pConnectedTo
)))
278 IPin_Disconnect(pConnectedTo
);
279 IPin_Release(pConnectedTo
);
281 IPin_Disconnect(This
->ppPins
[i
]);
283 IPin_Release(This
->ppPins
[i
]);
286 CoTaskMemFree(This
->ppPins
);
288 TRACE("Destroying transform filter\n");
289 FreeMediaType(&This
->pmt
);
298 /** IMediaFilter methods **/
300 HRESULT WINAPI
TransformFilterImpl_Stop(IBaseFilter
* iface
)
302 TransformFilter
*This
= (TransformFilter
*)iface
;
305 TRACE("(%p/%p)\n", This
, iface
);
307 EnterCriticalSection(&This
->filter
.csFilter
);
309 This
->filter
.state
= State_Stopped
;
310 if (This
->pFuncsTable
->pfnStopStreaming
)
311 hr
= This
->pFuncsTable
->pfnStopStreaming(This
);
313 LeaveCriticalSection(&This
->filter
.csFilter
);
318 HRESULT WINAPI
TransformFilterImpl_Pause(IBaseFilter
* iface
)
320 TransformFilter
*This
= (TransformFilter
*)iface
;
323 TRACE("(%p/%p)->()\n", This
, iface
);
325 EnterCriticalSection(&This
->filter
.csFilter
);
327 if (This
->filter
.state
== State_Stopped
)
328 hr
= IBaseFilter_Run(iface
, -1);
333 This
->filter
.state
= State_Paused
;
335 LeaveCriticalSection(&This
->filter
.csFilter
);
340 HRESULT WINAPI
TransformFilterImpl_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
343 TransformFilter
*This
= (TransformFilter
*)iface
;
345 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
347 EnterCriticalSection(&This
->filter
.csFilter
);
349 if (This
->filter
.state
== State_Stopped
)
351 ((BaseInputPin
*)This
->ppPins
[0])->end_of_stream
= 0;
352 if (This
->pFuncsTable
->pfnStartStreaming
)
353 hr
= This
->pFuncsTable
->pfnStartStreaming(This
);
355 hr
= BaseOutputPinImpl_Active((BaseOutputPin
*)This
->ppPins
[1]);
360 This
->filter
.rtStreamStart
= tStart
;
361 This
->filter
.state
= State_Running
;
364 LeaveCriticalSection(&This
->filter
.csFilter
);
369 /** IBaseFilter implementation **/
371 HRESULT WINAPI
TransformFilterImpl_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
373 TransformFilter
*This
= (TransformFilter
*)iface
;
375 TRACE("(%p/%p)->(%p,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
380 static const IBaseFilterVtbl TransformFilter_Vtbl
=
382 TransformFilterImpl_QueryInterface
,
383 BaseFilterImpl_AddRef
,
384 TransformFilterImpl_Release
,
385 BaseFilterImpl_GetClassID
,
386 TransformFilterImpl_Stop
,
387 TransformFilterImpl_Pause
,
388 TransformFilterImpl_Run
,
389 BaseFilterImpl_GetState
,
390 BaseFilterImpl_SetSyncSource
,
391 BaseFilterImpl_GetSyncSource
,
392 BaseFilterImpl_EnumPins
,
393 TransformFilterImpl_FindPin
,
394 BaseFilterImpl_QueryFilterInfo
,
395 BaseFilterImpl_JoinFilterGraph
,
396 BaseFilterImpl_QueryVendorInfo
399 static HRESULT WINAPI
TransformFilter_InputPin_EndOfStream(IPin
* iface
)
401 BaseInputPin
* This
= (BaseInputPin
*) iface
;
402 TransformFilter
* pTransform
;
406 TRACE("(%p)->()\n", iface
);
408 /* Since we process samples synchronously, just forward notification downstream */
409 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
413 hr
= IPin_ConnectedTo(pTransform
->ppPins
[1], &ppin
);
416 hr
= IPin_EndOfStream(ppin
);
425 static HRESULT WINAPI
TransformFilter_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
427 BaseInputPin
* This
= (BaseInputPin
*) iface
;
428 TransformFilter
* pTransform
;
431 TRACE("(%p)->(%p, %p)\n", iface
, pReceivePin
, pmt
);
433 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
435 if (pTransform
->pFuncsTable
->pfnSetMediaType
)
436 hr
= pTransform
->pFuncsTable
->pfnSetMediaType(pTransform
, PINDIR_INPUT
, pmt
);
438 if (SUCCEEDED(hr
) && pTransform
->pFuncsTable
->pfnCompleteConnect
)
439 hr
= pTransform
->pFuncsTable
->pfnCompleteConnect(pTransform
, PINDIR_INPUT
, pReceivePin
);
443 hr
= BaseInputPinImpl_ReceiveConnection(iface
, pReceivePin
, pmt
);
444 if (FAILED(hr
) && pTransform
->pFuncsTable
->pfnBreakConnect
)
445 pTransform
->pFuncsTable
->pfnBreakConnect(pTransform
, PINDIR_INPUT
);
451 static HRESULT WINAPI
TransformFilter_InputPin_Disconnect(IPin
* iface
)
453 BaseInputPin
* This
= (BaseInputPin
*) iface
;
454 TransformFilter
* pTransform
;
456 TRACE("(%p)->()\n", iface
);
458 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
459 if (pTransform
->pFuncsTable
->pfnBreakConnect
)
460 pTransform
->pFuncsTable
->pfnBreakConnect(pTransform
, PINDIR_INPUT
);
462 return BasePinImpl_Disconnect(iface
);
465 static HRESULT WINAPI
TransformFilter_InputPin_BeginFlush(IPin
* iface
)
467 BaseInputPin
* This
= (BaseInputPin
*) iface
;
468 TransformFilter
* pTransform
;
471 TRACE("(%p)->()\n", iface
);
473 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
474 EnterCriticalSection(&pTransform
->filter
.csFilter
);
475 if (pTransform
->pFuncsTable
->pfnBeginFlush
)
476 hr
= pTransform
->pFuncsTable
->pfnBeginFlush(pTransform
);
478 hr
= BaseInputPinImpl_BeginFlush(iface
);
479 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
483 static HRESULT WINAPI
TransformFilter_InputPin_EndFlush(IPin
* iface
)
485 BaseInputPin
* This
= (BaseInputPin
*) iface
;
486 TransformFilter
* pTransform
;
489 TRACE("(%p)->()\n", iface
);
491 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
492 EnterCriticalSection(&pTransform
->filter
.csFilter
);
493 if (pTransform
->pFuncsTable
->pfnEndFlush
)
494 hr
= pTransform
->pFuncsTable
->pfnEndFlush(pTransform
);
496 hr
= BaseInputPinImpl_EndFlush(iface
);
497 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
501 static HRESULT WINAPI
TransformFilter_InputPin_NewSegment(IPin
* iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
503 BaseInputPin
* This
= (BaseInputPin
*) iface
;
504 TransformFilter
* pTransform
;
507 TRACE("(%p)->()\n", iface
);
509 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
510 EnterCriticalSection(&pTransform
->filter
.csFilter
);
511 if (pTransform
->pFuncsTable
->pfnNewSegment
)
512 hr
= pTransform
->pFuncsTable
->pfnNewSegment(pTransform
, tStart
, tStop
, dRate
);
514 hr
= BaseInputPinImpl_NewSegment(iface
, tStart
, tStop
, dRate
);
515 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
519 static const IPinVtbl TransformFilter_InputPin_Vtbl
=
521 BaseInputPinImpl_QueryInterface
,
523 BaseInputPinImpl_Release
,
524 BaseInputPinImpl_Connect
,
525 TransformFilter_InputPin_ReceiveConnection
,
526 TransformFilter_InputPin_Disconnect
,
527 BasePinImpl_ConnectedTo
,
528 BasePinImpl_ConnectionMediaType
,
529 BasePinImpl_QueryPinInfo
,
530 BasePinImpl_QueryDirection
,
532 BaseInputPinImpl_QueryAccept
,
533 BasePinImpl_EnumMediaTypes
,
534 BasePinImpl_QueryInternalConnections
,
535 TransformFilter_InputPin_EndOfStream
,
536 TransformFilter_InputPin_BeginFlush
,
537 TransformFilter_InputPin_EndFlush
,
538 TransformFilter_InputPin_NewSegment
541 static const IPinVtbl TransformFilter_OutputPin_Vtbl
=
543 BaseOutputPinImpl_QueryInterface
,
545 BaseOutputPinImpl_Release
,
546 BaseOutputPinImpl_Connect
,
547 BaseOutputPinImpl_ReceiveConnection
,
548 BaseOutputPinImpl_Disconnect
,
549 BasePinImpl_ConnectedTo
,
550 BasePinImpl_ConnectionMediaType
,
551 BasePinImpl_QueryPinInfo
,
552 BasePinImpl_QueryDirection
,
554 TransformFilter_Output_QueryAccept
,
555 BasePinImpl_EnumMediaTypes
,
556 BasePinImpl_QueryInternalConnections
,
557 BaseOutputPinImpl_EndOfStream
,
558 BaseOutputPinImpl_BeginFlush
,
559 BaseOutputPinImpl_EndFlush
,
560 BasePinImpl_NewSegment
563 static HRESULT WINAPI
TransformFilter_QualityControlImpl_Notify(IQualityControl
*iface
, IBaseFilter
*sender
, Quality qm
) {
564 QualityControlImpl
*qc
= (QualityControlImpl
*)iface
;
565 TransformFilter
*This
= (TransformFilter
*)qc
->self
;
567 if (This
->pFuncsTable
->pfnNotify
)
568 return This
->pFuncsTable
->pfnNotify(This
, sender
, qm
);
570 return QualityControlImpl_Notify(iface
, sender
, qm
);
573 static const IQualityControlVtbl TransformFilter_QualityControl_Vtbl
= {
574 QualityControlImpl_QueryInterface
,
575 QualityControlImpl_AddRef
,
576 QualityControlImpl_Release
,
577 TransformFilter_QualityControlImpl_Notify
,
578 QualityControlImpl_SetSink