When including 'wine/port.h', include it first.
[wine] / dlls / quartz / basefilt.c
1 /*
2  * Implements IBaseFilter. (internal)
3  *
4  * hidenori@a2.ctktv.ne.jp
5  */
6
7 #include "config.h"
8
9 #include "windef.h"
10 #include "winbase.h"
11 #include "wingdi.h"
12 #include "winuser.h"
13 #include "winerror.h"
14 #include "strmif.h"
15 #include "vfwmsgs.h"
16
17 #include "debugtools.h"
18 DEFAULT_DEBUG_CHANNEL(quartz);
19
20 #include "quartz_private.h"
21 #include "basefilt.h"
22 #include "enumunk.h"
23
24
25 /***************************************************************************
26  *
27  *      CBaseFilterImpl::IBaseFilter
28  *
29  */
30
31 static HRESULT WINAPI
32 CBaseFilterImpl_fnQueryInterface(IBaseFilter* iface,REFIID riid,void** ppobj)
33 {
34         ICOM_THIS(CBaseFilterImpl,iface);
35
36         TRACE("(%p)->()\n",This);
37
38         return IUnknown_QueryInterface(This->punkControl,riid,ppobj);
39 }
40
41 static ULONG WINAPI
42 CBaseFilterImpl_fnAddRef(IBaseFilter* iface)
43 {
44         ICOM_THIS(CBaseFilterImpl,iface);
45
46         TRACE("(%p)->()\n",This);
47
48         return IUnknown_AddRef(This->punkControl);
49 }
50
51 static ULONG WINAPI
52 CBaseFilterImpl_fnRelease(IBaseFilter* iface)
53 {
54         ICOM_THIS(CBaseFilterImpl,iface);
55
56         TRACE("(%p)->()\n",This);
57
58         return IUnknown_Release(This->punkControl);
59 }
60
61
62 static HRESULT WINAPI
63 CBaseFilterImpl_fnGetClassID(IBaseFilter* iface,CLSID* pclsid)
64 {
65         ICOM_THIS(CBaseFilterImpl,iface);
66
67         TRACE("(%p)->()\n",This);
68
69         if ( pclsid == NULL )
70                 return E_POINTER;
71
72         memcpy( pclsid, This->pclsidFilter, sizeof(CLSID) );
73
74         return NOERROR;
75 }
76
77 static HRESULT WINAPI
78 CBaseFilterImpl_fnStop(IBaseFilter* iface)
79 {
80         ICOM_THIS(CBaseFilterImpl,iface);
81         HRESULT hr;
82
83         TRACE("(%p)->()\n",This);
84
85         hr = NOERROR;
86
87         EnterCriticalSection( &This->csFilter );
88
89         if ( This->fstate == State_Running )
90         {
91                 if ( This->pHandlers->pOnInactive != NULL )
92                         hr = This->pHandlers->pOnInactive( This );
93                 if ( SUCCEEDED(hr) )
94                         This->fstate = State_Paused;
95         }
96         if ( This->fstate == State_Paused )
97         {
98                 if ( This->pHandlers->pOnStop != NULL )
99                         hr = This->pHandlers->pOnStop( This );
100                 if ( SUCCEEDED(hr) )
101                         This->fstate = State_Stopped;
102         }
103
104         LeaveCriticalSection( &This->csFilter );
105
106         return hr;
107 }
108
109 static HRESULT WINAPI
110 CBaseFilterImpl_fnPause(IBaseFilter* iface)
111 {
112         ICOM_THIS(CBaseFilterImpl,iface);
113         HRESULT hr;
114
115         TRACE("(%p)->()\n",This);
116
117         hr = NOERROR;
118
119         EnterCriticalSection( &This->csFilter );
120         if ( This->fstate != State_Paused )
121         {
122                 if ( This->pHandlers->pOnInactive != NULL )
123                         hr = This->pHandlers->pOnInactive( This );
124                 if ( SUCCEEDED(hr) )
125                         This->fstate = State_Paused;
126         }
127         LeaveCriticalSection( &This->csFilter );
128
129         TRACE("hr = %08lx\n",hr);
130
131         return hr;
132 }
133
134 static HRESULT WINAPI
135 CBaseFilterImpl_fnRun(IBaseFilter* iface,REFERENCE_TIME rtStart)
136 {
137         ICOM_THIS(CBaseFilterImpl,iface);
138         HRESULT hr;
139
140         TRACE("(%p)->()\n",This);
141
142         hr = NOERROR;
143
144         EnterCriticalSection( &This->csFilter );
145
146         This->rtStart = rtStart;
147
148         if ( This->fstate == State_Stopped )
149         {
150                 if ( This->pHandlers->pOnInactive != NULL )
151                         hr = This->pHandlers->pOnInactive( This );
152                 if ( SUCCEEDED(hr) )
153                         This->fstate = State_Paused;
154         }
155         if ( This->fstate == State_Paused )
156         {
157                 if ( This->pHandlers->pOnActive != NULL )
158                         hr = This->pHandlers->pOnActive( This );
159                 if ( SUCCEEDED(hr) )
160                         This->fstate = State_Running;
161         }
162
163         LeaveCriticalSection( &This->csFilter );
164
165         return hr;
166 }
167
168 static HRESULT WINAPI
169 CBaseFilterImpl_fnGetState(IBaseFilter* iface,DWORD dw,FILTER_STATE* pState)
170 {
171         ICOM_THIS(CBaseFilterImpl,iface);
172
173         TRACE("(%p)->(%p)\n",This,pState);
174
175         if ( pState == NULL )
176                 return E_POINTER;
177
178         /* FIXME - ignore 'intermediate state' now */
179
180         EnterCriticalSection( &This->csFilter );
181         TRACE("state %d\n",This->fstate);
182         *pState = This->fstate;
183         LeaveCriticalSection( &This->csFilter );
184
185         return NOERROR;
186 }
187
188 static HRESULT WINAPI
189 CBaseFilterImpl_fnSetSyncSource(IBaseFilter* iface,IReferenceClock* pobjClock)
190 {
191         ICOM_THIS(CBaseFilterImpl,iface);
192
193         TRACE("(%p)->(%p)\n",This,pobjClock);
194
195         EnterCriticalSection( &This->csFilter );
196
197         if ( This->pClock != NULL )
198         {
199                 IReferenceClock_Release( This->pClock );
200                 This->pClock = NULL;
201         }
202
203         This->pClock = pobjClock;
204         if ( pobjClock != NULL )
205                 IReferenceClock_AddRef( pobjClock );
206
207         LeaveCriticalSection( &This->csFilter );
208
209         return NOERROR;
210 }
211
212 static HRESULT WINAPI
213 CBaseFilterImpl_fnGetSyncSource(IBaseFilter* iface,IReferenceClock** ppobjClock)
214 {
215         ICOM_THIS(CBaseFilterImpl,iface);
216         HRESULT hr = VFW_E_NO_CLOCK;
217
218         TRACE("(%p)->(%p)\n",This,ppobjClock);
219
220         if ( ppobjClock == NULL )
221                 return E_POINTER;
222
223         EnterCriticalSection( &This->csFilter );
224
225         *ppobjClock = This->pClock;
226         if ( This->pClock != NULL )
227         {
228                 hr = NOERROR;
229                 IReferenceClock_AddRef( This->pClock );
230         }
231
232         LeaveCriticalSection( &This->csFilter );
233
234         return hr;
235 }
236
237
238 static HRESULT WINAPI
239 CBaseFilterImpl_fnEnumPins(IBaseFilter* iface,IEnumPins** ppenum)
240 {
241         ICOM_THIS(CBaseFilterImpl,iface);
242         HRESULT hr = E_FAIL;
243         QUARTZ_CompList*        pListPins;
244         QUARTZ_CompListItem*    pItem;
245         IUnknown*       punkPin;
246
247         TRACE("(%p)->(%p)\n",This,ppenum);
248
249         if ( ppenum == NULL )
250                 return E_POINTER;
251         *ppenum = NULL;
252
253         pListPins = QUARTZ_CompList_Alloc();
254         if ( pListPins == NULL )
255                 return E_OUTOFMEMORY;
256
257         QUARTZ_CompList_Lock( This->pInPins );
258         QUARTZ_CompList_Lock( This->pOutPins );
259
260         pItem = QUARTZ_CompList_GetFirst( This->pInPins );
261         while ( pItem != NULL )
262         {
263                 punkPin = QUARTZ_CompList_GetItemPtr( pItem );
264                 hr = QUARTZ_CompList_AddComp( pListPins, punkPin, NULL, 0 );
265                 if ( FAILED(hr) )
266                         goto err;
267                 pItem = QUARTZ_CompList_GetNext( This->pInPins, pItem );
268         }
269
270         pItem = QUARTZ_CompList_GetFirst( This->pOutPins );
271         while ( pItem != NULL )
272         {
273                 punkPin = QUARTZ_CompList_GetItemPtr( pItem );
274                 hr = QUARTZ_CompList_AddComp( pListPins, punkPin, NULL, 0 );
275                 if ( FAILED(hr) )
276                         goto err;
277                 pItem = QUARTZ_CompList_GetNext( This->pOutPins, pItem );
278         }
279
280         hr = QUARTZ_CreateEnumUnknown(
281                 &IID_IEnumPins, (void**)ppenum, pListPins );
282 err:
283         QUARTZ_CompList_Unlock( This->pInPins );
284         QUARTZ_CompList_Unlock( This->pOutPins );
285
286         QUARTZ_CompList_Free( pListPins );
287
288         return hr;
289 }
290
291 static HRESULT WINAPI
292 CBaseFilterImpl_fnFindPin(IBaseFilter* iface,LPCWSTR lpwszId,IPin** ppobj)
293 {
294         ICOM_THIS(CBaseFilterImpl,iface);
295
296         FIXME("(%p)->(%s,%p) stub!\n",This,debugstr_w(lpwszId),ppobj);
297
298         if ( ppobj == NULL )
299                 return E_POINTER;
300
301
302
303         return E_NOTIMPL;
304 }
305
306 static HRESULT WINAPI
307 CBaseFilterImpl_fnQueryFilterInfo(IBaseFilter* iface,FILTER_INFO* pfi)
308 {
309         ICOM_THIS(CBaseFilterImpl,iface);
310
311         TRACE("(%p)->(%p)\n",This,pfi);
312
313         if ( pfi == NULL )
314                 return E_POINTER;
315
316         EnterCriticalSection( &This->csFilter );
317
318         if ( This->cbNameGraph <= sizeof(WCHAR)*MAX_FILTER_NAME )
319         {
320                 memcpy( pfi->achName, This->pwszNameGraph, This->cbNameGraph );
321         }
322         else
323         {
324                 memcpy( pfi->achName, This->pwszNameGraph,
325                                 sizeof(WCHAR)*MAX_FILTER_NAME );
326                 pfi->achName[MAX_FILTER_NAME-1] = (WCHAR)0;
327         }
328
329         pfi->pGraph = This->pfg;
330         if ( pfi->pGraph != NULL )
331                 IFilterGraph_AddRef(pfi->pGraph);
332
333         LeaveCriticalSection( &This->csFilter );
334
335         return NOERROR;
336 }
337
338 static HRESULT WINAPI
339 CBaseFilterImpl_fnJoinFilterGraph(IBaseFilter* iface,IFilterGraph* pfg,LPCWSTR lpwszName)
340 {
341         ICOM_THIS(CBaseFilterImpl,iface);
342         HRESULT hr;
343
344         TRACE("(%p)->(%p,%s)\n",This,pfg,debugstr_w(lpwszName));
345
346         EnterCriticalSection( &This->csFilter );
347
348         if ( This->pwszNameGraph != NULL )
349         {
350                 QUARTZ_FreeMem( This->pwszNameGraph );
351                 This->pwszNameGraph = NULL;
352                 This->cbNameGraph = 0;
353         }
354
355         This->pfg = pfg;
356         This->cbNameGraph = sizeof(WCHAR) * (lstrlenW(lpwszName)+1);
357         This->pwszNameGraph = (WCHAR*)QUARTZ_AllocMem( This->cbNameGraph );
358         if ( This->pwszNameGraph == NULL )
359         {
360                 hr = E_OUTOFMEMORY;
361                 goto err;
362         }
363         memcpy( This->pwszNameGraph, lpwszName, This->cbNameGraph );
364
365         hr = NOERROR;
366 err:
367         LeaveCriticalSection( &This->csFilter );
368
369         return hr;
370 }
371
372 static HRESULT WINAPI
373 CBaseFilterImpl_fnQueryVendorInfo(IBaseFilter* iface,LPWSTR* lpwszVendor)
374 {
375         ICOM_THIS(CBaseFilterImpl,iface);
376
377         TRACE("(%p)->(%p)\n",This,lpwszVendor);
378
379         /* E_NOTIMPL means 'no vender information'. */
380         return E_NOTIMPL;
381 }
382
383
384 /***************************************************************************
385  *
386  *      construct/destruct CBaseFilterImpl
387  *
388  */
389
390 static ICOM_VTABLE(IBaseFilter) ibasefilter =
391 {
392         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
393         /* IUnknown fields */
394         CBaseFilterImpl_fnQueryInterface,
395         CBaseFilterImpl_fnAddRef,
396         CBaseFilterImpl_fnRelease,
397         /* IPersist fields */
398         CBaseFilterImpl_fnGetClassID,
399         /* IMediaFilter fields */
400         CBaseFilterImpl_fnStop,
401         CBaseFilterImpl_fnPause,
402         CBaseFilterImpl_fnRun,
403         CBaseFilterImpl_fnGetState,
404         CBaseFilterImpl_fnSetSyncSource,
405         CBaseFilterImpl_fnGetSyncSource,
406         /* IBaseFilter fields */
407         CBaseFilterImpl_fnEnumPins,
408         CBaseFilterImpl_fnFindPin,
409         CBaseFilterImpl_fnQueryFilterInfo,
410         CBaseFilterImpl_fnJoinFilterGraph,
411         CBaseFilterImpl_fnQueryVendorInfo,
412 };
413
414
415 HRESULT CBaseFilterImpl_InitIBaseFilter(
416         CBaseFilterImpl* This, IUnknown* punkControl,
417         const CLSID* pclsidFilter, LPCWSTR lpwszNameGraph,
418         const CBaseFilterHandlers* pHandlers )
419 {
420         TRACE("(%p,%p)\n",This,punkControl);
421
422         if ( punkControl == NULL )
423         {
424                 ERR( "punkControl must not be NULL\n" );
425                 return E_INVALIDARG;
426         }
427
428         ICOM_VTBL(This) = &ibasefilter;
429         This->punkControl = punkControl;
430         This->pHandlers = pHandlers;
431         This->pclsidFilter = pclsidFilter;
432         This->pInPins = NULL;
433         This->pOutPins = NULL;
434         This->pfg = NULL;
435         This->cbNameGraph = 0;
436         This->pwszNameGraph = NULL;
437         This->pClock = NULL;
438         This->rtStart = 0;
439         This->fstate = State_Stopped;
440
441         This->cbNameGraph = sizeof(WCHAR) * (lstrlenW(lpwszNameGraph)+1);
442         This->pwszNameGraph = (WCHAR*)QUARTZ_AllocMem( This->cbNameGraph );
443         if ( This->pwszNameGraph == NULL )
444                 return E_OUTOFMEMORY;
445         memcpy( This->pwszNameGraph, lpwszNameGraph, This->cbNameGraph );
446
447         This->pInPins = QUARTZ_CompList_Alloc();
448         This->pOutPins = QUARTZ_CompList_Alloc();
449         if ( This->pInPins == NULL || This->pOutPins == NULL )
450         {
451                 if ( This->pInPins != NULL )
452                         QUARTZ_CompList_Free(This->pInPins);
453                 if ( This->pOutPins != NULL )
454                         QUARTZ_CompList_Free(This->pOutPins);
455                 QUARTZ_FreeMem(This->pwszNameGraph);
456                 return E_OUTOFMEMORY;
457         }
458
459         InitializeCriticalSection( &This->csFilter );
460
461         return NOERROR;
462 }
463
464 void CBaseFilterImpl_UninitIBaseFilter( CBaseFilterImpl* This )
465 {
466         QUARTZ_CompListItem*    pListItem;
467         IPin*   pPin;
468
469         TRACE("(%p)\n",This);
470
471         if ( This->pInPins != NULL )
472         {
473                 while ( 1 )
474                 {
475                         pListItem = QUARTZ_CompList_GetFirst( This->pInPins );
476                         if ( pListItem == NULL )
477                                 break;
478                         pPin = (IPin*)QUARTZ_CompList_GetItemPtr( pListItem );
479                         QUARTZ_CompList_RemoveComp( This->pInPins, (IUnknown*)pPin );
480                 }
481
482                 QUARTZ_CompList_Free( This->pInPins );
483                 This->pInPins = NULL;
484         }
485         if ( This->pOutPins != NULL )
486         {
487                 while ( 1 )
488                 {
489                         pListItem = QUARTZ_CompList_GetFirst( This->pOutPins );
490                         if ( pListItem == NULL )
491                                 break;
492                         pPin = (IPin*)QUARTZ_CompList_GetItemPtr( pListItem );
493                         QUARTZ_CompList_RemoveComp( This->pOutPins, (IUnknown*)pPin );
494                 }
495
496                 QUARTZ_CompList_Free( This->pOutPins );
497                 This->pOutPins = NULL;
498         }
499
500         if ( This->pwszNameGraph != NULL )
501         {
502                 QUARTZ_FreeMem( This->pwszNameGraph );
503                 This->pwszNameGraph = NULL;
504         }
505
506         if ( This->pClock != NULL )
507         {
508                 IReferenceClock_Release( This->pClock );
509                 This->pClock = NULL;
510         }
511
512         DeleteCriticalSection( &This->csFilter );
513 }
514
515 /***************************************************************************
516  *
517  *      CBaseFilterImpl methods
518  *
519  */
520
521 HRESULT CBaseFilterImpl_MediaEventNotify(
522         CBaseFilterImpl* This, long lEvent,LONG_PTR lParam1,LONG_PTR lParam2)
523 {
524         IMediaEventSink*        pSink = NULL;
525         HRESULT hr = E_NOTIMPL;
526
527         EnterCriticalSection( &This->csFilter );
528
529         if ( This->pfg == NULL )
530         {
531                 hr = E_UNEXPECTED;
532                 goto err;
533         }
534
535         hr = IFilterGraph_QueryInterface( This->pfg, &IID_IMediaEventSink, (void**)&pSink );
536         if ( FAILED(hr) )
537                 goto err;
538         if ( pSink == NULL )
539         {
540                 hr = E_FAIL;
541                 goto err;
542         }
543
544         hr = IMediaEventSink_Notify(pSink,lEvent,lParam1,lParam2);
545         IMediaEventSink_Release(pSink);
546 err:
547         LeaveCriticalSection( &This->csFilter );
548
549         return hr;
550 }
551