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"
29 #include "wine/unicode.h"
30 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
39 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
40 static const IBaseFilterVtbl Parser_Vtbl;
41 static const IMediaSeekingVtbl Parser_Seeking_Vtbl;
42 static const IPinVtbl Parser_OutputPin_Vtbl;
43 static const IPinVtbl Parser_InputPin_Vtbl;
45 static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt);
46 static HRESULT Parser_ChangeCurrent(IBaseFilter *iface);
47 static HRESULT Parser_ChangeStop(IBaseFilter *iface);
48 static HRESULT Parser_ChangeRate(IBaseFilter *iface);
50 static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
52 return (ParserImpl *)((char*)iface - FIELD_OFFSET(ParserImpl, mediaSeeking.lpVtbl));
56 HRESULT Parser_Create(ParserImpl* pParser, const CLSID* pClsid, PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate)
61 /* pTransformFilter is already allocated */
62 pParser->clsid = *pClsid;
64 pParser->lpVtbl = &Parser_Vtbl;
65 pParser->refCount = 1;
66 InitializeCriticalSection(&pParser->csFilter);
67 pParser->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": ParserImpl.csFilter");
68 pParser->state = State_Stopped;
69 pParser->pClock = NULL;
70 pParser->fnCleanup = fnCleanup;
71 pParser->fnDisconnect = fnDisconnect;
72 ZeroMemory(&pParser->filterInfo, sizeof(FILTER_INFO));
74 pParser->cStreams = 0;
75 pParser->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
77 /* construct input pin */
78 piInput.dir = PINDIR_INPUT;
79 piInput.pFilter = (IBaseFilter *)pParser;
80 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
83 current = Parser_ChangeCurrent;
86 stop = Parser_ChangeStop;
89 rate = Parser_ChangeRate;
91 MediaSeekingImpl_Init((IBaseFilter*)pParser, stop, current, rate, &pParser->mediaSeeking, &pParser->csFilter);
92 pParser->mediaSeeking.lpVtbl = &Parser_Seeking_Vtbl;
94 hr = PullPin_Construct(&Parser_InputPin_Vtbl, &piInput, fnProcessSample, (LPVOID)pParser, fnQueryAccept, fnCleanup, fnRequest, &pParser->csFilter, (IPin **)&pParser->pInputPin);
98 pParser->ppPins[0] = (IPin *)pParser->pInputPin;
99 pParser->pInputPin->fnPreConnect = fnPreConnect;
103 CoTaskMemFree(pParser->ppPins);
104 pParser->csFilter.DebugInfo->Spare[0] = 0;
105 DeleteCriticalSection(&pParser->csFilter);
106 CoTaskMemFree(pParser);
112 static HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
114 ParserImpl *This = (ParserImpl *)iface;
115 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
119 if (IsEqualIID(riid, &IID_IUnknown))
121 else if (IsEqualIID(riid, &IID_IPersist))
123 else if (IsEqualIID(riid, &IID_IMediaFilter))
125 else if (IsEqualIID(riid, &IID_IBaseFilter))
127 else if (IsEqualIID(riid, &IID_IMediaSeeking))
128 *ppv = (LPVOID)&This->mediaSeeking;
132 IUnknown_AddRef((IUnknown *)(*ppv));
136 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
137 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
139 return E_NOINTERFACE;
142 static ULONG WINAPI Parser_AddRef(IBaseFilter * iface)
144 ParserImpl *This = (ParserImpl *)iface;
145 ULONG refCount = InterlockedIncrement(&This->refCount);
147 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
152 static ULONG WINAPI Parser_Release(IBaseFilter * iface)
154 ParserImpl *This = (ParserImpl *)iface;
155 ULONG refCount = InterlockedDecrement(&This->refCount);
157 TRACE("(%p)->() Release from %d\n", This, refCount + 1);
164 This->fnCleanup(This);
167 IReferenceClock_Release(This->pClock);
169 for (i = 0; i < This->cStreams + 1; i++)
173 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
175 IPin_Disconnect(pConnectedTo);
176 IPin_Release(pConnectedTo);
178 IPin_Disconnect(This->ppPins[i]);
180 IPin_Release(This->ppPins[i]);
183 CoTaskMemFree(This->ppPins);
186 This->csFilter.DebugInfo->Spare[0] = 0;
187 DeleteCriticalSection(&This->csFilter);
189 TRACE("Destroying parser\n");
198 /** IPersist methods **/
200 static HRESULT WINAPI Parser_GetClassID(IBaseFilter * iface, CLSID * pClsid)
202 ParserImpl *This = (ParserImpl *)iface;
204 TRACE("(%p)\n", pClsid);
206 *pClsid = This->clsid;
211 /** IMediaFilter methods **/
213 static HRESULT WINAPI Parser_Stop(IBaseFilter * iface)
216 ParserImpl *This = (ParserImpl *)iface;
217 PullPin *pin = (PullPin *)This->ppPins[0];
221 EnterCriticalSection(&pin->thread_lock);
222 EnterCriticalSection(&This->csFilter);
224 if (This->state == State_Stopped)
226 LeaveCriticalSection(&This->csFilter);
227 LeaveCriticalSection(&pin->thread_lock);
230 This->state = State_Stopped;
232 LeaveCriticalSection(&This->csFilter);
234 hr = PullPin_StopProcessing(This->pInputPin);
235 LeaveCriticalSection(&pin->thread_lock);
239 static HRESULT WINAPI Parser_Pause(IBaseFilter * iface)
242 ParserImpl *This = (ParserImpl *)iface;
243 PullPin *pin = (PullPin *)This->ppPins[0];
247 EnterCriticalSection(&pin->thread_lock);
248 EnterCriticalSection(&This->csFilter);
250 if (This->state == State_Paused)
252 LeaveCriticalSection(&This->csFilter);
253 LeaveCriticalSection(&pin->thread_lock);
257 if (This->state == State_Stopped)
259 LeaveCriticalSection(&This->csFilter);
260 hr = IBaseFilter_Run(iface, -1);
261 EnterCriticalSection(&This->csFilter);
264 This->state = State_Paused;
266 LeaveCriticalSection(&This->csFilter);
268 hr = PullPin_PauseProcessing(This->pInputPin);
269 LeaveCriticalSection(&pin->thread_lock);
274 static HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
277 ParserImpl *This = (ParserImpl *)iface;
278 PullPin *pin = (PullPin *)This->ppPins[0];
282 TRACE("(%s)\n", wine_dbgstr_longlong(tStart));
284 EnterCriticalSection(&pin->thread_lock);
285 EnterCriticalSection(&This->csFilter);
287 if (This->state == State_Running)
289 LeaveCriticalSection(&This->csFilter);
290 LeaveCriticalSection(&pin->thread_lock);
294 This->rtStreamStart = tStart;
296 if (SUCCEEDED(hr) && (This->state == State_Stopped))
298 LeaveCriticalSection(&This->csFilter);
299 hr = PullPin_InitProcessing(This->pInputPin);
300 EnterCriticalSection(&This->csFilter);
304 for (i = 1; i < (This->cStreams + 1); i++)
306 OutputPin_CommitAllocator((OutputPin *)This->ppPins[i]);
313 LeaveCriticalSection(&This->csFilter);
314 hr = PullPin_StartProcessing(This->pInputPin);
315 EnterCriticalSection(&This->csFilter);
319 This->state = State_Running;
321 LeaveCriticalSection(&This->csFilter);
322 LeaveCriticalSection(&pin->thread_lock);
327 static HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
329 ParserImpl *This = (ParserImpl *)iface;
330 PullPin *pin = (PullPin *)This->ppPins[0];
333 TRACE("(%d, %p)\n", dwMilliSecsTimeout, pState);
335 EnterCriticalSection(&pin->thread_lock);
336 EnterCriticalSection(&This->csFilter);
338 *pState = This->state;
340 LeaveCriticalSection(&This->csFilter);
342 if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE))
343 hr = VFW_S_STATE_INTERMEDIATE;
344 LeaveCriticalSection(&pin->thread_lock);
349 static HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
351 ParserImpl *This = (ParserImpl *)iface;
352 PullPin *pin = (PullPin *)This->ppPins[0];
354 TRACE("(%p)\n", pClock);
356 EnterCriticalSection(&pin->thread_lock);
357 EnterCriticalSection(&This->csFilter);
360 IReferenceClock_Release(This->pClock);
361 This->pClock = pClock;
363 IReferenceClock_AddRef(This->pClock);
365 LeaveCriticalSection(&This->csFilter);
366 LeaveCriticalSection(&pin->thread_lock);
371 static HRESULT WINAPI Parser_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
373 ParserImpl *This = (ParserImpl *)iface;
375 TRACE("(%p)\n", ppClock);
377 EnterCriticalSection(&This->csFilter);
379 *ppClock = This->pClock;
381 IReferenceClock_AddRef(This->pClock);
383 LeaveCriticalSection(&This->csFilter);
388 /** IBaseFilter implementation **/
390 static HRESULT WINAPI Parser_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
393 ParserImpl *This = (ParserImpl *)iface;
395 TRACE("(%p)\n", ppEnum);
397 epd.cPins = This->cStreams + 1; /* +1 for input pin */
398 epd.ppPins = This->ppPins;
399 return IEnumPinsImpl_Construct(&epd, ppEnum);
402 static HRESULT WINAPI Parser_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
404 FIXME("(%p)->(%s,%p)\n", iface, debugstr_w(Id), ppPin);
406 /* FIXME: critical section */
411 static HRESULT WINAPI Parser_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
413 ParserImpl *This = (ParserImpl *)iface;
415 TRACE("(%p)\n", pInfo);
417 strcpyW(pInfo->achName, This->filterInfo.achName);
418 pInfo->pGraph = This->filterInfo.pGraph;
421 IFilterGraph_AddRef(pInfo->pGraph);
426 static HRESULT WINAPI Parser_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
429 ParserImpl *This = (ParserImpl *)iface;
431 TRACE("(%p, %s)\n", pGraph, debugstr_w(pName));
433 EnterCriticalSection(&This->csFilter);
436 strcpyW(This->filterInfo.achName, pName);
438 *This->filterInfo.achName = '\0';
439 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
441 LeaveCriticalSection(&This->csFilter);
446 static HRESULT WINAPI Parser_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
448 TRACE("(%p)\n", pVendorInfo);
452 static const IBaseFilterVtbl Parser_Vtbl =
454 Parser_QueryInterface,
462 Parser_SetSyncSource,
463 Parser_GetSyncSource,
466 Parser_QueryFilterInfo,
467 Parser_JoinFilterGraph,
468 Parser_QueryVendorInfo
471 HRESULT Parser_AddPin(ParserImpl * This, const PIN_INFO * piOutput, ALLOCATOR_PROPERTIES * props, const AM_MEDIA_TYPE * amt)
476 ppOldPins = This->ppPins;
478 This->ppPins = CoTaskMemAlloc((This->cStreams + 2) * sizeof(IPin *));
479 memcpy(This->ppPins, ppOldPins, (This->cStreams + 1) * sizeof(IPin *));
481 hr = OutputPin_Construct(&Parser_OutputPin_Vtbl, sizeof(Parser_OutputPin), piOutput, props, NULL, Parser_OutputPin_QueryAccept, &This->csFilter, This->ppPins + This->cStreams + 1);
485 IPin *pPin = This->ppPins[This->cStreams + 1];
486 Parser_OutputPin *pin = (Parser_OutputPin *)pPin;
487 pin->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
488 CopyMediaType(pin->pmt, amt);
489 pin->dwSamplesProcessed = 0;
491 pin->pin.pin.pUserData = (LPVOID)This->ppPins[This->cStreams + 1];
492 pin->pin.pin.pinInfo.pFilter = (LPVOID)This;
493 pin->pin.custom_allocator = 1;
495 CoTaskMemFree(ppOldPins);
499 CoTaskMemFree(This->ppPins);
500 This->ppPins = ppOldPins;
501 ERR("Failed with error %x\n", hr);
507 static HRESULT Parser_RemoveOutputPins(ParserImpl * This)
509 /* NOTE: should be in critical section when calling this function */
512 IPin ** ppOldPins = This->ppPins;
514 /* reduce the pin array down to 1 (just our input pin) */
515 This->ppPins = CoTaskMemAlloc(sizeof(IPin *) * 1);
516 memcpy(This->ppPins, ppOldPins, sizeof(IPin *) * 1);
518 for (i = 0; i < This->cStreams; i++)
520 OutputPin_DeliverDisconnect((OutputPin *)ppOldPins[i + 1]);
521 IPin_Release(ppOldPins[i + 1]);
525 CoTaskMemFree(ppOldPins);
530 static HRESULT Parser_ChangeCurrent(IBaseFilter *iface)
532 FIXME("(%p) filter hasn't implemented current position change!\n", iface);
536 static HRESULT Parser_ChangeStop(IBaseFilter *iface)
538 FIXME("(%p) filter hasn't implemented stop position change!\n", iface);
542 static HRESULT Parser_ChangeRate(IBaseFilter *iface)
544 FIXME("(%p) filter hasn't implemented rate change!\n", iface);
549 static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
551 ParserImpl *This = impl_from_IMediaSeeking(iface);
553 return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
556 static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface)
558 ParserImpl *This = impl_from_IMediaSeeking(iface);
560 return IUnknown_AddRef((IUnknown *)This);
563 static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface)
565 ParserImpl *This = impl_from_IMediaSeeking(iface);
567 return IUnknown_Release((IUnknown *)This);
570 static const IMediaSeekingVtbl Parser_Seeking_Vtbl =
572 Parser_Seeking_QueryInterface,
573 Parser_Seeking_AddRef,
574 Parser_Seeking_Release,
575 MediaSeekingImpl_GetCapabilities,
576 MediaSeekingImpl_CheckCapabilities,
577 MediaSeekingImpl_IsFormatSupported,
578 MediaSeekingImpl_QueryPreferredFormat,
579 MediaSeekingImpl_GetTimeFormat,
580 MediaSeekingImpl_IsUsingTimeFormat,
581 MediaSeekingImpl_SetTimeFormat,
582 MediaSeekingImpl_GetDuration,
583 MediaSeekingImpl_GetStopPosition,
584 MediaSeekingImpl_GetCurrentPosition,
585 MediaSeekingImpl_ConvertTimeFormat,
586 MediaSeekingImpl_SetPositions,
587 MediaSeekingImpl_GetPositions,
588 MediaSeekingImpl_GetAvailable,
589 MediaSeekingImpl_SetRate,
590 MediaSeekingImpl_GetRate,
591 MediaSeekingImpl_GetPreroll
594 static HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv)
596 Parser_OutputPin *This = (Parser_OutputPin *)iface;
598 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
602 if (IsEqualIID(riid, &IID_IUnknown))
603 *ppv = (LPVOID)iface;
604 else if (IsEqualIID(riid, &IID_IPin))
605 *ppv = (LPVOID)iface;
606 else if (IsEqualIID(riid, &IID_IMediaSeeking))
608 return IBaseFilter_QueryInterface(This->pin.pin.pinInfo.pFilter, &IID_IMediaSeeking, ppv);
613 IUnknown_AddRef((IUnknown *)(*ppv));
617 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
619 return E_NOINTERFACE;
622 static ULONG WINAPI Parser_OutputPin_Release(IPin * iface)
624 Parser_OutputPin *This = (Parser_OutputPin *)iface;
625 ULONG refCount = InterlockedDecrement(&This->pin.pin.refCount);
627 TRACE("(%p)->() Release from %d\n", iface, refCount + 1);
631 FreeMediaType(This->pmt);
632 CoTaskMemFree(This->pmt);
633 FreeMediaType(&This->pin.pin.mtCurrent);
640 static HRESULT WINAPI Parser_OutputPin_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
642 ENUMMEDIADETAILS emd;
643 Parser_OutputPin *This = (Parser_OutputPin *)iface;
645 TRACE("(%p)\n", ppEnum);
647 /* override this method to allow enumeration of your types */
649 emd.pMediaTypes = This->pmt;
651 return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
654 static HRESULT WINAPI Parser_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
656 Parser_OutputPin *This = (Parser_OutputPin *)iface;
657 ParserImpl *parser = (ParserImpl *)This->pin.pin.pinInfo.pFilter;
659 /* Set the allocator to our input pin's */
660 EnterCriticalSection(This->pin.pin.pCritSec);
661 This->pin.alloc = parser->pInputPin->pAlloc;
662 LeaveCriticalSection(This->pin.pin.pCritSec);
664 return OutputPin_Connect(iface, pReceivePin, pmt);
667 static HRESULT Parser_OutputPin_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
669 Parser_OutputPin *This = (Parser_OutputPin *)iface;
672 dump_AM_MEDIA_TYPE(pmt);
674 return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0);
677 static const IPinVtbl Parser_OutputPin_Vtbl =
679 Parser_OutputPin_QueryInterface,
681 Parser_OutputPin_Release,
682 Parser_OutputPin_Connect,
683 OutputPin_ReceiveConnection,
684 OutputPin_Disconnect,
685 IPinImpl_ConnectedTo,
686 IPinImpl_ConnectionMediaType,
687 IPinImpl_QueryPinInfo,
688 IPinImpl_QueryDirection,
690 IPinImpl_QueryAccept,
691 Parser_OutputPin_EnumMediaTypes,
692 IPinImpl_QueryInternalConnections,
693 OutputPin_EndOfStream,
694 OutputPin_BeginFlush,
699 static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface)
702 IPinImpl *This = (IPinImpl *)iface;
706 EnterCriticalSection(This->pCritSec);
708 if (This->pConnectedTo)
710 PullPin *ppin = (PullPin *)This;
712 ParserImpl *Parser = (ParserImpl *)This->pinInfo.pFilter;
714 hr = IBaseFilter_GetState(This->pinInfo.pFilter, 0, &state);
716 if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser)))
718 IPin_Release(This->pConnectedTo);
719 This->pConnectedTo = NULL;
720 if (FAILED(hr = IMemAllocator_Decommit(ppin->pAlloc)))
721 ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr);
722 hr = Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
725 hr = VFW_E_NOT_STOPPED;
730 LeaveCriticalSection(This->pCritSec);
735 HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
741 hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt);
744 IPinImpl *This = (IPinImpl *)iface;
746 EnterCriticalSection(This->pCritSec);
747 Parser_RemoveOutputPins((ParserImpl *)This->pinInfo.pFilter);
748 LeaveCriticalSection(This->pCritSec);
754 static const IPinVtbl Parser_InputPin_Vtbl =
756 PullPin_QueryInterface,
760 Parser_PullPin_ReceiveConnection,
761 Parser_PullPin_Disconnect,
762 IPinImpl_ConnectedTo,
763 IPinImpl_ConnectionMediaType,
764 IPinImpl_QueryPinInfo,
765 IPinImpl_QueryDirection,
767 IPinImpl_QueryAccept,
768 IPinImpl_EnumMediaTypes,
769 IPinImpl_QueryInternalConnections,