2 * Implementation of IFilterGraph.
4 * FIXME - create a thread to process some methods correctly.
7 * FIXME - process Pause/Stop asynchronously and notify when completed.
10 * hidenori@a2.ctktv.ne.jp
20 #include "wine/obj_base.h"
21 #include "wine/obj_oleaut.h"
26 #include "wine/unicode.h"
29 #include "debugtools.h"
30 DEFAULT_DEBUG_CHANNEL(quartz
);
32 #include "quartz_private.h"
38 static HRESULT
CFilterGraph_DisconnectAllPins( IBaseFilter
* pFilter
)
40 IEnumPins
* pEnum
= NULL
;
46 hr
= IBaseFilter_EnumPins( pFilter
, &pEnum
);
56 hr
= IEnumPins_Next( pEnum
, 1, &pPin
, &cFetched
);
59 if ( hr
!= NOERROR
|| pPin
== NULL
|| cFetched
!= 1 )
66 hr
= IPin_ConnectedTo(pPin
,&pConnTo
);
67 if ( hr
== NOERROR
&& pConnTo
!= NULL
)
69 IPin_Disconnect(pPin
);
70 IPin_Disconnect(pConnTo
);
71 IPin_Release(pConnTo
);
77 IEnumPins_Release( pEnum
);
83 static HRESULT
CFilterGraph_GraphChanged( CFilterGraph
* This
)
85 /* IDistributorNotify_NotifyGraphChange() */
87 IMediaEventSink_Notify(CFilterGraph_IMediaEventSink(This
),
88 EC_GRAPH_CHANGED
, 0, 0);
89 EnterCriticalSection( &This
->m_csGraphVersion
);
90 This
->m_lGraphVersion
++;
91 LeaveCriticalSection( &This
->m_csGraphVersion
);
97 /****************************************************************************/
100 IFilterGraph2_fnQueryInterface(IFilterGraph2
* iface
,REFIID riid
,void** ppobj
)
102 CFilterGraph_THIS(iface
,fgraph
);
104 TRACE("(%p)->()\n",This
);
106 return IUnknown_QueryInterface(This
->unk
.punkControl
,riid
,ppobj
);
110 IFilterGraph2_fnAddRef(IFilterGraph2
* iface
)
112 CFilterGraph_THIS(iface
,fgraph
);
114 TRACE("(%p)->()\n",This
);
116 return IUnknown_AddRef(This
->unk
.punkControl
);
120 IFilterGraph2_fnRelease(IFilterGraph2
* iface
)
122 CFilterGraph_THIS(iface
,fgraph
);
124 TRACE("(%p)->()\n",This
);
126 return IUnknown_Release(This
->unk
.punkControl
);
129 static HRESULT WINAPI
130 IFilterGraph2_fnAddFilter(IFilterGraph2
* iface
,IBaseFilter
* pFilter
, LPCWSTR pName
)
132 CFilterGraph_THIS(iface
,fgraph
);
136 HRESULT hrSucceeded
= S_OK
;
137 QUARTZ_CompListItem
* pItem
;
140 TRACE( "(%p)->(%p,%s)\n",This
,pFilter
,debugstr_w(pName
) );
142 QUARTZ_CompList_Lock( This
->m_pFilterList
);
144 hr
= IMediaFilter_GetState(CFilterGraph_IMediaFilter(This
),0,&fs
);
145 if ( hr
== VFW_S_STATE_INTERMEDIATE
)
146 hr
= VFW_E_STATE_CHANGED
;
147 if ( fs
!= State_Stopped
)
148 hr
= VFW_E_NOT_STOPPED
;
152 TRACE( "(%p) search the specified name.\n",This
);
156 pItem
= QUARTZ_CompList_SearchData(
158 pName
, sizeof(WCHAR
)*(strlenW(pName
)+1) );
162 hrSucceeded
= VFW_S_DUPLICATE_NAME
;
164 iLen
= strlenW(pName
);
167 memcpy( info
.achName
, pName
, sizeof(WCHAR
)*iLen
);
168 info
.achName
[iLen
] = 0;
172 ZeroMemory( &info
, sizeof(info
) );
173 hr
= IBaseFilter_QueryFilterInfo( pFilter
, &info
);
177 iLen
= strlenW(info
.achName
);
178 pItem
= QUARTZ_CompList_SearchData(
180 info
.achName
, sizeof(WCHAR
)*(iLen
+1) );
183 pName
= info
.achName
;
188 /* generate modified names for this filter.. */
189 iLen
= strlenW(info
.achName
);
192 info
.achName
[iLen
++] = ' ';
194 for ( i
= 0; i
<= 99; i
++ )
196 info
.achName
[iLen
+0] = (i
%10) + '0';
197 info
.achName
[iLen
+1] = ((i
/10)%10) + '0';
198 info
.achName
[iLen
+2] = 0;
199 pItem
= QUARTZ_CompList_SearchData(
201 info
.achName
, sizeof(WCHAR
)*(iLen
+3) );
204 pName
= info
.achName
;
209 hr
= ( pName
== NULL
) ? E_FAIL
: VFW_E_DUPLICATE_NAME
;
213 TRACE( "(%p) add this filter.\n",This
);
215 /* register this filter. */
216 hr
= QUARTZ_CompList_AddComp(
217 This
->m_pFilterList
, (IUnknown
*)pFilter
,
218 pName
, sizeof(WCHAR
)*(strlenW(pName
)+1) );
222 hr
= IBaseFilter_JoinFilterGraph(pFilter
,(IFilterGraph
*)iface
,pName
);
225 EnterCriticalSection( &This
->m_csClock
);
226 hr
= IBaseFilter_SetSyncSource( pFilter
, This
->m_pClock
);
227 LeaveCriticalSection( &This
->m_csClock
);
231 IBaseFilter_JoinFilterGraph(pFilter
,NULL
,pName
);
232 QUARTZ_CompList_RemoveComp(
233 This
->m_pFilterList
,(IUnknown
*)pFilter
);
237 hr
= CFilterGraph_GraphChanged(This
);
243 QUARTZ_CompList_Unlock( This
->m_pFilterList
);
245 TRACE( "(%p) return %08lx\n", This
, hr
);
250 static HRESULT WINAPI
251 IFilterGraph2_fnRemoveFilter(IFilterGraph2
* iface
,IBaseFilter
* pFilter
)
253 CFilterGraph_THIS(iface
,fgraph
);
254 QUARTZ_CompListItem
* pItem
;
256 HRESULT hr
= NOERROR
;
258 TRACE( "(%p)->(%p)\n",This
,pFilter
);
260 QUARTZ_CompList_Lock( This
->m_pFilterList
);
262 hr
= IMediaFilter_GetState(CFilterGraph_IMediaFilter(This
),0,&fs
);
263 if ( hr
== VFW_S_STATE_INTERMEDIATE
)
264 hr
= VFW_E_STATE_CHANGED
;
265 if ( fs
!= State_Stopped
)
266 hr
= VFW_E_NOT_STOPPED
;
270 hr
= S_FALSE
; /* FIXME? */
271 pItem
= QUARTZ_CompList_SearchComp(
272 This
->m_pFilterList
, (IUnknown
*)pFilter
);
275 CFilterGraph_DisconnectAllPins(pFilter
);
276 IBaseFilter_SetSyncSource( pFilter
, NULL
);
277 hr
= IBaseFilter_JoinFilterGraph(
278 pFilter
, NULL
, QUARTZ_CompList_GetDataPtr(pItem
) );
279 QUARTZ_CompList_RemoveComp(
280 This
->m_pFilterList
, (IUnknown
*)pFilter
);
283 hr
= CFilterGraph_GraphChanged(This
);
288 QUARTZ_CompList_Unlock( This
->m_pFilterList
);
293 static HRESULT WINAPI
294 IFilterGraph2_fnEnumFilters(IFilterGraph2
* iface
,IEnumFilters
** ppEnum
)
296 CFilterGraph_THIS(iface
,fgraph
);
299 TRACE( "(%p)->(%p)\n",This
,ppEnum
);
301 QUARTZ_CompList_Lock( This
->m_pFilterList
);
303 hr
= QUARTZ_CreateEnumUnknown(
304 &IID_IEnumFilters
, (void**)ppEnum
, This
->m_pFilterList
);
306 QUARTZ_CompList_Unlock( This
->m_pFilterList
);
311 static HRESULT WINAPI
312 IFilterGraph2_fnFindFilterByName(IFilterGraph2
* iface
,LPCWSTR pName
,IBaseFilter
** ppFilter
)
314 CFilterGraph_THIS(iface
,fgraph
);
315 QUARTZ_CompListItem
* pItem
;
318 TRACE( "(%p)->(%s,%p)\n",This
,debugstr_w(pName
),ppFilter
);
320 if ( ppFilter
== NULL
)
324 QUARTZ_CompList_Lock( This
->m_pFilterList
);
326 pItem
= QUARTZ_CompList_SearchData(
328 pName
, sizeof(WCHAR
)*(strlenW(pName
)+1) );
331 *ppFilter
= (IBaseFilter
*)QUARTZ_CompList_GetItemPtr(pItem
);
335 QUARTZ_CompList_Unlock( This
->m_pFilterList
);
340 static HRESULT WINAPI
341 IFilterGraph2_fnConnectDirect(IFilterGraph2
* iface
,IPin
* pOut
,IPin
* pIn
,const AM_MEDIA_TYPE
* pmt
)
343 CFilterGraph_THIS(iface
,fgraph
);
348 FILTER_INFO finfoOut
;
351 TRACE( "(%p)->(%p,%p,%p)\n",This
,pOut
,pIn
,pmt
);
353 infoIn
.pFilter
= NULL
;
354 infoOut
.pFilter
= NULL
;
355 finfoIn
.pGraph
= NULL
;
356 finfoOut
.pGraph
= NULL
;
358 QUARTZ_CompList_Lock( This
->m_pFilterList
);
360 hr
= IPin_QueryPinInfo(pIn
,&infoIn
);
363 hr
= IPin_QueryPinInfo(pOut
,&infoOut
);
366 if ( infoIn
.pFilter
== NULL
|| infoOut
.pFilter
== NULL
||
367 infoIn
.dir
!= PINDIR_INPUT
|| infoOut
.dir
!= PINDIR_OUTPUT
)
373 hr
= IBaseFilter_QueryFilterInfo(infoIn
.pFilter
,&finfoIn
);
376 hr
= IBaseFilter_QueryFilterInfo(infoOut
.pFilter
,&finfoOut
);
379 if ( finfoIn
.pGraph
!= ((IFilterGraph
*)iface
) ||
380 finfoOut
.pGraph
!= ((IFilterGraph
*)iface
) )
387 hr
= IPin_ConnectedTo(pIn
,&pConnTo
);
388 if ( hr
== NOERROR
&& pConnTo
!= NULL
)
390 IPin_Release(pConnTo
);
391 hr
= VFW_E_ALREADY_CONNECTED
;
396 hr
= IPin_ConnectedTo(pOut
,&pConnTo
);
397 if ( hr
== NOERROR
&& pConnTo
!= NULL
)
399 IPin_Release(pConnTo
);
400 hr
= VFW_E_ALREADY_CONNECTED
;
404 TRACE("(%p) try to connect %p<->%p\n",This
,pIn
,pOut
);
405 hr
= IPin_Connect(pOut
,pIn
,pmt
);
408 TRACE("(%p)->Connect(%p,%p) hr = %08lx\n",pOut
,pIn
,pmt
,hr
);
409 IPin_Disconnect(pOut
);
410 IPin_Disconnect(pIn
);
414 hr
= CFilterGraph_GraphChanged(This
);
419 QUARTZ_CompList_Unlock( This
->m_pFilterList
);
421 if ( infoIn
.pFilter
!= NULL
)
422 IBaseFilter_Release(infoIn
.pFilter
);
423 if ( infoOut
.pFilter
!= NULL
)
424 IBaseFilter_Release(infoOut
.pFilter
);
425 if ( finfoIn
.pGraph
!= NULL
)
426 IFilterGraph_Release(finfoIn
.pGraph
);
427 if ( finfoOut
.pGraph
!= NULL
)
428 IFilterGraph_Release(finfoOut
.pGraph
);
433 static HRESULT WINAPI
434 IFilterGraph2_fnReconnect(IFilterGraph2
* iface
,IPin
* pPin
)
436 CFilterGraph_THIS(iface
,fgraph
);
438 TRACE( "(%p)->(%p)\n",This
,pPin
);
440 return IFilterGraph2_ReconnectEx(iface
,pPin
,NULL
);
443 static HRESULT WINAPI
444 IFilterGraph2_fnDisconnect(IFilterGraph2
* iface
,IPin
* pPin
)
446 CFilterGraph_THIS(iface
,fgraph
);
450 TRACE( "(%p)->(%p)\n",This
,pPin
);
452 QUARTZ_CompList_Lock( This
->m_pFilterList
);
455 hr
= IPin_ConnectedTo(pPin
,&pConnTo
);
456 if ( hr
== NOERROR
&& pConnTo
!= NULL
)
458 IPin_Disconnect(pConnTo
);
459 IPin_Release(pConnTo
);
461 hr
= IPin_Disconnect(pPin
);
465 hr
= CFilterGraph_GraphChanged(This
);
470 QUARTZ_CompList_Unlock( This
->m_pFilterList
);
475 static HRESULT WINAPI
476 IFilterGraph2_fnSetDefaultSyncSource(IFilterGraph2
* iface
)
478 CFilterGraph_THIS(iface
,fgraph
);
480 IReferenceClock
* pClock
;
483 FIXME( "(%p)->() stub!\n", This
);
485 /* FIXME - search all filters. */
487 hr
= QUARTZ_CreateSystemClock( NULL
, (void**)&punk
);
490 hr
= IUnknown_QueryInterface( punk
, &IID_IReferenceClock
, (void**)&pClock
); IUnknown_Release( punk
);
494 hr
= IMediaFilter_SetSyncSource(
495 CFilterGraph_IMediaFilter(This
), pClock
);
496 IReferenceClock_Release( pClock
);
501 static HRESULT WINAPI
502 IFilterGraph2_fnConnect(IFilterGraph2
* iface
,IPin
* pOut
,IPin
* pIn
)
504 CFilterGraph_THIS(iface
,fgraph
);
507 TRACE( "(%p)->(%p,%p)\n",This
,pOut
,pIn
);
509 /* At first, try to connect directly. */
510 hr
= IFilterGraph_ConnectDirect(iface
,pOut
,pIn
,NULL
);
514 /* FIXME - try to connect indirectly. */
515 FIXME( "(%p)->(%p,%p) stub!\n",This
,pOut
,pIn
);
521 static HRESULT WINAPI
522 IFilterGraph2_fnRender(IFilterGraph2
* iface
,IPin
* pOut
)
524 CFilterGraph_THIS(iface
,fgraph
);
526 FIXME( "(%p)->(%p) stub!\n",This
,pOut
);
530 static HRESULT WINAPI
531 IFilterGraph2_fnRenderFile(IFilterGraph2
* iface
,LPCWSTR lpFileName
,LPCWSTR lpPlayList
)
533 CFilterGraph_THIS(iface
,fgraph
);
535 IBaseFilter
* pFilter
= NULL
;
536 IEnumPins
* pEnum
= NULL
;
543 TRACE( "(%p)->(%s,%s)\n",This
,
544 debugstr_w(lpFileName
),debugstr_w(lpPlayList
) );
546 if ( lpPlayList
!= NULL
)
550 hr
= IFilterGraph2_AddSourceFilter(iface
,lpFileName
,NULL
,&pFilter
);
553 if ( pFilter
== NULL
)
559 hr
= IBaseFilter_EnumPins( pFilter
, &pEnum
);
575 hr
= IEnumPins_Next( pEnum
, 1, &pPin
, &cFetched
);
578 if ( hr
!= NOERROR
|| pPin
== NULL
|| cFetched
!= 1 )
583 hr
= IPin_QueryDirection( pPin
, &dir
);
584 if ( hr
== NOERROR
&& dir
== PINDIR_OUTPUT
)
587 hr
= IFilterGraph2_Render( iface
, pPin
);
591 IPin_Release( pPin
);
596 if ( cTryToRender
> cActRender
)
597 hr
= VFW_S_PARTIAL_RENDER
;
598 if ( cActRender
== 0 )
604 IEnumPins_Release( pEnum
);
605 if ( pFilter
!= NULL
)
606 IBaseFilter_Release( pFilter
);
611 static HRESULT WINAPI
612 IFilterGraph2_fnAddSourceFilter(IFilterGraph2
* iface
,LPCWSTR lpFileName
,LPCWSTR lpFilterName
,IBaseFilter
** ppBaseFilter
)
614 CFilterGraph_THIS(iface
,fgraph
);
616 FIXME( "(%p)->(%s,%s,%p) stub!\n",This
,
617 debugstr_w(lpFileName
),debugstr_w(lpFilterName
),ppBaseFilter
);
621 static HRESULT WINAPI
622 IFilterGraph2_fnSetLogFile(IFilterGraph2
* iface
,DWORD_PTR hFile
)
624 CFilterGraph_THIS(iface
,fgraph
);
626 FIXME( "(%p)->() stub!\n", This
);
630 static HRESULT WINAPI
631 IFilterGraph2_fnAbort(IFilterGraph2
* iface
)
633 CFilterGraph_THIS(iface
,fgraph
);
637 FIXME( "(%p)->() stub!\n", This
);
641 static HRESULT WINAPI
642 IFilterGraph2_fnShouldOperationContinue(IFilterGraph2
* iface
)
644 CFilterGraph_THIS(iface
,fgraph
);
648 FIXME( "(%p)->() stub!\n", This
);
652 static HRESULT WINAPI
653 IFilterGraph2_fnAddSourceFilterForMoniker(IFilterGraph2
* iface
,IMoniker
* pMon
,IBindCtx
* pCtx
,LPCWSTR pFilterName
,IBaseFilter
** ppFilter
)
655 CFilterGraph_THIS(iface
,fgraph
);
657 FIXME( "(%p)->() stub!\n", This
);
661 static HRESULT WINAPI
662 IFilterGraph2_fnReconnectEx(IFilterGraph2
* iface
,IPin
* pPin
,const AM_MEDIA_TYPE
* pmt
)
664 CFilterGraph_THIS(iface
,fgraph
);
667 FIXME( "(%p)->(%p,%p) stub!\n",This
,pPin
,pmt
);
669 /* reconnect asynchronously. */
671 hr
= CFilterGraph_GraphChanged(This
);
676 static HRESULT WINAPI
677 IFilterGraph2_fnRenderEx(IFilterGraph2
* iface
,IPin
* pPin
,DWORD dwParam1
,DWORD
* pdwParam2
)
679 CFilterGraph_THIS(iface
,fgraph
);
682 FIXME( "(%p)->(%p,%08lx,%p) stub!\n",This
,pPin
,dwParam1
,pdwParam2
);
689 static ICOM_VTABLE(IFilterGraph2
) ifgraph
=
691 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
692 /* IUnknown fields */
693 IFilterGraph2_fnQueryInterface
,
694 IFilterGraph2_fnAddRef
,
695 IFilterGraph2_fnRelease
,
696 /* IFilterGraph fields */
697 IFilterGraph2_fnAddFilter
,
698 IFilterGraph2_fnRemoveFilter
,
699 IFilterGraph2_fnEnumFilters
,
700 IFilterGraph2_fnFindFilterByName
,
701 IFilterGraph2_fnConnectDirect
,
702 IFilterGraph2_fnReconnect
,
703 IFilterGraph2_fnDisconnect
,
704 IFilterGraph2_fnSetDefaultSyncSource
,
705 /* IGraphBuilder fields */
706 IFilterGraph2_fnConnect
,
707 IFilterGraph2_fnRender
,
708 IFilterGraph2_fnRenderFile
,
709 IFilterGraph2_fnAddSourceFilter
,
710 IFilterGraph2_fnSetLogFile
,
711 IFilterGraph2_fnAbort
,
712 IFilterGraph2_fnShouldOperationContinue
,
713 /* IFilterGraph2 fields */
714 IFilterGraph2_fnAddSourceFilterForMoniker
,
715 IFilterGraph2_fnReconnectEx
,
716 IFilterGraph2_fnRenderEx
,
719 HRESULT
CFilterGraph_InitIFilterGraph2( CFilterGraph
* pfg
)
722 ICOM_VTBL(&pfg
->fgraph
) = &ifgraph
;
724 pfg
->m_pFilterList
= QUARTZ_CompList_Alloc();
725 if ( pfg
->m_pFilterList
== NULL
)
726 return E_OUTOFMEMORY
;
731 void CFilterGraph_UninitIFilterGraph2( CFilterGraph
* pfg
)
733 QUARTZ_CompListItem
* pItem
;
737 /* remove all filters... */
740 pItem
= QUARTZ_CompList_GetFirst( pfg
->m_pFilterList
);
743 IFilterGraph2_RemoveFilter(
744 (IFilterGraph2
*)(&pfg
->fgraph
),
745 (IBaseFilter
*)QUARTZ_CompList_GetItemPtr(pItem
) );
748 QUARTZ_CompList_Free( pfg
->m_pFilterList
);