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