gdiplus: Add a stub for GdipGetCustomLineCapBaseInset.
[wine/testsucceed.git] / dlls / quartz / transform.c
blobdbb84a74dceef6a8a852cae408bd4fdc8d447cd8
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 IMemInputPinVtbl MemInputPin_Vtbl;
49 static const IPinVtbl TransformFilter_OutputPin_Vtbl;
51 static HRESULT TransformFilter_Sample(LPVOID iface, IMediaSample * pSample)
53 TransformFilterImpl *This = (TransformFilterImpl *)iface;
55 TRACE("%p %p\n", iface, pSample);
57 if (This->state == State_Paused)
58 return S_FALSE;
60 if (This->state == State_Stopped)
61 return VFW_E_WRONG_STATE;
63 return This->pFuncsTable->pfnProcessSampleData(This, pSample);
66 static HRESULT TransformFilter_Input_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
68 TransformFilterImpl* This = (TransformFilterImpl*)iface;
69 TRACE("%p\n", iface);
70 dump_AM_MEDIA_TYPE(pmt);
72 if (This->pFuncsTable->pfnQueryConnect)
73 return This->pFuncsTable->pfnQueryConnect(This, pmt);
74 /* Assume OK if there's no query method (the connection will fail if
75 needed) */
76 return S_OK;
80 static HRESULT TransformFilter_Output_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
82 TransformFilterImpl* pTransformFilter = (TransformFilterImpl*)iface;
83 AM_MEDIA_TYPE* outpmt = &((OutputPin*)pTransformFilter->ppPins[1])->pin.mtCurrent;
84 TRACE("%p\n", iface);
86 if (IsEqualIID(&pmt->majortype, &outpmt->majortype) && IsEqualIID(&pmt->subtype, &outpmt->subtype))
87 return S_OK;
88 return S_FALSE;
92 static inline TransformFilterImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
94 return (TransformFilterImpl *)((char*)iface - FIELD_OFFSET(TransformFilterImpl, mediaSeeking.lpVtbl));
97 static HRESULT WINAPI TransformFilter_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
99 TransformFilterImpl *This = impl_from_IMediaSeeking(iface);
101 return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
104 static ULONG WINAPI TransformFilter_Seeking_AddRef(IMediaSeeking * iface)
106 TransformFilterImpl *This = impl_from_IMediaSeeking(iface);
108 return IUnknown_AddRef((IUnknown *)This);
111 static ULONG WINAPI TransformFilter_Seeking_Release(IMediaSeeking * iface)
113 TransformFilterImpl *This = impl_from_IMediaSeeking(iface);
115 return IUnknown_Release((IUnknown *)This);
118 static const IMediaSeekingVtbl TransformFilter_Seeking_Vtbl =
120 TransformFilter_Seeking_QueryInterface,
121 TransformFilter_Seeking_AddRef,
122 TransformFilter_Seeking_Release,
123 MediaSeekingImpl_GetCapabilities,
124 MediaSeekingImpl_CheckCapabilities,
125 MediaSeekingImpl_IsFormatSupported,
126 MediaSeekingImpl_QueryPreferredFormat,
127 MediaSeekingImpl_GetTimeFormat,
128 MediaSeekingImpl_IsUsingTimeFormat,
129 MediaSeekingImpl_SetTimeFormat,
130 MediaSeekingImpl_GetDuration,
131 MediaSeekingImpl_GetStopPosition,
132 MediaSeekingImpl_GetCurrentPosition,
133 MediaSeekingImpl_ConvertTimeFormat,
134 MediaSeekingImpl_SetPositions,
135 MediaSeekingImpl_GetPositions,
136 MediaSeekingImpl_GetAvailable,
137 MediaSeekingImpl_SetRate,
138 MediaSeekingImpl_GetRate,
139 MediaSeekingImpl_GetPreroll
142 static HRESULT TransformFilter_ChangeCurrent(IBaseFilter *iface)
144 FIXME("(%p) filter hasn't implemented current position change!\n", iface);
145 return S_OK;
148 static HRESULT TransformFilter_ChangeStop(IBaseFilter *iface)
150 FIXME("(%p) filter hasn't implemented stop position change!\n", iface);
151 return S_OK;
154 static HRESULT TransformFilter_ChangeRate(IBaseFilter *iface)
156 FIXME("(%p) filter hasn't implemented rate change!\n", iface);
157 return S_OK;
160 HRESULT TransformFilter_Create(TransformFilterImpl* pTransformFilter, const CLSID* pClsid, const TransformFuncsTable* pFuncsTable, CHANGEPROC stop, CHANGEPROC current, CHANGEPROC rate)
162 HRESULT hr;
163 PIN_INFO piInput;
164 PIN_INFO piOutput;
166 /* pTransformFilter is already allocated */
167 pTransformFilter->clsid = *pClsid;
168 pTransformFilter->pFuncsTable = pFuncsTable;
170 pTransformFilter->lpVtbl = &TransformFilter_Vtbl;
172 pTransformFilter->refCount = 1;
173 InitializeCriticalSection(&pTransformFilter->csFilter);
174 pTransformFilter->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TransformFilterImpl.csFilter");
175 pTransformFilter->state = State_Stopped;
176 pTransformFilter->pClock = NULL;
177 ZeroMemory(&pTransformFilter->filterInfo, sizeof(FILTER_INFO));
179 pTransformFilter->ppPins = CoTaskMemAlloc(2 * sizeof(IPin *));
181 /* construct input pin */
182 piInput.dir = PINDIR_INPUT;
183 piInput.pFilter = (IBaseFilter *)pTransformFilter;
184 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
185 piOutput.dir = PINDIR_OUTPUT;
186 piOutput.pFilter = (IBaseFilter *)pTransformFilter;
187 lstrcpynW(piOutput.achName, wcsOutputPinName, sizeof(piOutput.achName) / sizeof(piOutput.achName[0]));
189 hr = InputPin_Construct(&TransformFilter_InputPin_Vtbl, &piInput, TransformFilter_Sample, pTransformFilter, TransformFilter_Input_QueryAccept, NULL, &pTransformFilter->csFilter, &pTransformFilter->ppPins[0]);
191 if (SUCCEEDED(hr))
193 ALLOCATOR_PROPERTIES props;
194 props.cbAlign = 1;
195 props.cbPrefix = 0;
196 props.cbBuffer = 0; /* Will be updated at connection time */
197 props.cBuffers = 2;
199 hr = OutputPin_Construct(&TransformFilter_OutputPin_Vtbl, sizeof(OutputPin), &piOutput, &props, pTransformFilter, TransformFilter_Output_QueryAccept, &pTransformFilter->csFilter, &pTransformFilter->ppPins[1]);
201 if (FAILED(hr))
202 ERR("Cannot create output pin (%x)\n", hr);
203 else
205 if (!stop)
206 stop = TransformFilter_ChangeStop;
207 if (!current)
208 current = TransformFilter_ChangeCurrent;
209 if (!rate)
210 rate = TransformFilter_ChangeRate;
212 MediaSeekingImpl_Init((IBaseFilter*)pTransformFilter, stop, current, rate, &pTransformFilter->mediaSeeking, &pTransformFilter->csFilter);
213 pTransformFilter->mediaSeeking.lpVtbl = &TransformFilter_Seeking_Vtbl;
216 else
218 CoTaskMemFree(pTransformFilter->ppPins);
219 pTransformFilter->csFilter.DebugInfo->Spare[0] = 0;
220 DeleteCriticalSection(&pTransformFilter->csFilter);
221 CoTaskMemFree(pTransformFilter);
224 return hr;
227 static HRESULT WINAPI TransformFilter_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
229 TransformFilterImpl *This = (TransformFilterImpl *)iface;
230 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
232 *ppv = NULL;
234 if (IsEqualIID(riid, &IID_IUnknown))
235 *ppv = (LPVOID)This;
236 else if (IsEqualIID(riid, &IID_IPersist))
237 *ppv = (LPVOID)This;
238 else if (IsEqualIID(riid, &IID_IMediaFilter))
239 *ppv = (LPVOID)This;
240 else if (IsEqualIID(riid, &IID_IBaseFilter))
241 *ppv = (LPVOID)This;
242 else if (IsEqualIID(riid, &IID_IMediaSeeking))
243 *ppv = &This->mediaSeeking;
245 if (*ppv)
247 IUnknown_AddRef((IUnknown *)(*ppv));
248 return S_OK;
251 if (!IsEqualIID(riid, &IID_IPin))
252 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
254 return E_NOINTERFACE;
257 static ULONG WINAPI TransformFilter_AddRef(IBaseFilter * iface)
259 TransformFilterImpl *This = (TransformFilterImpl *)iface;
260 ULONG refCount = InterlockedIncrement(&This->refCount);
262 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
264 return refCount;
267 static ULONG WINAPI TransformFilter_Release(IBaseFilter * iface)
269 TransformFilterImpl *This = (TransformFilterImpl *)iface;
270 ULONG refCount = InterlockedDecrement(&This->refCount);
272 TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
274 if (!refCount)
276 ULONG i;
278 if (This->pClock)
279 IReferenceClock_Release(This->pClock);
281 for (i = 0; i < 2; i++)
283 IPin *pConnectedTo;
285 if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[i], &pConnectedTo)))
287 IPin_Disconnect(pConnectedTo);
288 IPin_Release(pConnectedTo);
290 IPin_Disconnect(This->ppPins[i]);
292 IPin_Release(This->ppPins[i]);
295 CoTaskMemFree(This->ppPins);
296 This->lpVtbl = NULL;
298 This->csFilter.DebugInfo->Spare[0] = 0;
299 DeleteCriticalSection(&This->csFilter);
301 TRACE("Destroying transform filter\n");
302 CoTaskMemFree(This);
304 return 0;
306 else
307 return refCount;
310 /** IPersist methods **/
312 static HRESULT WINAPI TransformFilter_GetClassID(IBaseFilter * iface, CLSID * pClsid)
314 TransformFilterImpl *This = (TransformFilterImpl *)iface;
316 TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
318 *pClsid = This->clsid;
320 return S_OK;
323 /** IMediaFilter methods **/
325 static HRESULT WINAPI TransformFilter_Stop(IBaseFilter * iface)
327 TransformFilterImpl *This = (TransformFilterImpl *)iface;
329 TRACE("(%p/%p)\n", This, iface);
331 EnterCriticalSection(&This->csFilter);
333 This->state = State_Stopped;
334 if (This->pFuncsTable->pfnProcessEnd)
335 This->pFuncsTable->pfnProcessEnd(This);
337 LeaveCriticalSection(&This->csFilter);
339 return S_OK;
342 static HRESULT WINAPI TransformFilter_Pause(IBaseFilter * iface)
344 TransformFilterImpl *This = (TransformFilterImpl *)iface;
346 TRACE("(%p/%p)->()\n", This, iface);
348 EnterCriticalSection(&This->csFilter);
350 if (This->state == State_Stopped)
351 ((InputPin *)This->ppPins[0])->end_of_stream = 0;
353 This->state = State_Paused;
355 LeaveCriticalSection(&This->csFilter);
357 return S_OK;
360 static HRESULT WINAPI TransformFilter_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
362 HRESULT hr = S_OK;
363 TransformFilterImpl *This = (TransformFilterImpl *)iface;
365 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
367 EnterCriticalSection(&This->csFilter);
369 if (This->state == State_Stopped)
370 ((InputPin *)This->ppPins[0])->end_of_stream = 0;
372 This->rtStreamStart = tStart;
373 This->state = State_Running;
374 OutputPin_CommitAllocator((OutputPin *)This->ppPins[1]);
375 if (This->pFuncsTable->pfnProcessBegin)
376 This->pFuncsTable->pfnProcessBegin(This);
378 LeaveCriticalSection(&This->csFilter);
380 return hr;
383 static HRESULT WINAPI TransformFilter_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
385 TransformFilterImpl *This = (TransformFilterImpl *)iface;
387 TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
389 EnterCriticalSection(&This->csFilter);
391 *pState = This->state;
393 LeaveCriticalSection(&This->csFilter);
395 return S_OK;
398 static HRESULT WINAPI TransformFilter_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
400 TransformFilterImpl *This = (TransformFilterImpl *)iface;
402 TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
404 EnterCriticalSection(&This->csFilter);
406 if (This->pClock)
407 IReferenceClock_Release(This->pClock);
408 This->pClock = pClock;
409 if (This->pClock)
410 IReferenceClock_AddRef(This->pClock);
412 LeaveCriticalSection(&This->csFilter);
414 return S_OK;
417 static HRESULT WINAPI TransformFilter_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
419 TransformFilterImpl *This = (TransformFilterImpl *)iface;
421 TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
423 EnterCriticalSection(&This->csFilter);
425 *ppClock = This->pClock;
426 IReferenceClock_AddRef(This->pClock);
428 LeaveCriticalSection(&This->csFilter);
430 return S_OK;
433 /** IBaseFilter implementation **/
435 static HRESULT WINAPI TransformFilter_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
437 ENUMPINDETAILS epd;
438 TransformFilterImpl *This = (TransformFilterImpl *)iface;
440 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
442 epd.cPins = 2; /* input and output pins */
443 epd.ppPins = This->ppPins;
444 return IEnumPinsImpl_Construct(&epd, ppEnum);
447 static HRESULT WINAPI TransformFilter_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
449 TransformFilterImpl *This = (TransformFilterImpl *)iface;
451 TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
453 return E_NOTIMPL;
456 static HRESULT WINAPI TransformFilter_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
458 TransformFilterImpl *This = (TransformFilterImpl *)iface;
460 TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
462 strcpyW(pInfo->achName, This->filterInfo.achName);
463 pInfo->pGraph = This->filterInfo.pGraph;
465 if (pInfo->pGraph)
466 IFilterGraph_AddRef(pInfo->pGraph);
468 return S_OK;
471 static HRESULT WINAPI TransformFilter_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
473 HRESULT hr = S_OK;
474 TransformFilterImpl *This = (TransformFilterImpl *)iface;
476 TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
478 EnterCriticalSection(&This->csFilter);
480 if (pName)
481 strcpyW(This->filterInfo.achName, pName);
482 else
483 *This->filterInfo.achName = '\0';
484 This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
486 LeaveCriticalSection(&This->csFilter);
488 return hr;
491 static HRESULT WINAPI TransformFilter_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
493 TransformFilterImpl *This = (TransformFilterImpl *)iface;
494 TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
495 return E_NOTIMPL;
498 static const IBaseFilterVtbl TransformFilter_Vtbl =
500 TransformFilter_QueryInterface,
501 TransformFilter_AddRef,
502 TransformFilter_Release,
503 TransformFilter_GetClassID,
504 TransformFilter_Stop,
505 TransformFilter_Pause,
506 TransformFilter_Run,
507 TransformFilter_GetState,
508 TransformFilter_SetSyncSource,
509 TransformFilter_GetSyncSource,
510 TransformFilter_EnumPins,
511 TransformFilter_FindPin,
512 TransformFilter_QueryFilterInfo,
513 TransformFilter_JoinFilterGraph,
514 TransformFilter_QueryVendorInfo
517 static HRESULT WINAPI TransformFilter_InputPin_EndOfStream(IPin * iface)
519 InputPin* This = (InputPin*) iface;
520 TransformFilterImpl* pTransform;
521 IPin* ppin;
522 HRESULT hr;
524 TRACE("(%p)->()\n", iface);
526 /* Since we process samples synchronously, just forward notification downstream */
527 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
528 if (!pTransform)
529 hr = E_FAIL;
530 else
531 hr = IPin_ConnectedTo(pTransform->ppPins[1], &ppin);
532 if (SUCCEEDED(hr))
534 hr = IPin_EndOfStream(ppin);
535 IPin_Release(ppin);
538 if (FAILED(hr))
539 ERR("%x\n", hr);
540 return hr;
543 static HRESULT WINAPI TransformFilter_InputPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt)
545 InputPin* This = (InputPin*) iface;
546 TransformFilterImpl* pTransform;
547 HRESULT hr;
549 TRACE("(%p)->(%p, %p)\n", iface, pReceivePin, pmt);
551 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
553 hr = pTransform->pFuncsTable->pfnConnectInput(pTransform, pmt);
554 if (SUCCEEDED(hr))
556 hr = InputPin_ReceiveConnection(iface, pReceivePin, pmt);
557 if (FAILED(hr))
558 pTransform->pFuncsTable->pfnCleanup(pTransform);
561 return hr;
564 static HRESULT WINAPI TransformFilter_InputPin_Disconnect(IPin * iface)
566 InputPin* This = (InputPin*) iface;
567 TransformFilterImpl* pTransform;
569 TRACE("(%p)->()\n", iface);
571 pTransform = (TransformFilterImpl*)This->pin.pinInfo.pFilter;
572 pTransform->pFuncsTable->pfnCleanup(pTransform);
574 return IPinImpl_Disconnect(iface);
577 static const IPinVtbl TransformFilter_InputPin_Vtbl =
579 InputPin_QueryInterface,
580 IPinImpl_AddRef,
581 InputPin_Release,
582 InputPin_Connect,
583 TransformFilter_InputPin_ReceiveConnection,
584 TransformFilter_InputPin_Disconnect,
585 IPinImpl_ConnectedTo,
586 IPinImpl_ConnectionMediaType,
587 IPinImpl_QueryPinInfo,
588 IPinImpl_QueryDirection,
589 IPinImpl_QueryId,
590 IPinImpl_QueryAccept,
591 IPinImpl_EnumMediaTypes,
592 IPinImpl_QueryInternalConnections,
593 TransformFilter_InputPin_EndOfStream,
594 InputPin_BeginFlush,
595 InputPin_EndFlush,
596 InputPin_NewSegment
599 static HRESULT WINAPI TransformFilter_Output_EnumMediaTypes(IPin * iface, IEnumMediaTypes ** ppEnum)
601 IPinImpl *This = (IPinImpl *)iface;
602 ENUMMEDIADETAILS emd;
604 TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
606 emd.cMediaTypes = 1;
607 emd.pMediaTypes = &This->mtCurrent;
609 return IEnumMediaTypesImpl_Construct(&emd, ppEnum);
612 static const IPinVtbl TransformFilter_OutputPin_Vtbl =
614 OutputPin_QueryInterface,
615 IPinImpl_AddRef,
616 OutputPin_Release,
617 OutputPin_Connect,
618 OutputPin_ReceiveConnection,
619 OutputPin_Disconnect,
620 IPinImpl_ConnectedTo,
621 IPinImpl_ConnectionMediaType,
622 IPinImpl_QueryPinInfo,
623 IPinImpl_QueryDirection,
624 IPinImpl_QueryId,
625 IPinImpl_QueryAccept,
626 TransformFilter_Output_EnumMediaTypes,
627 IPinImpl_QueryInternalConnections,
628 OutputPin_EndOfStream,
629 OutputPin_BeginFlush,
630 OutputPin_EndFlush,
631 OutputPin_NewSegment
634 static const IMemInputPinVtbl MemInputPin_Vtbl =
636 MemInputPin_QueryInterface,
637 MemInputPin_AddRef,
638 MemInputPin_Release,
639 MemInputPin_GetAllocator,
640 MemInputPin_NotifyAllocator,
641 MemInputPin_GetAllocatorRequirements,
642 MemInputPin_Receive,
643 MemInputPin_ReceiveMultiple,
644 MemInputPin_ReceiveCanBlock