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