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