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