[STRMBASE]
[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 BasePinFuncTable tf_input_BaseFuncTable = {
161 TransformFilter_Input_CheckMediaType,
162 NULL,
163 BasePinImpl_GetMediaTypeVersion,
164 BasePinImpl_GetMediaType
165 };
166
167 static const BaseInputPinFuncTable tf_input_BaseInputFuncTable = {
168 TransformFilter_Input_Receive
169 };
170
171 static const BasePinFuncTable tf_output_BaseFuncTable = {
172 NULL,
173 BaseOutputPinImpl_AttemptConnection,
174 BasePinImpl_GetMediaTypeVersion,
175 TransformFilter_Output_GetMediaType
176 };
177
178 static const BaseOutputPinFuncTable tf_output_BaseOutputFuncTable = {
179 TransformFilter_Output_DecideBufferSize,
180 BaseOutputPinImpl_DecideAllocator,
181 BaseOutputPinImpl_BreakConnect
182 };
183
184 static HRESULT TransformFilter_Init(const IBaseFilterVtbl *pVtbl, const CLSID* pClsid, const TransformFilterFuncTable* pFuncsTable, TransformFilter* pTransformFilter)
185 {
186 HRESULT hr;
187 PIN_INFO piInput;
188 PIN_INFO piOutput;
189
190 BaseFilter_Init(&pTransformFilter->filter, pVtbl, pClsid, (DWORD_PTR)(__FILE__ ": TransformFilter.csFilter"), &tfBaseFuncTable);
191
192 InitializeCriticalSection(&pTransformFilter->csReceive);
193 pTransformFilter->csReceive.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": TransformFilter.csReceive");
194
195 /* pTransformFilter is already allocated */
196 pTransformFilter->pFuncsTable = pFuncsTable;
197 ZeroMemory(&pTransformFilter->pmt, sizeof(pTransformFilter->pmt));
198 pTransformFilter->npins = 2;
199
200 pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
201
202 /* construct input pin */
203 piInput.dir = PINDIR_INPUT;
204 piInput.pFilter = &pTransformFilter->filter.IBaseFilter_iface;
205 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
206 piOutput.dir = PINDIR_OUTPUT;
207 piOutput.pFilter = &pTransformFilter->filter.IBaseFilter_iface;
208 lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
209
210 hr = BaseInputPin_Construct(&TransformFilter_InputPin_Vtbl, &piInput, &tf_input_BaseFuncTable, &tf_input_BaseInputFuncTable, &pTransformFilter->filter.csFilter, NULL, &pTransformFilter->ppPins[0]);
211
212 if (SUCCEEDED(hr))
213 {
214 hr = BaseOutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(BaseOutputPin), &piOutput, &tf_output_BaseFuncTable, &tf_output_BaseOutputFuncTable, &pTransformFilter->filter.csFilter, &pTransformFilter->ppPins[1]);
215
216 if (FAILED(hr))
217 ERR("Cannot create output pin (%x)\n", hr);
218 else {
219 QualityControlImpl_Create( pTransformFilter->ppPins[0], &pTransformFilter->filter.IBaseFilter_iface, &pTransformFilter->qcimpl);
220 pTransformFilter->qcimpl->IQualityControl_iface.lpVtbl = &TransformFilter_QualityControl_Vtbl;
221 }
222 }
223
224 if (SUCCEEDED(hr))
225 {
226 ISeekingPassThru *passthru;
227 pTransformFilter->seekthru_unk = NULL;
228 hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)pTransformFilter, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&pTransformFilter->seekthru_unk);
229 if (SUCCEEDED(hr))
230 {
231 IUnknown_QueryInterface(pTransformFilter->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
232 ISeekingPassThru_Init(passthru, FALSE, pTransformFilter->ppPins[0]);
233 ISeekingPassThru_Release(passthru);
234 }
235 }
236
237 if (FAILED(hr))
238 {
239 CoTaskMemFree(pTransformFilter->ppPins);
240 BaseFilterImpl_Release(&pTransformFilter->filter.IBaseFilter_iface);
241 }
242
243 return hr;
244 }
245
246 HRESULT TransformFilter_Construct(const IBaseFilterVtbl *pVtbl, LONG filter_size, const CLSID* pClsid, const TransformFilterFuncTable* pFuncsTable, IBaseFilter ** ppTransformFilter)
247 {
248 TransformFilter* pTf;
249
250 *ppTransformFilter = NULL;
251
252 assert(filter_size >= sizeof(TransformFilter));
253
254 pTf = CoTaskMemAlloc(filter_size);
255
256 if (!pTf)
257 return E_OUTOFMEMORY;
258
259 ZeroMemory(pTf, filter_size);
260
261 if (SUCCEEDED(TransformFilter_Init(pVtbl, pClsid, pFuncsTable, pTf)))
262 {
263 *ppTransformFilter = &pTf->filter.IBaseFilter_iface;
264 return S_OK;
265 }
266
267 CoTaskMemFree(pTf);
268 return E_FAIL;
269 }
270
271 HRESULT WINAPI TransformFilterImpl_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
272 {
273 HRESULT hr;
274 TransformFilter *This = impl_from_IBaseFilter(iface);
275 TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
276
277 if (IsEqualIID(riid, &IID_IQualityControl)) {
278 *ppv = (IQualityControl*)This->qcimpl;
279 IUnknown_AddRef((IUnknown*)*ppv);
280 return S_OK;
281 }
282 else if (IsEqualIID(riid, &IID_IMediaSeeking) ||
283 IsEqualIID(riid, &IID_IMediaPosition))
284 {
285 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
286 }
287 hr = BaseFilterImpl_QueryInterface(iface, riid, ppv);
288
289 if (FAILED(hr) && !IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow) &&
290 !IsEqualIID(riid, &IID_IAMFilterMiscFlags))
291 FIXME("No interface for %s!\n", debugstr_guid(riid));
292
293 return hr;
294 }
295
296 ULONG WINAPI TransformFilterImpl_Release(IBaseFilter * iface)
297 {
298 TransformFilter *This = impl_from_IBaseFilter(iface);
299 ULONG refCount = BaseFilterImpl_Release(iface);
300
301 TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
302
303 if (!refCount)
304 {
305 ULONG i;
306
307 for (i = 0; i < This->npins; i++)
308 {
309 IPin *pConnectedTo;
310
311 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
312 {
313 IPin_Disconnect(pConnectedTo);
314 IPin_Release(pConnectedTo);
315 }
316 IPin_Disconnect(This->ppPins[i]);
317
318 IPin_Release(This->ppPins[i]);
319 }
320
321 CoTaskMemFree(This->ppPins);
322
323 TRACE("Destroying transform filter\n");
324 This->csReceive.DebugInfo->Spare[0] = 0;
325 DeleteCriticalSection(&This->csReceive);
326 FreeMediaType(&This->pmt);
327 QualityControlImpl_Destroy(This->qcimpl);
328 IUnknown_Release(This->seekthru_unk);
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 = 0;
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 };