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
);
225 ZeroMemory(pTf
, filter_size
);
228 return E_OUTOFMEMORY
;
230 if (SUCCEEDED(TransformFilter_Init(pVtbl
, pClsid
, pFuncsTable
, pTf
)))
232 *ppTransformFilter
= (IBaseFilter
*)(&pTf
->filter
.lpVtbl
);
240 HRESULT WINAPI
TransformFilterImpl_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
243 TransformFilter
*This
= (TransformFilter
*)iface
;
244 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, debugstr_guid(riid
), ppv
);
246 if (IsEqualIID(riid
, &IID_IQualityControl
)) {
247 *ppv
= (IQualityControl
*)&This
->qcimpl
;
248 IUnknown_AddRef((IUnknown
*)*ppv
);
251 hr
= BaseFilterImpl_QueryInterface(iface
, riid
, ppv
);
253 if (FAILED(hr
) && !IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
) &&
254 !IsEqualIID(riid
, &IID_IAMFilterMiscFlags
))
255 FIXME("No interface for %s!\n", debugstr_guid(riid
));
260 ULONG WINAPI
TransformFilterImpl_Release(IBaseFilter
* iface
)
262 TransformFilter
*This
= (TransformFilter
*)iface
;
263 ULONG refCount
= BaseFilterImpl_Release(iface
);
265 TRACE("(%p/%p)->() Release from %d\n", This
, iface
, refCount
+ 1);
271 for (i
= 0; i
< This
->npins
; i
++)
275 if (SUCCEEDED(IPin_ConnectedTo(This
->ppPins
[i
], &pConnectedTo
)))
277 IPin_Disconnect(pConnectedTo
);
278 IPin_Release(pConnectedTo
);
280 IPin_Disconnect(This
->ppPins
[i
]);
282 IPin_Release(This
->ppPins
[i
]);
285 CoTaskMemFree(This
->ppPins
);
287 TRACE("Destroying transform filter\n");
288 FreeMediaType(&This
->pmt
);
297 /** IMediaFilter methods **/
299 HRESULT WINAPI
TransformFilterImpl_Stop(IBaseFilter
* iface
)
301 TransformFilter
*This
= (TransformFilter
*)iface
;
304 TRACE("(%p/%p)\n", This
, iface
);
306 EnterCriticalSection(&This
->filter
.csFilter
);
308 This
->filter
.state
= State_Stopped
;
309 if (This
->pFuncsTable
->pfnStopStreaming
)
310 hr
= This
->pFuncsTable
->pfnStopStreaming(This
);
312 LeaveCriticalSection(&This
->filter
.csFilter
);
317 HRESULT WINAPI
TransformFilterImpl_Pause(IBaseFilter
* iface
)
319 TransformFilter
*This
= (TransformFilter
*)iface
;
322 TRACE("(%p/%p)->()\n", This
, iface
);
324 EnterCriticalSection(&This
->filter
.csFilter
);
326 if (This
->filter
.state
== State_Stopped
)
327 hr
= IBaseFilter_Run(iface
, -1);
332 This
->filter
.state
= State_Paused
;
334 LeaveCriticalSection(&This
->filter
.csFilter
);
339 HRESULT WINAPI
TransformFilterImpl_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
342 TransformFilter
*This
= (TransformFilter
*)iface
;
344 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
346 EnterCriticalSection(&This
->filter
.csFilter
);
348 if (This
->filter
.state
== State_Stopped
)
350 ((BaseInputPin
*)This
->ppPins
[0])->end_of_stream
= 0;
351 if (This
->pFuncsTable
->pfnStartStreaming
)
352 hr
= This
->pFuncsTable
->pfnStartStreaming(This
);
354 hr
= BaseOutputPinImpl_Active((BaseOutputPin
*)This
->ppPins
[1]);
359 This
->filter
.rtStreamStart
= tStart
;
360 This
->filter
.state
= State_Running
;
363 LeaveCriticalSection(&This
->filter
.csFilter
);
368 /** IBaseFilter implementation **/
370 HRESULT WINAPI
TransformFilterImpl_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
372 TransformFilter
*This
= (TransformFilter
*)iface
;
374 TRACE("(%p/%p)->(%p,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
379 static const IBaseFilterVtbl TransformFilter_Vtbl
=
381 TransformFilterImpl_QueryInterface
,
382 BaseFilterImpl_AddRef
,
383 TransformFilterImpl_Release
,
384 BaseFilterImpl_GetClassID
,
385 TransformFilterImpl_Stop
,
386 TransformFilterImpl_Pause
,
387 TransformFilterImpl_Run
,
388 BaseFilterImpl_GetState
,
389 BaseFilterImpl_SetSyncSource
,
390 BaseFilterImpl_GetSyncSource
,
391 BaseFilterImpl_EnumPins
,
392 TransformFilterImpl_FindPin
,
393 BaseFilterImpl_QueryFilterInfo
,
394 BaseFilterImpl_JoinFilterGraph
,
395 BaseFilterImpl_QueryVendorInfo
398 static HRESULT WINAPI
TransformFilter_InputPin_EndOfStream(IPin
* iface
)
400 BaseInputPin
* This
= (BaseInputPin
*) iface
;
401 TransformFilter
* pTransform
;
405 TRACE("(%p)->()\n", iface
);
407 /* Since we process samples synchronously, just forward notification downstream */
408 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
412 hr
= IPin_ConnectedTo(pTransform
->ppPins
[1], &ppin
);
415 hr
= IPin_EndOfStream(ppin
);
424 static HRESULT WINAPI
TransformFilter_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
426 BaseInputPin
* This
= (BaseInputPin
*) iface
;
427 TransformFilter
* pTransform
;
430 TRACE("(%p)->(%p, %p)\n", iface
, pReceivePin
, pmt
);
432 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
434 if (pTransform
->pFuncsTable
->pfnSetMediaType
)
435 hr
= pTransform
->pFuncsTable
->pfnSetMediaType(pTransform
, PINDIR_INPUT
, pmt
);
437 if (SUCCEEDED(hr
) && pTransform
->pFuncsTable
->pfnCompleteConnect
)
438 hr
= pTransform
->pFuncsTable
->pfnCompleteConnect(pTransform
, PINDIR_INPUT
, pReceivePin
);
442 hr
= BaseInputPinImpl_ReceiveConnection(iface
, pReceivePin
, pmt
);
443 if (FAILED(hr
) && pTransform
->pFuncsTable
->pfnBreakConnect
)
444 pTransform
->pFuncsTable
->pfnBreakConnect(pTransform
, PINDIR_INPUT
);
450 static HRESULT WINAPI
TransformFilter_InputPin_Disconnect(IPin
* iface
)
452 BaseInputPin
* This
= (BaseInputPin
*) iface
;
453 TransformFilter
* pTransform
;
455 TRACE("(%p)->()\n", iface
);
457 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
458 if (pTransform
->pFuncsTable
->pfnBreakConnect
)
459 pTransform
->pFuncsTable
->pfnBreakConnect(pTransform
, PINDIR_INPUT
);
461 return BasePinImpl_Disconnect(iface
);
464 static HRESULT WINAPI
TransformFilter_InputPin_BeginFlush(IPin
* iface
)
466 BaseInputPin
* This
= (BaseInputPin
*) iface
;
467 TransformFilter
* pTransform
;
470 TRACE("(%p)->()\n", iface
);
472 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
473 EnterCriticalSection(&pTransform
->filter
.csFilter
);
474 if (pTransform
->pFuncsTable
->pfnBeginFlush
)
475 hr
= pTransform
->pFuncsTable
->pfnBeginFlush(pTransform
);
477 hr
= BaseInputPinImpl_BeginFlush(iface
);
478 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
482 static HRESULT WINAPI
TransformFilter_InputPin_EndFlush(IPin
* iface
)
484 BaseInputPin
* This
= (BaseInputPin
*) iface
;
485 TransformFilter
* pTransform
;
488 TRACE("(%p)->()\n", iface
);
490 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
491 EnterCriticalSection(&pTransform
->filter
.csFilter
);
492 if (pTransform
->pFuncsTable
->pfnEndFlush
)
493 hr
= pTransform
->pFuncsTable
->pfnEndFlush(pTransform
);
495 hr
= BaseInputPinImpl_EndFlush(iface
);
496 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
500 static HRESULT WINAPI
TransformFilter_InputPin_NewSegment(IPin
* iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
502 BaseInputPin
* This
= (BaseInputPin
*) iface
;
503 TransformFilter
* pTransform
;
506 TRACE("(%p)->()\n", iface
);
508 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
509 EnterCriticalSection(&pTransform
->filter
.csFilter
);
510 if (pTransform
->pFuncsTable
->pfnNewSegment
)
511 hr
= pTransform
->pFuncsTable
->pfnNewSegment(pTransform
, tStart
, tStop
, dRate
);
513 hr
= BaseInputPinImpl_NewSegment(iface
, tStart
, tStop
, dRate
);
514 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
518 static const IPinVtbl TransformFilter_InputPin_Vtbl
=
520 BaseInputPinImpl_QueryInterface
,
522 BaseInputPinImpl_Release
,
523 BaseInputPinImpl_Connect
,
524 TransformFilter_InputPin_ReceiveConnection
,
525 TransformFilter_InputPin_Disconnect
,
526 BasePinImpl_ConnectedTo
,
527 BasePinImpl_ConnectionMediaType
,
528 BasePinImpl_QueryPinInfo
,
529 BasePinImpl_QueryDirection
,
531 BaseInputPinImpl_QueryAccept
,
532 BasePinImpl_EnumMediaTypes
,
533 BasePinImpl_QueryInternalConnections
,
534 TransformFilter_InputPin_EndOfStream
,
535 TransformFilter_InputPin_BeginFlush
,
536 TransformFilter_InputPin_EndFlush
,
537 TransformFilter_InputPin_NewSegment
540 static const IPinVtbl TransformFilter_OutputPin_Vtbl
=
542 BaseOutputPinImpl_QueryInterface
,
544 BaseOutputPinImpl_Release
,
545 BaseOutputPinImpl_Connect
,
546 BaseOutputPinImpl_ReceiveConnection
,
547 BaseOutputPinImpl_Disconnect
,
548 BasePinImpl_ConnectedTo
,
549 BasePinImpl_ConnectionMediaType
,
550 BasePinImpl_QueryPinInfo
,
551 BasePinImpl_QueryDirection
,
553 TransformFilter_Output_QueryAccept
,
554 BasePinImpl_EnumMediaTypes
,
555 BasePinImpl_QueryInternalConnections
,
556 BaseOutputPinImpl_EndOfStream
,
557 BaseOutputPinImpl_BeginFlush
,
558 BaseOutputPinImpl_EndFlush
,
559 BasePinImpl_NewSegment
562 HRESULT WINAPI
TransformFilter_QualityControlImpl_Notify(IQualityControl
*iface
, IBaseFilter
*sender
, Quality qm
) {
563 QualityControlImpl
*qc
= (QualityControlImpl
*)iface
;
564 TransformFilter
*This
= (TransformFilter
*)qc
->self
;
566 if (This
->pFuncsTable
->pfnNotify
)
567 return This
->pFuncsTable
->pfnNotify(This
, sender
, qm
);
569 return QualityControlImpl_Notify(iface
, sender
, qm
);
572 static const IQualityControlVtbl TransformFilter_QualityControl_Vtbl
= {
573 QualityControlImpl_QueryInterface
,
574 QualityControlImpl_AddRef
,
575 QualityControlImpl_Release
,
576 TransformFilter_QualityControlImpl_Notify
,
577 QualityControlImpl_SetSink