comctl32: statusbar: Rename NtfUnicode to bUnicode to make is more consistent with...
[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 IMemInputPinVtbl MemInputPin_Vtbl; 
49 static const IPinVtbl TransformFilter_OutputPin_Vtbl;
50
51 static HRESULT TransformFilter_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
52 {
53     TransformFilterImpl* This = (TransformFilterImpl*)iface;
54     TRACE("%p\n", iface);
55     dump_AM_MEDIA_TYPE(pmt);
56
57     if (This->pFuncsTable->pfnQueryConnect)
58         return This->pFuncsTable->pfnQueryConnect(This, pmt);
59     /* Assume OK if there's no query method (the connection will fail if
60        needed) */
61     return S_OK;
62 }
63
64
65 static HRESULT TransformFilter_Output_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
66 {
67     TransformFilterImpl* pTransformFilter = (TransformFilterImpl*)iface;
68     AM_MEDIA_TYPE* outpmt = &((OutputPin*)pTransformFilter->ppPins[1])->pin.mtCurrent;
69     TRACE("%p\n", iface);
70
71     if (IsEqualIID(&pmt->majortype, &outpmt->majortype) && IsEqualIID(&pmt->subtype, &outpmt->subtype))
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
169     pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
170
171     /* construct input pin */
172     piInput.dir = PINDIR_INPUT;
173     piInput.pFilter = (IBaseFilter *)pTransformFilter;
174     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
175     piOutput.dir = PINDIR_OUTPUT;
176     piOutput.pFilter = (IBaseFilter *)pTransformFilter;
177     lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
178
179     hr = InputPin_Construct(&TransformFilter_InputPin_Vtbl, &piInput, (SAMPLEPROC_PUSH)pFuncsTable->pfnProcessSampleData, pTransformFilter, TransformFilter_Input_QueryAccept, NULL, &pTransformFilter->csFilter, NULL, &pTransformFilter->ppPins[0]);
180
181     if (SUCCEEDED(hr))
182     {
183         ALLOCATOR_PROPERTIES props;
184         props.cbAlign = 1;
185         props.cbPrefix = 0;
186         props.cbBuffer = 0; /* Will be updated at connection time */
187         props.cBuffers = 1;
188
189         hr = OutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(OutputPin), &piOutput, &props, pTransformFilter, TransformFilter_Output_QueryAccept, &pTransformFilter->csFilter, &pTransformFilter->ppPins[1]);
190
191         if (FAILED(hr))
192             ERR("Cannot create output pin (%x)\n", hr);
193         else
194         {
195             if (!stop)
196                 stop = TransformFilter_ChangeStop;
197             if (!current)
198                 current = TransformFilter_ChangeCurrent;
199             if (!rate)
200                 rate = TransformFilter_ChangeRate;
201
202             MediaSeekingImpl_Init((IBaseFilter*)pTransformFilter, stop, current, rate, &pTransformFilter->mediaSeeking, &pTransformFilter->csFilter);
203             pTransformFilter->mediaSeeking.lpVtbl = &TransformFilter_Seeking_Vtbl;
204         }
205     }
206     else
207     {
208         CoTaskMemFree(pTransformFilter->ppPins);
209         pTransformFilter->csFilter.DebugInfo->Spare[0] = 0;
210         DeleteCriticalSection(&pTransformFilter->csFilter);
211         CoTaskMemFree(pTransformFilter);
212     }
213
214     return hr;
215 }
216
217 static HRESULT WINAPI TransformFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
218 {
219     TransformFilterImpl *This = (TransformFilterImpl *)iface;
220     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
221
222     *ppv = NULL;
223
224     if (IsEqualIID(riid, &IID_IUnknown))
225         *ppv = (LPVOID)This;
226     else if (IsEqualIID(riid, &IID_IPersist))
227         *ppv = (LPVOID)This;
228     else if (IsEqualIID(riid, &IID_IMediaFilter))
229         *ppv = (LPVOID)This;
230     else if (IsEqualIID(riid, &IID_IBaseFilter))
231         *ppv = (LPVOID)This;
232     else if (IsEqualIID(riid, &IID_IMediaSeeking))
233         *ppv = &This->mediaSeeking;
234
235     if (*ppv)
236     {
237         IUnknown_AddRef((IUnknown *)(*ppv));
238         return S_OK;
239     }
240
241     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
242         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
243
244     return E_NOINTERFACE;
245 }
246
247 static ULONG WINAPI TransformFilter_AddRef(IBaseFilter * iface)
248 {
249     TransformFilterImpl *This = (TransformFilterImpl *)iface;
250     ULONG refCount = InterlockedIncrement(&This->refCount);
251
252     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
253
254     return refCount;
255 }
256
257 static ULONG WINAPI TransformFilter_Release(IBaseFilter * iface)
258 {
259     TransformFilterImpl *This = (TransformFilterImpl *)iface;
260     ULONG refCount = InterlockedDecrement(&This->refCount);
261
262     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
263
264     if (!refCount)
265     {
266         ULONG i;
267
268         if (This->pClock)
269             IReferenceClock_Release(This->pClock);
270
271         for (i = 0; i < 2; i++)
272         {
273             IPin *pConnectedTo;
274
275             if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
276             {
277                 IPin_Disconnect(pConnectedTo);
278                 IPin_Release(pConnectedTo);
279             }
280             IPin_Disconnect(This->ppPins[i]);
281
282             IPin_Release(This->ppPins[i]);
283         }
284
285         CoTaskMemFree(This->ppPins);
286         This->lpVtbl = NULL;
287
288         This->csFilter.DebugInfo->Spare[0] = 0;
289         DeleteCriticalSection(&This->csFilter);
290
291         TRACE("Destroying transform filter\n");
292         FreeMediaType(&This->pmt);
293         CoTaskMemFree(This);
294
295         return 0;
296     }
297     else
298         return refCount;
299 }
300
301 /** IPersist methods **/
302
303 static HRESULT WINAPI TransformFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
304 {
305     TransformFilterImpl *This = (TransformFilterImpl *)iface;
306
307     TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
308
309     *pClsid = This->clsid;
310
311     return S_OK;
312 }
313
314 /** IMediaFilter methods **/
315
316 static HRESULT WINAPI TransformFilter_Stop(IBaseFilter * iface)
317 {
318     TransformFilterImpl *This = (TransformFilterImpl *)iface;
319
320     TRACE("(%p/%p)\n", This, iface);
321
322     EnterCriticalSection(&This->csFilter);
323     {
324         This->state = State_Stopped;
325         if (This->pFuncsTable->pfnProcessEnd)
326             This->pFuncsTable->pfnProcessEnd(This);
327     }
328     LeaveCriticalSection(&This->csFilter);
329
330     return S_OK;
331 }
332
333 static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface)
334 {
335     TransformFilterImpl *This = (TransformFilterImpl *)iface;
336
337     TRACE("(%p/%p)->()\n", This, iface);
338
339     EnterCriticalSection(&This->csFilter);
340     {
341         if (This->state == State_Stopped)
342             IBaseFilter_Run(iface, -1);
343
344         This->state = State_Paused;
345     }
346     LeaveCriticalSection(&This->csFilter);
347
348     return S_OK;
349 }
350
351 static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
352 {
353     HRESULT hr = S_OK;
354     TransformFilterImpl *This = (TransformFilterImpl *)iface;
355
356     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
357
358     EnterCriticalSection(&This->csFilter);
359     {
360         if (This->state == State_Stopped)
361         {
362             ((InputPin *)This->ppPins[0])->end_of_stream = 0;
363             if (This->pFuncsTable->pfnProcessBegin)
364                 This->pFuncsTable->pfnProcessBegin(This);
365             OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
366         }
367
368         This->rtStreamStart = tStart;
369         This->state = State_Running;
370     }
371     LeaveCriticalSection(&This->csFilter);
372
373     return hr;
374 }
375
376 static HRESULT WINAPI TransformFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
377 {
378     TransformFilterImpl *This = (TransformFilterImpl *)iface;
379
380     TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
381
382     EnterCriticalSection(&This->csFilter);
383     {
384         *pState = This->state;
385     }
386     LeaveCriticalSection(&This->csFilter);
387
388     return S_OK;
389 }
390
391 static HRESULT WINAPI TransformFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
392 {
393     TransformFilterImpl *This = (TransformFilterImpl *)iface;
394
395     TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
396
397     EnterCriticalSection(&This->csFilter);
398     {
399         if (This->pClock)
400             IReferenceClock_Release(This->pClock);
401         This->pClock = pClock;
402         if (This->pClock)
403             IReferenceClock_AddRef(This->pClock);
404     }
405     LeaveCriticalSection(&This->csFilter);
406
407     return S_OK;
408 }
409
410 static HRESULT WINAPI TransformFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
411 {
412     TransformFilterImpl *This = (TransformFilterImpl *)iface;
413
414     TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
415
416     EnterCriticalSection(&This->csFilter);
417     {
418         *ppClock = This->pClock;
419         if (This->pClock)
420             IReferenceClock_AddRef(This->pClock);
421     }
422     LeaveCriticalSection(&This->csFilter);
423
424     return S_OK;
425 }
426
427 /** IBaseFilter implementation **/
428
429 static HRESULT TransformFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
430 {
431     TransformFilterImpl *This = (TransformFilterImpl *)iface;
432
433     /* Our pins are static, not changing so setting static tick count is ok */
434     *lastsynctick = 0;
435
436     if (pos >= 2)
437         return S_FALSE;
438
439     *pin = This->ppPins[pos];
440     IPin_AddRef(*pin);
441     return S_OK;
442 }
443
444 static HRESULT WINAPI TransformFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
445 {
446     TransformFilterImpl *This = (TransformFilterImpl *)iface;
447
448     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
449
450     return IEnumPinsImpl_Construct(ppEnum, TransformFilter_GetPin, iface);
451 }
452
453 static HRESULT WINAPI TransformFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
454 {
455     TransformFilterImpl *This = (TransformFilterImpl *)iface;
456
457     TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
458
459     return E_NOTIMPL;
460 }
461
462 static HRESULT WINAPI TransformFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
463 {
464     TransformFilterImpl *This = (TransformFilterImpl *)iface;
465
466     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
467
468     strcpyW(pInfo->achName, This->filterInfo.achName);
469     pInfo->pGraph = This->filterInfo.pGraph;
470
471     if (pInfo->pGraph)
472         IFilterGraph_AddRef(pInfo->pGraph);
473
474     return S_OK;
475 }
476
477 static HRESULT WINAPI TransformFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
478 {
479     HRESULT hr = S_OK;
480     TransformFilterImpl *This = (TransformFilterImpl *)iface;
481
482     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
483
484     EnterCriticalSection(&This->csFilter);
485     {
486         if (pName)
487             strcpyW(This->filterInfo.achName, pName);
488         else
489             *This->filterInfo.achName = '\0';
490         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
491     }
492     LeaveCriticalSection(&This->csFilter);
493
494     return hr;
495 }
496
497 static HRESULT WINAPI TransformFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
498 {
499     TransformFilterImpl *This = (TransformFilterImpl *)iface;
500     TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
501     return E_NOTIMPL;
502 }
503
504 static const IBaseFilterVtbl TransformFilter_Vtbl =
505 {
506     TransformFilter_QueryInterface,
507     TransformFilter_AddRef,
508     TransformFilter_Release,
509     TransformFilter_GetClassID,
510     TransformFilter_Stop,
511     TransformFilter_Pause,
512     TransformFilter_Run,
513     TransformFilter_GetState,
514     TransformFilter_SetSyncSource,
515     TransformFilter_GetSyncSource,
516     TransformFilter_EnumPins,
517     TransformFilter_FindPin,
518     TransformFilter_QueryFilterInfo,
519     TransformFilter_JoinFilterGraph,
520     TransformFilter_QueryVendorInfo
521 };
522
523 static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface)
524 {
525     InputPin* This = (InputPin*) iface;
526     TransformFilterImpl* pTransform;
527     IPin* ppin;
528     HRESULT hr;
529     
530     TRACE("(%p)->()\n", iface);
531
532     /* Since we process samples synchronously, just forward notification downstream */
533     pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
534     if (!pTransform)
535         hr = E_FAIL;
536     else
537         hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin);
538     if (SUCCEEDED(hr))
539     {
540         hr = IPin_EndOfStream(ppin);
541         IPin_Release(ppin);
542     }
543
544     if (FAILED(hr))
545         ERR("%x\n", hr);
546     return hr;
547 }
548
549 static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
550 {
551     InputPin* This = (InputPin*) iface;
552     TransformFilterImpl* pTransform;
553     HRESULT hr;
554
555     TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt);
556
557     pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
558
559     hr = pTransform->pFuncsTable->pfnConnectInput(pTransform, pmt);
560     if (SUCCEEDED(hr))
561     {
562         hr = InputPin_ReceiveConnection(iface, pReceivePin, pmt);
563         if (FAILED(hr))
564             pTransform->pFuncsTable->pfnCleanup(pTransform);
565     }
566
567     return hr;
568 }
569
570 static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface)
571 {
572     InputPin* This = (InputPin*) iface;
573     TransformFilterImpl* pTransform;
574
575     TRACE("(%p)->()\n", iface);
576
577     pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
578     pTransform->pFuncsTable->pfnCleanup(pTransform);
579
580     return IPinImpl_Disconnect(iface);
581 }
582
583 static const IPinVtbl TransformFilter_InputPin_Vtbl = 
584 {
585     InputPin_QueryInterface,
586     IPinImpl_AddRef,
587     InputPin_Release,
588     InputPin_Connect,
589     TransformFilter_InputPin_ReceiveConnection,
590     TransformFilter_InputPin_Disconnect,
591     IPinImpl_ConnectedTo,
592     IPinImpl_ConnectionMediaType,
593     IPinImpl_QueryPinInfo,
594     IPinImpl_QueryDirection,
595     IPinImpl_QueryId,
596     IPinImpl_QueryAccept,
597     IPinImpl_EnumMediaTypes,
598     IPinImpl_QueryInternalConnections,
599     TransformFilter_InputPin_EndOfStream,
600     InputPin_BeginFlush,
601     InputPin_EndFlush,
602     InputPin_NewSegment
603 };
604
605 static HRESULT WINAPI TransformFilter_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
606 {
607     IPinImpl *This = (IPinImpl *)iface;
608     TransformFilterImpl *pTransform = (TransformFilterImpl *)This->pinInfo.pFilter;
609     ENUMMEDIADETAILS emd;
610
611     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
612
613     emd.cMediaTypes = 1;
614     emd.pMediaTypes = &pTransform->pmt;
615
616     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
617 }
618
619 static const IPinVtbl TransformFilter_OutputPin_Vtbl =
620 {
621     OutputPin_QueryInterface,
622     IPinImpl_AddRef,
623     OutputPin_Release,
624     OutputPin_Connect,
625     OutputPin_ReceiveConnection,
626     OutputPin_Disconnect,
627     IPinImpl_ConnectedTo,
628     IPinImpl_ConnectionMediaType,
629     IPinImpl_QueryPinInfo,
630     IPinImpl_QueryDirection,
631     IPinImpl_QueryId,
632     IPinImpl_QueryAccept,
633     TransformFilter_Output_EnumMediaTypes,
634     IPinImpl_QueryInternalConnections,
635     OutputPin_EndOfStream,
636     OutputPin_BeginFlush,
637     OutputPin_EndFlush,
638     OutputPin_NewSegment
639 };
640
641 static const IMemInputPinVtbl MemInputPin_Vtbl = 
642 {
643     MemInputPin_QueryInterface,
644     MemInputPin_AddRef,
645     MemInputPin_Release,
646     MemInputPin_GetAllocator,
647     MemInputPin_NotifyAllocator,
648     MemInputPin_GetAllocatorRequirements,
649     MemInputPin_Receive,
650     MemInputPin_ReceiveMultiple,
651     MemInputPin_ReceiveCanBlock
652 };