winex11: add owned windows to taskbar if owner is not mapped
[wine] / dlls / quartz / nullrenderer.c
1 /*
2  * Null Renderer (Promiscuous, not rendering anything at all!)
3  *
4  * Copyright 2004 Christian Costa
5  * Copyright 2008 Maarten Lankhorst
6  *
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.
11  *
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.
16  *
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
20  */
21
22 #include "config.h"
23
24 #define NONAMELESSSTRUCT
25 #define NONAMELESSUNION
26 #include "quartz_private.h"
27 #include "control_private.h"
28 #include "pin.h"
29
30 #include "uuids.h"
31 #include "vfwmsgs.h"
32 #include "amvideo.h"
33 #include "windef.h"
34 #include "winbase.h"
35 #include "dshow.h"
36 #include "evcode.h"
37 #include "strmif.h"
38 #include "ddraw.h"
39
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
44
45 static const WCHAR wcsInputPinName[] = {'i','n','p','u','t',' ','p','i','n',0};
46
47 static const IBaseFilterVtbl NullRenderer_Vtbl;
48 static const IUnknownVtbl IInner_VTable;
49 static const IPinVtbl NullRenderer_InputPin_Vtbl;
50
51 typedef struct NullRendererImpl
52 {
53     const IBaseFilterVtbl * lpVtbl;
54     const IUnknownVtbl * IInner_vtbl;
55
56     LONG refCount;
57     CRITICAL_SECTION csFilter;
58     FILTER_STATE state;
59     REFERENCE_TIME rtStreamStart;
60     IReferenceClock * pClock;
61     FILTER_INFO filterInfo;
62
63     InputPin *pInputPin;
64     IPin ** ppPins;
65     IUnknown * pUnkOuter;
66     BOOL bUnkOuterValid;
67     BOOL bAggregatable;
68     MediaSeekingImpl mediaSeeking;
69 } NullRendererImpl;
70
71 static const IMemInputPinVtbl MemInputPin_Vtbl =
72 {
73     MemInputPin_QueryInterface,
74     MemInputPin_AddRef,
75     MemInputPin_Release,
76     MemInputPin_GetAllocator,
77     MemInputPin_NotifyAllocator,
78     MemInputPin_GetAllocatorRequirements,
79     MemInputPin_Receive,
80     MemInputPin_ReceiveMultiple,
81     MemInputPin_ReceiveCanBlock
82 };
83
84 static HRESULT NullRenderer_Sample(LPVOID iface, IMediaSample * pSample)
85 {
86     LPBYTE pbSrcStream = NULL;
87     long cbSrcStream = 0;
88     REFERENCE_TIME tStart, tStop;
89     HRESULT hr;
90
91     TRACE("%p %p\n", iface, pSample);
92
93     hr = IMediaSample_GetPointer(pSample, &pbSrcStream);
94     if (FAILED(hr))
95     {
96         ERR("Cannot get pointer to sample data (%x)\n", hr);
97         return hr;
98     }
99
100     hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
101     if (FAILED(hr))
102         ERR("Cannot get sample time (%x)\n", hr);
103
104     cbSrcStream = IMediaSample_GetActualDataLength(pSample);
105
106     TRACE("val %p %ld\n", pbSrcStream, cbSrcStream);
107
108     return S_OK;
109 }
110
111 static HRESULT NullRenderer_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
112 {
113     TRACE("Not a stub!\n");
114     return S_OK;
115 }
116
117 static inline NullRendererImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
118 {
119     return (NullRendererImpl *)((char*)iface - FIELD_OFFSET(NullRendererImpl, mediaSeeking.lpVtbl));
120 }
121
122 static HRESULT WINAPI NullRendererImpl_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv)
123 {
124     NullRendererImpl *This = impl_from_IMediaSeeking(iface);
125
126     return IUnknown_QueryInterface((IUnknown *)This, riid, ppv);
127 }
128
129 static ULONG WINAPI NullRendererImpl_Seeking_AddRef(IMediaSeeking * iface)
130 {
131     NullRendererImpl *This = impl_from_IMediaSeeking(iface);
132
133     return IUnknown_AddRef((IUnknown *)This);
134 }
135
136 static ULONG WINAPI NullRendererImpl_Seeking_Release(IMediaSeeking * iface)
137 {
138     NullRendererImpl *This = impl_from_IMediaSeeking(iface);
139
140     return IUnknown_Release((IUnknown *)This);
141 }
142
143 static const IMediaSeekingVtbl TransformFilter_Seeking_Vtbl =
144 {
145     NullRendererImpl_Seeking_QueryInterface,
146     NullRendererImpl_Seeking_AddRef,
147     NullRendererImpl_Seeking_Release,
148     MediaSeekingImpl_GetCapabilities,
149     MediaSeekingImpl_CheckCapabilities,
150     MediaSeekingImpl_IsFormatSupported,
151     MediaSeekingImpl_QueryPreferredFormat,
152     MediaSeekingImpl_GetTimeFormat,
153     MediaSeekingImpl_IsUsingTimeFormat,
154     MediaSeekingImpl_SetTimeFormat,
155     MediaSeekingImpl_GetDuration,
156     MediaSeekingImpl_GetStopPosition,
157     MediaSeekingImpl_GetCurrentPosition,
158     MediaSeekingImpl_ConvertTimeFormat,
159     MediaSeekingImpl_SetPositions,
160     MediaSeekingImpl_GetPositions,
161     MediaSeekingImpl_GetAvailable,
162     MediaSeekingImpl_SetRate,
163     MediaSeekingImpl_GetRate,
164     MediaSeekingImpl_GetPreroll
165 };
166
167 static HRESULT NullRendererImpl_Change(IBaseFilter *iface)
168 {
169     TRACE("(%p)\n", iface);
170     return S_OK;
171 }
172
173 HRESULT NullRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv)
174 {
175     HRESULT hr;
176     PIN_INFO piInput;
177     NullRendererImpl * pNullRenderer;
178
179     TRACE("(%p, %p)\n", pUnkOuter, ppv);
180
181     *ppv = NULL;
182
183     pNullRenderer = CoTaskMemAlloc(sizeof(NullRendererImpl));
184     pNullRenderer->pUnkOuter = pUnkOuter;
185     pNullRenderer->bUnkOuterValid = FALSE;
186     pNullRenderer->bAggregatable = FALSE;
187     pNullRenderer->IInner_vtbl = &IInner_VTable;
188
189     pNullRenderer->lpVtbl = &NullRenderer_Vtbl;
190     pNullRenderer->refCount = 1;
191     InitializeCriticalSection(&pNullRenderer->csFilter);
192     pNullRenderer->csFilter.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": NullRendererImpl.csFilter");
193     pNullRenderer->state = State_Stopped;
194     pNullRenderer->pClock = NULL;
195     ZeroMemory(&pNullRenderer->filterInfo, sizeof(FILTER_INFO));
196
197     pNullRenderer->ppPins = CoTaskMemAlloc(1 * sizeof(IPin *));
198
199     /* construct input pin */
200     piInput.dir = PINDIR_INPUT;
201     piInput.pFilter = (IBaseFilter *)pNullRenderer;
202     lstrcpynW(piInput.achName, wcsInputPinName, sizeof(piInput.achName) / sizeof(piInput.achName[0]));
203
204     hr = InputPin_Construct(&NullRenderer_InputPin_Vtbl, &piInput, NullRenderer_Sample, (LPVOID)pNullRenderer, NullRenderer_QueryAccept, NULL, &pNullRenderer->csFilter, (IPin **)&pNullRenderer->pInputPin);
205
206     if (SUCCEEDED(hr))
207     {
208         pNullRenderer->ppPins[0] = (IPin *)pNullRenderer->pInputPin;
209         MediaSeekingImpl_Init((IBaseFilter*)pNullRenderer, NullRendererImpl_Change, NullRendererImpl_Change, NullRendererImpl_Change, &pNullRenderer->mediaSeeking, &pNullRenderer->csFilter);
210         pNullRenderer->mediaSeeking.lpVtbl = &TransformFilter_Seeking_Vtbl;
211
212         *ppv = (LPVOID)pNullRenderer;
213     }
214     else
215     {
216         CoTaskMemFree(pNullRenderer->ppPins);
217         pNullRenderer->csFilter.DebugInfo->Spare[0] = 0;
218         DeleteCriticalSection(&pNullRenderer->csFilter);
219         CoTaskMemFree(pNullRenderer);
220     }
221
222     return hr;
223 }
224
225 static HRESULT WINAPI NullRendererInner_QueryInterface(IUnknown * iface, REFIID riid, LPVOID * ppv)
226 {
227     ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
228     TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv);
229
230     if (This->bAggregatable)
231         This->bUnkOuterValid = TRUE;
232
233     *ppv = NULL;
234
235     if (IsEqualIID(riid, &IID_IUnknown))
236         *ppv = (LPVOID)&(This->IInner_vtbl);
237     else if (IsEqualIID(riid, &IID_IPersist))
238         *ppv = (LPVOID)This;
239     else if (IsEqualIID(riid, &IID_IMediaFilter))
240         *ppv = (LPVOID)This;
241     else if (IsEqualIID(riid, &IID_IBaseFilter))
242         *ppv = (LPVOID)This;
243     else if (IsEqualIID(riid, &IID_IMediaSeeking))
244         *ppv = &This->mediaSeeking;
245
246     if (*ppv)
247     {
248         IUnknown_AddRef((IUnknown *)(*ppv));
249         return S_OK;
250     }
251
252     if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow))
253         FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
254
255     return E_NOINTERFACE;
256 }
257
258 static ULONG WINAPI NullRendererInner_AddRef(IUnknown * iface)
259 {
260     ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
261     ULONG refCount = InterlockedIncrement(&This->refCount);
262
263     TRACE("(%p/%p)->() AddRef from %d\n", This, iface, refCount - 1);
264
265     return refCount;
266 }
267
268 static ULONG WINAPI NullRendererInner_Release(IUnknown * iface)
269 {
270     ICOM_THIS_MULTI(NullRendererImpl, IInner_vtbl, iface);
271     ULONG refCount = InterlockedDecrement(&This->refCount);
272
273     TRACE("(%p/%p)->() Release from %d\n", This, iface, refCount + 1);
274
275     if (!refCount)
276     {
277         IPin *pConnectedTo;
278
279         if (This->pClock)
280             IReferenceClock_Release(This->pClock);
281
282         if (SUCCEEDED(IPin_ConnectedTo(This->ppPins[0], &pConnectedTo)))
283         {
284             IPin_Disconnect(pConnectedTo);
285             IPin_Release(pConnectedTo);
286         }
287         IPin_Disconnect(This->ppPins[0]);
288         IPin_Release(This->ppPins[0]);
289
290         CoTaskMemFree(This->ppPins);
291         This->lpVtbl = NULL;
292
293         This->csFilter.DebugInfo->Spare[0] = 0;
294         DeleteCriticalSection(&This->csFilter);
295
296         TRACE("Destroying Null Renderer\n");
297         CoTaskMemFree(This);
298         return 0;
299     }
300     else
301         return refCount;
302 }
303
304 static const IUnknownVtbl IInner_VTable =
305 {
306     NullRendererInner_QueryInterface,
307     NullRendererInner_AddRef,
308     NullRendererInner_Release
309 };
310
311 static HRESULT WINAPI NullRenderer_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv)
312 {
313     NullRendererImpl *This = (NullRendererImpl *)iface;
314
315     if (This->bAggregatable)
316         This->bUnkOuterValid = TRUE;
317
318     if (This->pUnkOuter)
319     {
320         if (This->bAggregatable)
321             return IUnknown_QueryInterface(This->pUnkOuter, riid, ppv);
322
323         if (IsEqualIID(riid, &IID_IUnknown))
324         {
325             HRESULT hr;
326
327             IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
328             hr = IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
329             IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
330             This->bAggregatable = TRUE;
331             return hr;
332         }
333
334         *ppv = NULL;
335         return E_NOINTERFACE;
336     }
337
338     return IUnknown_QueryInterface((IUnknown *)&(This->IInner_vtbl), riid, ppv);
339 }
340
341 static ULONG WINAPI NullRenderer_AddRef(IBaseFilter * iface)
342 {
343     NullRendererImpl *This = (NullRendererImpl *)iface;
344
345     if (This->pUnkOuter && This->bUnkOuterValid)
346         return IUnknown_AddRef(This->pUnkOuter);
347     return IUnknown_AddRef((IUnknown *)&(This->IInner_vtbl));
348 }
349
350 static ULONG WINAPI NullRenderer_Release(IBaseFilter * iface)
351 {
352     NullRendererImpl *This = (NullRendererImpl *)iface;
353
354     if (This->pUnkOuter && This->bUnkOuterValid)
355         return IUnknown_Release(This->pUnkOuter);
356     return IUnknown_Release((IUnknown *)&(This->IInner_vtbl));
357 }
358
359 /** IPersist methods **/
360
361 static HRESULT WINAPI NullRenderer_GetClassID(IBaseFilter * iface, CLSID * pClsid)
362 {
363     NullRendererImpl *This = (NullRendererImpl *)iface;
364
365     TRACE("(%p/%p)->(%p)\n", This, iface, pClsid);
366
367     *pClsid = CLSID_NullRenderer;
368
369     return S_OK;
370 }
371
372 /** IMediaFilter methods **/
373
374 static HRESULT WINAPI NullRenderer_Stop(IBaseFilter * iface)
375 {
376     NullRendererImpl *This = (NullRendererImpl *)iface;
377
378     TRACE("(%p/%p)->()\n", This, iface);
379
380     EnterCriticalSection(&This->csFilter);
381     {
382         This->state = State_Stopped;
383     }
384     LeaveCriticalSection(&This->csFilter);
385
386     return S_OK;
387 }
388
389 static HRESULT WINAPI NullRenderer_Pause(IBaseFilter * iface)
390 {
391     NullRendererImpl *This = (NullRendererImpl *)iface;
392
393     TRACE("(%p/%p)->()\n", This, iface);
394
395     EnterCriticalSection(&This->csFilter);
396     {
397         if (This->state == State_Stopped)
398             This->pInputPin->end_of_stream = 0;
399         This->state = State_Paused;
400     }
401     LeaveCriticalSection(&This->csFilter);
402
403     return S_OK;
404 }
405
406 static HRESULT WINAPI NullRenderer_Run(IBaseFilter * iface, REFERENCE_TIME tStart)
407 {
408     NullRendererImpl *This = (NullRendererImpl *)iface;
409
410     TRACE("(%p/%p)->(%s)\n", This, iface, wine_dbgstr_longlong(tStart));
411
412     EnterCriticalSection(&This->csFilter);
413     {
414         This->rtStreamStart = tStart;
415         This->state = State_Running;
416         This->pInputPin->end_of_stream = 0;
417     }
418     LeaveCriticalSection(&This->csFilter);
419
420     return S_OK;
421 }
422
423 static HRESULT WINAPI NullRenderer_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState)
424 {
425     NullRendererImpl *This = (NullRendererImpl *)iface;
426
427     TRACE("(%p/%p)->(%d, %p)\n", This, iface, dwMilliSecsTimeout, pState);
428
429     EnterCriticalSection(&This->csFilter);
430     {
431         *pState = This->state;
432     }
433     LeaveCriticalSection(&This->csFilter);
434
435     return S_OK;
436 }
437
438 static HRESULT WINAPI NullRenderer_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock)
439 {
440     NullRendererImpl *This = (NullRendererImpl *)iface;
441
442     TRACE("(%p/%p)->(%p)\n", This, iface, pClock);
443
444     EnterCriticalSection(&This->csFilter);
445     {
446         if (This->pClock)
447             IReferenceClock_Release(This->pClock);
448         This->pClock = pClock;
449         if (This->pClock)
450             IReferenceClock_AddRef(This->pClock);
451     }
452     LeaveCriticalSection(&This->csFilter);
453
454     return S_OK;
455 }
456
457 static HRESULT WINAPI NullRenderer_GetSyncSource(IBaseFilter * iface, IReferenceClock **ppClock)
458 {
459     NullRendererImpl *This = (NullRendererImpl *)iface;
460
461     TRACE("(%p/%p)->(%p)\n", This, iface, ppClock);
462
463     EnterCriticalSection(&This->csFilter);
464     {
465         *ppClock = This->pClock;
466         IReferenceClock_AddRef(This->pClock);
467     }
468     LeaveCriticalSection(&This->csFilter);
469
470     return S_OK;
471 }
472
473 /** IBaseFilter implementation **/
474
475 static HRESULT WINAPI NullRenderer_EnumPins(IBaseFilter * iface, IEnumPins **ppEnum)
476 {
477     ENUMPINDETAILS epd;
478     NullRendererImpl *This = (NullRendererImpl *)iface;
479
480     TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum);
481
482     epd.cPins = 1; /* input pin */
483     epd.ppPins = This->ppPins;
484     return IEnumPinsImpl_Construct(&epd, ppEnum);
485 }
486
487 static HRESULT WINAPI NullRenderer_FindPin(IBaseFilter * iface, LPCWSTR Id, IPin **ppPin)
488 {
489     NullRendererImpl *This = (NullRendererImpl *)iface;
490
491     TRACE("(%p/%p)->(%p,%p)\n", This, iface, debugstr_w(Id), ppPin);
492
493     FIXME("NullRenderer::FindPin(...)\n");
494
495     /* FIXME: critical section */
496
497     return E_NOTIMPL;
498 }
499
500 static HRESULT WINAPI NullRenderer_QueryFilterInfo(IBaseFilter * iface, FILTER_INFO *pInfo)
501 {
502     NullRendererImpl *This = (NullRendererImpl *)iface;
503
504     TRACE("(%p/%p)->(%p)\n", This, iface, pInfo);
505
506     strcpyW(pInfo->achName, This->filterInfo.achName);
507     pInfo->pGraph = This->filterInfo.pGraph;
508
509     if (pInfo->pGraph)
510         IFilterGraph_AddRef(pInfo->pGraph);
511
512     return S_OK;
513 }
514
515 static HRESULT WINAPI NullRenderer_JoinFilterGraph(IBaseFilter * iface, IFilterGraph *pGraph, LPCWSTR pName)
516 {
517     NullRendererImpl *This = (NullRendererImpl *)iface;
518
519     TRACE("(%p/%p)->(%p, %s)\n", This, iface, pGraph, debugstr_w(pName));
520
521     EnterCriticalSection(&This->csFilter);
522     {
523         if (pName)
524             strcpyW(This->filterInfo.achName, pName);
525         else
526             *This->filterInfo.achName = '\0';
527         This->filterInfo.pGraph = pGraph; /* NOTE: do NOT increase ref. count */
528     }
529     LeaveCriticalSection(&This->csFilter);
530
531     return S_OK;
532 }
533
534 static HRESULT WINAPI NullRenderer_QueryVendorInfo(IBaseFilter * iface, LPWSTR *pVendorInfo)
535 {
536     NullRendererImpl *This = (NullRendererImpl *)iface;
537     TRACE("(%p/%p)->(%p)\n", This, iface, pVendorInfo);
538     return E_NOTIMPL;
539 }
540
541 static const IBaseFilterVtbl NullRenderer_Vtbl =
542 {
543     NullRenderer_QueryInterface,
544     NullRenderer_AddRef,
545     NullRenderer_Release,
546     NullRenderer_GetClassID,
547     NullRenderer_Stop,
548     NullRenderer_Pause,
549     NullRenderer_Run,
550     NullRenderer_GetState,
551     NullRenderer_SetSyncSource,
552     NullRenderer_GetSyncSource,
553     NullRenderer_EnumPins,
554     NullRenderer_FindPin,
555     NullRenderer_QueryFilterInfo,
556     NullRenderer_JoinFilterGraph,
557     NullRenderer_QueryVendorInfo
558 };
559
560 static HRESULT WINAPI NullRenderer_InputPin_EndOfStream(IPin * iface)
561 {
562     InputPin* This = (InputPin*)iface;
563     IMediaEventSink* pEventSink;
564     HRESULT hr;
565
566     TRACE("(%p/%p)->()\n", This, iface);
567
568     InputPin_EndOfStream(iface);
569     hr = IFilterGraph_QueryInterface(((NullRendererImpl*)This->pin.pinInfo.pFilter)->filterInfo.pGraph, &IID_IMediaEventSink, (LPVOID*)&pEventSink);
570     if (SUCCEEDED(hr))
571     {
572         hr = IMediaEventSink_Notify(pEventSink, EC_COMPLETE, S_OK, 0);
573         IMediaEventSink_Release(pEventSink);
574     }
575
576     return hr;
577 }
578
579 static const IPinVtbl NullRenderer_InputPin_Vtbl =
580 {
581     InputPin_QueryInterface,
582     IPinImpl_AddRef,
583     InputPin_Release,
584     InputPin_Connect,
585     InputPin_ReceiveConnection,
586     IPinImpl_Disconnect,
587     IPinImpl_ConnectedTo,
588     IPinImpl_ConnectionMediaType,
589     IPinImpl_QueryPinInfo,
590     IPinImpl_QueryDirection,
591     IPinImpl_QueryId,
592     IPinImpl_QueryAccept,
593     IPinImpl_EnumMediaTypes,
594     IPinImpl_QueryInternalConnections,
595     NullRenderer_InputPin_EndOfStream,
596     InputPin_BeginFlush,
597     InputPin_EndFlush,
598     InputPin_NewSegment
599 };