msi: Implement MSIMODIFY_MERGE function in TABLE_modify.
[wine.git] / dlls / quartz / nullrenderer.c
blobf850b40b12319bfa65d55017db457f6afe148bd0
1 /*
2 * Null Renderer (Promiscuous, not rendering anything at all!)
4 * Copyright 2004 Christian Costa
5 * Copyright 2008 Maarten Lankhorst
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 "config.h"
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
26 #include "quartz_private.h"
27 #include "pin.h"
29 #include "uuids.h"
30 #include "vfwmsgs.h"
31 #include "amvideo.h"
32 #include "windef.h"
33 #include "winbase.h"
34 #include "dshow.h"
35 #include "evcode.h"
36 #include "strmif.h"
37 #include "ddraw.h"
39 #include "wine/unicode.h"
40 #include "wine/debug.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
44 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
45 static const WCHAR wcsAltInputPinName[] = {'I','n',0};
47 static const IBaseFilterVtbl NullRenderer_Vtbl;
48 static const IUnknownVtbl IInner_VTable;
49 static const IPinVtbl NullRenderer_InputPin_Vtbl;
50 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl;
52 typedef struct NullRendererImpl
54 BaseFilter filter;
55 const IUnknownVtbl * IInner_vtbl;
56 const IAMFilterMiscFlagsVtbl *IAMFilterMiscFlags_vtbl;
57 IUnknown *seekthru_unk;
59 BaseInputPin *pInputPin;
60 IUnknown * pUnkOuter;
61 BOOL bUnkOuterValid;
62 BOOL bAggregatable;
63 } NullRendererImpl;
65 static HRESULT WINAPI NullRenderer_Receive(BaseInputPin *pin, IMediaSample * pSample)
67 NullRendererImpl *This = ((NullRendererImpl*)pin->pin.pinInfo.pFilter);
68 HRESULT hr = S_OK;
69 REFERENCE_TIME start, stop;
71 TRACE("%p %p\n", pin, pSample);
73 if (SUCCEEDED(IMediaSample_GetMediaTime(pSample, &start, &stop)))
74 RendererPosPassThru_RegisterMediaTime(This->seekthru_unk, start);
75 EnterCriticalSection(&This->filter.csFilter);
76 if (This->pInputPin->flushing || This->pInputPin->end_of_stream)
77 hr = S_FALSE;
78 LeaveCriticalSection(&This->filter.csFilter);
80 return hr;
83 static HRESULT WINAPI NullRenderer_CheckMediaType(BasePin *iface, const AM_MEDIA_TYPE * pmt)
85 TRACE("Not a stub!\n");
86 return S_OK;
89 static IPin* WINAPI NullRenderer_GetPin(BaseFilter *iface, int pos)
91 NullRendererImpl *This = (NullRendererImpl *)iface;
93 if (pos >= 1 || pos < 0)
94 return NULL;
96 IPin_AddRef((IPin *)This->pInputPin);
97 return (IPin *)This->pInputPin;
100 static LONG WINAPI NullRenderer_GetPinCount(BaseFilter *iface)
102 return 1;
105 static const BaseFilterFuncTable BaseFuncTable = {
106 NullRenderer_GetPin,
107 NullRenderer_GetPinCount
110 static const BasePinFuncTable input_BaseFuncTable = {
111 NullRenderer_CheckMediaType,
112 NULL,
113 BasePinImpl_GetMediaTypeVersion,
114 BasePinImpl_GetMediaType
117 static const BaseInputPinFuncTable input_BaseInputFuncTable = {
118 NullRenderer_Receive
122 HRESULT NullRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv)
124 HRESULT hr;
125 PIN_INFO piInput;
126 NullRendererImpl * pNullRenderer;
128 TRACE("(%p, %p)\n", pUnkOuter, ppv);
130 *ppv = NULL;
132 pNullRenderer = CoTaskMemAlloc(sizeof(NullRendererImpl));
133 pNullRenderer->pUnkOuter = pUnkOuter;
134 pNullRenderer->bUnkOuterValid = FALSE;
135 pNullRenderer->bAggregatable = FALSE;
136 pNullRenderer->IInner_vtbl = &IInner_VTable;
137 pNullRenderer->IAMFilterMiscFlags_vtbl = &IAMFilterMiscFlags_Vtbl;
139 BaseFilter_Init(&pNullRenderer->filter, &NullRenderer_Vtbl, &CLSID_NullRenderer, (DWORD_PTR)(__FILE__ ": NullRendererImpl.csFilter"), &BaseFuncTable);
141 /* construct input pin */
142 piInput.dir = PINDIR_INPUT;
143 piInput.pFilter = (IBaseFilter *)pNullRenderer;
144 lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
146 hr = BaseInputPin_Construct(&NullRenderer_InputPin_Vtbl, &piInput, &input_BaseFuncTable, &input_BaseInputFuncTable, &pNullRenderer->filter.csFilter, NULL, (IPin **)&pNullRenderer->pInputPin);
148 if (SUCCEEDED(hr))
150 hr = CreatePosPassThru(pUnkOuter ? pUnkOuter : (IUnknown*)&pNullRenderer->IInner_vtbl, TRUE, (IPin*)pNullRenderer->pInputPin, &pNullRenderer->seekthru_unk);
151 if (FAILED(hr)) {
152 IUnknown_Release((IUnknown*)pNullRenderer);
153 return hr;
155 *ppv = pNullRenderer;
157 else
159 BaseFilterImpl_Release((IBaseFilter*)pNullRenderer);
160 CoTaskMemFree(pNullRenderer);
163 return hr;
166 static HRESULT WINAPI NullRendererInner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
168 ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
169 TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
171 if (This->bAggregatable)
172 This->bUnkOuterValid = TRUE;
174 *ppv = NULL;
176 if (IsEqualIID(riid, &IID_IUnknown))
177 *ppv = &This->IInner_vtbl;
178 else if (IsEqualIID(riid, &IID_IPersist))
179 *ppv = This;
180 else if (IsEqualIID(riid, &IID_IMediaFilter))
181 *ppv = This;
182 else if (IsEqualIID(riid, &IID_IBaseFilter))
183 *ppv = This;
184 else if (IsEqualIID(riid, &IID_IMediaSeeking))
185 return IUnknown_QueryInterface(This->seekthru_unk, riid, ppv);
186 else if (IsEqualIID(riid, &IID_IAMFilterMiscFlags))
187 *ppv = &This->IAMFilterMiscFlags_vtbl;
189 if (*ppv)
191 IUnknown_AddRef((IUnknown *)(*ppv));
192 return S_OK;
195 if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
196 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
198 return E_NOINTERFACE;
201 static ULONG WINAPI NullRendererInner_AddRef(IUnknown * iface)
203 ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
204 ULONG refCount = InterlockedIncrement(&This->filter.refCount);
206 TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
208 return refCount;
211 static ULONG WINAPI NullRendererInner_Release(IUnknown * iface)
213 ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
214 ULONG refCount = InterlockedDecrement(&This->filter.refCount);
216 TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
218 if (!refCount)
220 IPin *pConnectedTo;
222 if (SUCCEEDED(IPin_ConnectedTo((IPin *)This->pInputPin, &pConnectedTo)))
224 IPin_Disconnect(pConnectedTo);
225 IPin_Release(pConnectedTo);
227 IPin_Disconnect((IPin *)This->pInputPin);
228 IPin_Release((IPin *)This->pInputPin);
230 if (This->seekthru_unk)
231 IUnknown_Release(This->seekthru_unk);
233 This->filter.csFilter.DebugInfo->Spare[0] = 0;
234 DeleteCriticalSection(&This->filter.csFilter);
236 TRACE("Destroying Null Renderer\n");
237 CoTaskMemFree(This);
238 return 0;
240 else
241 return refCount;
244 static const IUnknownVtbl IInner_VTable =
246 NullRendererInner_QueryInterface,
247 NullRendererInner_AddRef,
248 NullRendererInner_Release
251 static HRESULT WINAPI NullRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
253 NullRendererImpl *This = (NullRendererImpl *)iface;
255 if (This->bAggregatable)
256 This->bUnkOuterValid = TRUE;
258 if (This->pUnkOuter)
260 if (This->bAggregatable)
261 return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
263 if (IsEqualIID(riid, &IID_IUnknown))
265 HRESULT hr;
267 IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
268 hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
269 IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
270 This->bAggregatable = TRUE;
271 return hr;
274 *ppv = NULL;
275 return E_NOINTERFACE;
278 return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
281 static ULONG WINAPI NullRenderer_AddRef(IBaseFilter * iface)
283 NullRendererImpl *This = (NullRendererImpl *)iface;
285 if (This->pUnkOuter && This->bUnkOuterValid)
286 return IUnknown_AddRef(This->pUnkOuter);
287 return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
290 static ULONG WINAPI NullRenderer_Release(IBaseFilter * iface)
292 NullRendererImpl *This = (NullRendererImpl *)iface;
294 if (This->pUnkOuter && This->bUnkOuterValid)
295 return IUnknown_Release(This->pUnkOuter);
296 return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
299 /** IMediaFilter methods **/
301 static HRESULT WINAPI NullRenderer_Stop(IBaseFilter * iface)
303 NullRendererImpl *This = (NullRendererImpl *)iface;
305 TRACE("(%p/%p)->()\n", This, iface);
307 EnterCriticalSection(&This->filter.csFilter);
309 This->filter.state = State_Stopped;
310 RendererPosPassThru_ResetMediaTime(This->seekthru_unk);
312 LeaveCriticalSection(&This->filter.csFilter);
314 return S_OK;
317 static HRESULT WINAPI NullRenderer_Pause(IBaseFilter * iface)
319 NullRendererImpl *This = (NullRendererImpl *)iface;
321 TRACE("(%p/%p)->()\n", This, iface);
323 EnterCriticalSection(&This->filter.csFilter);
325 if (This->filter.state == State_Stopped)
326 This->pInputPin->end_of_stream = 0;
327 This->filter.state = State_Paused;
329 LeaveCriticalSection(&This->filter.csFilter);
331 return S_OK;
334 static HRESULT WINAPI NullRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
336 HRESULT hr = S_OK;
337 NullRendererImpl *This = (NullRendererImpl *)iface;
339 TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
341 EnterCriticalSection(&This->filter.csFilter);
342 This->filter.rtStreamStart = tStart;
343 if (This->filter.state == State_Running)
344 goto out;
345 if (This->pInputPin->pin.pConnectedTo)
347 This->pInputPin->end_of_stream = 0;
349 else if (This->filter.filterInfo.pGraph)
351 IMediaEventSink *pEventSink;
352 hr = IFilterGraph_QueryInterface(This->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
353 if (SUCCEEDED(hr))
355 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)This);
356 IMediaEventSink_Release(pEventSink);
358 hr = S_OK;
360 if (SUCCEEDED(hr))
361 This->filter.state = State_Running;
362 out:
363 LeaveCriticalSection(&This->filter.csFilter);
365 return hr;
368 /** IBaseFilter implementation **/
370 static HRESULT WINAPI NullRenderer_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
372 NullRendererImpl *This = (NullRendererImpl *)iface;
374 TRACE("(%p/%p)->(%s,%p)\n", This, iface, debugstr_w(Id), ppPin);
376 if (!Id || !ppPin)
377 return E_POINTER;
379 if (!lstrcmpiW(Id,wcsInputPinName) || !lstrcmpiW(Id,wcsAltInputPinName))
381 *ppPin = (IPin *)This->pInputPin;
382 IPin_AddRef(*ppPin);
383 return S_OK;
385 *ppPin = NULL;
386 return VFW_E_NOT_FOUND;
389 static const IBaseFilterVtbl NullRenderer_Vtbl =
391 NullRenderer_QueryInterface,
392 NullRenderer_AddRef,
393 NullRenderer_Release,
394 BaseFilterImpl_GetClassID,
395 NullRenderer_Stop,
396 NullRenderer_Pause,
397 NullRenderer_Run,
398 BaseFilterImpl_GetState,
399 BaseFilterImpl_SetSyncSource,
400 BaseFilterImpl_GetSyncSource,
401 BaseFilterImpl_EnumPins,
402 NullRenderer_FindPin,
403 BaseFilterImpl_QueryFilterInfo,
404 BaseFilterImpl_JoinFilterGraph,
405 BaseFilterImpl_QueryVendorInfo
408 static HRESULT WINAPI NullRenderer_InputPin_EndOfStream(IPin * iface)
410 BaseInputPin* This = (BaseInputPin*)iface;
411 IMediaEventSink* pEventSink;
412 NullRendererImpl *pNull;
413 IFilterGraph *graph;
414 HRESULT hr = S_OK;
416 TRACE("(%p/%p)->()\n", This, iface);
418 BaseInputPinImpl_EndOfStream(iface);
419 pNull = (NullRendererImpl*)This->pin.pinInfo.pFilter;
420 graph = pNull->filter.filterInfo.pGraph;
421 if (graph)
423 hr = IFilterGraph_QueryInterface(pNull->filter.filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
424 if (SUCCEEDED(hr))
426 hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, (LONG_PTR)pNull);
427 IMediaEventSink_Release(pEventSink);
430 RendererPosPassThru_EOS(pNull->seekthru_unk);
432 return hr;
435 static HRESULT WINAPI NullRenderer_InputPin_EndFlush(IPin * iface)
437 BaseInputPin* This = (BaseInputPin*)iface;
438 NullRendererImpl *pNull;
439 HRESULT hr = S_OK;
441 TRACE("(%p/%p)->()\n", This, iface);
443 hr = BaseInputPinImpl_EndOfStream(iface);
444 pNull = (NullRendererImpl*)This->pin.pinInfo.pFilter;
445 RendererPosPassThru_ResetMediaTime(pNull->seekthru_unk);
446 return hr;
449 static const IPinVtbl NullRenderer_InputPin_Vtbl =
451 BaseInputPinImpl_QueryInterface,
452 BasePinImpl_AddRef,
453 BaseInputPinImpl_Release,
454 BaseInputPinImpl_Connect,
455 BaseInputPinImpl_ReceiveConnection,
456 BasePinImpl_Disconnect,
457 BasePinImpl_ConnectedTo,
458 BasePinImpl_ConnectionMediaType,
459 BasePinImpl_QueryPinInfo,
460 BasePinImpl_QueryDirection,
461 BasePinImpl_QueryId,
462 BaseInputPinImpl_QueryAccept,
463 BasePinImpl_EnumMediaTypes,
464 BasePinImpl_QueryInternalConnections,
465 NullRenderer_InputPin_EndOfStream,
466 BaseInputPinImpl_BeginFlush,
467 NullRenderer_InputPin_EndFlush,
468 BaseInputPinImpl_NewSegment
471 static NullRendererImpl *from_IAMFilterMiscFlags(IAMFilterMiscFlags *iface) {
472 return (NullRendererImpl*)((char*)iface - offsetof(NullRendererImpl, IAMFilterMiscFlags_vtbl));
475 static HRESULT WINAPI AMFilterMiscFlags_QueryInterface(IAMFilterMiscFlags *iface, REFIID riid, void **ppv) {
476 NullRendererImpl *This = from_IAMFilterMiscFlags(iface);
477 return IUnknown_QueryInterface((IUnknown*)This, riid, ppv);
480 static ULONG WINAPI AMFilterMiscFlags_AddRef(IAMFilterMiscFlags *iface) {
481 NullRendererImpl *This = from_IAMFilterMiscFlags(iface);
482 return IUnknown_AddRef((IUnknown*)This);
485 static ULONG WINAPI AMFilterMiscFlags_Release(IAMFilterMiscFlags *iface) {
486 NullRendererImpl *This = from_IAMFilterMiscFlags(iface);
487 return IUnknown_Release((IUnknown*)This);
490 static ULONG WINAPI AMFilterMiscFlags_GetMiscFlags(IAMFilterMiscFlags *iface) {
491 return AM_FILTER_MISC_FLAGS_IS_RENDERER;
494 static const IAMFilterMiscFlagsVtbl IAMFilterMiscFlags_Vtbl = {
495 AMFilterMiscFlags_QueryInterface,
496 AMFilterMiscFlags_AddRef,
497 AMFilterMiscFlags_Release,
498 AMFilterMiscFlags_GetMiscFlags