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