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