ntdll: Fixed typo in previous patch, spotted by Ken Thomases.
[wine/multimedia.git] / dlls / quartz / parser.c
blobfb8c085667966302ba8e2c4566a5b53bf5dd0f67
1 /*
2 * Parser (Base for parsers and splitters)
4 * Copyright 2003 Robert Shearman
5 * Copyright 2004-2005 Christian Costa
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.
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.
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
22 #include "quartz_private.h"
23 #include "control_private.h"
24 #include "pin.h"
26 #include "uuids.h"
27 #include "aviriff.h"
28 #include "mmreg.h"
29 #include "vfwmsgs.h"
30 #include "amvideo.h"
32 #include "fourcc.h"
34 #include "wine/unicode.h"
35 #include "wine/debug.h"
37 #include <math.h>
38 #include <assert.h>
40 #include "parser.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
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;
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);
55 static HRESULT Parser_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin);
57 static inline Parser_OutputPin *impl_from_IMediaSeeking( IMediaSeeking *iface )
59 return (Parser_OutputPin *)((char*)iface - FIELD_OFFSET(Parser_OutputPin, mediaSeeking.lpVtbl));
63 HRESULT Parser_Create(ParserImpl* pParser, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect)
65 HRESULT hr;
66 PIN_INFO piInput;
68 /* pTransformFilter is already allocated */
69 pParser->clsid = *pClsid;
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 ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO));
79 pParser->cStreams = 0;
80 pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
82 /* construct input pin */
83 piInput.dir = PINDIR_INPUT;
84 piInput.pFilter = (IBaseFilter *)pParser;
85 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
87 hr = Parser_InputPin_Construct(&piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, &pParser->csFilter, (IPin **)&pParser->pInputPin);
89 if (SUCCEEDED(hr))
91 pParser->ppPins[0] = (IPin *)pParser->pInputPin;
92 pParser->pInputPin->fnPreConnect = fnPreConnect;
94 else
96 CoTaskMemFree(pParser->ppPins);
97 pParser->csFilter.DebugInfo->Spare[0] = 0;
98 DeleteCriticalSection(&pParser->csFilter);
99 CoTaskMemFree(pParser);
102 return hr;
105 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 pPinImpl->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
108 CopyMediaType(pPinImpl->pmt, pmt);
109 pPinImpl->dwSamplesProcessed = 0;
110 pPinImpl->dwSampleSize = 0;
111 pPinImpl->fSamplesPerSec = fSamplesPerSec;
113 MediaSeekingImpl_Init((LPVOID)pPinInfo->pFilter, Parser_ChangeStop, Parser_ChangeStart, Parser_ChangeRate, &pPinImpl->mediaSeeking);
114 pPinImpl->mediaSeeking.lpVtbl = &Parser_Seeking_Vtbl;
116 return OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pCritSec, &pPinImpl->pin);
119 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 Parser_OutputPin * pPinImpl;
123 *ppPin = NULL;
125 assert(pPinInfo->dir == PINDIR_OUTPUT);
127 pPinImpl = CoTaskMemAlloc(sizeof(Parser_OutputPin));
129 if (!pPinImpl)
130 return E_OUTOFMEMORY;
132 if (SUCCEEDED(Parser_OutputPin_Init(pPinInfo, props, pUserData, pQueryAccept, pmt, fSamplesPerSec, pCritSec, pPinImpl)))
134 pPinImpl->pin.pin.lpVtbl = &Parser_OutputPin_Vtbl;
136 *ppPin = (IPin *)pPinImpl;
137 return S_OK;
139 return E_FAIL;
142 static HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
144 ParserImpl *This = (ParserImpl *)iface;
145 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
147 *ppv = NULL;
149 if (IsEqualIID(riid, &IID_IUnknown))
150 *ppv = (LPVOID)This;
151 else if (IsEqualIID(riid, &IID_IPersist))
152 *ppv = (LPVOID)This;
153 else if (IsEqualIID(riid, &IID_IMediaFilter))
154 *ppv = (LPVOID)This;
155 else if (IsEqualIID(riid, &IID_IBaseFilter))
156 *ppv = (LPVOID)This;
158 if (*ppv)
160 IUnknown_AddRef((IUnknown *)(*ppv));
161 return S_OK;
164 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
166 return E_NOINTERFACE;
169 static ULONG WINAPI Parser_AddRef(IBaseFilter * iface)
171 ParserImpl *This = (ParserImpl *)iface;
172 ULONG refCount = InterlockedIncrement(&This->refCount);
174 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
176 return refCount;
179 static ULONG WINAPI Parser_Release(IBaseFilter * iface)
181 ParserImpl *This = (ParserImpl *)iface;
182 ULONG refCount = InterlockedDecrement(&This->refCount);
184 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
186 if (!refCount)
188 ULONG i;
190 This->csFilter.DebugInfo->Spare[0] = 0;
191 DeleteCriticalSection(&This->csFilter);
192 if (This->pClock)
193 IReferenceClock_Release(This->pClock);
195 for (i = 0; i < This->cStreams + 1; i++)
197 IPin *pConnectedTo;
199 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
201 IPin_Disconnect(pConnectedTo);
202 IPin_Release(pConnectedTo);
204 IPin_Disconnect(This->ppPins[i]);
206 IPin_Release(This->ppPins[i]);
209 CoTaskMemFree(This->ppPins);
210 This->lpVtbl = NULL;
212 TRACE("Destroying parser\n");
213 CoTaskMemFree(This);
215 return 0;
217 else
218 return refCount;
221 /** IPersist methods **/
223 static HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid)
225 TRACE("(%p)\n", pClsid);
227 *pClsid = CLSID_AviSplitter;
229 return S_OK;
232 /** IMediaFilter methods **/
234 static HRESULT WINAPI Parser_Stop(IBaseFilter * iface)
236 HRESULT hr;
237 ParserImpl *This = (ParserImpl *)iface;
239 TRACE("()\n");
241 EnterCriticalSection(&This->csFilter);
243 if (This->state == State_Stopped)
245 LeaveCriticalSection(&This->csFilter);
246 return S_OK;
248 hr = PullPin_StopProcessing(This->pInputPin);
249 This->state = State_Stopped;
251 LeaveCriticalSection(&This->csFilter);
253 return hr;
256 static HRESULT WINAPI Parser_Pause(IBaseFilter * iface)
258 HRESULT hr = S_OK;
259 BOOL bInit;
260 ParserImpl *This = (ParserImpl *)iface;
262 TRACE("()\n");
264 EnterCriticalSection(&This->csFilter);
266 if (This->state == State_Paused)
268 LeaveCriticalSection(&This->csFilter);
269 return S_OK;
271 bInit = (This->state == State_Stopped);
272 This->state = State_Paused;
274 LeaveCriticalSection(&This->csFilter);
276 if (bInit)
278 unsigned int i;
280 hr = PullPin_Seek(This->pInputPin, 0, ((LONGLONG)0x7fffffff << 32) | 0xffffffff);
282 if (SUCCEEDED(hr))
283 hr = PullPin_InitProcessing(This->pInputPin);
285 if (SUCCEEDED(hr))
287 for (i = 1; i < This->cStreams + 1; i++)
289 Parser_OutputPin* StreamPin = (Parser_OutputPin *)This->ppPins[i];
290 OutputPin_DeliverNewSegment((OutputPin *)This->ppPins[i], 0, (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec), 1.0);
291 StreamPin->mediaSeeking.llDuration = (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec);
292 StreamPin->mediaSeeking.llStop = (LONGLONG)ceil(10000000.0 * (float)StreamPin->dwLength / StreamPin->fSamplesPerSec);
293 OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
296 /* FIXME: this is a little hacky: we have to deliver (at least?) one sample
297 * to each renderer before they will complete their transitions. We should probably
298 * seek through the stream for the first of each, rather than do it this way which is
299 * probably a bit prone to deadlocking */
300 hr = PullPin_StartProcessing(This->pInputPin);
303 /* FIXME: else pause thread */
305 if (SUCCEEDED(hr))
306 hr = PullPin_PauseProcessing(This->pInputPin);
308 return hr;
311 static HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
313 HRESULT hr = S_OK;
314 ParserImpl *This = (ParserImpl *)iface;
315 int i;
317 TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
319 EnterCriticalSection(&This->csFilter);
321 if (This->state == State_Running)
323 LeaveCriticalSection(&This->csFilter);
324 return S_OK;
327 This->rtStreamStart = tStart;
329 hr = PullPin_Seek(This->pInputPin, tStart, ((LONGLONG)0x7fffffff << 32) | 0xffffffff);
331 if (SUCCEEDED(hr) && (This->state == State_Stopped))
333 hr = PullPin_InitProcessing(This->pInputPin);
335 if (SUCCEEDED(hr))
337 for (i = 1; i < (This->cStreams + 1); i++)
339 OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
344 if (SUCCEEDED(hr))
345 hr = PullPin_StartProcessing(This->pInputPin);
347 if (SUCCEEDED(hr))
348 This->state = State_Running;
350 LeaveCriticalSection(&This->csFilter);
352 return hr;
355 static HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
357 ParserImpl *This = (ParserImpl *)iface;
359 TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState);
361 EnterCriticalSection(&This->csFilter);
363 *pState = This->state;
365 LeaveCriticalSection(&This->csFilter);
367 /* FIXME: this is a little bit unsafe, but I don't see that we can do this
368 * while in the critical section. Maybe we could copy the pointer and addref in the
369 * critical section and then release after this.
371 if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE))
372 return VFW_S_STATE_INTERMEDIATE;
374 return S_OK;
377 static HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
379 ParserImpl *This = (ParserImpl *)iface;
381 TRACE("(%p)\n", pClock);
383 EnterCriticalSection(&This->csFilter);
385 if (This->pClock)
386 IReferenceClock_Release(This->pClock);
387 This->pClock = pClock;
388 if (This->pClock)
389 IReferenceClock_AddRef(This->pClock);
391 LeaveCriticalSection(&This->csFilter);
393 return S_OK;
396 static HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
398 ParserImpl *This = (ParserImpl *)iface;
400 TRACE("(%p)\n", ppClock);
402 EnterCriticalSection(&This->csFilter);
404 *ppClock = This->pClock;
405 if (This->pClock)
406 IReferenceClock_AddRef(This->pClock);
408 LeaveCriticalSection(&This->csFilter);
410 return S_OK;
413 /** IBaseFilter implementation **/
415 static HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
417 ENUMPINDETAILS epd;
418 ParserImpl *This = (ParserImpl *)iface;
420 TRACE("(%p)\n", ppEnum);
422 epd.cPins = This->cStreams + 1; /* +1 for input pin */
423 epd.ppPins = This->ppPins;
424 return IEnumPinsImpl_Construct(&epd, ppEnum);
427 static HRESULT WINAPI Parser_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
429 FIXME("(%p)->(%s,%p)\n", iface, debugstr_w(Id), ppPin);
431 /* FIXME: critical section */
433 return E_NOTIMPL;
436 static HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
438 ParserImpl *This = (ParserImpl *)iface;
440 TRACE("(%p)\n", pInfo);
442 strcpyW(pInfo->achName, This->filterInfo.achName);
443 pInfo->pGraph = This->filterInfo.pGraph;
445 if (pInfo->pGraph)
446 IFilterGraph_AddRef(pInfo->pGraph);
448 return S_OK;
451 static HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
453 HRESULT hr = S_OK;
454 ParserImpl *This = (ParserImpl *)iface;
456 TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
458 EnterCriticalSection(&This->csFilter);
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 */
466 LeaveCriticalSection(&This->csFilter);
468 return hr;
471 static HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
473 TRACE("(%p)\n", pVendorInfo);
474 return E_NOTIMPL;
477 static const IBaseFilterVtbl Parser_Vtbl =
479 Parser_QueryInterface,
480 Parser_AddRef,
481 Parser_Release,
482 Parser_GetClassID,
483 Parser_Stop,
484 Parser_Pause,
485 Parser_Run,
486 Parser_GetState,
487 Parser_SetSyncSource,
488 Parser_GetSyncSource,
489 Parser_EnumPins,
490 Parser_FindPin,
491 Parser_QueryFilterInfo,
492 Parser_JoinFilterGraph,
493 Parser_QueryVendorInfo
496 HRESULT Parser_AddPin(ParserImpl * This, PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, AM_MEDIA_TYPE * amt, float fSamplesPerSec, DWORD dwSampleSize, DWORD dwLength)
498 IPin ** ppOldPins;
499 HRESULT hr;
501 ppOldPins = This->ppPins;
503 This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *));
504 memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *));
506 hr = Parser_OutputPin_Construct(piOutput, props, NULL, Parser_OutputPin_QueryAccept, amt, fSamplesPerSec, &This->csFilter, This->ppPins + This->cStreams + 1);
508 if (SUCCEEDED(hr))
510 ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->dwSampleSize = dwSampleSize;
511 ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->dwLength = dwLength;
512 ((Parser_OutputPin *)(This->ppPins[This->cStreams + 1]))->pin.pin.pUserData = (LPVOID)This->ppPins[This->cStreams + 1];
513 This->cStreams++;
514 CoTaskMemFree(ppOldPins);
516 else
518 CoTaskMemFree(This->ppPins);
519 This->ppPins = ppOldPins;
520 ERR("Failed with error %x\n", hr);
523 return hr;
526 static HRESULT Parser_RemoveOutputPins(ParserImpl * This)
528 /* NOTE: should be in critical section when calling this function */
530 ULONG i;
531 IPin ** ppOldPins = This->ppPins;
533 /* reduce the pin array down to 1 (just our input pin) */
534 This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1);
535 memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1);
537 for (i = 0; i < This->cStreams; i++)
539 OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]);
540 IPin_Release(ppOldPins[i + 1]);
543 This->cStreams = 0;
544 CoTaskMemFree(ppOldPins);
546 return S_OK;
549 static HRESULT Parser_ChangeStart(LPVOID iface)
551 FIXME("(%p)\n", iface);
552 return S_OK;
555 static HRESULT Parser_ChangeStop(LPVOID iface)
557 FIXME("(%p)\n", iface);
558 return S_OK;
561 static HRESULT Parser_ChangeRate(LPVOID iface)
563 FIXME("(%p)\n", iface);
564 return S_OK;
568 static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
570 Parser_OutputPin *This = impl_from_IMediaSeeking(iface);
572 return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
575 static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface)
577 Parser_OutputPin *This = impl_from_IMediaSeeking(iface);
579 return IUnknown_AddRef((IUnknown *)This);
582 static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface)
584 Parser_OutputPin *This = impl_from_IMediaSeeking(iface);
586 return IUnknown_Release((IUnknown *)This);
589 static const IMediaSeekingVtbl Parser_Seeking_Vtbl =
591 Parser_Seeking_QueryInterface,
592 Parser_Seeking_AddRef,
593 Parser_Seeking_Release,
594 MediaSeekingImpl_GetCapabilities,
595 MediaSeekingImpl_CheckCapabilities,
596 MediaSeekingImpl_IsFormatSupported,
597 MediaSeekingImpl_QueryPreferredFormat,
598 MediaSeekingImpl_GetTimeFormat,
599 MediaSeekingImpl_IsUsingTimeFormat,
600 MediaSeekingImpl_SetTimeFormat,
601 MediaSeekingImpl_GetDuration,
602 MediaSeekingImpl_GetStopPosition,
603 MediaSeekingImpl_GetCurrentPosition,
604 MediaSeekingImpl_ConvertTimeFormat,
605 MediaSeekingImpl_SetPositions,
606 MediaSeekingImpl_GetPositions,
607 MediaSeekingImpl_GetAvailable,
608 MediaSeekingImpl_SetRate,
609 MediaSeekingImpl_GetRate,
610 MediaSeekingImpl_GetPreroll
613 static HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
615 Parser_OutputPin *This = (Parser_OutputPin *)iface;
617 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
619 *ppv = NULL;
621 if (IsEqualIID(riid, &IID_IUnknown))
622 *ppv = (LPVOID)iface;
623 else if (IsEqualIID(riid, &IID_IPin))
624 *ppv = (LPVOID)iface;
625 else if (IsEqualIID(riid, &IID_IMediaSeeking))
626 *ppv = (LPVOID)&This->mediaSeeking;
628 if (*ppv)
630 IUnknown_AddRef((IUnknown *)(*ppv));
631 return S_OK;
634 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
636 return E_NOINTERFACE;
639 static ULONG WINAPI Parser_OutputPin_Release(IPin * iface)
641 Parser_OutputPin *This = (Parser_OutputPin *)iface;
642 ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
644 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
646 if (!refCount)
648 FreeMediaType(This->pmt);
649 CoTaskMemFree(This->pmt);
650 FreeMediaType(&This->pin.pin.mtCurrent);
651 CoTaskMemFree(This);
652 return 0;
654 return refCount;
657 static HRESULT WINAPI Parser_OutputPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
659 ENUMMEDIADETAILS emd;
660 Parser_OutputPin *This = (Parser_OutputPin *)iface;
662 TRACE("(%p)\n", ppEnum);
664 /* override this method to allow enumeration of your types */
665 emd.cMediaTypes = 1;
666 emd.pMediaTypes = This->pmt;
668 return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
671 static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
673 Parser_OutputPin *This = (Parser_OutputPin *)iface;
675 TRACE("()\n");
676 dump_AM_MEDIA_TYPE(pmt);
678 return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0);
681 static const IPinVtbl Parser_OutputPin_Vtbl =
683 Parser_OutputPin_QueryInterface,
684 IPinImpl_AddRef,
685 Parser_OutputPin_Release,
686 OutputPin_Connect,
687 OutputPin_ReceiveConnection,
688 OutputPin_Disconnect,
689 IPinImpl_ConnectedTo,
690 IPinImpl_ConnectionMediaType,
691 IPinImpl_QueryPinInfo,
692 IPinImpl_QueryDirection,
693 IPinImpl_QueryId,
694 IPinImpl_QueryAccept,
695 Parser_OutputPin_EnumMediaTypes,
696 IPinImpl_QueryInternalConnections,
697 OutputPin_EndOfStream,
698 OutputPin_BeginFlush,
699 OutputPin_EndFlush,
700 OutputPin_NewSegment
703 static HRESULT Parser_InputPin_Construct(const PIN_INFO * pPinInfo, SAMPLEPROC pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, LPCRITICAL_SECTION pCritSec, IPin ** ppPin)
705 PullPin * pPinImpl;
707 *ppPin = NULL;
709 if (pPinInfo->dir != PINDIR_INPUT)
711 ERR("Pin direction(%x) != PINDIR_INPUT\n", pPinInfo->dir);
712 return E_INVALIDARG;
715 pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl));
717 if (!pPinImpl)
718 return E_OUTOFMEMORY;
720 if (SUCCEEDED(PullPin_Init(pPinInfo, pSampleProc, pUserData, pQueryAccept, pCritSec, pPinImpl)))
722 pPinImpl->pin.lpVtbl = &Parser_InputPin_Vtbl;
724 *ppPin = (IPin *)(&pPinImpl->pin.lpVtbl);
725 return S_OK;
727 return E_FAIL;
730 static HRESULT WINAPI Parser_InputPin_Disconnect(IPin * iface)
732 HRESULT hr;
733 IPinImpl *This = (IPinImpl *)iface;
735 TRACE("()\n");
737 EnterCriticalSection(This->pCritSec);
739 if (This->pConnectedTo)
741 FILTER_STATE state;
743 hr = IBaseFilter_GetState(This->pinInfo.pFilter, 0, &state);
745 if (SUCCEEDED(hr) && (state == State_Stopped))
747 IPin_Release(This->pConnectedTo);
748 This->pConnectedTo = NULL;
749 hr = Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
751 else
752 hr = VFW_E_NOT_STOPPED;
754 else
755 hr = S_FALSE;
757 LeaveCriticalSection(This->pCritSec);
759 return hr;
762 static const IPinVtbl Parser_InputPin_Vtbl =
764 PullPin_QueryInterface,
765 IPinImpl_AddRef,
766 PullPin_Release,
767 OutputPin_Connect,
768 PullPin_ReceiveConnection,
769 Parser_InputPin_Disconnect,
770 IPinImpl_ConnectedTo,
771 IPinImpl_ConnectionMediaType,
772 IPinImpl_QueryPinInfo,
773 IPinImpl_QueryDirection,
774 IPinImpl_QueryId,
775 IPinImpl_QueryAccept,
776 IPinImpl_EnumMediaTypes,
777 IPinImpl_QueryInternalConnections,
778 PullPin_EndOfStream,
779 PullPin_BeginFlush,
780 PullPin_EndFlush,
781 PullPin_NewSegment