mshtml: Implement IHTMLWindow2::get_top.
[wine] / dlls / quartz / transform.c
1 /*
2  * Transform Filter (Base for decoders, etc...)
3  *
4  * Copyright 2005 Christian Costa
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22
23 #include "quartz_private.h"
24 #include "control_private.h"
25 #include "pin.h"
26
27 #include "amvideo.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "dshow.h"
31 #include "strmif.h"
32 #include "vfw.h"
33
34 #include <assert.h>
35
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38
39 #include "transform.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
42
43 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
44 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
45
46 static const IBaseFilterVtbl TransformFilter_Vtbl;
47 static const IPinVtbl TransformFilter_InputPin_Vtbl;
48 static const IPinVtbl TransformFilter_OutputPin_Vtbl;
49
50 static HRESULT TransformFilter_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
51 {
52     TransformFilterImpl* This = (TransformFilterImpl *)((IPinImpl *)iface)->pinInfo.pFilter;
53     TRACE("%p\n", iface);
54     dump_AM_MEDIA_TYPE(pmt);
55
56     if (This->pFuncsTable->pfnQueryConnect)
57         return This->pFuncsTable->pfnQueryConnect(This, pmt);
58     /* Assume OK if there's no query method (the connection will fail if
59        needed) */
60     return S_OK;
61 }
62
63
64 static HRESULT TransformFilter_Output_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
65 {
66     TransformFilterImpl* pTransformFilter = iface;
67     AM_MEDIA_TYPE* outpmt = &pTransformFilter->pmt;
68     TRACE("%p\n", iface);
69
70     if (IsEqualIID(&pmt->majortype, &outpmt->majortype)
71         && (IsEqualIID(&pmt->subtype, &outpmt->subtype) || IsEqualIID(&outpmt->subtype, &GUID_NULL)))
72         return S_OK;
73     return S_FALSE;
74 }
75
76
77 static inline TransformFilterImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
78 {
79     return (TransformFilterImpl *)((char*)iface - FIELD_OFFSET(TransformFilterImpl, mediaSeeking.lpVtbl));
80 }
81
82 static HRESULT WINAPI TransformFilter_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
83 {
84     TransformFilterImpl *This = impl_from_IMediaSeeking(iface);
85
86     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
87 }
88
89 static ULONG WINAPI TransformFilter_Seeking_AddRef(IMediaSeeking * iface)
90 {
91     TransformFilterImpl *This = impl_from_IMediaSeeking(iface);
92
93     return IUnknown_AddRef((IUnknown *)This);
94 }
95
96 static ULONG WINAPI TransformFilter_Seeking_Release(IMediaSeeking * iface)
97 {
98     TransformFilterImpl *This = impl_from_IMediaSeeking(iface);
99
100     return IUnknown_Release((IUnknown *)This);
101 }
102
103 static const IMediaSeekingVtbl TransformFilter_Seeking_Vtbl =
104 {
105     TransformFilter_Seeking_QueryInterface,
106     TransformFilter_Seeking_AddRef,
107     TransformFilter_Seeking_Release,
108     MediaSeekingImpl_GetCapabilities,
109     MediaSeekingImpl_CheckCapabilities,
110     MediaSeekingImpl_IsFormatSupported,
111     MediaSeekingImpl_QueryPreferredFormat,
112     MediaSeekingImpl_GetTimeFormat,
113     MediaSeekingImpl_IsUsingTimeFormat,
114     MediaSeekingImpl_SetTimeFormat,
115     MediaSeekingImpl_GetDuration,
116     MediaSeekingImpl_GetStopPosition,
117     MediaSeekingImpl_GetCurrentPosition,
118     MediaSeekingImpl_ConvertTimeFormat,
119     MediaSeekingImpl_SetPositions,
120     MediaSeekingImpl_GetPositions,
121     MediaSeekingImpl_GetAvailable,
122     MediaSeekingImpl_SetRate,
123     MediaSeekingImpl_GetRate,
124     MediaSeekingImpl_GetPreroll
125 };
126
127 /* These shouldn't be implemented by default.
128  * Usually only source filters should implement these
129  * and even it's not needed all of the time
130  */
131 static HRESULT TransformFilter_ChangeCurrent(IBaseFilter *iface)
132 {
133     TRACE("(%p) filter hasn't implemented current position change!\n", iface);
134     return S_OK;
135 }
136
137 static HRESULT TransformFilter_ChangeStop(IBaseFilter *iface)
138 {
139     TRACE("(%p) filter hasn't implemented stop position change!\n", iface);
140     return S_OK;
141 }
142
143 static HRESULT TransformFilter_ChangeRate(IBaseFilter *iface)
144 {
145     TRACE("(%p) filter hasn't implemented rate change!\n", iface);
146     return S_OK;
147 }
148
149 HRESULT TransformFilter_Create(TransformFilterImpl* pTransformFilter, const CLSID* pClsid, const TransformFuncsTable* pFuncsTable, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate)
150 {
151     HRESULT hr;
152     PIN_INFO piInput;
153     PIN_INFO piOutput;
154
155     /* pTransformFilter is already allocated */
156     pTransformFilter->clsid = *pClsid;
157     pTransformFilter->pFuncsTable = pFuncsTable;
158
159     pTransformFilter->lpVtbl = &TransformFilter_Vtbl;
160
161     pTransformFilter->refCount = 1;
162     InitializeCriticalSection(&pTransformFilter->csFilter);
163     pTransformFilter->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TransformFilterImpl.csFilter");
164     pTransformFilter->state = State_Stopped;
165     pTransformFilter->pClock = NULL;
166     ZeroMemory(&pTransformFilter->filterInfo, sizeof(FILTER_INFO));
167     ZeroMemory(&pTransformFilter->pmt, sizeof(pTransformFilter->pmt));
168     pTransformFilter->npins = 2;
169
170     pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
171
172     /* construct input pin */
173     piInput.dir = PINDIR_INPUT;
174     piInput.pFilter = (IBaseFilter *)pTransformFilter;
175     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
176     piOutput.dir = PINDIR_OUTPUT;
177     piOutput.pFilter = (IBaseFilter *)pTransformFilter;
178     lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
179
180     hr = InputPin_Construct(&TransformFilter_InputPin_Vtbl, &piInput, (SAMPLEPROC_PUSH)pFuncsTable->pfnProcessSampleData, NULL, TransformFilter_Input_QueryAccept, NULL, &pTransformFilter->csFilter, NULL, &pTransformFilter->ppPins[0]);
181
182     if (SUCCEEDED(hr))
183     {
184         ALLOCATOR_PROPERTIES props;
185         props.cbAlign = 1;
186         props.cbPrefix = 0;
187         props.cbBuffer = 0; /* Will be updated at connection time */
188         props.cBuffers = 1;
189
190        ((InputPin *)pTransformFilter->ppPins[0])->pin.pUserData = pTransformFilter->ppPins[0];
191
192         hr = OutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(OutputPin), &piOutput, &props, pTransformFilter, TransformFilter_Output_QueryAccept, &pTransformFilter->csFilter, &pTransformFilter->ppPins[1]);
193
194         if (FAILED(hr))
195             ERR("Cannot create output pin (%x)\n", hr);
196         else
197         {
198             if (!stop)
199                 stop = TransformFilter_ChangeStop;
200             if (!current)
201                 current = TransformFilter_ChangeCurrent;
202             if (!rate)
203                 rate = TransformFilter_ChangeRate;
204
205             MediaSeekingImpl_Init((IBaseFilter*)pTransformFilter, stop, current, rate, &pTransformFilter->mediaSeeking, &pTransformFilter->csFilter);
206             pTransformFilter->mediaSeeking.lpVtbl = &TransformFilter_Seeking_Vtbl;
207         }
208     }
209     else
210     {
211         CoTaskMemFree(pTransformFilter->ppPins);
212         pTransformFilter->csFilter.DebugInfo->Spare[0] = 0;
213         DeleteCriticalSection(&pTransformFilter->csFilter);
214         CoTaskMemFree(pTransformFilter);
215     }
216
217     return hr;
218 }
219
220 static HRESULT WINAPI TransformFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
221 {
222     TransformFilterImpl *This = (TransformFilterImpl *)iface;
223     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
224
225     *ppv = NULL;
226
227     if (IsEqualIID(riid, &IID_IUnknown))
228         *ppv = This;
229     else if (IsEqualIID(riid, &IID_IPersist))
230         *ppv = This;
231     else if (IsEqualIID(riid, &IID_IMediaFilter))
232         *ppv = This;
233     else if (IsEqualIID(riid, &IID_IBaseFilter))
234         *ppv = This;
235     else if (IsEqualIID(riid, &IID_IMediaSeeking))
236         *ppv = &This->mediaSeeking;
237
238     if (*ppv)
239     {
240         IUnknown_AddRef((IUnknown *)(*ppv));
241         return S_OK;
242     }
243
244     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
245         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
246
247     return E_NOINTERFACE;
248 }
249
250 static ULONG WINAPI TransformFilter_AddRef(IBaseFilter * iface)
251 {
252     TransformFilterImpl *This = (TransformFilterImpl *)iface;
253     ULONG refCount = InterlockedIncrement(&This->refCount);
254
255     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
256
257     return refCount;
258 }
259
260 static ULONG WINAPI TransformFilter_Release(IBaseFilter * iface)
261 {
262     TransformFilterImpl *This = (TransformFilterImpl *)iface;
263     ULONG refCount = InterlockedDecrement(&This->refCount);
264
265     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
266
267     if (!refCount)
268     {
269         ULONG i;
270
271         if (This->pClock)
272             IReferenceClock_Release(This->pClock);
273
274         for (i = 0; i < This->npins; i++)
275         {
276             IPin *pConnectedTo;
277
278             if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
279             {
280                 IPin_Disconnect(pConnectedTo);
281                 IPin_Release(pConnectedTo);
282             }
283             IPin_Disconnect(This->ppPins[i]);
284
285             IPin_Release(This->ppPins[i]);
286         }
287
288         CoTaskMemFree(This->ppPins);
289         This->lpVtbl = NULL;
290
291         This->csFilter.DebugInfo->Spare[0] = 0;
292         DeleteCriticalSection(&This->csFilter);
293
294         TRACE("Destroying transform filter\n");
295         FreeMediaType(&This->pmt);
296         CoTaskMemFree(This);
297
298         return 0;
299     }
300     else
301         return refCount;
302 }
303
304 /** IPersist methods **/
305
306 static HRESULT WINAPI TransformFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
307 {
308     TransformFilterImpl *This = (TransformFilterImpl *)iface;
309
310     TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
311
312     *pClsid = This->clsid;
313
314     return S_OK;
315 }
316
317 /** IMediaFilter methods **/
318
319 static HRESULT WINAPI TransformFilter_Stop(IBaseFilter * iface)
320 {
321     TransformFilterImpl *This = (TransformFilterImpl *)iface;
322     HRESULT hr = S_OK;
323
324     TRACE("(%p/%p)\n", This, iface);
325
326     EnterCriticalSection(&This->csFilter);
327     {
328         This->state = State_Stopped;
329         if (This->pFuncsTable->pfnProcessEnd)
330             hr = This->pFuncsTable->pfnProcessEnd(This);
331     }
332     LeaveCriticalSection(&This->csFilter);
333
334     return hr;
335 }
336
337 static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface)
338 {
339     TransformFilterImpl *This = (TransformFilterImpl *)iface;
340     HRESULT hr;
341
342     TRACE("(%p/%p)->()\n", This, iface);
343
344     EnterCriticalSection(&This->csFilter);
345     {
346         if (This->state == State_Stopped)
347             hr = IBaseFilter_Run(iface, -1);
348         else
349             hr = S_OK;
350
351         if (SUCCEEDED(hr))
352             This->state = State_Paused;
353     }
354     LeaveCriticalSection(&This->csFilter);
355
356     return hr;
357 }
358
359 static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
360 {
361     HRESULT hr = S_OK;
362     TransformFilterImpl *This = (TransformFilterImpl *)iface;
363
364     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
365
366     EnterCriticalSection(&This->csFilter);
367     {
368         if (This->state == State_Stopped)
369         {
370             ((InputPin *)This->ppPins[0])->end_of_stream = 0;
371             if (This->pFuncsTable->pfnProcessBegin)
372                 hr = This->pFuncsTable->pfnProcessBegin(This);
373             if (SUCCEEDED(hr))
374                 hr = OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
375         }
376
377         if (SUCCEEDED(hr))
378         {
379             This->rtStreamStart = tStart;
380             This->state = State_Running;
381         }
382     }
383     LeaveCriticalSection(&This->csFilter);
384
385     return hr;
386 }
387
388 static HRESULT WINAPI TransformFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
389 {
390     TransformFilterImpl *This = (TransformFilterImpl *)iface;
391
392     TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
393
394     EnterCriticalSection(&This->csFilter);
395     {
396         *pState = This->state;
397     }
398     LeaveCriticalSection(&This->csFilter);
399
400     return S_OK;
401 }
402
403 static HRESULT WINAPI TransformFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
404 {
405     TransformFilterImpl *This = (TransformFilterImpl *)iface;
406
407     TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
408
409     EnterCriticalSection(&This->csFilter);
410     {
411         if (This->pClock)
412             IReferenceClock_Release(This->pClock);
413         This->pClock = pClock;
414         if (This->pClock)
415             IReferenceClock_AddRef(This->pClock);
416     }
417     LeaveCriticalSection(&This->csFilter);
418
419     return S_OK;
420 }
421
422 static HRESULT WINAPI TransformFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
423 {
424     TransformFilterImpl *This = (TransformFilterImpl *)iface;
425
426     TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
427
428     EnterCriticalSection(&This->csFilter);
429     {
430         *ppClock = This->pClock;
431         if (This->pClock)
432             IReferenceClock_AddRef(This->pClock);
433     }
434     LeaveCriticalSection(&This->csFilter);
435
436     return S_OK;
437 }
438
439 /** IBaseFilter implementation **/
440
441 static HRESULT TransformFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
442 {
443     TransformFilterImpl *This = (TransformFilterImpl *)iface;
444
445     /* Our pins are static, not changing so setting static tick count is ok */
446     *lastsynctick = 0;
447
448     if (pos >= This->npins)
449         return S_FALSE;
450
451     *pin = This->ppPins[pos];
452     IPin_AddRef(*pin);
453     return S_OK;
454 }
455
456 static HRESULT WINAPI TransformFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
457 {
458     TransformFilterImpl *This = (TransformFilterImpl *)iface;
459
460     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
461
462     return IEnumPinsImpl_Construct(ppEnum, TransformFilter_GetPin, iface);
463 }
464
465 static HRESULT WINAPI TransformFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
466 {
467     TransformFilterImpl *This = (TransformFilterImpl *)iface;
468
469     TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
470
471     return E_NOTIMPL;
472 }
473
474 static HRESULT WINAPI TransformFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
475 {
476     TransformFilterImpl *This = (TransformFilterImpl *)iface;
477
478     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
479
480     strcpyW(pInfo->achName, This->filterInfo.achName);
481     pInfo->pGraph = This->filterInfo.pGraph;
482
483     if (pInfo->pGraph)
484         IFilterGraph_AddRef(pInfo->pGraph);
485
486     return S_OK;
487 }
488
489 static HRESULT WINAPI TransformFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
490 {
491     HRESULT hr = S_OK;
492     TransformFilterImpl *This = (TransformFilterImpl *)iface;
493
494     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
495
496     EnterCriticalSection(&This->csFilter);
497     {
498         if (pName)
499             strcpyW(This->filterInfo.achName, pName);
500         else
501             *This->filterInfo.achName = '\0';
502         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
503     }
504     LeaveCriticalSection(&This->csFilter);
505
506     return hr;
507 }
508
509 static HRESULT WINAPI TransformFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
510 {
511     TransformFilterImpl *This = (TransformFilterImpl *)iface;
512     TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
513     return E_NOTIMPL;
514 }
515
516 static const IBaseFilterVtbl TransformFilter_Vtbl =
517 {
518     TransformFilter_QueryInterface,
519     TransformFilter_AddRef,
520     TransformFilter_Release,
521     TransformFilter_GetClassID,
522     TransformFilter_Stop,
523     TransformFilter_Pause,
524     TransformFilter_Run,
525     TransformFilter_GetState,
526     TransformFilter_SetSyncSource,
527     TransformFilter_GetSyncSource,
528     TransformFilter_EnumPins,
529     TransformFilter_FindPin,
530     TransformFilter_QueryFilterInfo,
531     TransformFilter_JoinFilterGraph,
532     TransformFilter_QueryVendorInfo
533 };
534
535 static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface)
536 {
537     InputPin* This = (InputPin*) iface;
538     TransformFilterImpl* pTransform;
539     IPin* ppin;
540     HRESULT hr;
541     
542     TRACE("(%p)->()\n", iface);
543
544     /* Since we process samples synchronously, just forward notification downstream */
545     pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
546     if (!pTransform)
547         hr = E_FAIL;
548     else
549         hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin);
550     if (SUCCEEDED(hr))
551     {
552         hr = IPin_EndOfStream(ppin);
553         IPin_Release(ppin);
554     }
555
556     if (FAILED(hr))
557         ERR("%x\n", hr);
558     return hr;
559 }
560
561 static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
562 {
563     InputPin* This = (InputPin*) iface;
564     TransformFilterImpl* pTransform;
565     HRESULT hr;
566
567     TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt);
568
569     pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
570
571     hr = pTransform->pFuncsTable->pfnConnectInput(This, pmt);
572     if (SUCCEEDED(hr))
573     {
574         hr = InputPin_ReceiveConnection(iface, pReceivePin, pmt);
575         if (FAILED(hr))
576             pTransform->pFuncsTable->pfnCleanup(This);
577     }
578
579     return hr;
580 }
581
582 static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface)
583 {
584     InputPin* This = (InputPin*) iface;
585     TransformFilterImpl* pTransform;
586
587     TRACE("(%p)->()\n", iface);
588
589     pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
590     pTransform->pFuncsTable->pfnCleanup(This);
591
592     return IPinImpl_Disconnect(iface);
593 }
594
595 static const IPinVtbl TransformFilter_InputPin_Vtbl = 
596 {
597     InputPin_QueryInterface,
598     IPinImpl_AddRef,
599     InputPin_Release,
600     InputPin_Connect,
601     TransformFilter_InputPin_ReceiveConnection,
602     TransformFilter_InputPin_Disconnect,
603     IPinImpl_ConnectedTo,
604     IPinImpl_ConnectionMediaType,
605     IPinImpl_QueryPinInfo,
606     IPinImpl_QueryDirection,
607     IPinImpl_QueryId,
608     IPinImpl_QueryAccept,
609     IPinImpl_EnumMediaTypes,
610     IPinImpl_QueryInternalConnections,
611     TransformFilter_InputPin_EndOfStream,
612     InputPin_BeginFlush,
613     InputPin_EndFlush,
614     InputPin_NewSegment
615 };
616
617 static HRESULT WINAPI TransformFilter_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
618 {
619     IPinImpl *This = (IPinImpl *)iface;
620     TransformFilterImpl *pTransform = (TransformFilterImpl *)This->pinInfo.pFilter;
621     ENUMMEDIADETAILS emd;
622
623     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
624
625     emd.cMediaTypes = 1;
626     emd.pMediaTypes = &pTransform->pmt;
627
628     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
629 }
630
631 static const IPinVtbl TransformFilter_OutputPin_Vtbl =
632 {
633     OutputPin_QueryInterface,
634     IPinImpl_AddRef,
635     OutputPin_Release,
636     OutputPin_Connect,
637     OutputPin_ReceiveConnection,
638     OutputPin_Disconnect,
639     IPinImpl_ConnectedTo,
640     IPinImpl_ConnectionMediaType,
641     IPinImpl_QueryPinInfo,
642     IPinImpl_QueryDirection,
643     IPinImpl_QueryId,
644     IPinImpl_QueryAccept,
645     TransformFilter_Output_EnumMediaTypes,
646     IPinImpl_QueryInternalConnections,
647     OutputPin_EndOfStream,
648     OutputPin_BeginFlush,
649     OutputPin_EndFlush,
650     OutputPin_NewSegment
651 };