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