Sweden-Number/dlls/quartz/sample.c

678 lines
16 KiB
C

/*
* Implements IMediaSample2 for CMemMediaSample.
*
* Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
*
* 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 "strmif.h"
#include "vfwmsgs.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(quartz);
#include "quartz_private.h"
#include "sample.h"
#include "mtype.h"
/***************************************************************************
*
* Helper functions
*
*/
HRESULT QUARTZ_IMediaSample_GetProperties(
IMediaSample* pSample,
AM_SAMPLE2_PROPERTIES* pProp )
{
#if 0 /* not yet */
HRESULT hr;
AM_SAMPLE2_PROPERTIES prop;
IMediaSample2* pSample2 = NULL;
ZeroMemory( &prop, sizeof(AM_SAMPLE2_PROPERTIES) );
hr = IMediaSample_QueryInterface( pSample, &IID_IMediaSample2, (void**)&pSample2 );
if ( hr == S_OK )
{
hr = IMediaSample2_GetProperties(pSample2,sizeof(AM_SAMPLE2_PROPERTIES),&prop);
IMediaSample2_Release(pSample2);
if ( hr == S_OK )
{
memcpy( pProp, &prop, sizeof(AM_SAMPLE2_PROPERTIES) );
pProp->pMediaType =
QUARTZ_MediaType_Duplicate( &prop.pMediaType );
return NOERROR;
}
}
#endif
pProp->cbData = sizeof(AM_SAMPLE2_PROPERTIES);
pProp->dwTypeSpecificFlags = 0;
pProp->dwSampleFlags = 0;
if ( IMediaSample_IsSyncPoint(pSample) == S_OK )
pProp->dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
if ( IMediaSample_IsPreroll(pSample) == S_OK )
pProp->dwSampleFlags |= AM_SAMPLE_PREROLL;
if ( IMediaSample_IsDiscontinuity(pSample) == S_OK )
pProp->dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
pProp->lActual = (LONG)IMediaSample_GetActualDataLength(pSample);
if ( IMediaSample_GetTime(pSample,&pProp->tStart,&pProp->tStop) == S_OK )
pProp->dwSampleFlags |= AM_SAMPLE_TIMEVALID | AM_SAMPLE_STOPVALID;
pProp->dwStreamId = 0;
if ( IMediaSample_GetMediaType(pSample,&(pProp->pMediaType)) == S_OK )
pProp->dwSampleFlags |= AM_SAMPLE_TYPECHANGED;
IMediaSample_GetPointer(pSample,&(pProp->pbBuffer));
pProp->cbBuffer = (LONG)IMediaSample_GetSize(pSample);
return NOERROR;
}
HRESULT QUARTZ_IMediaSample_SetProperties(
IMediaSample* pSample,
const AM_SAMPLE2_PROPERTIES* pProp )
{
HRESULT hr;
AM_SAMPLE2_PROPERTIES prop;
#if 0 /* not yet */
IMediaSample2* pSample2 = NULL;
#endif
memcpy( &prop, pProp, sizeof(AM_SAMPLE2_PROPERTIES) );
prop.cbData = sizeof(AM_SAMPLE2_PROPERTIES);
prop.pbBuffer = NULL;
prop.cbBuffer = 0;
#if 0 /* not yet */
hr = IMediaSample_QueryInterface( pSample, &IID_IMediaSample2, (void**)&pSample2 );
if ( hr == S_OK )
{
hr = IMediaSample2_SetProperties(pSample2,sizeof(AM_SAMPLE2_PROPERTIES),&prop);
IMediaSample2_Release(pSample2);
if ( hr == S_OK )
return NOERROR;
}
#endif
hr = S_OK;
if ( SUCCEEDED(hr) )
hr = IMediaSample_SetSyncPoint(pSample,
(prop.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? TRUE : FALSE);
if ( SUCCEEDED(hr) )
hr = IMediaSample_SetPreroll(pSample,
(prop.dwSampleFlags & AM_SAMPLE_PREROLL) ? TRUE : FALSE);
if ( SUCCEEDED(hr) )
hr = IMediaSample_SetDiscontinuity(pSample,
(prop.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? TRUE : FALSE);
if ( SUCCEEDED(hr) )
{
TRACE("length = %ld/%ld\n",prop.lActual,pProp->cbBuffer);
hr = IMediaSample_SetActualDataLength(pSample,prop.lActual);
}
if ( SUCCEEDED(hr) )
{
if ( ( prop.dwSampleFlags & AM_SAMPLE_TIMEVALID) &&
( prop.dwSampleFlags & AM_SAMPLE_STOPVALID) )
hr = IMediaSample_SetTime(pSample,&prop.tStart,&prop.tStop);
else
hr = IMediaSample_SetTime(pSample,NULL,NULL);
}
if ( SUCCEEDED(hr) )
hr = IMediaSample_SetMediaType(pSample,
(prop.dwSampleFlags & AM_SAMPLE_TYPECHANGED) ?
prop.pMediaType : NULL);
return hr;
}
HRESULT QUARTZ_IMediaSample_Copy(
IMediaSample* pDstSample,
IMediaSample* pSrcSample,
BOOL bCopyData )
{
HRESULT hr;
AM_SAMPLE2_PROPERTIES prop;
BYTE* pDataSrc = NULL;
BYTE* pDataDst = NULL;
hr = QUARTZ_IMediaSample_GetProperties( pSrcSample, &prop );
if ( FAILED(hr) )
return hr;
if ( !bCopyData )
prop.lActual = 0;
hr = QUARTZ_IMediaSample_SetProperties( pDstSample, &prop );
if ( prop.pMediaType != NULL )
QUARTZ_MediaType_Destroy( prop.pMediaType );
if ( SUCCEEDED(hr) && bCopyData )
{
hr = IMediaSample_GetPointer(pSrcSample,&pDataSrc);
if ( SUCCEEDED(hr) )
hr = IMediaSample_GetPointer(pDstSample,&pDataDst);
if ( SUCCEEDED(hr) )
{
if ( pDataSrc != NULL && pDataDst != NULL )
memcpy( pDataDst, pDataSrc, prop.lActual );
else
hr = E_FAIL;
}
}
return hr;
}
/***************************************************************************
*
* CMemMediaSample::IMediaSample2
*
*/
static HRESULT WINAPI
IMediaSample2_fnQueryInterface(IMediaSample2* iface,REFIID riid,void** ppobj)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
if ( ppobj == NULL )
return E_POINTER;
if ( IsEqualGUID( riid, &IID_IUnknown ) ||
IsEqualGUID( riid, &IID_IMediaSample ) ||
IsEqualGUID( riid, &IID_IMediaSample2 ) )
{
*ppobj = iface;
IMediaSample2_AddRef(iface);
return NOERROR;
}
return E_NOINTERFACE;
}
static ULONG WINAPI
IMediaSample2_fnAddRef(IMediaSample2* iface)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->()\n",This);
return InterlockedExchangeAdd(&(This->ref),1) + 1;
}
static ULONG WINAPI
IMediaSample2_fnRelease(IMediaSample2* iface)
{
ICOM_THIS(CMemMediaSample,iface);
LONG ref;
TRACE("(%p)->()\n",This);
if ( This->ref == 0 )
{
ERR("(%p) - released sample!\n",This);
return 0;
}
ref = InterlockedExchangeAdd(&(This->ref),-1) - 1;
if ( ref > 0 )
return (ULONG)ref;
/* this class would be reused.. */
if ( This->prop.pMediaType != NULL )
{
QUARTZ_MediaType_Destroy( This->prop.pMediaType );
This->prop.pMediaType = NULL;
}
This->prop.dwTypeSpecificFlags = 0;
This->prop.dwSampleFlags = 0;
This->prop.lActual = This->prop.cbBuffer;
IMemAllocator_ReleaseBuffer(This->pOwner,(IMediaSample*)iface);
return 0;
}
static HRESULT WINAPI
IMediaSample2_fnGetPointer(IMediaSample2* iface,BYTE** ppData)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->()\n",This);
if ( This->ref == 0 )
{
ERR("(%p) - released sample!\n",This);
return E_UNEXPECTED;
}
if ( ppData == NULL )
return E_POINTER;
*ppData = This->prop.pbBuffer;
return NOERROR;
}
static long WINAPI
IMediaSample2_fnGetSize(IMediaSample2* iface)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->()\n",This);
return This->prop.cbBuffer;
}
static HRESULT WINAPI
IMediaSample2_fnGetTime(IMediaSample2* iface,REFERENCE_TIME* prtStart,REFERENCE_TIME* prtEnd)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->(%p,%p)\n",This,prtStart,prtEnd);
if ( This->ref == 0 )
{
ERR("(%p) - released sample!\n",This);
return E_UNEXPECTED;
}
if ( prtStart == NULL || prtEnd == NULL )
return E_POINTER;
if ( ( This->prop.dwSampleFlags & AM_SAMPLE_TIMEVALID ) &&
( This->prop.dwSampleFlags & AM_SAMPLE_STOPVALID ) )
{
*prtStart = This->prop.tStart;
*prtEnd = This->prop.tStop;
return NOERROR;
}
return VFW_E_MEDIA_TIME_NOT_SET;
}
static HRESULT WINAPI
IMediaSample2_fnSetTime(IMediaSample2* iface,REFERENCE_TIME* prtStart,REFERENCE_TIME* prtEnd)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->(%p,%p) stub!\n",This,prtStart,prtEnd);
This->prop.dwSampleFlags &= ~(AM_SAMPLE_TIMEVALID|AM_SAMPLE_STOPVALID);
if ( prtStart != NULL )
{
This->prop.dwSampleFlags |= AM_SAMPLE_TIMEVALID;
This->prop.tStart = *prtStart;
}
if ( prtEnd != NULL )
{
This->prop.dwSampleFlags |= AM_SAMPLE_STOPVALID;
This->prop.tStop = *prtEnd;
}
return NOERROR;
}
static HRESULT WINAPI
IMediaSample2_fnIsSyncPoint(IMediaSample2* iface)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->()\n",This);
return ( This->prop.dwSampleFlags & AM_SAMPLE_SPLICEPOINT ) ?
S_OK : S_FALSE;
}
static HRESULT WINAPI
IMediaSample2_fnSetSyncPoint(IMediaSample2* iface,BOOL bSync)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->(%d)\n",This,bSync);
if ( bSync )
This->prop.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
else
This->prop.dwSampleFlags &= ~AM_SAMPLE_SPLICEPOINT;
return NOERROR;
}
static HRESULT WINAPI
IMediaSample2_fnIsPreroll(IMediaSample2* iface)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->()\n",This);
return ( This->prop.dwSampleFlags & AM_SAMPLE_PREROLL ) ?
S_OK : S_FALSE;
}
static HRESULT WINAPI
IMediaSample2_fnSetPreroll(IMediaSample2* iface,BOOL bPreroll)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->(%d)\n",This,bPreroll);
if ( bPreroll )
This->prop.dwSampleFlags |= AM_SAMPLE_PREROLL;
else
This->prop.dwSampleFlags &= ~AM_SAMPLE_PREROLL;
return NOERROR;
}
static long WINAPI
IMediaSample2_fnGetActualDataLength(IMediaSample2* iface)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->()\n",This);
return This->prop.lActual;
}
static HRESULT WINAPI
IMediaSample2_fnSetActualDataLength(IMediaSample2* iface,long lLength)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->(%ld)\n",This,lLength);
if ( This->prop.cbBuffer < lLength )
return E_INVALIDARG;
This->prop.lActual = lLength;
return NOERROR;
}
static HRESULT WINAPI
IMediaSample2_fnGetMediaType(IMediaSample2* iface,AM_MEDIA_TYPE** ppmt)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->(%p)\n",This,ppmt);
if ( ppmt == NULL )
return E_POINTER;
*ppmt = NULL;
if ( !(This->prop.dwSampleFlags & AM_SAMPLE_TYPECHANGED) )
return S_FALSE;
*ppmt = QUARTZ_MediaType_Duplicate( This->prop.pMediaType );
if ( *ppmt == NULL )
return E_OUTOFMEMORY;
return NOERROR;
}
static HRESULT WINAPI
IMediaSample2_fnSetMediaType(IMediaSample2* iface,AM_MEDIA_TYPE* pmt)
{
ICOM_THIS(CMemMediaSample,iface);
AM_MEDIA_TYPE* pmtDup;
TRACE("(%p)->(%p)\n",This,pmt);
if ( pmt == NULL )
{
/* FIXME? */
if ( This->prop.pMediaType != NULL )
{
QUARTZ_MediaType_Destroy( This->prop.pMediaType );
This->prop.pMediaType = NULL;
}
This->prop.dwSampleFlags &= ~AM_SAMPLE_TYPECHANGED;
return NOERROR;
}
pmtDup = QUARTZ_MediaType_Duplicate( pmt );
if ( pmtDup == NULL )
return E_OUTOFMEMORY;
if ( This->prop.pMediaType != NULL )
QUARTZ_MediaType_Destroy( This->prop.pMediaType );
This->prop.dwSampleFlags |= AM_SAMPLE_TYPECHANGED;
This->prop.pMediaType = pmtDup;
return NOERROR;
}
static HRESULT WINAPI
IMediaSample2_fnIsDiscontinuity(IMediaSample2* iface)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->()\n",This);
return ( This->prop.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY ) ?
S_OK : S_FALSE;
}
static HRESULT WINAPI
IMediaSample2_fnSetDiscontinuity(IMediaSample2* iface,BOOL bDiscontinuity)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->(%d)\n",This,bDiscontinuity);
if ( bDiscontinuity )
This->prop.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
else
This->prop.dwSampleFlags &= ~AM_SAMPLE_DATADISCONTINUITY;
return NOERROR;
}
static HRESULT WINAPI
IMediaSample2_fnGetMediaTime(IMediaSample2* iface,LONGLONG* pTimeStart,LONGLONG* pTimeEnd)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->(%p,%p)\n",This,pTimeStart,pTimeEnd);
if ( pTimeStart == NULL || pTimeEnd == NULL )
return E_POINTER;
if ( !This->fMediaTimeIsValid )
return VFW_E_MEDIA_TIME_NOT_SET;
*pTimeStart = This->llMediaTimeStart;
*pTimeEnd = This->llMediaTimeEnd;
return NOERROR;
return E_NOTIMPL;
}
static HRESULT WINAPI
IMediaSample2_fnSetMediaTime(IMediaSample2* iface,LONGLONG* pTimeStart,LONGLONG* pTimeEnd)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->()\n",This);
if ( pTimeStart == NULL || pTimeEnd == NULL )
{
This->fMediaTimeIsValid = FALSE;
}
else
{
This->fMediaTimeIsValid = TRUE;
This->llMediaTimeStart = *pTimeStart;
This->llMediaTimeEnd = *pTimeEnd;
}
return NOERROR;
}
static HRESULT WINAPI
IMediaSample2_fnGetProperties(IMediaSample2* iface,DWORD cbProp,BYTE* pbProp)
{
ICOM_THIS(CMemMediaSample,iface);
TRACE("(%p)->(%lu,%p)\n",This,cbProp,pbProp);
if ( cbProp < 0 || cbProp > sizeof(AM_SAMPLE2_PROPERTIES) )
return E_FAIL;
memcpy( pbProp, &This->prop, cbProp );
return NOERROR;
}
static HRESULT WINAPI
IMediaSample2_fnSetProperties(IMediaSample2* iface,DWORD cbProp,const BYTE* pbProp)
{
ICOM_THIS(CMemMediaSample,iface);
const AM_SAMPLE2_PROPERTIES* pProp;
AM_SAMPLE2_PROPERTIES propNew;
AM_MEDIA_TYPE* pmtDup = NULL;
HRESULT hr = E_INVALIDARG;
TRACE("(%p)->(%lu,%p)\n",This,cbProp,pbProp);
if ( pbProp == NULL )
return E_POINTER;
pProp = (const AM_SAMPLE2_PROPERTIES*)pbProp;
if ( cbProp != sizeof(AM_SAMPLE2_PROPERTIES) )
goto err;
CopyMemory( &propNew, pProp, sizeof(AM_SAMPLE2_PROPERTIES) );
if ( propNew.cbData != sizeof(AM_SAMPLE2_PROPERTIES) )
goto err;
if ( This->prop.cbBuffer < propNew.lActual )
goto err;
if ( propNew.dwSampleFlags & AM_SAMPLE_TYPECHANGED )
{
pmtDup = QUARTZ_MediaType_Duplicate( propNew.pMediaType );
if ( pmtDup == NULL )
{
hr = E_OUTOFMEMORY;
goto err;
}
}
if ( propNew.pbBuffer != NULL && propNew.pbBuffer != This->prop.pbBuffer )
goto err;
if ( propNew.cbBuffer != 0 && propNew.cbBuffer != This->prop.cbBuffer )
goto err;
if ( This->prop.pMediaType != NULL )
QUARTZ_MediaType_Destroy( This->prop.pMediaType );
CopyMemory( &This->prop, &propNew, sizeof(AM_SAMPLE2_PROPERTIES) );
This->prop.pMediaType = pmtDup;
pmtDup = NULL;
hr= NOERROR;
err:
if ( pmtDup != NULL )
QUARTZ_MediaType_Destroy( pmtDup );
return hr;
}
static ICOM_VTABLE(IMediaSample2) imediasample2 =
{
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
/* IUnknown fields */
IMediaSample2_fnQueryInterface,
IMediaSample2_fnAddRef,
IMediaSample2_fnRelease,
/* IMediaSample fields */
IMediaSample2_fnGetPointer,
IMediaSample2_fnGetSize,
IMediaSample2_fnGetTime,
IMediaSample2_fnSetTime,
IMediaSample2_fnIsSyncPoint,
IMediaSample2_fnSetSyncPoint,
IMediaSample2_fnIsPreroll,
IMediaSample2_fnSetPreroll,
IMediaSample2_fnGetActualDataLength,
IMediaSample2_fnSetActualDataLength,
IMediaSample2_fnGetMediaType,
IMediaSample2_fnSetMediaType,
IMediaSample2_fnIsDiscontinuity,
IMediaSample2_fnSetDiscontinuity,
IMediaSample2_fnGetMediaTime,
IMediaSample2_fnSetMediaTime,
/* IMediaSample2 fields */
IMediaSample2_fnGetProperties,
IMediaSample2_fnSetProperties,
};
/***************************************************************************
*
* new/delete for CMemMediaSample
*
*/
HRESULT QUARTZ_CreateMemMediaSample(
BYTE* pbData, DWORD dwDataLength,
IMemAllocator* pOwner,
CMemMediaSample** ppSample )
{
CMemMediaSample* pms;
TRACE("(%p,%08lx,%p,%p)\n",pbData,dwDataLength,pOwner,ppSample);
pms = (CMemMediaSample*)QUARTZ_AllocObj( sizeof(CMemMediaSample) );
if ( pms == NULL )
return E_OUTOFMEMORY;
ICOM_VTBL(pms) = &imediasample2;
pms->ref = 0;
pms->pOwner = pOwner;
pms->fMediaTimeIsValid = FALSE;
pms->llMediaTimeStart = 0;
pms->llMediaTimeEnd = 0;
ZeroMemory( &(pms->prop), sizeof(pms->prop) );
pms->prop.cbData = sizeof(pms->prop);
pms->prop.dwTypeSpecificFlags = 0;
pms->prop.dwSampleFlags = 0;
pms->prop.pbBuffer = pbData;
pms->prop.cbBuffer = (LONG)dwDataLength;
pms->prop.lActual = (LONG)dwDataLength;
*ppSample = pms;
return S_OK;
}
void QUARTZ_DestroyMemMediaSample(
CMemMediaSample* pSample )
{
TRACE("(%p)\n",pSample);
QUARTZ_FreeObj( pSample );
}