Implement ResetDC and PHYSICALOFFSET[X|Y] devcaps.
[wine] / dlls / quartz / imfilter.c
1 /*
2  * Implementation of IMediaFilter for FilterGraph.
3  *
4  * FIXME - stub.
5  *
6  * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "strmif.h"
31 #include "control.h"
32 #include "uuids.h"
33 #include "vfwmsgs.h"
34 #include "evcode.h"
35
36 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
38
39 #include "quartz_private.h"
40 #include "fgraph.h"
41
42
43 #define WINE_QUARTZ_POLL_INTERVAL       10
44
45 /*****************************************************************************/
46
47 static
48 HRESULT CFilterGraph_PollGraphState(
49         CFilterGraph* This,
50         FILTER_STATE* pState)
51 {
52         HRESULT hr;
53         DWORD   n;
54
55         hr = S_OK;
56         *pState = State_Stopped;
57
58         EnterCriticalSection( &This->m_csGraphState );
59         EnterCriticalSection( &This->m_csFilters );
60
61         for ( n = 0; n < This->m_cActiveFilters; n++ )
62         {
63                 hr = IBaseFilter_GetState( This->m_pActiveFilters[n].pFilter, (DWORD)0, pState );
64                 if ( hr != S_OK )
65                         break;
66         }
67
68         LeaveCriticalSection( &This->m_csFilters );
69         LeaveCriticalSection( &This->m_csGraphState );
70
71         TRACE( "returns %08lx, state %d\n",
72                 hr, *pState );
73
74         return hr;
75 }
76
77 static
78 HRESULT CFilterGraph_StopGraph(
79         CFilterGraph* This )
80 {
81         HRESULT hr;
82         HRESULT hrFilter;
83         DWORD   n;
84
85         hr = S_OK;
86
87         EnterCriticalSection( &This->m_csFilters );
88
89         for ( n = 0; n < This->m_cActiveFilters; n++ )
90         {
91                 hrFilter = IBaseFilter_Stop( This->m_pActiveFilters[n].pFilter );
92                 if ( hrFilter != S_OK )
93                 {
94                         if ( SUCCEEDED(hr) )
95                                 hr = hrFilter;
96                 }
97         }
98
99         LeaveCriticalSection( &This->m_csFilters );
100
101         return hr;
102 }
103
104 static
105 HRESULT CFilterGraph_PauseGraph(
106         CFilterGraph* This )
107 {
108         HRESULT hr;
109         HRESULT hrFilter;
110         DWORD   n;
111
112         hr = S_OK;
113
114         EnterCriticalSection( &This->m_csFilters );
115
116         for ( n = 0; n < This->m_cActiveFilters; n++ )
117         {
118                 hrFilter = IBaseFilter_Pause( This->m_pActiveFilters[n].pFilter );
119                 if ( hrFilter != S_OK )
120                 {
121                         if ( SUCCEEDED(hr) )
122                                 hr = hrFilter;
123                 }
124         }
125
126         LeaveCriticalSection( &This->m_csFilters );
127
128         return hr;
129 }
130
131 static
132 HRESULT CFilterGraph_RunGraph(
133         CFilterGraph* This, REFERENCE_TIME rtStart )
134 {
135         HRESULT hr;
136         HRESULT hrFilter;
137         DWORD   n;
138
139         hr = S_OK;
140
141         EnterCriticalSection( &This->m_csFilters );
142
143         for ( n = 0; n < This->m_cActiveFilters; n++ )
144         {
145                 hrFilter = IBaseFilter_Run( This->m_pActiveFilters[n].pFilter, rtStart );
146                 if ( hrFilter != S_OK )
147                 {
148                         if ( SUCCEEDED(hr) )
149                                 hr = hrFilter;
150                 }
151         }
152
153         LeaveCriticalSection( &This->m_csFilters );
154
155         return hr;
156 }
157
158 static
159 HRESULT CFilterGraph_SetSyncSourceGraph(
160         CFilterGraph* This, IReferenceClock* pClock )
161 {
162         HRESULT hr;
163         HRESULT hrFilter;
164         DWORD   n;
165
166         hr = S_OK;
167
168         EnterCriticalSection( &This->m_csFilters );
169
170         for ( n = 0; n < This->m_cActiveFilters; n++ )
171         {
172                 hrFilter = IBaseFilter_SetSyncSource( This->m_pActiveFilters[n].pFilter, pClock );
173                 if ( hrFilter == E_NOTIMPL )
174                         hrFilter = S_OK;
175                 if ( hrFilter != S_OK )
176                 {
177                         if ( SUCCEEDED(hr) )
178                                 hr = hrFilter;
179                 }
180         }
181
182         LeaveCriticalSection( &This->m_csFilters );
183
184         return hr;
185 }
186
187
188
189 /*****************************************************************************/
190
191 static HRESULT WINAPI
192 IMediaFilter_fnQueryInterface(IMediaFilter* iface,REFIID riid,void** ppobj)
193 {
194         CFilterGraph_THIS(iface,mediafilter);
195
196         TRACE("(%p)->()\n",This);
197
198         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
199 }
200
201 static ULONG WINAPI
202 IMediaFilter_fnAddRef(IMediaFilter* iface)
203 {
204         CFilterGraph_THIS(iface,mediafilter);
205
206         TRACE("(%p)->()\n",This);
207
208         return IUnknown_AddRef(This->unk.punkControl);
209 }
210
211 static ULONG WINAPI
212 IMediaFilter_fnRelease(IMediaFilter* iface)
213 {
214         CFilterGraph_THIS(iface,mediafilter);
215
216         TRACE("(%p)->()\n",This);
217
218         return IUnknown_Release(This->unk.punkControl);
219 }
220
221
222 static HRESULT WINAPI
223 IMediaFilter_fnGetClassID(IMediaFilter* iface,CLSID* pclsid)
224 {
225         CFilterGraph_THIS(iface,mediafilter);
226
227         TRACE("(%p)->()\n",This);
228
229         return IPersist_GetClassID(
230                 CFilterGraph_IPersist(This),pclsid);
231 }
232
233 static HRESULT WINAPI
234 IMediaFilter_fnStop(IMediaFilter* iface)
235 {
236         CFilterGraph_THIS(iface,mediafilter);
237         HRESULT hr;
238
239         TRACE("(%p)->()\n",This);
240
241         hr = S_OK;
242
243         EnterCriticalSection( &This->m_csGraphState );
244
245         if ( This->m_stateGraph != State_Stopped )
246         {
247                 /* IDistributorNotify_Stop() */
248
249                 hr = CFilterGraph_StopGraph(This);
250
251                 This->m_stateGraph = State_Stopped;
252         }
253
254         LeaveCriticalSection( &This->m_csGraphState );
255
256         return hr;
257 }
258
259 static HRESULT WINAPI
260 IMediaFilter_fnPause(IMediaFilter* iface)
261 {
262         CFilterGraph_THIS(iface,mediafilter);
263         HRESULT hr;
264
265         TRACE("(%p)->()\n",This);
266
267         hr = S_OK;
268
269         EnterCriticalSection( &This->m_csGraphState );
270
271         if ( This->m_stateGraph != State_Paused )
272         {
273                 /* IDistributorNotify_Pause() */
274
275                 hr = CFilterGraph_PauseGraph(This);
276                 if ( SUCCEEDED(hr) )
277                         This->m_stateGraph = State_Paused;
278                 else
279                         (void)CFilterGraph_StopGraph(This);
280         }
281
282         LeaveCriticalSection( &This->m_csGraphState );
283
284         return hr;
285 }
286
287 static HRESULT WINAPI
288 IMediaFilter_fnRun(IMediaFilter* iface,REFERENCE_TIME rtStart)
289 {
290         CFilterGraph_THIS(iface,mediafilter);
291         HRESULT hr;
292         IReferenceClock*        pClock;
293
294         TRACE("(%p)->()\n",This);
295
296         EnterCriticalSection( &This->m_csGraphState );
297
298         if ( This->m_stateGraph == State_Stopped )
299         {
300                 hr = IMediaFilter_Pause(iface);
301                 if ( FAILED(hr) )
302                         goto end;
303         }
304
305         /* handle the special time. */
306         if ( rtStart == (REFERENCE_TIME)0 )
307         {
308                 hr = IMediaFilter_GetSyncSource(iface,&pClock);
309                 if ( hr == S_OK && pClock != NULL )
310                 {
311                         IReferenceClock_GetTime(pClock,&rtStart);
312                         IReferenceClock_Release(pClock);
313                 }
314         }
315
316         hr = NOERROR;
317
318         if ( This->m_stateGraph != State_Running )
319         {
320                 /* IDistributorNotify_Run() */
321
322                 hr = CFilterGraph_RunGraph(This,rtStart);
323
324                 if ( SUCCEEDED(hr) )
325                         This->m_stateGraph = State_Running;
326                 else
327                         (void)CFilterGraph_StopGraph(This);
328         }
329
330 end:
331         LeaveCriticalSection( &This->m_csGraphState );
332
333         return hr;
334 }
335
336 static HRESULT WINAPI
337 IMediaFilter_fnGetState(IMediaFilter* iface,DWORD dwTimeOut,FILTER_STATE* pState)
338 {
339         CFilterGraph_THIS(iface,mediafilter);
340         HRESULT hr;
341         DWORD   dwTickStart;
342         DWORD   dwTickUsed;
343
344         TRACE("(%p)->(%p)\n",This,pState);
345         if ( pState == NULL )
346                 return E_POINTER;
347
348         dwTickStart = GetTickCount();
349
350         while ( 1 )
351         {
352                 hr = CFilterGraph_PollGraphState( This, pState );
353                 if ( hr != VFW_S_STATE_INTERMEDIATE )
354                         break;
355                 if ( dwTimeOut == 0 )
356                         break;
357
358                 Sleep( (dwTimeOut >= WINE_QUARTZ_POLL_INTERVAL) ?
359                         WINE_QUARTZ_POLL_INTERVAL : dwTimeOut );
360
361                 dwTickUsed = GetTickCount() - dwTickStart;
362
363                 dwTickStart += dwTickUsed;
364                 if ( dwTimeOut <= dwTickUsed )
365                         dwTimeOut = 0;
366                 else
367                         dwTimeOut -= dwTickUsed;
368         }
369
370         EnterCriticalSection( &This->m_csGraphState );
371         *pState = This->m_stateGraph;
372         LeaveCriticalSection( &This->m_csGraphState );
373
374         return hr;
375 }
376
377 static HRESULT WINAPI
378 IMediaFilter_fnSetSyncSource(IMediaFilter* iface,IReferenceClock* pobjClock)
379 {
380         CFilterGraph_THIS(iface,mediafilter);
381         HRESULT hr = NOERROR;
382
383         TRACE("(%p)->(%p)\n",This,pobjClock);
384
385         /* IDistributorNotify_SetSyncSource() */
386
387         EnterCriticalSection( &This->m_csClock );
388
389         hr = CFilterGraph_SetSyncSourceGraph( This, pobjClock );
390
391         if ( SUCCEEDED(hr) )
392         {
393                 if ( This->m_pClock != NULL )
394                 {
395                         IReferenceClock_Release(This->m_pClock);
396                         This->m_pClock = NULL;
397                 }
398                 This->m_pClock = pobjClock;
399                 if ( pobjClock != NULL )
400                         IReferenceClock_AddRef( pobjClock );
401                 IMediaEventSink_Notify(CFilterGraph_IMediaEventSink(This),
402                         EC_CLOCK_CHANGED, 0, 0);
403         }
404         else
405         {
406                 (void)CFilterGraph_SetSyncSourceGraph( This, This->m_pClock );
407         }
408
409         LeaveCriticalSection( &This->m_csClock );
410
411         TRACE( "hr = %08lx\n", hr );
412
413         return hr;
414 }
415
416 static HRESULT WINAPI
417 IMediaFilter_fnGetSyncSource(IMediaFilter* iface,IReferenceClock** ppobjClock)
418 {
419         CFilterGraph_THIS(iface,mediafilter);
420         HRESULT hr = VFW_E_NO_CLOCK;
421
422         TRACE("(%p)->(%p)\n",This,ppobjClock);
423
424         if ( ppobjClock == NULL )
425                 return E_POINTER;
426
427         EnterCriticalSection( &This->m_csClock );
428         *ppobjClock = This->m_pClock;
429         if ( This->m_pClock != NULL )
430         {
431                 hr = NOERROR;
432                 IReferenceClock_AddRef( This->m_pClock );
433         }
434         LeaveCriticalSection( &This->m_csClock );
435
436         TRACE( "hr = %08lx\n", hr );
437
438         return hr;
439 }
440
441
442
443 static ICOM_VTABLE(IMediaFilter) imediafilter =
444 {
445         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
446         /* IUnknown fields */
447         IMediaFilter_fnQueryInterface,
448         IMediaFilter_fnAddRef,
449         IMediaFilter_fnRelease,
450         /* IPersist fields */
451         IMediaFilter_fnGetClassID,
452         /* IMediaFilter fields */
453         IMediaFilter_fnStop,
454         IMediaFilter_fnPause,
455         IMediaFilter_fnRun,
456         IMediaFilter_fnGetState,
457         IMediaFilter_fnSetSyncSource,
458         IMediaFilter_fnGetSyncSource,
459 };
460
461 HRESULT CFilterGraph_InitIMediaFilter( CFilterGraph* pfg )
462 {
463         TRACE("(%p)\n",pfg);
464
465         ICOM_VTBL(&pfg->mediafilter) = &imediafilter;
466
467         InitializeCriticalSection( &pfg->m_csGraphState );
468         InitializeCriticalSection( &pfg->m_csClock );
469         pfg->m_stateGraph = State_Stopped;
470         pfg->m_pClock = NULL;
471
472         return NOERROR;
473 }
474
475 void CFilterGraph_UninitIMediaFilter( CFilterGraph* pfg )
476 {
477         TRACE("(%p)\n",pfg);
478
479         if ( pfg->m_pClock != NULL )
480         {
481                 IReferenceClock_Release( pfg->m_pClock );
482                 pfg->m_pClock = NULL;
483         }
484
485         DeleteCriticalSection( &pfg->m_csGraphState );
486         DeleteCriticalSection( &pfg->m_csClock );
487 }