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