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