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