xref: /reactos/sdk/lib/3rdparty/strmbase/transform.c (revision 10517de5)
1 /*
2  * Transform Filter (Base for decoders, etc...)
3  *
4  * Copyright 2005 Christian Costa
5  * Copyright 2010 Aric Stewart, CodeWeavers
6  *
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.
11  *
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.
16  *
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
20  */
21 #include "config.h"
22 #include <stdarg.h>
23 
24 #define COBJMACROS
25 
26 #include "windef.h"
27 #include "winbase.h"
28 #include "dshow.h"
29 #include "amvideo.h"
30 #include "strmif.h"
31 #include "vfw.h"
32 
33 #include <assert.h>
34 
35 #include "wine/unicode.h"
36 #include "wine/debug.h"
37 #include "wine/strmbase.h"
38 #include "strmbase_private.h"
39 
40 WINE_DEFAULT_DEBUG_CHANNEL(strmbase);
41 
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};
44 
45 static const IPinVtbl TransformFilter_InputPin_Vtbl;
46 static const IPinVtbl TransformFilter_OutputPin_Vtbl;
47 static const IQualityControlVtbl TransformFilter_QualityControl_Vtbl;
48 
impl_BaseInputPin_from_BasePin(BasePin * iface)49 static inline BaseInputPin *impl_BaseInputPin_from_BasePin( BasePin *iface )
50 {
51     return CONTAINING_RECORD(iface, BaseInputPin, pin);
52 }
53 
impl_BasePin_from_IPin(IPin * iface)54 static inline BasePin *impl_BasePin_from_IPin( IPin *iface )
55 {
56     return CONTAINING_RECORD(iface, BasePin, IPin_iface);
57 }
58 
impl_BaseInputPin_from_IPin(IPin * iface)59 static inline BaseInputPin *impl_BaseInputPin_from_IPin( IPin *iface )
60 {
61     return CONTAINING_RECORD(iface, BaseInputPin, pin.IPin_iface);
62 }
63 
impl_BaseOutputPin_from_IPin(IPin * iface)64 static inline BaseOutputPin *impl_BaseOutputPin_from_IPin( IPin *iface )
65 {
66     return CONTAINING_RECORD(iface, BaseOutputPin, pin.IPin_iface);
67 }
68 
impl_from_IBaseFilter(IBaseFilter * iface)69 static inline TransformFilter *impl_from_IBaseFilter( IBaseFilter *iface )
70 {
71     return CONTAINING_RECORD(iface, TransformFilter, filter.IBaseFilter_iface);
72 }
73 
impl_from_BaseFilter(BaseFilter * iface)74 static inline TransformFilter *impl_from_BaseFilter( BaseFilter *iface )
75 {
76     return CONTAINING_RECORD(iface, TransformFilter, filter);
77 }
78 
TransformFilter_Input_CheckMediaType(BasePin * iface,const AM_MEDIA_TYPE * pmt)79 static HRESULT WINAPI TransformFilter_Input_CheckMediaType(BasePin *iface, const AM_MEDIA_TYPE * pmt)
80 {
81     BaseInputPin* This = impl_BaseInputPin_from_BasePin(iface);
82     TransformFilter * pTransform;
83 
84     TRACE("%p\n", iface);
85     pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
86 
87     if (pTransform->pFuncsTable->pfnCheckInputType)
88         return pTransform->pFuncsTable->pfnCheckInputType(pTransform, pmt);
89     /* Assume OK if there's no query method (the connection will fail if
90        needed) */
91     return S_OK;
92 }
93 
TransformFilter_Input_Receive(BaseInputPin * This,IMediaSample * pInSample)94 static HRESULT WINAPI TransformFilter_Input_Receive(BaseInputPin *This, IMediaSample *pInSample)
95 {
96     HRESULT hr;
97     TransformFilter * pTransform;
98     TRACE("%p\n", This);
99     pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
100 
101     EnterCriticalSection(&pTransform->csReceive);
102     if (pTransform->filter.state == State_Stopped)
103     {
104         LeaveCriticalSection(&pTransform->csReceive);
105         return VFW_E_WRONG_STATE;
106     }
107 
108     if (This->end_of_stream || This->flushing)
109     {
110         LeaveCriticalSection(&pTransform->csReceive);
111         return S_FALSE;
112     }
113 
114     LeaveCriticalSection(&pTransform->csReceive);
115     if (pTransform->pFuncsTable->pfnReceive)
116         hr = pTransform->pFuncsTable->pfnReceive(pTransform, pInSample);
117     else
118         hr = S_FALSE;
119 
120     return hr;
121 }
122 
TransformFilter_Output_QueryAccept(IPin * iface,const AM_MEDIA_TYPE * pmt)123 static HRESULT WINAPI TransformFilter_Output_QueryAccept(IPin *iface, const AM_MEDIA_TYPE * pmt)
124 {
125     BasePin *This = impl_BasePin_from_IPin(iface);
126     TransformFilter *pTransformFilter = impl_from_IBaseFilter(This->pinInfo.pFilter);
127     AM_MEDIA_TYPE* outpmt = &pTransformFilter->pmt;
128     TRACE("%p\n", iface);
129 
130     if (IsEqualIID(&pmt->majortype, &outpmt->majortype)
131         && (IsEqualIID(&pmt->subtype, &outpmt->subtype) || IsEqualIID(&outpmt->subtype, &GUID_NULL)))
132         return S_OK;
133     return S_FALSE;
134 }
135 
TransformFilter_Output_DecideBufferSize(BaseOutputPin * This,IMemAllocator * pAlloc,ALLOCATOR_PROPERTIES * ppropInputRequest)136 static HRESULT WINAPI TransformFilter_Output_DecideBufferSize(BaseOutputPin *This, IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest)
137 {
138     TransformFilter *pTransformFilter = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
139     return pTransformFilter->pFuncsTable->pfnDecideBufferSize(pTransformFilter, pAlloc, ppropInputRequest);
140 }
141 
TransformFilter_Output_GetMediaType(BasePin * This,int iPosition,AM_MEDIA_TYPE * pmt)142 static HRESULT WINAPI TransformFilter_Output_GetMediaType(BasePin *This, int iPosition, AM_MEDIA_TYPE *pmt)
143 {
144     TransformFilter *pTransform = impl_from_IBaseFilter(This->pinInfo.pFilter);
145 
146     if (iPosition < 0)
147         return E_INVALIDARG;
148     if (iPosition > 0)
149         return VFW_S_NO_MORE_ITEMS;
150     CopyMediaType(pmt, &pTransform->pmt);
151     return S_OK;
152 }
153 
TransformFilter_GetPin(BaseFilter * iface,int pos)154 static IPin* WINAPI TransformFilter_GetPin(BaseFilter *iface, int pos)
155 {
156     TransformFilter *This = impl_from_BaseFilter(iface);
157 
158     if (pos >= This->npins || pos < 0)
159         return NULL;
160 
161     IPin_AddRef(This->ppPins[pos]);
162     return This->ppPins[pos];
163 }
164 
TransformFilter_GetPinCount(BaseFilter * iface)165 static LONG WINAPI TransformFilter_GetPinCount(BaseFilter *iface)
166 {
167     TransformFilter *This = impl_from_BaseFilter(iface);
168 
169     return (This->npins+1);
170 }
171 
172 static const BaseFilterFuncTable tfBaseFuncTable = {
173     TransformFilter_GetPin,
174     TransformFilter_GetPinCount
175 };
176 
177 static const BaseInputPinFuncTable tf_input_BaseInputFuncTable = {
178     {
179         TransformFilter_Input_CheckMediaType,
180         NULL,
181         BasePinImpl_GetMediaTypeVersion,
182         BasePinImpl_GetMediaType
183     },
184     TransformFilter_Input_Receive
185 };
186 
187 static const BaseOutputPinFuncTable tf_output_BaseOutputFuncTable = {
188     {
189         NULL,
190         BaseOutputPinImpl_AttemptConnection,
191         BasePinImpl_GetMediaTypeVersion,
192         TransformFilter_Output_GetMediaType
193     },
194     TransformFilter_Output_DecideBufferSize,
195     BaseOutputPinImpl_DecideAllocator,
196     BaseOutputPinImpl_BreakConnect
197 };
198 
TransformFilter_Init(const IBaseFilterVtbl * pVtbl,const CLSID * pClsid,const TransformFilterFuncTable * pFuncsTable,TransformFilter * pTransformFilter)199 static HRESULT TransformFilter_Init(const IBaseFilterVtbl *pVtbl, const CLSID* pClsid, const TransformFilterFuncTable* pFuncsTable, TransformFilter* pTransformFilter)
200 {
201     HRESULT hr;
202     PIN_INFO piInput;
203     PIN_INFO piOutput;
204 
205     BaseFilter_Init(&pTransformFilter->filter, pVtbl, pClsid, (DWORD_PTR)(__FILE__ ": TransformFilter.csFilter"), &tfBaseFuncTable);
206 
207     InitializeCriticalSection(&pTransformFilter->csReceive);
208     pTransformFilter->csReceive.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": TransformFilter.csReceive");
209 
210     /* pTransformFilter is already allocated */
211     pTransformFilter->pFuncsTable = pFuncsTable;
212     ZeroMemory(&pTransformFilter->pmt, sizeof(pTransformFilter->pmt));
213     pTransformFilter->npins = 2;
214 
215     pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
216 
217     /* construct input pin */
218     piInput.dir = PINDIR_INPUT;
219     piInput.pFilter = &pTransformFilter->filter.IBaseFilter_iface;
220     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
221     piOutput.dir = PINDIR_OUTPUT;
222     piOutput.pFilter = &pTransformFilter->filter.IBaseFilter_iface;
223     lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
224 
225     hr = BaseInputPin_Construct(&TransformFilter_InputPin_Vtbl, sizeof(BaseInputPin), &piInput,
226             &tf_input_BaseInputFuncTable, &pTransformFilter->filter.csFilter, NULL, &pTransformFilter->ppPins[0]);
227 
228     if (SUCCEEDED(hr))
229     {
230         hr = BaseOutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(BaseOutputPin), &piOutput, &tf_output_BaseOutputFuncTable, &pTransformFilter->filter.csFilter, &pTransformFilter->ppPins[1]);
231 
232         if (FAILED(hr))
233             ERR("Cannot create output pin (%x)\n", hr);
234         else {
235             QualityControlImpl_Create( pTransformFilter->ppPins[0], &pTransformFilter->filter.IBaseFilter_iface, &pTransformFilter->qcimpl);
236             pTransformFilter->qcimpl->IQualityControl_iface.lpVtbl = &TransformFilter_QualityControl_Vtbl;
237         }
238     }
239 
240     if (SUCCEEDED(hr))
241     {
242         ISeekingPassThru *passthru;
243         pTransformFilter->seekthru_unk = NULL;
244         hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown *)&pTransformFilter->filter.IBaseFilter_iface, CLSCTX_INPROC_SERVER,
245                 &IID_IUnknown, (void **)&pTransformFilter->seekthru_unk);
246         if (SUCCEEDED(hr))
247         {
248             IUnknown_QueryInterface(pTransformFilter->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
249             ISeekingPassThru_Init(passthru, FALSE, pTransformFilter->ppPins[0]);
250             ISeekingPassThru_Release(passthru);
251         }
252     }
253 
254     if (FAILED(hr))
255     {
256         CoTaskMemFree(pTransformFilter->ppPins);
257         BaseFilterImpl_Release(&pTransformFilter->filter.IBaseFilter_iface);
258     }
259 
260     return hr;
261 }
262 
TransformFilter_Construct(const IBaseFilterVtbl * pVtbl,LONG filter_size,const CLSID * pClsid,const TransformFilterFuncTable * pFuncsTable,IBaseFilter ** ppTransformFilter)263 HRESULT TransformFilter_Construct(const IBaseFilterVtbl *pVtbl, LONG filter_size, const CLSID* pClsid, const TransformFilterFuncTable* pFuncsTable, IBaseFilter ** ppTransformFilter)
264 {
265     TransformFilter* pTf;
266 
267     *ppTransformFilter = NULL;
268 
269     assert(filter_size >= sizeof(TransformFilter));
270 
271     pTf = CoTaskMemAlloc(filter_size);
272 
273     if (!pTf)
274         return E_OUTOFMEMORY;
275 
276     ZeroMemory(pTf, filter_size);
277 
278     if (SUCCEEDED(TransformFilter_Init(pVtbl, pClsid, pFuncsTable, pTf)))
279     {
280         *ppTransformFilter = &pTf->filter.IBaseFilter_iface;
281         return S_OK;
282     }
283 
284     CoTaskMemFree(pTf);
285     return E_FAIL;
286 }
287 
TransformFilterImpl_QueryInterface(IBaseFilter * iface,REFIID riid,LPVOID * ppv)288 HRESULT WINAPI TransformFilterImpl_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
289 {
290     HRESULT hr;
291     TransformFilter *This = impl_from_IBaseFilter(iface);
292     TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
293 
294     if (IsEqualIID(riid, &IID_IQualityControl))  {
295         *ppv = (IQualityControl*)This->qcimpl;
296         IUnknown_AddRef((IUnknown*)*ppv);
297         return S_OK;
298     }
299     else if (IsEqualIID(riid, &IID_IMediaSeeking) ||
300              IsEqualIID(riid, &IID_IMediaPosition))
301     {
302         return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
303     }
304     hr = BaseFilterImpl_QueryInterface(iface, riid, ppv);
305 
306     if (FAILED(hr) && !IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow) &&
307         !IsEqualIID(riid, &IID_IAMFilterMiscFlags))
308         FIXME("No interface for %s!\n", debugstr_guid(riid));
309 
310     return hr;
311 }
312 
TransformFilterImpl_Release(IBaseFilter * iface)313 ULONG WINAPI TransformFilterImpl_Release(IBaseFilter * iface)
314 {
315     TransformFilter *This = impl_from_IBaseFilter(iface);
316     ULONG refCount = InterlockedDecrement(&This->filter.refCount);
317 
318     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
319 
320     if (!refCount)
321     {
322         ULONG i;
323 
324         for (i = 0; i < This->npins; i++)
325         {
326             IPin *pConnectedTo;
327 
328             if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
329             {
330                 IPin_Disconnect(pConnectedTo);
331                 IPin_Release(pConnectedTo);
332             }
333             IPin_Disconnect(This->ppPins[i]);
334 
335             IPin_Release(This->ppPins[i]);
336         }
337 
338         CoTaskMemFree(This->ppPins);
339 
340         TRACE("Destroying transform filter\n");
341         This->csReceive.DebugInfo->Spare[0] = 0;
342         DeleteCriticalSection(&This->csReceive);
343         FreeMediaType(&This->pmt);
344         QualityControlImpl_Destroy(This->qcimpl);
345         IUnknown_Release(This->seekthru_unk);
346         BaseFilter_Destroy(&This->filter);
347         CoTaskMemFree(This);
348     }
349     return refCount;
350 }
351 
352 /** IMediaFilter methods **/
353 
TransformFilterImpl_Stop(IBaseFilter * iface)354 HRESULT WINAPI TransformFilterImpl_Stop(IBaseFilter * iface)
355 {
356     TransformFilter *This = impl_from_IBaseFilter(iface);
357     HRESULT hr = S_OK;
358 
359     TRACE("(%p/%p)\n", This, iface);
360 
361     EnterCriticalSection(&This->csReceive);
362     {
363         This->filter.state = State_Stopped;
364         if (This->pFuncsTable->pfnStopStreaming)
365             hr = This->pFuncsTable->pfnStopStreaming(This);
366         if (SUCCEEDED(hr))
367             hr = BaseOutputPinImpl_Inactive(impl_BaseOutputPin_from_IPin(This->ppPins[1]));
368     }
369     LeaveCriticalSection(&This->csReceive);
370 
371     return hr;
372 }
373 
TransformFilterImpl_Pause(IBaseFilter * iface)374 HRESULT WINAPI TransformFilterImpl_Pause(IBaseFilter * iface)
375 {
376     TransformFilter *This = impl_from_IBaseFilter(iface);
377     HRESULT hr;
378 
379     TRACE("(%p/%p)->()\n", This, iface);
380 
381     EnterCriticalSection(&This->csReceive);
382     {
383         if (This->filter.state == State_Stopped)
384             hr = IBaseFilter_Run(iface, -1);
385         else
386             hr = S_OK;
387 
388         if (SUCCEEDED(hr))
389             This->filter.state = State_Paused;
390     }
391     LeaveCriticalSection(&This->csReceive);
392 
393     return hr;
394 }
395 
TransformFilterImpl_Run(IBaseFilter * iface,REFERENCE_TIME tStart)396 HRESULT WINAPI TransformFilterImpl_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
397 {
398     HRESULT hr = S_OK;
399     TransformFilter *This = impl_from_IBaseFilter(iface);
400 
401     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
402 
403     EnterCriticalSection(&This->csReceive);
404     {
405         if (This->filter.state == State_Stopped)
406         {
407             impl_BaseInputPin_from_IPin(This->ppPins[0])->end_of_stream = FALSE;
408             if (This->pFuncsTable->pfnStartStreaming)
409                 hr = This->pFuncsTable->pfnStartStreaming(This);
410             if (SUCCEEDED(hr))
411                 hr = BaseOutputPinImpl_Active(impl_BaseOutputPin_from_IPin(This->ppPins[1]));
412         }
413 
414         if (SUCCEEDED(hr))
415         {
416             This->filter.rtStreamStart = tStart;
417             This->filter.state = State_Running;
418         }
419     }
420     LeaveCriticalSection(&This->csReceive);
421 
422     return hr;
423 }
424 
TransformFilterImpl_Notify(TransformFilter * iface,IBaseFilter * sender,Quality qm)425 HRESULT WINAPI TransformFilterImpl_Notify(TransformFilter *iface, IBaseFilter *sender, Quality qm)
426 {
427     return QualityControlImpl_Notify((IQualityControl*)iface->qcimpl, sender, qm);
428 }
429 
430 /** IBaseFilter implementation **/
431 
TransformFilterImpl_FindPin(IBaseFilter * iface,LPCWSTR Id,IPin ** ppPin)432 HRESULT WINAPI TransformFilterImpl_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
433 {
434     TransformFilter *This = impl_from_IBaseFilter(iface);
435 
436     TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
437 
438     return E_NOTIMPL;
439 }
440 
TransformFilter_InputPin_EndOfStream(IPin * iface)441 static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface)
442 {
443     BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
444     TransformFilter* pTransform;
445     IPin* ppin;
446     HRESULT hr;
447 
448     TRACE("(%p)->()\n", iface);
449 
450     /* Since we process samples synchronously, just forward notification downstream */
451     pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
452     if (!pTransform)
453         hr = E_FAIL;
454     else
455         hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin);
456     if (SUCCEEDED(hr))
457     {
458         hr = IPin_EndOfStream(ppin);
459         IPin_Release(ppin);
460     }
461 
462     if (FAILED(hr))
463         ERR("%x\n", hr);
464     return hr;
465 }
466 
TransformFilter_InputPin_ReceiveConnection(IPin * iface,IPin * pReceivePin,const AM_MEDIA_TYPE * pmt)467 static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
468 {
469     BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
470     TransformFilter* pTransform;
471     HRESULT hr = S_OK;
472 
473     TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt);
474 
475     pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
476 
477     if (pTransform->pFuncsTable->pfnSetMediaType)
478         hr = pTransform->pFuncsTable->pfnSetMediaType(pTransform, PINDIR_INPUT, pmt);
479 
480     if (SUCCEEDED(hr) && pTransform->pFuncsTable->pfnCompleteConnect)
481         hr = pTransform->pFuncsTable->pfnCompleteConnect(pTransform, PINDIR_INPUT, pReceivePin);
482 
483     if (SUCCEEDED(hr))
484     {
485         hr = BaseInputPinImpl_ReceiveConnection(iface, pReceivePin, pmt);
486         if (FAILED(hr) && pTransform->pFuncsTable->pfnBreakConnect)
487             pTransform->pFuncsTable->pfnBreakConnect(pTransform, PINDIR_INPUT);
488     }
489 
490     return hr;
491 }
492 
TransformFilter_InputPin_Disconnect(IPin * iface)493 static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface)
494 {
495     BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
496     TransformFilter* pTransform;
497 
498     TRACE("(%p)->()\n", iface);
499 
500     pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
501     if (pTransform->pFuncsTable->pfnBreakConnect)
502         pTransform->pFuncsTable->pfnBreakConnect(pTransform, PINDIR_INPUT);
503 
504     return BasePinImpl_Disconnect(iface);
505 }
506 
TransformFilter_InputPin_BeginFlush(IPin * iface)507 static HRESULT WINAPI TransformFilter_InputPin_BeginFlush(IPin * iface)
508 {
509     BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
510     TransformFilter* pTransform;
511     HRESULT hr = S_OK;
512 
513     TRACE("(%p)->()\n", iface);
514 
515     pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
516     EnterCriticalSection(&pTransform->filter.csFilter);
517     if (pTransform->pFuncsTable->pfnBeginFlush)
518         hr = pTransform->pFuncsTable->pfnBeginFlush(pTransform);
519     if (SUCCEEDED(hr))
520         hr = BaseInputPinImpl_BeginFlush(iface);
521     LeaveCriticalSection(&pTransform->filter.csFilter);
522     return hr;
523 }
524 
TransformFilter_InputPin_EndFlush(IPin * iface)525 static HRESULT WINAPI TransformFilter_InputPin_EndFlush(IPin * iface)
526 {
527     BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
528     TransformFilter* pTransform;
529     HRESULT hr = S_OK;
530 
531     TRACE("(%p)->()\n", iface);
532 
533     pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
534     EnterCriticalSection(&pTransform->filter.csFilter);
535     if (pTransform->pFuncsTable->pfnEndFlush)
536         hr = pTransform->pFuncsTable->pfnEndFlush(pTransform);
537     if (SUCCEEDED(hr))
538         hr = BaseInputPinImpl_EndFlush(iface);
539     LeaveCriticalSection(&pTransform->filter.csFilter);
540     return hr;
541 }
542 
TransformFilter_InputPin_NewSegment(IPin * iface,REFERENCE_TIME tStart,REFERENCE_TIME tStop,double dRate)543 static HRESULT WINAPI TransformFilter_InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
544 {
545     BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
546     TransformFilter* pTransform;
547     HRESULT hr = S_OK;
548 
549     TRACE("(%p)->(%s %s %e)\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate);
550 
551     pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
552     EnterCriticalSection(&pTransform->filter.csFilter);
553     if (pTransform->pFuncsTable->pfnNewSegment)
554         hr = pTransform->pFuncsTable->pfnNewSegment(pTransform, tStart, tStop, dRate);
555     if (SUCCEEDED(hr))
556         hr = BaseInputPinImpl_NewSegment(iface, tStart, tStop, dRate);
557     LeaveCriticalSection(&pTransform->filter.csFilter);
558     return hr;
559 }
560 
561 static const IPinVtbl TransformFilter_InputPin_Vtbl =
562 {
563     BaseInputPinImpl_QueryInterface,
564     BasePinImpl_AddRef,
565     BaseInputPinImpl_Release,
566     BaseInputPinImpl_Connect,
567     TransformFilter_InputPin_ReceiveConnection,
568     TransformFilter_InputPin_Disconnect,
569     BasePinImpl_ConnectedTo,
570     BasePinImpl_ConnectionMediaType,
571     BasePinImpl_QueryPinInfo,
572     BasePinImpl_QueryDirection,
573     BasePinImpl_QueryId,
574     BaseInputPinImpl_QueryAccept,
575     BasePinImpl_EnumMediaTypes,
576     BasePinImpl_QueryInternalConnections,
577     TransformFilter_InputPin_EndOfStream,
578     TransformFilter_InputPin_BeginFlush,
579     TransformFilter_InputPin_EndFlush,
580     TransformFilter_InputPin_NewSegment
581 };
582 
583 static const IPinVtbl TransformFilter_OutputPin_Vtbl =
584 {
585     BaseOutputPinImpl_QueryInterface,
586     BasePinImpl_AddRef,
587     BaseOutputPinImpl_Release,
588     BaseOutputPinImpl_Connect,
589     BaseOutputPinImpl_ReceiveConnection,
590     BaseOutputPinImpl_Disconnect,
591     BasePinImpl_ConnectedTo,
592     BasePinImpl_ConnectionMediaType,
593     BasePinImpl_QueryPinInfo,
594     BasePinImpl_QueryDirection,
595     BasePinImpl_QueryId,
596     TransformFilter_Output_QueryAccept,
597     BasePinImpl_EnumMediaTypes,
598     BasePinImpl_QueryInternalConnections,
599     BaseOutputPinImpl_EndOfStream,
600     BaseOutputPinImpl_BeginFlush,
601     BaseOutputPinImpl_EndFlush,
602     BasePinImpl_NewSegment
603 };
604 
TransformFilter_QualityControlImpl_Notify(IQualityControl * iface,IBaseFilter * sender,Quality qm)605 static HRESULT WINAPI TransformFilter_QualityControlImpl_Notify(IQualityControl *iface, IBaseFilter *sender, Quality qm) {
606     QualityControlImpl *qc = (QualityControlImpl*)iface;
607     TransformFilter *This = impl_from_IBaseFilter(qc->self);
608 
609     if (This->pFuncsTable->pfnNotify)
610         return This->pFuncsTable->pfnNotify(This, sender, qm);
611     else
612         return TransformFilterImpl_Notify(This, sender, qm);
613 }
614 
615 static const IQualityControlVtbl TransformFilter_QualityControl_Vtbl = {
616     QualityControlImpl_QueryInterface,
617     QualityControlImpl_AddRef,
618     QualityControlImpl_Release,
619     TransformFilter_QualityControlImpl_Notify,
620     QualityControlImpl_SetSink
621 };
622