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