/* * Copyright 2001 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 #include #include #include "winbase.h" #include "winnls.h" #include "mmsystem.h" #include "winerror.h" #include "vfw.h" #include "wine/debug.h" #include "avifile_private.h" WINE_DEFAULT_DEBUG_CHANNEL(avifile); static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj); static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream*iface); static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface); static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2); static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size); static LONG WINAPI IAVIStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags); static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize); static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize); static HRESULT WINAPI IAVIStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread); static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten); static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples); static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread); static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size); static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen); struct ICOM_VTABLE(IAVIStream) iavist = { ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE IAVIStream_fnQueryInterface, IAVIStream_fnAddRef, IAVIStream_fnRelease, IAVIStream_fnCreate, IAVIStream_fnInfo, IAVIStream_fnFindSample, IAVIStream_fnReadFormat, IAVIStream_fnSetFormat, IAVIStream_fnRead, IAVIStream_fnWrite, IAVIStream_fnDelete, IAVIStream_fnReadData, IAVIStream_fnWriteData, IAVIStream_fnSetInfo }; typedef struct IAVIStreamImpl { ICOM_VFIELD(IAVIStream); /* IUnknown stuff */ DWORD ref; /* IAVIStream stuff */ IAVIFile* paf; WINE_AVISTREAM_DATA* pData; } IAVIStreamImpl; static HRESULT IAVIStream_Construct( IAVIStreamImpl* This ); static void IAVIStream_Destruct( IAVIStreamImpl* This ); HRESULT AVIFILE_CreateIAVIStream(void** ppobj) { IAVIStreamImpl *This; HRESULT hr; *ppobj = NULL; This = (IAVIStreamImpl*)HeapAlloc(AVIFILE_data.hHeap,HEAP_ZERO_MEMORY, sizeof(IAVIStreamImpl)); This->ref = 1; ICOM_VTBL(This) = &iavist; hr = IAVIStream_Construct( This ); if ( hr != S_OK ) { IAVIStream_Destruct( This ); return hr; } *ppobj = (LPVOID)This; return S_OK; } /**************************************************************************** * IUnknown interface */ static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj) { ICOM_THIS(IAVIStreamImpl,iface); TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(refiid),obj); if ( IsEqualGUID(&IID_IUnknown,refiid) || IsEqualGUID(&IID_IAVIStream,refiid) ) { IAVIStream_AddRef(iface); *obj = iface; return S_OK; } /* can return IGetFrame interface too */ return OLE_E_ENUM_NOMORE; } static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream*iface) { ICOM_THIS(IAVIStreamImpl,iface); TRACE("(%p)->AddRef()\n",iface); return ++(This->ref); } static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface) { ICOM_THIS(IAVIStreamImpl,iface); TRACE("(%p)->Release()\n",iface); if ((--(This->ref)) > 0 ) return This->ref; IAVIStream_Destruct(This); HeapFree(AVIFILE_data.hHeap,0,iface); return 0; } /**************************************************************************** * IAVIStream interface */ static HRESULT IAVIStream_Construct( IAVIStreamImpl* This ) { This->paf = NULL; This->pData = NULL; AVIFILE_data.dwClassObjRef ++; return S_OK; } static void IAVIStream_Destruct( IAVIStreamImpl* This ) { AVIFILE_data.dwClassObjRef --; } static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2) { ICOM_THIS(IAVIStreamImpl,iface); FIXME("(%p)->Create(%ld,%ld)\n",iface,lParam1,lParam2); This->paf = (IAVIFile*)lParam1; This->pData = (WINE_AVISTREAM_DATA*)lParam2; return S_OK; } static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size) { ICOM_THIS(IAVIStreamImpl,iface); AVISTREAMINFOW siw; FIXME("(%p)->Info(%p,%ld)\n",iface,psi,size); if ( This->pData == NULL ) return E_UNEXPECTED; memset( &siw, 0, sizeof(AVISTREAMINFOW) ); siw.fccType = This->pData->pstrhdr->fccType; siw.fccHandler = This->pData->pstrhdr->fccHandler; siw.dwFlags = This->pData->pstrhdr->dwFlags; siw.dwCaps = 0; /* FIXME */ siw.wPriority = This->pData->pstrhdr->wPriority; siw.wLanguage = This->pData->pstrhdr->wLanguage; siw.dwScale = This->pData->pstrhdr->dwScale; siw.dwRate = This->pData->pstrhdr->dwRate; siw.dwStart = This->pData->pstrhdr->dwStart; siw.dwLength = This->pData->pstrhdr->dwLength; siw.dwInitialFrames = This->pData->pstrhdr->dwInitialFrames; siw.dwSuggestedBufferSize = This->pData->pstrhdr->dwSuggestedBufferSize; siw.dwQuality = This->pData->pstrhdr->dwQuality; siw.dwSampleSize = This->pData->pstrhdr->dwSampleSize; siw.rcFrame.left = This->pData->pstrhdr->rcFrame.left; siw.rcFrame.top = This->pData->pstrhdr->rcFrame.top; siw.rcFrame.right = This->pData->pstrhdr->rcFrame.right; siw.rcFrame.bottom = This->pData->pstrhdr->rcFrame.bottom; siw.dwEditCount = 0; /* FIXME */ siw.dwFormatChangeCount = 0; /* FIXME */ /* siw.szName[64] */ if ( size > sizeof(AVISTREAMINFOW) ) size = sizeof(AVISTREAMINFOW); memcpy( psi, &siw, size ); return S_OK; } static LONG WINAPI IAVIStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags) { ICOM_THIS(IAVIStreamImpl,iface); HRESULT hr; AVIINDEXENTRY* pIndexEntry; DWORD dwCountOfIndexEntry; LONG lCur, lAdd, lEnd; FIXME("(%p)->FindSample(%ld,0x%08lx)\n",This,pos,flags); hr = AVIFILE_IAVIFile_GetIndexTable( This->paf, This->pData->dwStreamIndex, &pIndexEntry, &dwCountOfIndexEntry ); if ( hr != S_OK ) return -1L; if ( flags & (~(FIND_DIR|FIND_TYPE|FIND_RET)) ) { FIXME( "unknown flag %08lx\n", flags ); return -1L; } switch ( flags & FIND_DIR ) { case FIND_NEXT: lCur = pos; lAdd = 1; lEnd = dwCountOfIndexEntry; if ( lCur > dwCountOfIndexEntry ) return -1L; break; case FIND_PREV: lCur = pos; if ( lCur > dwCountOfIndexEntry ) lCur = dwCountOfIndexEntry; lAdd = -1; lEnd = 0; break; case FIND_FROM_START: lCur = 0; lAdd = 1; lEnd = dwCountOfIndexEntry; break; default: FIXME( "unknown direction flag %08lx\n", (flags & FIND_DIR) ); return -1L; } switch ( flags & FIND_TYPE ) { case FIND_KEY: while ( 1 ) { if ( pIndexEntry[lCur].dwFlags & AVIIF_KEYFRAME ) break; if ( lCur == lEnd ) return -1L; lCur += lAdd; } break; case FIND_ANY: while ( 1 ) { if ( !(pIndexEntry[lCur].dwFlags & AVIIF_NOTIME) ) break; if ( lCur == lEnd ) return -1L; lCur += lAdd; } break; case FIND_FORMAT: FIXME( "FIND_FORMAT is not implemented.\n" ); return -1L; default: FIXME( "unknown type flag %08lx\n", (flags & FIND_TYPE) ); return -1L; } switch ( flags & FIND_RET ) { case FIND_POS: return lCur; case FIND_LENGTH: FIXME( "FIND_LENGTH is not implemented.\n" ); return -1L; case FIND_OFFSET: return pIndexEntry[lCur].dwChunkOffset; case FIND_SIZE: return pIndexEntry[lCur].dwChunkLength; case FIND_INDEX: FIXME( "FIND_INDEX is not implemented.\n" ); return -1L; default: FIXME( "unknown return type flag %08lx\n", (flags & FIND_RET) ); break; } return -1L; } static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize) { ICOM_THIS(IAVIStreamImpl,iface); TRACE("(%p)->ReadFormat(%ld,%p,%p)\n",This,pos,format,formatsize); if ( This->pData == NULL ) return E_UNEXPECTED; /* FIXME - check pos. */ if ( format == NULL ) { *formatsize = This->pData->dwFmtLen; return S_OK; } if ( (*formatsize) < This->pData->dwFmtLen ) return AVIERR_BUFFERTOOSMALL; memcpy( format, This->pData->pbFmt, This->pData->dwFmtLen ); *formatsize = This->pData->dwFmtLen; return S_OK; } static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize) { ICOM_THIS(IAVIStreamImpl,iface); FIXME("(%p)->SetFormat(%ld,%p,%ld)\n",This,pos,format,formatsize); return E_FAIL; } static HRESULT WINAPI IAVIStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread) { ICOM_THIS(IAVIStreamImpl,iface); HRESULT hr; AVIINDEXENTRY* pIndexEntry; DWORD dwCountOfIndexEntry; DWORD dwFrameLength; FIXME("(%p)->Read(%ld,%ld,%p,%ld,%p,%p)\n",This,start,samples,buffer,buffersize,bytesread,samplesread); *bytesread = 0; *samplesread = 0; hr = AVIFILE_IAVIFile_GetIndexTable( This->paf, This->pData->dwStreamIndex, &pIndexEntry, &dwCountOfIndexEntry ); if ( hr != S_OK ) return hr; if ( start < 0 ) return E_FAIL; if ( start >= dwCountOfIndexEntry || samples <= 0 ) { FIXME("start %ld,samples %ld,total %ld\n",start,samples,dwCountOfIndexEntry); return S_OK; } /* FIXME - no audio support. */ dwFrameLength = pIndexEntry[start].dwChunkLength; if ( buffer == NULL ) { *bytesread = dwFrameLength; *samplesread = 1; return S_OK; } if ( buffersize < dwFrameLength ) { FIXME( "buffer is too small!\n" ); return AVIERR_BUFFERTOOSMALL; } hr = AVIFILE_IAVIFile_ReadMovieData( This->paf, pIndexEntry[start].dwChunkOffset + sizeof(DWORD)*2, dwFrameLength, buffer ); if ( hr != S_OK ) { FIXME( "ReadMovieData failed!\n"); return hr; } *bytesread = dwFrameLength; *samplesread = 1; return S_OK; } static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten) { ICOM_THIS(IAVIStreamImpl,iface); FIXME("(%p)->Write(%ld,%ld,%p,%ld,0x%08lx,%p,%p)\n",This,start,samples,buffer,buffersize,flags,sampwritten,byteswritten); return E_FAIL; } static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples) { ICOM_THIS(IAVIStreamImpl,iface); FIXME("(%p)->Delete(%ld,%ld)\n",This,start,samples); return E_FAIL; } static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread) { ICOM_THIS(IAVIStreamImpl,iface); FIXME("(%p)->ReadData(0x%08lx,%p,%p)\n",This,fcc,lp,lpread); return E_FAIL; } static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size) { ICOM_THIS(IAVIStreamImpl,iface); FIXME("(%p)->WriteData(0x%08lx,%p,%ld)\n",This,fcc,lp,size); return E_FAIL; } static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen) { ICOM_THIS(IAVIStreamImpl,iface); FIXME("(%p)->SetInfo(%p,%ld)\n",This,info,infolen); return E_FAIL; }