quartz: Make wave parser and mpeg splitter zero copy by getting rid of the seperate...
[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, REQUESTPROC fnRequest, 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, fnRequest, &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         pin->pin.pin.pinInfo.pFilter = (LPVOID)This;
493         pin->pin.custom_allocator = 1;
494         This->cStreams++;
495         CoTaskMemFree(ppOldPins);
496     }
497     else
498     {
499         CoTaskMemFree(This->ppPins);
500         This->ppPins = ppOldPins;
501         ERR("Failed with error %x\n", hr);
502     }
503
504     return hr;
505 }
506
507 static HRESULT Parser_RemoveOutputPins(ParserImpl * This)
508 {
509     /* NOTE: should be in critical section when calling this function */
510
511     ULONG i;
512     IPin ** ppOldPins = This->ppPins;
513
514     /* reduce the pin array down to 1 (just our input pin) */
515     This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1);
516     memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1);
517
518     for (i = 0; i < This->cStreams; i++)
519     {
520         OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]);
521         IPin_Release(ppOldPins[i + 1]);
522     }
523
524     This->cStreams = 0;
525     CoTaskMemFree(ppOldPins);
526
527     return S_OK;
528 }
529
530 static HRESULT Parser_ChangeCurrent(IBaseFilter *iface)
531 {
532     FIXME("(%p) filter hasn't implemented current position change!\n", iface);
533     return S_OK;
534 }
535
536 static HRESULT Parser_ChangeStop(IBaseFilter *iface)
537 {
538     FIXME("(%p) filter hasn't implemented stop position change!\n", iface);
539     return S_OK;
540 }
541
542 static HRESULT Parser_ChangeRate(IBaseFilter *iface)
543 {
544     FIXME("(%p) filter hasn't implemented rate change!\n", iface);
545     return S_OK;
546 }
547
548
549 static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
550 {
551     ParserImpl *This = impl_from_IMediaSeeking(iface);
552
553     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
554 }
555
556 static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface)
557 {
558     ParserImpl *This = impl_from_IMediaSeeking(iface);
559
560     return IUnknown_AddRef((IUnknown *)This);
561 }
562
563 static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface)
564 {
565     ParserImpl *This = impl_from_IMediaSeeking(iface);
566
567     return IUnknown_Release((IUnknown *)This);
568 }
569
570 static const IMediaSeekingVtbl Parser_Seeking_Vtbl =
571 {
572     Parser_Seeking_QueryInterface,
573     Parser_Seeking_AddRef,
574     Parser_Seeking_Release,
575     MediaSeekingImpl_GetCapabilities,
576     MediaSeekingImpl_CheckCapabilities,
577     MediaSeekingImpl_IsFormatSupported,
578     MediaSeekingImpl_QueryPreferredFormat,
579     MediaSeekingImpl_GetTimeFormat,
580     MediaSeekingImpl_IsUsingTimeFormat,
581     MediaSeekingImpl_SetTimeFormat,
582     MediaSeekingImpl_GetDuration,
583     MediaSeekingImpl_GetStopPosition,
584     MediaSeekingImpl_GetCurrentPosition,
585     MediaSeekingImpl_ConvertTimeFormat,
586     MediaSeekingImpl_SetPositions,
587     MediaSeekingImpl_GetPositions,
588     MediaSeekingImpl_GetAvailable,
589     MediaSeekingImpl_SetRate,
590     MediaSeekingImpl_GetRate,
591     MediaSeekingImpl_GetPreroll
592 };
593
594 static HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
595 {
596     Parser_OutputPin *This = (Parser_OutputPin *)iface;
597
598     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
599
600     *ppv = NULL;
601
602     if (IsEqualIID(riid, &IID_IUnknown))
603         *ppv = (LPVOID)iface;
604     else if (IsEqualIID(riid, &IID_IPin))
605         *ppv = (LPVOID)iface;
606     else if (IsEqualIID(riid, &IID_IMediaSeeking))
607     {
608         return IBaseFilter_QueryInterface(This->pin.pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
609     }
610
611     if (*ppv)
612     {
613         IUnknown_AddRef((IUnknown *)(*ppv));
614         return S_OK;
615     }
616
617     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
618
619     return E_NOINTERFACE;
620 }
621
622 static ULONG WINAPI Parser_OutputPin_Release(IPin * iface)
623 {
624     Parser_OutputPin *This = (Parser_OutputPin *)iface;
625     ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
626     
627     TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
628     
629     if (!refCount)
630     {
631         FreeMediaType(This->pmt);
632         CoTaskMemFree(This->pmt);
633         FreeMediaType(&This->pin.pin.mtCurrent);
634         CoTaskMemFree(This);
635         return 0;
636     }
637     return refCount;
638 }
639
640 static HRESULT WINAPI Parser_OutputPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
641 {
642     ENUMMEDIADETAILS emd;
643     Parser_OutputPin *This = (Parser_OutputPin *)iface;
644
645     TRACE("(%p)\n", ppEnum);
646
647     /* override this method to allow enumeration of your types */
648     emd.cMediaTypes = 1;
649     emd.pMediaTypes = This->pmt;
650
651     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
652 }
653
654 static HRESULT WINAPI Parser_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
655 {
656     Parser_OutputPin *This = (Parser_OutputPin *)iface;
657     ParserImpl *parser = (ParserImpl *)This->pin.pin.pinInfo.pFilter;
658
659     /* Set the allocator to our input pin's */
660     EnterCriticalSection(This->pin.pin.pCritSec);
661     This->pin.alloc = parser->pInputPin->pAlloc;
662     LeaveCriticalSection(This->pin.pin.pCritSec);
663
664     return OutputPin_Connect(iface, pReceivePin, pmt);
665 }
666
667 static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
668 {
669     Parser_OutputPin *This = (Parser_OutputPin *)iface;
670
671     TRACE("()\n");
672     dump_AM_MEDIA_TYPE(pmt);
673
674     return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0);
675 }
676
677 static const IPinVtbl Parser_OutputPin_Vtbl = 
678 {
679     Parser_OutputPin_QueryInterface,
680     IPinImpl_AddRef,
681     Parser_OutputPin_Release,
682     Parser_OutputPin_Connect,
683     OutputPin_ReceiveConnection,
684     OutputPin_Disconnect,
685     IPinImpl_ConnectedTo,
686     IPinImpl_ConnectionMediaType,
687     IPinImpl_QueryPinInfo,
688     IPinImpl_QueryDirection,
689     IPinImpl_QueryId,
690     IPinImpl_QueryAccept,
691     Parser_OutputPin_EnumMediaTypes,
692     IPinImpl_QueryInternalConnections,
693     OutputPin_EndOfStream,
694     OutputPin_BeginFlush,
695     OutputPin_EndFlush,
696     OutputPin_NewSegment
697 };
698
699 static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface)
700 {
701     HRESULT hr;
702     IPinImpl *This = (IPinImpl *)iface;
703
704     TRACE("()\n");
705
706     EnterCriticalSection(This->pCritSec);
707     {
708         if (This->pConnectedTo)
709         {
710             PullPin *ppin = (PullPin *)This;
711             FILTER_STATE state;
712             ParserImpl *Parser = (ParserImpl *)This->pinInfo.pFilter;
713
714             hr = IBaseFilter_GetState(This->pinInfo.pFilter, 0, &state);
715
716             if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser)))
717             {
718                 IPin_Release(This->pConnectedTo);
719                 This->pConnectedTo = NULL;
720                 if (FAILED(hr = IMemAllocator_Decommit(ppin->pAlloc)))
721                     ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
722                 hr = Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
723             }
724             else
725                 hr = VFW_E_NOT_STOPPED;
726         }
727         else
728             hr = S_FALSE;
729     }
730     LeaveCriticalSection(This->pCritSec);
731     
732     return hr;
733 }
734
735 HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
736 {
737     HRESULT hr;
738
739     TRACE("()\n");
740
741     hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt);
742     if (FAILED(hr))
743     {
744         IPinImpl *This = (IPinImpl *)iface;
745
746         EnterCriticalSection(This->pCritSec);
747         Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
748         LeaveCriticalSection(This->pCritSec);
749     }
750
751     return hr;
752 }
753
754 static const IPinVtbl Parser_InputPin_Vtbl =
755 {
756     PullPin_QueryInterface,
757     IPinImpl_AddRef,
758     PullPin_Release,
759     InputPin_Connect,
760     Parser_PullPin_ReceiveConnection,
761     Parser_PullPin_Disconnect,
762     IPinImpl_ConnectedTo,
763     IPinImpl_ConnectionMediaType,
764     IPinImpl_QueryPinInfo,
765     IPinImpl_QueryDirection,
766     IPinImpl_QueryId,
767     IPinImpl_QueryAccept,
768     IPinImpl_EnumMediaTypes,
769     IPinImpl_QueryInternalConnections,
770     PullPin_EndOfStream,
771     PullPin_BeginFlush,
772     PullPin_EndFlush,
773     PullPin_NewSegment
774 };