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