2 * Implementation of IFilterGraph and related interfaces
5 * FIXME - create a thread to process some methods correctly.
8 * FIXME - process Pause/Stop asynchronously and notify when completed.
11 * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42 #include "wine/debug.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
45 #include "quartz_private.h"
53 #define NUMELEMS(elem) (sizeof(elem)/sizeof(elem[0]))
56 static HRESULT CFilterGraph_DisconnectAllPins( IBaseFilter* pFilter )
58 IEnumPins* pEnum = NULL;
64 hr = IBaseFilter_EnumPins( pFilter, &pEnum );
74 hr = IEnumPins_Next( pEnum, 1, &pPin, &cFetched );
77 if ( hr != NOERROR || pPin == NULL || cFetched != 1 )
84 hr = IPin_ConnectedTo(pPin,&pConnTo);
85 if ( hr == NOERROR && pConnTo != NULL )
87 IPin_Disconnect(pPin);
88 IPin_Disconnect(pConnTo);
89 IPin_Release(pConnTo);
95 IEnumPins_Release( pEnum );
101 static HRESULT CFilterGraph_GraphChanged( CFilterGraph* This )
103 /* IDistributorNotify_NotifyGraphChange() */
105 This->m_lGraphVersion ++;
110 /***************************************************************************
112 * CFilterGraph internal methods for IFilterGraph2::AddSourceFilter().
116 static HRESULT QUARTZ_PeekFile(
117 const WCHAR* pwszFileName,
118 BYTE* pData, DWORD cbData, DWORD* pcbRead )
124 hFile = CreateFileW( pwszFileName,
125 GENERIC_READ, FILE_SHARE_READ,
126 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL );
127 if ( hFile == INVALID_HANDLE_VALUE )
129 if ( ReadFile( hFile, pData, cbData, pcbRead, NULL ) )
131 CloseHandle( hFile );
137 static const WCHAR* skip_space(const WCHAR* pwsz)
139 if ( pwsz == NULL ) return NULL;
140 while ( *pwsz == (WCHAR)' ' ) pwsz++;
144 static const WCHAR* get_dword(const WCHAR* pwsz,DWORD* pdw)
149 if ( pwsz == NULL ) return NULL;
150 while ( *pwsz >= (WCHAR)'0' && *pwsz <= (WCHAR)'9' )
152 dw = dw * 10 + (DWORD)(*pwsz-(WCHAR)'0');
159 static int wchar_to_hex(WCHAR wch)
161 if ( wch >= (WCHAR)'0' && wch <= (WCHAR)'9' )
162 return (int)(wch - (WCHAR)'0');
163 if ( wch >= (WCHAR)'A' && wch <= (WCHAR)'F' )
164 return (int)(wch - (WCHAR)'A' + 10);
165 if ( wch >= (WCHAR)'a' && wch <= (WCHAR)'f' )
166 return (int)(wch - (WCHAR)'a' + 10);
170 static const WCHAR* get_hex(const WCHAR* pwsz,BYTE* pb)
175 if ( pwsz == NULL ) return NULL;
176 hi = wchar_to_hex(*pwsz); if ( hi < 0 ) return NULL; pwsz++;
177 lo = wchar_to_hex(*pwsz); if ( lo < 0 ) return NULL; pwsz++;
178 *pb = (BYTE)( (hi << 4) | lo );
182 static const WCHAR* skip_hex(const WCHAR* pwsz)
184 if ( pwsz == NULL ) return NULL;
187 if ( wchar_to_hex(*pwsz) < 0 )
194 static const WCHAR* next_token(const WCHAR* pwsz)
196 if ( pwsz == NULL ) return NULL;
197 pwsz = skip_space(pwsz);
198 if ( *pwsz != (WCHAR)',' ) return NULL; pwsz++;
199 return skip_space(pwsz);
203 static HRESULT QUARTZ_SourceTypeIsMatch(
204 const BYTE* pData, DWORD cbData,
205 const WCHAR* pwszTempl, DWORD cchTempl )
210 const WCHAR* pwszMask;
211 const WCHAR* pwszValue;
215 TRACE("(%p,%lu,%s,%lu)\n",pData,cbData,debugstr_w(pwszTempl),cchTempl);
217 pwszTempl = skip_space(pwszTempl);
220 pwszTempl = get_dword(pwszTempl,&dwOfs);
221 pwszTempl = next_token(pwszTempl);
222 pwszTempl = get_dword(pwszTempl,&cbLen);
223 pwszMask = pwszTempl = next_token(pwszTempl);
224 pwszTempl = skip_hex(pwszTempl);
225 pwszValue = pwszTempl = next_token(pwszTempl);
226 pwszTempl = skip_hex(pwszValue);
227 pwszTempl = skip_space(pwszTempl);
228 if ( pwszValue == NULL )
230 WARN( "parse error\n" );
234 if ( dwOfs >= cbData || ( (dwOfs+cbLen) >= cbData ) )
236 WARN( "length of given data is too short\n" );
240 for ( n = 0; n < cbLen; n++ )
242 pwszMask = get_hex(pwszMask,&bMask);
243 if ( pwszMask == NULL ) bMask = 0xff;
244 pwszValue = get_hex(pwszValue,&bValue);
245 if ( pwszValue == NULL )
247 WARN( "parse error - invalid hex data\n" );
250 if ( (pData[dwOfs+n]&bMask) != (bValue&bMask) )
252 TRACE( "not matched\n" );
257 if ( *pwszTempl == 0 )
259 pwszTempl = next_token(pwszTempl);
260 if ( pwszTempl == NULL )
262 WARN( "parse error\n" );
267 TRACE( "matched\n" );
271 static HRESULT QUARTZ_GetSourceTypeFromData(
272 const BYTE* pData, DWORD cbData,
273 GUID* pidMajor, GUID* pidSub, CLSID* pidSource )
275 HRESULT hr = S_FALSE;
279 WCHAR wszSource[128];
280 WCHAR wszSourceFilter[128];
281 WCHAR* pwszLocalBuf = NULL;
283 DWORD cbLocalBuf = 0;
293 FILETIME ftLastWrite;
294 static const WCHAR wszFmt[] = {'%','l','u',0};
296 if ( RegOpenKeyExW( HKEY_CLASSES_ROOT, QUARTZ_wszMediaType, 0, KEY_READ, &hkMajor ) == ERROR_SUCCESS )
299 while ( hr == S_FALSE )
301 cbPath = NUMELEMS(wszMajor)-1;
303 hkMajor, dwIndexMajor ++, wszMajor, &cbPath,
304 NULL, NULL, NULL, &ftLastWrite );
305 if ( lr != ERROR_SUCCESS )
307 if ( RegOpenKeyExW( hkMajor, wszMajor, 0, KEY_READ, &hkSub ) == ERROR_SUCCESS )
310 while ( hr == S_FALSE )
312 cbPath = NUMELEMS(wszSub)-1;
314 hkSub, dwIndexSub ++, wszSub, &cbPath,
315 NULL, NULL, NULL, &ftLastWrite );
316 if ( lr != ERROR_SUCCESS )
318 if ( RegOpenKeyExW( hkSub, wszSub, 0, KEY_READ, &hkSource ) == ERROR_SUCCESS )
321 while ( hr == S_FALSE )
323 wsprintfW(wszSource,wszFmt,dwIndexSource++);
324 lr = RegQueryValueExW(
325 hkSource, wszSource, NULL,
326 &dwRegType, NULL, &cbRegData );
327 if ( lr != ERROR_SUCCESS )
329 if ( cbLocalBuf < cbRegData )
331 pwszTemp = (WCHAR*)QUARTZ_ReallocMem( pwszLocalBuf, cbRegData+sizeof(WCHAR) );
332 if ( pwszTemp == NULL )
337 pwszLocalBuf = pwszTemp;
338 cbLocalBuf = cbRegData+sizeof(WCHAR);
340 cbRegData = cbLocalBuf;
341 lr = RegQueryValueExW(
342 hkSource, wszSource, NULL,
343 &dwRegType, (BYTE*)pwszLocalBuf, &cbRegData );
344 if ( lr != ERROR_SUCCESS )
347 hr = QUARTZ_SourceTypeIsMatch(
349 pwszLocalBuf, cbRegData / sizeof(WCHAR) );
352 hr = CLSIDFromString(wszMajor,pidMajor);
354 hr = CLSIDFromString(wszSub,pidSub);
357 lstrcpyW(wszSource,QUARTZ_wszSourceFilter);
358 cbRegData = NUMELEMS(wszSourceFilter)-sizeof(WCHAR);
359 lr = RegQueryValueExW(
360 hkSource, wszSource, NULL,
362 (BYTE*)wszSourceFilter, &cbRegData );
363 if ( lr == ERROR_SUCCESS )
365 hr = CLSIDFromString(wszSourceFilter,pidSource);
371 if ( hr != NOERROR && SUCCEEDED(hr) )
377 RegCloseKey( hkSource );
380 RegCloseKey( hkSub );
383 RegCloseKey( hkMajor );
386 if ( pwszLocalBuf != NULL )
387 QUARTZ_FreeMem(pwszLocalBuf);
394 /***************************************************************************
396 * CFilterGraph::IFilterGraph2 methods
400 static HRESULT WINAPI
401 IFilterGraph2_fnQueryInterface(IFilterGraph2* iface,REFIID riid,void** ppobj)
403 CFilterGraph_THIS(iface,fgraph);
405 TRACE("(%p)->()\n",This);
407 return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
411 IFilterGraph2_fnAddRef(IFilterGraph2* iface)
413 CFilterGraph_THIS(iface,fgraph);
415 TRACE("(%p)->()\n",This);
417 return IUnknown_AddRef(This->unk.punkControl);
421 IFilterGraph2_fnRelease(IFilterGraph2* iface)
423 CFilterGraph_THIS(iface,fgraph);
425 TRACE("(%p)->()\n",This);
427 return IUnknown_Release(This->unk.punkControl);
430 static HRESULT WINAPI
431 IFilterGraph2_fnAddFilter(IFilterGraph2* iface,IBaseFilter* pFilter, LPCWSTR pName)
433 CFilterGraph_THIS(iface,fgraph);
436 IBaseFilter* pTempFilter;
437 FG_FilterData* pActiveFiltersNew;
439 HRESULT hrSucceeded = S_OK;
442 TRACE( "(%p)->(%p,%s)\n",This,pFilter,debugstr_w(pName) );
444 EnterCriticalSection( &This->m_csFilters );
446 hr = IMediaFilter_GetState(CFilterGraph_IMediaFilter(This),0,&fs);
447 if ( hr == VFW_S_STATE_INTERMEDIATE )
448 hr = VFW_E_STATE_CHANGED;
449 if ( fs != State_Stopped )
450 hr = VFW_E_NOT_STOPPED;
454 TRACE( "(%p) search the specified name.\n",This );
458 hr = IFilterGraph2_FindFilterByName( CFilterGraph_IFilterGraph2(This), pName, &pTempFilter );
461 IBaseFilter_Release(pTempFilter);
462 hrSucceeded = VFW_S_DUPLICATE_NAME;
469 iLen = lstrlenW(pName);
472 memcpy( info.achName, pName, sizeof(WCHAR)*iLen );
473 info.achName[iLen] = 0;
477 ZeroMemory( &info, sizeof(info) );
478 hr = IBaseFilter_QueryFilterInfo( pFilter, &info );
481 if ( info.pGraph != NULL )
483 IFilterGraph_Release(info.pGraph);
484 hr = E_FAIL; /* FIXME */
488 hr = IFilterGraph2_FindFilterByName( CFilterGraph_IFilterGraph2(This), pName, &pTempFilter );
491 pName = info.achName;
496 /* generate modified names for this filter.. */
497 iLen = lstrlenW(info.achName);
500 info.achName[iLen++] = ' ';
502 for ( i = 0; i <= 99; i++ )
504 info.achName[iLen+0] = (i%10) + '0';
505 info.achName[iLen+1] = ((i/10)%10) + '0';
506 info.achName[iLen+2] = 0;
508 hr = IFilterGraph2_FindFilterByName( CFilterGraph_IFilterGraph2(This), info.achName, &pTempFilter );
511 pName = info.achName;
516 hr = ( pName == NULL ) ? E_FAIL : VFW_E_DUPLICATE_NAME;
520 TRACE( "(%p) add this filter - %s.\n",This,debugstr_w(pName) );
522 /* register this filter. */
523 pActiveFiltersNew = (FG_FilterData*)QUARTZ_ReallocMem(
524 This->m_pActiveFilters,
525 sizeof(FG_FilterData) * (This->m_cActiveFilters+1) );
526 if ( pActiveFiltersNew == NULL )
531 This->m_pActiveFilters = pActiveFiltersNew;
532 pActiveFiltersNew = &This->m_pActiveFilters[This->m_cActiveFilters];
534 pActiveFiltersNew->pFilter = NULL;
535 pActiveFiltersNew->pPosition = NULL;
536 pActiveFiltersNew->pSeeking = NULL;
537 pActiveFiltersNew->pwszName = NULL;
538 pActiveFiltersNew->cbName = 0;
540 pActiveFiltersNew->cbName = sizeof(WCHAR)*(lstrlenW(pName)+1);
541 pActiveFiltersNew->pwszName = (WCHAR*)QUARTZ_AllocMem( pActiveFiltersNew->cbName );
542 if ( pActiveFiltersNew->pwszName == NULL )
547 memcpy( pActiveFiltersNew->pwszName, pName, pActiveFiltersNew->cbName );
549 pActiveFiltersNew->pFilter = pFilter;
550 IBaseFilter_AddRef(pFilter);
551 IBaseFilter_QueryInterface( pFilter, &IID_IMediaPosition, (void**)&pActiveFiltersNew->pPosition );
552 IBaseFilter_QueryInterface( pFilter, &IID_IMediaSeeking, (void**)&pActiveFiltersNew->pSeeking );
554 This->m_cActiveFilters ++;
556 hr = IBaseFilter_JoinFilterGraph(pFilter,(IFilterGraph*)iface,pName);
559 EnterCriticalSection( &This->m_csClock );
560 hr = IBaseFilter_SetSyncSource( pFilter, This->m_pClock );
561 LeaveCriticalSection( &This->m_csClock );
565 IBaseFilter_JoinFilterGraph(pFilter,NULL,pName);
566 IFilterGraph2_RemoveFilter(CFilterGraph_IFilterGraph2(This),pFilter);
570 hr = CFilterGraph_GraphChanged(This);
576 LeaveCriticalSection( &This->m_csFilters );
578 TRACE( "(%p) return %08lx\n", This, hr );
583 static HRESULT WINAPI
584 IFilterGraph2_fnRemoveFilter(IFilterGraph2* iface,IBaseFilter* pFilter)
586 CFilterGraph_THIS(iface,fgraph);
589 HRESULT hr = NOERROR;
591 TRACE( "(%p)->(%p)\n",This,pFilter );
593 EnterCriticalSection( &This->m_csFilters );
595 hr = IMediaFilter_GetState(CFilterGraph_IMediaFilter(This),0,&fs);
596 if ( hr == VFW_S_STATE_INTERMEDIATE )
597 hr = VFW_E_STATE_CHANGED;
598 if ( fs != State_Stopped )
599 hr = VFW_E_NOT_STOPPED;
603 hr = S_FALSE; /* FIXME? */
605 for ( n = 0; n < This->m_cActiveFilters; n++ )
607 if ( This->m_pActiveFilters[n].pFilter == pFilter )
609 CFilterGraph_DisconnectAllPins(pFilter);
610 (void)IBaseFilter_SetSyncSource( pFilter, NULL );
611 (void)IBaseFilter_JoinFilterGraph(
612 pFilter, NULL, This->m_pActiveFilters[n].pwszName );
614 if ( This->m_pActiveFilters[n].pFilter != NULL )
615 IMediaPosition_Release(This->m_pActiveFilters[n].pFilter);
616 if ( This->m_pActiveFilters[n].pPosition != NULL )
617 IMediaPosition_Release(This->m_pActiveFilters[n].pPosition);
618 if ( This->m_pActiveFilters[n].pSeeking != NULL )
619 IMediaSeeking_Release(This->m_pActiveFilters[n].pSeeking);
620 if ( This->m_pActiveFilters[n].pwszName != NULL )
621 QUARTZ_FreeMem(This->m_pActiveFilters[n].pwszName);
623 copy = This->m_cActiveFilters - n - 1;
625 memmove( &This->m_pActiveFilters[n],
626 &This->m_pActiveFilters[n+1],
627 sizeof(FG_FilterData) * copy );
628 This->m_cActiveFilters --;
630 hr = CFilterGraph_GraphChanged(This);
636 LeaveCriticalSection( &This->m_csFilters );
641 static HRESULT WINAPI
642 IFilterGraph2_fnEnumFilters(IFilterGraph2* iface,IEnumFilters** ppEnum)
644 CFilterGraph_THIS(iface,fgraph);
645 QUARTZ_CompList* pList = NULL;
649 TRACE( "(%p)->(%p)\n",This,ppEnum );
651 EnterCriticalSection( &This->m_csFilters );
653 pList = QUARTZ_CompList_Alloc();
659 for ( n = 0; n < This->m_cActiveFilters; n++ )
661 hr = QUARTZ_CompList_AddTailComp(
662 pList, (IUnknown*)This->m_pActiveFilters[n].pFilter, NULL, 0 );
667 hr = QUARTZ_CreateEnumUnknown(
668 &IID_IEnumFilters, (void**)ppEnum, pList );
671 QUARTZ_CompList_Free( pList );
673 LeaveCriticalSection( &This->m_csFilters );
678 static HRESULT WINAPI
679 IFilterGraph2_fnFindFilterByName(IFilterGraph2* iface,LPCWSTR pName,IBaseFilter** ppFilter)
681 CFilterGraph_THIS(iface,fgraph);
684 HRESULT hr = E_FAIL; /* FIXME */
686 TRACE( "(%p)->(%s,%p)\n",This,debugstr_w(pName),ppFilter );
688 if ( pName == NULL || ppFilter == NULL )
692 cbName = sizeof(WCHAR) * (lstrlenW(pName) + 1);
694 EnterCriticalSection( &This->m_csFilters );
696 for ( n = 0; n < This->m_cActiveFilters; n++ )
698 if ( This->m_pActiveFilters[n].cbName == cbName &&
699 !memcmp( This->m_pActiveFilters[n].pwszName, pName, cbName ) )
701 *ppFilter = This->m_pActiveFilters[n].pFilter;
702 IBaseFilter_AddRef(*ppFilter);
707 LeaveCriticalSection( &This->m_csFilters );
712 static HRESULT WINAPI
713 IFilterGraph2_fnConnectDirect(IFilterGraph2* iface,IPin* pOut,IPin* pIn,const AM_MEDIA_TYPE* pmt)
715 CFilterGraph_THIS(iface,fgraph);
720 FILTER_INFO finfoOut;
724 TRACE( "(%p)->(%p,%p,%p)\n",This,pOut,pIn,pmt );
726 infoIn.pFilter = NULL;
727 infoOut.pFilter = NULL;
728 finfoIn.pGraph = NULL;
729 finfoOut.pGraph = NULL;
731 EnterCriticalSection( &This->m_csFilters );
733 hr = IMediaFilter_GetState(CFilterGraph_IMediaFilter(This),0,&fs);
734 if ( hr == VFW_S_STATE_INTERMEDIATE )
735 hr = VFW_E_STATE_CHANGED;
736 if ( fs != State_Stopped )
737 hr = VFW_E_NOT_STOPPED;
741 hr = IPin_QueryPinInfo(pIn,&infoIn);
744 hr = IPin_QueryPinInfo(pOut,&infoOut);
747 if ( infoIn.pFilter == NULL || infoOut.pFilter == NULL ||
748 infoIn.dir != PINDIR_INPUT || infoOut.dir != PINDIR_OUTPUT )
754 hr = IBaseFilter_QueryFilterInfo(infoIn.pFilter,&finfoIn);
757 hr = IBaseFilter_QueryFilterInfo(infoOut.pFilter,&finfoOut);
760 if ( finfoIn.pGraph != ((IFilterGraph*)iface) ||
761 finfoOut.pGraph != ((IFilterGraph*)iface) )
768 hr = IPin_ConnectedTo(pIn,&pConnTo);
769 if ( hr == NOERROR && pConnTo != NULL )
771 IPin_Release(pConnTo);
772 hr = VFW_E_ALREADY_CONNECTED;
777 hr = IPin_ConnectedTo(pOut,&pConnTo);
778 if ( hr == NOERROR && pConnTo != NULL )
780 IPin_Release(pConnTo);
781 hr = VFW_E_ALREADY_CONNECTED;
785 TRACE("(%p) try to connect %p<->%p\n",This,pIn,pOut);
786 hr = IPin_Connect(pOut,pIn,pmt);
789 TRACE("(%p)->Connect(%p,%p) hr = %08lx\n",pOut,pIn,pmt,hr);
790 IPin_Disconnect(pOut);
791 IPin_Disconnect(pIn);
795 hr = CFilterGraph_GraphChanged(This);
800 LeaveCriticalSection( &This->m_csFilters );
802 if ( infoIn.pFilter != NULL )
803 IBaseFilter_Release(infoIn.pFilter);
804 if ( infoOut.pFilter != NULL )
805 IBaseFilter_Release(infoOut.pFilter);
806 if ( finfoIn.pGraph != NULL )
807 IFilterGraph_Release(finfoIn.pGraph);
808 if ( finfoOut.pGraph != NULL )
809 IFilterGraph_Release(finfoOut.pGraph);
814 static HRESULT WINAPI
815 IFilterGraph2_fnReconnect(IFilterGraph2* iface,IPin* pPin)
817 CFilterGraph_THIS(iface,fgraph);
819 TRACE( "(%p)->(%p)\n",This,pPin );
821 return IFilterGraph2_ReconnectEx(iface,pPin,NULL);
824 static HRESULT WINAPI
825 IFilterGraph2_fnDisconnect(IFilterGraph2* iface,IPin* pPin)
827 CFilterGraph_THIS(iface,fgraph);
831 TRACE( "(%p)->(%p)\n",This,pPin );
833 EnterCriticalSection( &This->m_csFilters );
836 hr = IPin_ConnectedTo(pPin,&pConnTo);
837 if ( hr == NOERROR && pConnTo != NULL )
839 IPin_Disconnect(pConnTo);
840 IPin_Release(pConnTo);
842 hr = IPin_Disconnect(pPin);
846 hr = CFilterGraph_GraphChanged(This);
851 LeaveCriticalSection( &This->m_csFilters );
856 static HRESULT WINAPI
857 IFilterGraph2_fnSetDefaultSyncSource(IFilterGraph2* iface)
859 CFilterGraph_THIS(iface,fgraph);
861 IReferenceClock* pClock;
864 FIXME( "(%p)->() stub!\n", This );
866 /* FIXME - search all filters from renderer. */
868 hr = QUARTZ_CreateSystemClock( NULL, (void**)&punk );
871 hr = IUnknown_QueryInterface( punk, &IID_IReferenceClock, (void**)&pClock ); IUnknown_Release( punk );
875 hr = IMediaFilter_SetSyncSource(
876 CFilterGraph_IMediaFilter(This), pClock );
877 IReferenceClock_Release( pClock );
882 static HRESULT WINAPI
883 IFilterGraph2_fnConnect(IFilterGraph2* iface,IPin* pOut,IPin* pIn)
885 CFilterGraph_THIS(iface,fgraph);
886 IFilterMapper2* pMap2 = NULL;
887 IEnumMoniker* pEnumMon = NULL;
888 IMoniker* pMon = NULL;
889 IBaseFilter* pFilter = NULL;
890 IEnumPins* pEnumPin = NULL;
891 IPin* pPinTry = NULL;
893 PIN_DIRECTION pindir;
896 BOOL bConnected = FALSE;
897 CLSID clsidOutFilter;
902 TRACE( "(%p)->(%p,%p)\n",This,pOut,pIn );
904 /* At first, try to connect directly. */
905 hr = IFilterGraph_ConnectDirect(iface,pOut,pIn,NULL);
909 /* FIXME - try to connect indirectly. */
910 FIXME( "(%p)->(%p,%p) stub!\n",This,pOut,pIn );
913 hr = IPin_QueryPinInfo(pOut,&info);
916 if ( info.pFilter == NULL )
918 hr = IBaseFilter_GetClassID(info.pFilter,&clsidOutFilter);
919 IBaseFilter_Release(info.pFilter);
924 hr = IPin_QueryPinInfo(pIn,&info);
927 if ( info.pFilter == NULL )
929 hr = IBaseFilter_GetClassID(info.pFilter,&clsidInFilter);
930 IBaseFilter_Release(info.pFilter);
934 /* FIXME - try to connect with unused filters. */
935 /* FIXME - try to connect with cached filters. */
936 /* FIXME - enumerate transform filters and try to connect */
937 hr = CoCreateInstance(
938 &CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
939 &IID_IFilterMapper2, (void**)&pMap2 );
942 hr = IFilterMapper2_EnumMatchingFilters(
943 pMap2,&pEnumMon,0,FALSE,MERIT_DO_NOT_USE+1,
944 TRUE,0,NULL,NULL,NULL,FALSE,
945 TRUE,0,NULL,NULL,NULL);
946 IFilterMapper2_Release(pMap2);
949 TRACE("try to connect indirectly\n");
953 while ( !bConnected && hr == S_OK )
955 hr = IEnumMoniker_Next(pEnumMon,1,&pMon,&cReturned);
958 hr = IMoniker_BindToObject(pMon,NULL,NULL,&IID_IBaseFilter,(void**)&pFilter );
961 hr = IBaseFilter_GetClassID(pFilter,&clsid);
963 ( IsEqualGUID(&clsidOutFilter,&clsid) || IsEqualGUID(&clsidInFilter,&clsid) ) )
966 hr = IFilterGraph2_AddFilter(iface,pFilter,NULL);
970 hr = IBaseFilter_EnumPins(pFilter,&pEnumPin);
974 while ( !bTryConnect )
976 hr = IEnumPins_Next(pEnumPin,1,&pPinTry,&cReturned);
979 hr = IPin_QueryDirection(pPinTry,&pindir);
980 if ( hr == S_OK && pindir == PINDIR_INPUT )
982 /* try to connect directly. */
983 hr = IFilterGraph2_ConnectDirect(iface,pOut,pPinTry,NULL);
988 IPin_Release(pPinTry); pPinTry = NULL;
991 IEnumPins_Release(pEnumPin); pEnumPin = NULL;
993 TRACE("TryConnect %d\n",bTryConnect);
997 hr = IBaseFilter_EnumPins(pFilter,&pEnumPin);
1000 while ( !bConnected )
1002 hr = IEnumPins_Next(pEnumPin,1,&pPinTry,&cReturned);
1005 hr = IPin_QueryDirection(pPinTry,&pindir);
1006 if ( hr == S_OK && pindir == PINDIR_OUTPUT )
1008 /* try to connect indirectly. */
1009 hr = IFilterGraph2_Connect(iface,pPinTry,pIn);
1014 IPin_Release(pPinTry); pPinTry = NULL;
1016 IEnumPins_Release(pEnumPin); pEnumPin = NULL;
1020 hr = IFilterGraph2_RemoveFilter(iface,pFilter);
1022 IBaseFilter_Release(pFilter); pFilter = NULL;
1023 if ( SUCCEEDED(hr) )
1030 IMoniker_Release(pMon); pMon = NULL;
1032 IEnumMoniker_Release(pEnumMon); pEnumMon = NULL;
1035 if ( SUCCEEDED(hr) && !bConnected )
1036 hr = VFW_E_CANNOT_CONNECT;
1041 static HRESULT WINAPI
1042 IFilterGraph2_fnRender(IFilterGraph2* iface,IPin* pOut)
1044 CFilterGraph_THIS(iface,fgraph);
1046 TRACE( "(%p)->(%p)\n",This,pOut);
1048 return IFilterGraph2_RenderEx( CFilterGraph_IFilterGraph2(This), pOut, 0, NULL );
1051 static HRESULT WINAPI
1052 IFilterGraph2_fnRenderFile(IFilterGraph2* iface,LPCWSTR lpFileName,LPCWSTR lpPlayList)
1054 CFilterGraph_THIS(iface,fgraph);
1056 IBaseFilter* pFilter = NULL;
1057 IEnumPins* pEnum = NULL;
1064 TRACE( "(%p)->(%s,%s)\n",This,
1065 debugstr_w(lpFileName),debugstr_w(lpPlayList) );
1067 if ( lpPlayList != NULL )
1068 return E_INVALIDARG;
1071 hr = IFilterGraph2_AddSourceFilter(iface,lpFileName,NULL,&pFilter);
1074 if ( pFilter == NULL )
1079 TRACE("(%p) source filter %p\n",This,pFilter);
1082 hr = IBaseFilter_EnumPins( pFilter, &pEnum );
1085 if ( pEnum == NULL )
1098 hr = IEnumPins_Next( pEnum, 1, &pPin, &cFetched );
1101 if ( hr != NOERROR || pPin == NULL || cFetched != 1 )
1106 hr = IPin_QueryDirection( pPin, &dir );
1107 if ( hr == NOERROR && dir == PINDIR_OUTPUT )
1110 hr = IFilterGraph2_Render( iface, pPin );
1111 if ( hr == NOERROR )
1114 IPin_Release( pPin );
1117 if ( hr == NOERROR )
1119 if ( cTryToRender > cActRender )
1120 hr = VFW_S_PARTIAL_RENDER;
1121 if ( cActRender == 0 )
1126 if ( pEnum != NULL )
1127 IEnumPins_Release( pEnum );
1128 if ( pFilter != NULL )
1129 IBaseFilter_Release( pFilter );
1134 static HRESULT WINAPI
1135 IFilterGraph2_fnAddSourceFilter(IFilterGraph2* iface,LPCWSTR lpFileName,LPCWSTR lpFilterName,IBaseFilter** ppBaseFilter)
1137 CFilterGraph_THIS(iface,fgraph);
1139 BYTE bStartData[512];
1143 IFileSourceFilter* pSource;
1145 FIXME( "(%p)->(%s,%s,%p)\n",This,
1146 debugstr_w(lpFileName),debugstr_w(lpFilterName),ppBaseFilter );
1148 if ( lpFileName == NULL || ppBaseFilter == NULL )
1150 *ppBaseFilter = NULL;
1152 hr = QUARTZ_PeekFile( lpFileName, bStartData, 512, &cbStartData );
1155 FIXME("cannot open %s (NOTE: URL is not implemented)\n", debugstr_w(lpFileName));
1158 ZeroMemory( &mt, sizeof(AM_MEDIA_TYPE) );
1159 mt.bFixedSizeSamples = 1;
1161 memcpy( &mt.majortype, &MEDIATYPE_Stream, sizeof(GUID) );
1162 memcpy( &mt.subtype, &MEDIASUBTYPE_NULL, sizeof(GUID) );
1163 memcpy( &mt.formattype, &FORMAT_None, sizeof(GUID) );
1164 hr = QUARTZ_GetSourceTypeFromData(
1165 bStartData, cbStartData,
1166 &mt.majortype, &mt.subtype, &clsidSource );
1169 ERR("QUARTZ_GetSourceTypeFromData() failed - return %08lx\n",hr);
1174 FIXME( "file %s - unknown format\n", debugstr_w(lpFileName) );
1175 return VFW_E_INVALID_FILE_FORMAT;
1178 hr = CoCreateInstance(
1179 &clsidSource, NULL, CLSCTX_INPROC_SERVER,
1180 &IID_IBaseFilter, (void**)ppBaseFilter );
1183 hr = IBaseFilter_QueryInterface(*ppBaseFilter,&IID_IFileSourceFilter,(void**)&pSource);
1184 if ( SUCCEEDED(hr) )
1186 hr = IFileSourceFilter_Load(pSource,lpFileName,&mt);
1187 IFileSourceFilter_Release(pSource);
1189 if ( SUCCEEDED(hr) )
1190 hr = IFilterGraph2_AddFilter(iface,*ppBaseFilter,lpFilterName);
1193 IBaseFilter_Release(*ppBaseFilter);
1194 *ppBaseFilter = NULL;
1201 static HRESULT WINAPI
1202 IFilterGraph2_fnSetLogFile(IFilterGraph2* iface,DWORD_PTR hFile)
1204 CFilterGraph_THIS(iface,fgraph);
1206 FIXME( "(%p)->() stub!\n", This );
1208 return S_OK; /* no debug output */
1211 static HRESULT WINAPI
1212 IFilterGraph2_fnAbort(IFilterGraph2* iface)
1214 CFilterGraph_THIS(iface,fgraph);
1216 FIXME( "(%p)->() stub!\n", This );
1218 /* FIXME - abort the current asynchronous task. */
1223 static HRESULT WINAPI
1224 IFilterGraph2_fnShouldOperationContinue(IFilterGraph2* iface)
1226 CFilterGraph_THIS(iface,fgraph);
1228 FIXME( "(%p)->() stub!\n", This );
1233 static HRESULT WINAPI
1234 IFilterGraph2_fnAddSourceFilterForMoniker(IFilterGraph2* iface,IMoniker* pMon,IBindCtx* pCtx,LPCWSTR pFilterName,IBaseFilter** ppFilter)
1236 CFilterGraph_THIS(iface,fgraph);
1238 FIXME( "(%p)->() stub!\n", This );
1242 static HRESULT WINAPI
1243 IFilterGraph2_fnReconnectEx(IFilterGraph2* iface,IPin* pPin,const AM_MEDIA_TYPE* pmt)
1245 CFilterGraph_THIS(iface,fgraph);
1248 FIXME( "(%p)->(%p,%p) stub!\n",This,pPin,pmt );
1250 /* reconnect asynchronously. */
1252 EnterCriticalSection( &This->m_csFilters );
1253 hr = CFilterGraph_GraphChanged(This);
1254 LeaveCriticalSection( &This->m_csFilters );
1259 static HRESULT WINAPI
1260 IFilterGraph2_fnRenderEx(IFilterGraph2* iface,IPin* pOut,DWORD dwFlags,DWORD* pdwReserved)
1262 CFilterGraph_THIS(iface,fgraph);
1264 IFilterMapper2* pMap2 = NULL;
1265 IEnumMoniker* pEnumMon = NULL;
1266 IMoniker* pMon = NULL;
1267 IBaseFilter* pFilter = NULL;
1268 IEnumPins* pEnumPin = NULL;
1270 PIN_DIRECTION pindir;
1271 BOOL bRendered = FALSE;
1274 FIXME( "(%p)->(%p,%08lx,%p) stub!\n",This,pPin,dwFlags,pdwReserved);
1276 if ( pdwReserved != NULL )
1277 return E_INVALIDARG;
1281 FIXME( "dwFlags != 0...\n" );
1282 return E_INVALIDARG;
1285 /* FIXME - must be locked */
1286 /*EnterCriticalSection( &This->m_csFilters );*/
1291 hr = CoCreateInstance(
1292 &CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
1293 &IID_IFilterMapper2, (void**)&pMap2 );
1296 hr = IFilterMapper2_EnumMatchingFilters(
1297 pMap2,&pEnumMon,0,FALSE,MERIT_DO_NOT_USE+1,
1298 TRUE,0,NULL,NULL,NULL,TRUE,
1299 FALSE,0,NULL,NULL,NULL);
1300 IFilterMapper2_Release(pMap2);
1303 TRACE("try to render pin\n");
1307 /* try to render pin. */
1308 while ( !bRendered && hr == S_OK )
1310 hr = IEnumMoniker_Next(pEnumMon,1,&pMon,&cReturned);
1313 hr = IMoniker_BindToObject(pMon,NULL,NULL,&IID_IBaseFilter,(void**)&pFilter );
1316 hr = IFilterGraph2_AddFilter(iface,pFilter,NULL);
1319 hr = IBaseFilter_EnumPins(pFilter,&pEnumPin);
1322 while ( !bRendered )
1324 hr = IEnumPins_Next(pEnumPin,1,&pPin,&cReturned);
1327 hr = IPin_QueryDirection(pPin,&pindir);
1328 if ( hr == S_OK && pindir == PINDIR_INPUT )
1330 /* try to connect. */
1331 hr = IFilterGraph2_Connect(iface,pOut,pPin);
1336 IPin_Release(pPin); pPin = NULL;
1338 IEnumPins_Release(pEnumPin); pEnumPin = NULL;
1341 hr = IFilterGraph2_RemoveFilter(iface,pFilter);
1343 IBaseFilter_Release(pFilter); pFilter = NULL;
1344 if ( SUCCEEDED(hr) )
1351 IMoniker_Release(pMon); pMon = NULL;
1353 IEnumMoniker_Release(pEnumMon); pEnumMon = NULL;
1358 /* successfully rendered(but may be partial now) */
1361 /* FIXME - try to render all inserted filters. */
1362 /* hr = VFW_S_PARTIAL_RENDER; */
1366 if ( SUCCEEDED(hr) )
1367 hr = VFW_E_CANNOT_RENDER;
1370 /*LeaveCriticalSection( &This->m_csFilters );*/
1378 static ICOM_VTABLE(IFilterGraph2) ifgraph =
1380 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1381 /* IUnknown fields */
1382 IFilterGraph2_fnQueryInterface,
1383 IFilterGraph2_fnAddRef,
1384 IFilterGraph2_fnRelease,
1385 /* IFilterGraph fields */
1386 IFilterGraph2_fnAddFilter,
1387 IFilterGraph2_fnRemoveFilter,
1388 IFilterGraph2_fnEnumFilters,
1389 IFilterGraph2_fnFindFilterByName,
1390 IFilterGraph2_fnConnectDirect,
1391 IFilterGraph2_fnReconnect,
1392 IFilterGraph2_fnDisconnect,
1393 IFilterGraph2_fnSetDefaultSyncSource,
1394 /* IGraphBuilder fields */
1395 IFilterGraph2_fnConnect,
1396 IFilterGraph2_fnRender,
1397 IFilterGraph2_fnRenderFile,
1398 IFilterGraph2_fnAddSourceFilter,
1399 IFilterGraph2_fnSetLogFile,
1400 IFilterGraph2_fnAbort,
1401 IFilterGraph2_fnShouldOperationContinue,
1402 /* IFilterGraph2 fields */
1403 IFilterGraph2_fnAddSourceFilterForMoniker,
1404 IFilterGraph2_fnReconnectEx,
1405 IFilterGraph2_fnRenderEx,
1408 HRESULT CFilterGraph_InitIFilterGraph2( CFilterGraph* pfg )
1410 TRACE("(%p)\n",pfg);
1411 ICOM_VTBL(&pfg->fgraph) = &ifgraph;
1413 InitializeCriticalSection( &pfg->m_csFilters );
1414 pfg->m_cActiveFilters = 0;
1415 pfg->m_pActiveFilters = NULL;
1420 void CFilterGraph_UninitIFilterGraph2( CFilterGraph* pfg )
1422 TRACE("(%p)\n",pfg);
1424 /* remove all filters... */
1425 while ( pfg->m_cActiveFilters > 0 )
1427 IFilterGraph2_RemoveFilter(
1428 CFilterGraph_IFilterGraph2(pfg),
1429 pfg->m_pActiveFilters[pfg->m_cActiveFilters-1].pFilter );
1432 if ( pfg->m_pActiveFilters != NULL )
1433 QUARTZ_FreeMem( pfg->m_pActiveFilters );
1435 DeleteCriticalSection( &pfg->m_csFilters );
1438 /***************************************************************************
1440 * CFilterGraph::IGraphVersion methods
1444 static HRESULT WINAPI
1445 IGraphVersion_fnQueryInterface(IGraphVersion* iface,REFIID riid,void** ppobj)
1447 CFilterGraph_THIS(iface,graphversion);
1449 TRACE("(%p)->()\n",This);
1451 return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
1455 IGraphVersion_fnAddRef(IGraphVersion* iface)
1457 CFilterGraph_THIS(iface,graphversion);
1459 TRACE("(%p)->()\n",This);
1461 return IUnknown_AddRef(This->unk.punkControl);
1465 IGraphVersion_fnRelease(IGraphVersion* iface)
1467 CFilterGraph_THIS(iface,graphversion);
1469 TRACE("(%p)->()\n",This);
1471 return IUnknown_Release(This->unk.punkControl);
1475 static HRESULT WINAPI
1476 IGraphVersion_fnQueryVersion(IGraphVersion* iface,LONG* plVersion)
1478 CFilterGraph_THIS(iface,graphversion);
1480 TRACE("(%p)->(%p)\n",This,plVersion);
1482 if ( plVersion == NULL )
1485 EnterCriticalSection( &This->m_csFilters );
1486 *plVersion = This->m_lGraphVersion;
1487 LeaveCriticalSection( &This->m_csFilters );
1493 static ICOM_VTABLE(IGraphVersion) igraphversion =
1495 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1496 /* IUnknown fields */
1497 IGraphVersion_fnQueryInterface,
1498 IGraphVersion_fnAddRef,
1499 IGraphVersion_fnRelease,
1500 /* IGraphVersion fields */
1501 IGraphVersion_fnQueryVersion,
1506 HRESULT CFilterGraph_InitIGraphVersion( CFilterGraph* pfg )
1508 TRACE("(%p)\n",pfg);
1509 ICOM_VTBL(&pfg->graphversion) = &igraphversion;
1511 pfg->m_lGraphVersion = 1;
1516 void CFilterGraph_UninitIGraphVersion( CFilterGraph* pfg )
1518 TRACE("(%p)\n",pfg);