From 0f1f42ea9c664275564325342807892fe10b7e9f Mon Sep 17 00:00:00 2001 From: Hidenori Takeshima Date: Mon, 1 Apr 2002 20:59:24 +0000 Subject: [PATCH] Fixed some bugs. Implemented some methods of CLSID_ACMWrapper. --- dlls/quartz/README | 2 - dlls/quartz/acmwrap.c | 495 ++++++++++++++++++++++++++++++++++++++++- dlls/quartz/basefilt.c | 15 ++ dlls/quartz/fmap.c | 78 +++++-- dlls/quartz/main.c | 1 + dlls/quartz/mpgparse.c | 50 ++++- dlls/quartz/parser.c | 50 +++-- dlls/quartz/xform.h | 1 + winedefault.reg | 40 ++++ 9 files changed, 673 insertions(+), 59 deletions(-) diff --git a/dlls/quartz/README b/dlls/quartz/README index 0bcd135b5e0..44de309e38f 100644 --- a/dlls/quartz/README +++ b/dlls/quartz/README @@ -7,14 +7,12 @@ TODO - merge some C sources - implement filters - restruct color-space converter - - add FilterData to winedefault.reg for Connect() and Render() - sort active filters in filter graph - sort regfilters in Merit order - fix deadlocks in Receive/EndOfStream - handle plug-in distributor - handle seeking - implement some interfaces as plug-ins(???) - - implement ACM drivers (g711) - implement ACM wrapper (improve xform) - implement mciqtz(mci driver for quartz) - implement renderer diff --git a/dlls/quartz/acmwrap.c b/dlls/quartz/acmwrap.c index b5393e17b78..d3ef8238e3d 100644 --- a/dlls/quartz/acmwrap.c +++ b/dlls/quartz/acmwrap.c @@ -2,6 +2,7 @@ * Implements ACM Wrapper(CLSID_ACMWrapper). * * FIXME - stub + * FIXME - no encoding * * Copyright (C) 2002 Hidenori TAKESHIMA * @@ -40,6 +41,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(quartz); #include "quartz_private.h" #include "xform.h" +#include "mtype.h" static const WCHAR ACMWrapper_FilterName[] = @@ -49,8 +51,152 @@ static const WCHAR ACMWrapper_FilterName[] = typedef struct CACMWrapperImpl { HACMSTREAM has; + WAVEFORMATEX* pwfxIn; + AM_MEDIA_TYPE* pmtOuts; + DWORD cOuts; + BYTE* pConvBuf; + DWORD cbConvBlockSize; + DWORD cbConvCached; + DWORD cbConvAllocated; } CACMWrapperImpl; + +static +void ACMWrapper_CleanupMTypes( CACMWrapperImpl* This ) +{ + DWORD n; + + if ( This->pmtOuts == NULL ) return; + for ( n = 0; n < This->cOuts; n++ ) + { + QUARTZ_MediaType_Free( &This->pmtOuts[n] ); + } + QUARTZ_FreeMem( This->pmtOuts ); + This->pmtOuts = NULL; + This->cOuts = 0; +} + +static +void ACMWrapper_CleanupConvBuf( CACMWrapperImpl* This ) +{ + if ( This->pConvBuf != NULL ) + { + QUARTZ_FreeMem( This->pConvBuf ); + This->pConvBuf = NULL; + } + This->cbConvBlockSize = 0; + This->cbConvCached = 0; + This->cbConvAllocated = 0; +} + +static +const WAVEFORMATEX* ACMWrapper_GetAudioFmt( const AM_MEDIA_TYPE* pmt ) +{ + const WAVEFORMATEX* pwfx; + + if ( !IsEqualGUID( &pmt->majortype, &MEDIATYPE_Audio ) ) + return NULL; + if ( !IsEqualGUID( &pmt->subtype, &MEDIASUBTYPE_NULL ) && + !QUARTZ_MediaSubType_IsFourCC( &pmt->subtype ) ) + return NULL; + if ( !IsEqualGUID( &pmt->formattype, &FORMAT_WaveFormatEx ) ) + return NULL; + if ( pmt->pbFormat == NULL || + pmt->cbFormat < (sizeof(WAVEFORMATEX)-sizeof(WORD)) ) + return NULL; + + pwfx = (const WAVEFORMATEX*)pmt->pbFormat; + + if ( pwfx->wFormatTag != 1 && pmt->cbFormat < sizeof(WAVEFORMATEX) ) + return NULL; + + return pwfx; +} + +static +HRESULT ACMWrapper_SetupAudioFmt( + AM_MEDIA_TYPE* pmt, + DWORD cbFormat, WORD wFormatTag, DWORD dwBlockAlign ) +{ + ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) ); + memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) ); + QUARTZ_MediaSubType_FromFourCC( &pmt->subtype, (DWORD)wFormatTag ); + pmt->bFixedSizeSamples = 1; + pmt->bTemporalCompression = 1; + pmt->lSampleSize = dwBlockAlign; + memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) ); + pmt->pUnk = NULL; + pmt->cbFormat = cbFormat; + pmt->pbFormat = (BYTE*)CoTaskMemAlloc( cbFormat ); + if ( pmt->pbFormat == NULL ) + return E_OUTOFMEMORY; + + return S_OK; +} + +static +void ACMWrapper_FillFmtPCM( + WAVEFORMATEX* pwfxOut, + const WAVEFORMATEX* pwfxIn, + WORD wBitsPerSampOut ) +{ + pwfxOut->wFormatTag = 1; + pwfxOut->nChannels = pwfxIn->nChannels; + pwfxOut->nSamplesPerSec = pwfxIn->nSamplesPerSec; + pwfxOut->nAvgBytesPerSec = ((DWORD)pwfxIn->nSamplesPerSec * (DWORD)pwfxIn->nChannels * (DWORD)wBitsPerSampOut) >> 3; + pwfxOut->nBlockAlign = (pwfxIn->nChannels * wBitsPerSampOut) >> 3; + pwfxOut->wBitsPerSample = wBitsPerSampOut; + pwfxOut->cbSize = 0; +} + +static +BOOL ACMWrapper_IsSupported( + WAVEFORMATEX* pwfxOut, + WAVEFORMATEX* pwfxIn ) +{ + MMRESULT mr; + + mr = acmStreamOpen( + NULL,(HACMDRIVER)NULL, + pwfxIn,pwfxOut,NULL, + 0,0,ACM_STREAMOPENF_QUERY); + if ( mr == ACMERR_NOTPOSSIBLE ) + mr = acmStreamOpen( + NULL,(HACMDRIVER)NULL, + pwfxIn,pwfxOut,NULL, + 0,0,ACM_STREAMOPENF_NONREALTIME|ACM_STREAMOPENF_QUERY); + return !!(mr == MMSYSERR_NOERROR); +} + +static +HRESULT ACMWrapper_StreamOpen( + HACMSTREAM* phas, + WAVEFORMATEX* pwfxOut, + WAVEFORMATEX* pwfxIn ) +{ + HACMSTREAM has = (HACMSTREAM)NULL; + MMRESULT mr; + + mr = acmStreamOpen( + &has,(HACMDRIVER)NULL, + pwfxIn,pwfxOut,NULL, + 0,0,0); + if ( mr == ACMERR_NOTPOSSIBLE ) + mr = acmStreamOpen( + &has,(HACMDRIVER)NULL, + pwfxIn,pwfxOut,NULL, + 0,0,ACM_STREAMOPENF_NONREALTIME); + if ( mr != MMSYSERR_NOERROR ) + { + if ( mr == MMSYSERR_NOMEM ) + return E_OUTOFMEMORY; + return E_FAIL; + } + + *phas = has; + return S_OK; +} + /*************************************************************************** * * CACMWrapperImpl methods @@ -84,8 +230,12 @@ static HRESULT ACMWrapper_Init( CTransformBaseImpl* pImpl ) /* construct */ This->has = (HACMSTREAM)NULL; + This->pwfxIn = NULL; + This->pmtOuts = NULL; + This->cOuts = 0; + This->pConvBuf = NULL; - return E_NOTIMPL; + return S_OK; } static HRESULT ACMWrapper_Cleanup( CTransformBaseImpl* pImpl ) @@ -99,6 +249,9 @@ static HRESULT ACMWrapper_Cleanup( CTransformBaseImpl* pImpl ) /* destruct */ ACMWrapper_Close( This ); + QUARTZ_FreeMem( This->pwfxIn ); + ACMWrapper_CleanupMTypes( This ); + ACMWrapper_CleanupConvBuf( This ); QUARTZ_FreeMem( This ); pImpl->m_pUserData = NULL; @@ -109,57 +262,362 @@ static HRESULT ACMWrapper_Cleanup( CTransformBaseImpl* pImpl ) static HRESULT ACMWrapper_CheckMediaType( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut ) { CACMWrapperImpl* This = pImpl->m_pUserData; + const WAVEFORMATEX* pwfxIn; + const WAVEFORMATEX* pwfxOut; + WAVEFORMATEX wfx; FIXME("(%p)\n",This); if ( This == NULL ) return E_UNEXPECTED; - return E_NOTIMPL; + pwfxIn = ACMWrapper_GetAudioFmt(pmtIn); + if ( pwfxIn == NULL || + pwfxIn->wFormatTag == 0 || + pwfxIn->wFormatTag == 1 ) + { + TRACE("pwfxIn is not a compressed audio\n"); + return E_FAIL; + } + if ( pmtOut != NULL ) + { + pwfxOut = ACMWrapper_GetAudioFmt(pmtOut); + if ( pwfxOut == NULL || pwfxOut->wFormatTag != 1 ) + { + TRACE("pwfxOut is not a linear PCM\n"); + return E_FAIL; + } + if ( pwfxIn->nChannels != pwfxOut->nChannels || + pwfxIn->nSamplesPerSec != pwfxOut->nSamplesPerSec ) + { + TRACE("nChannels or nSamplesPerSec is not matched\n"); + return E_FAIL; + } + if ( !ACMWrapper_IsSupported((WAVEFORMATEX*)pwfxOut,(WAVEFORMATEX*)pwfxIn) ) + { + TRACE("specified formats are not supported by ACM\n"); + return E_FAIL; + } + } + else + { + ACMWrapper_FillFmtPCM(&wfx,pwfxIn,8); + if ( ACMWrapper_IsSupported(&wfx,(WAVEFORMATEX*)pwfxIn) ) + { + TRACE("compressed audio - can be decoded to 8bit\n"); + return S_OK; + } + ACMWrapper_FillFmtPCM(&wfx,pwfxIn,16); + if ( ACMWrapper_IsSupported(&wfx,(WAVEFORMATEX*)pwfxIn) ) + { + TRACE("compressed audio - can be decoded to 16bit\n"); + return S_OK; + } + + TRACE("unhandled audio %04x\n",(unsigned)pwfxIn->wFormatTag); + return E_FAIL; + } + + return S_OK; } static HRESULT ACMWrapper_GetOutputTypes( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE** ppmtAcceptTypes, ULONG* pcAcceptTypes ) { CACMWrapperImpl* This = pImpl->m_pUserData; HRESULT hr; + const WAVEFORMATEX* pwfxIn; + AM_MEDIA_TYPE* pmtTry; + WAVEFORMATEX* pwfxTry; FIXME("(%p)\n",This); hr = ACMWrapper_CheckMediaType( pImpl, pmtIn, NULL ); if ( FAILED(hr) ) return hr; + pwfxIn = (const WAVEFORMATEX*)pmtIn->pbFormat; - return E_NOTIMPL; + ACMWrapper_CleanupMTypes( This ); + This->pmtOuts = QUARTZ_AllocMem( sizeof(AM_MEDIA_TYPE) * 2 ); + if ( This->pmtOuts == NULL ) + return E_OUTOFMEMORY; + This->cOuts = 0; + + pmtTry = &This->pmtOuts[This->cOuts]; + hr = ACMWrapper_SetupAudioFmt( + pmtTry, + sizeof(WAVEFORMATEX), 1, + (pwfxIn->nChannels * 8) >> 3 ); + if ( FAILED(hr) ) goto err; + pwfxTry = (WAVEFORMATEX*)pmtTry->pbFormat; + ACMWrapper_FillFmtPCM( pwfxTry, pwfxIn, 8 ); + if ( ACMWrapper_IsSupported( pwfxTry, (WAVEFORMATEX*)pwfxIn ) ) + This->cOuts ++; + + pmtTry = &This->pmtOuts[This->cOuts]; + hr = ACMWrapper_SetupAudioFmt( + pmtTry, + sizeof(WAVEFORMATEX), 1, + (pwfxIn->nChannels * 16) >> 3 ); + if ( FAILED(hr) ) goto err; + pwfxTry = (WAVEFORMATEX*)pmtTry->pbFormat; + ACMWrapper_FillFmtPCM( pwfxTry, pwfxIn, 16 ); + if ( ACMWrapper_IsSupported( pwfxTry, (WAVEFORMATEX*)pwfxIn ) ) + This->cOuts ++; + + *ppmtAcceptTypes = This->pmtOuts; + *pcAcceptTypes = This->cOuts; + + return S_OK; +err: + ACMWrapper_CleanupMTypes( This ); + return hr; } +static HRESULT +ACMWrapper_GetConvBufSize( + CTransformBaseImpl* pImpl, + CACMWrapperImpl* This, + DWORD* pcbInput, DWORD* pcbOutput, + const AM_MEDIA_TYPE* pmtOut, const AM_MEDIA_TYPE* pmtIn ) +{ + HRESULT hr; + const WAVEFORMATEX* pwfxIn; + const WAVEFORMATEX* pwfxOut; + HACMSTREAM has; + MMRESULT mr; + DWORD cbInput; + DWORD cbOutput; + + if ( This == NULL ) + return E_UNEXPECTED; + + hr = ACMWrapper_CheckMediaType( pImpl, pmtIn, pmtOut ); + if ( FAILED(hr) ) + return hr; + pwfxIn = (const WAVEFORMATEX*)pmtIn->pbFormat; + pwfxOut = (const WAVEFORMATEX*)pmtOut->pbFormat; + + hr = ACMWrapper_StreamOpen( + &has, (WAVEFORMATEX*)pwfxOut, (WAVEFORMATEX*)pwfxIn ); + if ( FAILED(hr) ) + return hr; + + cbInput = (pwfxIn->nAvgBytesPerSec + pwfxIn->nBlockAlign - 1) / pwfxIn->nBlockAlign * pwfxIn->nBlockAlign; + cbOutput = 0; + + mr = acmStreamSize( has, cbInput, &cbOutput, ACM_STREAMSIZEF_SOURCE ); + acmStreamClose( has, 0 ); + + if ( mr != MMSYSERR_NOERROR || cbOutput == 0 ) + return E_FAIL; + TRACE("size %lu -> %lu\n", cbInput, cbOutput); + + if ( pcbInput != NULL ) *pcbInput = cbInput; + if ( pcbOutput != NULL ) *pcbOutput = cbOutput; + + return S_OK; +} + + static HRESULT ACMWrapper_GetAllocProp( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, ALLOCATOR_PROPERTIES* pProp, BOOL* pbTransInPlace, BOOL* pbTryToReuseSample ) { CACMWrapperImpl* This = pImpl->m_pUserData; HRESULT hr; + DWORD cbOutput; - FIXME("(%p)\n",This); + TRACE("(%p)\n",This); if ( This == NULL ) return E_UNEXPECTED; - hr = ACMWrapper_CheckMediaType( pImpl, pmtIn, pmtOut ); + hr = ACMWrapper_GetConvBufSize( + pImpl, This, NULL, &cbOutput, pmtOut, pmtIn ); if ( FAILED(hr) ) return hr; + pProp->cBuffers = 1; + pProp->cbBuffer = cbOutput; + *pbTransInPlace = FALSE; *pbTryToReuseSample = FALSE; - return E_NOTIMPL; + return S_OK; } static HRESULT ACMWrapper_BeginTransform( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, BOOL bReuseSample ) { CACMWrapperImpl* This = pImpl->m_pUserData; + HRESULT hr; + const WAVEFORMATEX* pwfxIn; + const WAVEFORMATEX* pwfxOut; + DWORD cbInput; FIXME("(%p,%p,%p,%d)\n",This,pmtIn,pmtOut,bReuseSample); if ( This == NULL ) return E_UNEXPECTED; - return E_NOTIMPL; + ACMWrapper_Close( This ); + ACMWrapper_CleanupMTypes( This ); + ACMWrapper_CleanupConvBuf( This ); + + hr = ACMWrapper_GetConvBufSize( + pImpl, This, &cbInput, NULL, pmtOut, pmtIn ); + if ( FAILED(hr) ) + return hr; + pwfxIn = (const WAVEFORMATEX*)pmtIn->pbFormat; + pwfxOut = (const WAVEFORMATEX*)pmtOut->pbFormat; + + This->pConvBuf = (BYTE*)QUARTZ_AllocMem( cbInput ); + if ( This->pConvBuf == NULL ) + return E_OUTOFMEMORY; + This->cbConvBlockSize = pwfxIn->nBlockAlign; + This->cbConvCached = 0; + This->cbConvAllocated = cbInput; + + hr = ACMWrapper_StreamOpen( + &This->has, + (WAVEFORMATEX*)pmtOut, (WAVEFORMATEX*)pmtIn ); + if ( FAILED(hr) ) + return E_FAIL; + + return S_OK; +} + +static HRESULT ACMWrapper_Convert( + CTransformBaseImpl* pImpl, + CACMWrapperImpl* This, + BYTE* pbSrc, DWORD cbSrcLen, + DWORD dwConvertFlags ) +{ + ACMSTREAMHEADER ash; + MMRESULT mr; + HRESULT hr = E_FAIL; + DWORD dwConvCallFlags; + DWORD cb; + IMediaSample* pSampOut = NULL; + BYTE* pOutBuf; + LONG lOutBufLen; + + TRACE("()\n"); + + if ( This->pConvBuf == NULL ) + return E_UNEXPECTED; + + dwConvCallFlags = ACM_STREAMCONVERTF_BLOCKALIGN; + if ( dwConvertFlags & ACM_STREAMCONVERTF_START ) + { + dwConvCallFlags |= ACM_STREAMCONVERTF_START; + This->cbConvCached = 0; + } + + while ( 1 ) + { + cb = cbSrcLen + This->cbConvCached; + if ( cb > This->cbConvAllocated ) + cb = This->cbConvAllocated; + cb -= This->cbConvCached; + if ( cb > 0 ) + { + memcpy( This->pConvBuf+This->cbConvCached, + pbSrc, cb ); + pbSrc += cb; + cbSrcLen -= cb; + This->cbConvCached += cb; + } + + cb = This->cbConvCached / This->cbConvBlockSize * This->cbConvBlockSize; + if ( cb == 0 ) + { + if ( dwConvertFlags & ACM_STREAMCONVERTF_END ) + { + dwConvCallFlags &= ~ACM_STREAMCONVERTF_BLOCKALIGN; + dwConvCallFlags |= ACM_STREAMCONVERTF_END; + cb = This->cbConvCached; + } + if ( cb == 0 ) + { + hr = S_OK; + break; + } + } + + ZeroMemory( &ash, sizeof(ash) ); + ash.cbStruct = sizeof(ash); + ash.pbSrc = This->pConvBuf; + ash.cbSrcLength = cb; + + hr = IMemAllocator_GetBuffer( + pImpl->m_pOutPinAllocator, + &pSampOut, NULL, NULL, 0 ); + if ( FAILED(hr) ) + break; + hr = IMediaSample_SetSyncPoint( pSampOut, TRUE ); + if ( FAILED(hr) ) + break; + if ( dwConvCallFlags & ACM_STREAMCONVERTF_START ) + { + hr = IMediaSample_SetDiscontinuity( pSampOut, TRUE ); + if ( FAILED(hr) ) + break; + } + hr = IMediaSample_GetPointer( pSampOut, &pOutBuf ); + if ( FAILED(hr) ) + break; + lOutBufLen = IMediaSample_GetSize( pSampOut ); + if ( lOutBufLen <= 0 ) + { + hr = E_FAIL; + break; + } + ash.pbDst = pOutBuf; + ash.cbDstLength = lOutBufLen; + + mr = acmStreamPrepareHeader( + This->has, &ash, 0 ); + if ( mr == MMSYSERR_NOERROR ) + mr = acmStreamConvert( + This->has, &ash, dwConvCallFlags ); + if ( mr == MMSYSERR_NOERROR ) + mr = acmStreamUnprepareHeader( + This->has, &ash, 0 ); + if ( mr != MMSYSERR_NOERROR || ash.cbSrcLengthUsed == 0 ) + { + hr = E_FAIL; + break; + } + + if ( ash.cbDstLengthUsed > 0 ) + { + hr = IMediaSample_SetActualDataLength( pSampOut, ash.cbDstLengthUsed ); + if ( FAILED(hr) ) + break; + + hr = CPinBaseImpl_SendSample( + &pImpl->pOutPin->pin, + pSampOut ); + if ( FAILED(hr) ) + break; + } + + if ( This->cbConvCached == ash.cbSrcLengthUsed ) + { + This->cbConvCached = 0; + } + else + { + This->cbConvCached -= ash.cbSrcLengthUsed; + memmove( This->pConvBuf, + This->pConvBuf + ash.cbSrcLengthUsed, + This->cbConvCached ); + } + + IMediaSample_Release( pSampOut ); pSampOut = NULL; + dwConvCallFlags &= ~ACM_STREAMCONVERTF_START; + } + + if ( pSampOut != NULL ) + IMediaSample_Release( pSampOut ); + + return hr; } static HRESULT ACMWrapper_ProcessReceive( CTransformBaseImpl* pImpl, IMediaSample* pSampIn ) @@ -168,32 +626,47 @@ static HRESULT ACMWrapper_ProcessReceive( CTransformBaseImpl* pImpl, IMediaSampl BYTE* pDataIn = NULL; LONG lDataInLen; HRESULT hr; + DWORD dwConvFlags = 0; FIXME("(%p)\n",This); - if ( This == NULL ) + if ( This == NULL || This->has == (HACMSTREAM)NULL ) return E_UNEXPECTED; hr = IMediaSample_GetPointer( pSampIn, &pDataIn ); if ( FAILED(hr) ) return hr; lDataInLen = IMediaSample_GetActualDataLength( pSampIn ); + if ( lDataInLen < 0 ) + return E_FAIL; + if ( IMediaSample_IsDiscontinuity( pSampIn ) != S_OK ) + dwConvFlags |= ACM_STREAMCONVERTF_START; - return E_NOTIMPL; + return ACMWrapper_Convert( + pImpl, This, pDataIn, (DWORD)lDataInLen, + dwConvFlags ); } static HRESULT ACMWrapper_EndTransform( CTransformBaseImpl* pImpl ) { CACMWrapperImpl* This = pImpl->m_pUserData; + HRESULT hr; + DWORD dwConvFlags = ACM_STREAMCONVERTF_END; TRACE("(%p)\n",This); if ( This == NULL ) return E_UNEXPECTED; - ACMWrapper_Close( This ); + hr = ACMWrapper_Convert( + pImpl, This, NULL, 0, + dwConvFlags ); - return S_OK; + ACMWrapper_Close( This ); + ACMWrapper_CleanupMTypes( This ); + ACMWrapper_CleanupConvBuf( This ); + + return hr; } static const TransformBaseHandlers transhandlers = diff --git a/dlls/quartz/basefilt.c b/dlls/quartz/basefilt.c index 4689786b1ae..143dbd3bacf 100644 --- a/dlls/quartz/basefilt.c +++ b/dlls/quartz/basefilt.c @@ -99,6 +99,11 @@ CBaseFilterImpl_fnStop(IBaseFilter* iface) hr = NOERROR; EnterCriticalSection( &This->csFilter ); + if ( This->bIntermediateState ) + { + LeaveCriticalSection( &This->csFilter ); + return VFW_S_STATE_INTERMEDIATE; /* FIXME? */ + } TRACE("(%p) state = %d\n",This,This->fstate); if ( This->fstate == State_Running ) @@ -132,6 +137,11 @@ CBaseFilterImpl_fnPause(IBaseFilter* iface) hr = NOERROR; EnterCriticalSection( &This->csFilter ); + if ( This->bIntermediateState ) + { + LeaveCriticalSection( &This->csFilter ); + return VFW_E_WRONG_STATE; /* FIXME? */ + } TRACE("(%p) state = %d\n",This,This->fstate); if ( This->fstate != State_Paused ) @@ -159,6 +169,11 @@ CBaseFilterImpl_fnRun(IBaseFilter* iface,REFERENCE_TIME rtStart) hr = NOERROR; EnterCriticalSection( &This->csFilter ); + if ( This->bIntermediateState ) + { + LeaveCriticalSection( &This->csFilter ); + return VFW_E_WRONG_STATE; /* FIXME? */ + } TRACE("(%p) state = %d\n",This,This->fstate); This->rtStart = rtStart; diff --git a/dlls/quartz/fmap.c b/dlls/quartz/fmap.c index 6c34480a760..4bb95ff7bbf 100644 --- a/dlls/quartz/fmap.c +++ b/dlls/quartz/fmap.c @@ -1,7 +1,7 @@ /* * Implementation of CLSID_FilterMapper and CLSID_FilterMapper2. * - * FIXME - stub. + * FIXME - some stubs * * Copyright (C) Hidenori TAKESHIMA * @@ -22,6 +22,7 @@ #include "config.h" +#include #include "windef.h" #include "winbase.h" #include "wingdi.h" @@ -840,6 +841,19 @@ err: return hr; } +struct MATCHED_ITEM +{ + IMoniker* pMonFilter; + DWORD dwMerit; +}; + +static int sort_comp_merit(const void* p1,const void* p2) +{ + const struct MATCHED_ITEM* pItem1 = (const struct MATCHED_ITEM*)p1; + const struct MATCHED_ITEM* pItem2 = (const struct MATCHED_ITEM*)p2; + + return (int)pItem2->dwMerit - (int)pItem1->dwMerit; +} static HRESULT WINAPI IFilterMapper2_fnEnumMatchingFilters(IFilterMapper2* iface, @@ -859,7 +873,10 @@ IFilterMapper2_fnEnumMatchingFilters(IFilterMapper2* iface, BYTE* pbFilterData = NULL; DWORD cbFilterData = 0; REGFILTER2* prf2 = NULL; - QUARTZ_CompList* pList = NULL; + QUARTZ_CompList* pListFilters = NULL; + struct MATCHED_ITEM* pItems = NULL; + struct MATCHED_ITEM* pItemsTmp; + int cItems = 0; const REGFILTERPINS2* pRegFilterPin; DWORD n; BOOL bMatch; @@ -995,32 +1012,44 @@ IFilterMapper2_fnEnumMatchingFilters(IFilterMapper2* iface, } /* matched - add pFilter to the list. */ - if ( pList == NULL ) + pItemsTmp = QUARTZ_ReallocMem( pItems, sizeof(struct MATCHED_ITEM) * (cItems+1) ); + if ( pItemsTmp == NULL ) { - pList = QUARTZ_CompList_Alloc(); - if ( pList == NULL ) - { - hr = E_OUTOFMEMORY; - goto err; - } - } - TRACE("matched\n"); - hr = QUARTZ_CompList_AddComp( - pList, (IUnknown*)pFilter, NULL, 0 ); - if ( FAILED(hr) ) + hr = E_OUTOFMEMORY; goto err; + } + pItems = pItemsTmp; + pItemsTmp = pItems + cItems; cItems ++; + pItemsTmp->pMonFilter = pFilter; pFilter = NULL; + pItemsTmp->dwMerit = prf2->dwMerit; } } - if ( pList == NULL ) + if ( pItems == NULL || cItems == 0 ) { hr = S_FALSE; goto err; } - FIXME("create IEnumMoniker - not sorted\n"); - /* FIXME - should be sorted?(in Merit order) */ - hr = QUARTZ_CreateEnumUnknown( &IID_IEnumMoniker, (void**)ppEnumMoniker, pList ); + /* FIXME - sort in Merit order */ + TRACE("sort in Merit order\n"); + qsort( pItems, cItems, sizeof(struct MATCHED_ITEM), sort_comp_merit ); + + pListFilters = QUARTZ_CompList_Alloc(); + if ( pListFilters == NULL ) + { + hr = E_OUTOFMEMORY; + goto err; + } + for ( n = 0; n < cItems; n++ ) + { + TRACE("merit %08lx\n",pItems[n].dwMerit); + hr = QUARTZ_CompList_AddComp( pListFilters, (IUnknown*)pItems[n].pMonFilter, NULL, 0 ); + if ( FAILED(hr) ) + goto err; + } + + hr = QUARTZ_CreateEnumUnknown( &IID_IEnumMoniker, (void**)ppEnumMoniker, pListFilters ); if ( FAILED(hr) ) goto err; @@ -1040,8 +1069,17 @@ err: QUARTZ_FreeMem(pbFilterData); if ( prf2 != NULL ) QUARTZ_FreeMem(prf2); - if ( pList != NULL ) - QUARTZ_CompList_Free( pList ); + if ( pItems != NULL && cItems > 0 ) + { + for ( n = 0; n < cItems; n++ ) + { + if ( pItems[n].pMonFilter != NULL ) + IMoniker_Release(pItems[n].pMonFilter); + } + QUARTZ_FreeMem(pItems); + } + if ( pListFilters != NULL ) + QUARTZ_CompList_Free( pListFilters ); TRACE("returns %08lx\n",hr); diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c index 22ad3aa6bbd..0949840acda 100644 --- a/dlls/quartz/main.c +++ b/dlls/quartz/main.c @@ -108,6 +108,7 @@ static const QUARTZ_CLASSENTRY QUARTZ_ClassList[] = { &CLSID_URLReader, &QUARTZ_CreateURLReader }, { &CLSID_AVIDec, &QUARTZ_CreateAVIDec }, { &CLSID_Colour, &QUARTZ_CreateColour }, + { &CLSID_ACMWrapper, &QUARTZ_CreateACMWrapper }, { &CLSID_FileWriter, &QUARTZ_CreateFileWriter }, { NULL, NULL }, }; diff --git a/dlls/quartz/mpgparse.c b/dlls/quartz/mpgparse.c index c6f8e939013..ed5b30a36ef 100644 --- a/dlls/quartz/mpgparse.c +++ b/dlls/quartz/mpgparse.c @@ -389,9 +389,18 @@ static HRESULT CMPGParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamInd pmpg1wav = (MPEG1WAVEFORMAT*)pmt->pbFormat; switch ( hdrbuf[1] & 0x6 ) { - case 0x6: pmpg1wav->fwHeadLayer = ACM_MPEG_LAYER1; - case 0x4: pmpg1wav->fwHeadLayer = ACM_MPEG_LAYER2; - case 0x2: pmpg1wav->fwHeadLayer = ACM_MPEG_LAYER3; + case 0x6: + TRACE("layer 1\n"); + pmpg1wav->fwHeadLayer = ACM_MPEG_LAYER1; + break; + case 0x4: + TRACE("layer 2\n"); + pmpg1wav->fwHeadLayer = ACM_MPEG_LAYER2; + break; + case 0x2: + TRACE("layer 3\n"); + pmpg1wav->fwHeadLayer = ACM_MPEG_LAYER3; + break; default: return E_FAIL; } @@ -412,10 +421,22 @@ static HRESULT CMPGParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamInd switch ( hdrbuf[3] & 0xc0 ) { - case 0x00: pmpg1wav->fwHeadMode = ACM_MPEG_STEREO; - case 0x40: pmpg1wav->fwHeadMode = ACM_MPEG_JOINTSTEREO; - case 0x80: pmpg1wav->fwHeadMode = ACM_MPEG_DUALCHANNEL; - case 0xc0: pmpg1wav->fwHeadMode = ACM_MPEG_SINGLECHANNEL; + case 0x00: + TRACE("STEREO\n"); + pmpg1wav->fwHeadMode = ACM_MPEG_STEREO; + break; + case 0x40: + TRACE("JOINTSTEREO\n"); + pmpg1wav->fwHeadMode = ACM_MPEG_JOINTSTEREO; + break; + case 0x80: + TRACE("DUALCHANNEL\n"); + pmpg1wav->fwHeadMode = ACM_MPEG_DUALCHANNEL; + break; + case 0xc0: + TRACE("SINGLECHANNEL\n"); + pmpg1wav->fwHeadMode = ACM_MPEG_SINGLECHANNEL; + break; } pmpg1wav->fwHeadModeExt = (hdrbuf[3] & 0x30) >> 4; /* FIXME?? */ @@ -436,9 +457,18 @@ static HRESULT CMPGParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamInd pmpg1wav->wfx.nChannels = (pmpg1wav->fwHeadMode != ACM_MPEG_SINGLECHANNEL) ? 2 : 1; switch ( hdrbuf[2] & 0x0c ) { - case 0x00: pmpg1wav->wfx.nSamplesPerSec = 44100; - case 0x01: pmpg1wav->wfx.nSamplesPerSec = 48000; - case 0x02: pmpg1wav->wfx.nSamplesPerSec = 32000; + case 0x00: + TRACE("44100Hz\n"); + pmpg1wav->wfx.nSamplesPerSec = 44100; + break; + case 0x01: + TRACE("48000Hz\n"); + pmpg1wav->wfx.nSamplesPerSec = 48000; + break; + case 0x02: + TRACE("32000Hz\n"); + pmpg1wav->wfx.nSamplesPerSec = 32000; + break; default: return E_FAIL; } pmpg1wav->wfx.nAvgBytesPerSec = pmpg1wav->dwHeadBitrate >> 3; diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c index ed8605ead04..1c23ed0e658 100644 --- a/dlls/quartz/parser.c +++ b/dlls/quartz/parser.c @@ -465,6 +465,10 @@ DWORD WINAPI CParserImplThread_Entry( LPVOID pv ) } } + This->m_dwThreadId = 0; + This->basefilter.bIntermediateState = FALSE; + SetEvent( This->m_hEventInit ); + return 0; } @@ -579,12 +583,21 @@ HRESULT CParserImpl_BeginThread( CParserImpl* This ) (LPVOID)This, 0, &This->m_dwThreadId ); if ( This->m_hThread == (HANDLE)NULL ) + { + CloseHandle( This->m_hEventInit ); + This->m_hEventInit = (HANDLE)NULL; return E_FAIL; + } hEvents[0] = This->m_hEventInit; hEvents[1] = This->m_hThread; dwRes = WaitForMultipleObjects(2,hEvents,FALSE,INFINITE); + + ResetEvent( This->m_hEventInit ); + CloseHandle( This->m_hThread ); + This->m_hThread = (HANDLE)NULL; + if ( dwRes != WAIT_OBJECT_0 ) return E_FAIL; @@ -592,25 +605,26 @@ HRESULT CParserImpl_BeginThread( CParserImpl* This ) } static -void CParserImpl_EndThread( CParserImpl* This ) +BOOL CParserImpl_EndThread( CParserImpl* This, BOOL bAsync ) { + DWORD dwThreadId; + TRACE("(%p)\n",This); - if ( This->m_hThread != (HANDLE)NULL ) - { - if ( PostThreadMessageA( - This->m_dwThreadId, QUARTZ_MSG_EXITTHREAD, 0, 0 ) ) - { - WaitForSingleObject( This->m_hThread, INFINITE ); - } - CloseHandle( This->m_hThread ); - This->m_hThread = (HANDLE)NULL; - This->m_dwThreadId = 0; - } + dwThreadId = This->m_dwThreadId; if ( This->m_hEventInit != (HANDLE)NULL ) { + if ( dwThreadId != 0 ) /* FIXME? */ + PostThreadMessageA( + dwThreadId, QUARTZ_MSG_EXITTHREAD, 0, 0 ); + if ( bAsync ) + return FALSE; + + WaitForSingleObject( This->m_hEventInit, INFINITE ); CloseHandle( This->m_hEventInit ); This->m_hEventInit = (HANDLE)NULL; } + + return TRUE; } static @@ -713,7 +727,7 @@ static HRESULT CParserImpl_OnInactive( CBaseFilterImpl* pImpl ) hr = CParserImpl_BeginThread(This); if ( FAILED(hr) ) { - CParserImpl_EndThread(This); + CParserImpl_EndThread(This,FALSE); return hr; } @@ -726,8 +740,11 @@ static HRESULT CParserImpl_OnStop( CBaseFilterImpl* pImpl ) FIXME( "(%p)\n", This ); - CParserImpl_EndThread(This); + This->basefilter.bIntermediateState = TRUE; + if ( !CParserImpl_EndThread(This,TRUE) ) + return VFW_S_STATE_INTERMEDIATE; + This->basefilter.bIntermediateState = FALSE; return NOERROR; } @@ -857,8 +874,9 @@ static HRESULT CParserInPinImpl_OnDisconnect( CPinBaseImpl* pImpl ) { CParserInPinImpl_THIS(pImpl,pin); - CParserImpl_OnInactive(&This->pParser->basefilter); - CParserImpl_OnStop(&This->pParser->basefilter); + /* assume the graph is already stopped */ + /*CParserImpl_OnInactive(&This->pParser->basefilter);*/ + /*CParserImpl_OnStop(&This->pParser->basefilter);*/ if ( This->pParser->m_pHandler->pUninitParser != NULL ) This->pParser->m_pHandler->pUninitParser(This->pParser); CParserImpl_SetAsyncReader( This->pParser, NULL ); diff --git a/dlls/quartz/xform.h b/dlls/quartz/xform.h index 383715c528c..a88c00e3aa3 100644 --- a/dlls/quartz/xform.h +++ b/dlls/quartz/xform.h @@ -121,5 +121,6 @@ HRESULT QUARTZ_CreateTransformBaseOutPin( HRESULT QUARTZ_CreateAVIDec(IUnknown* punkOuter,void** ppobj); HRESULT QUARTZ_CreateColour(IUnknown* punkOuter,void** ppobj); +HRESULT QUARTZ_CreateACMWrapper(IUnknown* punkOuter,void** ppobj); #endif /* WINE_DSHOW_XFORM_H */ diff --git a/winedefault.reg b/winedefault.reg index 3f8c73db577..d369c60390a 100644 --- a/winedefault.reg +++ b/winedefault.reg @@ -527,6 +527,46 @@ 30,74,79,33,00,00,00,00,60,00,00,00,60,00,00,00,\ 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 +# CLSID_MPEG1Splitter +[HKEY_CLASSES_ROOT\CLSID\{336475D0-942A-11CE-A870-00AA002FEAB5}] +@="MPEG1 Splitter" +[HKEY_CLASSES_ROOT\CLSID\{336475D0-942A-11CE-A870-00AA002FEAB5}\InprocServer32] +@="quartz.dll" +"ThreadingModel"="Both" + +[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{336475D0-942A-11CE-A870-00AA002FEAB5}] +"CLSID"="{336475D0-942A-11CE-A870-00AA002FEAB5}" +"FriendlyName"="MPEG1 Splitter" +# FilterData of generic transform filter. +"FilterData"=hex:02,00,00,00,00,00,60,00,02,00,00,00,00,00,00,00,\ + 30,70,69,33,00,00,00,00,00,00,00,00,\ + 01,00,00,00,00,00,00,00,00,00,00,00,\ + 30,74,79,33,00,00,00,00,60,00,00,00,60,00,00,00,\ + 31,70,69,33,08,00,00,00,00,00,00,00,\ + 01,00,00,00,00,00,00,00,00,00,00,00,\ + 30,74,79,33,00,00,00,00,60,00,00,00,60,00,00,00,\ + 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 + +# CLSID_ACMWrapper +[HKEY_CLASSES_ROOT\CLSID\{6A08CF80-0E18-11CF-A24D-0020AFD79767}] +@="ACM Wrapper" +[HKEY_CLASSES_ROOT\CLSID\{6A08CF80-0E18-11CF-A24D-0020AFD79767}\InprocServer32] +@="quartz.dll" +"ThreadingModel"="Both" + +[HKEY_CLASSES_ROOT\CLSID\{083863F1-70DE-11D0-BD40-00A0C911CE86}\Instance\{6A08CF80-0E18-11CF-A24D-0020AFD79767}] +"CLSID"="{6A08CF80-0E18-11CF-A24D-0020AFD79767}" +"FriendlyName"="ACM Wrapper" +# FilterData of generic transform filter. +"FilterData"=hex:02,00,00,00,00,00,60,00,02,00,00,00,00,00,00,00,\ + 30,70,69,33,00,00,00,00,00,00,00,00,\ + 01,00,00,00,00,00,00,00,00,00,00,00,\ + 30,74,79,33,00,00,00,00,60,00,00,00,60,00,00,00,\ + 31,70,69,33,08,00,00,00,00,00,00,00,\ + 01,00,00,00,00,00,00,00,00,00,00,00,\ + 30,74,79,33,00,00,00,00,60,00,00,00,60,00,00,00,\ + 00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00 + #