wined3d: We want to compare the old and the new format and not the old with the old.
[wine] / dlls / quartz / parser.c
1 /*
2  * Parser (Base for parsers and splitters)
3  *
4  * Copyright 2003 Robert Shearman
5  * Copyright 2004-2005 Christian Costa
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 "quartz_private.h"
23 #include "control_private.h"
24 #include "pin.h"
25
26 #include "vfwmsgs.h"
27 #include "amvideo.h"
28
29 #include "wine/unicode.h"
30 #include "wine/debug.h"
31
32 #include <math.h>
33 #include <assert.h>
34
35 #include "parser.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
38
39 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
40 static const IBaseFilterVtbl Parser_Vtbl;
41 static const IMediaSeekingVtbl Parser_Seeking_Vtbl;
42 static const IPinVtbl Parser_OutputPin_Vtbl;
43 static const IPinVtbl Parser_InputPin_Vtbl;
44
45 static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt);
46 static HRESULT Parser_ChangeStart(IBaseFilter *iface);
47 static HRESULT Parser_ChangeStop(IBaseFilter *iface);
48 static HRESULT Parser_ChangeRate(IBaseFilter *iface);
49
50 static HRESULT Parser_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
51
52 static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
53 {
54     return (ParserImpl *)((char*)iface - FIELD_OFFSET(ParserImpl, mediaSeeking.lpVtbl));
55 }
56
57
58 HRESULT Parser_Create(ParserImpl* pParser, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup)
59 {
60     HRESULT hr;
61     PIN_INFO piInput;
62
63     /* pTransformFilter is already allocated */
64     pParser->clsid = *pClsid;
65
66     pParser->lpVtbl = &Parser_Vtbl;
67     pParser->refCount = 1;
68     InitializeCriticalSection(&pParser->csFilter);
69     pParser->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ParserImpl.csFilter");
70     pParser->state = State_Stopped;
71     pParser->pClock = NULL;
72     pParser->fnCleanup = fnCleanup;
73     ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO));
74
75     pParser->cStreams = 0;
76     pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
77
78     /* construct input pin */
79     piInput.dir = PINDIR_INPUT;
80     piInput.pFilter = (IBaseFilter *)pParser;
81     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
82
83     MediaSeekingImpl_Init((IBaseFilter*)pParser, Parser_ChangeStop, Parser_ChangeStart, Parser_ChangeRate, &pParser->mediaSeeking, &pParser->csFilter);
84     pParser->mediaSeeking.lpVtbl = &Parser_Seeking_Vtbl;
85
86     hr = Parser_InputPin_Construct(&piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, &pParser->csFilter, (IPin **)&pParser->pInputPin);
87
88     if (SUCCEEDED(hr))
89     {
90         pParser->ppPins[0] = (IPin *)pParser->pInputPin;
91         pParser->pInputPin->fnPreConnect = fnPreConnect;
92     }
93     else
94     {
95         CoTaskMemFree(pParser->ppPins);
96         pParser->csFilter.DebugInfo->Spare[0] = 0;
97         DeleteCriticalSection(&pParser->csFilter);
98         CoTaskMemFree(pParser);
99     }
100
101     return hr;
102 }
103
104 static HRESULT Parser_OutputPin_Init(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, const AM_MEDIA_TYPE * pmt, LPCRITICAL_SECTION pCritSec, Parser_OutputPin * pPinImpl)
105 {
106     pPinImpl->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
107     CopyMediaType(pPinImpl->pmt, pmt);
108     pPinImpl->dwSamplesProcessed = 0;
109
110     return OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, &pPinImpl->pin);
111 }
112
113 static HRESULT Parser_OutputPin_Construct(const PIN_INFO * pPinInfo, ALLOCATOR_PROPERTIES * props, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, const AM_MEDIA_TYPE * pmt, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
114 {
115     Parser_OutputPin * pPinImpl;
116
117     *ppPin = NULL;
118
119     assert(pPinInfo->dir == PINDIR_OUTPUT);
120
121     pPinImpl = CoTaskMemAlloc(sizeof(Parser_OutputPin));
122
123     if (!pPinImpl)
124         return E_OUTOFMEMORY;
125
126     if (SUCCEEDED(Parser_OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pmt, pCritSec, pPinImpl)))
127     {
128         pPinImpl->pin.pin.lpVtbl = &Parser_OutputPin_Vtbl;
129
130         *ppPin = (IPin *)pPinImpl;
131         return S_OK;
132     }
133
134     CoTaskMemFree(pPinImpl);
135     return E_FAIL;
136 }
137
138 static HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
139 {
140     ParserImpl *This = (ParserImpl *)iface;
141     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
142
143     *ppv = NULL;
144
145     if (IsEqualIID(riid, &IID_IUnknown))
146         *ppv = (LPVOID)This;
147     else if (IsEqualIID(riid, &IID_IPersist))
148         *ppv = (LPVOID)This;
149     else if (IsEqualIID(riid, &IID_IMediaFilter))
150         *ppv = (LPVOID)This;
151     else if (IsEqualIID(riid, &IID_IBaseFilter))
152         *ppv = (LPVOID)This;
153     else if (IsEqualIID(riid, &IID_IMediaSeeking))
154         *ppv = (LPVOID)&This->mediaSeeking;
155
156     if (*ppv)
157     {
158         IUnknown_AddRef((IUnknown *)(*ppv));
159         return S_OK;
160     }
161
162     if (!IsEqualIID(riid, &IID_IPin))
163         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
164
165     return E_NOINTERFACE;
166 }
167
168 static ULONG WINAPI Parser_AddRef(IBaseFilter * iface)
169 {
170     ParserImpl *This = (ParserImpl *)iface;
171     ULONG refCount = InterlockedIncrement(&This->refCount);
172
173     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
174
175     return refCount;
176 }
177
178 static ULONG WINAPI Parser_Release(IBaseFilter * iface)
179 {
180     ParserImpl *This = (ParserImpl *)iface;
181     ULONG refCount = InterlockedDecrement(&This->refCount);
182
183     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
184     
185     if (!refCount)
186     {
187         ULONG i;
188
189         if (This->fnCleanup)
190             This->fnCleanup(This);
191
192         if (This->pClock)
193             IReferenceClock_Release(This->pClock);
194         
195         for (i = 0; i < This->cStreams + 1; i++)
196         {
197             IPin *pConnectedTo;
198
199             if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
200             {
201                 IPin_Disconnect(pConnectedTo);
202                 IPin_Release(pConnectedTo);
203             }
204             IPin_Disconnect(This->ppPins[i]);
205
206             IPin_Release(This->ppPins[i]);
207         }
208         
209         CoTaskMemFree(This->ppPins);
210         This->lpVtbl = NULL;
211
212         This->csFilter.DebugInfo->Spare[0] = 0;
213         DeleteCriticalSection(&This->csFilter);
214         
215         TRACE("Destroying parser\n");
216         CoTaskMemFree(This);
217         
218         return 0;
219     }
220     else
221         return refCount;
222 }
223
224 /** IPersist methods **/
225
226 static HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid)
227 {
228     ParserImpl *This = (ParserImpl *)iface;
229
230     TRACE("(%p)\n", pClsid);
231
232     *pClsid = This->clsid;
233
234     return S_OK;
235 }
236
237 /** IMediaFilter methods **/
238
239 static HRESULT WINAPI Parser_Stop(IBaseFilter * iface)
240 {
241     HRESULT hr;
242     ParserImpl *This = (ParserImpl *)iface;
243
244     TRACE("()\n");
245
246     EnterCriticalSection(&This->csFilter);
247     {
248         if (This->state == State_Stopped)
249         {
250             LeaveCriticalSection(&This->csFilter);
251             return S_OK;
252         }
253         hr = PullPin_StopProcessing(This->pInputPin);
254         This->state = State_Stopped;
255     }
256     LeaveCriticalSection(&This->csFilter);
257     
258     return hr;
259 }
260
261 static HRESULT WINAPI Parser_Pause(IBaseFilter * iface)
262 {
263     HRESULT hr = S_OK;
264     BOOL bInit;
265     ParserImpl *This = (ParserImpl *)iface;
266     
267     TRACE("()\n");
268
269     EnterCriticalSection(&This->csFilter);
270     {
271         if (This->state == State_Paused)
272         {
273             LeaveCriticalSection(&This->csFilter);
274             return S_OK;
275         }
276         bInit = (This->state == State_Stopped);
277         This->state = State_Paused;
278     }
279     LeaveCriticalSection(&This->csFilter);
280
281     if (bInit)
282     {
283         unsigned int i;
284
285         hr = PullPin_Seek(This->pInputPin, 0, ((LONGLONG)0x7fffffff << 32) | 0xffffffff);
286
287         if (SUCCEEDED(hr))
288             hr = PullPin_InitProcessing(This->pInputPin);
289
290         if (SUCCEEDED(hr))
291         {
292             for (i = 1; i < This->cStreams + 1; i++)
293             {
294                 LONGLONG duration;
295                 DOUBLE speed;
296
297                 IMediaSeeking_GetDuration((IMediaSeeking *)&This->mediaSeeking, &duration);
298                 IMediaSeeking_GetRate((IMediaSeeking *)&This->mediaSeeking, &speed);
299                 OutputPin_DeliverNewSegment((OutputPin *)This->ppPins[i], 0, duration, speed);
300                 OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
301             }
302
303             /* FIXME: this is a little hacky: we have to deliver (at least?) one sample
304              * to each renderer before they will complete their transitions. We should probably
305              * seek through the stream for the first of each, rather than do it this way which is
306              * probably a bit prone to deadlocking */
307             hr = PullPin_StartProcessing(This->pInputPin);
308         }
309     }
310     /* FIXME: else pause thread */
311
312     if (SUCCEEDED(hr))
313         hr = PullPin_PauseProcessing(This->pInputPin);
314
315     return hr;
316 }
317
318 static HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
319 {
320     HRESULT hr = S_OK;
321     ParserImpl *This = (ParserImpl *)iface;
322     int i;
323
324     TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
325
326     EnterCriticalSection(&This->csFilter);
327     {
328         if (This->state == State_Running)
329         {
330             LeaveCriticalSection(&This->csFilter);
331             return S_OK;
332         }
333
334         This->rtStreamStart = tStart;
335
336         hr = PullPin_Seek(This->pInputPin, 0, ((LONGLONG)0x7fffffff << 32) | 0xffffffff);
337
338         if (SUCCEEDED(hr) && (This->state == State_Stopped))
339         {
340             hr = PullPin_InitProcessing(This->pInputPin);
341
342             if (SUCCEEDED(hr))
343             { 
344                 for (i = 1; i < (This->cStreams + 1); i++)
345                 {
346                     OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
347                 }
348             }
349         }
350
351         if (SUCCEEDED(hr))
352             hr = PullPin_StartProcessing(This->pInputPin);
353
354         if (SUCCEEDED(hr))
355             This->state = State_Running;
356     }
357     LeaveCriticalSection(&This->csFilter);
358
359     return hr;
360 }
361
362 static HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
363 {
364     ParserImpl *This = (ParserImpl *)iface;
365
366     TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState);
367
368     EnterCriticalSection(&This->csFilter);
369     {
370         *pState = This->state;
371     }
372     LeaveCriticalSection(&This->csFilter);
373
374     /* FIXME: this is a little bit unsafe, but I don't see that we can do this
375      * while in the critical section. Maybe we could copy the pointer and addref in the
376      * critical section and then release after this.
377      */
378     if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE))
379         return VFW_S_STATE_INTERMEDIATE;
380
381     return S_OK;
382 }
383
384 static HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
385 {
386     ParserImpl *This = (ParserImpl *)iface;
387
388     TRACE("(%p)\n", pClock);
389
390     EnterCriticalSection(&This->csFilter);
391     {
392         if (This->pClock)
393             IReferenceClock_Release(This->pClock);
394         This->pClock = pClock;
395         if (This->pClock)
396             IReferenceClock_AddRef(This->pClock);
397     }
398     LeaveCriticalSection(&This->csFilter);
399
400     return S_OK;
401 }
402
403 static HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
404 {
405     ParserImpl *This = (ParserImpl *)iface;
406
407     TRACE("(%p)\n", ppClock);
408
409     EnterCriticalSection(&This->csFilter);
410     {
411         *ppClock = This->pClock;
412         if (This->pClock)
413             IReferenceClock_AddRef(This->pClock);
414     }
415     LeaveCriticalSection(&This->csFilter);
416     
417     return S_OK;
418 }
419
420 /** IBaseFilter implementation **/
421
422 static HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
423 {
424     ENUMPINDETAILS epd;
425     ParserImpl *This = (ParserImpl *)iface;
426
427     TRACE("(%p)\n", ppEnum);
428
429     epd.cPins = This->cStreams + 1; /* +1 for input pin */
430     epd.ppPins = This->ppPins;
431     return IEnumPinsImpl_Construct(&epd, ppEnum);
432 }
433
434 static HRESULT WINAPI Parser_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
435 {
436     FIXME("(%p)->(%s,%p)\n", iface, debugstr_w(Id), ppPin);
437
438     /* FIXME: critical section */
439
440     return E_NOTIMPL;
441 }
442
443 static HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
444 {
445     ParserImpl *This = (ParserImpl *)iface;
446
447     TRACE("(%p)\n", pInfo);
448
449     strcpyW(pInfo->achName, This->filterInfo.achName);
450     pInfo->pGraph = This->filterInfo.pGraph;
451
452     if (pInfo->pGraph)
453         IFilterGraph_AddRef(pInfo->pGraph);
454     
455     return S_OK;
456 }
457
458 static HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
459 {
460     HRESULT hr = S_OK;
461     ParserImpl *This = (ParserImpl *)iface;
462
463     TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
464
465     EnterCriticalSection(&This->csFilter);
466     {
467         if (pName)
468             strcpyW(This->filterInfo.achName, pName);
469         else
470             *This->filterInfo.achName = '\0';
471         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
472     }
473     LeaveCriticalSection(&This->csFilter);
474
475     return hr;
476 }
477
478 static HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
479 {
480     TRACE("(%p)\n", pVendorInfo);
481     return E_NOTIMPL;
482 }
483
484 static const IBaseFilterVtbl Parser_Vtbl =
485 {
486     Parser_QueryInterface,
487     Parser_AddRef,
488     Parser_Release,
489     Parser_GetClassID,
490     Parser_Stop,
491     Parser_Pause,
492     Parser_Run,
493     Parser_GetState,
494     Parser_SetSyncSource,
495     Parser_GetSyncSource,
496     Parser_EnumPins,
497     Parser_FindPin,
498     Parser_QueryFilterInfo,
499     Parser_JoinFilterGraph,
500     Parser_QueryVendorInfo
501 };
502
503 HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt)
504 {
505     IPin ** ppOldPins;
506     HRESULT hr;
507
508     ppOldPins = This->ppPins;
509
510     This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *));
511     memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *));
512
513     hr = Parser_OutputPin_Construct(piOutput, props, NULL, Parser_OutputPin_QueryAccept, amt, &This->csFilter, This->ppPins + This->cStreams + 1);
514
515     if (SUCCEEDED(hr))
516     {
517         ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->pin.pin.pUserData = (LPVOID)This->ppPins[This->cStreams + 1];
518         This->cStreams++;
519         CoTaskMemFree(ppOldPins);
520     }
521     else
522     {
523         CoTaskMemFree(This->ppPins);
524         This->ppPins = ppOldPins;
525         ERR("Failed with error %x\n", hr);
526     }
527
528     return hr;
529 }
530
531 static HRESULT Parser_RemoveOutputPins(ParserImpl * This)
532 {
533     /* NOTE: should be in critical section when calling this function */
534
535     ULONG i;
536     IPin ** ppOldPins = This->ppPins;
537
538     /* reduce the pin array down to 1 (just our input pin) */
539     This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1);
540     memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1);
541
542     for (i = 0; i < This->cStreams; i++)
543     {
544         OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]);
545         IPin_Release(ppOldPins[i + 1]);
546     }
547
548     This->cStreams = 0;
549     CoTaskMemFree(ppOldPins);
550
551     return S_OK;
552 }
553
554 static HRESULT Parser_ChangeStart(IBaseFilter *iface)
555 {
556     FIXME("(%p)\n", iface);
557     return S_OK;
558 }
559
560 static HRESULT Parser_ChangeStop(IBaseFilter *iface)
561 {
562     FIXME("(%p)\n", iface);
563     return S_OK;
564 }
565
566 static HRESULT Parser_ChangeRate(IBaseFilter *iface)
567 {
568     FIXME("(%p)\n", iface);
569     return S_OK;
570 }
571
572
573 static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
574 {
575     ParserImpl *This = impl_from_IMediaSeeking(iface);
576
577     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
578 }
579
580 static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface)
581 {
582     ParserImpl *This = impl_from_IMediaSeeking(iface);
583
584     return IUnknown_AddRef((IUnknown *)This);
585 }
586
587 static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface)
588 {
589     ParserImpl *This = impl_from_IMediaSeeking(iface);
590
591     return IUnknown_Release((IUnknown *)This);
592 }
593
594 static const IMediaSeekingVtbl Parser_Seeking_Vtbl =
595 {
596     Parser_Seeking_QueryInterface,
597     Parser_Seeking_AddRef,
598     Parser_Seeking_Release,
599     MediaSeekingImpl_GetCapabilities,
600     MediaSeekingImpl_CheckCapabilities,
601     MediaSeekingImpl_IsFormatSupported,
602     MediaSeekingImpl_QueryPreferredFormat,
603     MediaSeekingImpl_GetTimeFormat,
604     MediaSeekingImpl_IsUsingTimeFormat,
605     MediaSeekingImpl_SetTimeFormat,
606     MediaSeekingImpl_GetDuration,
607     MediaSeekingImpl_GetStopPosition,
608     MediaSeekingImpl_GetCurrentPosition,
609     MediaSeekingImpl_ConvertTimeFormat,
610     MediaSeekingImpl_SetPositions,
611     MediaSeekingImpl_GetPositions,
612     MediaSeekingImpl_GetAvailable,
613     MediaSeekingImpl_SetRate,
614     MediaSeekingImpl_GetRate,
615     MediaSeekingImpl_GetPreroll
616 };
617
618 static HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
619 {
620     Parser_OutputPin *This = (Parser_OutputPin *)iface;
621
622     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
623
624     *ppv = NULL;
625
626     if (IsEqualIID(riid, &IID_IUnknown))
627         *ppv = (LPVOID)iface;
628     else if (IsEqualIID(riid, &IID_IPin))
629         *ppv = (LPVOID)iface;
630     else if (IsEqualIID(riid, &IID_IMediaSeeking))
631     {
632         return IBaseFilter_QueryInterface(This->pin.pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
633     }
634
635     if (*ppv)
636     {
637         IUnknown_AddRef((IUnknown *)(*ppv));
638         return S_OK;
639     }
640
641     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
642
643     return E_NOINTERFACE;
644 }
645
646 static ULONG WINAPI Parser_OutputPin_Release(IPin * iface)
647 {
648     Parser_OutputPin *This = (Parser_OutputPin *)iface;
649     ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
650     
651     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
652     
653     if (!refCount)
654     {
655         FreeMediaType(This->pmt);
656         CoTaskMemFree(This->pmt);
657         FreeMediaType(&This->pin.pin.mtCurrent);
658         CoTaskMemFree(This);
659         return 0;
660     }
661     return refCount;
662 }
663
664 static HRESULT WINAPI Parser_OutputPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
665 {
666     ENUMMEDIADETAILS emd;
667     Parser_OutputPin *This = (Parser_OutputPin *)iface;
668
669     TRACE("(%p)\n", ppEnum);
670
671     /* override this method to allow enumeration of your types */
672     emd.cMediaTypes = 1;
673     emd.pMediaTypes = This->pmt;
674
675     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
676 }
677
678 static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
679 {
680     Parser_OutputPin *This = (Parser_OutputPin *)iface;
681
682     TRACE("()\n");
683     dump_AM_MEDIA_TYPE(pmt);
684
685     return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0);
686 }
687
688 static const IPinVtbl Parser_OutputPin_Vtbl = 
689 {
690     Parser_OutputPin_QueryInterface,
691     IPinImpl_AddRef,
692     Parser_OutputPin_Release,
693     OutputPin_Connect,
694     OutputPin_ReceiveConnection,
695     OutputPin_Disconnect,
696     IPinImpl_ConnectedTo,
697     IPinImpl_ConnectionMediaType,
698     IPinImpl_QueryPinInfo,
699     IPinImpl_QueryDirection,
700     IPinImpl_QueryId,
701     IPinImpl_QueryAccept,
702     Parser_OutputPin_EnumMediaTypes,
703     IPinImpl_QueryInternalConnections,
704     OutputPin_EndOfStream,
705     OutputPin_BeginFlush,
706     OutputPin_EndFlush,
707     OutputPin_NewSegment
708 };
709
710 static HRESULT Parser_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
711 {
712     PullPin * pPinImpl;
713
714     *ppPin = NULL;
715
716     if (pPinInfo->dir != PINDIR_INPUT)
717     {
718         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
719         return E_INVALIDARG;
720     }
721
722     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
723
724     if (!pPinImpl)
725         return E_OUTOFMEMORY;
726
727     if (SUCCEEDED(PullPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
728     {
729         pPinImpl->pin.lpVtbl = &Parser_InputPin_Vtbl;
730
731         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
732         return S_OK;
733     }
734
735     CoTaskMemFree(pPinImpl);
736     return E_FAIL;
737 }
738
739 static HRESULT WINAPI Parser_InputPin_Disconnect(IPin * iface)
740 {
741     HRESULT hr;
742     IPinImpl *This = (IPinImpl *)iface;
743
744     TRACE("()\n");
745
746     EnterCriticalSection(This->pCritSec);
747     {
748         if (This->pConnectedTo)
749         {
750             FILTER_STATE state;
751
752             hr = IBaseFilter_GetState(This->pinInfo.pFilter, 0, &state);
753
754             if (SUCCEEDED(hr) && (state == State_Stopped))
755             {
756                 IPin_Release(This->pConnectedTo);
757                 This->pConnectedTo = NULL;
758                 hr = Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
759             }
760             else
761                 hr = VFW_E_NOT_STOPPED;
762         }
763         else
764             hr = S_FALSE;
765     }
766     LeaveCriticalSection(This->pCritSec);
767     
768     return hr;
769 }
770
771 HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
772 {
773     HRESULT hr;
774
775     TRACE("()\n");
776
777     hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt);
778     if (FAILED(hr))
779     {
780         IPinImpl *This = (IPinImpl *)iface;
781
782         EnterCriticalSection(This->pCritSec);
783         Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
784         LeaveCriticalSection(This->pCritSec);
785     }
786
787     return hr;
788 }
789
790 static const IPinVtbl Parser_InputPin_Vtbl =
791 {
792     PullPin_QueryInterface,
793     IPinImpl_AddRef,
794     PullPin_Release,
795     OutputPin_Connect,
796     Parser_PullPin_ReceiveConnection,
797     Parser_InputPin_Disconnect,
798     IPinImpl_ConnectedTo,
799     IPinImpl_ConnectionMediaType,
800     IPinImpl_QueryPinInfo,
801     IPinImpl_QueryDirection,
802     IPinImpl_QueryId,
803     IPinImpl_QueryAccept,
804     IPinImpl_EnumMediaTypes,
805     IPinImpl_QueryInternalConnections,
806     PullPin_EndOfStream,
807     PullPin_BeginFlush,
808     PullPin_EndFlush,
809     PullPin_NewSegment
810 };