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"
38 #include "strmbase_private.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(strmbase
);
42 static const WCHAR wcsInputPinName
[] = {'i','n','p','u','t',' ','p','i','n',0};
43 static const WCHAR wcsOutputPinName
[] = {'o','u','t','p','u','t',' ','p','i','n',0};
45 static const IBaseFilterVtbl TransformFilter_Vtbl
;
46 static const IPinVtbl TransformFilter_InputPin_Vtbl
;
47 static const IPinVtbl TransformFilter_OutputPin_Vtbl
;
48 static const IQualityControlVtbl TransformFilter_QualityControl_Vtbl
;
50 static inline BaseInputPin
*impl_BaseInputPin_from_BasePin( BasePin
*iface
)
52 return CONTAINING_RECORD(iface
, BaseInputPin
, pin
);
55 static inline BasePin
*impl_BasePin_from_IPin( IPin
*iface
)
57 return CONTAINING_RECORD(iface
, BasePin
, IPin_iface
);
60 static inline BaseInputPin
*impl_BaseInputPin_from_IPin( IPin
*iface
)
62 return CONTAINING_RECORD(iface
, BaseInputPin
, pin
.IPin_iface
);
65 static inline BaseOutputPin
*impl_BaseOutputPin_from_IPin( IPin
*iface
)
67 return CONTAINING_RECORD(iface
, BaseOutputPin
, pin
.IPin_iface
);
70 static inline TransformFilter
*impl_from_IBaseFilter( IBaseFilter
*iface
)
72 return CONTAINING_RECORD(iface
, TransformFilter
, filter
.IBaseFilter_iface
);
75 static inline TransformFilter
*impl_from_BaseFilter( BaseFilter
*iface
)
77 return CONTAINING_RECORD(iface
, TransformFilter
, filter
);
80 static HRESULT WINAPI
TransformFilter_Input_CheckMediaType(BasePin
*iface
, const AM_MEDIA_TYPE
* pmt
)
82 BaseInputPin
* This
= impl_BaseInputPin_from_BasePin(iface
);
83 TransformFilter
* pTransform
;
86 pTransform
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
88 if (pTransform
->pFuncsTable
->pfnCheckInputType
)
89 return pTransform
->pFuncsTable
->pfnCheckInputType(pTransform
, pmt
);
90 /* Assume OK if there's no query method (the connection will fail if
95 static HRESULT WINAPI
TransformFilter_Input_Receive(BaseInputPin
*This
, IMediaSample
*pInSample
)
98 TransformFilter
* pTransform
;
100 pTransform
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
102 EnterCriticalSection(&pTransform
->csReceive
);
103 if (pTransform
->filter
.state
== State_Stopped
)
105 LeaveCriticalSection(&pTransform
->csReceive
);
106 return VFW_E_WRONG_STATE
;
109 if (This
->end_of_stream
|| This
->flushing
)
111 LeaveCriticalSection(&pTransform
->csReceive
);
115 LeaveCriticalSection(&pTransform
->csReceive
);
116 if (pTransform
->pFuncsTable
->pfnReceive
)
117 hr
= pTransform
->pFuncsTable
->pfnReceive(pTransform
, pInSample
);
124 static HRESULT WINAPI
TransformFilter_Output_QueryAccept(IPin
*iface
, const AM_MEDIA_TYPE
* pmt
)
126 BasePin
*This
= impl_BasePin_from_IPin(iface
);
127 TransformFilter
*pTransformFilter
= impl_from_IBaseFilter(This
->pinInfo
.pFilter
);
128 AM_MEDIA_TYPE
* outpmt
= &pTransformFilter
->pmt
;
129 TRACE("%p\n", iface
);
131 if (IsEqualIID(&pmt
->majortype
, &outpmt
->majortype
)
132 && (IsEqualIID(&pmt
->subtype
, &outpmt
->subtype
) || IsEqualIID(&outpmt
->subtype
, &GUID_NULL
)))
137 static HRESULT WINAPI
TransformFilter_Output_DecideBufferSize(BaseOutputPin
*This
, IMemAllocator
*pAlloc
, ALLOCATOR_PROPERTIES
*ppropInputRequest
)
139 TransformFilter
*pTransformFilter
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
140 return pTransformFilter
->pFuncsTable
->pfnDecideBufferSize(pTransformFilter
, pAlloc
, ppropInputRequest
);
143 static HRESULT WINAPI
TransformFilter_Output_GetMediaType(BasePin
*This
, int iPosition
, AM_MEDIA_TYPE
*pmt
)
145 TransformFilter
*pTransform
= impl_from_IBaseFilter(This
->pinInfo
.pFilter
);
150 return VFW_S_NO_MORE_ITEMS
;
151 CopyMediaType(pmt
, &pTransform
->pmt
);
155 static IPin
* WINAPI
TransformFilter_GetPin(BaseFilter
*iface
, int pos
)
157 TransformFilter
*This
= impl_from_BaseFilter(iface
);
159 if (pos
>= This
->npins
|| pos
< 0)
162 IPin_AddRef(This
->ppPins
[pos
]);
163 return This
->ppPins
[pos
];
166 static LONG WINAPI
TransformFilter_GetPinCount(BaseFilter
*iface
)
168 TransformFilter
*This
= impl_from_BaseFilter(iface
);
170 return (This
->npins
+1);
173 static const BaseFilterFuncTable tfBaseFuncTable
= {
174 TransformFilter_GetPin
,
175 TransformFilter_GetPinCount
178 static const BasePinFuncTable tf_input_BaseFuncTable
= {
179 TransformFilter_Input_CheckMediaType
,
181 BasePinImpl_GetMediaTypeVersion
,
182 BasePinImpl_GetMediaType
185 static const BaseInputPinFuncTable tf_input_BaseInputFuncTable
= {
186 TransformFilter_Input_Receive
189 static const BasePinFuncTable tf_output_BaseFuncTable
= {
191 BaseOutputPinImpl_AttemptConnection
,
192 BasePinImpl_GetMediaTypeVersion
,
193 TransformFilter_Output_GetMediaType
196 static const BaseOutputPinFuncTable tf_output_BaseOutputFuncTable
= {
197 TransformFilter_Output_DecideBufferSize
,
198 BaseOutputPinImpl_DecideAllocator
,
199 BaseOutputPinImpl_BreakConnect
202 static HRESULT
TransformFilter_Init(const IBaseFilterVtbl
*pVtbl
, const CLSID
* pClsid
, const TransformFilterFuncTable
* pFuncsTable
, TransformFilter
* pTransformFilter
)
208 BaseFilter_Init(&pTransformFilter
->filter
, pVtbl
, pClsid
, (DWORD_PTR
)(__FILE__
": TransformFilter.csFilter"), &tfBaseFuncTable
);
210 InitializeCriticalSection(&pTransformFilter
->csReceive
);
211 pTransformFilter
->csReceive
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": TransformFilter.csReceive");
213 /* pTransformFilter is already allocated */
214 pTransformFilter
->pFuncsTable
= pFuncsTable
;
215 ZeroMemory(&pTransformFilter
->pmt
, sizeof(pTransformFilter
->pmt
));
216 pTransformFilter
->npins
= 2;
218 pTransformFilter
->ppPins
= CoTaskMemAlloc(2 * sizeof(IPin
*));
220 /* construct input pin */
221 piInput
.dir
= PINDIR_INPUT
;
222 piInput
.pFilter
= &pTransformFilter
->filter
.IBaseFilter_iface
;
223 lstrcpynW(piInput
.achName
, wcsInputPinName
, sizeof(piInput
.achName
) / sizeof(piInput
.achName
[0]));
224 piOutput
.dir
= PINDIR_OUTPUT
;
225 piOutput
.pFilter
= &pTransformFilter
->filter
.IBaseFilter_iface
;
226 lstrcpynW(piOutput
.achName
, wcsOutputPinName
, sizeof(piOutput
.achName
) / sizeof(piOutput
.achName
[0]));
228 hr
= BaseInputPin_Construct(&TransformFilter_InputPin_Vtbl
, &piInput
, &tf_input_BaseFuncTable
, &tf_input_BaseInputFuncTable
, &pTransformFilter
->filter
.csFilter
, NULL
, &pTransformFilter
->ppPins
[0]);
232 hr
= BaseOutputPin_Construct(&TransformFilter_OutputPin_Vtbl
, sizeof(BaseOutputPin
), &piOutput
, &tf_output_BaseFuncTable
, &tf_output_BaseOutputFuncTable
, &pTransformFilter
->filter
.csFilter
, &pTransformFilter
->ppPins
[1]);
235 ERR("Cannot create output pin (%x)\n", hr
);
237 QualityControlImpl_Create( pTransformFilter
->ppPins
[0], &pTransformFilter
->filter
.IBaseFilter_iface
, &pTransformFilter
->qcimpl
);
238 pTransformFilter
->qcimpl
->IQualityControl_iface
.lpVtbl
= &TransformFilter_QualityControl_Vtbl
;
244 ISeekingPassThru
*passthru
;
245 pTransformFilter
->seekthru_unk
= NULL
;
246 hr
= CoCreateInstance(&CLSID_SeekingPassThru
, (IUnknown
*)pTransformFilter
, CLSCTX_INPROC_SERVER
, &IID_IUnknown
, (void**)&pTransformFilter
->seekthru_unk
);
249 IUnknown_QueryInterface(pTransformFilter
->seekthru_unk
, &IID_ISeekingPassThru
, (void**)&passthru
);
250 ISeekingPassThru_Init(passthru
, FALSE
, pTransformFilter
->ppPins
[0]);
251 ISeekingPassThru_Release(passthru
);
257 CoTaskMemFree(pTransformFilter
->ppPins
);
258 BaseFilterImpl_Release(&pTransformFilter
->filter
.IBaseFilter_iface
);
264 HRESULT
TransformFilter_Construct(const IBaseFilterVtbl
*pVtbl
, LONG filter_size
, const CLSID
* pClsid
, const TransformFilterFuncTable
* pFuncsTable
, IBaseFilter
** ppTransformFilter
)
266 TransformFilter
* pTf
;
268 *ppTransformFilter
= NULL
;
270 assert(filter_size
>= sizeof(TransformFilter
));
272 pTf
= CoTaskMemAlloc(filter_size
);
275 return E_OUTOFMEMORY
;
277 ZeroMemory(pTf
, filter_size
);
279 if (SUCCEEDED(TransformFilter_Init(pVtbl
, pClsid
, pFuncsTable
, pTf
)))
281 *ppTransformFilter
= &pTf
->filter
.IBaseFilter_iface
;
289 HRESULT WINAPI
TransformFilterImpl_QueryInterface(IBaseFilter
* iface
, REFIID riid
, LPVOID
* ppv
)
292 TransformFilter
*This
= impl_from_IBaseFilter(iface
);
293 TRACE("(%p/%p)->(%s, %p)\n", This
, iface
, debugstr_guid(riid
), ppv
);
295 if (IsEqualIID(riid
, &IID_IQualityControl
)) {
296 *ppv
= (IQualityControl
*)This
->qcimpl
;
297 IUnknown_AddRef((IUnknown
*)*ppv
);
300 else if (IsEqualIID(riid
, &IID_IMediaSeeking
) ||
301 IsEqualIID(riid
, &IID_IMediaPosition
))
303 return IUnknown_QueryInterface(This
->seekthru_unk
, riid
, ppv
);
305 hr
= BaseFilterImpl_QueryInterface(iface
, riid
, ppv
);
307 if (FAILED(hr
) && !IsEqualIID(riid
, &IID_IPin
) && !IsEqualIID(riid
, &IID_IVideoWindow
) &&
308 !IsEqualIID(riid
, &IID_IAMFilterMiscFlags
))
309 FIXME("No interface for %s!\n", debugstr_guid(riid
));
314 ULONG WINAPI
TransformFilterImpl_Release(IBaseFilter
* iface
)
316 TransformFilter
*This
= impl_from_IBaseFilter(iface
);
317 ULONG refCount
= BaseFilterImpl_Release(iface
);
319 TRACE("(%p/%p)->() Release from %d\n", This
, iface
, refCount
+ 1);
325 for (i
= 0; i
< This
->npins
; i
++)
329 if (SUCCEEDED(IPin_ConnectedTo(This
->ppPins
[i
], &pConnectedTo
)))
331 IPin_Disconnect(pConnectedTo
);
332 IPin_Release(pConnectedTo
);
334 IPin_Disconnect(This
->ppPins
[i
]);
336 IPin_Release(This
->ppPins
[i
]);
339 CoTaskMemFree(This
->ppPins
);
341 TRACE("Destroying transform filter\n");
342 This
->csReceive
.DebugInfo
->Spare
[0] = 0;
343 DeleteCriticalSection(&This
->csReceive
);
344 FreeMediaType(&This
->pmt
);
345 QualityControlImpl_Destroy(This
->qcimpl
);
346 IUnknown_Release(This
->seekthru_unk
);
355 /** IMediaFilter methods **/
357 HRESULT WINAPI
TransformFilterImpl_Stop(IBaseFilter
* iface
)
359 TransformFilter
*This
= impl_from_IBaseFilter(iface
);
362 TRACE("(%p/%p)\n", This
, iface
);
364 EnterCriticalSection(&This
->csReceive
);
366 This
->filter
.state
= State_Stopped
;
367 if (This
->pFuncsTable
->pfnStopStreaming
)
368 hr
= This
->pFuncsTable
->pfnStopStreaming(This
);
370 LeaveCriticalSection(&This
->csReceive
);
375 HRESULT WINAPI
TransformFilterImpl_Pause(IBaseFilter
* iface
)
377 TransformFilter
*This
= impl_from_IBaseFilter(iface
);
380 TRACE("(%p/%p)->()\n", This
, iface
);
382 EnterCriticalSection(&This
->csReceive
);
384 if (This
->filter
.state
== State_Stopped
)
385 hr
= IBaseFilter_Run(iface
, -1);
390 This
->filter
.state
= State_Paused
;
392 LeaveCriticalSection(&This
->csReceive
);
397 HRESULT WINAPI
TransformFilterImpl_Run(IBaseFilter
* iface
, REFERENCE_TIME tStart
)
400 TransformFilter
*This
= impl_from_IBaseFilter(iface
);
402 TRACE("(%p/%p)->(%s)\n", This
, iface
, wine_dbgstr_longlong(tStart
));
404 EnterCriticalSection(&This
->csReceive
);
406 if (This
->filter
.state
== State_Stopped
)
408 impl_BaseInputPin_from_IPin(This
->ppPins
[0])->end_of_stream
= 0;
409 if (This
->pFuncsTable
->pfnStartStreaming
)
410 hr
= This
->pFuncsTable
->pfnStartStreaming(This
);
412 hr
= BaseOutputPinImpl_Active(impl_BaseOutputPin_from_IPin(This
->ppPins
[1]));
417 This
->filter
.rtStreamStart
= tStart
;
418 This
->filter
.state
= State_Running
;
421 LeaveCriticalSection(&This
->csReceive
);
426 HRESULT WINAPI
TransformFilterImpl_Notify(TransformFilter
*iface
, IBaseFilter
*sender
, Quality qm
)
428 return QualityControlImpl_Notify((IQualityControl
*)iface
->qcimpl
, sender
, qm
);
431 /** IBaseFilter implementation **/
433 HRESULT WINAPI
TransformFilterImpl_FindPin(IBaseFilter
* iface
, LPCWSTR Id
, IPin
**ppPin
)
435 TransformFilter
*This
= impl_from_IBaseFilter(iface
);
437 TRACE("(%p/%p)->(%s,%p)\n", This
, iface
, debugstr_w(Id
), ppPin
);
442 static const IBaseFilterVtbl TransformFilter_Vtbl
=
444 TransformFilterImpl_QueryInterface
,
445 BaseFilterImpl_AddRef
,
446 TransformFilterImpl_Release
,
447 BaseFilterImpl_GetClassID
,
448 TransformFilterImpl_Stop
,
449 TransformFilterImpl_Pause
,
450 TransformFilterImpl_Run
,
451 BaseFilterImpl_GetState
,
452 BaseFilterImpl_SetSyncSource
,
453 BaseFilterImpl_GetSyncSource
,
454 BaseFilterImpl_EnumPins
,
455 TransformFilterImpl_FindPin
,
456 BaseFilterImpl_QueryFilterInfo
,
457 BaseFilterImpl_JoinFilterGraph
,
458 BaseFilterImpl_QueryVendorInfo
461 static HRESULT WINAPI
TransformFilter_InputPin_EndOfStream(IPin
* iface
)
463 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
464 TransformFilter
* pTransform
;
468 TRACE("(%p)->()\n", iface
);
470 /* Since we process samples synchronously, just forward notification downstream */
471 pTransform
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
475 hr
= IPin_ConnectedTo(pTransform
->ppPins
[1], &ppin
);
478 hr
= IPin_EndOfStream(ppin
);
487 static HRESULT WINAPI
TransformFilter_InputPin_ReceiveConnection(IPin
* iface
, IPin
* pReceivePin
, const AM_MEDIA_TYPE
* pmt
)
489 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
490 TransformFilter
* pTransform
;
493 TRACE("(%p)->(%p, %p)\n", iface
, pReceivePin
, pmt
);
495 pTransform
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
497 if (pTransform
->pFuncsTable
->pfnSetMediaType
)
498 hr
= pTransform
->pFuncsTable
->pfnSetMediaType(pTransform
, PINDIR_INPUT
, pmt
);
500 if (SUCCEEDED(hr
) && pTransform
->pFuncsTable
->pfnCompleteConnect
)
501 hr
= pTransform
->pFuncsTable
->pfnCompleteConnect(pTransform
, PINDIR_INPUT
, pReceivePin
);
505 hr
= BaseInputPinImpl_ReceiveConnection(iface
, pReceivePin
, pmt
);
506 if (FAILED(hr
) && pTransform
->pFuncsTable
->pfnBreakConnect
)
507 pTransform
->pFuncsTable
->pfnBreakConnect(pTransform
, PINDIR_INPUT
);
513 static HRESULT WINAPI
TransformFilter_InputPin_Disconnect(IPin
* iface
)
515 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
516 TransformFilter
* pTransform
;
518 TRACE("(%p)->()\n", iface
);
520 pTransform
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
521 if (pTransform
->pFuncsTable
->pfnBreakConnect
)
522 pTransform
->pFuncsTable
->pfnBreakConnect(pTransform
, PINDIR_INPUT
);
524 return BasePinImpl_Disconnect(iface
);
527 static HRESULT WINAPI
TransformFilter_InputPin_BeginFlush(IPin
* iface
)
529 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
530 TransformFilter
* pTransform
;
533 TRACE("(%p)->()\n", iface
);
535 pTransform
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
536 EnterCriticalSection(&pTransform
->filter
.csFilter
);
537 if (pTransform
->pFuncsTable
->pfnBeginFlush
)
538 hr
= pTransform
->pFuncsTable
->pfnBeginFlush(pTransform
);
540 hr
= BaseInputPinImpl_BeginFlush(iface
);
541 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
545 static HRESULT WINAPI
TransformFilter_InputPin_EndFlush(IPin
* iface
)
547 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
548 TransformFilter
* pTransform
;
551 TRACE("(%p)->()\n", iface
);
553 pTransform
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
554 EnterCriticalSection(&pTransform
->filter
.csFilter
);
555 if (pTransform
->pFuncsTable
->pfnEndFlush
)
556 hr
= pTransform
->pFuncsTable
->pfnEndFlush(pTransform
);
558 hr
= BaseInputPinImpl_EndFlush(iface
);
559 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
563 static HRESULT WINAPI
TransformFilter_InputPin_NewSegment(IPin
* iface
, REFERENCE_TIME tStart
, REFERENCE_TIME tStop
, double dRate
)
565 BaseInputPin
* This
= impl_BaseInputPin_from_IPin(iface
);
566 TransformFilter
* pTransform
;
569 TRACE("(%p)->()\n", iface
);
571 pTransform
= impl_from_IBaseFilter(This
->pin
.pinInfo
.pFilter
);
572 EnterCriticalSection(&pTransform
->filter
.csFilter
);
573 if (pTransform
->pFuncsTable
->pfnNewSegment
)
574 hr
= pTransform
->pFuncsTable
->pfnNewSegment(pTransform
, tStart
, tStop
, dRate
);
576 hr
= BaseInputPinImpl_NewSegment(iface
, tStart
, tStop
, dRate
);
577 LeaveCriticalSection(&pTransform
->filter
.csFilter
);
581 static const IPinVtbl TransformFilter_InputPin_Vtbl
=
583 BaseInputPinImpl_QueryInterface
,
585 BaseInputPinImpl_Release
,
586 BaseInputPinImpl_Connect
,
587 TransformFilter_InputPin_ReceiveConnection
,
588 TransformFilter_InputPin_Disconnect
,
589 BasePinImpl_ConnectedTo
,
590 BasePinImpl_ConnectionMediaType
,
591 BasePinImpl_QueryPinInfo
,
592 BasePinImpl_QueryDirection
,
594 BaseInputPinImpl_QueryAccept
,
595 BasePinImpl_EnumMediaTypes
,
596 BasePinImpl_QueryInternalConnections
,
597 TransformFilter_InputPin_EndOfStream
,
598 TransformFilter_InputPin_BeginFlush
,
599 TransformFilter_InputPin_EndFlush
,
600 TransformFilter_InputPin_NewSegment
603 static const IPinVtbl TransformFilter_OutputPin_Vtbl
=
605 BaseOutputPinImpl_QueryInterface
,
607 BaseOutputPinImpl_Release
,
608 BaseOutputPinImpl_Connect
,
609 BaseOutputPinImpl_ReceiveConnection
,
610 BaseOutputPinImpl_Disconnect
,
611 BasePinImpl_ConnectedTo
,
612 BasePinImpl_ConnectionMediaType
,
613 BasePinImpl_QueryPinInfo
,
614 BasePinImpl_QueryDirection
,
616 TransformFilter_Output_QueryAccept
,
617 BasePinImpl_EnumMediaTypes
,
618 BasePinImpl_QueryInternalConnections
,
619 BaseOutputPinImpl_EndOfStream
,
620 BaseOutputPinImpl_BeginFlush
,
621 BaseOutputPinImpl_EndFlush
,
622 BasePinImpl_NewSegment
625 static HRESULT WINAPI
TransformFilter_QualityControlImpl_Notify(IQualityControl
*iface
, IBaseFilter
*sender
, Quality qm
) {
626 QualityControlImpl
*qc
= (QualityControlImpl
*)iface
;
627 TransformFilter
*This
= impl_from_IBaseFilter(qc
->self
);
629 if (This
->pFuncsTable
->pfnNotify
)
630 return This
->pFuncsTable
->pfnNotify(This
, sender
, qm
);
632 return TransformFilterImpl_Notify(This
, sender
, qm
);
635 static const IQualityControlVtbl TransformFilter_QualityControl_Vtbl
= {
636 QualityControlImpl_QueryInterface
,
637 QualityControlImpl_AddRef
,
638 QualityControlImpl_Release
,
639 TransformFilter_QualityControlImpl_Notify
,
640 QualityControlImpl_SetSink