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
->csReceive
);
72 if (pTransform
->filter
.state
== State_Stopped
)
74 LeaveCriticalSection(&pTransform
->csReceive
);
75 return VFW_E_WRONG_STATE
;
78 if (This
->end_of_stream
|| This
->flushing
)
80 LeaveCriticalSection(&pTransform
->csReceive
);
84 LeaveCriticalSection(&pTransform
->csReceive
);
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 InitializeCriticalSection(&pTransformFilter
->csReceive
);
180 pTransformFilter
->csReceive
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TransformFilter.csReceive");
182 /* pTransformFilter is already allocated */
183 pTransformFilter
->pFuncsTable
= pFuncsTable
;
184 ZeroMemory(&pTransformFilter
->pmt
, sizeof(pTransformFilter
->pmt
));
185 pTransformFilter
->npins
= 2;
187 pTransformFilter
->ppPins
= CoTaskMemAlloc(2 * sizeof(IPin
*));
189 /* construct input pin */
190 piInput
.dir
= PINDIR_INPUT
;
191 piInput
.pFilter
= (IBaseFilter
*)pTransformFilter
;
192 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
193 piOutput
.dir
= PINDIR_OUTPUT
;
194 piOutput
.pFilter
= (IBaseFilter
*)pTransformFilter
;
195 lstrcpynW(piOutput
.achName
, wcsOutputPinName
, sizeof(piOutput
.achName
) / sizeof(piOutput
.achName
[0]));
197 hr
= BaseInputPin_Construct(&TransformFilter_InputPin_Vtbl
, &piInput
, &tf_input_BaseFuncTable
, &tf_input_BaseInputFuncTable
, &pTransformFilter
->filter
.csFilter
, NULL
, &pTransformFilter
->ppPins
[0]);
201 hr
= BaseOutputPin_Construct(&TransformFilter_OutputPin_Vtbl
, sizeof(BaseOutputPin
), &piOutput
, &tf_output_BaseFuncTable
, &tf_output_BaseOutputFuncTable
, &pTransformFilter
->filter
.csFilter
, &pTransformFilter
->ppPins
[1]);
204 ERR("Cannot create output pin (%x)\n", hr
);
206 QualityControlImpl_init(&pTransformFilter
->qcimpl
, (IPin
*)pTransformFilter
->ppPins
[0], (IBaseFilter
*)pTransformFilter
);
207 pTransformFilter
->qcimpl
.lpVtbl
= &TransformFilter_QualityControl_Vtbl
;
212 CoTaskMemFree(pTransformFilter
->ppPins
);
213 BaseFilterImpl_Release((IBaseFilter
*)pTransformFilter
);
219 HRESULT
TransformFilter_Construct(const IBaseFilterVtbl
*pVtbl
, LONG filter_size
, const CLSID
* pClsid
, const TransformFilterFuncTable
* pFuncsTable
, IBaseFilter
** ppTransformFilter
)
221 TransformFilter
* pTf
;
223 *ppTransformFilter
= NULL
;
225 assert(filter_size
>= sizeof(TransformFilter
));
227 pTf
= CoTaskMemAlloc(filter_size
);
230 return E_OUTOFMEMORY
;
232 ZeroMemory(pTf
, filter_size
);
234 if (SUCCEEDED(TransformFilter_Init(pVtbl
, pClsid
, pFuncsTable
, pTf
)))
236 *ppTransformFilter
= (IBaseFilter
*)(&pTf
->filter
.lpVtbl
);
244 HRESULT WINAPI
TransformFilterImpl_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
247 TransformFilter
*This
= (TransformFilter
*)iface
;
248 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, debugstr_guid(riid
), ppv
);
250 if (IsEqualIID(riid
, &IID_IQualityControl
)) {
251 *ppv
= (IQualityControl
*)&This
->qcimpl
;
252 IUnknown_AddRef((IUnknown
*)*ppv
);
255 hr
= BaseFilterImpl_QueryInterface(iface
, riid
, ppv
);
257 if (FAILED(hr
) && !IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
) &&
258 !IsEqualIID(riid
, &IID_IAMFilterMiscFlags
))
259 FIXME("No interface for %s!\n", debugstr_guid(riid
));
264 ULONG WINAPI
TransformFilterImpl_Release(IBaseFilter
* iface
)
266 TransformFilter
*This
= (TransformFilter
*)iface
;
267 ULONG refCount
= BaseFilterImpl_Release(iface
);
269 TRACE("(%p/%p)->() Release from %d\n", This
, iface
, refCount
+ 1);
275 for (i
= 0; i
< This
->npins
; i
++)
279 if (SUCCEEDED(IPin_ConnectedTo(This
->ppPins
[i
], &pConnectedTo
)))
281 IPin_Disconnect(pConnectedTo
);
282 IPin_Release(pConnectedTo
);
284 IPin_Disconnect(This
->ppPins
[i
]);
286 IPin_Release(This
->ppPins
[i
]);
289 CoTaskMemFree(This
->ppPins
);
291 TRACE("Destroying transform filter\n");
292 This
->csReceive
.DebugInfo
->Spare
[0] = 0;
293 DeleteCriticalSection(&This
->csReceive
);
294 FreeMediaType(&This
->pmt
);
303 /** IMediaFilter methods **/
305 HRESULT WINAPI
TransformFilterImpl_Stop(IBaseFilter
* iface
)
307 TransformFilter
*This
= (TransformFilter
*)iface
;
310 TRACE("(%p/%p)\n", This
, iface
);
312 EnterCriticalSection(&This
->csReceive
);
314 This
->filter
.state
= State_Stopped
;
315 if (This
->pFuncsTable
->pfnStopStreaming
)
316 hr
= This
->pFuncsTable
->pfnStopStreaming(This
);
318 LeaveCriticalSection(&This
->csReceive
);
323 HRESULT WINAPI
TransformFilterImpl_Pause(IBaseFilter
* iface
)
325 TransformFilter
*This
= (TransformFilter
*)iface
;
328 TRACE("(%p/%p)->()\n", This
, iface
);
330 EnterCriticalSection(&This
->csReceive
);
332 if (This
->filter
.state
== State_Stopped
)
333 hr
= IBaseFilter_Run(iface
, -1);
338 This
->filter
.state
= State_Paused
;
340 LeaveCriticalSection(&This
->csReceive
);
345 HRESULT WINAPI
TransformFilterImpl_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
348 TransformFilter
*This
= (TransformFilter
*)iface
;
350 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
352 EnterCriticalSection(&This
->csReceive
);
354 if (This
->filter
.state
== State_Stopped
)
356 ((BaseInputPin
*)This
->ppPins
[0])->end_of_stream
= 0;
357 if (This
->pFuncsTable
->pfnStartStreaming
)
358 hr
= This
->pFuncsTable
->pfnStartStreaming(This
);
360 hr
= BaseOutputPinImpl_Active((BaseOutputPin
*)This
->ppPins
[1]);
365 This
->filter
.rtStreamStart
= tStart
;
366 This
->filter
.state
= State_Running
;
369 LeaveCriticalSection(&This
->csReceive
);
374 /** IBaseFilter implementation **/
376 HRESULT WINAPI
TransformFilterImpl_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
378 TransformFilter
*This
= (TransformFilter
*)iface
;
380 TRACE("(%p/%p)->(%p,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
385 static const IBaseFilterVtbl TransformFilter_Vtbl
=
387 TransformFilterImpl_QueryInterface
,
388 BaseFilterImpl_AddRef
,
389 TransformFilterImpl_Release
,
390 BaseFilterImpl_GetClassID
,
391 TransformFilterImpl_Stop
,
392 TransformFilterImpl_Pause
,
393 TransformFilterImpl_Run
,
394 BaseFilterImpl_GetState
,
395 BaseFilterImpl_SetSyncSource
,
396 BaseFilterImpl_GetSyncSource
,
397 BaseFilterImpl_EnumPins
,
398 TransformFilterImpl_FindPin
,
399 BaseFilterImpl_QueryFilterInfo
,
400 BaseFilterImpl_JoinFilterGraph
,
401 BaseFilterImpl_QueryVendorInfo
404 static HRESULT WINAPI
TransformFilter_InputPin_EndOfStream(IPin
* iface
)
406 BaseInputPin
* This
= (BaseInputPin
*) iface
;
407 TransformFilter
* pTransform
;
411 TRACE("(%p)->()\n", iface
);
413 /* Since we process samples synchronously, just forward notification downstream */
414 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
418 hr
= IPin_ConnectedTo(pTransform
->ppPins
[1], &ppin
);
421 hr
= IPin_EndOfStream(ppin
);
430 static HRESULT WINAPI
TransformFilter_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
432 BaseInputPin
* This
= (BaseInputPin
*) iface
;
433 TransformFilter
* pTransform
;
436 TRACE("(%p)->(%p, %p)\n", iface
, pReceivePin
, pmt
);
438 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
440 if (pTransform
->pFuncsTable
->pfnSetMediaType
)
441 hr
= pTransform
->pFuncsTable
->pfnSetMediaType(pTransform
, PINDIR_INPUT
, pmt
);
443 if (SUCCEEDED(hr
) && pTransform
->pFuncsTable
->pfnCompleteConnect
)
444 hr
= pTransform
->pFuncsTable
->pfnCompleteConnect(pTransform
, PINDIR_INPUT
, pReceivePin
);
448 hr
= BaseInputPinImpl_ReceiveConnection(iface
, pReceivePin
, pmt
);
449 if (FAILED(hr
) && pTransform
->pFuncsTable
->pfnBreakConnect
)
450 pTransform
->pFuncsTable
->pfnBreakConnect(pTransform
, PINDIR_INPUT
);
456 static HRESULT WINAPI
TransformFilter_InputPin_Disconnect(IPin
* iface
)
458 BaseInputPin
* This
= (BaseInputPin
*) iface
;
459 TransformFilter
* pTransform
;
461 TRACE("(%p)->()\n", iface
);
463 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
464 if (pTransform
->pFuncsTable
->pfnBreakConnect
)
465 pTransform
->pFuncsTable
->pfnBreakConnect(pTransform
, PINDIR_INPUT
);
467 return BasePinImpl_Disconnect(iface
);
470 static HRESULT WINAPI
TransformFilter_InputPin_BeginFlush(IPin
* iface
)
472 BaseInputPin
* This
= (BaseInputPin
*) iface
;
473 TransformFilter
* pTransform
;
476 TRACE("(%p)->()\n", iface
);
478 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
479 EnterCriticalSection(&pTransform
->filter
.csFilter
);
480 if (pTransform
->pFuncsTable
->pfnBeginFlush
)
481 hr
= pTransform
->pFuncsTable
->pfnBeginFlush(pTransform
);
483 hr
= BaseInputPinImpl_BeginFlush(iface
);
484 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
488 static HRESULT WINAPI
TransformFilter_InputPin_EndFlush(IPin
* iface
)
490 BaseInputPin
* This
= (BaseInputPin
*) iface
;
491 TransformFilter
* pTransform
;
494 TRACE("(%p)->()\n", iface
);
496 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
497 EnterCriticalSection(&pTransform
->filter
.csFilter
);
498 if (pTransform
->pFuncsTable
->pfnEndFlush
)
499 hr
= pTransform
->pFuncsTable
->pfnEndFlush(pTransform
);
501 hr
= BaseInputPinImpl_EndFlush(iface
);
502 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
506 static HRESULT WINAPI
TransformFilter_InputPin_NewSegment(IPin
* iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
508 BaseInputPin
* This
= (BaseInputPin
*) iface
;
509 TransformFilter
* pTransform
;
512 TRACE("(%p)->()\n", iface
);
514 pTransform
= (TransformFilter
*)This
->pin
.pinInfo
.pFilter
;
515 EnterCriticalSection(&pTransform
->filter
.csFilter
);
516 if (pTransform
->pFuncsTable
->pfnNewSegment
)
517 hr
= pTransform
->pFuncsTable
->pfnNewSegment(pTransform
, tStart
, tStop
, dRate
);
519 hr
= BaseInputPinImpl_NewSegment(iface
, tStart
, tStop
, dRate
);
520 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
524 static const IPinVtbl TransformFilter_InputPin_Vtbl
=
526 BaseInputPinImpl_QueryInterface
,
528 BaseInputPinImpl_Release
,
529 BaseInputPinImpl_Connect
,
530 TransformFilter_InputPin_ReceiveConnection
,
531 TransformFilter_InputPin_Disconnect
,
532 BasePinImpl_ConnectedTo
,
533 BasePinImpl_ConnectionMediaType
,
534 BasePinImpl_QueryPinInfo
,
535 BasePinImpl_QueryDirection
,
537 BaseInputPinImpl_QueryAccept
,
538 BasePinImpl_EnumMediaTypes
,
539 BasePinImpl_QueryInternalConnections
,
540 TransformFilter_InputPin_EndOfStream
,
541 TransformFilter_InputPin_BeginFlush
,
542 TransformFilter_InputPin_EndFlush
,
543 TransformFilter_InputPin_NewSegment
546 static const IPinVtbl TransformFilter_OutputPin_Vtbl
=
548 BaseOutputPinImpl_QueryInterface
,
550 BaseOutputPinImpl_Release
,
551 BaseOutputPinImpl_Connect
,
552 BaseOutputPinImpl_ReceiveConnection
,
553 BaseOutputPinImpl_Disconnect
,
554 BasePinImpl_ConnectedTo
,
555 BasePinImpl_ConnectionMediaType
,
556 BasePinImpl_QueryPinInfo
,
557 BasePinImpl_QueryDirection
,
559 TransformFilter_Output_QueryAccept
,
560 BasePinImpl_EnumMediaTypes
,
561 BasePinImpl_QueryInternalConnections
,
562 BaseOutputPinImpl_EndOfStream
,
563 BaseOutputPinImpl_BeginFlush
,
564 BaseOutputPinImpl_EndFlush
,
565 BasePinImpl_NewSegment
568 static HRESULT WINAPI
TransformFilter_QualityControlImpl_Notify(IQualityControl
*iface
, IBaseFilter
*sender
, Quality qm
) {
569 QualityControlImpl
*qc
= (QualityControlImpl
*)iface
;
570 TransformFilter
*This
= (TransformFilter
*)qc
->self
;
572 if (This
->pFuncsTable
->pfnNotify
)
573 return This
->pFuncsTable
->pfnNotify(This
, sender
, qm
);
575 return QualityControlImpl_Notify(iface
, sender
, qm
);
578 static const IQualityControlVtbl TransformFilter_QualityControl_Vtbl
= {
579 QualityControlImpl_QueryInterface
,
580 QualityControlImpl_AddRef
,
581 QualityControlImpl_Release
,
582 TransformFilter_QualityControlImpl_Notify
,
583 QualityControlImpl_SetSink