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