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