2 * Transform Filter (Base for decoders, etc...)
4 * Copyright 2005 Christian Costa
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include "quartz_private.h"
24 #include "control_private.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
39 #include "transform.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
43 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
44 static const WCHAR wcsOutputPinName[] = {'o','u','t','p','u','t',' ','p','i','n',0};
46 static const IBaseFilterVtbl TransformFilter_Vtbl;
47 static const IPinVtbl TransformFilter_InputPin_Vtbl;
48 static const IPinVtbl TransformFilter_OutputPin_Vtbl;
50 static HRESULT TransformFilter_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
52 TransformFilterImpl* This = (TransformFilterImpl *)((BasePin *)iface)->pinInfo.pFilter;
54 dump_AM_MEDIA_TYPE(pmt);
56 if (This->pFuncsTable->pfnQueryConnect)
57 return This->pFuncsTable->pfnQueryConnect(This, pmt);
58 /* Assume OK if there's no query method (the connection will fail if
64 static HRESULT WINAPI TransformFilter_Output_QueryAccept(IPin *iface, const AM_MEDIA_TYPE * pmt)
66 BasePin *This = (BasePin *)iface;
67 TransformFilterImpl *pTransformFilter = (TransformFilterImpl *)This->pinInfo.pFilter;
68 AM_MEDIA_TYPE* outpmt = &pTransformFilter->pmt;
71 if (IsEqualIID(&pmt->majortype, &outpmt->majortype)
72 && (IsEqualIID(&pmt->subtype, &outpmt->subtype) || IsEqualIID(&outpmt->subtype, &GUID_NULL)))
77 HRESULT TransformFilter_Create(TransformFilterImpl* pTransformFilter, const CLSID* pClsid, const TransformFuncsTable* pFuncsTable)
83 /* pTransformFilter is already allocated */
84 pTransformFilter->clsid = *pClsid;
85 pTransformFilter->pFuncsTable = pFuncsTable;
87 pTransformFilter->lpVtbl = &TransformFilter_Vtbl;
89 pTransformFilter->refCount = 1;
90 InitializeCriticalSection(&pTransformFilter->csFilter);
91 pTransformFilter->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TransformFilterImpl.csFilter");
92 pTransformFilter->state = State_Stopped;
93 pTransformFilter->pClock = NULL;
94 ZeroMemory(&pTransformFilter->filterInfo, sizeof(FILTER_INFO));
95 ZeroMemory(&pTransformFilter->pmt, sizeof(pTransformFilter->pmt));
96 pTransformFilter->npins = 2;
98 pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
100 /* construct input pin */
101 piInput.dir = PINDIR_INPUT;
102 piInput.pFilter = (IBaseFilter *)pTransformFilter;
103 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
104 piOutput.dir = PINDIR_OUTPUT;
105 piOutput.pFilter = (IBaseFilter *)pTransformFilter;
106 lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
108 hr = InputPin_Construct(&TransformFilter_InputPin_Vtbl, &piInput, (SAMPLEPROC_PUSH)pFuncsTable->pfnProcessSampleData, NULL, TransformFilter_Input_QueryAccept, NULL, &pTransformFilter->csFilter, NULL, &pTransformFilter->ppPins[0]);
112 ALLOCATOR_PROPERTIES props;
115 props.cbBuffer = 0; /* Will be updated at connection time */
118 ((InputPin *)pTransformFilter->ppPins[0])->pUserData = pTransformFilter->ppPins[0];
120 hr = OutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(OutputPin), &piOutput, &props, &pTransformFilter->csFilter, &pTransformFilter->ppPins[1]);
123 ERR("Cannot create output pin (%x)\n", hr);
126 ISeekingPassThru *passthru;
127 hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)pTransformFilter, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&pTransformFilter->seekthru_unk);
128 IUnknown_QueryInterface(pTransformFilter->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
129 ISeekingPassThru_Init(passthru, FALSE, (IPin*)pTransformFilter->ppPins[0]);
130 ISeekingPassThru_Release(passthru);
135 CoTaskMemFree(pTransformFilter->ppPins);
136 pTransformFilter->csFilter.DebugInfo->Spare[0] = 0;
137 DeleteCriticalSection(&pTransformFilter->csFilter);
138 CoTaskMemFree(pTransformFilter);
144 static HRESULT WINAPI TransformFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
146 TransformFilterImpl *This = (TransformFilterImpl *)iface;
147 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
151 if (IsEqualIID(riid, &IID_IUnknown))
153 else if (IsEqualIID(riid, &IID_IPersist))
155 else if (IsEqualIID(riid, &IID_IMediaFilter))
157 else if (IsEqualIID(riid, &IID_IBaseFilter))
159 else if (IsEqualIID(riid, &IID_IMediaSeeking))
160 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
164 IUnknown_AddRef((IUnknown *)(*ppv));
168 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
169 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
171 return E_NOINTERFACE;
174 static ULONG WINAPI TransformFilter_AddRef(IBaseFilter * iface)
176 TransformFilterImpl *This = (TransformFilterImpl *)iface;
177 ULONG refCount = InterlockedIncrement(&This->refCount);
179 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
184 static ULONG WINAPI TransformFilter_Release(IBaseFilter * iface)
186 TransformFilterImpl *This = (TransformFilterImpl *)iface;
187 ULONG refCount = InterlockedDecrement(&This->refCount);
189 TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
196 IReferenceClock_Release(This->pClock);
198 for (i = 0; i < This->npins; i++)
202 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
204 IPin_Disconnect(pConnectedTo);
205 IPin_Release(pConnectedTo);
207 IPin_Disconnect(This->ppPins[i]);
209 IPin_Release(This->ppPins[i]);
212 CoTaskMemFree(This->ppPins);
215 This->csFilter.DebugInfo->Spare[0] = 0;
216 DeleteCriticalSection(&This->csFilter);
218 TRACE("Destroying transform filter\n");
219 FreeMediaType(&This->pmt);
228 /** IPersist methods **/
230 static HRESULT WINAPI TransformFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
232 TransformFilterImpl *This = (TransformFilterImpl *)iface;
234 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
236 *pClsid = This->clsid;
241 /** IMediaFilter methods **/
243 static HRESULT WINAPI TransformFilter_Stop(IBaseFilter * iface)
245 TransformFilterImpl *This = (TransformFilterImpl *)iface;
248 TRACE("(%p/%p)\n", This, iface);
250 EnterCriticalSection(&This->csFilter);
252 This->state = State_Stopped;
253 if (This->pFuncsTable->pfnProcessEnd)
254 hr = This->pFuncsTable->pfnProcessEnd(This);
256 LeaveCriticalSection(&This->csFilter);
261 static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface)
263 TransformFilterImpl *This = (TransformFilterImpl *)iface;
266 TRACE("(%p/%p)->()\n", This, iface);
268 EnterCriticalSection(&This->csFilter);
270 if (This->state == State_Stopped)
271 hr = IBaseFilter_Run(iface, -1);
276 This->state = State_Paused;
278 LeaveCriticalSection(&This->csFilter);
283 static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
286 TransformFilterImpl *This = (TransformFilterImpl *)iface;
288 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
290 EnterCriticalSection(&This->csFilter);
292 if (This->state == State_Stopped)
294 ((InputPin *)This->ppPins[0])->end_of_stream = 0;
295 if (This->pFuncsTable->pfnProcessBegin)
296 hr = This->pFuncsTable->pfnProcessBegin(This);
298 hr = OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
303 This->rtStreamStart = tStart;
304 This->state = State_Running;
307 LeaveCriticalSection(&This->csFilter);
312 static HRESULT WINAPI TransformFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
314 TransformFilterImpl *This = (TransformFilterImpl *)iface;
316 TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
318 EnterCriticalSection(&This->csFilter);
320 *pState = This->state;
322 LeaveCriticalSection(&This->csFilter);
327 static HRESULT WINAPI TransformFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
329 TransformFilterImpl *This = (TransformFilterImpl *)iface;
331 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
333 EnterCriticalSection(&This->csFilter);
336 IReferenceClock_Release(This->pClock);
337 This->pClock = pClock;
339 IReferenceClock_AddRef(This->pClock);
341 LeaveCriticalSection(&This->csFilter);
346 static HRESULT WINAPI TransformFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
348 TransformFilterImpl *This = (TransformFilterImpl *)iface;
350 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
352 EnterCriticalSection(&This->csFilter);
354 *ppClock = This->pClock;
356 IReferenceClock_AddRef(This->pClock);
358 LeaveCriticalSection(&This->csFilter);
363 /** IBaseFilter implementation **/
365 static IPin* WINAPI TransformFilter_GetPin(IBaseFilter *iface, int pos)
367 TransformFilterImpl *This = (TransformFilterImpl *)iface;
369 if (pos >= This->npins || pos < 0)
372 IPin_AddRef(This->ppPins[pos]);
373 return This->ppPins[pos];
376 static LONG WINAPI TransformFilter_GetPinCount(IBaseFilter *iface)
378 TransformFilterImpl *This = (TransformFilterImpl *)iface;
380 return (This->npins+1);
383 static LONG WINAPI TransformFilter_GetPinVersion(IBaseFilter *iface)
385 /* Our pins are static, not changing so setting static tick count is ok */
389 static HRESULT WINAPI TransformFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
391 TransformFilterImpl *This = (TransformFilterImpl *)iface;
393 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
395 return EnumPins_Construct(iface, TransformFilter_GetPin, TransformFilter_GetPinCount, TransformFilter_GetPinVersion, ppEnum);
398 static HRESULT WINAPI TransformFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
400 TransformFilterImpl *This = (TransformFilterImpl *)iface;
402 TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
407 static HRESULT WINAPI TransformFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
409 TransformFilterImpl *This = (TransformFilterImpl *)iface;
411 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
413 strcpyW(pInfo->achName, This->filterInfo.achName);
414 pInfo->pGraph = This->filterInfo.pGraph;
417 IFilterGraph_AddRef(pInfo->pGraph);
422 static HRESULT WINAPI TransformFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
425 TransformFilterImpl *This = (TransformFilterImpl *)iface;
427 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
429 EnterCriticalSection(&This->csFilter);
432 strcpyW(This->filterInfo.achName, pName);
434 *This->filterInfo.achName = '\0';
435 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
437 LeaveCriticalSection(&This->csFilter);
442 static HRESULT WINAPI TransformFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
444 TransformFilterImpl *This = (TransformFilterImpl *)iface;
445 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
449 static const IBaseFilterVtbl TransformFilter_Vtbl =
451 TransformFilter_QueryInterface,
452 TransformFilter_AddRef,
453 TransformFilter_Release,
454 TransformFilter_GetClassID,
455 TransformFilter_Stop,
456 TransformFilter_Pause,
458 TransformFilter_GetState,
459 TransformFilter_SetSyncSource,
460 TransformFilter_GetSyncSource,
461 TransformFilter_EnumPins,
462 TransformFilter_FindPin,
463 TransformFilter_QueryFilterInfo,
464 TransformFilter_JoinFilterGraph,
465 TransformFilter_QueryVendorInfo
468 static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface)
470 InputPin* This = (InputPin*) iface;
471 TransformFilterImpl* pTransform;
475 TRACE("(%p)->()\n", iface);
477 /* Since we process samples synchronously, just forward notification downstream */
478 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
482 hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin);
485 hr = IPin_EndOfStream(ppin);
494 static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
496 InputPin* This = (InputPin*) iface;
497 TransformFilterImpl* pTransform;
500 TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt);
502 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
504 hr = pTransform->pFuncsTable->pfnConnectInput(This, pmt);
507 hr = InputPin_ReceiveConnection(iface, pReceivePin, pmt);
509 pTransform->pFuncsTable->pfnCleanup(This);
515 static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface)
517 InputPin* This = (InputPin*) iface;
518 TransformFilterImpl* pTransform;
520 TRACE("(%p)->()\n", iface);
522 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
523 pTransform->pFuncsTable->pfnCleanup(This);
525 return BasePinImpl_Disconnect(iface);
528 static HRESULT WINAPI TransformFilter_InputPin_BeginFlush(IPin * iface)
530 InputPin* This = (InputPin*) iface;
531 TransformFilterImpl* pTransform;
534 TRACE("(%p)->()\n", iface);
536 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
537 EnterCriticalSection(&pTransform->csFilter);
538 if (pTransform->pFuncsTable->pfnBeginFlush)
539 hr = pTransform->pFuncsTable->pfnBeginFlush(This);
541 hr = InputPin_BeginFlush(iface);
542 LeaveCriticalSection(&pTransform->csFilter);
546 static HRESULT WINAPI TransformFilter_InputPin_EndFlush(IPin * iface)
548 InputPin* This = (InputPin*) iface;
549 TransformFilterImpl* pTransform;
552 TRACE("(%p)->()\n", iface);
554 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
555 EnterCriticalSection(&pTransform->csFilter);
556 if (pTransform->pFuncsTable->pfnEndFlush)
557 hr = pTransform->pFuncsTable->pfnEndFlush(This);
559 hr = InputPin_EndFlush(iface);
560 LeaveCriticalSection(&pTransform->csFilter);
564 static HRESULT WINAPI TransformFilter_InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
566 InputPin* This = (InputPin*) iface;
567 TransformFilterImpl* pTransform;
570 TRACE("(%p)->()\n", iface);
572 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
573 EnterCriticalSection(&pTransform->csFilter);
574 if (pTransform->pFuncsTable->pfnNewSegment)
575 hr = pTransform->pFuncsTable->pfnNewSegment(This, tStart, tStop, dRate);
577 hr = InputPin_NewSegment(iface, tStart, tStop, dRate);
578 LeaveCriticalSection(&pTransform->csFilter);
582 static const IPinVtbl TransformFilter_InputPin_Vtbl =
584 InputPin_QueryInterface,
588 TransformFilter_InputPin_ReceiveConnection,
589 TransformFilter_InputPin_Disconnect,
590 BasePinImpl_ConnectedTo,
591 BasePinImpl_ConnectionMediaType,
592 BasePinImpl_QueryPinInfo,
593 BasePinImpl_QueryDirection,
595 InputPin_QueryAccept,
596 BasePinImpl_EnumMediaTypes,
597 BasePinImpl_QueryInternalConnections,
598 TransformFilter_InputPin_EndOfStream,
599 TransformFilter_InputPin_BeginFlush,
600 TransformFilter_InputPin_EndFlush,
601 TransformFilter_InputPin_NewSegment
604 static HRESULT WINAPI TransformFilter_Output_GetMediaType(IPin *iface, int iPosition, AM_MEDIA_TYPE *pmt)
606 BasePin *This = (BasePin *)iface;
607 TransformFilterImpl *pTransform = (TransformFilterImpl *)This->pinInfo.pFilter;
612 return VFW_S_NO_MORE_ITEMS;
613 CopyMediaType(pmt, &pTransform->pmt);
617 static HRESULT WINAPI TransformFilter_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
619 BasePin *This = (BasePin *)iface;
620 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
622 return EnumMediaTypes_Construct(iface, TransformFilter_Output_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum);
625 static const IPinVtbl TransformFilter_OutputPin_Vtbl =
627 OutputPin_QueryInterface,
631 OutputPin_ReceiveConnection,
632 OutputPin_Disconnect,
633 BasePinImpl_ConnectedTo,
634 BasePinImpl_ConnectionMediaType,
635 BasePinImpl_QueryPinInfo,
636 BasePinImpl_QueryDirection,
638 TransformFilter_Output_QueryAccept,
639 TransformFilter_Output_EnumMediaTypes,
640 BasePinImpl_QueryInternalConnections,
641 OutputPin_EndOfStream,
642 OutputPin_BeginFlush,