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