Various cosmetic changes.
[wine] / dlls / quartz / imfilter.c
1 /*
2  * Implementation of IMediaFilter for FilterGraph.
3  *
4  * FIXME - stub.
5  *
6  * hidenori@a2.ctktv.ne.jp
7  */
8
9 #include "config.h"
10
11 #include "windef.h"
12 #include "winbase.h"
13 #include "wingdi.h"
14 #include "winuser.h"
15 #include "winerror.h"
16 #include "strmif.h"
17 #include "control.h"
18 #include "uuids.h"
19 #include "vfwmsgs.h"
20 #include "evcode.h"
21
22 #include "debugtools.h"
23 DEFAULT_DEBUG_CHANNEL(quartz);
24
25 #include "quartz_private.h"
26 #include "fgraph.h"
27
28
29 #define WINE_QUARTZ_POLL_INTERVAL       10
30
31 /*****************************************************************************/
32
33 static
34 HRESULT CFilterGraph_PollGraphState(
35         CFilterGraph* This,
36         FILTER_STATE* pState)
37 {
38         HRESULT hr;
39         QUARTZ_CompListItem*    pItem;
40         IBaseFilter*    pFilter;
41
42         hr = S_OK;
43         *pState = State_Stopped;
44
45         EnterCriticalSection( &This->m_csGraphState );
46         QUARTZ_CompList_Lock( This->m_pFilterList );
47
48         pItem = QUARTZ_CompList_GetFirst( This->m_pFilterList );
49
50         while ( pItem != NULL )
51         {
52                 pFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr( pItem );
53                 hr = IBaseFilter_GetState( pFilter, (DWORD)0, pState );
54                 if ( hr != S_OK )
55                         break;
56
57                 pItem = QUARTZ_CompList_GetNext( This->m_pFilterList, pItem );
58         }
59
60         QUARTZ_CompList_Unlock( This->m_pFilterList );
61         LeaveCriticalSection( &This->m_csGraphState );
62
63         TRACE( "returns %08lx, state %d\n",
64                 hr, *pState );
65
66         return hr;
67 }
68
69 /*****************************************************************************/
70
71 static HRESULT WINAPI
72 IMediaFilter_fnQueryInterface(IMediaFilter* iface,REFIID riid,void** ppobj)
73 {
74         CFilterGraph_THIS(iface,mediafilter);
75
76         TRACE("(%p)->()\n",This);
77
78         return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
79 }
80
81 static ULONG WINAPI
82 IMediaFilter_fnAddRef(IMediaFilter* iface)
83 {
84         CFilterGraph_THIS(iface,mediafilter);
85
86         TRACE("(%p)->()\n",This);
87
88         return IUnknown_AddRef(This->unk.punkControl);
89 }
90
91 static ULONG WINAPI
92 IMediaFilter_fnRelease(IMediaFilter* iface)
93 {
94         CFilterGraph_THIS(iface,mediafilter);
95
96         TRACE("(%p)->()\n",This);
97
98         return IUnknown_Release(This->unk.punkControl);
99 }
100
101
102 static HRESULT WINAPI
103 IMediaFilter_fnGetClassID(IMediaFilter* iface,CLSID* pclsid)
104 {
105         CFilterGraph_THIS(iface,mediafilter);
106
107         TRACE("(%p)->()\n",This);
108
109         return IPersist_GetClassID(
110                 CFilterGraph_IPersist(This),pclsid);
111 }
112
113 static HRESULT WINAPI
114 IMediaFilter_fnStop(IMediaFilter* iface)
115 {
116         CFilterGraph_THIS(iface,mediafilter);
117         HRESULT hr;
118         HRESULT hrFilter;
119         QUARTZ_CompListItem*    pItem;
120         IBaseFilter*    pFilter;
121
122         TRACE("(%p)->()\n",This);
123
124         hr = S_OK;
125
126         EnterCriticalSection( &This->m_csGraphState );
127
128         if ( This->m_stateGraph != State_Stopped )
129         {
130                 /* IDistributorNotify_Stop() */
131
132                 QUARTZ_CompList_Lock( This->m_pFilterList );
133
134                 pItem = QUARTZ_CompList_GetFirst( This->m_pFilterList );
135
136                 while ( pItem != NULL )
137                 {
138                         pFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr( pItem );
139                         hrFilter = IBaseFilter_Stop( pFilter );
140                         if ( hrFilter != S_OK )
141                         {
142                                 if ( SUCCEEDED(hr) )
143                                         hr = hrFilter;
144                         }
145
146                         pItem = QUARTZ_CompList_GetNext( This->m_pFilterList, pItem );
147                 }
148
149                 QUARTZ_CompList_Unlock( This->m_pFilterList );
150
151                 This->m_stateGraph = State_Stopped;
152         }
153
154         LeaveCriticalSection( &This->m_csGraphState );
155
156         return hr;
157 }
158
159 static HRESULT WINAPI
160 IMediaFilter_fnPause(IMediaFilter* iface)
161 {
162         CFilterGraph_THIS(iface,mediafilter);
163         HRESULT hr;
164         HRESULT hrFilter;
165         QUARTZ_CompListItem*    pItem;
166         IBaseFilter*    pFilter;
167
168         TRACE("(%p)->()\n",This);
169
170         hr = S_OK;
171
172         EnterCriticalSection( &This->m_csGraphState );
173
174         if ( This->m_stateGraph != State_Paused )
175         {
176                 /* IDistributorNotify_Pause() */
177
178                 QUARTZ_CompList_Lock( This->m_pFilterList );
179
180                 pItem = QUARTZ_CompList_GetFirst( This->m_pFilterList );
181
182                 while ( pItem != NULL )
183                 {
184                         pFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr( pItem );
185                         hrFilter = IBaseFilter_Pause( pFilter );
186                         if ( hrFilter != S_OK )
187                         {
188                                 if ( SUCCEEDED(hr) )
189                                         hr = hrFilter;
190                         }
191
192                         pItem = QUARTZ_CompList_GetNext( This->m_pFilterList, pItem );
193                 }
194
195                 QUARTZ_CompList_Unlock( This->m_pFilterList );
196
197                 This->m_stateGraph = State_Paused;
198         }
199
200         LeaveCriticalSection( &This->m_csGraphState );
201
202         return hr;
203 }
204
205 static HRESULT WINAPI
206 IMediaFilter_fnRun(IMediaFilter* iface,REFERENCE_TIME rtStart)
207 {
208         CFilterGraph_THIS(iface,mediafilter);
209         HRESULT hr;
210         HRESULT hrFilter;
211         QUARTZ_CompListItem*    pItem;
212         IBaseFilter*    pFilter;
213         IReferenceClock*        pClock;
214
215         TRACE("(%p)->()\n",This);
216
217         EnterCriticalSection( &This->m_csGraphState );
218
219         if ( This->m_stateGraph == State_Stopped )
220         {
221                 hr = IMediaFilter_Pause(iface);
222                 if ( FAILED(hr) )
223                         goto end;
224         }
225
226         /* handle the special time. */
227         if ( rtStart == (REFERENCE_TIME)0 )
228         {
229                 hr = IMediaFilter_GetSyncSource(iface,&pClock);
230                 if ( hr == S_OK && pClock != NULL )
231                 {
232                         IReferenceClock_GetTime(pClock,&rtStart);
233                         IReferenceClock_Release(pClock);
234                 }
235         }
236
237         hr = NOERROR;
238
239         if ( This->m_stateGraph != State_Running )
240         {
241                 /* IDistributorNotify_Run() */
242
243                 QUARTZ_CompList_Lock( This->m_pFilterList );
244
245                 pItem = QUARTZ_CompList_GetFirst( This->m_pFilterList );
246
247                 while ( pItem != NULL )
248                 {
249                         pFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr( pItem );
250                         hrFilter = IBaseFilter_Run( pFilter, rtStart );
251                         if ( hrFilter != S_OK )
252                         {
253                                 if ( SUCCEEDED(hr) )
254                                         hr = hrFilter;
255                         }
256
257                         pItem = QUARTZ_CompList_GetNext( This->m_pFilterList, pItem );
258                 }
259
260                 QUARTZ_CompList_Unlock( This->m_pFilterList );
261
262                 This->m_stateGraph = State_Running;
263         }
264
265 end:
266         LeaveCriticalSection( &This->m_csGraphState );
267
268         return hr;
269 }
270
271 static HRESULT WINAPI
272 IMediaFilter_fnGetState(IMediaFilter* iface,DWORD dwTimeOut,FILTER_STATE* pState)
273 {
274         CFilterGraph_THIS(iface,mediafilter);
275         HRESULT hr;
276         DWORD   dwTickStart;
277         DWORD   dwTickUsed;
278
279         TRACE("(%p)->(%p)\n",This,pState);
280         if ( pState == NULL )
281                 return E_POINTER;
282
283         dwTickStart = GetTickCount();
284
285         while ( 1 )
286         {
287                 hr = CFilterGraph_PollGraphState( This, pState );
288                 if ( hr != VFW_S_STATE_INTERMEDIATE )
289                         break;
290                 if ( dwTimeOut == 0 )
291                         break;
292
293                 Sleep( (dwTimeOut >= WINE_QUARTZ_POLL_INTERVAL) ?
294                         WINE_QUARTZ_POLL_INTERVAL : dwTimeOut );
295
296                 dwTickUsed = GetTickCount() - dwTickStart;
297
298                 dwTickStart += dwTickUsed;
299                 if ( dwTimeOut <= dwTickUsed )
300                         dwTimeOut = 0;
301                 else
302                         dwTimeOut -= dwTickUsed;
303         }
304
305         EnterCriticalSection( &This->m_csGraphState );
306         *pState = This->m_stateGraph;
307         LeaveCriticalSection( &This->m_csGraphState );
308
309         return hr;
310 }
311
312 static HRESULT WINAPI
313 IMediaFilter_fnSetSyncSource(IMediaFilter* iface,IReferenceClock* pobjClock)
314 {
315         CFilterGraph_THIS(iface,mediafilter);
316         QUARTZ_CompListItem*    pItem;
317         IBaseFilter*    pFilter;
318         HRESULT hr = NOERROR;
319         HRESULT hrCur;
320
321         TRACE("(%p)->(%p)\n",This,pobjClock);
322
323         /* IDistributorNotify_SetSyncSource() */
324
325         EnterCriticalSection( &This->m_csClock );
326         QUARTZ_CompList_Lock( This->m_pFilterList );
327
328         if ( This->m_pClock != NULL )
329         {
330                 IReferenceClock_Release(This->m_pClock);
331                 This->m_pClock = NULL;
332         }
333
334         This->m_pClock = pobjClock;
335         if ( pobjClock != NULL )
336                 IReferenceClock_AddRef( pobjClock );
337
338         pItem = QUARTZ_CompList_GetFirst( This->m_pFilterList );
339         while ( pItem != NULL )
340         {
341                 pFilter = (IBaseFilter*)QUARTZ_CompList_GetItemPtr( pItem );
342                 hrCur = IBaseFilter_SetSyncSource(pFilter,pobjClock);
343                 if ( FAILED(hrCur) )
344                         hr = hrCur;
345                 pItem = QUARTZ_CompList_GetNext( This->m_pFilterList, pItem );
346         }
347
348         QUARTZ_CompList_Unlock( This->m_pFilterList );
349
350         IMediaEventSink_Notify(CFilterGraph_IMediaEventSink(This),
351                 EC_CLOCK_CHANGED, 0, 0);
352
353         LeaveCriticalSection( &This->m_csClock );
354
355         TRACE( "hr = %08lx\n", hr );
356
357         return hr;
358 }
359
360 static HRESULT WINAPI
361 IMediaFilter_fnGetSyncSource(IMediaFilter* iface,IReferenceClock** ppobjClock)
362 {
363         CFilterGraph_THIS(iface,mediafilter);
364         HRESULT hr = VFW_E_NO_CLOCK;
365
366         TRACE("(%p)->(%p)\n",This,ppobjClock);
367
368         if ( ppobjClock == NULL )
369                 return E_POINTER;
370
371         EnterCriticalSection( &This->m_csClock );
372         *ppobjClock = This->m_pClock;
373         if ( This->m_pClock != NULL )
374         {
375                 hr = NOERROR;
376                 IReferenceClock_AddRef( This->m_pClock );
377         }
378         LeaveCriticalSection( &This->m_csClock );
379
380         TRACE( "hr = %08lx\n", hr );
381
382         return hr;
383 }
384
385
386
387 static ICOM_VTABLE(IMediaFilter) imediafilter =
388 {
389         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
390         /* IUnknown fields */
391         IMediaFilter_fnQueryInterface,
392         IMediaFilter_fnAddRef,
393         IMediaFilter_fnRelease,
394         /* IPersist fields */
395         IMediaFilter_fnGetClassID,
396         /* IMediaFilter fields */
397         IMediaFilter_fnStop,
398         IMediaFilter_fnPause,
399         IMediaFilter_fnRun,
400         IMediaFilter_fnGetState,
401         IMediaFilter_fnSetSyncSource,
402         IMediaFilter_fnGetSyncSource,
403 };
404
405 HRESULT CFilterGraph_InitIMediaFilter( CFilterGraph* pfg )
406 {
407         TRACE("(%p)\n",pfg);
408
409         ICOM_VTBL(&pfg->mediafilter) = &imediafilter;
410
411         InitializeCriticalSection( &pfg->m_csGraphState );
412         InitializeCriticalSection( &pfg->m_csClock );
413         pfg->m_stateGraph = State_Stopped;
414         pfg->m_pClock = NULL;
415
416         return NOERROR;
417 }
418
419 void CFilterGraph_UninitIMediaFilter( CFilterGraph* pfg )
420 {
421         TRACE("(%p)\n",pfg);
422
423         if ( pfg->m_pClock != NULL )
424         {
425                 IReferenceClock_Release( pfg->m_pClock );
426                 pfg->m_pClock = NULL;
427         }
428
429         DeleteCriticalSection( &pfg->m_csGraphState );
430         DeleteCriticalSection( &pfg->m_csClock );
431 }