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