strmbase: Move BasePin implementation to strmbase.
[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 IMediaSeekingVtbl Parser_Seeking_Vtbl;
41 static const IPinVtbl Parser_OutputPin_Vtbl;
42 static const IPinVtbl Parser_InputPin_Vtbl;
43
44 static HRESULT Parser_ChangeCurrent(IBaseFilter *iface);
45 static HRESULT Parser_ChangeStop(IBaseFilter *iface);
46 static HRESULT Parser_ChangeRate(IBaseFilter *iface);
47
48 static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
49 {
50     return (ParserImpl *)((char*)iface - FIELD_OFFSET(ParserImpl, mediaSeeking.lpVtbl));
51 }
52
53
54 HRESULT Parser_Create(ParserImpl* pParser, const IBaseFilterVtbl *Parser_Vtbl, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest, STOPPROCESSPROC fnDone, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate)
55 {
56     HRESULT hr;
57     PIN_INFO piInput;
58
59     /* pTransformFilter is already allocated */
60     pParser->clsid = *pClsid;
61     pParser->lpVtbl = Parser_Vtbl;
62     pParser->refCount = 1;
63     InitializeCriticalSection(&pParser->csFilter);
64     pParser->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ParserImpl.csFilter");
65     pParser->state = State_Stopped;
66     pParser->pClock = NULL;
67     pParser->fnDisconnect = fnDisconnect;
68     ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO));
69     pParser->lastpinchange = GetTickCount();
70
71     pParser->cStreams = 0;
72     pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
73
74     /* construct input pin */
75     piInput.dir = PINDIR_INPUT;
76     piInput.pFilter = (IBaseFilter *)pParser;
77     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
78
79     if (!current)
80         current = Parser_ChangeCurrent;
81
82     if (!stop)
83         stop = Parser_ChangeStop;
84
85     if (!rate)
86         rate = Parser_ChangeRate;
87
88     MediaSeekingImpl_Init((IBaseFilter*)pParser, stop, current, rate, &pParser->mediaSeeking, &pParser->csFilter);
89     pParser->mediaSeeking.lpVtbl = &Parser_Seeking_Vtbl;
90
91     hr = PullPin_Construct(&Parser_InputPin_Vtbl, &piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, fnCleanup, fnRequest, fnDone, &pParser->csFilter, (IPin **)&pParser->pInputPin);
92
93     if (SUCCEEDED(hr))
94     {
95         pParser->ppPins[0] = (IPin *)pParser->pInputPin;
96         pParser->pInputPin->fnPreConnect = fnPreConnect;
97     }
98     else
99     {
100         CoTaskMemFree(pParser->ppPins);
101         pParser->csFilter.DebugInfo->Spare[0] = 0;
102         DeleteCriticalSection(&pParser->csFilter);
103         CoTaskMemFree(pParser);
104     }
105
106     return hr;
107 }
108
109 HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
110 {
111     ParserImpl *This = (ParserImpl *)iface;
112     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
113
114     *ppv = NULL;
115
116     if ( IsEqualIID(riid, &IID_IUnknown)
117       || IsEqualIID(riid, &IID_IPersist)
118       || IsEqualIID(riid, &IID_IMediaFilter)
119       || IsEqualIID(riid, &IID_IBaseFilter) )
120         *ppv = This;
121
122     if (*ppv)
123     {
124         IUnknown_AddRef((IUnknown *)(*ppv));
125         return S_OK;
126     }
127
128     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
129         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
130
131     return E_NOINTERFACE;
132 }
133
134 ULONG WINAPI Parser_AddRef(IBaseFilter * iface)
135 {
136     ParserImpl *This = (ParserImpl *)iface;
137     ULONG refCount = InterlockedIncrement(&This->refCount);
138
139     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
140
141     return refCount;
142 }
143
144 void Parser_Destroy(ParserImpl *This)
145 {
146     IPin *connected = NULL;
147     ULONG pinref;
148
149     assert(!This->refCount);
150     PullPin_WaitForStateChange(This->pInputPin, INFINITE);
151
152     if (This->pClock)
153         IReferenceClock_Release(This->pClock);
154
155     /* Don't need to clean up output pins, freeing input pin will do that */
156     IPin_ConnectedTo((IPin *)This->pInputPin, &connected);
157     if (connected)
158     {
159         assert(IPin_Disconnect(connected) == S_OK);
160         IPin_Release(connected);
161         assert(IPin_Disconnect((IPin *)This->pInputPin) == S_OK);
162     }
163     pinref = IPin_Release((IPin *)This->pInputPin);
164     if (pinref)
165     {
166         /* Valgrind could find this, if I kill it here */
167         ERR("pinref should be null, is %u, destroying anyway\n", pinref);
168         assert((LONG)pinref > 0);
169
170         while (pinref)
171             pinref = IPin_Release((IPin *)This->pInputPin);
172     }
173
174     CoTaskMemFree(This->ppPins);
175     This->lpVtbl = NULL;
176
177     This->csFilter.DebugInfo->Spare[0] = 0;
178     DeleteCriticalSection(&This->csFilter);
179
180     TRACE("Destroying parser\n");
181     CoTaskMemFree(This);
182 }
183
184 ULONG WINAPI Parser_Release(IBaseFilter * iface)
185 {
186     ParserImpl *This = (ParserImpl *)iface;
187     ULONG refCount = InterlockedDecrement(&This->refCount);
188
189     TRACE("(%p)->() Release from %d\n", This, refCount + 1);
190
191     if (!refCount)
192         Parser_Destroy(This);
193
194     return refCount;
195 }
196
197 /** IPersist methods **/
198
199 HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid)
200 {
201     ParserImpl *This = (ParserImpl *)iface;
202
203     TRACE("(%p)\n", pClsid);
204
205     *pClsid = This->clsid;
206
207     return S_OK;
208 }
209
210 /** IMediaFilter methods **/
211
212 HRESULT WINAPI Parser_Stop(IBaseFilter * iface)
213 {
214     ParserImpl *This = (ParserImpl *)iface;
215     PullPin *pin = (PullPin *)This->ppPins[0];
216     ULONG i;
217
218     TRACE("()\n");
219
220     EnterCriticalSection(&pin->thread_lock);
221
222     IAsyncReader_BeginFlush(This->pInputPin->pReader);
223     EnterCriticalSection(&This->csFilter);
224
225     if (This->state == State_Stopped)
226     {
227         LeaveCriticalSection(&This->csFilter);
228         IAsyncReader_EndFlush(This->pInputPin->pReader);
229         LeaveCriticalSection(&pin->thread_lock);
230         return S_OK;
231     }
232
233     This->state = State_Stopped;
234
235     for (i = 1; i < (This->cStreams + 1); i++)
236     {
237         OutputPin_DecommitAllocator((OutputPin *)This->ppPins[i]);
238     }
239
240     LeaveCriticalSection(&This->csFilter);
241
242     PullPin_PauseProcessing(This->pInputPin);
243     PullPin_WaitForStateChange(This->pInputPin, INFINITE);
244     IAsyncReader_EndFlush(This->pInputPin->pReader);
245
246     LeaveCriticalSection(&pin->thread_lock);
247     return S_OK;
248 }
249
250 HRESULT WINAPI Parser_Pause(IBaseFilter * iface)
251 {
252     HRESULT hr = S_OK;
253     ParserImpl *This = (ParserImpl *)iface;
254     PullPin *pin = (PullPin *)This->ppPins[0];
255
256     TRACE("()\n");
257
258     EnterCriticalSection(&pin->thread_lock);
259     EnterCriticalSection(&This->csFilter);
260
261     if (This->state == State_Paused)
262     {
263         LeaveCriticalSection(&This->csFilter);
264         LeaveCriticalSection(&pin->thread_lock);
265         return S_OK;
266     }
267
268     if (This->state == State_Stopped)
269     {
270         LeaveCriticalSection(&This->csFilter);
271         hr = IBaseFilter_Run(iface, -1);
272         EnterCriticalSection(&This->csFilter);
273     }
274
275     if (SUCCEEDED(hr))
276         This->state = State_Paused;
277
278     LeaveCriticalSection(&This->csFilter);
279     LeaveCriticalSection(&pin->thread_lock);
280
281     return hr;
282 }
283
284 HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
285 {
286     HRESULT hr = S_OK;
287     ParserImpl *This = (ParserImpl *)iface;
288     PullPin *pin = (PullPin *)This->ppPins[0];
289
290     ULONG i;
291
292     TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
293
294     EnterCriticalSection(&pin->thread_lock);
295     EnterCriticalSection(&This->csFilter);
296     {
297         HRESULT hr_any = VFW_E_NOT_CONNECTED;
298
299         if (This->state == State_Running || This->state == State_Paused)
300         {
301             This->state = State_Running;
302             LeaveCriticalSection(&This->csFilter);
303             LeaveCriticalSection(&pin->thread_lock);
304             return S_OK;
305         }
306
307         This->rtStreamStart = tStart;
308
309         for (i = 1; i < (This->cStreams + 1); i++)
310         {
311             hr = OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
312             if (SUCCEEDED(hr))
313                 hr_any = hr;
314         }
315
316         hr = hr_any;
317         if (SUCCEEDED(hr))
318         {
319             LeaveCriticalSection(&This->csFilter);
320             hr = PullPin_StartProcessing(This->pInputPin);
321             EnterCriticalSection(&This->csFilter);
322         }
323
324         if (SUCCEEDED(hr))
325             This->state = State_Running;
326     }
327     LeaveCriticalSection(&This->csFilter);
328     LeaveCriticalSection(&pin->thread_lock);
329
330     return hr;
331 }
332
333 HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
334 {
335     ParserImpl *This = (ParserImpl *)iface;
336     PullPin *pin = (PullPin *)This->ppPins[0];
337     HRESULT hr = S_OK;
338
339     TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState);
340
341     EnterCriticalSection(&pin->thread_lock);
342     EnterCriticalSection(&This->csFilter);
343     {
344         *pState = This->state;
345     }
346     LeaveCriticalSection(&This->csFilter);
347
348     if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE))
349         hr = VFW_S_STATE_INTERMEDIATE;
350     LeaveCriticalSection(&pin->thread_lock);
351
352     return hr;
353 }
354
355 HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
356 {
357     ParserImpl *This = (ParserImpl *)iface;
358     PullPin *pin = (PullPin *)This->ppPins[0];
359
360     TRACE("(%p)\n", pClock);
361
362     EnterCriticalSection(&pin->thread_lock);
363     EnterCriticalSection(&This->csFilter);
364     {
365         if (This->pClock)
366             IReferenceClock_Release(This->pClock);
367         This->pClock = pClock;
368         if (This->pClock)
369             IReferenceClock_AddRef(This->pClock);
370     }
371     LeaveCriticalSection(&This->csFilter);
372     LeaveCriticalSection(&pin->thread_lock);
373
374     return S_OK;
375 }
376
377 HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
378 {
379     ParserImpl *This = (ParserImpl *)iface;
380
381     TRACE("(%p)\n", ppClock);
382
383     EnterCriticalSection(&This->csFilter);
384     {
385         *ppClock = This->pClock;
386         if (This->pClock)
387             IReferenceClock_AddRef(This->pClock);
388     }
389     LeaveCriticalSection(&This->csFilter);
390     
391     return S_OK;
392 }
393
394 /** IBaseFilter implementation **/
395
396 /* FIXME: WRONG */
397 static IPin* WINAPI Parser_GetPin(IBaseFilter *iface, int pos)
398 {
399     ParserImpl *This = (ParserImpl *)iface;
400
401     TRACE("Asking for pos %x\n", pos);
402
403     /* Input pin also has a pin, hence the > and not >= */
404     if (pos > This->cStreams || pos < 0)
405         return NULL;
406
407     IPin_AddRef(This->ppPins[pos]);
408     return This->ppPins[pos];
409 }
410
411 static LONG WINAPI Parser_GetPinCount(IBaseFilter *iface)
412 {
413     ParserImpl *This = (ParserImpl *)iface;
414
415     return This->cStreams;
416 }
417
418 static LONG WINAPI Parser_GetPinVersion(IBaseFilter *iface)
419 {
420     ParserImpl *This = (ParserImpl *)iface;
421
422     return This->lastpinchange;
423 }
424
425 HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
426 {
427     ParserImpl *This = (ParserImpl *)iface;
428
429     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
430
431     return EnumPins_Construct(iface, Parser_GetPin, Parser_GetPinCount, Parser_GetPinVersion, ppEnum);
432 }
433
434 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 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 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 HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
479 {
480     TRACE("(%p)\n", pVendorInfo);
481     return E_NOTIMPL;
482 }
483
484 HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt)
485 {
486     IPin ** ppOldPins;
487     HRESULT hr;
488
489     ppOldPins = This->ppPins;
490
491     This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *));
492     memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *));
493
494     hr = OutputPin_Construct(&Parser_OutputPin_Vtbl, sizeof(Parser_OutputPin), piOutput, props, &This->csFilter, This->ppPins + (This->cStreams + 1));
495
496     if (SUCCEEDED(hr))
497     {
498         IPin *pPin = This->ppPins[This->cStreams + 1];
499         Parser_OutputPin *pin = (Parser_OutputPin *)pPin;
500         pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
501         CopyMediaType(pin->pmt, amt);
502         pin->dwSamplesProcessed = 0;
503
504         pin->pin.pin.pinInfo.pFilter = (LPVOID)This;
505         pin->pin.custom_allocator = 1;
506         This->cStreams++;
507         This->lastpinchange = GetTickCount();
508         CoTaskMemFree(ppOldPins);
509     }
510     else
511     {
512         CoTaskMemFree(This->ppPins);
513         This->ppPins = ppOldPins;
514         ERR("Failed with error %x\n", hr);
515     }
516
517     return hr;
518 }
519
520 static HRESULT Parser_RemoveOutputPins(ParserImpl * This)
521 {
522     /* NOTE: should be in critical section when calling this function */
523     HRESULT hr;
524     ULONG i;
525     IPin ** ppOldPins = This->ppPins;
526
527     TRACE("(%p)\n", This);
528
529     /* reduce the pin array down to 1 (just our input pin) */
530     This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1);
531     memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1);
532
533     for (i = 0; i < This->cStreams; i++)
534     {
535         hr = OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]);
536         TRACE("Disconnect: %08x\n", hr);
537         IPin_Release(ppOldPins[i + 1]);
538     }
539
540     This->lastpinchange = GetTickCount();
541     This->cStreams = 0;
542     CoTaskMemFree(ppOldPins);
543
544     return S_OK;
545 }
546
547 static HRESULT Parser_ChangeCurrent(IBaseFilter *iface)
548 {
549     FIXME("(%p) filter hasn't implemented current position change!\n", iface);
550     return S_OK;
551 }
552
553 static HRESULT Parser_ChangeStop(IBaseFilter *iface)
554 {
555     FIXME("(%p) filter hasn't implemented stop position change!\n", iface);
556     return S_OK;
557 }
558
559 static HRESULT Parser_ChangeRate(IBaseFilter *iface)
560 {
561     FIXME("(%p) filter hasn't implemented rate change!\n", iface);
562     return S_OK;
563 }
564
565
566 static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
567 {
568     ParserImpl *This = impl_from_IMediaSeeking(iface);
569
570     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
571 }
572
573 static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface)
574 {
575     ParserImpl *This = impl_from_IMediaSeeking(iface);
576
577     return IUnknown_AddRef((IUnknown *)This);
578 }
579
580 static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface)
581 {
582     ParserImpl *This = impl_from_IMediaSeeking(iface);
583
584     return IUnknown_Release((IUnknown *)This);
585 }
586
587 static const IMediaSeekingVtbl Parser_Seeking_Vtbl =
588 {
589     Parser_Seeking_QueryInterface,
590     Parser_Seeking_AddRef,
591     Parser_Seeking_Release,
592     MediaSeekingImpl_GetCapabilities,
593     MediaSeekingImpl_CheckCapabilities,
594     MediaSeekingImpl_IsFormatSupported,
595     MediaSeekingImpl_QueryPreferredFormat,
596     MediaSeekingImpl_GetTimeFormat,
597     MediaSeekingImpl_IsUsingTimeFormat,
598     MediaSeekingImpl_SetTimeFormat,
599     MediaSeekingImpl_GetDuration,
600     MediaSeekingImpl_GetStopPosition,
601     MediaSeekingImpl_GetCurrentPosition,
602     MediaSeekingImpl_ConvertTimeFormat,
603     MediaSeekingImpl_SetPositions,
604     MediaSeekingImpl_GetPositions,
605     MediaSeekingImpl_GetAvailable,
606     MediaSeekingImpl_SetRate,
607     MediaSeekingImpl_GetRate,
608     MediaSeekingImpl_GetPreroll
609 };
610
611 static HRESULT WINAPI Parser_OutputPin_GetMediaType(IPin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
612 {
613     Parser_OutputPin *This = (Parser_OutputPin *)iface;
614     if (iPosition < 0)
615         return E_INVALIDARG;
616     if (iPosition > 0)
617         return VFW_S_NO_MORE_ITEMS;
618     CopyMediaType(pmt, This->pmt);
619     return S_OK;
620 }
621
622 static HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
623 {
624     Parser_OutputPin *This = (Parser_OutputPin *)iface;
625
626     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
627
628     *ppv = NULL;
629
630     if (IsEqualIID(riid, &IID_IUnknown))
631         *ppv = iface;
632     else if (IsEqualIID(riid, &IID_IPin))
633         *ppv = iface;
634     else if (IsEqualIID(riid, &IID_IMediaSeeking))
635     {
636         return IBaseFilter_QueryInterface(This->pin.pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
637     }
638
639     if (*ppv)
640     {
641         IUnknown_AddRef((IUnknown *)(*ppv));
642         return S_OK;
643     }
644
645     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
646
647     return E_NOINTERFACE;
648 }
649
650 static ULONG WINAPI Parser_OutputPin_Release(IPin * iface)
651 {
652     Parser_OutputPin *This = (Parser_OutputPin *)iface;
653     ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
654     
655     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
656
657     if (!refCount)
658     {
659         FreeMediaType(This->pmt);
660         CoTaskMemFree(This->pmt);
661         FreeMediaType(&This->pin.pin.mtCurrent);
662         CoTaskMemFree(This);
663         return 0;
664     }
665     return refCount;
666 }
667
668 static HRESULT WINAPI Parser_OutputPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
669 {
670     TRACE("(%p)\n", ppEnum);
671
672     /* override this method to allow enumeration of your types */
673
674     return EnumMediaTypes_Construct(iface, Parser_OutputPin_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum);
675 }
676
677 static HRESULT WINAPI Parser_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
678 {
679     Parser_OutputPin *This = (Parser_OutputPin *)iface;
680     ParserImpl *parser = (ParserImpl *)This->pin.pin.pinInfo.pFilter;
681
682     /* Set the allocator to our input pin's */
683     EnterCriticalSection(This->pin.pin.pCritSec);
684     This->pin.alloc = parser->pInputPin->pAlloc;
685     LeaveCriticalSection(This->pin.pin.pCritSec);
686
687     return OutputPin_Connect(iface, pReceivePin, pmt);
688 }
689
690 static HRESULT WINAPI Parser_OutputPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE * pmt)
691 {
692     Parser_OutputPin *This = (Parser_OutputPin *)iface;
693
694     TRACE("()\n");
695     dump_AM_MEDIA_TYPE(pmt);
696
697     return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0);
698 }
699
700 static const IPinVtbl Parser_OutputPin_Vtbl = 
701 {
702     Parser_OutputPin_QueryInterface,
703     BasePinImpl_AddRef,
704     Parser_OutputPin_Release,
705     Parser_OutputPin_Connect,
706     OutputPin_ReceiveConnection,
707     OutputPin_Disconnect,
708     BasePinImpl_ConnectedTo,
709     BasePinImpl_ConnectionMediaType,
710     BasePinImpl_QueryPinInfo,
711     BasePinImpl_QueryDirection,
712     BasePinImpl_QueryId,
713     Parser_OutputPin_QueryAccept,
714     Parser_OutputPin_EnumMediaTypes,
715     BasePinImpl_QueryInternalConnections,
716     OutputPin_EndOfStream,
717     OutputPin_BeginFlush,
718     OutputPin_EndFlush,
719     OutputPin_NewSegment
720 };
721
722 static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface)
723 {
724     HRESULT hr;
725     PullPin *This = (PullPin *)iface;
726
727     TRACE("()\n");
728
729     EnterCriticalSection(&This->thread_lock);
730     EnterCriticalSection(This->pin.pCritSec);
731     {
732         if (This->pin.pConnectedTo)
733         {
734             FILTER_STATE state;
735             ParserImpl *Parser = (ParserImpl *)This->pin.pinInfo.pFilter;
736
737             LeaveCriticalSection(This->pin.pCritSec);
738             hr = IBaseFilter_GetState(This->pin.pinInfo.pFilter, INFINITE, &state);
739             EnterCriticalSection(This->pin.pCritSec);
740
741             if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser)))
742             {
743                 LeaveCriticalSection(This->pin.pCritSec);
744                 PullPin_Disconnect(iface);
745                 EnterCriticalSection(This->pin.pCritSec);
746                 hr = Parser_RemoveOutputPins((ParserImpl *)This->pin.pinInfo.pFilter);
747             }
748             else
749                 hr = VFW_E_NOT_STOPPED;
750         }
751         else
752             hr = S_FALSE;
753     }
754     LeaveCriticalSection(This->pin.pCritSec);
755     LeaveCriticalSection(&This->thread_lock);
756
757     return hr;
758 }
759
760 static HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
761 {
762     HRESULT hr;
763
764     TRACE("()\n");
765
766     hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt);
767     if (FAILED(hr))
768     {
769         BasePin *This = (BasePin *)iface;
770
771         EnterCriticalSection(This->pCritSec);
772         Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
773         LeaveCriticalSection(This->pCritSec);
774     }
775
776     return hr;
777 }
778
779 static const IPinVtbl Parser_InputPin_Vtbl =
780 {
781     PullPin_QueryInterface,
782     BasePinImpl_AddRef,
783     PullPin_Release,
784     InputPin_Connect,
785     Parser_PullPin_ReceiveConnection,
786     Parser_PullPin_Disconnect,
787     BasePinImpl_ConnectedTo,
788     BasePinImpl_ConnectionMediaType,
789     BasePinImpl_QueryPinInfo,
790     BasePinImpl_QueryDirection,
791     BasePinImpl_QueryId,
792     PullPin_QueryAccept,
793     BasePinImpl_EnumMediaTypes,
794     BasePinImpl_QueryInternalConnections,
795     PullPin_EndOfStream,
796     PullPin_BeginFlush,
797     PullPin_EndFlush,
798     PullPin_NewSegment
799 };