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