user32: Check structure size in GetGUIThreadInfo.
[wine] / dlls / strmbase / pin.c
1 /*
2  * Generic Implementation of IPin Interface
3  *
4  * Copyright 2003 Robert Shearman
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 #define COBJMACROS
23
24 #include "dshow.h"
25 #include "wine/debug.h"
26 #include "wine/unicode.h"
27 #include "wine/strmbase.h"
28 #include "uuids.h"
29 #include "vfwmsgs.h"
30 #include <assert.h>
31
32 WINE_DEFAULT_DEBUG_CHANNEL(strmbase);
33
34 static const IPinVtbl InputPin_Vtbl;
35 static const IPinVtbl OutputPin_Vtbl;
36 static const IMemInputPinVtbl MemInputPin_Vtbl;
37
38 typedef HRESULT (*SendPinFunc)( IPin *to, LPVOID arg );
39
40 /** Helper function, there are a lot of places where the error code is inherited
41  * The following rules apply:
42  *
43  * Return the first received error code (E_NOTIMPL is ignored)
44  * If no errors occur: return the first received non-error-code that isn't S_OK
45  */
46 static HRESULT updatehres( HRESULT original, HRESULT new )
47 {
48     if (FAILED( original ) || new == E_NOTIMPL)
49         return original;
50
51     if (FAILED( new ) || original == S_OK)
52         return new;
53
54     return original;
55 }
56
57 /** Sends a message from a pin further to other, similar pins
58  * fnMiddle is called on each pin found further on the stream.
59  * fnEnd (can be NULL) is called when the message can't be sent any further (this is a renderer or source)
60  *
61  * If the pin given is an input pin, the message will be sent downstream to other input pins
62  * If the pin given is an output pin, the message will be sent upstream to other output pins
63  */
64 static HRESULT SendFurther( IPin *from, SendPinFunc fnMiddle, LPVOID arg, SendPinFunc fnEnd )
65 {
66     PIN_INFO pin_info;
67     ULONG amount = 0;
68     HRESULT hr = S_OK;
69     HRESULT hr_return = S_OK;
70     IEnumPins *enumpins = NULL;
71     BOOL foundend = TRUE;
72     PIN_DIRECTION from_dir;
73
74     IPin_QueryDirection( from, &from_dir );
75
76     hr = IPin_QueryInternalConnections( from, NULL, &amount );
77     if (hr != E_NOTIMPL && amount)
78         FIXME("Use QueryInternalConnections!\n");
79      hr = S_OK;
80
81     pin_info.pFilter = NULL;
82     hr = IPin_QueryPinInfo( from, &pin_info );
83     if (FAILED(hr))
84         goto out;
85
86     hr = IBaseFilter_EnumPins( pin_info.pFilter, &enumpins );
87     if (FAILED(hr))
88         goto out;
89
90     hr = IEnumPins_Reset( enumpins );
91     while (hr == S_OK) {
92         IPin *pin = NULL;
93         hr = IEnumPins_Next( enumpins, 1, &pin, NULL );
94         if (hr == VFW_E_ENUM_OUT_OF_SYNC)
95         {
96             hr = IEnumPins_Reset( enumpins );
97             continue;
98         }
99         if (pin)
100         {
101             PIN_DIRECTION dir;
102
103             IPin_QueryDirection( pin, &dir );
104             if (dir != from_dir)
105             {
106                 IPin *connected = NULL;
107
108                 foundend = FALSE;
109                 IPin_ConnectedTo( pin, &connected );
110                 if (connected)
111                 {
112                     HRESULT hr_local;
113
114                     hr_local = fnMiddle( connected, arg );
115                     hr_return = updatehres( hr_return, hr_local );
116                     IPin_Release(connected);
117                 }
118             }
119             IPin_Release( pin );
120         }
121         else
122         {
123             hr = S_OK;
124             break;
125         }
126     }
127
128     if (!foundend)
129         hr = hr_return;
130     else if (fnEnd) {
131         HRESULT hr_local;
132
133         hr_local = fnEnd( from, arg );
134         hr_return = updatehres( hr_return, hr_local );
135     }
136
137 out:
138     if (pin_info.pFilter)
139         IBaseFilter_Release( pin_info.pFilter );
140     return hr;
141 }
142
143 static void Copy_PinInfo(PIN_INFO * pDest, const PIN_INFO * pSrc)
144 {
145     /* Tempting to just do a memcpy, but the name field is
146        128 characters long! We will probably never exceed 10
147        most of the time, so we are better off copying
148        each field manually */
149     strcpyW(pDest->achName, pSrc->achName);
150     pDest->dir = pSrc->dir;
151     pDest->pFilter = pSrc->pFilter;
152 }
153
154 static void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt)
155 {
156     if (!pmt)
157         return;
158     TRACE("\t%s\n\t%s\n\t...\n\t%s\n", debugstr_guid(&pmt->majortype), debugstr_guid(&pmt->subtype), debugstr_guid(&pmt->formattype));
159 }
160
161 static BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards)
162 {
163     TRACE("pmt1: ");
164     dump_AM_MEDIA_TYPE(pmt1);
165     TRACE("pmt2: ");
166     dump_AM_MEDIA_TYPE(pmt2);
167     return (((bWildcards && (IsEqualGUID(&pmt1->majortype, &GUID_NULL) || IsEqualGUID(&pmt2->majortype, &GUID_NULL))) || IsEqualGUID(&pmt1->majortype, &pmt2->majortype)) &&
168             ((bWildcards && (IsEqualGUID(&pmt1->subtype, &GUID_NULL)   || IsEqualGUID(&pmt2->subtype, &GUID_NULL)))   || IsEqualGUID(&pmt1->subtype, &pmt2->subtype)));
169 }
170
171 /*** Common Base Pin function */
172 HRESULT WINAPI BasePinImpl_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
173 {
174     if (iPosition < 0)
175         return E_INVALIDARG;
176     return VFW_S_NO_MORE_ITEMS;
177 }
178
179 LONG WINAPI BasePinImpl_GetMediaTypeVersion(BasePin *iface)
180 {
181     return 1;
182 }
183
184 ULONG WINAPI BasePinImpl_AddRef(IPin * iface)
185 {
186     BasePin *This = (BasePin *)iface;
187     ULONG refCount = InterlockedIncrement(&This->refCount);
188
189     TRACE("(%p)->() AddRef from %d\n", iface, refCount - 1);
190
191     return refCount;
192 }
193
194 HRESULT WINAPI BasePinImpl_Disconnect(IPin * iface)
195 {
196     HRESULT hr;
197     BasePin *This = (BasePin *)iface;
198
199     TRACE("()\n");
200
201     EnterCriticalSection(This->pCritSec);
202     {
203         if (This->pConnectedTo)
204         {
205             IPin_Release(This->pConnectedTo);
206             This->pConnectedTo = NULL;
207             FreeMediaType(&This->mtCurrent);
208             ZeroMemory(&This->mtCurrent, sizeof(This->mtCurrent));
209             hr = S_OK;
210         }
211         else
212             hr = S_FALSE;
213     }
214     LeaveCriticalSection(This->pCritSec);
215
216     return hr;
217 }
218
219 HRESULT WINAPI BasePinImpl_ConnectedTo(IPin * iface, IPin ** ppPin)
220 {
221     HRESULT hr;
222     BasePin *This = (BasePin *)iface;
223
224     TRACE("(%p)\n", ppPin);
225
226     EnterCriticalSection(This->pCritSec);
227     {
228         if (This->pConnectedTo)
229         {
230             *ppPin = This->pConnectedTo;
231             IPin_AddRef(*ppPin);
232             hr = S_OK;
233         }
234         else
235         {
236             hr = VFW_E_NOT_CONNECTED;
237             *ppPin = NULL;
238         }
239     }
240     LeaveCriticalSection(This->pCritSec);
241
242     return hr;
243 }
244
245 HRESULT WINAPI BasePinImpl_ConnectionMediaType(IPin * iface, AM_MEDIA_TYPE * pmt)
246 {
247     HRESULT hr;
248     BasePin *This = (BasePin *)iface;
249
250     TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
251
252     EnterCriticalSection(This->pCritSec);
253     {
254         if (This->pConnectedTo)
255         {
256             CopyMediaType(pmt, &This->mtCurrent);
257             hr = S_OK;
258         }
259         else
260         {
261             ZeroMemory(pmt, sizeof(*pmt));
262             hr = VFW_E_NOT_CONNECTED;
263         }
264     }
265     LeaveCriticalSection(This->pCritSec);
266
267     return hr;
268 }
269
270 HRESULT WINAPI BasePinImpl_QueryPinInfo(IPin * iface, PIN_INFO * pInfo)
271 {
272     BasePin *This = (BasePin *)iface;
273
274     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
275
276     Copy_PinInfo(pInfo, &This->pinInfo);
277     IBaseFilter_AddRef(pInfo->pFilter);
278
279     return S_OK;
280 }
281
282 HRESULT WINAPI BasePinImpl_QueryDirection(IPin * iface, PIN_DIRECTION * pPinDir)
283 {
284     BasePin *This = (BasePin *)iface;
285
286     TRACE("(%p/%p)->(%p)\n", This, iface, pPinDir);
287
288     *pPinDir = This->pinInfo.dir;
289
290     return S_OK;
291 }
292
293 HRESULT WINAPI BasePinImpl_QueryId(IPin * iface, LPWSTR * Id)
294 {
295     BasePin *This = (BasePin *)iface;
296
297     TRACE("(%p/%p)->(%p)\n", This, iface, Id);
298
299     *Id = CoTaskMemAlloc((strlenW(This->pinInfo.achName) + 1) * sizeof(WCHAR));
300     if (!*Id)
301         return E_OUTOFMEMORY;
302
303     strcpyW(*Id, This->pinInfo.achName);
304
305     return S_OK;
306 }
307
308 HRESULT WINAPI BasePinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
309 {
310     TRACE("(%p)->(%p)\n", iface, pmt);
311
312     return S_OK;
313 }
314
315 HRESULT WINAPI BasePinImpl_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
316 {
317     BasePin *This = (BasePin *)iface;
318
319     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
320
321     /* override this method to allow enumeration of your types */
322
323     return EnumMediaTypes_Construct(This, This->pFuncsTable->pfnGetMediaType, This->pFuncsTable->pfnGetMediaTypeVersion , ppEnum);
324 }
325
326 HRESULT WINAPI BasePinImpl_QueryInternalConnections(IPin * iface, IPin ** apPin, ULONG * cPin)
327 {
328     BasePin *This = (BasePin *)iface;
329
330     TRACE("(%p/%p)->(%p, %p)\n", This, iface, apPin, cPin);
331
332     return E_NOTIMPL; /* to tell caller that all input pins connected to all output pins */
333 }
334
335 HRESULT WINAPI BasePinImpl_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
336 {
337     BasePin *This = (BasePin *)iface;
338
339     TRACE("(%x%08x, %x%08x, %e)\n", (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
340
341     This->tStart = tStart;
342     This->tStop = tStop;
343     This->dRate = dRate;
344
345     return S_OK;
346 }
347
348 /*** OutputPin implementation ***/
349
350 HRESULT WINAPI BaseOutputPinImpl_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
351 {
352     BaseOutputPin *This = (BaseOutputPin *)iface;
353
354     TRACE("(%p/%p)->(%s, %p)\n", This, iface, debugstr_guid(riid), ppv);
355
356     *ppv = NULL;
357
358     if (IsEqualIID(riid, &IID_IUnknown))
359         *ppv = iface;
360     else if (IsEqualIID(riid, &IID_IPin))
361         *ppv = iface;
362     else if (IsEqualIID(riid, &IID_IMediaSeeking) ||
363              IsEqualIID(riid, &IID_IQualityControl))
364     {
365         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, riid, ppv);
366     }
367
368     if (*ppv)
369     {
370         IUnknown_AddRef((IUnknown *)(*ppv));
371         return S_OK;
372     }
373
374     FIXME("No interface for %s!\n", debugstr_guid(riid));
375
376     return E_NOINTERFACE;
377 }
378
379 ULONG WINAPI BaseOutputPinImpl_Release(IPin * iface)
380 {
381     BaseOutputPin *This = (BaseOutputPin *)iface;
382     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
383
384     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
385
386     if (!refCount)
387     {
388         FreeMediaType(&This->pin.mtCurrent);
389         CoTaskMemFree(This);
390         return 0;
391     }
392     return refCount;
393 }
394
395 HRESULT WINAPI BaseOutputPinImpl_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
396 {
397     HRESULT hr;
398     BaseOutputPin *This = (BaseOutputPin *)iface;
399
400     TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt);
401     dump_AM_MEDIA_TYPE(pmt);
402
403     /* If we try to connect to ourself, we will definitely deadlock.
404      * There are other cases where we could deadlock too, but this
405      * catches the obvious case */
406     assert(pReceivePin != iface);
407
408     EnterCriticalSection(This->pin.pCritSec);
409     {
410         /* if we have been a specific type to connect with, then we can either connect
411          * with that or fail. We cannot choose different AM_MEDIA_TYPE */
412         if (pmt && !IsEqualGUID(&pmt->majortype, &GUID_NULL) && !IsEqualGUID(&pmt->subtype, &GUID_NULL))
413             hr = This->pin.pFuncsTable->pfnAttemptConnection((BasePin*)This, pReceivePin, pmt);
414         else
415         {
416             /* negotiate media type */
417
418             IEnumMediaTypes * pEnumCandidates;
419             AM_MEDIA_TYPE * pmtCandidate = NULL; /* Candidate media type */
420
421             if (SUCCEEDED(hr = IPin_EnumMediaTypes(iface, &pEnumCandidates)))
422             {
423                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
424
425                 /* try this filter's media types first */
426                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
427                 {
428                     assert(pmtCandidate);
429                     dump_AM_MEDIA_TYPE(pmtCandidate);
430                     if (!IsEqualGUID(&FORMAT_None, &pmtCandidate->formattype)
431                         && !IsEqualGUID(&GUID_NULL, &pmtCandidate->formattype))
432                         assert(pmtCandidate->pbFormat);
433                     if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) &&
434                         (This->pin.pFuncsTable->pfnAttemptConnection((BasePin*)This, pReceivePin, pmtCandidate) == S_OK))
435                     {
436                         hr = S_OK;
437                         DeleteMediaType(pmtCandidate);
438                         break;
439                     }
440                     DeleteMediaType(pmtCandidate);
441                     pmtCandidate = NULL;
442                 }
443                 IEnumMediaTypes_Release(pEnumCandidates);
444             }
445
446             /* then try receiver filter's media types */
447             if (hr != S_OK && SUCCEEDED(hr = IPin_EnumMediaTypes(pReceivePin, &pEnumCandidates))) /* if we haven't already connected successfully */
448             {
449                 hr = VFW_E_NO_ACCEPTABLE_TYPES; /* Assume the worst, but set to S_OK if connected successfully */
450
451                 while (S_OK == IEnumMediaTypes_Next(pEnumCandidates, 1, &pmtCandidate, NULL))
452                 {
453                     assert(pmtCandidate);
454                     dump_AM_MEDIA_TYPE(pmtCandidate);
455                     if (( !pmt || CompareMediaTypes(pmt, pmtCandidate, TRUE) ) &&
456                         (This->pin.pFuncsTable->pfnAttemptConnection((BasePin*)This, pReceivePin, pmtCandidate) == S_OK))
457                     {
458                         hr = S_OK;
459                         DeleteMediaType(pmtCandidate);
460                         break;
461                     }
462                     DeleteMediaType(pmtCandidate);
463                     pmtCandidate = NULL;
464                 } /* while */
465                 IEnumMediaTypes_Release(pEnumCandidates);
466             } /* if not found */
467         } /* if negotiate media type */
468     } /* if succeeded */
469     LeaveCriticalSection(This->pin.pCritSec);
470
471     TRACE(" -- %x\n", hr);
472     return hr;
473 }
474
475 HRESULT WINAPI BaseOutputPinImpl_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
476 {
477     ERR("Incoming connection on an output pin! (%p, %p)\n", pReceivePin, pmt);
478
479     return E_UNEXPECTED;
480 }
481
482 HRESULT WINAPI BaseOutputPinImpl_Disconnect(IPin * iface)
483 {
484     HRESULT hr;
485     BaseOutputPin *This = (BaseOutputPin *)iface;
486
487     TRACE("()\n");
488
489     EnterCriticalSection(This->pin.pCritSec);
490     {
491         if (This->pMemInputPin)
492         {
493             IMemInputPin_Release(This->pMemInputPin);
494             This->pMemInputPin = NULL;
495         }
496         if (This->pin.pConnectedTo)
497         {
498             IPin_Release(This->pin.pConnectedTo);
499             This->pin.pConnectedTo = NULL;
500             FreeMediaType(&This->pin.mtCurrent);
501             ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent));
502             hr = S_OK;
503         }
504         else
505             hr = S_FALSE;
506     }
507     LeaveCriticalSection(This->pin.pCritSec);
508
509     return hr;
510 }
511
512 HRESULT WINAPI BaseOutputPinImpl_EndOfStream(IPin * iface)
513 {
514     TRACE("()\n");
515
516     /* not supposed to do anything in an output pin */
517
518     return E_UNEXPECTED;
519 }
520
521 HRESULT WINAPI BaseOutputPinImpl_BeginFlush(IPin * iface)
522 {
523     TRACE("(%p)->()\n", iface);
524
525     /* not supposed to do anything in an output pin */
526
527     return E_UNEXPECTED;
528 }
529
530 HRESULT WINAPI BaseOutputPinImpl_EndFlush(IPin * iface)
531 {
532     TRACE("(%p)->()\n", iface);
533
534     /* not supposed to do anything in an output pin */
535
536     return E_UNEXPECTED;
537 }
538
539 static const IPinVtbl OutputPin_Vtbl =
540 {
541     BaseOutputPinImpl_QueryInterface,
542     BasePinImpl_AddRef,
543     BaseOutputPinImpl_Release,
544     BaseOutputPinImpl_Connect,
545     BaseOutputPinImpl_ReceiveConnection,
546     BaseOutputPinImpl_Disconnect,
547     BasePinImpl_ConnectedTo,
548     BasePinImpl_ConnectionMediaType,
549     BasePinImpl_QueryPinInfo,
550     BasePinImpl_QueryDirection,
551     BasePinImpl_QueryId,
552     BasePinImpl_QueryAccept,
553     BasePinImpl_EnumMediaTypes,
554     BasePinImpl_QueryInternalConnections,
555     BaseOutputPinImpl_EndOfStream,
556     BaseOutputPinImpl_BeginFlush,
557     BaseOutputPinImpl_EndFlush,
558     BasePinImpl_NewSegment
559 };
560
561 HRESULT WINAPI BaseOutputPinImpl_GetDeliveryBuffer(BaseOutputPin *This, IMediaSample ** ppSample, REFERENCE_TIME * tStart, REFERENCE_TIME * tStop, DWORD dwFlags)
562 {
563     HRESULT hr;
564
565     TRACE("(%p, %p, %p, %x)\n", ppSample, tStart, tStop, dwFlags);
566
567     EnterCriticalSection(This->pin.pCritSec);
568     {
569         if (!This->pin.pConnectedTo)
570             hr = VFW_E_NOT_CONNECTED;
571         else
572         {
573             IMemAllocator * pAlloc = NULL;
574
575             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
576
577             if (SUCCEEDED(hr))
578                 hr = IMemAllocator_GetBuffer(pAlloc, ppSample, tStart, tStop, dwFlags);
579
580             if (SUCCEEDED(hr))
581                 hr = IMediaSample_SetTime(*ppSample, tStart, tStop);
582
583             if (pAlloc)
584                 IMemAllocator_Release(pAlloc);
585         }
586     }
587     LeaveCriticalSection(This->pin.pCritSec);
588
589     return hr;
590 }
591
592 /* replaces OutputPin_SendSample */
593 HRESULT WINAPI BaseOutputPinImpl_Deliver(BaseOutputPin *This, IMediaSample * pSample)
594 {
595     HRESULT hr = S_OK;
596     IMemInputPin * pMemConnected = NULL;
597     PIN_INFO pinInfo;
598
599     EnterCriticalSection(This->pin.pCritSec);
600     {
601         if (!This->pin.pConnectedTo || !This->pMemInputPin)
602             hr = VFW_E_NOT_CONNECTED;
603         else
604         {
605             /* we don't have the lock held when using This->pMemInputPin,
606              * so we need to AddRef it to stop it being deleted while we are
607              * using it. Same with its filter. */
608             pMemConnected = This->pMemInputPin;
609             IMemInputPin_AddRef(pMemConnected);
610             hr = IPin_QueryPinInfo(This->pin.pConnectedTo, &pinInfo);
611         }
612     }
613     LeaveCriticalSection(This->pin.pCritSec);
614
615     if (SUCCEEDED(hr))
616     {
617         /* NOTE: if we are in a critical section when Receive is called
618          * then it causes some problems (most notably with the native Video
619          * Renderer) if we are re-entered for whatever reason */
620         hr = IMemInputPin_Receive(pMemConnected, pSample);
621
622         /* If the filter's destroyed, tell upstream to stop sending data */
623         if(IBaseFilter_Release(pinInfo.pFilter) == 0 && SUCCEEDED(hr))
624             hr = S_FALSE;
625     }
626     if (pMemConnected)
627         IMemInputPin_Release(pMemConnected);
628
629     return hr;
630 }
631
632 /* replaces OutputPin_CommitAllocator */
633 HRESULT WINAPI BaseOutputPinImpl_Active(BaseOutputPin *This)
634 {
635     HRESULT hr = S_OK;
636
637     TRACE("(%p)->()\n", This);
638
639     EnterCriticalSection(This->pin.pCritSec);
640     {
641         if (!This->pin.pConnectedTo || !This->pMemInputPin)
642             hr = VFW_E_NOT_CONNECTED;
643         else
644         {
645             IMemAllocator * pAlloc = NULL;
646
647             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
648
649             if (SUCCEEDED(hr))
650                 hr = IMemAllocator_Commit(pAlloc);
651
652             if (pAlloc)
653                 IMemAllocator_Release(pAlloc);
654         }
655     }
656     LeaveCriticalSection(This->pin.pCritSec);
657
658     TRACE("--> %08x\n", hr);
659     return hr;
660 }
661
662 /* replaces OutputPin_DecommitAllocator */
663 HRESULT WINAPI BaseOutputPinImpl_Inactive(BaseOutputPin *This)
664 {
665     HRESULT hr = S_OK;
666
667     TRACE("(%p)->()\n", This);
668
669     EnterCriticalSection(This->pin.pCritSec);
670     {
671         if (!This->pin.pConnectedTo || !This->pMemInputPin)
672             hr = VFW_E_NOT_CONNECTED;
673         else
674         {
675             IMemAllocator * pAlloc = NULL;
676
677             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
678
679             if (SUCCEEDED(hr))
680                 hr = IMemAllocator_Decommit(pAlloc);
681
682             if (pAlloc)
683                 IMemAllocator_Release(pAlloc);
684         }
685     }
686     LeaveCriticalSection(This->pin.pCritSec);
687
688     TRACE("--> %08x\n", hr);
689     return hr;
690 }
691
692 /* replaces OutputPin_DeliverDisconnect */
693 HRESULT WINAPI BaseOutputPinImpl_BreakConnect(BaseOutputPin *This)
694 {
695     HRESULT hr;
696
697     TRACE("(%p)->()\n", This);
698
699     EnterCriticalSection(This->pin.pCritSec);
700     {
701         if (!This->pin.pConnectedTo || !This->pMemInputPin)
702             hr = VFW_E_NOT_CONNECTED;
703         else
704         {
705             IMemAllocator * pAlloc = NULL;
706
707             hr = IMemInputPin_GetAllocator(This->pMemInputPin, &pAlloc);
708
709             if (SUCCEEDED(hr))
710                 hr = IMemAllocator_Decommit(pAlloc);
711
712             if (pAlloc)
713                 IMemAllocator_Release(pAlloc);
714
715             if (SUCCEEDED(hr))
716                 hr = IPin_Disconnect(This->pin.pConnectedTo);
717         }
718         IPin_Disconnect((IPin *)This);
719     }
720     LeaveCriticalSection(This->pin.pCritSec);
721
722     return hr;
723 }
724
725 HRESULT WINAPI BaseOutputPinImpl_InitAllocator(BaseOutputPin *This, IMemAllocator **pMemAlloc)
726 {
727     return CoCreateInstance(&CLSID_MemoryAllocator, NULL, CLSCTX_INPROC_SERVER, &IID_IMemAllocator, (LPVOID*)pMemAlloc);
728 }
729
730 HRESULT WINAPI BaseOutputPinImpl_DecideAllocator(BaseOutputPin *This, IMemInputPin *pPin, IMemAllocator **pAlloc)
731 {
732     HRESULT hr;
733
734     hr = IMemInputPin_GetAllocator(pPin, pAlloc);
735
736     if (hr == VFW_E_NO_ALLOCATOR)
737         /* Input pin provides no allocator, use standard memory allocator */
738         hr = BaseOutputPinImpl_InitAllocator(This, pAlloc);
739
740     if (SUCCEEDED(hr))
741     {
742         ALLOCATOR_PROPERTIES rProps;
743         ZeroMemory(&rProps, sizeof(ALLOCATOR_PROPERTIES));
744
745         IMemInputPin_GetAllocatorRequirements(pPin, &rProps);
746         hr = This->pFuncsTable->pfnDecideBufferSize(This, *pAlloc, &rProps);
747     }
748
749     if (SUCCEEDED(hr))
750         hr = IMemInputPin_NotifyAllocator(pPin, *pAlloc, FALSE);
751
752     return hr;
753 }
754
755 /*** The Construct functions ***/
756
757 /* Function called as a helper to IPin_Connect */
758 /* specific AM_MEDIA_TYPE - it cannot be NULL */
759 HRESULT WINAPI BaseOutputPinImpl_AttemptConnection(BasePin* iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
760 {
761     BaseOutputPin *This = (BaseOutputPin *)iface;
762     HRESULT hr;
763     IMemAllocator * pMemAlloc = NULL;
764
765     TRACE("(%p, %p)\n", pReceivePin, pmt);
766     dump_AM_MEDIA_TYPE(pmt);
767
768     /* FIXME: call queryacceptproc */
769
770     This->pin.pConnectedTo = pReceivePin;
771     IPin_AddRef(pReceivePin);
772     CopyMediaType(&This->pin.mtCurrent, pmt);
773
774     hr = IPin_ReceiveConnection(pReceivePin, (IPin*)iface, pmt);
775
776     /* get the IMemInputPin interface we will use to deliver samples to the
777      * connected pin */
778     if (SUCCEEDED(hr))
779     {
780         This->pMemInputPin = NULL;
781         hr = IPin_QueryInterface(pReceivePin, &IID_IMemInputPin, (LPVOID)&This->pMemInputPin);
782
783         if (SUCCEEDED(hr))
784         {
785             hr = This->pFuncsTable->pfnDecideAllocator(This, This->pMemInputPin, &pMemAlloc);
786             if (pMemAlloc)
787                 IMemAllocator_Release(pMemAlloc);
788         }
789
790         /* break connection if we couldn't get the allocator */
791         if (FAILED(hr))
792         {
793             if (This->pMemInputPin)
794                 IMemInputPin_Release(This->pMemInputPin);
795             This->pMemInputPin = NULL;
796
797             IPin_Disconnect(pReceivePin);
798         }
799     }
800
801     if (FAILED(hr))
802     {
803         IPin_Release(This->pin.pConnectedTo);
804         This->pin.pConnectedTo = NULL;
805         FreeMediaType(&This->pin.mtCurrent);
806     }
807
808     TRACE(" -- %x\n", hr);
809     return hr;
810 }
811
812 static HRESULT OutputPin_Init(const IPinVtbl *OutputPin_Vtbl, const PIN_INFO * pPinInfo, const BasePinFuncTable* pBaseFuncsTable, const BaseOutputPinFuncTable* pBaseOutputFuncsTable,  LPCRITICAL_SECTION pCritSec, BaseOutputPin * pPinImpl)
813 {
814     TRACE("\n");
815
816     /* Common attributes */
817     pPinImpl->pin.lpVtbl = OutputPin_Vtbl;
818     pPinImpl->pin.refCount = 1;
819     pPinImpl->pin.pConnectedTo = NULL;
820     pPinImpl->pin.pCritSec = pCritSec;
821     pPinImpl->pin.tStart = 0;
822     pPinImpl->pin.tStop = 0;
823     pPinImpl->pin.dRate = 1.0;
824     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
825     pPinImpl->pin.pFuncsTable = pBaseFuncsTable;
826     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
827
828     /* Output pin attributes */
829     pPinImpl->pMemInputPin = NULL;
830     pPinImpl->pFuncsTable = pBaseOutputFuncsTable;
831
832     return S_OK;
833 }
834
835 HRESULT WINAPI BaseOutputPin_Construct(const IPinVtbl *OutputPin_Vtbl, LONG outputpin_size, const PIN_INFO * pPinInfo, const BasePinFuncTable* pBaseFuncsTable, const BaseOutputPinFuncTable* pBaseOutputFuncsTable, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
836 {
837     BaseOutputPin * pPinImpl;
838
839     *ppPin = NULL;
840
841     if (pPinInfo->dir != PINDIR_OUTPUT)
842     {
843         ERR("Pin direction(%x) != PINDIR_OUTPUT\n", pPinInfo->dir);
844         return E_INVALIDARG;
845     }
846
847     assert(outputpin_size >= sizeof(BaseOutputPin));
848     assert(pBaseFuncsTable->pfnAttemptConnection);
849
850     pPinImpl = CoTaskMemAlloc(outputpin_size);
851
852     if (!pPinImpl)
853         return E_OUTOFMEMORY;
854
855     if (SUCCEEDED(OutputPin_Init(OutputPin_Vtbl, pPinInfo, pBaseFuncsTable, pBaseOutputFuncsTable, pCritSec, pPinImpl)))
856     {
857         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
858         return S_OK;
859     }
860
861     CoTaskMemFree(pPinImpl);
862     return E_FAIL;
863 }
864
865 /*** Input Pin implementation ***/
866
867 HRESULT WINAPI BaseInputPinImpl_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
868 {
869     BaseInputPin *This = (BaseInputPin *)iface;
870
871     TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ppv);
872
873     *ppv = NULL;
874
875     if (IsEqualIID(riid, &IID_IUnknown))
876         *ppv = iface;
877     else if (IsEqualIID(riid, &IID_IPin))
878         *ppv = iface;
879     else if (IsEqualIID(riid, &IID_IMemInputPin))
880         *ppv = &This->lpVtblMemInput;
881     else if (IsEqualIID(riid, &IID_IMediaSeeking))
882     {
883         return IBaseFilter_QueryInterface(This->pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
884     }
885
886     if (*ppv)
887     {
888         IUnknown_AddRef((IUnknown *)(*ppv));
889         return S_OK;
890     }
891
892     FIXME("No interface for %s!\n", debugstr_guid(riid));
893
894     return E_NOINTERFACE;
895 }
896
897 ULONG WINAPI BaseInputPinImpl_Release(IPin * iface)
898 {
899     BaseInputPin *This = (BaseInputPin *)iface;
900     ULONG refCount = InterlockedDecrement(&This->pin.refCount);
901
902     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
903
904     if (!refCount)
905     {
906         FreeMediaType(&This->pin.mtCurrent);
907         if (This->pAllocator)
908             IMemAllocator_Release(This->pAllocator);
909         This->pAllocator = NULL;
910         This->pin.lpVtbl = NULL;
911         CoTaskMemFree(This);
912         return 0;
913     }
914     else
915         return refCount;
916 }
917
918 HRESULT WINAPI BaseInputPinImpl_Connect(IPin * iface, IPin * pConnector, const AM_MEDIA_TYPE * pmt)
919 {
920     ERR("Outgoing connection on an input pin! (%p, %p)\n", pConnector, pmt);
921
922     return E_UNEXPECTED;
923 }
924
925
926 HRESULT WINAPI BaseInputPinImpl_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
927 {
928     BaseInputPin *This = (BaseInputPin *)iface;
929     PIN_DIRECTION pindirReceive;
930     HRESULT hr = S_OK;
931
932     TRACE("(%p, %p)\n", pReceivePin, pmt);
933     dump_AM_MEDIA_TYPE(pmt);
934
935     EnterCriticalSection(This->pin.pCritSec);
936     {
937         if (This->pin.pConnectedTo)
938             hr = VFW_E_ALREADY_CONNECTED;
939
940         if (SUCCEEDED(hr) && This->pin.pFuncsTable->pfnCheckMediaType((BasePin*)This, pmt) != S_OK)
941             hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto
942                                            * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */
943
944         if (SUCCEEDED(hr))
945         {
946             IPin_QueryDirection(pReceivePin, &pindirReceive);
947
948             if (pindirReceive != PINDIR_OUTPUT)
949             {
950                 ERR("Can't connect from non-output pin\n");
951                 hr = VFW_E_INVALID_DIRECTION;
952             }
953         }
954
955         if (SUCCEEDED(hr))
956         {
957             CopyMediaType(&This->pin.mtCurrent, pmt);
958             This->pin.pConnectedTo = pReceivePin;
959             IPin_AddRef(pReceivePin);
960         }
961     }
962     LeaveCriticalSection(This->pin.pCritSec);
963
964     return hr;
965 }
966
967 static HRESULT deliver_endofstream(IPin* pin, LPVOID unused)
968 {
969     return IPin_EndOfStream( pin );
970 }
971
972 HRESULT WINAPI BaseInputPinImpl_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt)
973 {
974     BaseInputPin *This = (BaseInputPin *)iface;
975
976     TRACE("(%p/%p)->(%p)\n", This, iface, pmt);
977
978     return (This->pin.pFuncsTable->pfnCheckMediaType((BasePin*)This, pmt) == S_OK ? S_OK : S_FALSE);
979 }
980
981 HRESULT WINAPI BaseInputPinImpl_EndOfStream(IPin * iface)
982 {
983     HRESULT hr = S_OK;
984     BaseInputPin *This = (BaseInputPin *)iface;
985
986     TRACE("(%p)\n", This);
987
988     EnterCriticalSection(This->pin.pCritSec);
989     if (This->flushing)
990         hr = S_FALSE;
991     else
992         This->end_of_stream = 1;
993     LeaveCriticalSection(This->pin.pCritSec);
994
995     if (hr == S_OK)
996         hr = SendFurther( iface, deliver_endofstream, NULL, NULL );
997     return hr;
998 }
999
1000 static HRESULT deliver_beginflush(IPin* pin, LPVOID unused)
1001 {
1002     return IPin_BeginFlush( pin );
1003 }
1004
1005 HRESULT WINAPI BaseInputPinImpl_BeginFlush(IPin * iface)
1006 {
1007     BaseInputPin *This = (BaseInputPin *)iface;
1008     HRESULT hr;
1009     TRACE("() semi-stub\n");
1010
1011     EnterCriticalSection(This->pin.pCritSec);
1012     This->flushing = 1;
1013
1014     hr = SendFurther( iface, deliver_beginflush, NULL, NULL );
1015     LeaveCriticalSection(This->pin.pCritSec);
1016
1017     return hr;
1018 }
1019
1020 static HRESULT deliver_endflush(IPin* pin, LPVOID unused)
1021 {
1022     return IPin_EndFlush( pin );
1023 }
1024
1025 HRESULT WINAPI BaseInputPinImpl_EndFlush(IPin * iface)
1026 {
1027     BaseInputPin *This = (BaseInputPin *)iface;
1028     HRESULT hr;
1029     TRACE("(%p)\n", This);
1030
1031     EnterCriticalSection(This->pin.pCritSec);
1032     This->flushing = This->end_of_stream = 0;
1033
1034     hr = SendFurther( iface, deliver_endflush, NULL, NULL );
1035     LeaveCriticalSection(This->pin.pCritSec);
1036
1037     return hr;
1038 }
1039
1040 typedef struct newsegmentargs
1041 {
1042     REFERENCE_TIME tStart, tStop;
1043     double rate;
1044 } newsegmentargs;
1045
1046 static HRESULT deliver_newsegment(IPin *pin, LPVOID data)
1047 {
1048     newsegmentargs *args = data;
1049     return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate);
1050 }
1051
1052 HRESULT WINAPI BaseInputPinImpl_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
1053 {
1054     BaseInputPin *This = (BaseInputPin *)iface;
1055     newsegmentargs args;
1056
1057     TRACE("(%x%08x, %x%08x, %e)\n", (ULONG)(tStart >> 32), (ULONG)tStart, (ULONG)(tStop >> 32), (ULONG)tStop, dRate);
1058
1059     args.tStart = This->pin.tStart = tStart;
1060     args.tStop = This->pin.tStop = tStop;
1061     args.rate = This->pin.dRate = dRate;
1062
1063     return SendFurther( iface, deliver_newsegment, &args, NULL );
1064 }
1065
1066 static const IPinVtbl InputPin_Vtbl =
1067 {
1068     BaseInputPinImpl_QueryInterface,
1069     BasePinImpl_AddRef,
1070     BaseInputPinImpl_Release,
1071     BaseInputPinImpl_Connect,
1072     BaseInputPinImpl_ReceiveConnection,
1073     BasePinImpl_Disconnect,
1074     BasePinImpl_ConnectedTo,
1075     BasePinImpl_ConnectionMediaType,
1076     BasePinImpl_QueryPinInfo,
1077     BasePinImpl_QueryDirection,
1078     BasePinImpl_QueryId,
1079     BaseInputPinImpl_QueryAccept,
1080     BasePinImpl_EnumMediaTypes,
1081     BasePinImpl_QueryInternalConnections,
1082     BaseInputPinImpl_EndOfStream,
1083     BaseInputPinImpl_BeginFlush,
1084     BaseInputPinImpl_EndFlush,
1085     BaseInputPinImpl_NewSegment
1086 };
1087
1088 /*** IMemInputPin implementation ***/
1089
1090 static inline BaseInputPin *impl_from_IMemInputPin( IMemInputPin *iface )
1091 {
1092     return (BaseInputPin *)((char*)iface - FIELD_OFFSET(BaseInputPin, lpVtblMemInput));
1093 }
1094
1095 static HRESULT WINAPI MemInputPin_QueryInterface(IMemInputPin * iface, REFIID riid, LPVOID * ppv)
1096 {
1097     BaseInputPin *This = impl_from_IMemInputPin(iface);
1098
1099     return IPin_QueryInterface((IPin *)&This->pin, riid, ppv);
1100 }
1101
1102 static ULONG WINAPI MemInputPin_AddRef(IMemInputPin * iface)
1103 {
1104     BaseInputPin *This = impl_from_IMemInputPin(iface);
1105
1106     return IPin_AddRef((IPin *)&This->pin);
1107 }
1108
1109 static ULONG WINAPI MemInputPin_Release(IMemInputPin * iface)
1110 {
1111     BaseInputPin *This = impl_from_IMemInputPin(iface);
1112
1113     return IPin_Release((IPin *)&This->pin);
1114 }
1115
1116 static HRESULT WINAPI MemInputPin_GetAllocator(IMemInputPin * iface, IMemAllocator ** ppAllocator)
1117 {
1118     BaseInputPin *This = impl_from_IMemInputPin(iface);
1119
1120     TRACE("(%p/%p)->(%p)\n", This, iface, ppAllocator);
1121
1122     *ppAllocator = This->pAllocator;
1123     if (*ppAllocator)
1124         IMemAllocator_AddRef(*ppAllocator);
1125
1126     return *ppAllocator ? S_OK : VFW_E_NO_ALLOCATOR;
1127 }
1128
1129 static HRESULT WINAPI MemInputPin_NotifyAllocator(IMemInputPin * iface, IMemAllocator * pAllocator, BOOL bReadOnly)
1130 {
1131     BaseInputPin *This = impl_from_IMemInputPin(iface);
1132
1133     TRACE("(%p/%p)->(%p, %d)\n", This, iface, pAllocator, bReadOnly);
1134
1135     if (bReadOnly)
1136         FIXME("Read only flag not handled yet!\n");
1137
1138     /* FIXME: Should we release the allocator on disconnection? */
1139     if (!pAllocator)
1140     {
1141         WARN("Null allocator\n");
1142         return E_POINTER;
1143     }
1144
1145     if (This->preferred_allocator && pAllocator != This->preferred_allocator)
1146         return E_FAIL;
1147
1148     if (This->pAllocator)
1149         IMemAllocator_Release(This->pAllocator);
1150     This->pAllocator = pAllocator;
1151     if (This->pAllocator)
1152         IMemAllocator_AddRef(This->pAllocator);
1153
1154     return S_OK;
1155 }
1156
1157 static HRESULT WINAPI MemInputPin_GetAllocatorRequirements(IMemInputPin * iface, ALLOCATOR_PROPERTIES * pProps)
1158 {
1159     BaseInputPin *This = impl_from_IMemInputPin(iface);
1160
1161     TRACE("(%p/%p)->(%p)\n", This, iface, pProps);
1162
1163     /* override this method if you have any specific requirements */
1164
1165     return E_NOTIMPL;
1166 }
1167
1168 static HRESULT WINAPI MemInputPin_Receive(IMemInputPin * iface, IMediaSample * pSample)
1169 {
1170     BaseInputPin *This = impl_from_IMemInputPin(iface);
1171     HRESULT hr = S_FALSE;
1172
1173     /* this trace commented out for performance reasons */
1174     /*TRACE("(%p/%p)->(%p)\n", This, iface, pSample);*/
1175     if (This->pFuncsTable->pfnReceive)
1176         hr = This->pFuncsTable->pfnReceive(This, pSample);
1177     return hr;
1178 }
1179
1180 static HRESULT WINAPI MemInputPin_ReceiveMultiple(IMemInputPin * iface, IMediaSample ** pSamples, LONG nSamples, LONG *nSamplesProcessed)
1181 {
1182     HRESULT hr = S_OK;
1183     BaseInputPin *This = impl_from_IMemInputPin(iface);
1184
1185     TRACE("(%p/%p)->(%p, %d, %p)\n", This, iface, pSamples, nSamples, nSamplesProcessed);
1186
1187     for (*nSamplesProcessed = 0; *nSamplesProcessed < nSamples; (*nSamplesProcessed)++)
1188     {
1189         hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
1190         if (hr != S_OK)
1191             break;
1192     }
1193
1194     return hr;
1195 }
1196
1197 static HRESULT WINAPI MemInputPin_ReceiveCanBlock(IMemInputPin * iface)
1198 {
1199     BaseInputPin *This = impl_from_IMemInputPin(iface);
1200
1201     TRACE("(%p/%p)->()\n", This, iface);
1202
1203     return S_OK;
1204 }
1205
1206 static const IMemInputPinVtbl MemInputPin_Vtbl =
1207 {
1208     MemInputPin_QueryInterface,
1209     MemInputPin_AddRef,
1210     MemInputPin_Release,
1211     MemInputPin_GetAllocator,
1212     MemInputPin_NotifyAllocator,
1213     MemInputPin_GetAllocatorRequirements,
1214     MemInputPin_Receive,
1215     MemInputPin_ReceiveMultiple,
1216     MemInputPin_ReceiveCanBlock
1217 };
1218
1219 static HRESULT InputPin_Init(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo,
1220                              const BasePinFuncTable* pBaseFuncsTable, const BaseInputPinFuncTable* pBaseInputFuncsTable,
1221                              LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, BaseInputPin * pPinImpl)
1222 {
1223     TRACE("\n");
1224
1225     /* Common attributes */
1226     pPinImpl->pin.refCount = 1;
1227     pPinImpl->pin.pConnectedTo = NULL;
1228     pPinImpl->pin.pCritSec = pCritSec;
1229     pPinImpl->pin.tStart = 0;
1230     pPinImpl->pin.tStop = 0;
1231     pPinImpl->pin.dRate = 1.0;
1232     Copy_PinInfo(&pPinImpl->pin.pinInfo, pPinInfo);
1233     ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE));
1234     pPinImpl->pin.pFuncsTable = pBaseFuncsTable;
1235
1236     /* Input pin attributes */
1237     pPinImpl->pFuncsTable = pBaseInputFuncsTable;
1238     pPinImpl->pAllocator = pPinImpl->preferred_allocator = allocator;
1239     if (pPinImpl->preferred_allocator)
1240         IMemAllocator_AddRef(pPinImpl->preferred_allocator);
1241     pPinImpl->pin.lpVtbl = InputPin_Vtbl;
1242     pPinImpl->lpVtblMemInput = &MemInputPin_Vtbl;
1243     pPinImpl->flushing = pPinImpl->end_of_stream = 0;
1244
1245     return S_OK;
1246 }
1247
1248 HRESULT BaseInputPin_Construct(const IPinVtbl *InputPin_Vtbl, const PIN_INFO * pPinInfo,
1249                                const BasePinFuncTable* pBaseFuncsTable, const BaseInputPinFuncTable* pBaseInputFuncsTable,
1250                                LPCRITICAL_SECTION pCritSec, IMemAllocator *allocator, IPin ** ppPin)
1251 {
1252     BaseInputPin * pPinImpl;
1253
1254     *ppPin = NULL;
1255
1256     assert(pBaseFuncsTable->pfnCheckMediaType);
1257
1258     if (pPinInfo->dir != PINDIR_INPUT)
1259     {
1260         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
1261         return E_INVALIDARG;
1262     }
1263
1264     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
1265
1266     if (!pPinImpl)
1267         return E_OUTOFMEMORY;
1268
1269     if (SUCCEEDED(InputPin_Init(InputPin_Vtbl, pPinInfo, pBaseFuncsTable, pBaseInputFuncsTable, pCritSec, allocator, pPinImpl)))
1270     {
1271         *ppPin = (IPin *)pPinImpl;
1272         return S_OK;
1273     }
1274
1275     CoTaskMemFree(pPinImpl);
1276     return E_FAIL;
1277 }