wine/dlls/avifil32/igframe.c
2002-02-19 18:29:54 +00:00

415 lines
10 KiB
C

/*
* Copyright 2001 Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
*
* FIXME - implements color space(depth) converter.
*/
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "winbase.h"
#include "winnls.h"
#include "mmsystem.h"
#include "winerror.h"
#include "vfw.h"
#include "debugtools.h"
#include "avifile_private.h"
DEFAULT_DEBUG_CHANNEL(avifile);
static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame* iface,REFIID refiid,LPVOID *obj);
static ULONG WINAPI IGetFrame_fnAddRef(IGetFrame* iface);
static ULONG WINAPI IGetFrame_fnRelease(IGetFrame* iface);
static LPVOID WINAPI IGetFrame_fnGetFrame(IGetFrame* iface,LONG lPos);
static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame* iface,LONG lStart,LONG lEnd,LONG lRate);
static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame* iface);
static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame* iface,LPBITMAPINFOHEADER lpbi,LPVOID lpBits,INT x,INT y,INT dx,INT dy);
struct ICOM_VTABLE(IGetFrame) igetfrm = {
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
IGetFrame_fnQueryInterface,
IGetFrame_fnAddRef,
IGetFrame_fnRelease,
IGetFrame_fnGetFrame,
IGetFrame_fnBegin,
IGetFrame_fnEnd,
IGetFrame_fnSetFormat,
};
typedef struct IGetFrameImpl
{
ICOM_VFIELD(IGetFrame);
/* IUnknown stuff */
DWORD ref;
/* IGetFrame stuff */
IAVIStream* pas;
HIC hIC;
LONG lCachedFrame;
BITMAPINFO* pbiICIn;
BITMAPINFO* pbiICOut;
LPVOID pvICOutBits;
LPVOID pvICInFmtBuf;
DWORD dwICInDataBufSize;
LPVOID pvICInDataBuf;
LPVOID pvICOutBuf;
} IGetFrameImpl;
static HRESULT IGetFrame_Construct( IGetFrameImpl* This,
IAVIStream* pstr,
LPBITMAPINFOHEADER lpbi );
static void IGetFrame_Destruct( IGetFrameImpl* This );
static LPVOID AVIFILE_IGetFrame_DecodeFrame(IGetFrameImpl* This,LONG lPos)
{
HRESULT hr;
DWORD dwRes;
LONG lFrameLength;
LONG lSampleCount;
ICDECOMPRESS icd;
if ( This->hIC == (HIC)NULL )
return NULL;
hr = IAVIStream_Read(This->pas,lPos,1,NULL,0,
&lFrameLength,&lSampleCount);
if ( hr != S_OK || lSampleCount <= 0 )
{
FIXME( "IAVIStream_Read failed! res = %08lx\n", hr );
return NULL;
}
TRACE( "frame length = %ld\n", lFrameLength );
if ( This->dwICInDataBufSize < lFrameLength )
{
LPVOID lpv;
if ( This->pvICInDataBuf == NULL )
{
lpv = HeapAlloc(
AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
lFrameLength );
}
else
{
lpv = HeapReAlloc(
AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
This->pvICInDataBuf,lFrameLength );
}
if ( lpv == NULL )
{
ERR( "out of memory!\n" );
return NULL;
}
This->pvICInDataBuf = lpv;
This->dwICInDataBufSize = lFrameLength;
}
hr = IAVIStream_Read(This->pas,lPos,1,
This->pvICInDataBuf,This->dwICInDataBufSize,
&lFrameLength,&lSampleCount);
if ( hr != S_OK || lSampleCount <= 0 )
{
FIXME( "IAVIStream_Read to buffer failed! res = %08lx\n", hr );
return NULL;
}
This->pbiICIn->bmiHeader.biSizeImage = lFrameLength;
TRACE( "call ICM_DECOMPRESS\n" );
icd.dwFlags = 0;
if ( IAVIStream_FindSample(This->pas,lPos,FIND_PREV|FIND_KEY) != lPos )
icd.dwFlags = ICDECOMPRESS_NOTKEYFRAME;
icd.lpbiInput = &This->pbiICIn->bmiHeader;
icd.lpInput = (BYTE*)This->pvICInDataBuf;
icd.lpbiOutput = &This->pbiICOut->bmiHeader;
icd.lpOutput = This->pvICOutBits;
icd.ckid = *((DWORD*)This->pvICInDataBuf);
dwRes = ICSendMessage(This->hIC,ICM_DECOMPRESS,
(DWORD)(&icd),sizeof(ICDECOMPRESS) );
TRACE( "returned from ICM_DECOMPRESS\n" );
if ( dwRes != ICERR_OK )
{
ERR( "ICDecompress failed!\n" );
return NULL;
}
This->lCachedFrame = lPos;
return This->pvICOutBits;
}
/****************************************************************************/
HRESULT AVIFILE_CreateIGetFrame(void** ppobj,
IAVIStream* pstr,LPBITMAPINFOHEADER lpbi)
{
IGetFrameImpl *This;
HRESULT hr;
*ppobj = NULL;
This = (IGetFrameImpl*)HeapAlloc(AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
sizeof(IGetFrameImpl));
This->ref = 1;
ICOM_VTBL(This) = &igetfrm;
hr = IGetFrame_Construct( This, pstr, lpbi );
if ( hr != S_OK )
{
IGetFrame_Destruct( This );
return hr;
}
*ppobj = (LPVOID)This;
return S_OK;
}
/****************************************************************************
* IUnknown interface
*/
static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame* iface,REFIID refiid,LPVOID *obj)
{
ICOM_THIS(IGetFrameImpl,iface);
TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj);
if ( IsEqualGUID(&IID_IUnknown,refiid) ||
IsEqualGUID(&IID_IGetFrame,refiid) )
{
IGetFrame_AddRef(iface);
*obj = iface;
return S_OK;
}
return OLE_E_ENUM_NOMORE;
}
static ULONG WINAPI IGetFrame_fnAddRef(IGetFrame* iface)
{
ICOM_THIS(IGetFrameImpl,iface);
TRACE("(%p)->AddRef()\n",iface);
return ++(This->ref);
}
static ULONG WINAPI IGetFrame_fnRelease(IGetFrame* iface)
{
ICOM_THIS(IGetFrameImpl,iface);
TRACE("(%p)->Release()\n",iface);
if ((--(This->ref)) > 0 )
return This->ref;
IGetFrame_Destruct(This);
if ( This->pas != NULL )
IAVIStream_Release( This->pas );
HeapFree(AVIFILE_data.hHeap,0,iface);
return 0;
}
/****************************************************************************
* IGetFrrame interface
*/
static LPVOID WINAPI IGetFrame_fnGetFrame(IGetFrame* iface,LONG lPos)
{
ICOM_THIS(IGetFrameImpl,iface);
LPVOID lpv;
LONG lKeyFrame;
TRACE( "(%p)->(%ld)\n", This, lPos );
if ( lPos < 0 )
return NULL;
if ( This->lCachedFrame == lPos )
return This->pvICOutBits;
if ( (This->lCachedFrame+1) != lPos )
{
lKeyFrame = IAVIStream_FindSample( This->pas, lPos,
FIND_KEY | FIND_PREV );
if ( lKeyFrame < 0 || lKeyFrame > lPos )
return NULL;
while ( ++lKeyFrame < lPos )
{
lpv = AVIFILE_IGetFrame_DecodeFrame(This, lKeyFrame);
if ( lpv == NULL )
return NULL;
}
}
lpv = AVIFILE_IGetFrame_DecodeFrame(This, lPos);
TRACE( "lpv = %p\n",lpv );
if ( lpv == NULL )
return NULL;
return lpv;
}
static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame* iface,LONG lStart,LONG lEnd,LONG lRate)
{
ICOM_THIS(IGetFrameImpl,iface);
TRACE( "(%p)->(%ld,%ld,%ld)\n", This, lStart, lEnd, lRate );
if ( This->hIC == (HIC)NULL )
return E_UNEXPECTED;
if ( ICDecompressBegin( This->hIC,
This->pbiICIn,
This->pbiICOut ) != ICERR_OK )
return E_FAIL;
return S_OK;
}
static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame* iface)
{
ICOM_THIS(IGetFrameImpl,iface);
TRACE( "(%p)->()\n", This );
if ( This->hIC == (HIC)NULL )
return E_UNEXPECTED;
if ( ICDecompressEnd( This->hIC ) != ICERR_OK )
return E_FAIL;
return S_OK;
}
static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame* iface,LPBITMAPINFOHEADER lpbi,LPVOID lpBits,INT x,INT y,INT dx,INT dy)
{
ICOM_THIS(IGetFrameImpl,iface);
HRESULT hr;
LONG fmtlen;
BITMAPINFOHEADER biTemp;
DWORD dwSizeImage;
FIXME( "(%p)->(%p,%p,%d,%d,%d,%d)\n",This,lpbi,lpBits,x,y,dx,dy );
IGetFrame_Destruct(This);
hr = IAVIStream_ReadFormat(This->pas,0,NULL,&fmtlen);
if ( hr != S_OK )
return hr;
This->pvICInFmtBuf = HeapAlloc(
AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,fmtlen);
if ( This->pvICInFmtBuf == NULL )
return AVIERR_MEMORY;
hr = IAVIStream_ReadFormat(This->pas,0,This->pvICInFmtBuf,&fmtlen);
if ( hr != S_OK )
return hr;
This->pbiICIn = (LPBITMAPINFO)This->pvICInFmtBuf;
This->hIC = (HIC)ICOpen( ICTYPE_VIDEO,
This->pbiICIn->bmiHeader.biCompression,
ICMODE_DECOMPRESS );
if ( This->hIC == (HIC)NULL )
{
ERR( "no AVI decompressor for %c%c%c%c.\n",
(int)(This->pbiICIn->bmiHeader.biCompression>> 0)&0xff,
(int)(This->pbiICIn->bmiHeader.biCompression>> 8)&0xff,
(int)(This->pbiICIn->bmiHeader.biCompression>>16)&0xff,
(int)(This->pbiICIn->bmiHeader.biCompression>>24)&0xff );
return E_FAIL;
}
if ( lpbi == NULL || lpbi == ((LPBITMAPINFOHEADER)1) )
{
memset( &biTemp, 0, sizeof(biTemp) );
biTemp.biSize = sizeof(BITMAPINFOHEADER);
biTemp.biWidth = This->pbiICIn->bmiHeader.biWidth;
biTemp.biHeight = This->pbiICIn->bmiHeader.biHeight;
biTemp.biPlanes = 1;
biTemp.biBitCount = 24;
biTemp.biCompression = 0;
lpbi = &biTemp;
}
if ( lpbi->biPlanes != 1 || lpbi->biCompression != 0 )
return E_FAIL;
dwSizeImage =
((This->pbiICIn->bmiHeader.biWidth*lpbi->biBitCount+7)/8)*
This->pbiICIn->bmiHeader.biHeight;
This->pvICOutBuf = HeapAlloc(
AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
(sizeof(BITMAPINFO)+sizeof(RGBQUAD)*256)*2+
dwSizeImage );
if ( This->pvICOutBuf == NULL )
return AVIERR_MEMORY;
This->pbiICOut = (BITMAPINFO*)This->pvICOutBuf;
This->pvICOutBits = (LPVOID)( (BYTE*)This->pvICOutBuf +
sizeof(BITMAPINFO) + sizeof(RGBQUAD)*256 );
This->pbiICOut->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
This->pbiICOut->bmiHeader.biWidth = This->pbiICIn->bmiHeader.biWidth;
This->pbiICOut->bmiHeader.biHeight = This->pbiICIn->bmiHeader.biHeight;
This->pbiICOut->bmiHeader.biPlanes = 1;
This->pbiICOut->bmiHeader.biBitCount = lpbi->biBitCount;
This->pbiICOut->bmiHeader.biSizeImage = dwSizeImage;
memcpy( This->pvICOutBits, This->pbiICOut, sizeof(BITMAPINFOHEADER) );
return S_OK;
}
static HRESULT IGetFrame_Construct( IGetFrameImpl* This,
IAVIStream* pstr,
LPBITMAPINFOHEADER lpbi )
{
HRESULT hr;
TRACE( "(%p)->(%p,%p)\n",This,pstr,lpbi );
IAVIStream_AddRef( pstr );
This->pas = pstr;
This->hIC = (HIC)NULL;
This->lCachedFrame = -1L;
This->pbiICIn = NULL;
This->pbiICOut = NULL;
This->pvICInFmtBuf = NULL;
This->pvICInDataBuf = NULL;
This->dwICInDataBufSize = 0;
This->pvICOutBuf = NULL;
hr = IGetFrame_SetFormat((IGetFrame*)This,lpbi,NULL,0,0,0,0);
if ( hr != S_OK )
return hr;
return S_OK;
}
static void IGetFrame_Destruct( IGetFrameImpl* This )
{
if ( This->hIC != (HIC)NULL )
{
ICClose( This->hIC );
This->hIC = (HIC)NULL;
}
if ( This->pvICInFmtBuf != NULL )
{
HeapFree( AVIFILE_data.hHeap, 0, This->pvICInFmtBuf );
This->pvICInFmtBuf = NULL;
}
if ( This->pvICInDataBuf != NULL )
{
HeapFree( AVIFILE_data.hHeap, 0, This->pvICInDataBuf );
This->pvICInDataBuf = NULL;
}
if ( This->pvICOutBuf != NULL )
{
HeapFree( AVIFILE_data.hHeap, 0, This->pvICOutBuf );
This->pvICOutBuf = NULL;
}
This->lCachedFrame = -1L;
This->pbiICIn = NULL;
This->pbiICOut = NULL;
This->dwICInDataBufSize = 0;
}