diff --git a/dlls/Makefile.in b/dlls/Makefile.in index c774784efad..64e530853ff 100644 --- a/dlls/Makefile.in +++ b/dlls/Makefile.in @@ -636,8 +636,8 @@ qcap/qcap.dll$(DLLEXT): dummy ntdll.dll$(DLLEXT) @cd qcap && $(MAKE) qcap.dll$(DLLEXT) quartz/quartz.dll$(DLLEXT): dummy oleaut32.dll$(DLLEXT) ole32.dll$(DLLEXT) \ - msvfw32.dll$(DLLEXT) winmm.dll$(DLLEXT) user32.dll$(DLLEXT) gdi32.dll$(DLLEXT) \ - advapi32.dll$(DLLEXT) kernel32.dll$(DLLEXT) ntdll.dll$(DLLEXT) + msvfw32.dll$(DLLEXT) msacm32.dll$(DLLEXT) winmm.dll$(DLLEXT) user32.dll$(DLLEXT) \ + gdi32.dll$(DLLEXT) advapi32.dll$(DLLEXT) kernel32.dll$(DLLEXT) ntdll.dll$(DLLEXT) @cd quartz && $(MAKE) quartz.dll$(DLLEXT) rasapi32/rasapi32.dll$(DLLEXT): dummy kernel32.dll$(DLLEXT) ntdll.dll$(DLLEXT) diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index 7413c41480f..7e3be21fcf5 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -9,6 +9,7 @@ LDDLLFLAGS = @LDDLLFLAGS@ SYMBOLFILE = $(MODULE).tmp.o C_SRCS = \ + acmwrap.c \ amundoc.c \ asyncsrc.c \ audioutl.c \ @@ -35,6 +36,7 @@ C_SRCS = \ iunk.c \ main.c \ memalloc.c \ + mpgparse.c \ mtype.c \ parser.c \ regsvr.c \ diff --git a/dlls/quartz/acmwrap.c b/dlls/quartz/acmwrap.c new file mode 100644 index 00000000000..b5393e17b78 --- /dev/null +++ b/dlls/quartz/acmwrap.c @@ -0,0 +1,222 @@ +/* + * Implements ACM Wrapper(CLSID_ACMWrapper). + * + * FIXME - stub + * + * Copyright (C) 2002 Hidenori TAKESHIMA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "config.h" + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winerror.h" +#include "msacm.h" +#include "strmif.h" +#include "control.h" +#include "amvideo.h" +#include "vfwmsgs.h" +#include "uuids.h" + +#include "wine/debug.h" +WINE_DEFAULT_DEBUG_CHANNEL(quartz); + +#include "quartz_private.h" +#include "xform.h" + + +static const WCHAR ACMWrapper_FilterName[] = +{'A','C','M',' ','W','r','a','p','p','e','r',0}; + + +typedef struct CACMWrapperImpl +{ + HACMSTREAM has; +} CACMWrapperImpl; + +/*************************************************************************** + * + * CACMWrapperImpl methods + * + */ + +static void ACMWrapper_Close( CACMWrapperImpl* This ) +{ + if ( This->has != (HACMSTREAM)NULL ) + { + acmStreamReset( This->has, 0 ); + acmStreamClose( This->has, 0 ); + This->has = (HACMSTREAM)NULL; + } +} + +static HRESULT ACMWrapper_Init( CTransformBaseImpl* pImpl ) +{ + CACMWrapperImpl* This = pImpl->m_pUserData; + + TRACE("(%p)\n",This); + + if ( This != NULL ) + return NOERROR; + + This = (CACMWrapperImpl*)QUARTZ_AllocMem( sizeof(CACMWrapperImpl) ); + if ( This == NULL ) + return E_OUTOFMEMORY; + ZeroMemory( This, sizeof(CACMWrapperImpl) ); + pImpl->m_pUserData = This; + + /* construct */ + This->has = (HACMSTREAM)NULL; + + return E_NOTIMPL; +} + +static HRESULT ACMWrapper_Cleanup( CTransformBaseImpl* pImpl ) +{ + CACMWrapperImpl* This = pImpl->m_pUserData; + + TRACE("(%p)\n",This); + + if ( This == NULL ) + return NOERROR; + + /* destruct */ + ACMWrapper_Close( This ); + + QUARTZ_FreeMem( This ); + pImpl->m_pUserData = NULL; + + return S_OK; +} + +static HRESULT ACMWrapper_CheckMediaType( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut ) +{ + CACMWrapperImpl* This = pImpl->m_pUserData; + + FIXME("(%p)\n",This); + if ( This == NULL ) + return E_UNEXPECTED; + + return E_NOTIMPL; +} + +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; + + FIXME("(%p)\n",This); + hr = ACMWrapper_CheckMediaType( pImpl, pmtIn, NULL ); + if ( FAILED(hr) ) + return hr; + + return E_NOTIMPL; +} + +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; + + FIXME("(%p)\n",This); + + if ( This == NULL ) + return E_UNEXPECTED; + + hr = ACMWrapper_CheckMediaType( pImpl, pmtIn, pmtOut ); + if ( FAILED(hr) ) + return hr; + + *pbTransInPlace = FALSE; + *pbTryToReuseSample = FALSE; + + return E_NOTIMPL; +} + +static HRESULT ACMWrapper_BeginTransform( CTransformBaseImpl* pImpl, const AM_MEDIA_TYPE* pmtIn, const AM_MEDIA_TYPE* pmtOut, BOOL bReuseSample ) +{ + CACMWrapperImpl* This = pImpl->m_pUserData; + + FIXME("(%p,%p,%p,%d)\n",This,pmtIn,pmtOut,bReuseSample); + + if ( This == NULL ) + return E_UNEXPECTED; + + return E_NOTIMPL; +} + +static HRESULT ACMWrapper_ProcessReceive( CTransformBaseImpl* pImpl, IMediaSample* pSampIn ) +{ + CACMWrapperImpl* This = pImpl->m_pUserData; + BYTE* pDataIn = NULL; + LONG lDataInLen; + HRESULT hr; + + FIXME("(%p)\n",This); + + if ( This == NULL ) + return E_UNEXPECTED; + + hr = IMediaSample_GetPointer( pSampIn, &pDataIn ); + if ( FAILED(hr) ) + return hr; + lDataInLen = IMediaSample_GetActualDataLength( pSampIn ); + + return E_NOTIMPL; +} + +static HRESULT ACMWrapper_EndTransform( CTransformBaseImpl* pImpl ) +{ + CACMWrapperImpl* This = pImpl->m_pUserData; + + TRACE("(%p)\n",This); + + if ( This == NULL ) + return E_UNEXPECTED; + + ACMWrapper_Close( This ); + + return S_OK; +} + +static const TransformBaseHandlers transhandlers = +{ + ACMWrapper_Init, + ACMWrapper_Cleanup, + ACMWrapper_CheckMediaType, + ACMWrapper_GetOutputTypes, + ACMWrapper_GetAllocProp, + ACMWrapper_BeginTransform, + ACMWrapper_ProcessReceive, + NULL, + ACMWrapper_EndTransform, +}; + +HRESULT QUARTZ_CreateACMWrapper(IUnknown* punkOuter,void** ppobj) +{ + return QUARTZ_CreateTransformBase( + punkOuter,ppobj, + &CLSID_ACMWrapper, + ACMWrapper_FilterName, + NULL, NULL, + &transhandlers ); +} + + diff --git a/dlls/quartz/aviparse.c b/dlls/quartz/aviparse.c index 996705757ec..ec5c3fbce16 100644 --- a/dlls/quartz/aviparse.c +++ b/dlls/quartz/aviparse.c @@ -1,6 +1,8 @@ /* * Implements AVI Parser(Splitter). * + * FIXME - no seeking + * * Copyright (C) Hidenori TAKESHIMA * * This library is free software; you can redistribute it and/or @@ -79,6 +81,7 @@ struct CAVIParseStream DWORD cIndexCur; REFERENCE_TIME rtCur; REFERENCE_TIME rtInternal; + BOOL bDataDiscontinuity; }; @@ -288,6 +291,7 @@ static HRESULT CAVIParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams ) This->pStreamsBuf[nIndex].rtCur = 0; This->pStreamsBuf[nIndex].rtInternal = 0; TRACE("stream %lu - %lu entries\n",nIndex,This->pStreamsBuf[nIndex].cIndexEntries); + This->pStreamsBuf[nIndex].bDataDiscontinuity = TRUE; } QUARTZ_FreeMem(This->pIndexEntriesBuf); This->pIndexEntriesBuf = pEntriesBuf; @@ -610,6 +614,11 @@ static HRESULT CAVIParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStream *prtStop = rtNext; /* FIXME - is this frame keyframe?? */ *pdwSampleFlags = AM_SAMPLE_SPLICEPOINT; + if ( pStream->bDataDiscontinuity ) + { + *pdwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; + pStream->bDataDiscontinuity = FALSE; + } switch ( pStream->strh.fccType ) { diff --git a/dlls/quartz/basefilt.c b/dlls/quartz/basefilt.c index 5a73976fd97..4689786b1ae 100644 --- a/dlls/quartz/basefilt.c +++ b/dlls/quartz/basefilt.c @@ -187,20 +187,21 @@ static HRESULT WINAPI CBaseFilterImpl_fnGetState(IBaseFilter* iface,DWORD dw,FILTER_STATE* pState) { ICOM_THIS(CBaseFilterImpl,iface); + HRESULT hr = S_OK; TRACE("(%p)->(%p)\n",This,pState); if ( pState == NULL ) return E_POINTER; - /* FIXME - ignore 'intermediate state' now */ - EnterCriticalSection( &This->csFilter ); TRACE("(%p) state = %d\n",This,This->fstate); *pState = This->fstate; + if ( This->bIntermediateState ) + hr = VFW_S_STATE_INTERMEDIATE; LeaveCriticalSection( &This->csFilter ); - return NOERROR; + return hr; } static HRESULT WINAPI @@ -455,6 +456,7 @@ HRESULT CBaseFilterImpl_InitIBaseFilter( This->pClock = NULL; This->rtStart = 0; This->fstate = State_Stopped; + This->bIntermediateState = FALSE; This->cbNameGraph = sizeof(WCHAR) * (lstrlenW(lpwszNameGraph)+1); This->pwszNameGraph = (WCHAR*)QUARTZ_AllocMem( This->cbNameGraph ); diff --git a/dlls/quartz/basefilt.h b/dlls/quartz/basefilt.h index 32c1b2d5cd2..3b7daaba296 100644 --- a/dlls/quartz/basefilt.h +++ b/dlls/quartz/basefilt.h @@ -56,6 +56,7 @@ typedef struct CBaseFilterImpl IReferenceClock* pClock; REFERENCE_TIME rtStart; FILTER_STATE fstate; + BOOL bIntermediateState; /* if set, fstate is ignored. */ } CBaseFilterImpl; struct CBaseFilterHandlers diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c index 00cb4eaf541..35d6704ecbc 100644 --- a/dlls/quartz/main.c +++ b/dlls/quartz/main.c @@ -104,6 +104,8 @@ static const QUARTZ_CLASSENTRY QUARTZ_ClassList[] = { &CLSID_VideoRenderer, &QUARTZ_CreateVideoRenderer }, { &CLSID_quartzWaveParser, &QUARTZ_CreateWaveParser }, { &CLSID_AviSplitter, &QUARTZ_CreateAVISplitter }, + { &CLSID_MPEG1Splitter, &QUARTZ_CreateMPEG1Splitter }, + { &CLSID_MMSPLITTER, &QUARTZ_CreateMPEG2Splitter }, { &CLSID_AsyncReader, &QUARTZ_CreateAsyncReader }, { &CLSID_URLReader, &QUARTZ_CreateURLReader }, { &CLSID_AVIDec, &QUARTZ_CreateAVIDec }, diff --git a/dlls/quartz/mpgparse.c b/dlls/quartz/mpgparse.c new file mode 100644 index 00000000000..4747d9cce5b --- /dev/null +++ b/dlls/quartz/mpgparse.c @@ -0,0 +1,715 @@ +/* + * Implements MPEG-1 / MPEG-2 Parser(Splitter). + * + * FIXME - no splitter implementation. + * FIXME - no packet support (implemented payload only) + * FIXME - no seeking + * + * Copyright (C) 2002 Hidenori TAKESHIMA + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "mmsystem.h" +#include "vfw.h" +#include "winerror.h" +#include "strmif.h" +#include "control.h" +#include "vfwmsgs.h" +#include "amvideo.h" +#include "mmreg.h" +#include "uuids.h" +#include "dvdmedia.h" + +#include "wine/debug.h" +WINE_DEFAULT_DEBUG_CHANNEL(quartz); + +#include "quartz_private.h" +#include "parser.h" +#include "mtype.h" + +static const WCHAR QUARTZ_MPEG1Parser_Name[] = +{ 'M','P','E','G','-','I',' ','S','p','l','i','t','t','e','r',0 }; +static const WCHAR QUARTZ_MPEG2Parser_Name[] = +{ 'M','P','E','G','-','2',' ','S','p','l','i','t','t','e','r',0 }; +static const WCHAR QUARTZ_MPGParserInPin_Name[] = +{ 'I','n',0 }; +static const WCHAR QUARTZ_MPGParserOutPin_VideoPinName[] = +{ 'V','i','d','e','o',0 }; +static const WCHAR QUARTZ_MPGParserOutPin_AudioPinName[] = +{ 'A','u','d','i','o',0 }; + /* FIXME */ +static const WCHAR QUARTZ_MPGParserOutPin_UnknownTypePinName[] = +{ 'O','u','t',0 }; + + + +static DWORD bitratesl1[16] = + { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448, 0}; +static DWORD bitratesl2[16] = + { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384, 0}; +static DWORD bitratesl3[16] = + { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320, 0}; + + +/**************************************************************************** + * + * CMPGParseImpl + */ + + +typedef struct CMPGParseImpl CMPGParseImpl; +typedef struct CMPGParsePayload CMPGParsePayload; + +enum MPGPayloadType +{ + MPGPayload_Video = 0xe0, + MPGPayload_Audio = 0xc0, +}; + +struct CMPGParseImpl +{ + LONGLONG llPosNext; + BOOL bRawPayload; + DWORD dwPayloadBlockSizeMax; + DWORD cPayloads; + CMPGParsePayload* pPayloads; +}; + +struct CMPGParsePayload +{ + enum MPGPayloadType payloadtype; + BOOL bDataDiscontinuity; +}; + + +static HRESULT CMPGParseImpl_SyncReadPayload( + CParserImpl* pImpl, CMPGParseImpl* This, + enum MPGPayloadType payloadtype, + LONGLONG llPosStart, LONG lLength, BYTE* pbBuf ) +{ + if ( This == NULL || This->pPayloads == NULL ) + return E_UNEXPECTED; + + if ( This->bRawPayload ) + { + if ( payloadtype != This->pPayloads[0].payloadtype ) + return E_UNEXPECTED; + return IAsyncReader_SyncRead( pImpl->m_pReader, llPosStart, lLength, pbBuf ); + } + else + { + FIXME( "not implemented\n" ); + } + + return E_NOTIMPL; +} + + + +static HRESULT CMPGParseImpl_InitParser( CParserImpl* pImpl, ULONG* pcStreams ) +{ + CMPGParseImpl* This = NULL; + HRESULT hr; + BYTE hdrbuf[8]; + + TRACE("(%p,%p)\n",pImpl,pcStreams); + + This = (CMPGParseImpl*)QUARTZ_AllocMem( sizeof(CMPGParseImpl) ); + if ( This == NULL ) + return E_OUTOFMEMORY; + pImpl->m_pUserData = This; + ZeroMemory( This, sizeof(CMPGParseImpl) ); + + hr = IAsyncReader_SyncRead( pImpl->m_pReader, 0, 8, hdrbuf ); + if ( FAILED(hr) ) + return hr; + if ( hr != S_OK ) + return E_FAIL; + + if ( hdrbuf[0] == 0x00 && hdrbuf[1] == 0x00 && + hdrbuf[2] == 0x01 && hdrbuf[3] == 0xba ) + { + This->bRawPayload = FALSE; + This->dwPayloadBlockSizeMax = 0; + + FIXME( "no mpeg/system support\n" ); + return E_FAIL; + } + else + if ( hdrbuf[0] == 0x00 && hdrbuf[1] == 0x00 && + hdrbuf[2] == 0x01 && hdrbuf[3] == 0xb3 ) + { + TRACE( "mpeg/video payload\n" ); + This->llPosNext = 0; + This->bRawPayload = TRUE; + This->dwPayloadBlockSizeMax = 0x4000; + This->cPayloads = 1; + This->pPayloads = (CMPGParsePayload*)QUARTZ_AllocMem( sizeof(CMPGParsePayload) ); + if ( This->pPayloads == NULL ) + return E_OUTOFMEMORY; + *pcStreams = 1; + This->pPayloads[0].payloadtype = MPGPayload_Video; + This->pPayloads[0].bDataDiscontinuity = TRUE; + } + else + if ( hdrbuf[0] == 0xff && (hdrbuf[1]&0xf0) == 0xf0 ) + { + TRACE( "mpeg/audio payload\n" ); + This->llPosNext = 0; + This->bRawPayload = TRUE; + This->dwPayloadBlockSizeMax = 0; + This->cPayloads = 1; + This->pPayloads = (CMPGParsePayload*)QUARTZ_AllocMem( sizeof(CMPGParsePayload) ); + if ( This->pPayloads == NULL ) + return E_OUTOFMEMORY; + *pcStreams = 1; + This->pPayloads[0].payloadtype = MPGPayload_Audio; + This->pPayloads[0].bDataDiscontinuity = TRUE; + } + else + { + return E_FAIL; + } + + return S_OK; +} + +static HRESULT CMPGParseImpl_UninitParser( CParserImpl* pImpl ) +{ + CMPGParseImpl* This = (CMPGParseImpl*)pImpl->m_pUserData; + ULONG nIndex; + + TRACE("(%p)\n",This); + + if ( This == NULL ) + return NOERROR; + + /* destruct */ + + if ( This->pPayloads != NULL ) + { + for ( nIndex = 0; nIndex < This->cPayloads; nIndex++ ) + { + /* release this stream */ + + + } + QUARTZ_FreeMem( This->pPayloads ); + This->pPayloads = NULL; + } + + QUARTZ_FreeMem( This ); + pImpl->m_pUserData = NULL; + + return NOERROR; +} + +static LPCWSTR CMPGParseImpl_GetOutPinName( CParserImpl* pImpl, ULONG nStreamIndex ) +{ + CMPGParseImpl* This = (CMPGParseImpl*)pImpl->m_pUserData; + + TRACE("(%p,%lu)\n",This,nStreamIndex); + + if ( This == NULL || nStreamIndex >= This->cPayloads ) + return NULL; + + switch ( This->pPayloads[nStreamIndex].payloadtype ) + { + case MPGPayload_Video: + return QUARTZ_MPGParserOutPin_VideoPinName; + case MPGPayload_Audio: + return QUARTZ_MPGParserOutPin_AudioPinName; + default: + FIXME("mpeg - unknown stream type %02x\n",This->pPayloads[nStreamIndex].payloadtype); + } + + /* FIXME */ + return QUARTZ_MPGParserOutPin_UnknownTypePinName; +} + +static HRESULT CMPGParseImpl_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt ) +{ + CMPGParseImpl* This = (CMPGParseImpl*)pImpl->m_pUserData; + HRESULT hr; + BYTE hdrbuf[140+10]; + UINT seqhdrlen; + MPEG1VIDEOINFO* pmpg1vi; + MPEG2VIDEOINFO* pmpg2vi; + MPEG1WAVEFORMAT* pmpg1wav; + enum MPGPayloadType payloadtype; + DWORD dwPayloadBlockSize; + + TRACE("(%p,%lu,%p)\n",This,nStreamIndex,pmt); + + if ( This == NULL ) + return E_UNEXPECTED; + if ( nStreamIndex >= This->cPayloads ) + return E_INVALIDARG; + + ZeroMemory( pmt, sizeof(AM_MEDIA_TYPE) ); + + payloadtype = This->pPayloads[nStreamIndex].payloadtype; + switch ( payloadtype ) + { + case MPGPayload_Video: + hr = CMPGParseImpl_SyncReadPayload( + pImpl, This, payloadtype, 0, 140+10, hdrbuf ); + if ( FAILED(hr) ) + return hr; + if ( hr != S_OK ) + return E_FAIL; + + memcpy( &pmt->majortype, &MEDIATYPE_Video, sizeof(GUID) ); + seqhdrlen = 12; + if ( hdrbuf[seqhdrlen-1] & 0x2 ) + seqhdrlen += 64; + if ( hdrbuf[seqhdrlen-1] & 0x1 ) + seqhdrlen += 64; + if ( hdrbuf[seqhdrlen ] == 0x00 && hdrbuf[seqhdrlen+1] == 0x00 && + hdrbuf[seqhdrlen+2] == 0x01 && hdrbuf[seqhdrlen+3] == 0xb5 ) + { + /* video MPEG-2 */ + FIXME("video MPEG-2\n"); + if ( (hdrbuf[seqhdrlen+4]&0xf0) != 0x1 ) + return E_FAIL; + memcpy( &pmt->subtype, &MEDIASUBTYPE_MPEG2_VIDEO, sizeof(GUID) ); + memcpy( &pmt->formattype, &FORMAT_MPEG2_VIDEO, sizeof(GUID) ); + pmt->bFixedSizeSamples = 0; + pmt->bTemporalCompression = 1; + pmt->lSampleSize = 0; + pmt->cbFormat = sizeof(MPEG2VIDEOINFO); + pmt->pbFormat = (BYTE*)CoTaskMemAlloc( sizeof(MPEG2VIDEOINFO) ); + if ( pmt->pbFormat == NULL ) + return E_OUTOFMEMORY; + ZeroMemory( pmt->pbFormat, sizeof(MPEG2VIDEOINFO) ); + pmpg2vi = (MPEG2VIDEOINFO*)pmt->pbFormat; + pmpg2vi->hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pmpg2vi->hdr.bmiHeader.biWidth = ((UINT)hdrbuf[4] << 4) | ((UINT)hdrbuf[5] >> 4); /* FIXME! */ + pmpg2vi->hdr.bmiHeader.biHeight = (((UINT)hdrbuf[5] & 0xf) << 8) | ((UINT)hdrbuf[6]); /* FIXME! */ + pmpg2vi->hdr.dwInterlaceFlags = AMINTERLACE_FieldPatBothRegular; /* FIXME? */ + pmpg2vi->hdr.dwCopyProtectFlags = AMCOPYPROTECT_RestrictDuplication; /* FIXME? */ + pmpg2vi->hdr.dwPictAspectRatioX = 1; /* FIXME? */ + pmpg2vi->hdr.dwPictAspectRatioY = 1; /* FIXME? */ + pmpg2vi->dwStartTimeCode = 0; + pmpg2vi->cbSequenceHeader = seqhdrlen + 10; + switch ( hdrbuf[seqhdrlen+4] & 0xf ) + { + case 5: pmpg2vi->dwProfile = AM_MPEG2Profile_Simple; break; + case 4: pmpg2vi->dwProfile = AM_MPEG2Profile_Main; break; + case 3: pmpg2vi->dwProfile = AM_MPEG2Profile_SNRScalable; break; + case 2: pmpg2vi->dwProfile = AM_MPEG2Profile_SpatiallyScalable; break; + case 1: pmpg2vi->dwProfile = AM_MPEG2Profile_High; break; + default: return E_FAIL; + } + switch ( hdrbuf[seqhdrlen+5] >> 4 ) + { + case 10: pmpg2vi->dwLevel = AM_MPEG2Level_Low; break; + case 8: pmpg2vi->dwLevel = AM_MPEG2Level_Main; break; + case 6: pmpg2vi->dwLevel = AM_MPEG2Level_High1440; break; + case 4: pmpg2vi->dwLevel = AM_MPEG2Level_High; break; + default: return E_FAIL; + } + pmpg2vi->dwFlags = 0; /* FIXME? */ + memcpy( pmpg2vi->dwSequenceHeader, hdrbuf, seqhdrlen + 10 ); + + return S_OK; + } + else + { + /* MPEG-1 */ + memcpy( &pmt->subtype, &MEDIASUBTYPE_MPEG1Payload, sizeof(GUID) ); + memcpy( &pmt->formattype, &FORMAT_MPEGVideo, sizeof(GUID) ); + pmt->bFixedSizeSamples = 0; + pmt->bTemporalCompression = 1; + pmt->lSampleSize = 0; + pmt->cbFormat = sizeof(MPEG1VIDEOINFO); + pmt->pbFormat = (BYTE*)CoTaskMemAlloc( sizeof(MPEG1VIDEOINFO) ); + if ( pmt->pbFormat == NULL ) + return E_OUTOFMEMORY; + ZeroMemory( pmt->pbFormat, sizeof(MPEG1VIDEOINFO) ); + pmpg1vi = (MPEG1VIDEOINFO*)pmt->pbFormat; + pmpg1vi->hdr.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + pmpg1vi->hdr.bmiHeader.biWidth = ((UINT)hdrbuf[4] << 4) | ((UINT)hdrbuf[5] >> 4); + pmpg1vi->hdr.bmiHeader.biHeight = (((UINT)hdrbuf[5] & 0xf) << 8) | ((UINT)hdrbuf[6]); + pmpg1vi->hdr.bmiHeader.biPlanes = 1; + pmpg1vi->dwStartTimeCode = 0; + pmpg1vi->cbSequenceHeader = seqhdrlen; + memcpy( pmpg1vi->bSequenceHeader, hdrbuf, seqhdrlen ); + } + + return S_OK; + case MPGPayload_Audio: + hr = CMPGParseImpl_SyncReadPayload( + pImpl, This, payloadtype, 0, 4, hdrbuf ); + if ( FAILED(hr) ) + return hr; + if ( hr != S_OK ) + return E_FAIL; + + memcpy( &pmt->majortype, &MEDIATYPE_Audio, sizeof(GUID) ); + memcpy( &pmt->formattype, &FORMAT_WaveFormatEx, sizeof(GUID) ); + + if ( !( hdrbuf[1] & 0x8 ) ) + { + /* FIXME!!! */ + FIXME("audio not MPEG-1\n"); + return E_FAIL; + } + else + { + /* MPEG-1 */ + memcpy( &pmt->subtype, &MEDIASUBTYPE_MPEG1AudioPayload, sizeof(GUID) ); + pmt->bFixedSizeSamples = 0; + pmt->bTemporalCompression = 1; + pmt->lSampleSize = 0; + pmt->cbFormat = sizeof(MPEG1WAVEFORMAT); + pmt->pbFormat = (BYTE*)CoTaskMemAlloc( sizeof(MPEG1WAVEFORMAT) ); + if ( pmt->pbFormat == NULL ) + return E_OUTOFMEMORY; + ZeroMemory( pmt->pbFormat, sizeof(MPEG1WAVEFORMAT) ); + 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; + default: return E_FAIL; + } + + switch ( pmpg1wav->fwHeadLayer ) + { + case ACM_MPEG_LAYER1: + pmpg1wav->dwHeadBitrate = bitratesl1[hdrbuf[2]>>4]*1000; + break; + case ACM_MPEG_LAYER2: + pmpg1wav->dwHeadBitrate = bitratesl2[hdrbuf[2]>>4]*1000; + break; + case ACM_MPEG_LAYER3: + pmpg1wav->dwHeadBitrate = bitratesl3[hdrbuf[2]>>4]*1000; + break; + } + if ( pmpg1wav->dwHeadBitrate == 0 ) + return E_FAIL; + + 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; + } + + pmpg1wav->fwHeadModeExt = (hdrbuf[3] & 0x30) >> 4; /* FIXME?? */ + pmpg1wav->wHeadEmphasis = (hdrbuf[3] & 0x03); /* FIXME?? */ + pmpg1wav->fwHeadFlags = ACM_MPEG_ID_MPEG1; + if ( hdrbuf[1] & 0x1 ) + pmpg1wav->fwHeadFlags |= ACM_MPEG_PROTECTIONBIT; + if ( hdrbuf[2] & 0x1 ) + pmpg1wav->fwHeadFlags |= ACM_MPEG_PRIVATEBIT; + if ( hdrbuf[3] & 0x8 ) + pmpg1wav->fwHeadFlags |= ACM_MPEG_COPYRIGHT; + if ( hdrbuf[3] & 0x4 ) + pmpg1wav->fwHeadFlags |= ACM_MPEG_ORIGINALHOME; + pmpg1wav->dwPTSLow = 0; + pmpg1wav->dwPTSHigh = 0; + + pmpg1wav->wfx.wFormatTag = WAVE_FORMAT_MPEG; + 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; + default: return E_FAIL; + } + pmpg1wav->wfx.nAvgBytesPerSec = pmpg1wav->dwHeadBitrate >> 3; + switch ( pmpg1wav->fwHeadLayer ) + { + case ACM_MPEG_LAYER1: + pmpg1wav->wfx.nBlockAlign = (384>>3) * pmpg1wav->dwHeadBitrate / pmpg1wav->wfx.nSamplesPerSec; + break; + case ACM_MPEG_LAYER2: + pmpg1wav->wfx.nBlockAlign = (1152>>3) * pmpg1wav->dwHeadBitrate / pmpg1wav->wfx.nSamplesPerSec; + break; + case ACM_MPEG_LAYER3: + pmpg1wav->wfx.nBlockAlign = 1; + break; + } + pmpg1wav->wfx.wBitsPerSample = 0; + pmpg1wav->wfx.cbSize = sizeof(MPEG1WAVEFORMAT) - sizeof(WAVEFORMATEX); + if ( pmpg1wav->fwHeadLayer != ACM_MPEG_LAYER3 ) + { + pmt->bFixedSizeSamples = 1; + pmt->lSampleSize = pmpg1wav->wfx.nBlockAlign; + } + dwPayloadBlockSize = (pmpg1wav->wfx.nAvgBytesPerSec + pmpg1wav->wfx.nBlockAlign - 1) / pmpg1wav->wfx.nBlockAlign; + if ( dwPayloadBlockSize > This->dwPayloadBlockSizeMax ) + This->dwPayloadBlockSizeMax = dwPayloadBlockSize; + } + + return S_OK; + default: + FIXME("mpeg - unknown stream type %02x\n",This->pPayloads[nStreamIndex].payloadtype); + break; + } + + FIXME("stub\n"); + return E_NOTIMPL; +} + +static HRESULT CMPGParseImpl_CheckStreamType( CParserImpl* pImpl, ULONG nStreamIndex, const AM_MEDIA_TYPE* pmt ) +{ + CMPGParseImpl* This = (CMPGParseImpl*)pImpl->m_pUserData; + HRESULT hr; + AM_MEDIA_TYPE mt; + MPEG1VIDEOINFO* pmpg1vi; + MPEG1VIDEOINFO* pmpg1viCheck; + MPEG2VIDEOINFO* pmpg2vi; + MPEG2VIDEOINFO* pmpg2viCheck; + WAVEFORMATEX* pwfx; + WAVEFORMATEX* pwfxCheck; + enum MPGPayloadType payloadtype; + + TRACE("(%p,%lu,%p)\n",This,nStreamIndex,pmt); + + if ( This == NULL ) + return E_UNEXPECTED; + if ( nStreamIndex >= This->cPayloads ) + return E_INVALIDARG; + + hr = CMPGParseImpl_GetStreamType( pImpl, nStreamIndex, &mt ); + if ( FAILED(hr) ) + return hr; + if ( !IsEqualGUID( &pmt->majortype, &mt.majortype ) || + !IsEqualGUID( &pmt->subtype, &mt.subtype ) || + !IsEqualGUID( &pmt->formattype, &mt.formattype ) ) + { + hr = E_FAIL; + goto end; + } + + TRACE("check format\n"); + hr = S_OK; + + payloadtype = This->pPayloads[nStreamIndex].payloadtype; + switch ( payloadtype ) + { + case MPGPayload_Video: + if ( IsEqualGUID( &mt.formattype, &FORMAT_MPEGVideo ) ) + { + /* MPEG-1 Video */ + if ( pmt->cbFormat != mt.cbFormat || + pmt->pbFormat == NULL ) + { + hr = E_FAIL; + goto end; + } + pmpg1vi = (MPEG1VIDEOINFO*)mt.pbFormat; + pmpg1viCheck = (MPEG1VIDEOINFO*)pmt->pbFormat; + if ( memcmp( pmpg1vi, pmpg1viCheck, sizeof(MPEG1VIDEOINFO) ) != 0 ) + { + hr = E_FAIL; + goto end; + } + } + else + if ( IsEqualGUID( &mt.formattype, &FORMAT_MPEG2_VIDEO ) ) + { + /* MPEG-2 Video */ + if ( pmt->cbFormat != mt.cbFormat || + pmt->pbFormat == NULL ) + { + hr = E_FAIL; + goto end; + } + pmpg2vi = (MPEG2VIDEOINFO*)mt.pbFormat; + pmpg2viCheck = (MPEG2VIDEOINFO*)pmt->pbFormat; + if ( memcmp( pmpg2vi, pmpg2viCheck, sizeof(MPEG2VIDEOINFO) ) != 0 ) + { + hr = E_FAIL; + goto end; + } + } + else + { + hr = E_FAIL; + goto end; + } + break; + case MPGPayload_Audio: + if ( IsEqualGUID( &mt.formattype, &FORMAT_WaveFormatEx ) ) + { + if ( mt.cbFormat != pmt->cbFormat || + pmt->pbFormat == NULL ) + { + hr = E_FAIL; + goto end; + } + pwfx = (WAVEFORMATEX*)mt.pbFormat; + pwfxCheck = (WAVEFORMATEX*)pmt->pbFormat; + + if ( memcmp( pwfx, pwfxCheck, sizeof(WAVEFORMATEX) ) != 0 ) + { + hr = E_FAIL; + goto end; + } + } + else + { + hr = E_FAIL; + goto end; + } + + break; + default: + FIXME( "unsupported payload type\n" ); + hr = E_FAIL; + goto end; + } + + hr = S_OK; +end: + QUARTZ_MediaType_Free( &mt ); + + TRACE("%08lx\n",hr); + + return hr; +} + +static HRESULT CMPGParseImpl_GetAllocProp( CParserImpl* pImpl, ALLOCATOR_PROPERTIES* pReqProp ) +{ + CMPGParseImpl* This = (CMPGParseImpl*)pImpl->m_pUserData; + + TRACE("(%p,%p)\n",This,pReqProp); + + if ( This == NULL ) + return E_UNEXPECTED; + + ZeroMemory( pReqProp, sizeof(ALLOCATOR_PROPERTIES) ); + pReqProp->cBuffers = This->cPayloads; + pReqProp->cbBuffer = This->dwPayloadBlockSizeMax; + + return S_OK; +} + +static HRESULT CMPGParseImpl_GetNextRequest( CParserImpl* pImpl, ULONG* pnStreamIndex, LONGLONG* pllStart, LONG* plLength, REFERENCE_TIME* prtStart, REFERENCE_TIME* prtStop, DWORD* pdwSampleFlags ) +{ + CMPGParseImpl* This = (CMPGParseImpl*)pImpl->m_pUserData; + + if ( This == NULL ) + return E_UNEXPECTED; + *pdwSampleFlags = AM_SAMPLE_SPLICEPOINT; + + TRACE("(%p)\n",This); + + if ( This->bRawPayload ) + { + if ( This->dwPayloadBlockSizeMax == 0 || + This->cPayloads != 1 || This->pPayloads == NULL ) + return E_UNEXPECTED; + *pnStreamIndex = 0; + *pllStart = This->llPosNext; + *plLength = This->dwPayloadBlockSizeMax; + *prtStart = 0; + *prtStop = 0; + if ( This->pPayloads[0].bDataDiscontinuity ) + { + *pdwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; + This->pPayloads[0].bDataDiscontinuity = FALSE; + } + } + else + { + FIXME("stub\n"); + return E_NOTIMPL; + } + + return S_OK; +} + +static HRESULT CMPGParseImpl_ProcessSample( CParserImpl* pImpl, ULONG nStreamIndex, LONGLONG llStart, LONG lLength, IMediaSample* pSample ) +{ + CMPGParseImpl* This = (CMPGParseImpl*)pImpl->m_pUserData; + HRESULT hr; + + TRACE("(%p,%lu,%ld,%ld,%p)\n",This,nStreamIndex,(long)llStart,lLength,pSample); + + if ( This == NULL ) + return E_UNEXPECTED; + + if ( This->bRawPayload ) + { + hr = IMediaSample_SetTime(pSample,NULL,NULL); + if ( FAILED(hr) ) + return hr; + } + + return NOERROR; +} + + +static const struct ParserHandlers CMPGParseImpl_Handlers = +{ + CMPGParseImpl_InitParser, + CMPGParseImpl_UninitParser, + CMPGParseImpl_GetOutPinName, + CMPGParseImpl_GetStreamType, + CMPGParseImpl_CheckStreamType, + CMPGParseImpl_GetAllocProp, + CMPGParseImpl_GetNextRequest, + CMPGParseImpl_ProcessSample, + + /* for IQualityControl */ + NULL, /* pQualityNotify */ + + /* for seeking */ + NULL, /* pGetSeekingCaps */ + NULL, /* pIsTimeFormatSupported */ + NULL, /* pGetCurPos */ + NULL, /* pSetCurPos */ + NULL, /* pGetDuration */ + NULL, /* pGetStopPos */ + NULL, /* pSetStopPos */ + NULL, /* pGetPreroll */ +}; + +HRESULT QUARTZ_CreateMPEG1Splitter(IUnknown* punkOuter,void** ppobj) +{ + return QUARTZ_CreateParser( + punkOuter,ppobj, + &CLSID_MPEG1Splitter, + QUARTZ_MPEG1Parser_Name, + QUARTZ_MPGParserInPin_Name, + &CMPGParseImpl_Handlers ); +} + +HRESULT QUARTZ_CreateMPEG2Splitter(IUnknown* punkOuter,void** ppobj) +{ + return QUARTZ_CreateParser( + punkOuter,ppobj, + &CLSID_MMSPLITTER, + QUARTZ_MPEG2Parser_Name, + QUARTZ_MPGParserInPin_Name, + &CMPGParseImpl_Handlers ); +} + + diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c index cc6f736fdb0..ed8605ead04 100644 --- a/dlls/quartz/parser.c +++ b/dlls/quartz/parser.c @@ -172,6 +172,28 @@ static HRESULT CParserImplThread_SendEndOfStream( CParserImpl* This ) return hrRet; } +static +void CParserImplThread_MemDecommit( CParserImpl* This ) +{ + ULONG nIndex; + IMemAllocator* pAlloc; + + TRACE("(%p)\n",This); + + if ( This->m_pAllocator != NULL ) + IMemAllocator_Decommit( This->m_pAllocator ); + + if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 ) + { + for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ ) + { + pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator; + if ( pAlloc != NULL ) + IMemAllocator_Decommit( pAlloc ); + } + } +} + static HRESULT CParserImplThread_SendFlush( CParserImpl* This ) { ULONG nIndex; @@ -210,6 +232,19 @@ static void CParserImplThread_ErrorAbort( CParserImpl* This, HRESULT hr ) CParserImplThread_SendEndOfStream(This); } +static +void CParserImplThread_ResetAllStreams( CParserImpl* This ) +{ + ULONG nIndex; + + if ( This->m_pHandler->pSetCurPos != NULL ) + { + for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ ) + This->m_pHandler->pSetCurPos(This, + &This->m_guidTimeFormat,nIndex,(LONGLONG)0); + } +} + static HRESULT CParserImplThread_ProcessNextSample( CParserImpl* This ) { @@ -233,6 +268,11 @@ HRESULT CParserImplThread_ProcessNextSample( CParserImpl* This ) CParserImplThread_ClearAllRequests(This); CParserImplThread_SendFlush(This); CParserImplThread_SendEndOfStream(This); + This->m_bSendEOS = FALSE; + + CParserImplThread_ResetAllStreams(This); + CParserImplThread_MemDecommit(This); + TRACE("(%p) exit thread\n",This); return S_FALSE; case QUARTZ_MSG_SEEK: @@ -606,28 +646,6 @@ HRESULT CParserImpl_MemCommit( CParserImpl* This ) return NOERROR; } -static -void CParserImpl_MemDecommit( CParserImpl* This ) -{ - ULONG nIndex; - IMemAllocator* pAlloc; - - TRACE("(%p)\n",This); - - if ( This->m_pAllocator != NULL ) - IMemAllocator_Decommit( This->m_pAllocator ); - - if ( This->m_ppOutPins != NULL && This->m_cOutStreams > 0 ) - { - for ( nIndex = 0; nIndex < This->m_cOutStreams; nIndex++ ) - { - pAlloc = This->m_ppOutPins[nIndex]->m_pOutPinAllocator; - if ( pAlloc != NULL ) - IMemAllocator_Decommit( pAlloc ); - } - } -} - static HRESULT CParserImpl_GetPreferredTimeFormat( CParserImpl* This, GUID* pguidFormat ) { @@ -705,20 +723,10 @@ static HRESULT CParserImpl_OnInactive( CBaseFilterImpl* pImpl ) static HRESULT CParserImpl_OnStop( CBaseFilterImpl* pImpl ) { CParserImpl_THIS(pImpl,basefilter); - DWORD n; FIXME( "(%p)\n", This ); CParserImpl_EndThread(This); - CParserImpl_MemDecommit(This); - This->m_bSendEOS = FALSE; - - /* reset streams. */ - if ( This->m_pHandler->pSetCurPos != NULL ) - { - for ( n = 0; n < This->m_cOutStreams; n++ ) - This->m_pHandler->pSetCurPos(This,&This->m_guidTimeFormat,n,(LONGLONG)0); - } return NOERROR; } diff --git a/dlls/quartz/parser.h b/dlls/quartz/parser.h index 0e2e62fc25e..79a70bbdad0 100644 --- a/dlls/quartz/parser.h +++ b/dlls/quartz/parser.h @@ -180,6 +180,8 @@ HRESULT QUARTZ_CreateParserOutPin( HRESULT QUARTZ_CreateWaveParser(IUnknown* punkOuter,void** ppobj); HRESULT QUARTZ_CreateAVISplitter(IUnknown* punkOuter,void** ppobj); +HRESULT QUARTZ_CreateMPEG1Splitter(IUnknown* punkOuter,void** ppobj); +HRESULT QUARTZ_CreateMPEG2Splitter(IUnknown* punkOuter,void** ppobj); HRESULT RIFF_GetNext( diff --git a/dlls/quartz/quartz.spec b/dlls/quartz/quartz.spec index f8bff790999..0e0a121b428 100644 --- a/dlls/quartz/quartz.spec +++ b/dlls/quartz/quartz.spec @@ -5,6 +5,7 @@ init QUARTZ_DllMain import oleaut32.dll import ole32.dll import msvfw32.dll +import msacm32.dll import winmm.dll import user32.dll import gdi32.dll