8f5815a2bfdd1d3852bfed24fd298a66a7425713
[reactos.git] / reactos / 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 = BaseFilterImpl_Release(iface);
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 CoTaskMemFree(This);
329
330 return 0;
331 }
332 else
333 return refCount;
334 }
335
336 /** IMediaFilter methods **/
337
338 HRESULT WINAPI TransformFilterImpl_Stop(IBaseFilter * iface)
339 {
340 TransformFilter *This = impl_from_IBaseFilter(iface);
341 HRESULT hr = S_OK;
342
343 TRACE("(%p/%p)\n", This, iface);
344
345 EnterCriticalSection(&This->csReceive);
346 {
347 This->filter.state = State_Stopped;
348 if (This->pFuncsTable->pfnStopStreaming)
349 hr = This->pFuncsTable->pfnStopStreaming(This);
350 }
351 LeaveCriticalSection(&This->csReceive);
352
353 return hr;
354 }
355
356 HRESULT WINAPI TransformFilterImpl_Pause(IBaseFilter * iface)
357 {
358 TransformFilter *This = impl_from_IBaseFilter(iface);
359 HRESULT hr;
360
361 TRACE("(%p/%p)->()\n", This, iface);
362
363 EnterCriticalSection(&This->csReceive);
364 {
365 if (This->filter.state == State_Stopped)
366 hr = IBaseFilter_Run(iface, -1);
367 else
368 hr = S_OK;
369
370 if (SUCCEEDED(hr))
371 This->filter.state = State_Paused;
372 }
373 LeaveCriticalSection(&This->csReceive);
374
375 return hr;
376 }
377
378 HRESULT WINAPI TransformFilterImpl_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
379 {
380 HRESULT hr = S_OK;
381 TransformFilter *This = impl_from_IBaseFilter(iface);
382
383 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
384
385 EnterCriticalSection(&This->csReceive);
386 {
387 if (This->filter.state == State_Stopped)
388 {
389 impl_BaseInputPin_from_IPin(This->ppPins[0])->end_of_stream = FALSE;
390 if (This->pFuncsTable->pfnStartStreaming)
391 hr = This->pFuncsTable->pfnStartStreaming(This);
392 if (SUCCEEDED(hr))
393 hr = BaseOutputPinImpl_Active(impl_BaseOutputPin_from_IPin(This->ppPins[1]));
394 }
395
396 if (SUCCEEDED(hr))
397 {
398 This->filter.rtStreamStart = tStart;
399 This->filter.state = State_Running;
400 }
401 }
402 LeaveCriticalSection(&This->csReceive);
403
404 return hr;
405 }
406
407 HRESULT WINAPI TransformFilterImpl_Notify(TransformFilter *iface, IBaseFilter *sender, Quality qm)
408 {
409 return QualityControlImpl_Notify((IQualityControl*)iface->qcimpl, sender, qm);
410 }
411
412 /** IBaseFilter implementation **/
413
414 HRESULT WINAPI TransformFilterImpl_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
415 {
416 TransformFilter *This = impl_from_IBaseFilter(iface);
417
418 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
419
420 return E_NOTIMPL;
421 }
422
423 static const IBaseFilterVtbl TransformFilter_Vtbl =
424 {
425 TransformFilterImpl_QueryInterface,
426 BaseFilterImpl_AddRef,
427 TransformFilterImpl_Release,
428 BaseFilterImpl_GetClassID,
429 TransformFilterImpl_Stop,
430 TransformFilterImpl_Pause,
431 TransformFilterImpl_Run,
432 BaseFilterImpl_GetState,
433 BaseFilterImpl_SetSyncSource,
434 BaseFilterImpl_GetSyncSource,
435 BaseFilterImpl_EnumPins,
436 TransformFilterImpl_FindPin,
437 BaseFilterImpl_QueryFilterInfo,
438 BaseFilterImpl_JoinFilterGraph,
439 BaseFilterImpl_QueryVendorInfo
440 };
441
442 static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface)
443 {
444 BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
445 TransformFilter* pTransform;
446 IPin* ppin;
447 HRESULT hr;
448
449 TRACE("(%p)->()\n", iface);
450
451 /* Since we process samples synchronously, just forward notification downstream */
452 pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
453 if (!pTransform)
454 hr = E_FAIL;
455 else
456 hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin);
457 if (SUCCEEDED(hr))
458 {
459 hr = IPin_EndOfStream(ppin);
460 IPin_Release(ppin);
461 }
462
463 if (FAILED(hr))
464 ERR("%x\n", hr);
465 return hr;
466 }
467
468 static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
469 {
470 BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
471 TransformFilter* pTransform;
472 HRESULT hr = S_OK;
473
474 TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt);
475
476 pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
477
478 if (pTransform->pFuncsTable->pfnSetMediaType)
479 hr = pTransform->pFuncsTable->pfnSetMediaType(pTransform, PINDIR_INPUT, pmt);
480
481 if (SUCCEEDED(hr) && pTransform->pFuncsTable->pfnCompleteConnect)
482 hr = pTransform->pFuncsTable->pfnCompleteConnect(pTransform, PINDIR_INPUT, pReceivePin);
483
484 if (SUCCEEDED(hr))
485 {
486 hr = BaseInputPinImpl_ReceiveConnection(iface, pReceivePin, pmt);
487 if (FAILED(hr) && pTransform->pFuncsTable->pfnBreakConnect)
488 pTransform->pFuncsTable->pfnBreakConnect(pTransform, PINDIR_INPUT);
489 }
490
491 return hr;
492 }
493
494 static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface)
495 {
496 BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
497 TransformFilter* pTransform;
498
499 TRACE("(%p)->()\n", iface);
500
501 pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
502 if (pTransform->pFuncsTable->pfnBreakConnect)
503 pTransform->pFuncsTable->pfnBreakConnect(pTransform, PINDIR_INPUT);
504
505 return BasePinImpl_Disconnect(iface);
506 }
507
508 static HRESULT WINAPI TransformFilter_InputPin_BeginFlush(IPin * iface)
509 {
510 BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
511 TransformFilter* pTransform;
512 HRESULT hr = S_OK;
513
514 TRACE("(%p)->()\n", iface);
515
516 pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
517 EnterCriticalSection(&pTransform->filter.csFilter);
518 if (pTransform->pFuncsTable->pfnBeginFlush)
519 hr = pTransform->pFuncsTable->pfnBeginFlush(pTransform);
520 if (SUCCEEDED(hr))
521 hr = BaseInputPinImpl_BeginFlush(iface);
522 LeaveCriticalSection(&pTransform->filter.csFilter);
523 return hr;
524 }
525
526 static HRESULT WINAPI TransformFilter_InputPin_EndFlush(IPin * iface)
527 {
528 BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
529 TransformFilter* pTransform;
530 HRESULT hr = S_OK;
531
532 TRACE("(%p)->()\n", iface);
533
534 pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
535 EnterCriticalSection(&pTransform->filter.csFilter);
536 if (pTransform->pFuncsTable->pfnEndFlush)
537 hr = pTransform->pFuncsTable->pfnEndFlush(pTransform);
538 if (SUCCEEDED(hr))
539 hr = BaseInputPinImpl_EndFlush(iface);
540 LeaveCriticalSection(&pTransform->filter.csFilter);
541 return hr;
542 }
543
544 static HRESULT WINAPI TransformFilter_InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
545 {
546 BaseInputPin* This = impl_BaseInputPin_from_IPin(iface);
547 TransformFilter* pTransform;
548 HRESULT hr = S_OK;
549
550 TRACE("(%p)->()\n", iface);
551
552 pTransform = impl_from_IBaseFilter(This->pin.pinInfo.pFilter);
553 EnterCriticalSection(&pTransform->filter.csFilter);
554 if (pTransform->pFuncsTable->pfnNewSegment)
555 hr = pTransform->pFuncsTable->pfnNewSegment(pTransform, tStart, tStop, dRate);
556 if (SUCCEEDED(hr))
557 hr = BaseInputPinImpl_NewSegment(iface, tStart, tStop, dRate);
558 LeaveCriticalSection(&pTransform->filter.csFilter);
559 return hr;
560 }
561
562 static const IPinVtbl TransformFilter_InputPin_Vtbl =
563 {
564 BaseInputPinImpl_QueryInterface,
565 BasePinImpl_AddRef,
566 BaseInputPinImpl_Release,
567 BaseInputPinImpl_Connect,
568 TransformFilter_InputPin_ReceiveConnection,
569 TransformFilter_InputPin_Disconnect,
570 BasePinImpl_ConnectedTo,
571 BasePinImpl_ConnectionMediaType,
572 BasePinImpl_QueryPinInfo,
573 BasePinImpl_QueryDirection,
574 BasePinImpl_QueryId,
575 BaseInputPinImpl_QueryAccept,
576 BasePinImpl_EnumMediaTypes,
577 BasePinImpl_QueryInternalConnections,
578 TransformFilter_InputPin_EndOfStream,
579 TransformFilter_InputPin_BeginFlush,
580 TransformFilter_InputPin_EndFlush,
581 TransformFilter_InputPin_NewSegment
582 };
583
584 static const IPinVtbl TransformFilter_OutputPin_Vtbl =
585 {
586 BaseOutputPinImpl_QueryInterface,
587 BasePinImpl_AddRef,
588 BaseOutputPinImpl_Release,
589 BaseOutputPinImpl_Connect,
590 BaseOutputPinImpl_ReceiveConnection,
591 BaseOutputPinImpl_Disconnect,
592 BasePinImpl_ConnectedTo,
593 BasePinImpl_ConnectionMediaType,
594 BasePinImpl_QueryPinInfo,
595 BasePinImpl_QueryDirection,
596 BasePinImpl_QueryId,
597 TransformFilter_Output_QueryAccept,
598 BasePinImpl_EnumMediaTypes,
599 BasePinImpl_QueryInternalConnections,
600 BaseOutputPinImpl_EndOfStream,
601 BaseOutputPinImpl_BeginFlush,
602 BaseOutputPinImpl_EndFlush,
603 BasePinImpl_NewSegment
604 };
605
606 static HRESULT WINAPI TransformFilter_QualityControlImpl_Notify(IQualityControl *iface, IBaseFilter *sender, Quality qm) {
607 QualityControlImpl *qc = (QualityControlImpl*)iface;
608 TransformFilter *This = impl_from_IBaseFilter(qc->self);
609
610 if (This->pFuncsTable->pfnNotify)
611 return This->pFuncsTable->pfnNotify(This, sender, qm);
612 else
613 return TransformFilterImpl_Notify(This, sender, qm);
614 }
615
616 static const IQualityControlVtbl TransformFilter_QualityControl_Vtbl = {
617 QualityControlImpl_QueryInterface,
618 QualityControlImpl_AddRef,
619 QualityControlImpl_Release,
620 TransformFilter_QualityControlImpl_Notify,
621 QualityControlImpl_SetSink
622 };