Fixed clock release in transform template.
[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 struct IBaseFilterVtbl Parser_Vtbl;
46 static const struct IMediaSeekingVtbl Parser_Seeking_Vtbl;
47 static const struct IPinVtbl Parser_OutputPin_Vtbl;
48 static const struct 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         hr = PullPin_StopProcessing(This->pInputPin);
227         This->state = State_Stopped;
228     }
229     LeaveCriticalSection(&This->csFilter);
230     
231     return hr;
232 }
233
234 static HRESULT WINAPI Parser_Pause(IBaseFilter * iface)
235 {
236     HRESULT hr = S_OK;
237     BOOL bInit;
238     ParserImpl *This = (ParserImpl *)iface;
239     
240     TRACE("()\n");
241
242     EnterCriticalSection(&This->csFilter);
243     {
244         bInit = (This->state == State_Stopped);
245         This->state = State_Paused;
246     }
247     LeaveCriticalSection(&This->csFilter);
248
249     if (bInit)
250     {
251         unsigned int i;
252
253         /*hr = PullPin_Seek(This->pInputPin, This->CurrentChunkOffset, This->EndOfFile); */
254
255         if (SUCCEEDED(hr))
256             hr = PullPin_InitProcessing(This->pInputPin);
257
258         if (SUCCEEDED(hr))
259         {
260             for (i = 1; i < This->cStreams + 1; i++)
261             {
262                 Parser_OutputPin* StreamPin = (Parser_OutputPin *)This->ppPins[i];
263                 OutputPin_DeliverNewSegment((OutputPin *)This->ppPins[i], 0, (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec), 1.0);
264                 StreamPin->mediaSeeking.llDuration = (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec);
265                 StreamPin->mediaSeeking.llStop = (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec);
266                 OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
267             }
268
269             /* FIXME: this is a little hacky: we have to deliver (at least?) one sample
270              * to each renderer before they will complete their transitions. We should probably
271              * seek through the stream for the first of each, rather than do it this way which is
272              * probably a bit prone to deadlocking */
273             hr = PullPin_StartProcessing(This->pInputPin);
274         }
275     }
276     /* FIXME: else pause thread */
277
278     return hr;
279 }
280
281 static HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
282 {
283     HRESULT hr = S_OK;
284     ParserImpl *This = (ParserImpl *)iface;
285     int i;
286
287     TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
288
289     EnterCriticalSection(&This->csFilter);
290     {
291         This->rtStreamStart = tStart;
292         This->state = State_Running;
293
294         hr = PullPin_InitProcessing(This->pInputPin);
295
296         if (SUCCEEDED(hr))
297         { 
298             for (i = 1; i < This->cStreams + 1; i++)
299             {
300                 OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
301             }
302             hr = PullPin_StartProcessing(This->pInputPin);
303         }
304     }
305     LeaveCriticalSection(&This->csFilter);
306
307     return hr;
308 }
309
310 static HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
311 {
312     ParserImpl *This = (ParserImpl *)iface;
313
314     TRACE("(%ld, %p)\n", dwMilliSecsTimeout, pState);
315
316     EnterCriticalSection(&This->csFilter);
317     {
318         *pState = This->state;
319     }
320     LeaveCriticalSection(&This->csFilter);
321
322     /* FIXME: this is a little bit unsafe, but I don't see that we can do this
323      * while in the critical section. Maybe we could copy the pointer and addref in the
324      * critical section and then release after this.
325      */
326     if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE))
327         return VFW_S_STATE_INTERMEDIATE;
328
329     return S_OK;
330 }
331
332 static HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
333 {
334     ParserImpl *This = (ParserImpl *)iface;
335
336     TRACE("(%p)\n", pClock);
337
338     EnterCriticalSection(&This->csFilter);
339     {
340         if (This->pClock)
341             IReferenceClock_Release(This->pClock);
342         This->pClock = pClock;
343         if (This->pClock)
344             IReferenceClock_AddRef(This->pClock);
345     }
346     LeaveCriticalSection(&This->csFilter);
347
348     return S_OK;
349 }
350
351 static HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
352 {
353     ParserImpl *This = (ParserImpl *)iface;
354
355     TRACE("(%p)\n", ppClock);
356
357     EnterCriticalSection(&This->csFilter);
358     {
359         *ppClock = This->pClock;
360         if (This->pClock)
361             IReferenceClock_AddRef(This->pClock);
362     }
363     LeaveCriticalSection(&This->csFilter);
364     
365     return S_OK;
366 }
367
368 /** IBaseFilter implementation **/
369
370 static HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
371 {
372     ENUMPINDETAILS epd;
373     ParserImpl *This = (ParserImpl *)iface;
374
375     TRACE("(%p)\n", ppEnum);
376
377     epd.cPins = This->cStreams + 1; /* +1 for input pin */
378     epd.ppPins = This->ppPins;
379     return IEnumPinsImpl_Construct(&epd, ppEnum);
380 }
381
382 static HRESULT WINAPI Parser_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
383 {
384     FIXME("(%p)->(%s,%p)\n", iface, debugstr_w(Id), ppPin);
385
386     /* FIXME: critical section */
387
388     return E_NOTIMPL;
389 }
390
391 static HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
392 {
393     ParserImpl *This = (ParserImpl *)iface;
394
395     TRACE("(%p)\n", pInfo);
396
397     strcpyW(pInfo->achName, This->filterInfo.achName);
398     pInfo->pGraph = This->filterInfo.pGraph;
399
400     if (pInfo->pGraph)
401         IFilterGraph_AddRef(pInfo->pGraph);
402     
403     return S_OK;
404 }
405
406 static HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
407 {
408     HRESULT hr = S_OK;
409     ParserImpl *This = (ParserImpl *)iface;
410
411     TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
412
413     EnterCriticalSection(&This->csFilter);
414     {
415         if (pName)
416             strcpyW(This->filterInfo.achName, pName);
417         else
418             *This->filterInfo.achName = '\0';
419         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
420     }
421     LeaveCriticalSection(&This->csFilter);
422
423     return hr;
424 }
425
426 static HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
427 {
428     TRACE("(%p)\n", pVendorInfo);
429     return E_NOTIMPL;
430 }
431
432 static const IBaseFilterVtbl Parser_Vtbl =
433 {
434     Parser_QueryInterface,
435     Parser_AddRef,
436     Parser_Release,
437     Parser_GetClassID,
438     Parser_Stop,
439     Parser_Pause,
440     Parser_Run,
441     Parser_GetState,
442     Parser_SetSyncSource,
443     Parser_GetSyncSource,
444     Parser_EnumPins,
445     Parser_FindPin,
446     Parser_QueryFilterInfo,
447     Parser_JoinFilterGraph,
448     Parser_QueryVendorInfo
449 };
450
451 HRESULT Parser_AddPin(ParserImpl * This, PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, AM_MEDIA_TYPE * amt, float fSamplesPerSec, DWORD dwSampleSize, DWORD dwLength)
452 {
453     IPin ** ppOldPins;
454     HRESULT hr;
455
456     ppOldPins = This->ppPins;
457
458     This->ppPins = HeapAlloc(GetProcessHeap(), 0, (This->cStreams + 2) * sizeof(IPin *));
459     memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *));
460
461     hr = Parser_OutputPin_Construct(piOutput, props, NULL, Parser_OutputPin_QueryAccept, amt, fSamplesPerSec, &This->csFilter, This->ppPins + This->cStreams + 1);
462
463     if (SUCCEEDED(hr))
464     {
465         ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->dwSampleSize = dwSampleSize;
466         ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->dwLength = dwLength;
467         ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->pin.pin.pUserData = (LPVOID)This->ppPins[This->cStreams + 1];
468         This->cStreams++;
469         HeapFree(GetProcessHeap(), 0, ppOldPins);
470     }
471     else
472     {
473         HeapFree(GetProcessHeap(), 0, This->ppPins);
474         This->ppPins = ppOldPins;
475         ERR("Failed with error %lx\n", hr);
476     }
477
478     return hr;
479 }
480
481 static HRESULT Parser_RemoveOutputPins(ParserImpl * This)
482 {
483     /* NOTE: should be in critical section when calling this function */
484
485     ULONG i;
486     IPin ** ppOldPins = This->ppPins;
487
488     /* reduce the pin array down to 1 (just our input pin) */
489     This->ppPins = HeapAlloc(GetProcessHeap(), 0, sizeof(IPin *) * 1);
490     memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1);
491
492     for (i = 0; i < This->cStreams; i++)
493     {
494         OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]);
495         IPin_Release(ppOldPins[i + 1]);
496     }
497
498     This->cStreams = 0;
499     HeapFree(GetProcessHeap(), 0, ppOldPins);
500
501     return S_OK;
502 }
503
504 static HRESULT Parser_ChangeStart(LPVOID iface)
505 {
506     FIXME("(%p)\n", iface);
507     return S_OK;
508 }
509
510 static HRESULT Parser_ChangeStop(LPVOID iface)
511 {
512     FIXME("(%p)\n", iface);
513     return S_OK;
514 }
515
516 static HRESULT Parser_ChangeRate(LPVOID iface)
517 {
518     FIXME("(%p)\n", iface);
519     return S_OK;
520 }
521
522
523 static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
524 {
525     ICOM_THIS_From_IMediaSeeking(Parser_OutputPin, iface);
526
527     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
528 }
529
530 static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface)
531 {
532     ICOM_THIS_From_IMediaSeeking(Parser_OutputPin, iface);
533
534     return IUnknown_AddRef((IUnknown *)This);
535 }
536
537 static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface)
538 {
539     ICOM_THIS_From_IMediaSeeking(Parser_OutputPin, iface);
540
541     return IUnknown_Release((IUnknown *)This);
542 }
543
544 static const IMediaSeekingVtbl Parser_Seeking_Vtbl =
545 {
546     Parser_Seeking_QueryInterface,
547     Parser_Seeking_AddRef,
548     Parser_Seeking_Release,
549     MediaSeekingImpl_GetCapabilities,
550     MediaSeekingImpl_CheckCapabilities,
551     MediaSeekingImpl_IsFormatSupported,
552     MediaSeekingImpl_QueryPreferredFormat,
553     MediaSeekingImpl_GetTimeFormat,
554     MediaSeekingImpl_IsUsingTimeFormat,
555     MediaSeekingImpl_SetTimeFormat,
556     MediaSeekingImpl_GetDuration,
557     MediaSeekingImpl_GetStopPosition,
558     MediaSeekingImpl_GetCurrentPosition,
559     MediaSeekingImpl_ConvertTimeFormat,
560     MediaSeekingImpl_SetPositions,
561     MediaSeekingImpl_GetPositions,
562     MediaSeekingImpl_GetAvailable,
563     MediaSeekingImpl_SetRate,
564     MediaSeekingImpl_GetRate,
565     MediaSeekingImpl_GetPreroll
566 };
567
568 HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
569 {
570     Parser_OutputPin *This = (Parser_OutputPin *)iface;
571
572     TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
573
574     *ppv = NULL;
575
576     if (IsEqualIID(riid, &IID_IUnknown))
577         *ppv = (LPVOID)iface;
578     else if (IsEqualIID(riid, &IID_IPin))
579         *ppv = (LPVOID)iface;
580     else if (IsEqualIID(riid, &IID_IMediaSeeking))
581         *ppv = (LPVOID)&This->mediaSeeking;
582
583     if (*ppv)
584     {
585         IUnknown_AddRef((IUnknown *)(*ppv));
586         return S_OK;
587     }
588
589     FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
590
591     return E_NOINTERFACE;
592 }
593
594 static ULONG WINAPI Parser_OutputPin_Release(IPin * iface)
595 {
596     Parser_OutputPin *This = (Parser_OutputPin *)iface;
597     ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
598     
599     TRACE("(%p)->() Release from %ld\n", iface, refCount + 1);
600     
601     if (!refCount)
602     {
603         FreeMediaType(This->pmt);
604         CoTaskMemFree(This->pmt);
605         FreeMediaType(&This->pin.pin.mtCurrent);
606         CoTaskMemFree(This);
607         return 0;
608     }
609     return refCount;
610 }
611
612 static HRESULT WINAPI Parser_OutputPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
613 {
614     ENUMMEDIADETAILS emd;
615     Parser_OutputPin *This = (Parser_OutputPin *)iface;
616
617     TRACE("(%p)\n", ppEnum);
618
619     /* override this method to allow enumeration of your types */
620     emd.cMediaTypes = 1;
621     emd.pMediaTypes = This->pmt;
622
623     return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
624 }
625
626 static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
627 {
628     Parser_OutputPin *This = (Parser_OutputPin *)iface;
629
630     TRACE("()\n");
631     dump_AM_MEDIA_TYPE(pmt);
632
633     return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0);
634 }
635
636 static const IPinVtbl Parser_OutputPin_Vtbl = 
637 {
638     Parser_OutputPin_QueryInterface,
639     IPinImpl_AddRef,
640     Parser_OutputPin_Release,
641     OutputPin_Connect,
642     OutputPin_ReceiveConnection,
643     OutputPin_Disconnect,
644     IPinImpl_ConnectedTo,
645     IPinImpl_ConnectionMediaType,
646     IPinImpl_QueryPinInfo,
647     IPinImpl_QueryDirection,
648     IPinImpl_QueryId,
649     IPinImpl_QueryAccept,
650     Parser_OutputPin_EnumMediaTypes,
651     IPinImpl_QueryInternalConnections,
652     OutputPin_EndOfStream,
653     OutputPin_BeginFlush,
654     OutputPin_EndFlush,
655     OutputPin_NewSegment
656 };
657
658 static HRESULT Parser_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
659 {
660     PullPin * pPinImpl;
661
662     *ppPin = NULL;
663
664     if (pPinInfo->dir != PINDIR_INPUT)
665     {
666         ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
667         return E_INVALIDARG;
668     }
669
670     pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
671
672     if (!pPinImpl)
673         return E_OUTOFMEMORY;
674
675     if (SUCCEEDED(PullPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
676     {
677         pPinImpl->pin.lpVtbl = &Parser_InputPin_Vtbl;
678         
679         *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
680         return S_OK;
681     }
682     return E_FAIL;
683 }
684
685 static HRESULT WINAPI Parser_InputPin_Disconnect(IPin * iface)
686 {
687     HRESULT hr;
688     IPinImpl *This = (IPinImpl *)iface;
689
690     TRACE("()\n");
691
692     EnterCriticalSection(This->pCritSec);
693     {
694         if (This->pConnectedTo)
695         {
696             FILTER_STATE state;
697
698             hr = IBaseFilter_GetState(This->pinInfo.pFilter, 0, &state);
699
700             if (SUCCEEDED(hr) && (state == State_Stopped))
701             {
702                 IPin_Release(This->pConnectedTo);
703                 This->pConnectedTo = NULL;
704                 hr = Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
705             }
706             else
707                 hr = VFW_E_NOT_STOPPED;
708         }
709         else
710             hr = S_FALSE;
711     }
712     LeaveCriticalSection(This->pCritSec);
713     
714     return hr;
715 }
716
717 static const IPinVtbl Parser_InputPin_Vtbl =
718 {
719     PullPin_QueryInterface,
720     IPinImpl_AddRef,
721     PullPin_Release,
722     OutputPin_Connect,
723     PullPin_ReceiveConnection,
724     Parser_InputPin_Disconnect,
725     IPinImpl_ConnectedTo,
726     IPinImpl_ConnectionMediaType,
727     IPinImpl_QueryPinInfo,
728     IPinImpl_QueryDirection,
729     IPinImpl_QueryId,
730     IPinImpl_QueryAccept,
731     IPinImpl_EnumMediaTypes,
732     IPinImpl_QueryInternalConnections,
733     PullPin_EndOfStream,
734     PullPin_BeginFlush,
735     PullPin_EndFlush,
736     PullPin_NewSegment
737 };