mirror of
https://github.com/reactos/wine.git
synced 2024-12-06 18:56:49 +00:00
745 lines
18 KiB
C
745 lines
18 KiB
C
/*
|
|
* Copyright 1999 Marcus Meissner
|
|
* Copyright 2001 Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
|
|
*
|
|
* FIXME - implements editing/writing.
|
|
*/
|
|
|
|
#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);
|
|
|
|
#define AVIFILE_STREAMS_MAX 4
|
|
|
|
|
|
static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj);
|
|
static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile* iface);
|
|
static ULONG WINAPI IAVIFile_fnRelease(IAVIFile* iface);
|
|
static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size);
|
|
static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam);
|
|
static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi);
|
|
static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size);
|
|
static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size);
|
|
static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface);
|
|
static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam);
|
|
|
|
struct ICOM_VTABLE(IAVIFile) iavift = {
|
|
ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
|
|
IAVIFile_fnQueryInterface,
|
|
IAVIFile_fnAddRef,
|
|
IAVIFile_fnRelease,
|
|
IAVIFile_fnInfo,
|
|
IAVIFile_fnGetStream,
|
|
IAVIFile_fnCreateStream,
|
|
IAVIFile_fnWriteData,
|
|
IAVIFile_fnReadData,
|
|
IAVIFile_fnEndRecord,
|
|
IAVIFile_fnDeleteStream,
|
|
/* IAVIFILE_fnOpen */ /* FIXME? */
|
|
};
|
|
|
|
|
|
typedef struct IAVIFileImpl
|
|
{
|
|
ICOM_VFIELD(IAVIFile);
|
|
/* IUnknown stuff */
|
|
DWORD ref;
|
|
/* IAVIFile stuff */
|
|
HANDLE hf;
|
|
DWORD dwAVIFileCaps;
|
|
DWORD dwAVIFileScale;
|
|
DWORD dwAVIFileRate;
|
|
DWORD dwAVIFileLength;
|
|
DWORD dwAVIFileEditCount;
|
|
MainAVIHeader hdr;
|
|
IAVIStream* pStreams[AVIFILE_STREAMS_MAX];
|
|
AVIStreamHeader strhdrs[AVIFILE_STREAMS_MAX];
|
|
DWORD dwMoviTop;
|
|
DWORD dwCountOfIndexEntry;
|
|
AVIINDEXENTRY* pIndexEntry;
|
|
AVIINDEXENTRY* pStreamIndexEntry[AVIFILE_STREAMS_MAX+1];
|
|
} IAVIFileImpl;
|
|
|
|
|
|
/****************************************************************************
|
|
* AVI file parser.
|
|
*/
|
|
|
|
static HRESULT AVIFILE_IAVIFile_ReadNextChunkHeader(
|
|
IAVIFileImpl* This, FOURCC* pfcc, DWORD* pdwSize )
|
|
{
|
|
BYTE buf[8];
|
|
DWORD dwRead;
|
|
|
|
if ( ( !ReadFile( This->hf, buf, 8, &dwRead, NULL ) ) ||
|
|
( 8 != dwRead ) )
|
|
return AVIERR_FILEREAD;
|
|
*pfcc = mmioFOURCC(buf[0],buf[1],buf[2],buf[3]);
|
|
*pdwSize = ( ((DWORD)buf[4]) ) |
|
|
( ((DWORD)buf[5]) << 8 ) |
|
|
( ((DWORD)buf[6]) << 16 ) |
|
|
( ((DWORD)buf[7]) << 24 );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT AVIFILE_IAVIFile_SkipChunkData(
|
|
IAVIFileImpl* This, DWORD dwChunkSize )
|
|
{
|
|
LONG lHigh = 0;
|
|
DWORD dwRes;
|
|
|
|
if ( dwChunkSize == 0 )
|
|
return S_OK;
|
|
|
|
SetLastError(NO_ERROR);
|
|
dwRes = SetFilePointer( This->hf, (LONG)dwChunkSize,
|
|
&lHigh, FILE_CURRENT );
|
|
if ( dwRes == (DWORD)0xffffffff && GetLastError() != NO_ERROR )
|
|
return AVIERR_FILEREAD;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT AVIFILE_IAVIFile_ReadChunkData(
|
|
IAVIFileImpl* This, DWORD dwChunkSize,
|
|
LPVOID lpvBuf, DWORD dwBufSize, LPDWORD lpdwRead )
|
|
{
|
|
if ( dwBufSize > dwChunkSize )
|
|
dwBufSize = dwChunkSize;
|
|
if ( ( !ReadFile( This->hf, lpvBuf, dwBufSize, lpdwRead, NULL ) ) ||
|
|
( dwBufSize != *lpdwRead ) )
|
|
return AVIERR_FILEREAD;
|
|
|
|
return AVIFILE_IAVIFile_SkipChunkData( This, dwChunkSize - dwBufSize );
|
|
}
|
|
|
|
static HRESULT AVIFILE_IAVIFile_SeekToSpecifiedChunk(
|
|
IAVIFileImpl* This, FOURCC fccType, DWORD* pdwLen )
|
|
{
|
|
HRESULT hr;
|
|
FOURCC fcc;
|
|
BYTE buf[4];
|
|
DWORD dwRead;
|
|
|
|
while ( 1 )
|
|
{
|
|
hr = AVIFILE_IAVIFile_ReadNextChunkHeader(
|
|
This, &fcc, pdwLen );
|
|
if ( hr != S_OK )
|
|
return hr;
|
|
if ( fcc == fccType )
|
|
return S_OK;
|
|
|
|
if ( fcc == FOURCC_LIST )
|
|
{
|
|
if ( ( !ReadFile( This->hf, buf, 4, &dwRead, NULL ) ) ||
|
|
( 4 != dwRead ) )
|
|
return AVIERR_FILEREAD;
|
|
}
|
|
else
|
|
{
|
|
hr = AVIFILE_IAVIFile_SkipChunkData(
|
|
This, *pdwLen );
|
|
if ( hr != S_OK )
|
|
return hr;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
WINE_AVISTREAM_DATA* AVIFILE_Alloc_IAVIStreamData( DWORD dwFmtLen )
|
|
{
|
|
WINE_AVISTREAM_DATA* pData;
|
|
|
|
pData = (WINE_AVISTREAM_DATA*)
|
|
HeapAlloc( AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
|
|
sizeof(WINE_AVISTREAM_DATA) );
|
|
if ( pData == NULL )
|
|
return NULL;
|
|
if ( dwFmtLen > 0 )
|
|
{
|
|
pData->pbFmt = (BYTE*)
|
|
HeapAlloc( AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
|
|
sizeof(BYTE)*dwFmtLen );
|
|
if ( pData->pbFmt == NULL )
|
|
{
|
|
AVIFILE_Free_IAVIStreamData( pData );
|
|
return NULL;
|
|
}
|
|
}
|
|
pData->dwFmtLen = dwFmtLen;
|
|
|
|
return pData;
|
|
}
|
|
|
|
void AVIFILE_Free_IAVIStreamData( WINE_AVISTREAM_DATA* pData )
|
|
{
|
|
if ( pData != NULL )
|
|
{
|
|
if ( pData->pbFmt != NULL )
|
|
HeapFree( AVIFILE_data.hHeap,0,pData->pbFmt );
|
|
HeapFree( AVIFILE_data.hHeap,0,pData );
|
|
}
|
|
}
|
|
|
|
static void AVIFILE_IAVIFile_InitIndexTable(
|
|
IAVIFileImpl* This,
|
|
AVIINDEXENTRY* pIndexBuf,
|
|
AVIINDEXENTRY* pIndexData,
|
|
DWORD dwCountOfIndexEntry )
|
|
{
|
|
DWORD dwStreamIndex;
|
|
DWORD dwIndex;
|
|
FOURCC ckid;
|
|
|
|
dwStreamIndex = 0;
|
|
for ( ; dwStreamIndex < (AVIFILE_STREAMS_MAX+1); dwStreamIndex ++ )
|
|
This->pStreamIndexEntry[dwStreamIndex] = NULL;
|
|
|
|
dwStreamIndex = 0;
|
|
for ( ; dwStreamIndex < This->hdr.dwStreams; dwStreamIndex ++ )
|
|
{
|
|
ckid = mmioFOURCC('0','0'+dwStreamIndex,0,0);
|
|
TRACE( "testing ckid %c%c%c%c\n",
|
|
(int)(ckid>> 0)&0xff,
|
|
(int)(ckid>> 8)&0xff,
|
|
(int)(ckid>>16)&0xff,
|
|
(int)(ckid>>24)&0xff );
|
|
This->pStreamIndexEntry[dwStreamIndex] = pIndexBuf;
|
|
FIXME( "pIndexBuf = %p\n", pIndexBuf );
|
|
for ( dwIndex = 0; dwIndex < dwCountOfIndexEntry; dwIndex++ )
|
|
{
|
|
TRACE( "ckid %c%c%c%c\n",
|
|
(int)(pIndexData[dwIndex].ckid>> 0)&0xff,
|
|
(int)(pIndexData[dwIndex].ckid>> 8)&0xff,
|
|
(int)(pIndexData[dwIndex].ckid>>16)&0xff,
|
|
(int)(pIndexData[dwIndex].ckid>>24)&0xff );
|
|
|
|
if ( (pIndexData[dwIndex].ckid & mmioFOURCC(0xff,0xff,0,0))
|
|
== ckid )
|
|
{
|
|
memcpy( pIndexBuf, &pIndexData[dwIndex],
|
|
sizeof(AVIINDEXENTRY) );
|
|
pIndexBuf ++;
|
|
}
|
|
}
|
|
FIXME( "pIndexBuf = %p\n", pIndexBuf );
|
|
}
|
|
This->pStreamIndexEntry[This->hdr.dwStreams] = pIndexBuf;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
* Create an IAVIFile object.
|
|
*/
|
|
|
|
static HRESULT AVIFILE_IAVIFile_Construct( IAVIFileImpl* This );
|
|
static void AVIFILE_IAVIFile_Destruct( IAVIFileImpl* This );
|
|
|
|
HRESULT AVIFILE_CreateIAVIFile(void** ppobj)
|
|
{
|
|
IAVIFileImpl *This;
|
|
HRESULT hr;
|
|
|
|
TRACE("(%p)\n",ppobj);
|
|
*ppobj = NULL;
|
|
This = (IAVIFileImpl*)HeapAlloc(AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
|
|
sizeof(IAVIFileImpl));
|
|
if ( This == NULL )
|
|
return AVIERR_MEMORY;
|
|
This->ref = 1;
|
|
ICOM_VTBL(This) = &iavift;
|
|
hr = AVIFILE_IAVIFile_Construct( This );
|
|
if ( hr != S_OK )
|
|
{
|
|
AVIFILE_IAVIFile_Destruct( This );
|
|
return hr;
|
|
}
|
|
|
|
TRACE("new -> %p\n",This);
|
|
*ppobj = (LPVOID)This;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* IUnknown interface
|
|
*/
|
|
|
|
static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj) {
|
|
ICOM_THIS(IAVIFileImpl,iface);
|
|
|
|
TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj);
|
|
if ( IsEqualGUID(&IID_IUnknown,refiid) ||
|
|
IsEqualGUID(&IID_IAVIFile,refiid) )
|
|
{
|
|
*obj = iface;
|
|
IAVIFile_AddRef(iface);
|
|
return S_OK;
|
|
}
|
|
return OLE_E_ENUM_NOMORE;
|
|
}
|
|
|
|
static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile* iface) {
|
|
ICOM_THIS(IAVIFileImpl,iface);
|
|
|
|
TRACE("(%p)->AddRef()\n",iface);
|
|
return ++(This->ref);
|
|
}
|
|
|
|
static ULONG WINAPI IAVIFile_fnRelease(IAVIFile* iface) {
|
|
ICOM_THIS(IAVIFileImpl,iface);
|
|
|
|
TRACE("(%p)->Release()\n",iface);
|
|
if ( (--(This->ref)) > 0 )
|
|
return This->ref;
|
|
|
|
AVIFILE_IAVIFile_Destruct(This);
|
|
HeapFree(AVIFILE_data.hHeap,0,iface);
|
|
return 0;
|
|
}
|
|
|
|
/****************************************************************************
|
|
* IAVIFile interface
|
|
*/
|
|
|
|
static HRESULT AVIFILE_IAVIFile_Construct( IAVIFileImpl* This )
|
|
{
|
|
DWORD dwIndex;
|
|
|
|
This->hf = INVALID_HANDLE_VALUE;
|
|
This->dwAVIFileCaps = 0;
|
|
This->dwAVIFileScale = 0;
|
|
This->dwAVIFileRate = 0;
|
|
This->dwAVIFileLength = 0;
|
|
This->dwAVIFileEditCount = 0;
|
|
for ( dwIndex = 0; dwIndex < AVIFILE_STREAMS_MAX; dwIndex++ )
|
|
This->pStreams[dwIndex] = NULL;
|
|
This->dwCountOfIndexEntry = 0;
|
|
This->pIndexEntry = NULL;
|
|
|
|
AVIFILE_data.dwClassObjRef ++;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static void AVIFILE_IAVIFile_Destruct( IAVIFileImpl* This )
|
|
{
|
|
DWORD dwIndex;
|
|
|
|
if ( This->pIndexEntry != NULL )
|
|
{
|
|
HeapFree(AVIFILE_data.hHeap,0,This->pIndexEntry);
|
|
This->pIndexEntry = NULL;
|
|
}
|
|
|
|
for ( dwIndex = 0; dwIndex < AVIFILE_STREAMS_MAX; dwIndex++ )
|
|
{
|
|
if ( This->pStreams[dwIndex] != NULL )
|
|
{
|
|
IAVIStream_Release( This->pStreams[dwIndex] );
|
|
This->pStreams[dwIndex] = NULL;
|
|
}
|
|
}
|
|
|
|
if ( This->hf != INVALID_HANDLE_VALUE )
|
|
CloseHandle( This->hf );
|
|
|
|
AVIFILE_data.dwClassObjRef --;
|
|
}
|
|
|
|
static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size)
|
|
{
|
|
ICOM_THIS(IAVIFileImpl,iface);
|
|
AVIFILEINFOW fiw;
|
|
|
|
FIXME("(%p)->Info(%p,%ld)\n",iface,afi,size);
|
|
|
|
memset( &fiw, 0, sizeof(fiw) );
|
|
fiw.dwMaxBytesPerSec = This->hdr.dwMaxBytesPerSec;
|
|
fiw.dwFlags = This->hdr.dwFlags;
|
|
fiw.dwCaps = This->dwAVIFileCaps;
|
|
fiw.dwStreams = This->hdr.dwStreams;
|
|
fiw.dwSuggestedBufferSize = This->hdr.dwSuggestedBufferSize;
|
|
fiw.dwWidth = This->hdr.dwWidth;
|
|
fiw.dwHeight = This->hdr.dwHeight;
|
|
fiw.dwScale = This->dwAVIFileScale; /* FIXME */
|
|
fiw.dwRate = This->dwAVIFileRate; /* FIXME */
|
|
fiw.dwLength = This->dwAVIFileLength; /* FIXME */
|
|
fiw.dwEditCount = This->dwAVIFileEditCount; /* FIXME */
|
|
/* fiw.szFileType[64]; */
|
|
|
|
if ( size > sizeof(AVIFILEINFOW) )
|
|
size = sizeof(AVIFILEINFOW);
|
|
memcpy( afi, &fiw, size );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam)
|
|
{
|
|
ICOM_THIS(IAVIFileImpl,iface);
|
|
|
|
FIXME("(%p)->GetStream(%p,0x%08lx,%ld)\n",iface,avis,fccType,lParam);
|
|
if ( fccType != 0 )
|
|
return E_FAIL;
|
|
if ( lParam < 0 || lParam >= This->hdr.dwStreams )
|
|
return E_FAIL;
|
|
*avis = This->pStreams[lParam];
|
|
IAVIStream_AddRef( *avis );
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi)
|
|
{
|
|
ICOM_THIS(IAVIFileImpl,iface);
|
|
|
|
FIXME("(%p,%p,%p)\n",This,avis,asi);
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size)
|
|
{
|
|
ICOM_THIS(IAVIFileImpl,iface);
|
|
|
|
FIXME("(%p)->WriteData(0x%08lx,%p,%ld)\n",This,ckid,lpData,size);
|
|
/* FIXME: write data to file */
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size)
|
|
{
|
|
ICOM_THIS(IAVIFileImpl,iface);
|
|
|
|
FIXME("(%p)->ReadData(0x%08lx,%p,%p)\n",This,ckid,lpData,size);
|
|
/* FIXME: read at most size bytes from file */
|
|
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile*iface)
|
|
{
|
|
ICOM_THIS(IAVIFileImpl,iface);
|
|
|
|
FIXME("(%p)->EndRecord()\n",This);
|
|
/* FIXME: end record? */
|
|
return E_FAIL;
|
|
}
|
|
|
|
static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam)
|
|
{
|
|
ICOM_THIS(IAVIFileImpl,iface);
|
|
|
|
FIXME("(%p)->DeleteStream(0x%08lx,%ld)\n",This,fccType,lParam);
|
|
/* FIXME: delete stream? */
|
|
return E_FAIL;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* AVIFILE_IAVIFile_Open (internal)
|
|
*/
|
|
HRESULT AVIFILE_IAVIFile_Open( PAVIFILE paf, LPCWSTR szFile, UINT uMode )
|
|
{
|
|
ICOM_THIS(IAVIFileImpl,paf);
|
|
HRESULT hr;
|
|
DWORD dwAcc;
|
|
DWORD dwShared;
|
|
DWORD dwCreate;
|
|
BYTE buf[12];
|
|
DWORD dwRead;
|
|
FOURCC fccFileType;
|
|
DWORD dwLen;
|
|
DWORD dwIndex;
|
|
|
|
FIXME("(%p)->Open(%p,%u)\n",This,szFile,uMode);
|
|
|
|
if ( This->hf != INVALID_HANDLE_VALUE )
|
|
{
|
|
CloseHandle( This->hf );
|
|
This->hf = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
switch ( uMode & 0x3 )
|
|
{
|
|
case OF_READ: /* 0x0 */
|
|
dwAcc = GENERIC_READ;
|
|
dwCreate = OPEN_EXISTING;
|
|
This->dwAVIFileCaps = AVIFILECAPS_CANREAD;
|
|
break;
|
|
case OF_WRITE: /* 0x1 */
|
|
dwAcc = GENERIC_WRITE;
|
|
dwCreate = OPEN_ALWAYS;
|
|
This->dwAVIFileCaps = AVIFILECAPS_CANWRITE;
|
|
break;
|
|
case OF_READWRITE: /* 0x2 */
|
|
dwAcc = GENERIC_READ|GENERIC_WRITE;
|
|
dwCreate = OPEN_ALWAYS;
|
|
This->dwAVIFileCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
|
|
break;
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
|
|
if ( This->dwAVIFileCaps & AVIFILECAPS_CANWRITE )
|
|
{
|
|
FIXME( "editing AVI is currently not supported!\n" );
|
|
return E_FAIL;
|
|
}
|
|
|
|
switch ( uMode & 0x70 )
|
|
{
|
|
case OF_SHARE_COMPAT: /* 0x00 */
|
|
dwShared = FILE_SHARE_READ|FILE_SHARE_WRITE;
|
|
break;
|
|
case OF_SHARE_EXCLUSIVE: /* 0x10 */
|
|
dwShared = 0;
|
|
break;
|
|
case OF_SHARE_DENY_WRITE: /* 0x20 */
|
|
dwShared = FILE_SHARE_READ;
|
|
break;
|
|
case OF_SHARE_DENY_READ: /* 0x30 */
|
|
dwShared = FILE_SHARE_WRITE;
|
|
break;
|
|
case OF_SHARE_DENY_NONE: /* 0x40 */
|
|
dwShared = FILE_SHARE_READ|FILE_SHARE_WRITE;
|
|
break;
|
|
default:
|
|
return E_FAIL;
|
|
}
|
|
if ( uMode & OF_CREATE )
|
|
dwCreate = CREATE_ALWAYS;
|
|
|
|
This->hf = CreateFileW( szFile, dwAcc, dwShared, NULL,
|
|
dwCreate, FILE_ATTRIBUTE_NORMAL,
|
|
(HANDLE)NULL );
|
|
if ( This->hf == INVALID_HANDLE_VALUE )
|
|
return AVIERR_FILEOPEN;
|
|
|
|
if ( dwAcc & GENERIC_READ )
|
|
{
|
|
if ( !ReadFile( This->hf, buf, 12, &dwRead, NULL ) )
|
|
return AVIERR_FILEREAD;
|
|
if ( dwRead == 12 )
|
|
{
|
|
if ( mmioFOURCC(buf[0],buf[1],buf[2],buf[3]) != FOURCC_RIFF )
|
|
return AVIERR_BADFORMAT;
|
|
|
|
fccFileType = mmioFOURCC(buf[8],buf[9],buf[10],buf[11]);
|
|
if ( fccFileType != formtypeAVI )
|
|
return AVIERR_BADFORMAT;
|
|
|
|
/* get AVI main header. */
|
|
hr = AVIFILE_IAVIFile_SeekToSpecifiedChunk(
|
|
This, ckidAVIMAINHDR, &dwLen );
|
|
if ( hr != S_OK )
|
|
return hr;
|
|
if ( dwLen < (sizeof(DWORD)*10) )
|
|
return AVIERR_BADFORMAT;
|
|
hr = AVIFILE_IAVIFile_ReadChunkData(
|
|
This, dwLen,
|
|
&(This->hdr), sizeof(MainAVIHeader), &dwLen );
|
|
if ( This->hdr.dwStreams == 0 ||
|
|
This->hdr.dwStreams > AVIFILE_STREAMS_MAX )
|
|
return AVIERR_BADFORMAT;
|
|
|
|
/* get stream headers. */
|
|
dwIndex = 0;
|
|
while ( dwIndex < This->hdr.dwStreams )
|
|
{
|
|
WINE_AVISTREAM_DATA* pData;
|
|
|
|
hr = AVIFILE_IAVIFile_SeekToSpecifiedChunk(
|
|
This, ckidSTREAMHEADER, &dwLen );
|
|
if ( hr != S_OK )
|
|
return hr;
|
|
if ( dwLen < (sizeof(DWORD)*12) )
|
|
return AVIERR_BADFORMAT;
|
|
hr = AVIFILE_IAVIFile_ReadChunkData(
|
|
This, dwLen,
|
|
&This->strhdrs[dwIndex],
|
|
sizeof(AVIStreamHeader), &dwLen );
|
|
|
|
hr = AVIFILE_IAVIFile_SeekToSpecifiedChunk(
|
|
This, ckidSTREAMFORMAT, &dwLen );
|
|
if ( hr != S_OK )
|
|
return hr;
|
|
pData = AVIFILE_Alloc_IAVIStreamData( dwLen );
|
|
if ( pData == NULL )
|
|
return AVIERR_MEMORY;
|
|
hr = AVIFILE_IAVIFile_ReadChunkData(
|
|
This, dwLen,
|
|
pData->pbFmt, dwLen, &dwLen );
|
|
if ( hr != S_OK )
|
|
{
|
|
AVIFILE_Free_IAVIStreamData( pData );
|
|
return hr;
|
|
}
|
|
pData->dwStreamIndex = dwIndex;
|
|
pData->pstrhdr = &This->strhdrs[dwIndex];
|
|
|
|
hr = AVIStreamCreate(&This->pStreams[dwIndex],
|
|
(LONG)paf, (LONG)(pData), NULL );
|
|
if ( hr != S_OK )
|
|
{
|
|
AVIFILE_Free_IAVIStreamData( pData );
|
|
return hr;
|
|
}
|
|
|
|
if ( (This->strhdrs[dwIndex].fccType
|
|
== mmioFOURCC('v','i','d','s')) ||
|
|
(This->strhdrs[dwIndex].fccType
|
|
== mmioFOURCC('V','I','D','S')) )
|
|
{
|
|
This->dwAVIFileScale =
|
|
This->strhdrs[dwIndex].dwScale;
|
|
This->dwAVIFileRate =
|
|
This->strhdrs[dwIndex].dwRate;
|
|
This->dwAVIFileLength =
|
|
This->strhdrs[dwIndex].dwLength;
|
|
}
|
|
else
|
|
if ( This->dwAVIFileScale == 0 )
|
|
{
|
|
This->dwAVIFileScale =
|
|
This->strhdrs[dwIndex].dwScale;
|
|
This->dwAVIFileRate =
|
|
This->strhdrs[dwIndex].dwRate;
|
|
This->dwAVIFileLength =
|
|
This->strhdrs[dwIndex].dwLength;
|
|
}
|
|
|
|
dwIndex ++;
|
|
}
|
|
|
|
/* skip movi. */
|
|
while ( 1 )
|
|
{
|
|
hr = AVIFILE_IAVIFile_SeekToSpecifiedChunk(
|
|
This, FOURCC_LIST, &dwLen );
|
|
if ( hr != S_OK )
|
|
return hr;
|
|
if ( dwLen < 4 )
|
|
return AVIERR_BADFORMAT;
|
|
|
|
This->dwMoviTop = SetFilePointer( This->hf,0,NULL,FILE_CURRENT );
|
|
if ( This->dwMoviTop == 0xffffffff )
|
|
return AVIERR_BADFORMAT;
|
|
|
|
if ( ( !ReadFile(This->hf, buf, 4, &dwRead, NULL) ) ||
|
|
( dwRead != 4 ) )
|
|
return AVIERR_FILEREAD;
|
|
|
|
hr = AVIFILE_IAVIFile_SkipChunkData(
|
|
This, dwLen - 4 );
|
|
if ( hr != S_OK )
|
|
return hr;
|
|
if ( mmioFOURCC(buf[0],buf[1],buf[2],buf[3])
|
|
== mmioFOURCC('m', 'o', 'v', 'i') )
|
|
break;
|
|
}
|
|
|
|
/* get idx1. */
|
|
hr = AVIFILE_IAVIFile_SeekToSpecifiedChunk(
|
|
This, ckidAVINEWINDEX, &dwLen );
|
|
if ( hr != S_OK )
|
|
return hr;
|
|
|
|
This->dwCountOfIndexEntry = dwLen / sizeof(AVIINDEXENTRY);
|
|
This->pIndexEntry = (AVIINDEXENTRY*)
|
|
HeapAlloc(AVIFILE_data.hHeap,HEAP_ZERO_MEMORY,
|
|
sizeof(AVIINDEXENTRY) *
|
|
This->dwCountOfIndexEntry * 2 );
|
|
if ( This->pIndexEntry == NULL )
|
|
return AVIERR_MEMORY;
|
|
hr = AVIFILE_IAVIFile_ReadChunkData(
|
|
This, dwLen,
|
|
This->pIndexEntry + This->dwCountOfIndexEntry,
|
|
sizeof(AVIINDEXENTRY) *
|
|
This->dwCountOfIndexEntry, &dwLen );
|
|
if ( hr != S_OK )
|
|
return hr;
|
|
AVIFILE_IAVIFile_InitIndexTable(
|
|
This, This->pIndexEntry,
|
|
This->pIndexEntry + This->dwCountOfIndexEntry,
|
|
This->dwCountOfIndexEntry );
|
|
}
|
|
else
|
|
{
|
|
/* FIXME - create the handle has GENERIC_WRITE access. */
|
|
return AVIERR_FILEREAD;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return AVIERR_FILEOPEN; /* FIXME */
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* AVIFILE_IAVIFile_GetIndexTable (internal)
|
|
*/
|
|
HRESULT AVIFILE_IAVIFile_GetIndexTable( PAVIFILE paf, DWORD dwStreamIndex,
|
|
AVIINDEXENTRY** ppIndexEntry,
|
|
DWORD* pdwCountOfIndexEntry )
|
|
{
|
|
ICOM_THIS(IAVIFileImpl,paf);
|
|
|
|
if ( dwStreamIndex < 0 || dwStreamIndex >= This->hdr.dwStreams )
|
|
{
|
|
FIXME( "invalid stream index %lu\n", dwStreamIndex );
|
|
return E_FAIL;
|
|
}
|
|
FIXME( "cur %p, next %p\n",
|
|
This->pStreamIndexEntry[dwStreamIndex],
|
|
This->pStreamIndexEntry[dwStreamIndex+1] );
|
|
*ppIndexEntry = This->pStreamIndexEntry[dwStreamIndex];
|
|
*pdwCountOfIndexEntry =
|
|
This->pStreamIndexEntry[dwStreamIndex+1] -
|
|
This->pStreamIndexEntry[dwStreamIndex];
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
/*****************************************************************************
|
|
* AVIFILE_IAVIFile_ReadMovieData (internal)
|
|
*/
|
|
HRESULT AVIFILE_IAVIFile_ReadMovieData( PAVIFILE paf, DWORD dwOffset,
|
|
DWORD dwLength, LPVOID lpvBuf )
|
|
{
|
|
ICOM_THIS(IAVIFileImpl,paf);
|
|
LONG lHigh = 0;
|
|
DWORD dwRes;
|
|
|
|
if ( dwLength == 0 )
|
|
return S_OK;
|
|
SetLastError(NO_ERROR);
|
|
dwRes = SetFilePointer( This->hf, (LONG)(dwOffset+This->dwMoviTop),
|
|
&lHigh, FILE_BEGIN );
|
|
if ( dwRes == (DWORD)0xffffffff && GetLastError() != NO_ERROR )
|
|
return AVIERR_FILEREAD;
|
|
|
|
if ( ( !ReadFile(This->hf, lpvBuf, dwLength, &dwRes, NULL) ) ||
|
|
( dwLength != dwRes ) )
|
|
{
|
|
FIXME( "error in ReadFile()\n" );
|
|
return AVIERR_FILEREAD;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|