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