/* * 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_GetStreamType( CParserImpl* pImpl, ULONG nStreamIndex, AM_MEDIA_TYPE* pmt ); 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; DWORD n; AM_MEDIA_TYPE mt; 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; } /* To determine block size, scan all payloads. */ ZeroMemory( &mt, sizeof(mt) ); for ( n = 0; n < This->cPayloads; n++ ) { CMPGParseImpl_GetStreamType(pImpl,n,&mt); QUARTZ_MediaType_Free(&mt); } 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: 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; } 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: 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?? */ 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: 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; 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; TRACE("payload block size = %lu\n",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; TRACE("buf %d size %d\n", (int)This->cPayloads, (int)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 ); }