quartz: Add additional notifications to transform filter.
[wine/multimedia.git] / dlls / quartz / transform.c
blobe8056b0b341bb36415069f3a85cea3be7ee4aaf0
1 /*
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
21 #include "config.h"
23 #include "quartz_private.h"
24 #include "control_private.h"
25 #include "pin.h"
27 #include "amvideo.h"
28 #include "windef.h"
29 #include "winbase.h"
30 #include "dshow.h"
31 #include "strmif.h"
32 #include "vfw.h"
34 #include <assert.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 *)((IPinImpl *)iface)->pinInfo.pFilter;
53 TRACE("%p\n", iface);
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
59 needed) */
60 return S_OK;
64 static HRESULT TransformFilter_Output_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
66 TransformFilterImpl* pTransformFilter = iface;
67 AM_MEDIA_TYPE* outpmt = &pTransformFilter->pmt;
68 TRACE("%p\n", iface);
70 if (IsEqualIID(&pmt->majortype, &outpmt->majortype)
71 && (IsEqualIID(&pmt->subtype, &outpmt->subtype) || IsEqualIID(&outpmt->subtype, &GUID_NULL)))
72 return S_OK;
73 return S_FALSE;
76 HRESULT TransformFilter_Create(TransformFilterImpl* pTransformFilter, const CLSID* pClsid, const TransformFuncsTable* pFuncsTable)
78 HRESULT hr;
79 PIN_INFO piInput;
80 PIN_INFO piOutput;
82 /* pTransformFilter is already allocated */
83 pTransformFilter->clsid = *pClsid;
84 pTransformFilter->pFuncsTable = pFuncsTable;
86 pTransformFilter->lpVtbl = &TransformFilter_Vtbl;
88 pTransformFilter->refCount = 1;
89 InitializeCriticalSection(&pTransformFilter->csFilter);
90 pTransformFilter->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TransformFilterImpl.csFilter");
91 pTransformFilter->state = State_Stopped;
92 pTransformFilter->pClock = NULL;
93 ZeroMemory(&pTransformFilter->filterInfo, sizeof(FILTER_INFO));
94 ZeroMemory(&pTransformFilter->pmt, sizeof(pTransformFilter->pmt));
95 pTransformFilter->npins = 2;
97 pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
99 /* construct input pin */
100 piInput.dir = PINDIR_INPUT;
101 piInput.pFilter = (IBaseFilter *)pTransformFilter;
102 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
103 piOutput.dir = PINDIR_OUTPUT;
104 piOutput.pFilter = (IBaseFilter *)pTransformFilter;
105 lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
107 hr = InputPin_Construct(&TransformFilter_InputPin_Vtbl, &piInput, (SAMPLEPROC_PUSH)pFuncsTable->pfnProcessSampleData, NULL, TransformFilter_Input_QueryAccept, NULL, &pTransformFilter->csFilter, NULL, &pTransformFilter->ppPins[0]);
109 if (SUCCEEDED(hr))
111 ALLOCATOR_PROPERTIES props;
112 props.cbAlign = 1;
113 props.cbPrefix = 0;
114 props.cbBuffer = 0; /* Will be updated at connection time */
115 props.cBuffers = 1;
117 ((InputPin *)pTransformFilter->ppPins[0])->pin.pUserData = pTransformFilter->ppPins[0];
119 hr = OutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(OutputPin), &piOutput, &props, pTransformFilter, TransformFilter_Output_QueryAccept, &pTransformFilter->csFilter, &pTransformFilter->ppPins[1]);
121 if (FAILED(hr))
122 ERR("Cannot create output pin (%x)\n", hr);
123 else
125 ISeekingPassThru *passthru;
126 hr = CoCreateInstance(&CLSID_SeekingPassThru, (IUnknown*)pTransformFilter, CLSCTX_INPROC_SERVER, &IID_IUnknown, (void**)&pTransformFilter->seekthru_unk);
127 IUnknown_QueryInterface(pTransformFilter->seekthru_unk, &IID_ISeekingPassThru, (void**)&passthru);
128 ISeekingPassThru_Init(passthru, FALSE, (IPin*)pTransformFilter->ppPins[0]);
129 ISeekingPassThru_Release(passthru);
132 if (FAILED(hr))
134 CoTaskMemFree(pTransformFilter->ppPins);
135 pTransformFilter->csFilter.DebugInfo->Spare[0] = 0;
136 DeleteCriticalSection(&pTransformFilter->csFilter);
137 CoTaskMemFree(pTransformFilter);
140 return hr;
143 static HRESULT WINAPI TransformFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
145 TransformFilterImpl *This = (TransformFilterImpl *)iface;
146 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
148 *ppv = NULL;
150 if (IsEqualIID(riid, &IID_IUnknown))
151 *ppv = This;
152 else if (IsEqualIID(riid, &IID_IPersist))
153 *ppv = This;
154 else if (IsEqualIID(riid, &IID_IMediaFilter))
155 *ppv = This;
156 else if (IsEqualIID(riid, &IID_IBaseFilter))
157 *ppv = This;
158 else if (IsEqualIID(riid, &IID_IMediaSeeking))
159 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
161 if (*ppv)
163 IUnknown_AddRef((IUnknown *)(*ppv));
164 return S_OK;
167 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
168 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
170 return E_NOINTERFACE;
173 static ULONG WINAPI TransformFilter_AddRef(IBaseFilter * iface)
175 TransformFilterImpl *This = (TransformFilterImpl *)iface;
176 ULONG refCount = InterlockedIncrement(&This->refCount);
178 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
180 return refCount;
183 static ULONG WINAPI TransformFilter_Release(IBaseFilter * iface)
185 TransformFilterImpl *This = (TransformFilterImpl *)iface;
186 ULONG refCount = InterlockedDecrement(&This->refCount);
188 TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
190 if (!refCount)
192 ULONG i;
194 if (This->pClock)
195 IReferenceClock_Release(This->pClock);
197 for (i = 0; i < This->npins; i++)
199 IPin *pConnectedTo;
201 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
203 IPin_Disconnect(pConnectedTo);
204 IPin_Release(pConnectedTo);
206 IPin_Disconnect(This->ppPins[i]);
208 IPin_Release(This->ppPins[i]);
211 CoTaskMemFree(This->ppPins);
212 This->lpVtbl = NULL;
214 This->csFilter.DebugInfo->Spare[0] = 0;
215 DeleteCriticalSection(&This->csFilter);
217 TRACE("Destroying transform filter\n");
218 FreeMediaType(&This->pmt);
219 CoTaskMemFree(This);
221 return 0;
223 else
224 return refCount;
227 /** IPersist methods **/
229 static HRESULT WINAPI TransformFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
231 TransformFilterImpl *This = (TransformFilterImpl *)iface;
233 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
235 *pClsid = This->clsid;
237 return S_OK;
240 /** IMediaFilter methods **/
242 static HRESULT WINAPI TransformFilter_Stop(IBaseFilter * iface)
244 TransformFilterImpl *This = (TransformFilterImpl *)iface;
245 HRESULT hr = S_OK;
247 TRACE("(%p/%p)\n", This, iface);
249 EnterCriticalSection(&This->csFilter);
251 This->state = State_Stopped;
252 if (This->pFuncsTable->pfnProcessEnd)
253 hr = This->pFuncsTable->pfnProcessEnd(This);
255 LeaveCriticalSection(&This->csFilter);
257 return hr;
260 static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface)
262 TransformFilterImpl *This = (TransformFilterImpl *)iface;
263 HRESULT hr;
265 TRACE("(%p/%p)->()\n", This, iface);
267 EnterCriticalSection(&This->csFilter);
269 if (This->state == State_Stopped)
270 hr = IBaseFilter_Run(iface, -1);
271 else
272 hr = S_OK;
274 if (SUCCEEDED(hr))
275 This->state = State_Paused;
277 LeaveCriticalSection(&This->csFilter);
279 return hr;
282 static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
284 HRESULT hr = S_OK;
285 TransformFilterImpl *This = (TransformFilterImpl *)iface;
287 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
289 EnterCriticalSection(&This->csFilter);
291 if (This->state == State_Stopped)
293 ((InputPin *)This->ppPins[0])->end_of_stream = 0;
294 if (This->pFuncsTable->pfnProcessBegin)
295 hr = This->pFuncsTable->pfnProcessBegin(This);
296 if (SUCCEEDED(hr))
297 hr = OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
300 if (SUCCEEDED(hr))
302 This->rtStreamStart = tStart;
303 This->state = State_Running;
306 LeaveCriticalSection(&This->csFilter);
308 return hr;
311 static HRESULT WINAPI TransformFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
313 TransformFilterImpl *This = (TransformFilterImpl *)iface;
315 TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
317 EnterCriticalSection(&This->csFilter);
319 *pState = This->state;
321 LeaveCriticalSection(&This->csFilter);
323 return S_OK;
326 static HRESULT WINAPI TransformFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
328 TransformFilterImpl *This = (TransformFilterImpl *)iface;
330 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
332 EnterCriticalSection(&This->csFilter);
334 if (This->pClock)
335 IReferenceClock_Release(This->pClock);
336 This->pClock = pClock;
337 if (This->pClock)
338 IReferenceClock_AddRef(This->pClock);
340 LeaveCriticalSection(&This->csFilter);
342 return S_OK;
345 static HRESULT WINAPI TransformFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
347 TransformFilterImpl *This = (TransformFilterImpl *)iface;
349 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
351 EnterCriticalSection(&This->csFilter);
353 *ppClock = This->pClock;
354 if (This->pClock)
355 IReferenceClock_AddRef(This->pClock);
357 LeaveCriticalSection(&This->csFilter);
359 return S_OK;
362 /** IBaseFilter implementation **/
364 static HRESULT TransformFilter_GetPin(IBaseFilter *iface, ULONG pos, IPin **pin, DWORD *lastsynctick)
366 TransformFilterImpl *This = (TransformFilterImpl *)iface;
368 /* Our pins are static, not changing so setting static tick count is ok */
369 *lastsynctick = 0;
371 if (pos >= This->npins)
372 return S_FALSE;
374 *pin = This->ppPins[pos];
375 IPin_AddRef(*pin);
376 return S_OK;
379 static HRESULT WINAPI TransformFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
381 TransformFilterImpl *This = (TransformFilterImpl *)iface;
383 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
385 return IEnumPinsImpl_Construct(ppEnum, TransformFilter_GetPin, iface);
388 static HRESULT WINAPI TransformFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
390 TransformFilterImpl *This = (TransformFilterImpl *)iface;
392 TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
394 return E_NOTIMPL;
397 static HRESULT WINAPI TransformFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
399 TransformFilterImpl *This = (TransformFilterImpl *)iface;
401 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
403 strcpyW(pInfo->achName, This->filterInfo.achName);
404 pInfo->pGraph = This->filterInfo.pGraph;
406 if (pInfo->pGraph)
407 IFilterGraph_AddRef(pInfo->pGraph);
409 return S_OK;
412 static HRESULT WINAPI TransformFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
414 HRESULT hr = S_OK;
415 TransformFilterImpl *This = (TransformFilterImpl *)iface;
417 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
419 EnterCriticalSection(&This->csFilter);
421 if (pName)
422 strcpyW(This->filterInfo.achName, pName);
423 else
424 *This->filterInfo.achName = '\0';
425 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
427 LeaveCriticalSection(&This->csFilter);
429 return hr;
432 static HRESULT WINAPI TransformFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
434 TransformFilterImpl *This = (TransformFilterImpl *)iface;
435 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
436 return E_NOTIMPL;
439 static const IBaseFilterVtbl TransformFilter_Vtbl =
441 TransformFilter_QueryInterface,
442 TransformFilter_AddRef,
443 TransformFilter_Release,
444 TransformFilter_GetClassID,
445 TransformFilter_Stop,
446 TransformFilter_Pause,
447 TransformFilter_Run,
448 TransformFilter_GetState,
449 TransformFilter_SetSyncSource,
450 TransformFilter_GetSyncSource,
451 TransformFilter_EnumPins,
452 TransformFilter_FindPin,
453 TransformFilter_QueryFilterInfo,
454 TransformFilter_JoinFilterGraph,
455 TransformFilter_QueryVendorInfo
458 static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface)
460 InputPin* This = (InputPin*) iface;
461 TransformFilterImpl* pTransform;
462 IPin* ppin;
463 HRESULT hr;
465 TRACE("(%p)->()\n", iface);
467 /* Since we process samples synchronously, just forward notification downstream */
468 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
469 if (!pTransform)
470 hr = E_FAIL;
471 else
472 hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin);
473 if (SUCCEEDED(hr))
475 hr = IPin_EndOfStream(ppin);
476 IPin_Release(ppin);
479 if (FAILED(hr))
480 ERR("%x\n", hr);
481 return hr;
484 static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
486 InputPin* This = (InputPin*) iface;
487 TransformFilterImpl* pTransform;
488 HRESULT hr;
490 TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt);
492 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
494 hr = pTransform->pFuncsTable->pfnConnectInput(This, pmt);
495 if (SUCCEEDED(hr))
497 hr = InputPin_ReceiveConnection(iface, pReceivePin, pmt);
498 if (FAILED(hr))
499 pTransform->pFuncsTable->pfnCleanup(This);
502 return hr;
505 static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface)
507 InputPin* This = (InputPin*) iface;
508 TransformFilterImpl* pTransform;
510 TRACE("(%p)->()\n", iface);
512 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
513 pTransform->pFuncsTable->pfnCleanup(This);
515 return IPinImpl_Disconnect(iface);
518 static HRESULT WINAPI TransformFilter_InputPin_BeginFlush(IPin * iface)
520 InputPin* This = (InputPin*) iface;
521 TransformFilterImpl* pTransform;
522 HRESULT hr = S_OK;
524 TRACE("(%p)->()\n", iface);
526 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
527 EnterCriticalSection(&pTransform->csFilter);
528 if (pTransform->pFuncsTable->pfnBeginFlush)
529 hr = pTransform->pFuncsTable->pfnBeginFlush(This);
530 if (SUCCEEDED(hr))
531 hr = InputPin_BeginFlush(iface);
532 LeaveCriticalSection(&pTransform->csFilter);
533 return hr;
536 static HRESULT WINAPI TransformFilter_InputPin_EndFlush(IPin * iface)
538 InputPin* This = (InputPin*) iface;
539 TransformFilterImpl* pTransform;
540 HRESULT hr = S_OK;
542 TRACE("(%p)->()\n", iface);
544 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
545 EnterCriticalSection(&pTransform->csFilter);
546 if (pTransform->pFuncsTable->pfnEndFlush)
547 hr = pTransform->pFuncsTable->pfnEndFlush(This);
548 if (SUCCEEDED(hr))
549 hr = InputPin_EndFlush(iface);
550 LeaveCriticalSection(&pTransform->csFilter);
551 return hr;
554 static HRESULT WINAPI TransformFilter_InputPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate)
556 InputPin* This = (InputPin*) iface;
557 TransformFilterImpl* pTransform;
558 HRESULT hr = S_OK;
560 TRACE("(%p)->()\n", iface);
562 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
563 EnterCriticalSection(&pTransform->csFilter);
564 if (pTransform->pFuncsTable->pfnNewSegment)
565 hr = pTransform->pFuncsTable->pfnNewSegment(This, tStart, tStop, dRate);
566 if (SUCCEEDED(hr))
567 hr = InputPin_NewSegment(iface, tStart, tStop, dRate);
568 LeaveCriticalSection(&pTransform->csFilter);
569 return hr;
572 static const IPinVtbl TransformFilter_InputPin_Vtbl =
574 InputPin_QueryInterface,
575 IPinImpl_AddRef,
576 InputPin_Release,
577 InputPin_Connect,
578 TransformFilter_InputPin_ReceiveConnection,
579 TransformFilter_InputPin_Disconnect,
580 IPinImpl_ConnectedTo,
581 IPinImpl_ConnectionMediaType,
582 IPinImpl_QueryPinInfo,
583 IPinImpl_QueryDirection,
584 IPinImpl_QueryId,
585 IPinImpl_QueryAccept,
586 IPinImpl_EnumMediaTypes,
587 IPinImpl_QueryInternalConnections,
588 TransformFilter_InputPin_EndOfStream,
589 TransformFilter_InputPin_BeginFlush,
590 TransformFilter_InputPin_EndFlush,
591 TransformFilter_InputPin_NewSegment
594 static HRESULT WINAPI TransformFilter_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
596 IPinImpl *This = (IPinImpl *)iface;
597 TransformFilterImpl *pTransform = (TransformFilterImpl *)This->pinInfo.pFilter;
598 ENUMMEDIADETAILS emd;
600 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
602 emd.cMediaTypes = 1;
603 emd.pMediaTypes = &pTransform->pmt;
605 return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
608 static const IPinVtbl TransformFilter_OutputPin_Vtbl =
610 OutputPin_QueryInterface,
611 IPinImpl_AddRef,
612 OutputPin_Release,
613 OutputPin_Connect,
614 OutputPin_ReceiveConnection,
615 OutputPin_Disconnect,
616 IPinImpl_ConnectedTo,
617 IPinImpl_ConnectionMediaType,
618 IPinImpl_QueryPinInfo,
619 IPinImpl_QueryDirection,
620 IPinImpl_QueryId,
621 IPinImpl_QueryAccept,
622 TransformFilter_Output_EnumMediaTypes,
623 IPinImpl_QueryInternalConnections,
624 OutputPin_EndOfStream,
625 OutputPin_BeginFlush,
626 OutputPin_EndFlush,
627 OutputPin_NewSegment