--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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
+ */
+
+#define COM_NO_WINDOWS_H
+#include <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "windowsx.h"
+#include "mmsystem.h"
+#include "vfw.h"
+#include "msacm.h"
+
+#include "avifile_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+/***********************************************************************/
+
+static HRESULT WINAPI ACMStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj);
+static ULONG WINAPI ACMStream_fnAddRef(IAVIStream*iface);
+static ULONG WINAPI ACMStream_fnRelease(IAVIStream* iface);
+static HRESULT WINAPI ACMStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
+static HRESULT WINAPI ACMStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
+static LONG WINAPI ACMStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags);
+static HRESULT WINAPI ACMStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize);
+static HRESULT WINAPI ACMStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
+static HRESULT WINAPI ACMStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread);
+static HRESULT WINAPI ACMStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten);
+static HRESULT WINAPI ACMStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
+static HRESULT WINAPI ACMStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread);
+static HRESULT WINAPI ACMStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size);
+static HRESULT WINAPI ACMStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
+
+static const struct IAVIStreamVtbl iacmst = {
+ ACMStream_fnQueryInterface,
+ ACMStream_fnAddRef,
+ ACMStream_fnRelease,
+ ACMStream_fnCreate,
+ ACMStream_fnInfo,
+ ACMStream_fnFindSample,
+ ACMStream_fnReadFormat,
+ ACMStream_fnSetFormat,
+ ACMStream_fnRead,
+ ACMStream_fnWrite,
+ ACMStream_fnDelete,
+ ACMStream_fnReadData,
+ ACMStream_fnWriteData,
+ ACMStream_fnSetInfo
+};
+
+typedef struct _IAVIStreamImpl {
+ /* IUnknown stuff */
+ const IAVIStreamVtbl *lpVtbl;
+ LONG ref;
+
+ /* IAVIStream stuff */
+ PAVISTREAM pStream;
+ AVISTREAMINFOW sInfo;
+
+ HACMSTREAM has;
+
+ LPWAVEFORMATEX lpInFormat;
+ LONG cbInFormat;
+
+ LPWAVEFORMATEX lpOutFormat;
+ LONG cbOutFormat;
+
+ ACMSTREAMHEADER acmStreamHdr;
+} IAVIStreamImpl;
+
+/***********************************************************************/
+
+#define CONVERT_STREAM_to_THIS(a) do { \
+ DWORD __bytes; \
+ acmStreamSize(This->has,*(a) * This->lpInFormat->nBlockAlign,\
+ &__bytes, ACM_STREAMSIZEF_SOURCE); \
+ *(a) = __bytes / This->lpOutFormat->nBlockAlign; } while(0)
+
+#define CONVERT_THIS_to_STREAM(a) do { \
+ DWORD __bytes; \
+ acmStreamSize(This->has,*(a) * This->lpOutFormat->nBlockAlign,\
+ &__bytes, ACM_STREAMSIZEF_DESTINATION); \
+ *(a) = __bytes / This->lpInFormat->nBlockAlign; } while(0)
+
+static HRESULT AVIFILE_OpenCompressor(IAVIStreamImpl *This);
+
+HRESULT AVIFILE_CreateACMStream(REFIID riid, LPVOID *ppv)
+{
+ IAVIStreamImpl *pstream;
+ HRESULT hr;
+
+ assert(riid != NULL && ppv != NULL);
+
+ *ppv = NULL;
+
+ pstream = (IAVIStreamImpl*)LocalAlloc(LPTR, sizeof(IAVIStreamImpl));
+ if (pstream == NULL)
+ return AVIERR_MEMORY;
+
+ pstream->lpVtbl = &iacmst;
+
+ hr = IAVIStream_QueryInterface((IAVIStream*)pstream, riid, ppv);
+ if (FAILED(hr))
+ LocalFree((HLOCAL)pstream);
+
+ return hr;
+}
+
+static HRESULT WINAPI ACMStream_fnQueryInterface(IAVIStream *iface,
+ REFIID refiid, LPVOID *obj)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%s,%p)\n", iface, debugstr_guid(refiid), obj);
+
+ if (IsEqualGUID(&IID_IUnknown, refiid) ||
+ IsEqualGUID(&IID_IAVIStream, refiid)) {
+ *obj = This;
+ IAVIStream_AddRef(iface);
+
+ return S_OK;
+ }
+
+ return OLE_E_ENUM_NOMORE;
+}
+
+static ULONG WINAPI ACMStream_fnAddRef(IAVIStream *iface)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ /* also add reference to the nested stream */
+ if (This->pStream != NULL)
+ IAVIStream_AddRef(This->pStream);
+
+ return ref;
+}
+
+static ULONG WINAPI ACMStream_fnRelease(IAVIStream* iface)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ if (ref == 0) {
+ /* destruct */
+ if (This->has != NULL) {
+ if (This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)
+ acmStreamUnprepareHeader(This->has, &This->acmStreamHdr, 0);
+ acmStreamClose(This->has, 0);
+ This->has = NULL;
+ }
+ if (This->acmStreamHdr.pbSrc != NULL) {
+ GlobalFreePtr(This->acmStreamHdr.pbSrc);
+ This->acmStreamHdr.pbSrc = NULL;
+ }
+ if (This->acmStreamHdr.pbDst != NULL) {
+ GlobalFreePtr(This->acmStreamHdr.pbDst);
+ This->acmStreamHdr.pbDst = NULL;
+ }
+ if (This->lpInFormat != NULL) {
+ GlobalFreePtr(This->lpInFormat);
+ This->lpInFormat = NULL;
+ This->cbInFormat = 0;
+ }
+ if (This->lpOutFormat != NULL) {
+ GlobalFreePtr(This->lpOutFormat);
+ This->lpOutFormat = NULL;
+ This->cbOutFormat = 0;
+ }
+ if (This->pStream != NULL) {
+ IAVIStream_Release(This->pStream);
+ This->pStream = NULL;
+ }
+ LocalFree((HLOCAL)This);
+
+ return 0;
+ }
+
+ /* also release reference to the nested stream */
+ if (This->pStream != NULL)
+ IAVIStream_Release(This->pStream);
+
+ return ref;
+}
+
+/* lParam1: PAVISTREAM
+ * lParam2: LPAVICOMPRESSOPTIONS -- even if doc's say LPWAVEFORMAT
+ */
+static HRESULT WINAPI ACMStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
+ LPARAM lParam2)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
+
+ /* check for swapped parameters */
+ if ((LPVOID)lParam1 != NULL &&
+ ((LPAVICOMPRESSOPTIONS)lParam1)->fccType == streamtypeAUDIO) {
+ register LPARAM tmp = lParam1;
+
+ lParam1 = lParam2;
+ lParam2 = tmp;
+ }
+
+ if ((LPVOID)lParam1 == NULL)
+ return AVIERR_BADPARAM;
+
+ IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
+ if (This->sInfo.fccType != streamtypeAUDIO)
+ return AVIERR_ERROR; /* error in registry or AVIMakeCompressedStream */
+
+ This->sInfo.fccHandler = 0; /* be paranoid */
+
+ /* FIXME: check ACM version? Which version does we need? */
+
+ if ((LPVOID)lParam2 != NULL) {
+ /* We only need the format from the compress-options */
+ if (((LPAVICOMPRESSOPTIONS)lParam2)->fccType == streamtypeAUDIO)
+ lParam2 = (LPARAM)((LPAVICOMPRESSOPTIONS)lParam2)->lpFormat;
+
+ if (((LPWAVEFORMATEX)lParam2)->wFormatTag != WAVE_FORMAT_PCM)
+ This->cbOutFormat = sizeof(WAVEFORMATEX) + ((LPWAVEFORMATEX)lParam2)->cbSize;
+ else
+ This->cbOutFormat = sizeof(PCMWAVEFORMAT);
+
+ This->lpOutFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, This->cbOutFormat);
+ if (This->lpOutFormat == NULL)
+ return AVIERR_MEMORY;
+
+ memcpy(This->lpOutFormat, (LPVOID)lParam2, This->cbOutFormat);
+ } else {
+ This->lpOutFormat = NULL;
+ This->cbOutFormat = 0;
+ }
+
+ This->pStream = (PAVISTREAM)lParam1;
+ IAVIStream_AddRef(This->pStream);
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI ACMStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
+ LONG size)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%p,%ld)\n", iface, psi, size);
+
+ if (psi == NULL)
+ return AVIERR_BADPARAM;
+ if (size < 0)
+ return AVIERR_BADSIZE;
+
+ /* Need codec to correct some values in structure */
+ if (This->has == NULL) {
+ HRESULT hr = AVIFILE_OpenCompressor(This);
+
+ if (FAILED(hr))
+ return hr;
+ }
+
+ memcpy(psi, &This->sInfo, min(size, (LONG)sizeof(This->sInfo)));
+
+ if (size < (LONG)sizeof(This->sInfo))
+ return AVIERR_BUFFERTOOSMALL;
+ return AVIERR_OK;
+}
+
+static LONG WINAPI ACMStream_fnFindSample(IAVIStream *iface, LONG pos,
+ LONG flags)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
+
+ if (flags & FIND_FROM_START) {
+ pos = This->sInfo.dwStart;
+ flags &= ~(FIND_FROM_START|FIND_PREV);
+ flags |= FIND_NEXT;
+ }
+
+ /* convert pos from our 'space' to This->pStream's one */
+ CONVERT_THIS_to_STREAM(&pos);
+
+ /* ask stream */
+ pos = IAVIStream_FindSample(This->pStream, pos, flags);
+
+ if (pos != -1) {
+ /* convert pos back to our 'space' if it's no size or physical pos */
+ if ((flags & FIND_RET) == 0)
+ CONVERT_STREAM_to_THIS(&pos);
+ }
+
+ return pos;
+}
+
+static HRESULT WINAPI ACMStream_fnReadFormat(IAVIStream *iface, LONG pos,
+ LPVOID format, LONG *formatsize)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%ld,%p,%p)\n", iface, pos, format, formatsize);
+
+ if (formatsize == NULL)
+ return AVIERR_BADPARAM;
+
+ if (This->has == NULL) {
+ HRESULT hr = AVIFILE_OpenCompressor(This);
+
+ if (FAILED(hr))
+ return hr;
+ }
+
+ /* only interested in needed buffersize? */
+ if (format == NULL || *formatsize <= 0) {
+ *formatsize = This->cbOutFormat;
+
+ return AVIERR_OK;
+ }
+
+ /* copy initial format (only as much as will fit) */
+ memcpy(format, This->lpOutFormat, min(*formatsize, This->cbOutFormat));
+ if (*formatsize < This->cbOutFormat) {
+ *formatsize = This->cbOutFormat;
+ return AVIERR_BUFFERTOOSMALL;
+ }
+
+ *formatsize = This->cbOutFormat;
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI ACMStream_fnSetFormat(IAVIStream *iface, LONG pos,
+ LPVOID format, LONG formatsize)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ HRESULT hr;
+
+ TRACE("(%p,%ld,%p,%ld)\n", iface, pos, format, formatsize);
+
+ /* check parameters */
+ if (format == NULL || formatsize <= 0)
+ return AVIERR_BADPARAM;
+
+ /* Input format already known?
+ * Changing is unsupported, but be quiet if it's the same */
+ if (This->lpInFormat != NULL) {
+ if (This->cbInFormat != formatsize ||
+ memcmp(format, This->lpInFormat, formatsize) != 0)
+ return AVIERR_UNSUPPORTED;
+
+ return AVIERR_OK;
+ }
+
+ /* Does the nested stream support writing? */
+ if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
+ return AVIERR_READONLY;
+
+ This->lpInFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GMEM_MOVEABLE, formatsize);
+ if (This->lpInFormat == NULL)
+ return AVIERR_MEMORY;
+ This->cbInFormat = formatsize;
+ memcpy(This->lpInFormat, format, formatsize);
+
+ /* initialize formats and get compressor */
+ hr = AVIFILE_OpenCompressor(This);
+ if (FAILED(hr))
+ return hr;
+
+ CONVERT_THIS_to_STREAM(&pos);
+
+ /* tell the nested stream the new format */
+ return IAVIStream_SetFormat(This->pStream, pos, This->lpOutFormat,
+ This->cbOutFormat);
+}
+
+static HRESULT WINAPI ACMStream_fnRead(IAVIStream *iface, LONG start,
+ LONG samples, LPVOID buffer,
+ LONG buffersize, LPLONG bytesread,
+ LPLONG samplesread)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ HRESULT hr;
+ DWORD size;
+
+ TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface, start, samples, buffer,
+ buffersize, bytesread, samplesread);
+
+ /* clear return parameters if given */
+ if (bytesread != NULL)
+ *bytesread = 0;
+ if (samplesread != NULL)
+ *samplesread = 0;
+
+ /* Do we have our compressor? */
+ if (This->has == NULL) {
+ hr = AVIFILE_OpenCompressor(This);
+
+ if (FAILED(hr))
+ return hr;
+ }
+
+ /* only need to pass through? */
+ if (This->cbInFormat == This->cbOutFormat &&
+ memcmp(This->lpInFormat, This->lpOutFormat, This->cbInFormat) == 0) {
+ return IAVIStream_Read(This->pStream, start, samples, buffer, buffersize,
+ bytesread, samplesread);
+ }
+
+ /* read as much as fit? */
+ if (samples == -1)
+ samples = buffersize / This->lpOutFormat->nBlockAlign;
+ /* limit to buffersize */
+ if (samples * This->lpOutFormat->nBlockAlign > buffersize)
+ samples = buffersize / This->lpOutFormat->nBlockAlign;
+
+ /* only return needed size? */
+ if (buffer == NULL || buffersize <= 0 || samples == 0) {
+ if (bytesread == NULL && samplesread == NULL)
+ return AVIERR_BADPARAM;
+
+ if (bytesread != NULL)
+ *bytesread = samples * This->lpOutFormat->nBlockAlign;
+ if (samplesread != NULL)
+ *samplesread = samples;
+
+ return AVIERR_OK;
+ }
+
+ /* map our positions to pStream positions */
+ CONVERT_THIS_to_STREAM(&start);
+
+ /* our needed internal buffersize */
+ size = samples * This->lpInFormat->nBlockAlign;
+
+ /* Need to free destination buffer used for writing? */
+ if (This->acmStreamHdr.pbDst != NULL) {
+ GlobalFreePtr(This->acmStreamHdr.pbDst);
+ This->acmStreamHdr.pbDst = NULL;
+ This->acmStreamHdr.dwDstUser = 0;
+ }
+
+ /* need bigger source buffer? */
+ if (This->acmStreamHdr.pbSrc == NULL ||
+ This->acmStreamHdr.dwSrcUser < size) {
+ if (This->acmStreamHdr.pbSrc == NULL)
+ This->acmStreamHdr.pbSrc = GlobalAllocPtr(GMEM_MOVEABLE, size);
+ else
+ This->acmStreamHdr.pbSrc = GlobalReAllocPtr(This->acmStreamHdr.pbSrc,
+ size, GMEM_MOVEABLE);
+ if (This->acmStreamHdr.pbSrc == NULL)
+ return AVIERR_MEMORY;
+ This->acmStreamHdr.dwSrcUser = size;
+ }
+
+ This->acmStreamHdr.cbStruct = sizeof(This->acmStreamHdr);
+ This->acmStreamHdr.cbSrcLengthUsed = 0;
+ This->acmStreamHdr.cbDstLengthUsed = 0;
+ This->acmStreamHdr.cbSrcLength = size;
+
+ /* read source data */
+ hr = IAVIStream_Read(This->pStream, start, -1, This->acmStreamHdr.pbSrc,
+ This->acmStreamHdr.cbSrcLength,
+ (LONG *)&This->acmStreamHdr.cbSrcLength, NULL);
+ if (FAILED(hr) || This->acmStreamHdr.cbSrcLength == 0)
+ return hr;
+
+ /* need to prepare stream? */
+ This->acmStreamHdr.pbDst = buffer;
+ This->acmStreamHdr.cbDstLength = buffersize;
+ if ((This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) == 0) {
+ if (acmStreamPrepareHeader(This->has, &This->acmStreamHdr, 0) != S_OK) {
+ This->acmStreamHdr.pbDst = NULL;
+ This->acmStreamHdr.cbDstLength = 0;
+ return AVIERR_COMPRESSOR;
+ }
+ }
+
+ /* now do the conversion */
+ /* FIXME: use ACM_CONVERTF_* flags */
+ if (acmStreamConvert(This->has, &This->acmStreamHdr, 0) != S_OK)
+ hr = AVIERR_COMPRESSOR;
+
+ This->acmStreamHdr.pbDst = NULL;
+ This->acmStreamHdr.cbDstLength = 0;
+
+ /* fill out return parameters if given */
+ if (bytesread != NULL)
+ *bytesread = This->acmStreamHdr.cbDstLengthUsed;
+ if (samplesread != NULL)
+ *samplesread =
+ This->acmStreamHdr.cbDstLengthUsed / This->lpOutFormat->nBlockAlign;
+
+ return hr;
+}
+
+static HRESULT WINAPI ACMStream_fnWrite(IAVIStream *iface, LONG start,
+ LONG samples, LPVOID buffer,
+ LONG buffersize, DWORD flags,
+ LPLONG sampwritten,
+ LPLONG byteswritten)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ HRESULT hr;
+ ULONG size;
+
+ TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface, start, samples,
+ buffer, buffersize, flags, sampwritten, byteswritten);
+
+ /* clear return parameters if given */
+ if (sampwritten != NULL)
+ *sampwritten = 0;
+ if (byteswritten != NULL)
+ *byteswritten = 0;
+
+ /* check parameters */
+ if (buffer == NULL && (buffersize > 0 || samples > 0))
+ return AVIERR_BADPARAM;
+
+ /* Have we write capability? */
+ if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
+ return AVIERR_READONLY;
+
+ /* also need a compressor */
+ if (This->has == NULL)
+ return AVIERR_NOCOMPRESSOR;
+
+ /* map our sizes to pStream sizes */
+ size = buffersize;
+ CONVERT_THIS_to_STREAM(&size);
+ CONVERT_THIS_to_STREAM(&start);
+
+ /* no bytes to write? -- short circuit */
+ if (size == 0) {
+ return IAVIStream_Write(This->pStream, -1, samples, buffer, size,
+ flags, sampwritten, byteswritten);
+ }
+
+ /* Need to free source buffer used for reading? */
+ if (This->acmStreamHdr.pbSrc != NULL) {
+ GlobalFreePtr(This->acmStreamHdr.pbSrc);
+ This->acmStreamHdr.pbSrc = NULL;
+ This->acmStreamHdr.dwSrcUser = 0;
+ }
+
+ /* Need bigger destination buffer? */
+ if (This->acmStreamHdr.pbDst == NULL ||
+ This->acmStreamHdr.dwDstUser < size) {
+ if (This->acmStreamHdr.pbDst == NULL)
+ This->acmStreamHdr.pbDst = GlobalAllocPtr(GMEM_MOVEABLE, size);
+ else
+ This->acmStreamHdr.pbDst = GlobalReAllocPtr(This->acmStreamHdr.pbDst,
+ size, GMEM_MOVEABLE);
+ if (This->acmStreamHdr.pbDst == NULL)
+ return AVIERR_MEMORY;
+ This->acmStreamHdr.dwDstUser = size;
+ }
+ This->acmStreamHdr.cbStruct = sizeof(This->acmStreamHdr);
+ This->acmStreamHdr.cbSrcLengthUsed = 0;
+ This->acmStreamHdr.cbDstLengthUsed = 0;
+ This->acmStreamHdr.cbDstLength = This->acmStreamHdr.dwDstUser;
+
+ /* need to prepare stream? */
+ This->acmStreamHdr.pbSrc = buffer;
+ This->acmStreamHdr.cbSrcLength = buffersize;
+ if ((This->acmStreamHdr.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED) == 0) {
+ if (acmStreamPrepareHeader(This->has, &This->acmStreamHdr, 0) != S_OK) {
+ This->acmStreamHdr.pbSrc = NULL;
+ This->acmStreamHdr.cbSrcLength = 0;
+ return AVIERR_COMPRESSOR;
+ }
+ }
+
+ /* now do the conversion */
+ /* FIXME: use ACM_CONVERTF_* flags */
+ if (acmStreamConvert(This->has, &This->acmStreamHdr, 0) != S_OK)
+ hr = AVIERR_COMPRESSOR;
+ else
+ hr = AVIERR_OK;
+
+ This->acmStreamHdr.pbSrc = NULL;
+ This->acmStreamHdr.cbSrcLength = 0;
+
+ if (FAILED(hr))
+ return hr;
+
+ return IAVIStream_Write(This->pStream,-1,This->acmStreamHdr.cbDstLengthUsed /
+ This->lpOutFormat->nBlockAlign,This->acmStreamHdr.pbDst,
+ This->acmStreamHdr.cbDstLengthUsed,flags,sampwritten,
+ byteswritten);
+}
+
+static HRESULT WINAPI ACMStream_fnDelete(IAVIStream *iface, LONG start,
+ LONG samples)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%ld,%ld)\n", iface, start, samples);
+
+ /* check parameters */
+ if (start < 0 || samples < 0)
+ return AVIERR_BADPARAM;
+
+ /* Delete before start of stream? */
+ if ((DWORD)(start + samples) < This->sInfo.dwStart)
+ return AVIERR_OK;
+
+ /* Delete after end of stream? */
+ if ((DWORD)start > This->sInfo.dwLength)
+ return AVIERR_OK;
+
+ /* For the rest we need write capability */
+ if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
+ return AVIERR_READONLY;
+
+ /* A compressor is also necessary */
+ if (This->has == NULL)
+ return AVIERR_NOCOMPRESSOR;
+
+ /* map our positions to pStream positions */
+ CONVERT_THIS_to_STREAM(&start);
+ CONVERT_THIS_to_STREAM(&samples);
+
+ return IAVIStream_Delete(This->pStream, start, samples);
+}
+
+static HRESULT WINAPI ACMStream_fnReadData(IAVIStream *iface, DWORD fcc,
+ LPVOID lp, LPLONG lpread)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,0x%08lX,%p,%p)\n", iface, fcc, lp, lpread);
+
+ assert(This->pStream != NULL);
+
+ return IAVIStream_ReadData(This->pStream, fcc, lp, lpread);
+}
+
+static HRESULT WINAPI ACMStream_fnWriteData(IAVIStream *iface, DWORD fcc,
+ LPVOID lp, LONG size)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,0x%08lx,%p,%ld)\n", iface, fcc, lp, size);
+
+ assert(This->pStream != NULL);
+
+ return IAVIStream_WriteData(This->pStream, fcc, lp, size);
+}
+
+static HRESULT WINAPI ACMStream_fnSetInfo(IAVIStream *iface,
+ LPAVISTREAMINFOW info, LONG infolen)
+{
+ FIXME("(%p,%p,%ld): stub\n", iface, info, infolen);
+
+ return E_FAIL;
+}
+
+/***********************************************************************/
+
+static HRESULT AVIFILE_OpenCompressor(IAVIStreamImpl *This)
+{
+ HRESULT hr;
+
+ /* pre-conditions */
+ assert(This != NULL);
+ assert(This->pStream != NULL);
+
+ if (This->has != NULL)
+ return AVIERR_OK;
+
+ if (This->lpInFormat == NULL) {
+ /* decode or encode the data from pStream */
+ hr = AVIStreamFormatSize(This->pStream, This->sInfo.dwStart, &This->cbInFormat);
+ if (FAILED(hr))
+ return hr;
+ This->lpInFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GMEM_MOVEABLE, This->cbInFormat);
+ if (This->lpInFormat == NULL)
+ return AVIERR_MEMORY;
+
+ hr = IAVIStream_ReadFormat(This->pStream, This->sInfo.dwStart,
+ This->lpInFormat, &This->cbInFormat);
+ if (FAILED(hr))
+ return hr;
+
+ if (This->lpOutFormat == NULL) {
+ /* we must decode to default format */
+ This->cbOutFormat = sizeof(PCMWAVEFORMAT);
+ This->lpOutFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, This->cbOutFormat);
+ if (This->lpOutFormat == NULL)
+ return AVIERR_MEMORY;
+
+ This->lpOutFormat->wFormatTag = WAVE_FORMAT_PCM;
+ if (acmFormatSuggest(NULL, This->lpInFormat, This->lpOutFormat,
+ This->cbOutFormat, ACM_FORMATSUGGESTF_WFORMATTAG) != S_OK)
+ return AVIERR_NOCOMPRESSOR;
+ }
+ } else if (This->lpOutFormat == NULL)
+ return AVIERR_ERROR; /* To what should I encode? */
+
+ if (acmStreamOpen(&This->has, NULL, This->lpInFormat, This->lpOutFormat,
+ NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME) != S_OK)
+ return AVIERR_NOCOMPRESSOR;
+
+ /* update AVISTREAMINFO structure */
+ This->sInfo.dwSampleSize = This->lpOutFormat->nBlockAlign;
+ This->sInfo.dwScale = This->lpOutFormat->nBlockAlign;
+ This->sInfo.dwRate = This->lpOutFormat->nAvgBytesPerSec;
+ This->sInfo.dwQuality = (DWORD)ICQUALITY_DEFAULT;
+ SetRectEmpty(&This->sInfo.rcFrame);
+
+ /* convert positions ansd sizes to output format */
+ CONVERT_STREAM_to_THIS(&This->sInfo.dwStart);
+ CONVERT_STREAM_to_THIS(&This->sInfo.dwLength);
+ CONVERT_STREAM_to_THIS(&This->sInfo.dwSuggestedBufferSize);
+
+ return AVIERR_OK;
+}
--- /dev/null
+/*
+ * Copyright 1999 Marcus Meissner
+ * Copyright 2002-2003 Michael Günnewig
+ *
+ * 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 <assert.h>
+#include <stdarg.h>
+
+#define COBJMACROS
+#define COM_NO_WINDOWS_H
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+#include "windowsx.h"
+
+#include "ole2.h"
+#include "shellapi.h"
+#include "shlobj.h"
+#include "vfw.h"
+#include "msacm.h"
+
+#include "avifile_private.h"
+
+#include "wine/debug.h"
+#include "wine/unicode.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+
+/***********************************************************************
+ * for AVIBuildFilterW -- uses fixed size table
+ */
+#define MAX_FILTERS 30 /* 30 => 7kB */
+
+typedef struct _AVIFilter {
+ WCHAR szClsid[40];
+ WCHAR szExtensions[MAX_FILTERS * 7];
+} AVIFilter;
+
+/***********************************************************************
+ * for AVISaveOptions
+ */
+static struct {
+ UINT uFlags;
+ INT nStreams;
+ PAVISTREAM *ppavis;
+ LPAVICOMPRESSOPTIONS *ppOptions;
+ INT nCurrent;
+} SaveOpts;
+
+/***********************************************************************
+ * copied from dlls/ole32/compobj.c
+ */
+static HRESULT AVIFILE_CLSIDFromString(LPCSTR idstr, LPCLSID id)
+{
+ BYTE const *s;
+ BYTE *p;
+ INT i;
+ BYTE table[256];
+
+ if (!idstr) {
+ memset(id, 0, sizeof(CLSID));
+ return S_OK;
+ }
+
+ /* validate the CLSID string */
+ if (lstrlenA(idstr) != 38)
+ return CO_E_CLASSSTRING;
+
+ s = (BYTE const*)idstr;
+ if ((s[0]!='{') || (s[9]!='-') || (s[14]!='-') || (s[19]!='-') ||
+ (s[24]!='-') || (s[37]!='}'))
+ return CO_E_CLASSSTRING;
+
+ for (i = 1; i < 37; i++) {
+ if ((i == 9) || (i == 14) || (i == 19) || (i == 24))
+ continue;
+ if (!(((s[i] >= '0') && (s[i] <= '9')) ||
+ ((s[i] >= 'a') && (s[i] <= 'f')) ||
+ ((s[i] >= 'A') && (s[i] <= 'F')))
+ )
+ return CO_E_CLASSSTRING;
+ }
+
+ TRACE("%s -> %p\n", s, id);
+
+ /* quick lookup table */
+ memset(table, 0, 256);
+
+ for (i = 0; i < 10; i++)
+ table['0' + i] = i;
+
+ for (i = 0; i < 6; i++) {
+ table['A' + i] = i+10;
+ table['a' + i] = i+10;
+ }
+
+ /* in form {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} */
+ p = (BYTE *) id;
+
+ s++; /* skip leading brace */
+ for (i = 0; i < 4; i++) {
+ p[3 - i] = table[*s]<<4 | table[*(s+1)];
+ s += 2;
+ }
+ p += 4;
+ s++; /* skip - */
+
+ for (i = 0; i < 2; i++) {
+ p[1-i] = table[*s]<<4 | table[*(s+1)];
+ s += 2;
+ }
+ p += 2;
+ s++; /* skip - */
+
+ for (i = 0; i < 2; i++) {
+ p[1-i] = table[*s]<<4 | table[*(s+1)];
+ s += 2;
+ }
+ p += 2;
+ s++; /* skip - */
+
+ /* these are just sequential bytes */
+ for (i = 0; i < 2; i++) {
+ *p++ = table[*s]<<4 | table[*(s+1)];
+ s += 2;
+ }
+ s++; /* skip - */
+
+ for (i = 0; i < 6; i++) {
+ *p++ = table[*s]<<4 | table[*(s+1)];
+ s += 2;
+ }
+
+ return S_OK;
+}
+
+static BOOL AVIFILE_GetFileHandlerByExtension(LPCWSTR szFile, LPCLSID lpclsid)
+{
+ CHAR szRegKey[25];
+ CHAR szValue[100];
+ LPWSTR szExt = strrchrW(szFile, '.');
+ LONG len = sizeof(szValue) / sizeof(szValue[0]);
+
+ if (szExt == NULL)
+ return FALSE;
+
+ szExt++;
+
+ wsprintfA(szRegKey, "AVIFile\\Extensions\\%.3ls", szExt);
+ if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &len) != ERROR_SUCCESS)
+ return FALSE;
+
+ return (AVIFILE_CLSIDFromString(szValue, lpclsid) == S_OK);
+}
+
+/***********************************************************************
+ * AVIFileInit (AVIFIL32.@)
+ * AVIFileInit (AVIFILE.100)
+ */
+void WINAPI AVIFileInit(void) {
+ OleInitialize(NULL);
+}
+
+/***********************************************************************
+ * AVIFileExit (AVIFIL32.@)
+ * AVIFileExit (AVIFILE.101)
+ */
+void WINAPI AVIFileExit(void) {
+ /* need to free ole32.dll if we are the last exit call */
+ /* OleUnitialize() */
+ FIXME("(): stub!\n");
+}
+
+/***********************************************************************
+ * AVIFileOpen (AVIFIL32.@)
+ * AVIFileOpenA (AVIFIL32.@)
+ * AVIFileOpen (AVIFILE.102)
+ */
+HRESULT WINAPI AVIFileOpenA(PAVIFILE *ppfile, LPCSTR szFile, UINT uMode,
+ LPCLSID lpHandler)
+{
+ LPWSTR wszFile = NULL;
+ HRESULT hr;
+ int len;
+
+ TRACE("(%p,%s,0x%08X,%s)\n", ppfile, debugstr_a(szFile), uMode,
+ debugstr_guid(lpHandler));
+
+ /* check parameters */
+ if (ppfile == NULL || szFile == NULL)
+ return AVIERR_BADPARAM;
+
+ /* convert ASCII string to Unicode and call unicode function */
+ len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
+ if (len <= 0)
+ return AVIERR_BADPARAM;
+
+ wszFile = (LPWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR));
+ if (wszFile == NULL)
+ return AVIERR_MEMORY;
+
+ MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
+
+ hr = AVIFileOpenW(ppfile, wszFile, uMode, lpHandler);
+
+ LocalFree((HLOCAL)wszFile);
+
+ return hr;
+}
+
+/***********************************************************************
+ * AVIFileOpenW (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIFileOpenW(PAVIFILE *ppfile, LPCWSTR szFile, UINT uMode,
+ LPCLSID lpHandler)
+{
+ IPersistFile *ppersist = NULL;
+ CLSID clsidHandler;
+ HRESULT hr;
+
+ TRACE("(%p,%s,0x%X,%s)\n", ppfile, debugstr_w(szFile), uMode,
+ debugstr_guid(lpHandler));
+
+ /* check parameters */
+ if (ppfile == NULL || szFile == NULL)
+ return AVIERR_BADPARAM;
+
+ *ppfile = NULL;
+
+ /* if no handler then try guessing it by extension */
+ if (lpHandler == NULL) {
+ if (! AVIFILE_GetFileHandlerByExtension(szFile, &clsidHandler))
+ return AVIERR_UNSUPPORTED;
+ } else
+ memcpy(&clsidHandler, lpHandler, sizeof(clsidHandler));
+
+ /* create instance of handler */
+ hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIFile, (LPVOID*)ppfile);
+ if (FAILED(hr) || *ppfile == NULL)
+ return hr;
+
+ /* ask for IPersistFile interface for loading/creating the file */
+ hr = IAVIFile_QueryInterface(*ppfile, &IID_IPersistFile, (LPVOID*)&ppersist);
+ if (FAILED(hr) || ppersist == NULL) {
+ IAVIFile_Release(*ppfile);
+ *ppfile = NULL;
+ return hr;
+ }
+
+ hr = IPersistFile_Load(ppersist, szFile, uMode);
+ IPersistFile_Release(ppersist);
+ if (FAILED(hr)) {
+ IAVIFile_Release(*ppfile);
+ *ppfile = NULL;
+ }
+
+ return hr;
+}
+
+/***********************************************************************
+ * AVIFileAddRef (AVIFIL32.@)
+ * AVIFileAddRef (AVIFILE.140)
+ */
+ULONG WINAPI AVIFileAddRef(PAVIFILE pfile)
+{
+ TRACE("(%p)\n", pfile);
+
+ if (pfile == NULL) {
+ ERR(": bad handle passed!\n");
+ return 0;
+ }
+
+ return IAVIFile_AddRef(pfile);
+}
+
+/***********************************************************************
+ * AVIFileRelease (AVIFIL32.@)
+ * AVIFileRelease (AVIFILE.141)
+ */
+ULONG WINAPI AVIFileRelease(PAVIFILE pfile)
+{
+ TRACE("(%p)\n", pfile);
+
+ if (pfile == NULL) {
+ ERR(": bad handle passed!\n");
+ return 0;
+ }
+
+ return IAVIFile_Release(pfile);
+}
+
+/***********************************************************************
+ * AVIFileInfo (AVIFIL32.@)
+ * AVIFileInfoA (AVIFIL32.@)
+ * AVIFileInfo (AVIFILE.142)
+ */
+HRESULT WINAPI AVIFileInfoA(PAVIFILE pfile, LPAVIFILEINFOA afi, LONG size)
+{
+ AVIFILEINFOW afiw;
+ HRESULT hres;
+
+ TRACE("(%p,%p,%ld)\n", pfile, afi, size);
+
+ if (pfile == NULL)
+ return AVIERR_BADHANDLE;
+ if ((DWORD)size < sizeof(AVIFILEINFOA))
+ return AVIERR_BADSIZE;
+
+ hres = IAVIFile_Info(pfile, &afiw, sizeof(afiw));
+
+ memcpy(afi, &afiw, sizeof(*afi) - sizeof(afi->szFileType));
+ WideCharToMultiByte(CP_ACP, 0, afiw.szFileType, -1, afi->szFileType,
+ sizeof(afi->szFileType), NULL, NULL);
+ afi->szFileType[sizeof(afi->szFileType) - 1] = 0;
+
+ return hres;
+}
+
+/***********************************************************************
+ * AVIFileInfoW (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIFileInfoW(PAVIFILE pfile, LPAVIFILEINFOW afiw, LONG size)
+{
+ TRACE("(%p,%p,%ld)\n", pfile, afiw, size);
+
+ if (pfile == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIFile_Info(pfile, afiw, size);
+}
+
+/***********************************************************************
+ * AVIFileGetStream (AVIFIL32.@)
+ * AVIFileGetStream (AVIFILE.143)
+ */
+HRESULT WINAPI AVIFileGetStream(PAVIFILE pfile, PAVISTREAM *avis,
+ DWORD fccType, LONG lParam)
+{
+ TRACE("(%p,%p,'%4.4s',%ld)\n", pfile, avis, (char*)&fccType, lParam);
+
+ if (pfile == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIFile_GetStream(pfile, avis, fccType, lParam);
+}
+
+/***********************************************************************
+ * AVIFileCreateStream (AVIFIL32.@)
+ * AVIFileCreateStreamA (AVIFIL32.@)
+ * AVIFileCreateStream (AVIFILE.144)
+ */
+HRESULT WINAPI AVIFileCreateStreamA(PAVIFILE pfile, PAVISTREAM *ppavi,
+ LPAVISTREAMINFOA psi)
+{
+ AVISTREAMINFOW psiw;
+
+ TRACE("(%p,%p,%p)\n", pfile, ppavi, psi);
+
+ if (pfile == NULL)
+ return AVIERR_BADHANDLE;
+
+ /* Only the szName at the end is different */
+ memcpy(&psiw, psi, sizeof(*psi) - sizeof(psi->szName));
+ MultiByteToWideChar(CP_ACP, 0, psi->szName, -1, psiw.szName,
+ sizeof(psiw.szName) / sizeof(psiw.szName[0]));
+
+ return IAVIFile_CreateStream(pfile, ppavi, &psiw);
+}
+
+/***********************************************************************
+ * AVIFileCreateStreamW (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIFileCreateStreamW(PAVIFILE pfile, PAVISTREAM *avis,
+ LPAVISTREAMINFOW asi)
+{
+ TRACE("(%p,%p,%p)\n", pfile, avis, asi);
+
+ if (pfile == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIFile_CreateStream(pfile, avis, asi);
+}
+
+/***********************************************************************
+ * AVIFileWriteData (AVIFIL32.@)
+ * AVIFileWriteData (AVIFILE.146)
+ */
+HRESULT WINAPI AVIFileWriteData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LONG size)
+{
+ TRACE("(%p,'%4.4s',%p,%ld)\n", pfile, (char*)&fcc, lp, size);
+
+ if (pfile == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIFile_WriteData(pfile, fcc, lp, size);
+}
+
+/***********************************************************************
+ * AVIFileReadData (AVIFIL32.@)
+ * AVIFileReadData (AVIFILE.147)
+ */
+HRESULT WINAPI AVIFileReadData(PAVIFILE pfile,DWORD fcc,LPVOID lp,LPLONG size)
+{
+ TRACE("(%p,'%4.4s',%p,%p)\n", pfile, (char*)&fcc, lp, size);
+
+ if (pfile == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIFile_ReadData(pfile, fcc, lp, size);
+}
+
+/***********************************************************************
+ * AVIFileEndRecord (AVIFIL32.@)
+ * AVIFileEndRecord (AVIFILE.148)
+ */
+HRESULT WINAPI AVIFileEndRecord(PAVIFILE pfile)
+{
+ TRACE("(%p)\n", pfile);
+
+ if (pfile == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIFile_EndRecord(pfile);
+}
+
+/***********************************************************************
+ * AVIStreamAddRef (AVIFIL32.@)
+ * AVIStreamAddRef (AVIFILE.160)
+ */
+ULONG WINAPI AVIStreamAddRef(PAVISTREAM pstream)
+{
+ TRACE("(%p)\n", pstream);
+
+ if (pstream == NULL) {
+ ERR(": bad handle passed!\n");
+ return 0;
+ }
+
+ return IAVIStream_AddRef(pstream);
+}
+
+/***********************************************************************
+ * AVIStreamRelease (AVIFIL32.@)
+ * AVIStreamRelease (AVIFILE.161)
+ */
+ULONG WINAPI AVIStreamRelease(PAVISTREAM pstream)
+{
+ TRACE("(%p)\n", pstream);
+
+ if (pstream == NULL) {
+ ERR(": bad handle passed!\n");
+ return 0;
+ }
+
+ return IAVIStream_Release(pstream);
+}
+
+/***********************************************************************
+ * AVIStreamCreate (AVIFIL32.@)
+ * AVIStreamCreate (AVIFILE.104)
+ */
+HRESULT WINAPI AVIStreamCreate(PAVISTREAM *ppavi, LONG lParam1, LONG lParam2,
+ LPCLSID pclsidHandler)
+{
+ HRESULT hr;
+
+ TRACE("(%p,0x%08lX,0x%08lX,%s)\n", ppavi, lParam1, lParam2,
+ debugstr_guid(pclsidHandler));
+
+ if (ppavi == NULL)
+ return AVIERR_BADPARAM;
+
+ *ppavi = NULL;
+ if (pclsidHandler == NULL)
+ return AVIERR_UNSUPPORTED;
+
+ hr = CoCreateInstance(pclsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppavi);
+ if (FAILED(hr) || *ppavi == NULL)
+ return hr;
+
+ hr = IAVIStream_Create(*ppavi, lParam1, lParam2);
+ if (FAILED(hr)) {
+ IAVIStream_Release(*ppavi);
+ *ppavi = NULL;
+ }
+
+ return hr;
+}
+
+/***********************************************************************
+ * AVIStreamInfo (AVIFIL32.@)
+ * AVIStreamInfoA (AVIFIL32.@)
+ * AVIStreamInfo (AVIFILE.162)
+ */
+HRESULT WINAPI AVIStreamInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
+ LONG size)
+{
+ AVISTREAMINFOW asiw;
+ HRESULT hres;
+
+ TRACE("(%p,%p,%ld)\n", pstream, asi, size);
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+ if ((DWORD)size < sizeof(AVISTREAMINFOA))
+ return AVIERR_BADSIZE;
+
+ hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
+
+ memcpy(asi, &asiw, sizeof(asiw) - sizeof(asiw.szName));
+ WideCharToMultiByte(CP_ACP, 0, asiw.szName, -1, asi->szName,
+ sizeof(asi->szName), NULL, NULL);
+ asi->szName[sizeof(asi->szName) - 1] = 0;
+
+ return hres;
+}
+
+/***********************************************************************
+ * AVIStreamInfoW (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIStreamInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
+ LONG size)
+{
+ TRACE("(%p,%p,%ld)\n", pstream, asi, size);
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIStream_Info(pstream, asi, size);
+}
+
+/***********************************************************************
+ * AVIStreamFindSample (AVIFIL32.@)
+ * AVIStreamFindSample (AVIFILE.163)
+ */
+HRESULT WINAPI AVIStreamFindSample(PAVISTREAM pstream, LONG pos, DWORD flags)
+{
+ TRACE("(%p,%ld,0x%lX)\n", pstream, pos, flags);
+
+ if (pstream == NULL)
+ return -1;
+
+ return IAVIStream_FindSample(pstream, pos, flags);
+}
+
+/***********************************************************************
+ * AVIStreamReadFormat (AVIFIL32.@)
+ * AVIStreamReadFormat (AVIFILE.164)
+ */
+HRESULT WINAPI AVIStreamReadFormat(PAVISTREAM pstream, LONG pos,
+ LPVOID format, LPLONG formatsize)
+{
+ TRACE("(%p,%ld,%p,%p)\n", pstream, pos, format, formatsize);
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIStream_ReadFormat(pstream, pos, format, formatsize);
+}
+
+/***********************************************************************
+ * AVIStreamSetFormat (AVIFIL32.@)
+ * AVIStreamSetFormat (AVIFILE.169)
+ */
+HRESULT WINAPI AVIStreamSetFormat(PAVISTREAM pstream, LONG pos,
+ LPVOID format, LONG formatsize)
+{
+ TRACE("(%p,%ld,%p,%ld)\n", pstream, pos, format, formatsize);
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIStream_SetFormat(pstream, pos, format, formatsize);
+}
+
+/***********************************************************************
+ * AVIStreamRead (AVIFIL32.@)
+ * AVIStreamRead (AVIFILE.167)
+ */
+HRESULT WINAPI AVIStreamRead(PAVISTREAM pstream, LONG start, LONG samples,
+ LPVOID buffer, LONG buffersize,
+ LPLONG bytesread, LPLONG samplesread)
+{
+ TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", pstream, start, samples, buffer,
+ buffersize, bytesread, samplesread);
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIStream_Read(pstream, start, samples, buffer, buffersize,
+ bytesread, samplesread);
+}
+
+/***********************************************************************
+ * AVIStreamWrite (AVIFIL32.@)
+ * AVIStreamWrite (AVIFILE.168)
+ */
+HRESULT WINAPI AVIStreamWrite(PAVISTREAM pstream, LONG start, LONG samples,
+ LPVOID buffer, LONG buffersize, DWORD flags,
+ LPLONG sampwritten, LPLONG byteswritten)
+{
+ TRACE("(%p,%ld,%ld,%p,%ld,0x%lX,%p,%p)\n", pstream, start, samples, buffer,
+ buffersize, flags, sampwritten, byteswritten);
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIStream_Write(pstream, start, samples, buffer, buffersize,
+ flags, sampwritten, byteswritten);
+}
+
+/***********************************************************************
+ * AVIStreamReadData (AVIFIL32.@)
+ * AVIStreamReadData (AVIFILE.165)
+ */
+HRESULT WINAPI AVIStreamReadData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
+ LPLONG lpread)
+{
+ TRACE("(%p,'%4.4s',%p,%p)\n", pstream, (char*)&fcc, lp, lpread);
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIStream_ReadData(pstream, fcc, lp, lpread);
+}
+
+/***********************************************************************
+ * AVIStreamWriteData (AVIFIL32.@)
+ * AVIStreamWriteData (AVIFILE.166)
+ */
+HRESULT WINAPI AVIStreamWriteData(PAVISTREAM pstream, DWORD fcc, LPVOID lp,
+ LONG size)
+{
+ TRACE("(%p,'%4.4s',%p,%ld)\n", pstream, (char*)&fcc, lp, size);
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+
+ return IAVIStream_WriteData(pstream, fcc, lp, size);
+}
+
+/***********************************************************************
+ * AVIStreamGetFrameOpen (AVIFIL32.@)
+ * AVIStreamGetFrameOpen (AVIFILE.112)
+ */
+PGETFRAME WINAPI AVIStreamGetFrameOpen(PAVISTREAM pstream,
+ LPBITMAPINFOHEADER lpbiWanted)
+{
+ PGETFRAME pg = NULL;
+
+ TRACE("(%p,%p)\n", pstream, lpbiWanted);
+
+ if (FAILED(IAVIStream_QueryInterface(pstream, &IID_IGetFrame, (LPVOID*)&pg)) ||
+ pg == NULL) {
+ pg = AVIFILE_CreateGetFrame(pstream);
+ if (pg == NULL)
+ return NULL;
+ }
+
+ if (FAILED(IGetFrame_SetFormat(pg, lpbiWanted, NULL, 0, 0, -1, -1))) {
+ IGetFrame_Release(pg);
+ return NULL;
+ }
+
+ return pg;
+}
+
+/***********************************************************************
+ * AVIStreamGetFrame (AVIFIL32.@)
+ * AVIStreamGetFrame (AVIFILE.110)
+ */
+LPVOID WINAPI AVIStreamGetFrame(PGETFRAME pg, LONG pos)
+{
+ TRACE("(%p,%ld)\n", pg, pos);
+
+ if (pg == NULL)
+ return NULL;
+
+ return IGetFrame_GetFrame(pg, pos);
+}
+
+/***********************************************************************
+ * AVIStreamGetFrameClose (AVIFIL32.@)
+ * AVIStreamGetFrameClose (AVIFILE.111)
+ */
+HRESULT WINAPI AVIStreamGetFrameClose(PGETFRAME pg)
+{
+ TRACE("(%p)\n", pg);
+
+ if (pg != NULL)
+ return IGetFrame_Release(pg);
+ return 0;
+}
+
+/***********************************************************************
+ * AVIMakeCompressedStream (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIMakeCompressedStream(PAVISTREAM *ppsCompressed,
+ PAVISTREAM psSource,
+ LPAVICOMPRESSOPTIONS aco,
+ LPCLSID pclsidHandler)
+{
+ AVISTREAMINFOW asiw;
+ CHAR szRegKey[25];
+ CHAR szValue[100];
+ CLSID clsidHandler;
+ HRESULT hr;
+ LONG size = sizeof(szValue);
+
+ TRACE("(%p,%p,%p,%s)\n", ppsCompressed, psSource, aco,
+ debugstr_guid(pclsidHandler));
+
+ if (ppsCompressed == NULL)
+ return AVIERR_BADPARAM;
+ if (psSource == NULL)
+ return AVIERR_BADHANDLE;
+
+ *ppsCompressed = NULL;
+
+ /* if no handler given get default ones based on streamtype */
+ if (pclsidHandler == NULL) {
+ hr = IAVIStream_Info(psSource, &asiw, sizeof(asiw));
+ if (FAILED(hr))
+ return hr;
+
+ wsprintfA(szRegKey, "AVIFile\\Compressors\\%4.4s", (char*)&asiw.fccType);
+ if (RegQueryValueA(HKEY_CLASSES_ROOT, szRegKey, szValue, &size) != ERROR_SUCCESS)
+ return AVIERR_UNSUPPORTED;
+ if (AVIFILE_CLSIDFromString(szValue, &clsidHandler) != S_OK)
+ return AVIERR_UNSUPPORTED;
+ } else
+ memcpy(&clsidHandler, pclsidHandler, sizeof(clsidHandler));
+
+ hr = CoCreateInstance(&clsidHandler, NULL, CLSCTX_INPROC, &IID_IAVIStream, (LPVOID*)ppsCompressed);
+ if (FAILED(hr) || *ppsCompressed == NULL)
+ return hr;
+
+ hr = IAVIStream_Create(*ppsCompressed, (LPARAM)psSource, (LPARAM)aco);
+ if (FAILED(hr)) {
+ IAVIStream_Release(*ppsCompressed);
+ *ppsCompressed = NULL;
+ }
+
+ return hr;
+}
+
+/***********************************************************************
+ * AVIMakeFileFromStreams (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIMakeFileFromStreams(PAVIFILE *ppfile, int nStreams,
+ PAVISTREAM *ppStreams)
+{
+ TRACE("(%p,%d,%p)\n", ppfile, nStreams, ppStreams);
+
+ if (nStreams < 0 || ppfile == NULL || ppStreams == NULL)
+ return AVIERR_BADPARAM;
+
+ *ppfile = AVIFILE_CreateAVITempFile(nStreams, ppStreams);
+ if (*ppfile == NULL)
+ return AVIERR_MEMORY;
+
+ return AVIERR_OK;
+}
+
+/***********************************************************************
+ * AVIStreamOpenFromFile (AVIFIL32.@)
+ * AVIStreamOpenFromFileA (AVIFIL32.@)
+ * AVIStreamOpenFromFile (AVIFILE.103)
+ */
+HRESULT WINAPI AVIStreamOpenFromFileA(PAVISTREAM *ppavi, LPCSTR szFile,
+ DWORD fccType, LONG lParam,
+ UINT mode, LPCLSID pclsidHandler)
+{
+ PAVIFILE pfile = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_a(szFile),
+ (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
+
+ if (ppavi == NULL || szFile == NULL)
+ return AVIERR_BADPARAM;
+
+ *ppavi = NULL;
+
+ hr = AVIFileOpenA(&pfile, szFile, mode, pclsidHandler);
+ if (FAILED(hr) || pfile == NULL)
+ return hr;
+
+ hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
+ IAVIFile_Release(pfile);
+
+ return hr;
+}
+
+/***********************************************************************
+ * AVIStreamOpenFromFileW (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIStreamOpenFromFileW(PAVISTREAM *ppavi, LPCWSTR szFile,
+ DWORD fccType, LONG lParam,
+ UINT mode, LPCLSID pclsidHandler)
+{
+ PAVIFILE pfile = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%s,'%4.4s',%ld,0x%X,%s)\n", ppavi, debugstr_w(szFile),
+ (char*)&fccType, lParam, mode, debugstr_guid(pclsidHandler));
+
+ if (ppavi == NULL || szFile == NULL)
+ return AVIERR_BADPARAM;
+
+ *ppavi = NULL;
+
+ hr = AVIFileOpenW(&pfile, szFile, mode, pclsidHandler);
+ if (FAILED(hr) || pfile == NULL)
+ return hr;
+
+ hr = IAVIFile_GetStream(pfile, ppavi, fccType, lParam);
+ IAVIFile_Release(pfile);
+
+ return hr;
+}
+
+/***********************************************************************
+ * AVIStreamBeginStreaming (AVIFIL32.@)
+ */
+LONG WINAPI AVIStreamBeginStreaming(PAVISTREAM pavi, LONG lStart, LONG lEnd, LONG lRate)
+{
+ IAVIStreaming* pstream = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%ld,%ld,%ld)\n", pavi, lStart, lEnd, lRate);
+
+ if (pavi == NULL)
+ return AVIERR_BADHANDLE;
+
+ hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
+ if (SUCCEEDED(hr) && pstream != NULL) {
+ hr = IAVIStreaming_Begin(pstream, lStart, lEnd, lRate);
+ IAVIStreaming_Release(pstream);
+ } else
+ hr = AVIERR_OK;
+
+ return hr;
+}
+
+/***********************************************************************
+ * AVIStreamEndStreaming (AVIFIL32.@)
+ */
+LONG WINAPI AVIStreamEndStreaming(PAVISTREAM pavi)
+{
+ IAVIStreaming* pstream = NULL;
+ HRESULT hr;
+
+ TRACE("(%p)\n", pavi);
+
+ hr = IAVIStream_QueryInterface(pavi, &IID_IAVIStreaming, (LPVOID*)&pstream);
+ if (SUCCEEDED(hr) && pstream != NULL) {
+ IAVIStreaming_End(pstream);
+ IAVIStreaming_Release(pstream);
+ }
+
+ return AVIERR_OK;
+}
+
+/***********************************************************************
+ * AVIStreamStart (AVIFILE.130)
+ * AVIStreamStart (AVIFIL32.@)
+ */
+LONG WINAPI AVIStreamStart(PAVISTREAM pstream)
+{
+ AVISTREAMINFOW asiw;
+
+ TRACE("(%p)\n", pstream);
+
+ if (pstream == NULL)
+ return 0;
+
+ if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
+ return 0;
+
+ return asiw.dwStart;
+}
+
+/***********************************************************************
+ * AVIStreamLength (AVIFILE.131)
+ * AVIStreamLength (AVIFIL32.@)
+ */
+LONG WINAPI AVIStreamLength(PAVISTREAM pstream)
+{
+ AVISTREAMINFOW asiw;
+
+ TRACE("(%p)\n", pstream);
+
+ if (pstream == NULL)
+ return 0;
+
+ if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
+ return 0;
+
+ return asiw.dwLength;
+}
+
+/***********************************************************************
+ * AVIStreamSampleToTime (AVIFILE.133)
+ * AVIStreamSampleToTime (AVIFIL32.@)
+ */
+LONG WINAPI AVIStreamSampleToTime(PAVISTREAM pstream, LONG lSample)
+{
+ AVISTREAMINFOW asiw;
+ LONG time;
+
+ TRACE("(%p,%ld)\n", pstream, lSample);
+
+ if (pstream == NULL)
+ return -1;
+
+ if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
+ return -1;
+ if (asiw.dwRate == 0)
+ return -1;
+
+ /* limit to stream bounds */
+ if (lSample < asiw.dwStart)
+ lSample = asiw.dwStart;
+ if (lSample > asiw.dwStart + asiw.dwLength)
+ lSample = asiw.dwStart + asiw.dwLength;
+
+ if (asiw.dwRate / asiw.dwScale < 1000)
+ time = (LONG)(((float)lSample * asiw.dwScale * 1000) / asiw.dwRate);
+ else
+ time = (LONG)(((float)lSample * asiw.dwScale * 1000 + (asiw.dwRate - 1)) / asiw.dwRate);
+
+ TRACE(" -> %ld\n",time);
+ return time;
+}
+
+/***********************************************************************
+ * AVIStreamTimeToSample (AVIFILE.132)
+ * AVIStreamTimeToSample (AVIFIL32.@)
+ */
+LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime)
+{
+ AVISTREAMINFOW asiw;
+ ULONG sample;
+
+ TRACE("(%p,%ld)\n", pstream, lTime);
+
+ if (pstream == NULL || lTime < 0)
+ return -1;
+
+ if (FAILED(IAVIStream_Info(pstream, &asiw, sizeof(asiw))))
+ return -1;
+ if (asiw.dwScale == 0)
+ return -1;
+
+ if (asiw.dwRate / asiw.dwScale < 1000)
+ sample = (LONG)((((float)asiw.dwRate * lTime) / (asiw.dwScale * 1000)));
+ else
+ sample = (LONG)(((float)asiw.dwRate * lTime + (asiw.dwScale * 1000 - 1)) / (asiw.dwScale * 1000));
+
+ /* limit to stream bounds */
+ if (sample < asiw.dwStart)
+ sample = asiw.dwStart;
+ if (sample > asiw.dwStart + asiw.dwLength)
+ sample = asiw.dwStart + asiw.dwLength;
+
+ TRACE(" -> %ld\n", sample);
+ return sample;
+}
+
+/***********************************************************************
+ * AVIBuildFilter (AVIFIL32.@)
+ * AVIBuildFilterA (AVIFIL32.@)
+ * AVIBuildFilter (AVIFILE.123)
+ */
+HRESULT WINAPI AVIBuildFilterA(LPSTR szFilter, LONG cbFilter, BOOL fSaving)
+{
+ LPWSTR wszFilter;
+ HRESULT hr;
+
+ TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
+
+ /* check parameters */
+ if (szFilter == NULL)
+ return AVIERR_BADPARAM;
+ if (cbFilter < 2)
+ return AVIERR_BADSIZE;
+
+ szFilter[0] = 0;
+ szFilter[1] = 0;
+
+ wszFilter = (LPWSTR)GlobalAllocPtr(GHND, cbFilter * sizeof(WCHAR));
+ if (wszFilter == NULL)
+ return AVIERR_MEMORY;
+
+ hr = AVIBuildFilterW(wszFilter, cbFilter, fSaving);
+ if (SUCCEEDED(hr)) {
+ WideCharToMultiByte(CP_ACP, 0, wszFilter, cbFilter,
+ szFilter, cbFilter, NULL, NULL);
+ }
+
+ GlobalFreePtr(wszFilter);
+
+ return hr;
+}
+
+/***********************************************************************
+ * AVIBuildFilterW (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIBuildFilterW(LPWSTR szFilter, LONG cbFilter, BOOL fSaving)
+{
+ static const WCHAR szClsid[] = {'C','L','S','I','D',0};
+ static const WCHAR szExtensionFmt[] = {';','*','.','%','s',0};
+ static const WCHAR szAVIFileExtensions[] =
+ {'A','V','I','F','i','l','e','\\','E','x','t','e','n','s','i','o','n','s',0};
+
+ AVIFilter *lp;
+ WCHAR szAllFiles[40];
+ WCHAR szFileExt[10];
+ WCHAR szValue[128];
+ HKEY hKey;
+ DWORD n, i;
+ LONG size;
+ DWORD count = 0;
+
+ TRACE("(%p,%ld,%d)\n", szFilter, cbFilter, fSaving);
+
+ /* check parameters */
+ if (szFilter == NULL)
+ return AVIERR_BADPARAM;
+ if (cbFilter < 2)
+ return AVIERR_BADSIZE;
+
+ lp = (AVIFilter*)GlobalAllocPtr(GHND, MAX_FILTERS * sizeof(AVIFilter));
+ if (lp == NULL)
+ return AVIERR_MEMORY;
+
+ /*
+ * 1. iterate over HKEY_CLASSES_ROOT\\AVIFile\\Extensions and collect
+ * extensions and CLSID's
+ * 2. iterate over collected CLSID's and copy its description and its
+ * extensions to szFilter if it fits
+ *
+ * First filter is named "All multimedia files" and its filter is a
+ * collection of all possible extensions except "*.*".
+ */
+ if (RegOpenKeyW(HKEY_CLASSES_ROOT, szAVIFileExtensions, &hKey) != S_OK) {
+ GlobalFreePtr(lp);
+ return AVIERR_ERROR;
+ }
+ for (n = 0;RegEnumKeyW(hKey, n, szFileExt, sizeof(szFileExt)) == S_OK;n++) {
+ /* get CLSID to extension */
+ size = sizeof(szValue)/sizeof(szValue[0]);
+ if (RegQueryValueW(hKey, szFileExt, szValue, &size) != S_OK)
+ break;
+
+ /* search if the CLSID is already known */
+ for (i = 1; i <= count; i++) {
+ if (lstrcmpW(lp[i].szClsid, szValue) == 0)
+ break; /* a new one */
+ }
+
+ if (count - i == -1U) {
+ /* it's a new CLSID */
+
+ /* FIXME: How do we get info's about read/write capabilities? */
+
+ if (count >= MAX_FILTERS) {
+ /* try to inform user of our full fixed size table */
+ ERR(": More than %d filters found! Adjust MAX_FILTERS in dlls/avifil32/api.c\n", MAX_FILTERS);
+ break;
+ }
+
+ lstrcpyW(lp[i].szClsid, szValue);
+
+ count++;
+ }
+
+ /* append extension to the filter */
+ wsprintfW(szValue, szExtensionFmt, szFileExt);
+ if (lp[i].szExtensions[0] == 0)
+ lstrcatW(lp[i].szExtensions, szValue + 1);
+ else
+ lstrcatW(lp[i].szExtensions, szValue);
+
+ /* also append to the "all multimedia"-filter */
+ if (lp[0].szExtensions[0] == 0)
+ lstrcatW(lp[0].szExtensions, szValue + 1);
+ else
+ lstrcatW(lp[0].szExtensions, szValue);
+ }
+ RegCloseKey(hKey);
+
+ /* 2. get descriptions for the CLSIDs and fill out szFilter */
+ if (RegOpenKeyW(HKEY_CLASSES_ROOT, szClsid, &hKey) != S_OK) {
+ GlobalFreePtr(lp);
+ return AVIERR_ERROR;
+ }
+ for (n = 0; n <= count; n++) {
+ /* first the description */
+ if (n != 0) {
+ size = sizeof(szValue)/sizeof(szValue[0]);
+ if (RegQueryValueW(hKey, lp[n].szClsid, szValue, &size) == S_OK) {
+ size = lstrlenW(szValue);
+ lstrcpynW(szFilter, szValue, cbFilter);
+ }
+ } else
+ size = LoadStringW(AVIFILE_hModule,IDS_ALLMULTIMEDIA,szFilter,cbFilter);
+
+ /* check for enough space */
+ size++;
+ if (cbFilter < size + lstrlenW(lp[n].szExtensions) + 2) {
+ szFilter[0] = 0;
+ szFilter[1] = 0;
+ GlobalFreePtr(lp);
+ RegCloseKey(hKey);
+ return AVIERR_BUFFERTOOSMALL;
+ }
+ cbFilter -= size;
+ szFilter += size;
+
+ /* and then the filter */
+ lstrcpynW(szFilter, lp[n].szExtensions, cbFilter);
+ size = lstrlenW(lp[n].szExtensions) + 1;
+ cbFilter -= size;
+ szFilter += size;
+ }
+
+ RegCloseKey(hKey);
+ GlobalFreePtr(lp);
+
+ /* add "All files" "*.*" filter if enough space left */
+ size = LoadStringW(AVIFILE_hModule, IDS_ALLFILES,
+ szAllFiles, sizeof(szAllFiles)) + 1;
+ if (cbFilter > size) {
+ int i;
+
+ /* replace '@' with \000 to separate description of filter */
+ for (i = 0; i < size && szAllFiles[i] != 0; i++) {
+ if (szAllFiles[i] == '@') {
+ szAllFiles[i] = 0;
+ break;
+ }
+ }
+
+ memcpy(szFilter, szAllFiles, size * sizeof(szAllFiles[0]));
+ szFilter += size;
+ szFilter[0] = 0;
+
+ return AVIERR_OK;
+ } else {
+ szFilter[0] = 0;
+ return AVIERR_BUFFERTOOSMALL;
+ }
+}
+
+static BOOL AVISaveOptionsFmtChoose(HWND hWnd)
+{
+ LPAVICOMPRESSOPTIONS pOptions = SaveOpts.ppOptions[SaveOpts.nCurrent];
+ AVISTREAMINFOW sInfo;
+
+ TRACE("(%p)\n", hWnd);
+
+ if (pOptions == NULL || SaveOpts.ppavis[SaveOpts.nCurrent] == NULL) {
+ ERR(": bad state!\n");
+ return FALSE;
+ }
+
+ if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent],
+ &sInfo, sizeof(sInfo)))) {
+ ERR(": AVIStreamInfoW failed!\n");
+ return FALSE;
+ }
+
+ if (sInfo.fccType == streamtypeVIDEO) {
+ COMPVARS cv;
+ BOOL ret;
+
+ memset(&cv, 0, sizeof(cv));
+
+ if ((pOptions->dwFlags & AVICOMPRESSF_VALID) == 0) {
+ memset(pOptions, 0, sizeof(AVICOMPRESSOPTIONS));
+ pOptions->fccType = streamtypeVIDEO;
+ pOptions->fccHandler = comptypeDIB;
+ pOptions->dwQuality = (DWORD)ICQUALITY_DEFAULT;
+ }
+
+ cv.cbSize = sizeof(cv);
+ cv.dwFlags = ICMF_COMPVARS_VALID;
+ /*cv.fccType = pOptions->fccType; */
+ cv.fccHandler = pOptions->fccHandler;
+ cv.lQ = pOptions->dwQuality;
+ cv.lpState = pOptions->lpParms;
+ cv.cbState = pOptions->cbParms;
+ if (pOptions->dwFlags & AVICOMPRESSF_KEYFRAMES)
+ cv.lKey = pOptions->dwKeyFrameEvery;
+ else
+ cv.lKey = 0;
+ if (pOptions->dwFlags & AVICOMPRESSF_DATARATE)
+ cv.lDataRate = pOptions->dwBytesPerSecond / 1024; /* need kBytes */
+ else
+ cv.lDataRate = 0;
+
+ ret = ICCompressorChoose(hWnd, SaveOpts.uFlags, NULL,
+ SaveOpts.ppavis[SaveOpts.nCurrent], &cv, NULL);
+
+ if (ret) {
+ pOptions->fccHandler = cv.fccHandler;
+ pOptions->lpParms = cv.lpState;
+ pOptions->cbParms = cv.cbState;
+ pOptions->dwQuality = cv.lQ;
+ if (cv.lKey != 0) {
+ pOptions->dwKeyFrameEvery = cv.lKey;
+ pOptions->dwFlags |= AVICOMPRESSF_KEYFRAMES;
+ } else
+ pOptions->dwFlags &= ~AVICOMPRESSF_KEYFRAMES;
+ if (cv.lDataRate != 0) {
+ pOptions->dwBytesPerSecond = cv.lDataRate * 1024; /* need bytes */
+ pOptions->dwFlags |= AVICOMPRESSF_DATARATE;
+ } else
+ pOptions->dwFlags &= ~AVICOMPRESSF_DATARATE;
+ pOptions->dwFlags |= AVICOMPRESSF_VALID;
+ }
+ ICCompressorFree(&cv);
+
+ return ret;
+ } else if (sInfo.fccType == streamtypeAUDIO) {
+ ACMFORMATCHOOSEW afmtc;
+ MMRESULT ret;
+ LONG size;
+
+ /* FIXME: check ACM version -- Which version is needed? */
+
+ memset(&afmtc, 0, sizeof(afmtc));
+ afmtc.cbStruct = sizeof(afmtc);
+ afmtc.fdwStyle = 0;
+ afmtc.hwndOwner = hWnd;
+
+ acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &size);
+ if ((pOptions->cbFormat == 0 || pOptions->lpFormat == NULL) && size != 0) {
+ pOptions->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, size);
+ pOptions->cbFormat = size;
+ } else if (pOptions->cbFormat < (DWORD)size) {
+ pOptions->lpFormat = GlobalReAllocPtr(pOptions->lpFormat, size, GMEM_MOVEABLE);
+ pOptions->cbFormat = size;
+ }
+ if (pOptions->lpFormat == NULL)
+ return FALSE;
+ afmtc.pwfx = pOptions->lpFormat;
+ afmtc.cbwfx = pOptions->cbFormat;
+
+ size = 0;
+ AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],
+ sInfo.dwStart, &size);
+ if (size < (LONG)sizeof(PCMWAVEFORMAT))
+ size = sizeof(PCMWAVEFORMAT);
+ afmtc.pwfxEnum = GlobalAllocPtr(GHND, size);
+ if (afmtc.pwfxEnum != NULL) {
+ AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],
+ sInfo.dwStart, afmtc.pwfxEnum, &size);
+ afmtc.fdwEnum = ACM_FORMATENUMF_CONVERT;
+ }
+
+ ret = acmFormatChooseW(&afmtc);
+ if (ret == S_OK)
+ pOptions->dwFlags |= AVICOMPRESSF_VALID;
+
+ if (afmtc.pwfxEnum != NULL)
+ GlobalFreePtr(afmtc.pwfxEnum);
+
+ return (ret == S_OK ? TRUE : FALSE);
+ } else {
+ ERR(": unknown streamtype 0x%08lX\n", sInfo.fccType);
+ return FALSE;
+ }
+}
+
+static void AVISaveOptionsUpdate(HWND hWnd)
+{
+ static const WCHAR szVideoFmt[]={'%','l','d','x','%','l','d','x','%','d',0};
+ static const WCHAR szAudioFmt[]={'%','s',' ','%','s',0};
+
+ WCHAR szFormat[128];
+ AVISTREAMINFOW sInfo;
+ LPVOID lpFormat;
+ LONG size;
+
+ TRACE("(%p)\n", hWnd);
+
+ SaveOpts.nCurrent = SendDlgItemMessageW(hWnd,IDC_STREAM,CB_GETCURSEL,0,0);
+ if (SaveOpts.nCurrent < 0)
+ return;
+
+ if (FAILED(AVIStreamInfoW(SaveOpts.ppavis[SaveOpts.nCurrent], &sInfo, sizeof(sInfo))))
+ return;
+
+ AVIStreamFormatSize(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,&size);
+ if (size > 0) {
+ szFormat[0] = 0;
+
+ /* read format to build format description string */
+ lpFormat = GlobalAllocPtr(GHND, size);
+ if (lpFormat != NULL) {
+ if (SUCCEEDED(AVIStreamReadFormat(SaveOpts.ppavis[SaveOpts.nCurrent],sInfo.dwStart,lpFormat, &size))) {
+ if (sInfo.fccType == streamtypeVIDEO) {
+ LPBITMAPINFOHEADER lpbi = lpFormat;
+ ICINFO icinfo;
+
+ wsprintfW(szFormat, szVideoFmt, lpbi->biWidth,
+ lpbi->biHeight, lpbi->biBitCount);
+
+ if (lpbi->biCompression != BI_RGB) {
+ HIC hic;
+
+ hic = ICLocate(ICTYPE_VIDEO, sInfo.fccHandler, lpFormat,
+ NULL, ICMODE_DECOMPRESS);
+ if (hic != NULL) {
+ if (ICGetInfo(hic, &icinfo, sizeof(icinfo)) == S_OK)
+ lstrcatW(szFormat, icinfo.szDescription);
+ ICClose(hic);
+ }
+ } else {
+ LoadStringW(AVIFILE_hModule, IDS_UNCOMPRESSED,
+ icinfo.szDescription, sizeof(icinfo.szDescription));
+ lstrcatW(szFormat, icinfo.szDescription);
+ }
+ } else if (sInfo.fccType == streamtypeAUDIO) {
+ ACMFORMATTAGDETAILSW aftd;
+ ACMFORMATDETAILSW afd;
+
+ memset(&aftd, 0, sizeof(aftd));
+ memset(&afd, 0, sizeof(afd));
+
+ aftd.cbStruct = sizeof(aftd);
+ aftd.dwFormatTag = afd.dwFormatTag =
+ ((PWAVEFORMATEX)lpFormat)->wFormatTag;
+ aftd.cbFormatSize = afd.cbwfx = size;
+
+ afd.cbStruct = sizeof(afd);
+ afd.pwfx = lpFormat;
+
+ if (acmFormatTagDetailsW(NULL, &aftd,
+ ACM_FORMATTAGDETAILSF_FORMATTAG) == S_OK) {
+ if (acmFormatDetailsW(NULL,&afd,ACM_FORMATDETAILSF_FORMAT) == S_OK)
+ wsprintfW(szFormat, szAudioFmt, afd.szFormat, aftd.szFormatTag);
+ }
+ }
+ }
+ GlobalFreePtr(lpFormat);
+ }
+
+ /* set text for format description */
+ SetDlgItemTextW(hWnd, IDC_FORMATTEXT, szFormat);
+
+ /* Disable option button for unsupported streamtypes */
+ if (sInfo.fccType == streamtypeVIDEO ||
+ sInfo.fccType == streamtypeAUDIO)
+ EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), TRUE);
+ else
+ EnableWindow(GetDlgItem(hWnd, IDC_OPTIONS), FALSE);
+ }
+
+}
+
+static INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
+ WPARAM wParam, LPARAM lParam)
+{
+ DWORD dwInterleave;
+ BOOL bIsInterleaved;
+ INT n;
+
+ /*TRACE("(%p,%u,0x%04X,0x%08lX)\n", hWnd, uMsg, wParam, lParam);*/
+
+ switch (uMsg) {
+ case WM_INITDIALOG:
+ SaveOpts.nCurrent = 0;
+ if (SaveOpts.nStreams == 1) {
+ EndDialog(hWnd, AVISaveOptionsFmtChoose(hWnd));
+ return TRUE;
+ }
+
+ /* add streams */
+ for (n = 0; n < SaveOpts.nStreams; n++) {
+ AVISTREAMINFOW sInfo;
+
+ AVIStreamInfoW(SaveOpts.ppavis[n], &sInfo, sizeof(sInfo));
+ SendDlgItemMessageW(hWnd, IDC_STREAM, CB_ADDSTRING,
+ 0L, (LPARAM)sInfo.szName);
+ }
+
+ /* select first stream */
+ SendDlgItemMessageW(hWnd, IDC_STREAM, CB_SETCURSEL, 0, 0);
+ SendMessageW(hWnd, WM_COMMAND,
+ GET_WM_COMMAND_MPS(IDC_STREAM, hWnd, CBN_SELCHANGE));
+
+ /* initialize interleave */
+ if (SaveOpts.ppOptions[0] != NULL &&
+ (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_VALID)) {
+ bIsInterleaved = (SaveOpts.ppOptions[0]->dwFlags & AVICOMPRESSF_INTERLEAVE);
+ dwInterleave = SaveOpts.ppOptions[0]->dwInterleaveEvery;
+ } else {
+ bIsInterleaved = TRUE;
+ dwInterleave = 0;
+ }
+ CheckDlgButton(hWnd, IDC_INTERLEAVE, bIsInterleaved);
+ SetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, dwInterleave, FALSE);
+ EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY), bIsInterleaved);
+ break;
+ case WM_COMMAND:
+ switch (GET_WM_COMMAND_ID(wParam, lParam)) {
+ case IDOK:
+ /* get data from controls and save them */
+ dwInterleave = GetDlgItemInt(hWnd, IDC_INTERLEAVEEVERY, NULL, 0);
+ bIsInterleaved = IsDlgButtonChecked(hWnd, IDC_INTERLEAVE);
+ for (n = 0; n < SaveOpts.nStreams; n++) {
+ if (SaveOpts.ppOptions[n] != NULL) {
+ if (bIsInterleaved) {
+ SaveOpts.ppOptions[n]->dwFlags |= AVICOMPRESSF_INTERLEAVE;
+ SaveOpts.ppOptions[n]->dwInterleaveEvery = dwInterleave;
+ } else
+ SaveOpts.ppOptions[n]->dwFlags &= ~AVICOMPRESSF_INTERLEAVE;
+ }
+ }
+ /* fall through */
+ case IDCANCEL:
+ EndDialog(hWnd, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
+ break;
+ case IDC_INTERLEAVE:
+ EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
+ IsDlgButtonChecked(hWnd, IDC_INTERLEAVE));
+ break;
+ case IDC_STREAM:
+ if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE) {
+ /* update control elements */
+ AVISaveOptionsUpdate(hWnd);
+ }
+ break;
+ case IDC_OPTIONS:
+ AVISaveOptionsFmtChoose(hWnd);
+ break;
+ };
+ return TRUE;
+ };
+
+ return FALSE;
+}
+
+/***********************************************************************
+ * AVISaveOptions (AVIFIL32.@)
+ */
+BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
+ PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *ppOptions)
+{
+ LPAVICOMPRESSOPTIONS pSavedOptions = NULL;
+ INT ret, n;
+
+ TRACE("(%p,0x%X,%d,%p,%p)\n", hWnd, uFlags, nStreams,
+ ppavi, ppOptions);
+
+ /* check parameters */
+ if (nStreams <= 0 || ppavi == NULL || ppOptions == NULL)
+ return AVIERR_BADPARAM;
+
+ /* save options in case the user presses cancel */
+ if (ppOptions != NULL && nStreams > 1) {
+ pSavedOptions = GlobalAllocPtr(GHND,nStreams * sizeof(AVICOMPRESSOPTIONS));
+ if (pSavedOptions == NULL)
+ return FALSE;
+
+ for (n = 0; n < nStreams; n++) {
+ if (ppOptions[n] != NULL)
+ memcpy(pSavedOptions + n, ppOptions[n], sizeof(AVICOMPRESSOPTIONS));
+ }
+ }
+
+ SaveOpts.uFlags = uFlags;
+ SaveOpts.nStreams = nStreams;
+ SaveOpts.ppavis = ppavi;
+ SaveOpts.ppOptions = ppOptions;
+
+ ret = DialogBoxW(AVIFILE_hModule, MAKEINTRESOURCEW(IDD_SAVEOPTIONS),
+ hWnd, AVISaveOptionsDlgProc);
+
+ if (ret == -1)
+ ret = FALSE;
+
+ /* restore options when user pressed cancel */
+ if (pSavedOptions != NULL) {
+ if (ret == FALSE) {
+ for (n = 0; n < nStreams; n++) {
+ if (ppOptions[n] != NULL)
+ memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
+ }
+ }
+ GlobalFreePtr(pSavedOptions);
+ }
+
+ return (BOOL)ret;
+}
+
+/***********************************************************************
+ * AVISaveOptionsFree (AVIFIL32.@)
+ * AVISaveOptionsFree (AVIFILE.124)
+ */
+HRESULT WINAPI AVISaveOptionsFree(INT nStreams,LPAVICOMPRESSOPTIONS*ppOptions)
+{
+ TRACE("(%d,%p)\n", nStreams, ppOptions);
+
+ if (nStreams < 0 || ppOptions == NULL)
+ return AVIERR_BADPARAM;
+
+ for (; nStreams > 0; nStreams--) {
+ if (ppOptions[nStreams] != NULL) {
+ ppOptions[nStreams]->dwFlags &= ~AVICOMPRESSF_VALID;
+
+ if (ppOptions[nStreams]->lpParms != NULL) {
+ GlobalFreePtr(ppOptions[nStreams]->lpParms);
+ ppOptions[nStreams]->lpParms = NULL;
+ ppOptions[nStreams]->cbParms = 0;
+ }
+ if (ppOptions[nStreams]->lpFormat != NULL) {
+ GlobalFreePtr(ppOptions[nStreams]->lpFormat);
+ ppOptions[nStreams]->lpFormat = NULL;
+ ppOptions[nStreams]->cbFormat = 0;
+ }
+ }
+ }
+
+ return AVIERR_OK;
+}
+
+/***********************************************************************
+ * AVISaveVA (AVIFIL32.@)
+ */
+HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
+ AVISAVECALLBACK lpfnCallback, int nStream,
+ PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
+{
+ LPWSTR wszFile = NULL;
+ HRESULT hr;
+ int len;
+
+ TRACE("%s,%p,%p,%d,%p,%p)\n", debugstr_a(szFile), pclsidHandler,
+ lpfnCallback, nStream, ppavi, plpOptions);
+
+ if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
+ return AVIERR_BADPARAM;
+
+ /* convert ASCII string to Unicode and call Unicode function */
+ len = MultiByteToWideChar(CP_ACP, 0, szFile, -1, NULL, 0);
+ if (len <= 0)
+ return AVIERR_BADPARAM;
+
+ wszFile = LocalAlloc(LPTR, len * sizeof(WCHAR));
+ if (wszFile == NULL)
+ return AVIERR_MEMORY;
+
+ MultiByteToWideChar(CP_ACP, 0, szFile, -1, wszFile, len);
+
+ hr = AVISaveVW(wszFile, pclsidHandler, lpfnCallback,
+ nStream, ppavi, plpOptions);
+
+ LocalFree((HLOCAL)wszFile);
+
+ return hr;
+}
+
+/***********************************************************************
+ * AVIFILE_AVISaveDefaultCallback (internal)
+ */
+static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress)
+{
+ TRACE("(%d)\n", progress);
+
+ return FALSE;
+}
+
+/***********************************************************************
+ * AVISaveVW (AVIFIL32.@)
+ */
+HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
+ AVISAVECALLBACK lpfnCallback, int nStreams,
+ PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
+{
+ LONG lStart[MAX_AVISTREAMS];
+ PAVISTREAM pOutStreams[MAX_AVISTREAMS];
+ PAVISTREAM pInStreams[MAX_AVISTREAMS];
+ AVIFILEINFOW fInfo;
+ AVISTREAMINFOW sInfo;
+
+ PAVIFILE pfile = NULL; /* the output AVI file */
+ LONG lFirstVideo = -1;
+ int curStream;
+
+ /* for interleaving ... */
+ DWORD dwInterleave = 0; /* interleave rate */
+ DWORD dwFileInitialFrames;
+ LONG lFileLength;
+ LONG lSampleInc;
+
+ /* for reading/writing the data ... */
+ LPVOID lpBuffer = NULL;
+ LONG cbBuffer; /* real size of lpBuffer */
+ LONG lBufferSize; /* needed bytes for format(s), etc. */
+ LONG lReadBytes;
+ LONG lReadSamples;
+ HRESULT hres;
+
+ TRACE("(%s,%p,%p,%d,%p,%p)\n", debugstr_w(szFile), pclsidHandler,
+ lpfnCallback, nStreams, ppavi, plpOptions);
+
+ if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
+ return AVIERR_BADPARAM;
+ if (nStreams >= MAX_AVISTREAMS) {
+ WARN("Can't write AVI with %d streams only supports %d -- change MAX_AVISTREAMS!\n", nStreams, MAX_AVISTREAMS);
+ return AVIERR_INTERNAL;
+ }
+
+ if (lpfnCallback == NULL)
+ lpfnCallback = AVIFILE_AVISaveDefaultCallback;
+
+ /* clear local variable(s) */
+ for (curStream = 0; curStream < nStreams; curStream++) {
+ pInStreams[curStream] = NULL;
+ pOutStreams[curStream] = NULL;
+ }
+
+ /* open output AVI file (create it if it doesn't exist) */
+ hres = AVIFileOpenW(&pfile, szFile, OF_CREATE|OF_SHARE_EXCLUSIVE|OF_WRITE,
+ pclsidHandler);
+ if (FAILED(hres))
+ return hres;
+ AVIFileInfoW(pfile, &fInfo, sizeof(fInfo)); /* for dwCaps */
+
+ /* initialize our data structures part 1 */
+ for (curStream = 0; curStream < nStreams; curStream++) {
+ PAVISTREAM pCurStream = ppavi[curStream];
+
+ hres = AVIStreamInfoW(pCurStream, &sInfo, sizeof(sInfo));
+ if (FAILED(hres))
+ goto error;
+
+ /* search first video stream and check for interleaving */
+ if (sInfo.fccType == streamtypeVIDEO) {
+ /* remember first video stream -- needed for interleaving */
+ if (lFirstVideo < 0)
+ lFirstVideo = curStream;
+ } else if (!dwInterleave && plpOptions != NULL) {
+ /* check if any non-video stream wants to be interleaved */
+ WARN("options.flags=0x%lX options.dwInterleave=%lu\n",plpOptions[curStream]->dwFlags,plpOptions[curStream]->dwInterleaveEvery);
+ if (plpOptions[curStream] != NULL &&
+ plpOptions[curStream]->dwFlags & AVICOMPRESSF_INTERLEAVE)
+ dwInterleave = plpOptions[curStream]->dwInterleaveEvery;
+ }
+
+ /* create de-/compressed stream interface if needed */
+ pInStreams[curStream] = NULL;
+ if (plpOptions != NULL && plpOptions[curStream] != NULL) {
+ if (plpOptions[curStream]->fccHandler ||
+ plpOptions[curStream]->lpFormat != NULL) {
+ DWORD dwKeySave = plpOptions[curStream]->dwKeyFrameEvery;
+
+ if (fInfo.dwCaps & AVIFILECAPS_ALLKEYFRAMES)
+ plpOptions[curStream]->dwKeyFrameEvery = 1;
+
+ hres = AVIMakeCompressedStream(&pInStreams[curStream], pCurStream,
+ plpOptions[curStream], NULL);
+ plpOptions[curStream]->dwKeyFrameEvery = dwKeySave;
+ if (FAILED(hres) || pInStreams[curStream] == NULL) {
+ pInStreams[curStream] = NULL;
+ goto error;
+ }
+
+ /* test stream interface and update stream-info */
+ hres = AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
+ if (FAILED(hres))
+ goto error;
+ }
+ }
+
+ /* now handle streams which will only be copied */
+ if (pInStreams[curStream] == NULL) {
+ pCurStream = pInStreams[curStream] = ppavi[curStream];
+ AVIStreamAddRef(pCurStream);
+ } else
+ pCurStream = pInStreams[curStream];
+
+ lStart[curStream] = sInfo.dwStart;
+ } /* for all streams */
+
+ /* check that first video stream is the first stream */
+ if (lFirstVideo > 0) {
+ PAVISTREAM pTmp = pInStreams[lFirstVideo];
+ LONG lTmp = lStart[lFirstVideo];
+
+ pInStreams[lFirstVideo] = pInStreams[0];
+ pInStreams[0] = pTmp;
+ lStart[lFirstVideo] = lStart[0];
+ lStart[0] = lTmp;
+ lFirstVideo = 0;
+ }
+
+ /* allocate buffer for formats, data, etc. of an initial size of 64 kBytes*/
+ lpBuffer = GlobalAllocPtr(GPTR, cbBuffer = 0x00010000);
+ if (lpBuffer == NULL) {
+ hres = AVIERR_MEMORY;
+ goto error;
+ }
+
+ AVIStreamInfoW(pInStreams[0], &sInfo, sizeof(sInfo));
+ lFileLength = sInfo.dwLength;
+ dwFileInitialFrames = 0;
+ if (lFirstVideo >= 0) {
+ /* check for correct version of the format
+ * -- need at least BITMAPINFOHEADER or newer
+ */
+ lSampleInc = 1;
+ lBufferSize = cbBuffer;
+ hres = AVIStreamReadFormat(pInStreams[lFirstVideo], AVIStreamStart(pInStreams[lFirstVideo]), lpBuffer, &lBufferSize);
+ if (lBufferSize < (LONG)sizeof(BITMAPINFOHEADER))
+ hres = AVIERR_INTERNAL;
+ if (FAILED(hres))
+ goto error;
+ } else /* use one second blocks for interleaving if no video present */
+ lSampleInc = AVIStreamTimeToSample(pInStreams[0], 1000000);
+
+ /* create output streams */
+ for (curStream = 0; curStream < nStreams; curStream++) {
+ AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
+
+ sInfo.dwInitialFrames = 0;
+ if (dwInterleave != 0 && curStream > 0 && sInfo.fccType != streamtypeVIDEO) {
+ /* 750 ms initial frames for non-video streams */
+ sInfo.dwInitialFrames = AVIStreamTimeToSample(pInStreams[0], 750);
+ }
+
+ hres = AVIFileCreateStreamW(pfile, &pOutStreams[curStream], &sInfo);
+ if (pOutStreams[curStream] != NULL && SUCCEEDED(hres)) {
+ /* copy initial format for this stream */
+ lBufferSize = cbBuffer;
+ hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
+ lpBuffer, &lBufferSize);
+ if (FAILED(hres))
+ goto error;
+ hres = AVIStreamSetFormat(pOutStreams[curStream], 0, lpBuffer, lBufferSize);
+ if (FAILED(hres))
+ goto error;
+
+ /* try to copy stream handler data */
+ lBufferSize = cbBuffer;
+ hres = AVIStreamReadData(pInStreams[curStream], ckidSTREAMHANDLERDATA,
+ lpBuffer, &lBufferSize);
+ if (SUCCEEDED(hres) && lBufferSize > 0) {
+ hres = AVIStreamWriteData(pOutStreams[curStream],ckidSTREAMHANDLERDATA,
+ lpBuffer, lBufferSize);
+ if (FAILED(hres))
+ goto error;
+ }
+
+ if (dwFileInitialFrames < sInfo.dwInitialFrames)
+ dwFileInitialFrames = sInfo.dwInitialFrames;
+ lReadBytes =
+ AVIStreamSampleToSample(pOutStreams[0], pInStreams[curStream],
+ sInfo.dwLength);
+ if (lFileLength < lReadBytes)
+ lFileLength = lReadBytes;
+ } else {
+ /* creation of de-/compression stream interface failed */
+ WARN("creation of (de-)compression stream failed for stream %d\n",curStream);
+ AVIStreamRelease(pInStreams[curStream]);
+ if (curStream + 1 >= nStreams) {
+ /* move the others one up */
+ PAVISTREAM *ppas = &pInStreams[curStream];
+ int n = nStreams - (curStream + 1);
+
+ do {
+ *ppas = pInStreams[curStream + 1];
+ } while (--n);
+ }
+ nStreams--;
+ curStream--;
+ }
+ } /* create output streams for all input streams */
+
+ /* have we still something to write, or lost everything? */
+ if (nStreams <= 0)
+ goto error;
+
+ if (dwInterleave) {
+ LONG lCurFrame = -dwFileInitialFrames;
+
+ /* interleaved file */
+ if (dwInterleave == 1)
+ AVIFileEndRecord(pfile);
+
+ for (; lCurFrame < lFileLength; lCurFrame += lSampleInc) {
+ for (curStream = 0; curStream < nStreams; curStream++) {
+ LONG lLastSample;
+
+ hres = AVIStreamInfoW(pOutStreams[curStream], &sInfo, sizeof(sInfo));
+ if (FAILED(hres))
+ goto error;
+
+ /* initial frames phase at the end for this stream? */
+ if (-(LONG)sInfo.dwInitialFrames > lCurFrame)
+ continue;
+
+ if ((lFileLength - lSampleInc) <= lCurFrame) {
+ lLastSample = AVIStreamLength(pInStreams[curStream]);
+ lFirstVideo = lLastSample + AVIStreamStart(pInStreams[curStream]);
+ } else {
+ if (curStream != 0) {
+ lFirstVideo =
+ AVIStreamSampleToSample(pInStreams[curStream], pInStreams[0],
+ (sInfo.fccType == streamtypeVIDEO ?
+ (LONG)dwInterleave : lSampleInc) +
+ sInfo.dwInitialFrames + lCurFrame);
+ } else
+ lFirstVideo = lSampleInc + (sInfo.dwInitialFrames + lCurFrame);
+
+ lLastSample = AVIStreamEnd(pInStreams[curStream]);
+ if (lLastSample <= lFirstVideo)
+ lFirstVideo = lLastSample;
+ }
+
+ /* copy needed samples now */
+ WARN("copy from stream %d samples %ld to %ld...\n",curStream,
+ lStart[curStream],lFirstVideo);
+ while (lFirstVideo > lStart[curStream]) {
+ DWORD flags = 0;
+
+ /* copy format in case it can change */
+ lBufferSize = cbBuffer;
+ hres = AVIStreamReadFormat(pInStreams[curStream], lStart[curStream],
+ lpBuffer, &lBufferSize);
+ if (FAILED(hres))
+ goto error;
+ AVIStreamSetFormat(pOutStreams[curStream], lStart[curStream],
+ lpBuffer, lBufferSize);
+
+ /* try to read data until we got it, or error */
+ do {
+ hres = AVIStreamRead(pInStreams[curStream], lStart[curStream],
+ lFirstVideo - lStart[curStream], lpBuffer,
+ cbBuffer, &lReadBytes, &lReadSamples);
+ } while ((hres == AVIERR_BUFFERTOOSMALL) &&
+ (lpBuffer = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != NULL);
+ if (lpBuffer == NULL)
+ hres = AVIERR_MEMORY;
+ if (FAILED(hres))
+ goto error;
+
+ if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
+ flags = AVIIF_KEYFRAME;
+ hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
+ lpBuffer, lReadBytes, flags, NULL, NULL);
+ if (FAILED(hres))
+ goto error;
+
+ lStart[curStream] += lReadSamples;
+ }
+ lStart[curStream] = lFirstVideo;
+ } /* stream by stream */
+
+ /* need to close this block? */
+ if (dwInterleave == 1) {
+ hres = AVIFileEndRecord(pfile);
+ if (FAILED(hres))
+ break;
+ }
+
+ /* show progress */
+ if (lpfnCallback(MulDiv(dwFileInitialFrames + lCurFrame, 100,
+ dwFileInitialFrames + lFileLength))) {
+ hres = AVIERR_USERABORT;
+ break;
+ }
+ } /* copy frame by frame */
+ } else {
+ /* non-interleaved file */
+
+ for (curStream = 0; curStream < nStreams; curStream++) {
+ /* show progress */
+ if (lpfnCallback(MulDiv(curStream, 100, nStreams))) {
+ hres = AVIERR_USERABORT;
+ goto error;
+ }
+
+ AVIStreamInfoW(pInStreams[curStream], &sInfo, sizeof(sInfo));
+
+ if (sInfo.dwSampleSize != 0) {
+ /* sample-based data like audio */
+ while (sInfo.dwStart < sInfo.dwLength) {
+ LONG lSamples = cbBuffer / sInfo.dwSampleSize;
+
+ /* copy format in case it can change */
+ lBufferSize = cbBuffer;
+ hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
+ lpBuffer, &lBufferSize);
+ if (FAILED(hres))
+ return hres;
+ AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
+ lpBuffer, lBufferSize);
+
+ /* limit to stream boundaries */
+ if (lSamples != (LONG)(sInfo.dwLength - sInfo.dwStart))
+ lSamples = sInfo.dwLength - sInfo.dwStart;
+
+ /* now try to read until we get it, or an error occurs */
+ do {
+ lReadBytes = cbBuffer;
+ lReadSamples = 0;
+ hres = AVIStreamRead(pInStreams[curStream],sInfo.dwStart,lSamples,
+ lpBuffer,cbBuffer,&lReadBytes,&lReadSamples);
+ } while ((hres == AVIERR_BUFFERTOOSMALL) &&
+ (lpBuffer = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != NULL);
+ if (lpBuffer == NULL)
+ hres = AVIERR_MEMORY;
+ if (FAILED(hres))
+ goto error;
+ if (lReadSamples != 0) {
+ sInfo.dwStart += lReadSamples;
+ hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
+ lpBuffer, lReadBytes, 0, NULL , NULL);
+ if (FAILED(hres))
+ goto error;
+
+ /* show progress */
+ if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
+ MulDiv(curStream, 100, nStreams))) {
+ hres = AVIERR_USERABORT;
+ goto error;
+ }
+ } else {
+ if ((sInfo.dwLength - sInfo.dwStart) != 1) {
+ hres = AVIERR_FILEREAD;
+ goto error;
+ }
+ }
+ }
+ } else {
+ /* block-based data like video */
+ for (; sInfo.dwStart < sInfo.dwLength; sInfo.dwStart++) {
+ DWORD flags = 0;
+
+ /* copy format in case it can change */
+ lBufferSize = cbBuffer;
+ hres = AVIStreamReadFormat(pInStreams[curStream], sInfo.dwStart,
+ lpBuffer, &lBufferSize);
+ if (FAILED(hres))
+ goto error;
+ AVIStreamSetFormat(pOutStreams[curStream], sInfo.dwStart,
+ lpBuffer, lBufferSize);
+
+ /* try to read block and resize buffer if necessary */
+ do {
+ lReadSamples = 0;
+ lReadBytes = cbBuffer;
+ hres = AVIStreamRead(pInStreams[curStream], sInfo.dwStart, 1,
+ lpBuffer, cbBuffer,&lReadBytes,&lReadSamples);
+ } while ((hres == AVIERR_BUFFERTOOSMALL) &&
+ (lpBuffer = GlobalReAllocPtr(lpBuffer, cbBuffer *= 2, GPTR)) != NULL);
+ if (lpBuffer == NULL)
+ hres = AVIERR_MEMORY;
+ if (FAILED(hres))
+ goto error;
+ if (lReadSamples != 1) {
+ hres = AVIERR_FILEREAD;
+ goto error;
+ }
+
+ if (AVIStreamIsKeyFrame(pInStreams[curStream], (LONG)sInfo.dwStart))
+ flags = AVIIF_KEYFRAME;
+ hres = AVIStreamWrite(pOutStreams[curStream], -1, lReadSamples,
+ lpBuffer, lReadBytes, flags, NULL, NULL);
+ if (FAILED(hres))
+ goto error;
+
+ /* show progress */
+ if (lpfnCallback(MulDiv(sInfo.dwStart,100,nStreams*sInfo.dwLength)+
+ MulDiv(curStream, 100, nStreams))) {
+ hres = AVIERR_USERABORT;
+ goto error;
+ }
+ } /* copy all blocks */
+ }
+ } /* copy data stream by stream */
+ }
+
+ error:
+ if (lpBuffer != NULL)
+ GlobalFreePtr(lpBuffer);
+ if (pfile != NULL) {
+ for (curStream = 0; curStream < nStreams; curStream++) {
+ if (pOutStreams[curStream] != NULL)
+ AVIStreamRelease(pOutStreams[curStream]);
+ if (pInStreams[curStream] != NULL)
+ AVIStreamRelease(pInStreams[curStream]);
+ }
+
+ AVIFileRelease(pfile);
+ }
+
+ return hres;
+}
+
+/***********************************************************************
+ * CreateEditableStream (AVIFIL32.@)
+ */
+HRESULT WINAPI CreateEditableStream(PAVISTREAM *ppEditable, PAVISTREAM pSource)
+{
+ IAVIEditStream *pEdit = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p)\n", ppEditable, pSource);
+
+ if (ppEditable == NULL)
+ return AVIERR_BADPARAM;
+
+ *ppEditable = NULL;
+
+ if (pSource != NULL) {
+ hr = IAVIStream_QueryInterface(pSource, &IID_IAVIEditStream,
+ (LPVOID*)&pEdit);
+ if (SUCCEEDED(hr) && pEdit != NULL) {
+ hr = IAVIEditStream_Clone(pEdit, ppEditable);
+ IAVIEditStream_Release(pEdit);
+
+ return hr;
+ }
+ }
+
+ /* need own implementation of IAVIEditStream */
+ pEdit = AVIFILE_CreateEditStream(pSource);
+ if (pEdit == NULL)
+ return AVIERR_MEMORY;
+
+ hr = IAVIEditStream_QueryInterface(pEdit, &IID_IAVIStream,
+ (LPVOID*)ppEditable);
+ IAVIEditStream_Release(pEdit);
+
+ return hr;
+}
+
+/***********************************************************************
+ * EditStreamClone (AVIFIL32.@)
+ */
+HRESULT WINAPI EditStreamClone(PAVISTREAM pStream, PAVISTREAM *ppResult)
+{
+ PAVIEDITSTREAM pEdit = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p)\n", pStream, ppResult);
+
+ if (pStream == NULL)
+ return AVIERR_BADHANDLE;
+ if (ppResult == NULL)
+ return AVIERR_BADPARAM;
+
+ *ppResult = NULL;
+
+ hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
+ if (SUCCEEDED(hr) && pEdit != NULL) {
+ hr = IAVIEditStream_Clone(pEdit, ppResult);
+
+ IAVIEditStream_Release(pEdit);
+ } else
+ hr = AVIERR_UNSUPPORTED;
+
+ return hr;
+}
+
+/***********************************************************************
+ * EditStreamCopy (AVIFIL32.@)
+ */
+HRESULT WINAPI EditStreamCopy(PAVISTREAM pStream, LONG *plStart,
+ LONG *plLength, PAVISTREAM *ppResult)
+{
+ PAVIEDITSTREAM pEdit = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
+
+ if (pStream == NULL)
+ return AVIERR_BADHANDLE;
+ if (plStart == NULL || plLength == NULL || ppResult == NULL)
+ return AVIERR_BADPARAM;
+
+ *ppResult = NULL;
+
+ hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
+ if (SUCCEEDED(hr) && pEdit != NULL) {
+ hr = IAVIEditStream_Copy(pEdit, plStart, plLength, ppResult);
+
+ IAVIEditStream_Release(pEdit);
+ } else
+ hr = AVIERR_UNSUPPORTED;
+
+ return hr;
+}
+
+/***********************************************************************
+ * EditStreamCut (AVIFIL32.@)
+ */
+HRESULT WINAPI EditStreamCut(PAVISTREAM pStream, LONG *plStart,
+ LONG *plLength, PAVISTREAM *ppResult)
+{
+ PAVIEDITSTREAM pEdit = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%p,%p)\n", pStream, plStart, plLength, ppResult);
+
+ if (ppResult != NULL)
+ *ppResult = NULL;
+ if (pStream == NULL)
+ return AVIERR_BADHANDLE;
+ if (plStart == NULL || plLength == NULL)
+ return AVIERR_BADPARAM;
+
+ hr = IAVIStream_QueryInterface(pStream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
+ if (SUCCEEDED(hr) && pEdit != NULL) {
+ hr = IAVIEditStream_Cut(pEdit, plStart, plLength, ppResult);
+
+ IAVIEditStream_Release(pEdit);
+ } else
+ hr = AVIERR_UNSUPPORTED;
+
+ return hr;
+}
+
+/***********************************************************************
+ * EditStreamPaste (AVIFIL32.@)
+ */
+HRESULT WINAPI EditStreamPaste(PAVISTREAM pDest, LONG *plStart, LONG *plLength,
+ PAVISTREAM pSource, LONG lStart, LONG lEnd)
+{
+ PAVIEDITSTREAM pEdit = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%p,%p,%ld,%ld)\n", pDest, plStart, plLength,
+ pSource, lStart, lEnd);
+
+ if (pDest == NULL || pSource == NULL)
+ return AVIERR_BADHANDLE;
+ if (plStart == NULL || plLength == NULL || lStart < 0)
+ return AVIERR_BADPARAM;
+
+ hr = IAVIStream_QueryInterface(pDest, &IID_IAVIEditStream,(LPVOID*)&pEdit);
+ if (SUCCEEDED(hr) && pEdit != NULL) {
+ hr = IAVIEditStream_Paste(pEdit, plStart, plLength, pSource, lStart, lEnd);
+
+ IAVIEditStream_Release(pEdit);
+ } else
+ hr = AVIERR_UNSUPPORTED;
+
+ return hr;
+}
+
+/***********************************************************************
+ * EditStreamSetInfoA (AVIFIL32.@)
+ */
+HRESULT WINAPI EditStreamSetInfoA(PAVISTREAM pstream, LPAVISTREAMINFOA asi,
+ LONG size)
+{
+ AVISTREAMINFOW asiw;
+
+ TRACE("(%p,%p,%ld)\n", pstream, asi, size);
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+ if ((DWORD)size < sizeof(AVISTREAMINFOA))
+ return AVIERR_BADSIZE;
+
+ memcpy(&asiw, asi, sizeof(asiw) - sizeof(asiw.szName));
+ MultiByteToWideChar(CP_ACP, 0, asi->szName, -1,
+ asiw.szName, sizeof(asiw.szName));
+
+ return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
+}
+
+/***********************************************************************
+ * EditStreamSetInfoW (AVIFIL32.@)
+ */
+HRESULT WINAPI EditStreamSetInfoW(PAVISTREAM pstream, LPAVISTREAMINFOW asi,
+ LONG size)
+{
+ PAVIEDITSTREAM pEdit = NULL;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%ld)\n", pstream, asi, size);
+
+ hr = IAVIStream_QueryInterface(pstream, &IID_IAVIEditStream,(LPVOID*)&pEdit);
+ if (SUCCEEDED(hr) && pEdit != NULL) {
+ hr = IAVIEditStream_SetInfo(pEdit, asi, size);
+
+ IAVIEditStream_Release(pEdit);
+ } else
+ hr = AVIERR_UNSUPPORTED;
+
+ return hr;
+}
+
+/***********************************************************************
+ * EditStreamSetNameA (AVIFIL32.@)
+ */
+HRESULT WINAPI EditStreamSetNameA(PAVISTREAM pstream, LPCSTR szName)
+{
+ AVISTREAMINFOA asia;
+ HRESULT hres;
+
+ TRACE("(%p,%s)\n", pstream, debugstr_a(szName));
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+ if (szName == NULL)
+ return AVIERR_BADPARAM;
+
+ hres = AVIStreamInfoA(pstream, &asia, sizeof(asia));
+ if (FAILED(hres))
+ return hres;
+
+ memset(asia.szName, 0, sizeof(asia.szName));
+ lstrcpynA(asia.szName, szName, sizeof(asia.szName)/sizeof(asia.szName[0]));
+
+ return EditStreamSetInfoA(pstream, &asia, sizeof(asia));
+}
+
+/***********************************************************************
+ * EditStreamSetNameW (AVIFIL32.@)
+ */
+HRESULT WINAPI EditStreamSetNameW(PAVISTREAM pstream, LPCWSTR szName)
+{
+ AVISTREAMINFOW asiw;
+ HRESULT hres;
+
+ TRACE("(%p,%s)\n", pstream, debugstr_w(szName));
+
+ if (pstream == NULL)
+ return AVIERR_BADHANDLE;
+ if (szName == NULL)
+ return AVIERR_BADPARAM;
+
+ hres = IAVIStream_Info(pstream, &asiw, sizeof(asiw));
+ if (FAILED(hres))
+ return hres;
+
+ memset(asiw.szName, 0, sizeof(asiw.szName));
+ lstrcpynW(asiw.szName, szName, sizeof(asiw.szName)/sizeof(asiw.szName[0]));
+
+ return EditStreamSetInfoW(pstream, &asiw, sizeof(asiw));
+}
+
+/***********************************************************************
+ * AVIClearClipboard (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIClearClipboard(void)
+{
+ TRACE("()\n");
+
+ return AVIERR_UNSUPPORTED; /* OleSetClipboard(NULL); */
+}
+
+/***********************************************************************
+ * AVIGetFromClipboard (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIGetFromClipboard(PAVIFILE *ppfile)
+{
+ FIXME("(%p), stub!\n", ppfile);
+
+ *ppfile = NULL;
+
+ return AVIERR_UNSUPPORTED;
+}
+
+/***********************************************************************
+ * AVIMakeStreamFromClipboard (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIMakeStreamFromClipboard(UINT cfFormat, HANDLE hGlobal,
+ PAVISTREAM * ppstream)
+{
+ FIXME("(0x%08x,%p,%p), stub!\n", cfFormat, hGlobal, ppstream);
+
+ if (ppstream == NULL)
+ return AVIERR_BADHANDLE;
+
+ return AVIERR_UNSUPPORTED;
+}
+
+/***********************************************************************
+ * AVIPutFileOnClipboard (AVIFIL32.@)
+ */
+HRESULT WINAPI AVIPutFileOnClipboard(PAVIFILE pfile)
+{
+ FIXME("(%p), stub!\n", pfile);
+
+ if (pfile == NULL)
+ return AVIERR_BADHANDLE;
+
+ return AVIERR_UNSUPPORTED;
+}
+
+HRESULT CDECL AVISaveA(LPCSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
+ int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
+{
+ FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_a(szFile), pclsidHandler, lpfnCallback,
+ nStreams, pavi, lpOptions);
+
+ return AVIERR_UNSUPPORTED;
+}
+
+HRESULT CDECL AVISaveW(LPCWSTR szFile, CLSID * pclsidHandler, AVISAVECALLBACK lpfnCallback,
+ int nStreams, PAVISTREAM pavi, LPAVICOMPRESSOPTIONS lpOptions, ...)
+{
+ FIXME("(%s,%p,%p,0x%08x,%p,%p), stub!\n", debugstr_w(szFile), pclsidHandler, lpfnCallback,
+ nStreams, pavi, lpOptions);
+
+ return AVIERR_UNSUPPORTED;
+}
--- /dev/null
+@ stdcall AVIBuildFilter(str long long) AVIBuildFilterA
+@ stdcall AVIBuildFilterA(str long long)
+@ stdcall AVIBuildFilterW(wstr long long)
+@ stdcall AVIClearClipboard()
+@ stdcall AVIFileAddRef(ptr)
+@ stdcall AVIFileCreateStream(ptr ptr ptr) AVIFileCreateStreamA
+@ stdcall AVIFileCreateStreamA(ptr ptr ptr)
+@ stdcall AVIFileCreateStreamW(ptr ptr ptr)
+@ stdcall AVIFileEndRecord(ptr)
+@ stdcall AVIFileExit()
+@ stdcall AVIFileGetStream(ptr ptr long long)
+@ stdcall AVIFileInfo (ptr ptr long) AVIFileInfoA # A in both Win95 and NT
+@ stdcall AVIFileInfoA(ptr ptr long)
+@ stdcall AVIFileInfoW(ptr ptr long)
+@ stdcall AVIFileInit()
+@ stdcall AVIFileOpen(ptr str long ptr) AVIFileOpenA
+@ stdcall AVIFileOpenA(ptr str long ptr)
+@ stdcall AVIFileOpenW(ptr wstr long ptr)
+@ stdcall AVIFileReadData(ptr long ptr ptr)
+@ stdcall AVIFileRelease(ptr)
+@ stdcall AVIFileWriteData(ptr long ptr long)
+@ stdcall AVIGetFromClipboard(ptr)
+@ stdcall AVIMakeCompressedStream(ptr ptr ptr ptr)
+@ stdcall AVIMakeFileFromStreams(ptr long ptr)
+@ stdcall AVIMakeStreamFromClipboard(long long ptr)
+@ stdcall AVIPutFileOnClipboard(ptr)
+@ varargs AVISave(str ptr ptr long ptr ptr) AVISaveA
+@ varargs AVISaveA(str ptr ptr long ptr ptr)
+@ stdcall AVISaveOptions(long long long ptr ptr)
+@ stdcall AVISaveOptionsFree(long ptr)
+@ stdcall AVISaveV(str ptr ptr long ptr ptr) AVISaveVA
+@ stdcall AVISaveVA(str ptr ptr long ptr ptr)
+@ stdcall AVISaveVW(wstr ptr ptr long ptr ptr)
+@ varargs AVISaveW(wstr ptr ptr long ptr ptr)
+@ stdcall AVIStreamAddRef(ptr)
+@ stdcall AVIStreamBeginStreaming(ptr long long long)
+@ stdcall AVIStreamCreate(ptr long long ptr)
+@ stdcall AVIStreamEndStreaming(ptr)
+@ stdcall AVIStreamFindSample(ptr long long)
+@ stdcall AVIStreamGetFrame(ptr long)
+@ stdcall AVIStreamGetFrameClose(ptr)
+@ stdcall AVIStreamGetFrameOpen(ptr ptr)
+@ stdcall AVIStreamInfo (ptr ptr long) AVIStreamInfoA
+@ stdcall AVIStreamInfoA(ptr ptr long)
+@ stdcall AVIStreamInfoW(ptr ptr long)
+@ stdcall AVIStreamLength(ptr)
+@ stdcall AVIStreamOpenFromFile (ptr str long long long ptr) AVIStreamOpenFromFileA
+@ stdcall AVIStreamOpenFromFileA(ptr str long long long ptr)
+@ stdcall AVIStreamOpenFromFileW(ptr wstr long long long ptr)
+@ stdcall AVIStreamRead(ptr long long ptr long ptr ptr)
+@ stdcall AVIStreamReadData(ptr long ptr ptr)
+@ stdcall AVIStreamReadFormat(ptr long ptr long)
+@ stdcall AVIStreamRelease(ptr)
+@ stdcall AVIStreamSampleToTime(ptr long)
+@ stdcall AVIStreamSetFormat(ptr long ptr long)
+@ stdcall AVIStreamStart(ptr)
+@ stdcall AVIStreamTimeToSample(ptr long)
+@ stdcall AVIStreamWrite(ptr long long ptr long long ptr ptr)
+@ stdcall AVIStreamWriteData(ptr long ptr long)
+@ extern CLSID_AVISimpleUnMarshal
+@ stdcall CreateEditableStream(ptr ptr)
+@ stdcall -private DllCanUnloadNow()
+@ stdcall -private DllGetClassObject(ptr ptr ptr)
+@ stdcall -private DllRegisterServer()
+@ stdcall -private DllUnregisterServer()
+@ stdcall EditStreamClone(ptr ptr)
+@ stdcall EditStreamCopy(ptr ptr ptr ptr)
+@ stdcall EditStreamCut(ptr ptr ptr ptr)
+@ stdcall EditStreamPaste(ptr ptr ptr ptr long long)
+@ stdcall EditStreamSetInfo(ptr ptr long) EditStreamSetInfoA
+@ stdcall EditStreamSetInfoA(ptr ptr long)
+@ stdcall EditStreamSetInfoW(ptr ptr long)
+@ stdcall EditStreamSetName(ptr str) EditStreamSetNameA
+@ stdcall EditStreamSetNameA(ptr str)
+@ stdcall EditStreamSetNameW(ptr wstr)
+@ extern IID_IAVIEditStream
+@ extern IID_IAVIFile
+@ extern IID_IAVIStream
+@ extern IID_IGetFrame
--- /dev/null
+<module name="avifil32" type="win32dll" baseaddress="${BASEADDRESS_AVIFIL32}" installbase="system32" installname="avifil32.dll">
+ <importlibrary definition="avifil32.spec.def" />
+ <include base="avifil32">.</include>
+ <include base="ReactOS">include/wine</include>
+ <define name="__USE_W32API" />
+ <define name="_WIN32_WINNT">0x501</define>
+ <library>uuid</library>
+ <library>ntdll</library>
+ <library>winmm</library>
+ <library>ole32</library>
+ <library>msvfw32</library>
+ <library>msacm32</library>
+ <library>kernel32</library>
+ <library>wine</library>
+ <file>acmstream.c</file>
+ <file>api.c</file>
+ <file>avifile.c</file>
+ <file>editstream.c</file>
+ <file>extrachunk.c</file>
+ <file>factory.c</file>
+ <file>getframe.c</file>
+ <file>icmstream.c</file>
+ <file>regsvr.c</file>
+ <file>tmpfile.c</file>
+ <file>wavfile.c</file>
+ <file>rsrc.rc</file>
+ <file>avifil32.spec</file>
+</module>
--- /dev/null
+/*
+ * Copyright 1999 Marcus Meissner
+ * Copyright 2002-2003 Michael Günnewig
+ *
+ * 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
+ */
+
+/* TODO:
+ * - IAVIStreaming interface is missing for the IAVIStreamImpl
+ * - IAVIStream_fnFindSample: FIND_INDEX isn't supported.
+ * - IAVIStream_fnReadFormat: formatchanges aren't read in.
+ * - IAVIStream_fnDelete: a stub.
+ * - IAVIStream_fnSetInfo: a stub.
+ * - make thread safe
+ *
+ * KNOWN Bugs:
+ * - native version can hangup when reading a file generated with this DLL.
+ * When index is missing it works, but index seems to be okay.
+ */
+
+#define COM_NO_WINDOWS_H
+#include <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "windowsx.h"
+#include "mmsystem.h"
+#include "vfw.h"
+
+#include "avifile_private.h"
+#include "extrachunk.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+#ifndef IDX_PER_BLOCK
+#define IDX_PER_BLOCK 2730
+#endif
+
+/***********************************************************************/
+
+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);
+
+static const struct IAVIFileVtbl iavift = {
+ IAVIFile_fnQueryInterface,
+ IAVIFile_fnAddRef,
+ IAVIFile_fnRelease,
+ IAVIFile_fnInfo,
+ IAVIFile_fnGetStream,
+ IAVIFile_fnCreateStream,
+ IAVIFile_fnWriteData,
+ IAVIFile_fnReadData,
+ IAVIFile_fnEndRecord,
+ IAVIFile_fnDeleteStream
+};
+
+static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile*iface,REFIID refiid,LPVOID*obj);
+static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile*iface);
+static ULONG WINAPI IPersistFile_fnRelease(IPersistFile*iface);
+static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile*iface,CLSID*pClassID);
+static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile*iface);
+static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile*iface,LPCOLESTR pszFileName,DWORD dwMode);
+static HRESULT WINAPI IPersistFile_fnSave(IPersistFile*iface,LPCOLESTR pszFileName,BOOL fRemember);
+static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile*iface,LPCOLESTR pszFileName);
+static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile*iface,LPOLESTR*ppszFileName);
+
+static const struct IPersistFileVtbl ipersistft = {
+ IPersistFile_fnQueryInterface,
+ IPersistFile_fnAddRef,
+ IPersistFile_fnRelease,
+ IPersistFile_fnGetClassID,
+ IPersistFile_fnIsDirty,
+ IPersistFile_fnLoad,
+ IPersistFile_fnSave,
+ IPersistFile_fnSaveCompleted,
+ IPersistFile_fnGetCurFile
+};
+
+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);
+
+static const struct IAVIStreamVtbl iavist = {
+ 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 _IAVIFileImpl IAVIFileImpl;
+
+typedef struct _IPersistFileImpl {
+ /* IUnknown stuff */
+ const IPersistFileVtbl *lpVtbl;
+
+ /* IPersistFile stuff */
+ IAVIFileImpl *paf;
+} IPersistFileImpl;
+
+typedef struct _IAVIStreamImpl {
+ /* IUnknown stuff */
+ const IAVIStreamVtbl *lpVtbl;
+ LONG ref;
+
+ /* IAVIStream stuff */
+ IAVIFileImpl *paf;
+ DWORD nStream; /* the n-th stream in file */
+ AVISTREAMINFOW sInfo;
+
+ LPVOID lpFormat;
+ DWORD cbFormat;
+
+ LPVOID lpHandlerData;
+ DWORD cbHandlerData;
+
+ EXTRACHUNKS extra;
+
+ LPDWORD lpBuffer;
+ DWORD cbBuffer; /* size of lpBuffer */
+ DWORD dwCurrentFrame; /* frame/block currently in lpBuffer */
+
+ LONG lLastFrame; /* last correct index in idxFrames */
+ AVIINDEXENTRY *idxFrames;
+ DWORD nIdxFrames; /* upper index limit of idxFrames */
+ AVIINDEXENTRY *idxFmtChanges;
+ DWORD nIdxFmtChanges; /* upper index limit of idxFmtChanges */
+} IAVIStreamImpl;
+
+struct _IAVIFileImpl {
+ /* IUnknown stuff */
+ const IAVIFileVtbl *lpVtbl;
+ LONG ref;
+
+ /* IAVIFile stuff... */
+ IPersistFileImpl iPersistFile;
+
+ AVIFILEINFOW fInfo;
+ IAVIStreamImpl *ppStreams[MAX_AVISTREAMS];
+
+ EXTRACHUNKS fileextra;
+
+ DWORD dwMoviChunkPos; /* some stuff for saving ... */
+ DWORD dwIdxChunkPos;
+ DWORD dwNextFramePos;
+ DWORD dwInitialFrames;
+
+ MMCKINFO ckLastRecord;
+ AVIINDEXENTRY *idxRecords; /* won't be updated while loading */
+ DWORD nIdxRecords; /* current fill level */
+ DWORD cbIdxRecords; /* size of idxRecords */
+
+ /* IPersistFile stuff ... */
+ HMMIO hmmio;
+ LPWSTR szFileName;
+ UINT uMode;
+ BOOL fDirty;
+};
+
+/***********************************************************************/
+
+static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size,
+ DWORD offset, DWORD flags);
+static HRESULT AVIFILE_AddRecord(IAVIFileImpl *This);
+static DWORD AVIFILE_ComputeMoviStart(IAVIFileImpl *This);
+static void AVIFILE_ConstructAVIStream(IAVIFileImpl *paf, DWORD nr,
+ LPAVISTREAMINFOW asi);
+static void AVIFILE_DestructAVIStream(IAVIStreamImpl *This);
+static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This);
+static HRESULT AVIFILE_LoadIndex(IAVIFileImpl *This, DWORD size, DWORD offset);
+static HRESULT AVIFILE_ParseIndex(IAVIFileImpl *This, AVIINDEXENTRY *lp,
+ LONG count, DWORD pos, BOOL *bAbsolute);
+static HRESULT AVIFILE_ReadBlock(IAVIStreamImpl *This, DWORD start,
+ LPVOID buffer, LONG size);
+static void AVIFILE_SamplesToBlock(IAVIStreamImpl *This, LPLONG pos,
+ LPLONG offset);
+static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This);
+static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This);
+static ULONG AVIFILE_SearchStream(IAVIFileImpl *This, DWORD fccType,
+ LONG lSkip);
+static void AVIFILE_UpdateInfo(IAVIFileImpl *This);
+static HRESULT AVIFILE_WriteBlock(IAVIStreamImpl *This, DWORD block,
+ FOURCC ckid, DWORD flags, LPVOID buffer,
+ LONG size);
+
+HRESULT AVIFILE_CreateAVIFile(REFIID riid, LPVOID *ppv)
+{
+ IAVIFileImpl *pfile;
+ HRESULT hr;
+
+ assert(riid != NULL && ppv != NULL);
+
+ *ppv = NULL;
+
+ pfile = (IAVIFileImpl*)LocalAlloc(LPTR, sizeof(IAVIFileImpl));
+ if (pfile == NULL)
+ return AVIERR_MEMORY;
+
+ pfile->lpVtbl = &iavift;
+ pfile->ref = 0;
+ pfile->iPersistFile.lpVtbl = &ipersistft;
+ pfile->iPersistFile.paf = pfile;
+
+ hr = IAVIFile_QueryInterface((IAVIFile*)pfile, riid, ppv);
+ if (FAILED(hr))
+ LocalFree((HLOCAL)pfile);
+
+ return hr;
+}
+
+static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile *iface, REFIID refiid,
+ LPVOID *obj)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,%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;
+ } else if (IsEqualGUID(&IID_IPersistFile, refiid)) {
+ *obj = &This->iPersistFile;
+ IAVIFile_AddRef(iface);
+
+ return S_OK;
+ }
+
+ return OLE_E_ENUM_NOMORE;
+}
+
+static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+ UINT i;
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ if (!ref) {
+ if (This->fDirty) {
+ /* need to write headers to file */
+ AVIFILE_SaveFile(This);
+ }
+
+ for (i = 0; i < This->fInfo.dwStreams; i++) {
+ if (This->ppStreams[i] != NULL) {
+ if (This->ppStreams[i]->ref != 0) {
+ ERR(": someone has still %lu reference to stream %u (%p)!\n",
+ This->ppStreams[i]->ref, i, This->ppStreams[i]);
+ }
+ AVIFILE_DestructAVIStream(This->ppStreams[i]);
+ LocalFree((HLOCAL)This->ppStreams[i]);
+ This->ppStreams[i] = NULL;
+ }
+ }
+
+ if (This->idxRecords != NULL) {
+ GlobalFreePtr(This->idxRecords);
+ This->idxRecords = NULL;
+ This->nIdxRecords = 0;
+ }
+
+ if (This->fileextra.lp != NULL) {
+ GlobalFreePtr(This->fileextra.lp);
+ This->fileextra.lp = NULL;
+ This->fileextra.cb = 0;
+ }
+
+ if (This->szFileName != NULL) {
+ LocalFree((HLOCAL)This->szFileName);
+ This->szFileName = NULL;
+ }
+ if (This->hmmio != NULL) {
+ mmioClose(This->hmmio, 0);
+ This->hmmio = NULL;
+ }
+
+ LocalFree((HLOCAL)This);
+ }
+ return ref;
+}
+
+static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile *iface, LPAVIFILEINFOW afi,
+ LONG size)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,%p,%ld)\n",iface,afi,size);
+
+ if (afi == NULL)
+ return AVIERR_BADPARAM;
+ if (size < 0)
+ return AVIERR_BADSIZE;
+
+ AVIFILE_UpdateInfo(This);
+
+ memcpy(afi, &This->fInfo, min((DWORD)size, sizeof(This->fInfo)));
+
+ if ((DWORD)size < sizeof(This->fInfo))
+ return AVIERR_BUFFERTOOSMALL;
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile *iface, PAVISTREAM *avis,
+ DWORD fccType, LONG lParam)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ ULONG nStream;
+
+ TRACE("(%p,%p,0x%08lX,%ld)\n", iface, avis, fccType, lParam);
+
+ if (avis == NULL || lParam < 0)
+ return AVIERR_BADPARAM;
+
+ nStream = AVIFILE_SearchStream(This, fccType, lParam);
+
+ /* Does the requested stream exist? */
+ if (nStream < This->fInfo.dwStreams &&
+ This->ppStreams[nStream] != NULL) {
+ *avis = (PAVISTREAM)This->ppStreams[nStream];
+ IAVIStream_AddRef(*avis);
+
+ return AVIERR_OK;
+ }
+
+ /* Sorry, but the specified stream doesn't exist */
+ return AVIERR_NODATA;
+}
+
+static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile *iface,PAVISTREAM *avis,
+ LPAVISTREAMINFOW asi)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ DWORD n;
+
+ TRACE("(%p,%p,%p)\n", iface, avis, asi);
+
+ /* check parameters */
+ if (avis == NULL || asi == NULL)
+ return AVIERR_BADPARAM;
+
+ *avis = NULL;
+
+ /* Does the user have write permission? */
+ if ((This->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ /* Can we add another stream? */
+ n = This->fInfo.dwStreams;
+ if (n >= MAX_AVISTREAMS || This->dwMoviChunkPos != 0) {
+ /* already reached max nr of streams
+ * or have already written frames to disk */
+ return AVIERR_UNSUPPORTED;
+ }
+
+ /* check AVISTREAMINFO for some really needed things */
+ if (asi->fccType == 0 || asi->dwScale == 0 || asi->dwRate == 0)
+ return AVIERR_BADFORMAT;
+
+ /* now it seems to be save to add the stream */
+ assert(This->ppStreams[n] == NULL);
+ This->ppStreams[n] = (IAVIStreamImpl*)LocalAlloc(LPTR,
+ sizeof(IAVIStreamImpl));
+ if (This->ppStreams[n] == NULL)
+ return AVIERR_MEMORY;
+
+ /* initialize the new allocated stream */
+ AVIFILE_ConstructAVIStream(This, n, asi);
+
+ This->fInfo.dwStreams++;
+ This->fDirty = TRUE;
+
+ /* update our AVIFILEINFO structure */
+ AVIFILE_UpdateInfo(This);
+
+ /* return it */
+ *avis = (PAVISTREAM)This->ppStreams[n];
+ IAVIStream_AddRef(*avis);
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile *iface, DWORD ckid,
+ LPVOID lpData, LONG size)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,0x%08lX,%p,%ld)\n", iface, ckid, lpData, size);
+
+ /* check parameters */
+ if (lpData == NULL)
+ return AVIERR_BADPARAM;
+ if (size < 0)
+ return AVIERR_BADSIZE;
+
+ /* Do we have write permission? */
+ if ((This->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ This->fDirty = TRUE;
+
+ return WriteExtraChunk(&This->fileextra, ckid, lpData, size);
+}
+
+static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile *iface, DWORD ckid,
+ LPVOID lpData, LONG *size)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,0x%08lX,%p,%p)\n", iface, ckid, lpData, size);
+
+ return ReadExtraChunk(&This->fileextra, ckid, lpData, size);
+}
+
+static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p)\n",iface);
+
+ if ((This->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ This->fDirty = TRUE;
+
+ /* no frames written to any stream? -- compute start of 'movi'-chunk */
+ if (This->dwMoviChunkPos == 0)
+ AVIFILE_ComputeMoviStart(This);
+
+ This->fInfo.dwFlags |= AVIFILEINFO_ISINTERLEAVED;
+
+ /* already written frames to any stream, ... */
+ if (This->ckLastRecord.dwFlags & MMIO_DIRTY) {
+ /* close last record */
+ if (mmioAscend(This->hmmio, &This->ckLastRecord, 0) != 0)
+ return AVIERR_FILEWRITE;
+
+ AVIFILE_AddRecord(This);
+
+ if (This->fInfo.dwSuggestedBufferSize < This->ckLastRecord.cksize + 3 * sizeof(DWORD))
+ This->fInfo.dwSuggestedBufferSize = This->ckLastRecord.cksize + 3 * sizeof(DWORD);
+ }
+
+ /* write out a new record into file, but don't close it */
+ This->ckLastRecord.cksize = 0;
+ This->ckLastRecord.fccType = listtypeAVIRECORD;
+ if (mmioSeek(This->hmmio, This->dwNextFramePos, SEEK_SET) == -1)
+ return AVIERR_FILEWRITE;
+ if (mmioCreateChunk(This->hmmio, &This->ckLastRecord, MMIO_CREATELIST) != 0)
+ return AVIERR_FILEWRITE;
+ This->dwNextFramePos += 3 * sizeof(DWORD);
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile *iface, DWORD fccType,
+ LONG lParam)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ ULONG nStream;
+
+ TRACE("(%p,0x%08lX,%ld)\n", iface, fccType, lParam);
+
+ /* check parameter */
+ if (lParam < 0)
+ return AVIERR_BADPARAM;
+
+ /* Have user write permissions? */
+ if ((This->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ nStream = AVIFILE_SearchStream(This, fccType, lParam);
+
+ /* Does the requested stream exist? */
+ if (nStream < This->fInfo.dwStreams &&
+ This->ppStreams[nStream] != NULL) {
+ /* ... so delete it now */
+ LocalFree((HLOCAL)This->ppStreams[nStream]);
+
+ if (This->fInfo.dwStreams - nStream > 0)
+ memcpy(This->ppStreams + nStream, This->ppStreams + nStream + 1,
+ (This->fInfo.dwStreams - nStream) * sizeof(IAVIStreamImpl*));
+
+ This->ppStreams[This->fInfo.dwStreams] = NULL;
+ This->fInfo.dwStreams--;
+ This->fDirty = TRUE;
+
+ /* This->fInfo will be updated further when asked for */
+ return AVIERR_OK;
+ } else
+ return AVIERR_NODATA;
+}
+
+/***********************************************************************/
+
+static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile *iface,
+ REFIID refiid, LPVOID *obj)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ assert(This->paf != NULL);
+
+ return IAVIFile_QueryInterface((PAVIFILE)This->paf, refiid, obj);
+}
+
+static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile *iface)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ assert(This->paf != NULL);
+
+ return IAVIFile_AddRef((PAVIFILE)This->paf);
+}
+
+static ULONG WINAPI IPersistFile_fnRelease(IPersistFile *iface)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ assert(This->paf != NULL);
+
+ return IAVIFile_Release((PAVIFILE)This->paf);
+}
+
+static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile *iface,
+ LPCLSID pClassID)
+{
+ TRACE("(%p,%p)\n", iface, pClassID);
+
+ if (pClassID == NULL)
+ return AVIERR_BADPARAM;
+
+ memcpy(pClassID, &CLSID_AVIFile, sizeof(CLSID_AVIFile));
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile *iface)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ TRACE("(%p)\n", iface);
+
+ assert(This->paf != NULL);
+
+ return (This->paf->fDirty ? S_OK : S_FALSE);
+}
+
+static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile *iface,
+ LPCOLESTR pszFileName, DWORD dwMode)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ int len;
+
+ TRACE("(%p,%s,0x%08lX)\n", iface, debugstr_w(pszFileName), dwMode);
+
+ /* check parameter */
+ if (pszFileName == NULL)
+ return AVIERR_BADPARAM;
+
+ assert(This->paf != NULL);
+ if (This->paf->hmmio != NULL)
+ return AVIERR_ERROR; /* No reuse of this object for another file! */
+
+ /* remeber mode and name */
+ This->paf->uMode = dwMode;
+
+ len = lstrlenW(pszFileName) + 1;
+ This->paf->szFileName = (LPWSTR)LocalAlloc(LPTR, len * sizeof(WCHAR));
+ if (This->paf->szFileName == NULL)
+ return AVIERR_MEMORY;
+ lstrcpyW(This->paf->szFileName, pszFileName);
+
+ /* try to open the file */
+ This->paf->hmmio = mmioOpenW(This->paf->szFileName, NULL,
+ MMIO_ALLOCBUF | dwMode);
+ if (This->paf->hmmio == NULL) {
+ /* mmioOpenW not in native DLLs of Win9x -- try mmioOpenA */
+ LPSTR szFileName;
+
+ len = WideCharToMultiByte(CP_ACP, 0, This->paf->szFileName, -1,
+ NULL, 0, NULL, NULL);
+ szFileName = LocalAlloc(LPTR, len * sizeof(CHAR));
+ if (szFileName == NULL)
+ return AVIERR_MEMORY;
+
+ WideCharToMultiByte(CP_ACP, 0, This->paf->szFileName, -1, szFileName,
+ len, NULL, NULL);
+
+ This->paf->hmmio = mmioOpenA(szFileName, NULL, MMIO_ALLOCBUF | dwMode);
+ LocalFree((HLOCAL)szFileName);
+ if (This->paf->hmmio == NULL)
+ return AVIERR_FILEOPEN;
+ }
+
+ /* should we create a new file? */
+ if (dwMode & OF_CREATE) {
+ memset(& This->paf->fInfo, 0, sizeof(This->paf->fInfo));
+ This->paf->fInfo.dwFlags = AVIFILEINFO_HASINDEX | AVIFILEINFO_TRUSTCKTYPE;
+
+ return AVIERR_OK;
+ } else
+ return AVIFILE_LoadFile(This->paf);
+}
+
+static HRESULT WINAPI IPersistFile_fnSave(IPersistFile *iface,
+ LPCOLESTR pszFileName,BOOL fRemember)
+{
+ TRACE("(%p,%s,%d)\n", iface, debugstr_w(pszFileName), fRemember);
+
+ /* We write directly to disk, so nothing to do. */
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile *iface,
+ LPCOLESTR pszFileName)
+{
+ TRACE("(%p,%s)\n", iface, debugstr_w(pszFileName));
+
+ /* We write directly to disk, so nothing to do. */
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile *iface,
+ LPOLESTR *ppszFileName)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ TRACE("(%p,%p)\n", iface, ppszFileName);
+
+ if (ppszFileName == NULL)
+ return AVIERR_BADPARAM;
+
+ *ppszFileName = NULL;
+
+ assert(This->paf != NULL);
+
+ if (This->paf->szFileName != NULL) {
+ int len = lstrlenW(This->paf->szFileName) + 1;
+
+ *ppszFileName = (LPOLESTR)GlobalAllocPtr(GHND, len * sizeof(WCHAR));
+ if (*ppszFileName == NULL)
+ return AVIERR_MEMORY;
+
+ strcpyW(*ppszFileName, This->paf->szFileName);
+ }
+
+ return AVIERR_OK;
+}
+
+/***********************************************************************/
+
+static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream *iface,
+ REFIID refiid, LPVOID *obj)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%s,%p)\n", iface, debugstr_guid(refiid), obj);
+
+ if (IsEqualGUID(&IID_IUnknown, refiid) ||
+ IsEqualGUID(&IID_IAVIStream, refiid)) {
+ *obj = This;
+ IAVIStream_AddRef(iface);
+
+ return S_OK;
+ }
+ /* FIXME: IAVIStreaming interface */
+
+ return OLE_E_ENUM_NOMORE;
+}
+
+static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream *iface)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ /* also add ref to parent, so that it doesn't kill us */
+ if (This->paf != NULL)
+ IAVIFile_AddRef((PAVIFILE)This->paf);
+
+ return ref;
+}
+
+static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ if (This->paf != NULL)
+ IAVIFile_Release((PAVIFILE)This->paf);
+
+ return ref;
+}
+
+static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
+ LPARAM lParam2)
+{
+ TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
+
+ /* This IAVIStream interface needs an AVIFile */
+ return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
+ LONG size)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%p,%ld)\n", iface, psi, size);
+
+ if (psi == NULL)
+ return AVIERR_BADPARAM;
+ if (size < 0)
+ return AVIERR_BADSIZE;
+
+ memcpy(psi, &This->sInfo, min((DWORD)size, sizeof(This->sInfo)));
+
+ if ((DWORD)size < sizeof(This->sInfo))
+ return AVIERR_BUFFERTOOSMALL;
+ return AVIERR_OK;
+}
+
+static LONG WINAPI IAVIStream_fnFindSample(IAVIStream *iface, LONG pos,
+ LONG flags)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ LONG offset = 0;
+
+ TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
+
+ if (flags & FIND_FROM_START) {
+ pos = This->sInfo.dwStart;
+ flags &= ~(FIND_FROM_START|FIND_PREV);
+ flags |= FIND_NEXT;
+ }
+
+ if (This->sInfo.dwSampleSize != 0) {
+ /* convert samples into block number with offset */
+ AVIFILE_SamplesToBlock(This, &pos, &offset);
+ }
+
+ if (flags & FIND_TYPE) {
+ if (flags & FIND_KEY) {
+ while (0 <= pos && pos <= This->lLastFrame) {
+ if (This->idxFrames[pos].dwFlags & AVIIF_KEYFRAME)
+ goto RETURN_FOUND;
+
+ if (flags & FIND_NEXT)
+ pos++;
+ else
+ pos--;
+ };
+ } else if (flags & FIND_ANY) {
+ while (0 <= pos && pos <= This->lLastFrame) {
+ if (This->idxFrames[pos].dwChunkLength > 0)
+ goto RETURN_FOUND;
+
+ if (flags & FIND_NEXT)
+ pos++;
+ else
+ pos--;
+
+ };
+ } else if ((flags & FIND_FORMAT) && This->idxFmtChanges != NULL &&
+ This->sInfo.fccType == streamtypeVIDEO) {
+ if (flags & FIND_NEXT) {
+ ULONG n;
+
+ for (n = 0; n < This->sInfo.dwFormatChangeCount; n++)
+ if (This->idxFmtChanges[n].ckid >= pos) {
+ pos = This->idxFmtChanges[n].ckid;
+ goto RETURN_FOUND;
+ }
+ } else {
+ LONG n;
+
+ for (n = (LONG)This->sInfo.dwFormatChangeCount; n >= 0; n--) {
+ if (This->idxFmtChanges[n].ckid <= pos) {
+ pos = This->idxFmtChanges[n].ckid;
+ goto RETURN_FOUND;
+ }
+ }
+
+ if (pos > (LONG)This->sInfo.dwStart)
+ return 0; /* format changes always for first frame */
+ }
+ }
+
+ return -1;
+ }
+
+ RETURN_FOUND:
+ if (pos < (LONG)This->sInfo.dwStart)
+ return -1;
+
+ switch (flags & FIND_RET) {
+ case FIND_LENGTH:
+ /* physical size */
+ pos = This->idxFrames[pos].dwChunkLength;
+ break;
+ case FIND_OFFSET:
+ /* physical position */
+ pos = This->idxFrames[pos].dwChunkOffset + 2 * sizeof(DWORD)
+ + offset * This->sInfo.dwSampleSize;
+ break;
+ case FIND_SIZE:
+ /* logical size */
+ if (This->sInfo.dwSampleSize)
+ pos = This->sInfo.dwSampleSize;
+ else
+ pos = 1;
+ break;
+ case FIND_INDEX:
+ FIXME(": FIND_INDEX flag is not supported!\n");
+ /* This is an index in the index-table on disc. */
+ break;
+ }; /* else logical position */
+
+ return pos;
+}
+
+static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream *iface, LONG pos,
+ LPVOID format, LONG *formatsize)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%ld,%p,%p)\n", iface, pos, format, formatsize);
+
+ if (formatsize == NULL)
+ return AVIERR_BADPARAM;
+
+ /* only interested in needed buffersize? */
+ if (format == NULL || *formatsize <= 0) {
+ *formatsize = This->cbFormat;
+
+ return AVIERR_OK;
+ }
+
+ /* copy initial format (only as much as will fit) */
+ memcpy(format, This->lpFormat, min(*(DWORD*)formatsize, This->cbFormat));
+ if (*(DWORD*)formatsize < This->cbFormat) {
+ *formatsize = This->cbFormat;
+ return AVIERR_BUFFERTOOSMALL;
+ }
+
+ /* Could format change? When yes will it change? */
+ if ((This->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
+ pos > This->sInfo.dwStart) {
+ LONG lLastFmt;
+
+ lLastFmt = IAVIStream_fnFindSample(iface, pos, FIND_FORMAT|FIND_PREV);
+ if (lLastFmt > 0) {
+ FIXME(": need to read formatchange for %ld -- unimplemented!\n",lLastFmt);
+ }
+ }
+
+ *formatsize = This->cbFormat;
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream *iface, LONG pos,
+ LPVOID format, LONG formatsize)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ LPBITMAPINFOHEADER lpbiNew = (LPBITMAPINFOHEADER)format;
+
+ TRACE("(%p,%ld,%p,%ld)\n", iface, pos, format, formatsize);
+
+ /* check parameters */
+ if (format == NULL || formatsize <= 0)
+ return AVIERR_BADPARAM;
+
+ /* Do we have write permission? */
+ if ((This->paf->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ /* can only set format before frame is written! */
+ if (This->lLastFrame > pos)
+ return AVIERR_UNSUPPORTED;
+
+ /* initial format or a formatchange? */
+ if (This->lpFormat == NULL) {
+ /* initial format */
+ if (This->paf->dwMoviChunkPos != 0)
+ return AVIERR_ERROR; /* user has used API in wrong sequnece! */
+
+ This->lpFormat = GlobalAllocPtr(GMEM_MOVEABLE, formatsize);
+ if (This->lpFormat == NULL)
+ return AVIERR_MEMORY;
+ This->cbFormat = formatsize;
+
+ memcpy(This->lpFormat, format, formatsize);
+
+ /* update some infos about stream */
+ if (This->sInfo.fccType == streamtypeVIDEO) {
+ LONG lDim;
+
+ lDim = This->sInfo.rcFrame.right - This->sInfo.rcFrame.left;
+ if (lDim < lpbiNew->biWidth)
+ This->sInfo.rcFrame.right = This->sInfo.rcFrame.left + lpbiNew->biWidth;
+ lDim = This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top;
+ if (lDim < lpbiNew->biHeight)
+ This->sInfo.rcFrame.bottom = This->sInfo.rcFrame.top + lpbiNew->biHeight;
+ } else if (This->sInfo.fccType == streamtypeAUDIO)
+ This->sInfo.dwSampleSize = ((LPWAVEFORMATEX)This->lpFormat)->nBlockAlign;
+
+ return AVIERR_OK;
+ } else {
+ MMCKINFO ck;
+ LPBITMAPINFOHEADER lpbiOld = (LPBITMAPINFOHEADER)This->lpFormat;
+ RGBQUAD *rgbNew = (RGBQUAD*)((LPBYTE)lpbiNew + lpbiNew->biSize);
+ AVIPALCHANGE *lppc = NULL;
+ UINT n;
+
+ /* perhaps format change, check it ... */
+ if (This->cbFormat != formatsize)
+ return AVIERR_UNSUPPORTED;
+
+ /* no format change, only the initial one */
+ if (memcmp(This->lpFormat, format, formatsize) == 0)
+ return AVIERR_OK;
+
+ /* check that's only the palette, which changes */
+ if (lpbiOld->biSize != lpbiNew->biSize ||
+ lpbiOld->biWidth != lpbiNew->biWidth ||
+ lpbiOld->biHeight != lpbiNew->biHeight ||
+ lpbiOld->biPlanes != lpbiNew->biPlanes ||
+ lpbiOld->biBitCount != lpbiNew->biBitCount ||
+ lpbiOld->biCompression != lpbiNew->biCompression ||
+ lpbiOld->biClrUsed != lpbiNew->biClrUsed)
+ return AVIERR_UNSUPPORTED;
+
+ This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
+
+ /* simply say all colors have changed */
+ ck.ckid = MAKEAVICKID(cktypePALchange, This->nStream);
+ ck.cksize = 2 * sizeof(WORD) + lpbiOld->biClrUsed * sizeof(PALETTEENTRY);
+ lppc = (AVIPALCHANGE*)GlobalAllocPtr(GMEM_MOVEABLE, ck.cksize);
+ if (lppc == NULL)
+ return AVIERR_MEMORY;
+
+ lppc->bFirstEntry = 0;
+ lppc->bNumEntries = (lpbiOld->biClrUsed < 256 ? lpbiOld->biClrUsed : 0);
+ lppc->wFlags = 0;
+ for (n = 0; n < lpbiOld->biClrUsed; n++) {
+ lppc->peNew[n].peRed = rgbNew[n].rgbRed;
+ lppc->peNew[n].peGreen = rgbNew[n].rgbGreen;
+ lppc->peNew[n].peBlue = rgbNew[n].rgbBlue;
+ lppc->peNew[n].peFlags = 0;
+ }
+
+ if (mmioSeek(This->paf->hmmio, This->paf->dwNextFramePos, SEEK_SET) == -1)
+ return AVIERR_FILEWRITE;
+ if (mmioCreateChunk(This->paf->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (mmioWrite(This->paf->hmmio, (HPSTR)lppc, ck.cksize) != ck.cksize)
+ return AVIERR_FILEWRITE;
+ if (mmioAscend(This->paf->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ This->paf->dwNextFramePos += ck.cksize + 2 * sizeof(DWORD);
+
+ GlobalFreePtr(lppc);
+
+ return AVIFILE_AddFrame(This, cktypePALchange, n, ck.dwDataOffset, 0);
+ }
+}
+
+static HRESULT WINAPI IAVIStream_fnRead(IAVIStream *iface, LONG start,
+ LONG samples, LPVOID buffer,
+ LONG buffersize, LPLONG bytesread,
+ LPLONG samplesread)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ DWORD size;
+ HRESULT hr;
+
+ TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface, start, samples, buffer,
+ buffersize, bytesread, samplesread);
+
+ /* clear return parameters if given */
+ if (bytesread != NULL)
+ *bytesread = 0;
+ if (samplesread != NULL)
+ *samplesread = 0;
+
+ /* check parameters */
+ if ((LONG)This->sInfo.dwStart > start)
+ return AVIERR_NODATA; /* couldn't read before start of stream */
+ if (This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
+ return AVIERR_NODATA; /* start is past end of stream */
+
+ /* should we read as much as possible? */
+ if (samples == -1) {
+ /* User should know how much we have read */
+ if (bytesread == NULL && samplesread == NULL)
+ return AVIERR_BADPARAM;
+
+ if (This->sInfo.dwSampleSize != 0)
+ samples = buffersize / This->sInfo.dwSampleSize;
+ else
+ samples = 1;
+ }
+
+ /* limit to end of stream */
+ if ((LONG)This->sInfo.dwLength < samples)
+ samples = This->sInfo.dwLength;
+ if ((start - This->sInfo.dwStart) > (This->sInfo.dwLength - samples))
+ samples = This->sInfo.dwLength - (start - This->sInfo.dwStart);
+
+ /* nothing to read? Then leave ... */
+ if (samples == 0)
+ return AVIERR_OK;
+
+ if (This->sInfo.dwSampleSize != 0) {
+ /* fixed samplesize -- we can read over frame/block boundaries */
+ LONG block = start;
+ LONG offset = 0;
+
+ /* convert start sample to block,offset pair */
+ AVIFILE_SamplesToBlock(This, &block, &offset);
+
+ /* convert samples to bytes */
+ samples *= This->sInfo.dwSampleSize;
+
+ while (samples > 0 && buffersize > 0) {
+ if (block != This->dwCurrentFrame) {
+ hr = AVIFILE_ReadBlock(This, block, NULL, 0);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ size = min((DWORD)samples, (DWORD)buffersize);
+ size = min(size, This->cbBuffer - offset);
+ memcpy(buffer, ((BYTE*)&This->lpBuffer[2]) + offset, size);
+
+ block++;
+ offset = 0;
+ buffer = ((LPBYTE)buffer)+size;
+ samples -= size;
+ buffersize -= size;
+
+ /* fill out return parameters if given */
+ if (bytesread != NULL)
+ *bytesread += size;
+ if (samplesread != NULL)
+ *samplesread += size / This->sInfo.dwSampleSize;
+ }
+
+ if (samples == 0)
+ return AVIERR_OK;
+ else
+ return AVIERR_BUFFERTOOSMALL;
+ } else {
+ /* variable samplesize -- we can only read one full frame/block */
+ if (samples > 1)
+ samples = 1;
+
+ assert(start <= This->lLastFrame);
+ size = This->idxFrames[start].dwChunkLength;
+ if (buffer != NULL && buffersize >= size) {
+ hr = AVIFILE_ReadBlock(This, start, buffer, size);
+ if (FAILED(hr))
+ return hr;
+ } else if (buffer != NULL)
+ return AVIERR_BUFFERTOOSMALL;
+
+ /* fill out return parameters if given */
+ if (bytesread != NULL)
+ *bytesread = size;
+ if (samplesread != NULL)
+ *samplesread = samples;
+
+ return AVIERR_OK;
+ }
+}
+
+static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream *iface, LONG start,
+ LONG samples, LPVOID buffer,
+ LONG buffersize, DWORD flags,
+ LPLONG sampwritten,
+ LPLONG byteswritten)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ FOURCC ckid;
+ HRESULT hr;
+
+ TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface, start, samples,
+ buffer, buffersize, flags, sampwritten, byteswritten);
+
+ /* clear return parameters if given */
+ if (sampwritten != NULL)
+ *sampwritten = 0;
+ if (byteswritten != NULL)
+ *byteswritten = 0;
+
+ /* check parameters */
+ if (buffer == NULL && (buffersize > 0 || samples > 0))
+ return AVIERR_BADPARAM;
+
+ /* Have we write permission? */
+ if ((This->paf->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ switch (This->sInfo.fccType) {
+ case streamtypeAUDIO:
+ ckid = MAKEAVICKID(cktypeWAVEbytes, This->nStream);
+ break;
+ default:
+ if ((flags & AVIIF_KEYFRAME) && buffersize != 0)
+ ckid = MAKEAVICKID(cktypeDIBbits, This->nStream);
+ else
+ ckid = MAKEAVICKID(cktypeDIBcompressed, This->nStream);
+ break;
+ };
+
+ /* append to end of stream? */
+ if (start == -1) {
+ if (This->lLastFrame == -1)
+ start = This->sInfo.dwStart;
+ else
+ start = This->sInfo.dwLength;
+ } else if (This->lLastFrame == -1)
+ This->sInfo.dwStart = start;
+
+ if (This->sInfo.dwSampleSize != 0) {
+ /* fixed sample size -- audio like */
+ if (samples * This->sInfo.dwSampleSize != buffersize)
+ return AVIERR_BADPARAM;
+
+ /* Couldn't skip audio-like data -- User must supply appropriate silence */
+ if (This->sInfo.dwLength != start)
+ return AVIERR_UNSUPPORTED;
+
+ /* Convert position to frame/block */
+ start = This->lLastFrame + 1;
+
+ if ((This->paf->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) == 0) {
+ FIXME(": not interleaved, could collect audio data!\n");
+ }
+ } else {
+ /* variable sample size -- video like */
+ if (samples > 1)
+ return AVIERR_UNSUPPORTED;
+
+ /* must we fill up with empty frames? */
+ if (This->lLastFrame != -1) {
+ FOURCC ckid2 = MAKEAVICKID(cktypeDIBcompressed, This->nStream);
+
+ while (start > This->lLastFrame + 1) {
+ hr = AVIFILE_WriteBlock(This, This->lLastFrame + 1, ckid2, 0, NULL, 0);
+ if (FAILED(hr))
+ return hr;
+ }
+ }
+ }
+
+ /* write the block now */
+ hr = AVIFILE_WriteBlock(This, start, ckid, flags, buffer, buffersize);
+ if (SUCCEEDED(hr)) {
+ /* fill out return parameters if given */
+ if (sampwritten != NULL)
+ *sampwritten = samples;
+ if (byteswritten != NULL)
+ *byteswritten = buffersize;
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream *iface, LONG start,
+ LONG samples)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ FIXME("(%p,%ld,%ld): stub\n", iface, start, samples);
+
+ /* check parameters */
+ if (start < 0 || samples < 0)
+ return AVIERR_BADPARAM;
+
+ /* Delete before start of stream? */
+ if (start + samples < This->sInfo.dwStart)
+ return AVIERR_OK;
+
+ /* Delete after end of stream? */
+ if (start > This->sInfo.dwLength)
+ return AVIERR_OK;
+
+ /* For the rest we need write permissions */
+ if ((This->paf->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ /* 1. overwrite the data with JUNK
+ *
+ * if ISINTERLEAVED {
+ * 2. concat all neighboured JUNK-blocks in this record to one
+ * 3. if this record only contains JUNK and is at end set dwNextFramePos
+ * to start of this record, repeat this.
+ * } else {
+ * 2. concat all neighboured JUNK-blocks.
+ * 3. if the JUNK block is at the end, then set dwNextFramePos to
+ * start of this block.
+ * }
+ */
+
+ return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream *iface, DWORD fcc,
+ LPVOID lp, LPLONG lpread)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,0x%08lX,%p,%p)\n", iface, fcc, lp, lpread);
+
+ if (fcc == ckidSTREAMHANDLERDATA) {
+ if (This->lpHandlerData != NULL && This->cbHandlerData > 0) {
+ if (lp == NULL || *lpread <= 0) {
+ *lpread = This->cbHandlerData;
+ return AVIERR_OK;
+ }
+
+ memcpy(lp, This->lpHandlerData, min(This->cbHandlerData, *lpread));
+ if (*lpread < This->cbHandlerData)
+ return AVIERR_BUFFERTOOSMALL;
+ return AVIERR_OK;
+ } else
+ return AVIERR_NODATA;
+ } else
+ return ReadExtraChunk(&This->extra, fcc, lp, lpread);
+}
+
+static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc,
+ LPVOID lp, LONG size)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,0x%08lx,%p,%ld)\n", iface, fcc, lp, size);
+
+ /* check parameters */
+ if (lp == NULL)
+ return AVIERR_BADPARAM;
+ if (size <= 0)
+ return AVIERR_BADSIZE;
+
+ /* need write permission */
+ if ((This->paf->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ /* already written something to this file? */
+ if (This->paf->dwMoviChunkPos != 0) {
+ /* the data will be inserted before the 'movi' chunk, so check for
+ * enough space */
+ DWORD dwPos = AVIFILE_ComputeMoviStart(This->paf);
+
+ /* ckid,size => 2 * sizeof(DWORD) */
+ dwPos += 2 * sizeof(DWORD) + size;
+ if (size >= This->paf->dwMoviChunkPos - 2 * sizeof(DWORD))
+ return AVIERR_UNSUPPORTED; /* not enough space left */
+ }
+
+ This->paf->fDirty = TRUE;
+
+ if (fcc == ckidSTREAMHANDLERDATA) {
+ if (This->lpHandlerData != NULL) {
+ FIXME(": handler data already set -- overwirte?\n");
+ return AVIERR_UNSUPPORTED;
+ }
+
+ This->lpHandlerData = GlobalAllocPtr(GMEM_MOVEABLE, size);
+ if (This->lpHandlerData == NULL)
+ return AVIERR_MEMORY;
+ This->cbHandlerData = size;
+ memcpy(This->lpHandlerData, lp, size);
+
+ return AVIERR_OK;
+ } else
+ return WriteExtraChunk(&This->extra, fcc, lp, size);
+}
+
+static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream *iface,
+ LPAVISTREAMINFOW info, LONG infolen)
+{
+ FIXME("(%p,%p,%ld): stub\n", iface, info, infolen);
+
+ return E_FAIL;
+}
+
+/***********************************************************************/
+
+static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size, DWORD offset, DWORD flags)
+{
+ /* pre-conditions */
+ assert(This != NULL);
+
+ switch (TWOCCFromFOURCC(ckid)) {
+ case cktypeDIBbits:
+ if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
+ flags |= AVIIF_KEYFRAME;
+ break;
+ case cktypeDIBcompressed:
+ if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
+ flags &= ~AVIIF_KEYFRAME;
+ break;
+ case cktypePALchange:
+ if (This->sInfo.fccType != streamtypeVIDEO) {
+ ERR(": found palette change in non-video stream!\n");
+ return AVIERR_BADFORMAT;
+ }
+ This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
+ This->sInfo.dwFormatChangeCount++;
+
+ if (This->idxFmtChanges == NULL || This->sInfo.dwFormatChangeCount < This->nIdxFmtChanges) {
+ UINT n = This->sInfo.dwFormatChangeCount;
+
+ This->nIdxFmtChanges += 16;
+ if (This->idxFmtChanges == NULL)
+ This->idxFmtChanges =
+ GlobalAllocPtr(GHND, This->nIdxFmtChanges * sizeof(AVIINDEXENTRY));
+ else
+ This->idxFmtChanges =
+ GlobalReAllocPtr(This->idxFmtChanges,
+ This->nIdxFmtChanges * sizeof(AVIINDEXENTRY), GHND);
+ if (This->idxFmtChanges == NULL)
+ return AVIERR_MEMORY;
+
+ This->idxFmtChanges[n].ckid = This->lLastFrame;
+ This->idxFmtChanges[n].dwFlags = 0;
+ This->idxFmtChanges[n].dwChunkOffset = offset;
+ This->idxFmtChanges[n].dwChunkLength = size;
+
+ return AVIERR_OK;
+ }
+ break;
+ case cktypeWAVEbytes:
+ if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
+ flags |= AVIIF_KEYFRAME;
+ break;
+ default:
+ WARN(": unknown TWOCC 0x%04X found\n", TWOCCFromFOURCC(ckid));
+ break;
+ };
+
+ /* first frame is alwasy a keyframe */
+ if (This->lLastFrame == -1)
+ flags |= AVIIF_KEYFRAME;
+
+ if (This->sInfo.dwSuggestedBufferSize < size)
+ This->sInfo.dwSuggestedBufferSize = size;
+
+ /* get memory for index */
+ if (This->idxFrames == NULL || This->lLastFrame + 1 >= This->nIdxFrames) {
+ This->nIdxFrames += 512;
+ if (This->idxFrames == NULL)
+ This->idxFrames =
+ GlobalAllocPtr(GHND, This->nIdxFrames * sizeof(AVIINDEXENTRY));
+ else
+ This->idxFrames =
+ GlobalReAllocPtr(This->idxFrames,
+ This->nIdxFrames * sizeof(AVIINDEXENTRY), GHND);
+ if (This->idxFrames == NULL)
+ return AVIERR_MEMORY;
+ }
+
+ This->lLastFrame++;
+ This->idxFrames[This->lLastFrame].ckid = ckid;
+ This->idxFrames[This->lLastFrame].dwFlags = flags;
+ This->idxFrames[This->lLastFrame].dwChunkOffset = offset;
+ This->idxFrames[This->lLastFrame].dwChunkLength = size;
+
+ /* update AVISTREAMINFO structure if necessary */
+ if (This->sInfo.dwLength <= This->lLastFrame)
+ This->sInfo.dwLength = This->lLastFrame + 1;
+
+ return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_AddRecord(IAVIFileImpl *This)
+{
+ /* pre-conditions */
+ assert(This != NULL && This->ppStreams[0] != NULL);
+
+ if (This->idxRecords == NULL || This->cbIdxRecords == 0) {
+ This->cbIdxRecords += 1024 * sizeof(AVIINDEXENTRY);
+ This->idxRecords = GlobalAllocPtr(GHND, This->cbIdxRecords);
+ if (This->idxRecords == NULL)
+ return AVIERR_MEMORY;
+ }
+
+ assert(This->nIdxRecords < This->cbIdxRecords/sizeof(AVIINDEXENTRY));
+
+ This->idxRecords[This->nIdxRecords].ckid = listtypeAVIRECORD;
+ This->idxRecords[This->nIdxRecords].dwFlags = AVIIF_LIST;
+ This->idxRecords[This->nIdxRecords].dwChunkOffset =
+ This->ckLastRecord.dwDataOffset - 2 * sizeof(DWORD);
+ This->idxRecords[This->nIdxRecords].dwChunkLength =
+ This->ckLastRecord.cksize;
+ This->nIdxRecords++;
+
+ return AVIERR_OK;
+}
+
+static DWORD AVIFILE_ComputeMoviStart(IAVIFileImpl *This)
+{
+ DWORD dwPos;
+ DWORD nStream;
+
+ /* RIFF,hdrl,movi,avih => (3 * 3 + 2) * sizeof(DWORD) = 11 * sizeof(DWORD) */
+ dwPos = 11 * sizeof(DWORD) + sizeof(MainAVIHeader);
+
+ for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
+ IAVIStreamImpl *pStream = This->ppStreams[nStream];
+
+ /* strl,strh,strf => (3 + 2 * 2) * sizeof(DWORD) = 7 * sizeof(DWORD) */
+ dwPos += 7 * sizeof(DWORD) + sizeof(AVIStreamHeader);
+ dwPos += ((pStream->cbFormat + 1) & ~1U);
+ if (pStream->lpHandlerData != NULL && pStream->cbHandlerData > 0)
+ dwPos += 2 * sizeof(DWORD) + ((pStream->cbHandlerData + 1) & ~1U);
+ if (lstrlenW(pStream->sInfo.szName) > 0)
+ dwPos += 2 * sizeof(DWORD) + ((lstrlenW(pStream->sInfo.szName) + 1) & ~1U);
+ }
+
+ if (This->dwMoviChunkPos == 0) {
+ This->dwNextFramePos = dwPos;
+
+ /* pad to multiple of AVI_HEADERSIZE only if we are more than 8 bytes away from it */
+ if (((dwPos + AVI_HEADERSIZE) & ~(AVI_HEADERSIZE - 1)) - dwPos > 2 * sizeof(DWORD))
+ This->dwNextFramePos = (dwPos + AVI_HEADERSIZE) & ~(AVI_HEADERSIZE - 1);
+
+ This->dwMoviChunkPos = This->dwNextFramePos - sizeof(DWORD);
+ }
+
+ return dwPos;
+}
+
+static void AVIFILE_ConstructAVIStream(IAVIFileImpl *paf, DWORD nr, LPAVISTREAMINFOW asi)
+{
+ IAVIStreamImpl *pstream;
+
+ /* pre-conditions */
+ assert(paf != NULL);
+ assert(nr < MAX_AVISTREAMS);
+ assert(paf->ppStreams[nr] != NULL);
+
+ pstream = paf->ppStreams[nr];
+
+ pstream->lpVtbl = &iavist;
+ pstream->ref = 0;
+ pstream->paf = paf;
+ pstream->nStream = nr;
+ pstream->dwCurrentFrame = (DWORD)-1;
+ pstream->lLastFrame = -1;
+
+ if (asi != NULL) {
+ memcpy(&pstream->sInfo, asi, sizeof(pstream->sInfo));
+
+ if (asi->dwLength > 0) {
+ /* pre-allocate mem for frame-index structure */
+ pstream->idxFrames =
+ (AVIINDEXENTRY*)GlobalAllocPtr(GHND, asi->dwLength * sizeof(AVIINDEXENTRY));
+ if (pstream->idxFrames != NULL)
+ pstream->nIdxFrames = asi->dwLength;
+ }
+ if (asi->dwFormatChangeCount > 0) {
+ /* pre-allocate mem for formatchange-index structure */
+ pstream->idxFmtChanges =
+ (AVIINDEXENTRY*)GlobalAllocPtr(GHND, asi->dwFormatChangeCount * sizeof(AVIINDEXENTRY));
+ if (pstream->idxFmtChanges != NULL)
+ pstream->nIdxFmtChanges = asi->dwFormatChangeCount;
+ }
+
+ /* These values will be computed */
+ pstream->sInfo.dwLength = 0;
+ pstream->sInfo.dwSuggestedBufferSize = 0;
+ pstream->sInfo.dwFormatChangeCount = 0;
+ pstream->sInfo.dwEditCount = 1;
+ if (pstream->sInfo.dwSampleSize > 0)
+ SetRectEmpty(&pstream->sInfo.rcFrame);
+ }
+
+ pstream->sInfo.dwCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
+}
+
+static void AVIFILE_DestructAVIStream(IAVIStreamImpl *This)
+{
+ /* pre-conditions */
+ assert(This != NULL);
+
+ This->dwCurrentFrame = (DWORD)-1;
+ This->lLastFrame = -1;
+ This->paf = NULL;
+ if (This->idxFrames != NULL) {
+ GlobalFreePtr(This->idxFrames);
+ This->idxFrames = NULL;
+ This->nIdxFrames = 0;
+ }
+ if (This->idxFmtChanges != NULL) {
+ GlobalFreePtr(This->idxFmtChanges);
+ This->idxFmtChanges = NULL;
+ }
+ if (This->lpBuffer != NULL) {
+ GlobalFreePtr(This->lpBuffer);
+ This->lpBuffer = NULL;
+ This->cbBuffer = 0;
+ }
+ if (This->lpHandlerData != NULL) {
+ GlobalFreePtr(This->lpHandlerData);
+ This->lpHandlerData = NULL;
+ This->cbHandlerData = 0;
+ }
+ if (This->extra.lp != NULL) {
+ GlobalFreePtr(This->extra.lp);
+ This->extra.lp = NULL;
+ This->extra.cb = 0;
+ }
+ if (This->lpFormat != NULL) {
+ GlobalFreePtr(This->lpFormat);
+ This->lpFormat = NULL;
+ This->cbFormat = 0;
+ }
+}
+
+static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This)
+{
+ MainAVIHeader MainAVIHdr;
+ MMCKINFO ckRIFF;
+ MMCKINFO ckLIST1;
+ MMCKINFO ckLIST2;
+ MMCKINFO ck;
+ IAVIStreamImpl *pStream;
+ DWORD nStream;
+ HRESULT hr;
+
+ if (This->hmmio == NULL)
+ return AVIERR_FILEOPEN;
+
+ /* initialize stream ptr's */
+ memset(This->ppStreams, 0, sizeof(This->ppStreams));
+
+ /* try to get "RIFF" chunk -- must not be at beginning of file! */
+ ckRIFF.fccType = formtypeAVI;
+ if (mmioDescend(This->hmmio, &ckRIFF, NULL, MMIO_FINDRIFF) != S_OK) {
+ ERR(": not an AVI!\n");
+ return AVIERR_FILEREAD;
+ }
+
+ /* get "LIST" "hdrl" */
+ ckLIST1.fccType = listtypeAVIHEADER;
+ hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ckLIST1, &ckRIFF, MMIO_FINDLIST);
+ if (FAILED(hr))
+ return hr;
+
+ /* get "avih" chunk */
+ ck.ckid = ckidAVIMAINHDR;
+ hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckLIST1, MMIO_FINDCHUNK);
+ if (FAILED(hr))
+ return hr;
+
+ if (ck.cksize != sizeof(MainAVIHdr)) {
+ ERR(": invalid size of %ld for MainAVIHeader!\n", ck.cksize);
+ return AVIERR_BADFORMAT;
+ }
+ if (mmioRead(This->hmmio, (HPSTR)&MainAVIHdr, ck.cksize) != ck.cksize)
+ return AVIERR_FILEREAD;
+
+ /* check for MAX_AVISTREAMS limit */
+ if (MainAVIHdr.dwStreams > MAX_AVISTREAMS) {
+ WARN("file contains %lu streams, but only supports %d -- change MAX_AVISTREAMS!\n", MainAVIHdr.dwStreams, MAX_AVISTREAMS);
+ return AVIERR_UNSUPPORTED;
+ }
+
+ /* adjust permissions if copyrighted material in file */
+ if (MainAVIHdr.dwFlags & AVIFILEINFO_COPYRIGHTED) {
+ This->uMode &= ~MMIO_RWMODE;
+ This->uMode |= MMIO_READ;
+ }
+
+ /* convert MainAVIHeader into AVIFILINFOW */
+ memset(&This->fInfo, 0, sizeof(This->fInfo));
+ This->fInfo.dwRate = MainAVIHdr.dwMicroSecPerFrame;
+ This->fInfo.dwScale = 1000000;
+ This->fInfo.dwMaxBytesPerSec = MainAVIHdr.dwMaxBytesPerSec;
+ This->fInfo.dwFlags = MainAVIHdr.dwFlags;
+ This->fInfo.dwCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
+ This->fInfo.dwLength = MainAVIHdr.dwTotalFrames;
+ This->fInfo.dwStreams = MainAVIHdr.dwStreams;
+ This->fInfo.dwSuggestedBufferSize = MainAVIHdr.dwSuggestedBufferSize;
+ This->fInfo.dwWidth = MainAVIHdr.dwWidth;
+ This->fInfo.dwHeight = MainAVIHdr.dwHeight;
+ LoadStringW(AVIFILE_hModule, IDS_AVIFILETYPE, This->fInfo.szFileType,
+ sizeof(This->fInfo.szFileType));
+
+ /* go back to into header list */
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEREAD;
+
+ /* foreach stream exists a "LIST","strl" chunk */
+ for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
+ /* get next nested chunk in this "LIST","strl" */
+ if (mmioDescend(This->hmmio, &ckLIST2, &ckLIST1, 0) != S_OK)
+ return AVIERR_FILEREAD;
+
+ /* nested chunk must be of type "LIST","strl" -- when not normally JUNK */
+ if (ckLIST2.ckid == FOURCC_LIST &&
+ ckLIST2.fccType == listtypeSTREAMHEADER) {
+ pStream = This->ppStreams[nStream] =
+ (IAVIStreamImpl*)LocalAlloc(LPTR, sizeof(IAVIStreamImpl));
+ if (pStream == NULL)
+ return AVIERR_MEMORY;
+ AVIFILE_ConstructAVIStream(This, nStream, NULL);
+
+ ck.ckid = 0;
+ while (mmioDescend(This->hmmio, &ck, &ckLIST2, 0) == S_OK) {
+ switch (ck.ckid) {
+ case ckidSTREAMHANDLERDATA:
+ if (pStream->lpHandlerData != NULL)
+ return AVIERR_BADFORMAT;
+ pStream->lpHandlerData = GlobalAllocPtr(GMEM_DDESHARE|GMEM_MOVEABLE,
+ ck.cksize);
+ if (pStream->lpHandlerData == NULL)
+ return AVIERR_MEMORY;
+ pStream->cbHandlerData = ck.cksize;
+
+ if (mmioRead(This->hmmio, (HPSTR)pStream->lpHandlerData, ck.cksize) != ck.cksize)
+ return AVIERR_FILEREAD;
+ break;
+ case ckidSTREAMFORMAT:
+ if (pStream->lpFormat != NULL)
+ return AVIERR_BADFORMAT;
+ if (ck.cksize == 0)
+ break;
+
+ pStream->lpFormat = GlobalAllocPtr(GMEM_DDESHARE|GMEM_MOVEABLE,
+ ck.cksize);
+ if (pStream->lpFormat == NULL)
+ return AVIERR_MEMORY;
+ pStream->cbFormat = ck.cksize;
+
+ if (mmioRead(This->hmmio, (HPSTR)pStream->lpFormat, ck.cksize) != ck.cksize)
+ return AVIERR_FILEREAD;
+
+ if (pStream->sInfo.fccType == streamtypeVIDEO) {
+ LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)pStream->lpFormat;
+
+ /* some corrections to the video format */
+ if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
+ lpbi->biClrUsed = 1u << lpbi->biBitCount;
+ if (lpbi->biCompression == BI_RGB && lpbi->biSizeImage == 0)
+ lpbi->biSizeImage = DIBWIDTHBYTES(*lpbi) * lpbi->biHeight;
+ if (lpbi->biCompression != BI_RGB && lpbi->biBitCount == 8) {
+ if (pStream->sInfo.fccHandler == mmioFOURCC('R','L','E','0') ||
+ pStream->sInfo.fccHandler == mmioFOURCC('R','L','E',' '))
+ lpbi->biCompression = BI_RLE8;
+ }
+ if (lpbi->biCompression == BI_RGB &&
+ (pStream->sInfo.fccHandler == 0 ||
+ pStream->sInfo.fccHandler == mmioFOURCC('N','O','N','E')))
+ pStream->sInfo.fccHandler = comptypeDIB;
+
+ /* init rcFrame if it's empty */
+ if (IsRectEmpty(&pStream->sInfo.rcFrame))
+ SetRect(&pStream->sInfo.rcFrame, 0, 0, lpbi->biWidth, lpbi->biHeight);
+ }
+ break;
+ case ckidSTREAMHEADER:
+ {
+ static const WCHAR streamTypeFmt[] = {'%','4','.','4','h','s',0};
+
+ AVIStreamHeader streamHdr;
+ WCHAR szType[25];
+ WCHAR streamNameFmt[25];
+ UINT count;
+ LONG n = ck.cksize;
+
+ if (ck.cksize > sizeof(streamHdr))
+ n = sizeof(streamHdr);
+
+ if (mmioRead(This->hmmio, (HPSTR)&streamHdr, n) != n)
+ return AVIERR_FILEREAD;
+
+ pStream->sInfo.fccType = streamHdr.fccType;
+ pStream->sInfo.fccHandler = streamHdr.fccHandler;
+ pStream->sInfo.dwFlags = streamHdr.dwFlags;
+ pStream->sInfo.wPriority = streamHdr.wPriority;
+ pStream->sInfo.wLanguage = streamHdr.wLanguage;
+ pStream->sInfo.dwInitialFrames = streamHdr.dwInitialFrames;
+ pStream->sInfo.dwScale = streamHdr.dwScale;
+ pStream->sInfo.dwRate = streamHdr.dwRate;
+ pStream->sInfo.dwStart = streamHdr.dwStart;
+ pStream->sInfo.dwLength = streamHdr.dwLength;
+ pStream->sInfo.dwSuggestedBufferSize =
+ streamHdr.dwSuggestedBufferSize;
+ pStream->sInfo.dwQuality = streamHdr.dwQuality;
+ pStream->sInfo.dwSampleSize = streamHdr.dwSampleSize;
+ pStream->sInfo.rcFrame.left = streamHdr.rcFrame.left;
+ pStream->sInfo.rcFrame.top = streamHdr.rcFrame.top;
+ pStream->sInfo.rcFrame.right = streamHdr.rcFrame.right;
+ pStream->sInfo.rcFrame.bottom = streamHdr.rcFrame.bottom;
+ pStream->sInfo.dwEditCount = 0;
+ pStream->sInfo.dwFormatChangeCount = 0;
+
+ /* generate description for stream like "filename.avi Type #n" */
+ if (streamHdr.fccType == streamtypeVIDEO)
+ LoadStringW(AVIFILE_hModule, IDS_VIDEO, szType, sizeof(szType));
+ else if (streamHdr.fccType == streamtypeAUDIO)
+ LoadStringW(AVIFILE_hModule, IDS_AUDIO, szType, sizeof(szType));
+ else
+ wsprintfW(szType, streamTypeFmt, (char*)&streamHdr.fccType);
+
+ /* get count of this streamtype up to this stream */
+ count = 0;
+ for (n = nStream; 0 <= n; n--) {
+ if (This->ppStreams[n]->sInfo.fccHandler == streamHdr.fccType)
+ count++;
+ }
+
+ memset(pStream->sInfo.szName, 0, sizeof(pStream->sInfo.szName));
+
+ LoadStringW(AVIFILE_hModule, IDS_AVISTREAMFORMAT, streamNameFmt, sizeof(streamNameFmt));
+
+ /* FIXME: avoid overflow -- better use wsnprintfW, which doesn't exists ! */
+ wsprintfW(pStream->sInfo.szName, streamNameFmt,
+ AVIFILE_BasenameW(This->szFileName), szType, count);
+ }
+ break;
+ case ckidSTREAMNAME:
+ { /* streamname will be saved as ASCII string */
+ LPSTR str = (LPSTR)LocalAlloc(LMEM_FIXED, ck.cksize);
+ if (str == NULL)
+ return AVIERR_MEMORY;
+
+ if (mmioRead(This->hmmio, (HPSTR)str, ck.cksize) != ck.cksize)
+ {
+ LocalFree((HLOCAL)str);
+ return AVIERR_FILEREAD;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, str, -1, pStream->sInfo.szName,
+ sizeof(pStream->sInfo.szName)/sizeof(pStream->sInfo.szName[0]));
+
+ LocalFree((HLOCAL)str);
+ }
+ break;
+ case ckidAVIPADDING:
+ case mmioFOURCC('p','a','d','d'):
+ break;
+ default:
+ WARN(": found extra chunk 0x%08lX\n", ck.ckid);
+ hr = ReadChunkIntoExtra(&pStream->extra, This->hmmio, &ck);
+ if (FAILED(hr))
+ return hr;
+ };
+
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEREAD;
+ }
+ } else {
+ /* nested chunks in "LIST","hdrl" which are not of type "LIST","strl" */
+ hr = ReadChunkIntoExtra(&This->fileextra, This->hmmio, &ckLIST2);
+ if (FAILED(hr))
+ return hr;
+ }
+ if (mmioAscend(This->hmmio, &ckLIST2, 0) != S_OK)
+ return AVIERR_FILEREAD;
+ }
+
+ /* read any extra headers in "LIST","hdrl" */
+ FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckLIST1, 0);
+ if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
+ return AVIERR_FILEREAD;
+
+ /* search "LIST","movi" chunk in "RIFF","AVI " */
+ ckLIST1.fccType = listtypeAVIMOVIE;
+ hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ckLIST1, &ckRIFF,
+ MMIO_FINDLIST);
+ if (FAILED(hr))
+ return hr;
+
+ This->dwMoviChunkPos = ckLIST1.dwDataOffset;
+ This->dwIdxChunkPos = ckLIST1.cksize + ckLIST1.dwDataOffset;
+ if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
+ return AVIERR_FILEREAD;
+
+ /* try to find an index */
+ ck.ckid = ckidAVINEWINDEX;
+ hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio,
+ &ck, &ckRIFF, MMIO_FINDCHUNK);
+ if (SUCCEEDED(hr) && ck.cksize > 0) {
+ if (FAILED(AVIFILE_LoadIndex(This, ck.cksize, ckLIST1.dwDataOffset)))
+ This->fInfo.dwFlags &= ~AVIFILEINFO_HASINDEX;
+ }
+
+ /* when we haven't found an index or it's bad, then build one
+ * by parsing 'movi' chunk */
+ if ((This->fInfo.dwFlags & AVIFILEINFO_HASINDEX) == 0) {
+ for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++)
+ This->ppStreams[nStream]->lLastFrame = -1;
+
+ if (mmioSeek(This->hmmio, ckLIST1.dwDataOffset + sizeof(DWORD), SEEK_SET) == -1) {
+ ERR(": Oops, can't seek back to 'movi' chunk!\n");
+ return AVIERR_FILEREAD;
+ }
+
+ /* seek through the 'movi' list until end */
+ while (mmioDescend(This->hmmio, &ck, &ckLIST1, 0) == S_OK) {
+ if (ck.ckid != FOURCC_LIST) {
+ if (mmioAscend(This->hmmio, &ck, 0) == S_OK) {
+ nStream = StreamFromFOURCC(ck.ckid);
+
+ if (nStream > This->fInfo.dwStreams)
+ return AVIERR_BADFORMAT;
+
+ AVIFILE_AddFrame(This->ppStreams[nStream], ck.ckid, ck.cksize,
+ ck.dwDataOffset - 2 * sizeof(DWORD), 0);
+ } else {
+ nStream = StreamFromFOURCC(ck.ckid);
+ WARN(": file seems to be truncated!\n");
+ if (nStream <= This->fInfo.dwStreams &&
+ This->ppStreams[nStream]->sInfo.dwSampleSize > 0) {
+ ck.cksize = mmioSeek(This->hmmio, 0, SEEK_END);
+ if (ck.cksize != -1) {
+ ck.cksize -= ck.dwDataOffset;
+ ck.cksize &= ~(This->ppStreams[nStream]->sInfo.dwSampleSize - 1);
+
+ AVIFILE_AddFrame(This->ppStreams[nStream], ck.ckid, ck.cksize,
+ ck.dwDataOffset - 2 * sizeof(DWORD), 0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* find other chunks */
+ FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckRIFF, 0);
+
+ return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_LoadIndex(IAVIFileImpl *This, DWORD size, DWORD offset)
+{
+ AVIINDEXENTRY *lp;
+ DWORD pos, n;
+ HRESULT hr = AVIERR_OK;
+ BOOL bAbsolute = TRUE;
+
+ lp = (AVIINDEXENTRY*)GlobalAllocPtr(GMEM_MOVEABLE,
+ IDX_PER_BLOCK * sizeof(AVIINDEXENTRY));
+ if (lp == NULL)
+ return AVIERR_MEMORY;
+
+ /* adjust limits for index tables, so that inserting will be faster */
+ for (n = 0; n < This->fInfo.dwStreams; n++) {
+ IAVIStreamImpl *pStream = This->ppStreams[n];
+
+ pStream->lLastFrame = -1;
+
+ if (pStream->idxFrames != NULL) {
+ GlobalFreePtr(pStream->idxFrames);
+ pStream->idxFrames = NULL;
+ pStream->nIdxFrames = 0;
+ }
+
+ if (pStream->sInfo.dwSampleSize != 0) {
+ if (n > 0 && This->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) {
+ pStream->nIdxFrames = This->ppStreams[0]->nIdxFrames;
+ } else if (pStream->sInfo.dwSuggestedBufferSize) {
+ pStream->nIdxFrames =
+ pStream->sInfo.dwLength / pStream->sInfo.dwSuggestedBufferSize;
+ }
+ } else
+ pStream->nIdxFrames = pStream->sInfo.dwLength;
+
+ pStream->idxFrames =
+ (AVIINDEXENTRY*)GlobalAllocPtr(GHND, pStream->nIdxFrames * sizeof(AVIINDEXENTRY));
+ if (pStream->idxFrames == NULL && pStream->nIdxFrames > 0) {
+ pStream->nIdxFrames = 0;
+ return AVIERR_MEMORY;
+ }
+ }
+
+ pos = (DWORD)-1;
+ while (size != 0) {
+ LONG read = min(IDX_PER_BLOCK * sizeof(AVIINDEXENTRY), size);
+
+ if (mmioRead(This->hmmio, (HPSTR)lp, read) != read) {
+ hr = AVIERR_FILEREAD;
+ break;
+ }
+ size -= read;
+
+ if (pos == (DWORD)-1)
+ pos = offset - lp->dwChunkOffset + sizeof(DWORD);
+
+ AVIFILE_ParseIndex(This, lp, read / sizeof(AVIINDEXENTRY),
+ pos, &bAbsolute);
+ }
+
+ if (lp != NULL)
+ GlobalFreePtr(lp);
+
+ /* checking ... */
+ for (n = 0; n < This->fInfo.dwStreams; n++) {
+ IAVIStreamImpl *pStream = This->ppStreams[n];
+
+ if (pStream->sInfo.dwSampleSize == 0 &&
+ pStream->sInfo.dwLength != pStream->lLastFrame+1)
+ ERR("stream %lu length mismatch: dwLength=%lu found=%ld\n",
+ n, pStream->sInfo.dwLength, pStream->lLastFrame);
+ }
+
+ return hr;
+}
+
+static HRESULT AVIFILE_ParseIndex(IAVIFileImpl *This, AVIINDEXENTRY *lp,
+ LONG count, DWORD pos, BOOL *bAbsolute)
+{
+ if (lp == NULL)
+ return AVIERR_BADPARAM;
+
+ for (; count > 0; count--, lp++) {
+ WORD nStream = StreamFromFOURCC(lp->ckid);
+
+ if (lp->ckid == listtypeAVIRECORD || nStream == 0x7F)
+ continue; /* skip these */
+
+ if (nStream > This->fInfo.dwStreams)
+ return AVIERR_BADFORMAT;
+
+ if (*bAbsolute && lp->dwChunkOffset < This->dwMoviChunkPos)
+ *bAbsolute = FALSE;
+
+ if (*bAbsolute)
+ lp->dwChunkOffset += sizeof(DWORD);
+ else
+ lp->dwChunkOffset += pos;
+
+ if (FAILED(AVIFILE_AddFrame(This->ppStreams[nStream], lp->ckid, lp->dwChunkLength, lp->dwChunkOffset, lp->dwFlags)))
+ return AVIERR_MEMORY;
+ }
+
+ return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_ReadBlock(IAVIStreamImpl *This, DWORD pos,
+ LPVOID buffer, LONG size)
+{
+ /* pre-conditions */
+ assert(This != NULL);
+ assert(This->paf != NULL);
+ assert(This->paf->hmmio != NULL);
+ assert(This->sInfo.dwStart <= pos && pos < This->sInfo.dwLength);
+ assert(pos <= This->lLastFrame);
+
+ /* should we read as much as block gives us? */
+ if (size == 0 || size > This->idxFrames[pos].dwChunkLength)
+ size = This->idxFrames[pos].dwChunkLength;
+
+ /* read into out own buffer or given one? */
+ if (buffer == NULL) {
+ /* we also read the chunk */
+ size += 2 * sizeof(DWORD);
+
+ /* check that buffer is big enough -- don't trust dwSuggestedBufferSize */
+ if (This->lpBuffer == NULL || size < This->cbBuffer) {
+ DWORD maxSize = max(size, This->sInfo.dwSuggestedBufferSize);
+
+ if (This->lpBuffer == NULL)
+ This->lpBuffer = (LPDWORD)GlobalAllocPtr(GMEM_MOVEABLE, maxSize);
+ else
+ This->lpBuffer =
+ (LPDWORD)GlobalReAllocPtr(This->lpBuffer, maxSize, GMEM_MOVEABLE);
+ if (This->lpBuffer == NULL)
+ return AVIERR_MEMORY;
+ This->cbBuffer = max(size, This->sInfo.dwSuggestedBufferSize);
+ }
+
+ /* now read the complete chunk into our buffer */
+ if (mmioSeek(This->paf->hmmio, This->idxFrames[pos].dwChunkOffset, SEEK_SET) == -1)
+ return AVIERR_FILEREAD;
+ if (mmioRead(This->paf->hmmio, (HPSTR)This->lpBuffer, size) != size)
+ return AVIERR_FILEREAD;
+
+ /* check if it was the correct block which we have read */
+ if (This->lpBuffer[0] != This->idxFrames[pos].ckid ||
+ This->lpBuffer[1] != This->idxFrames[pos].dwChunkLength) {
+ ERR(": block %ld not found at 0x%08lX\n", pos, This->idxFrames[pos].dwChunkOffset);
+ ERR(": Index says: '%4.4s'(0x%08lX) size 0x%08lX\n",
+ (char*)&This->idxFrames[pos].ckid, This->idxFrames[pos].ckid,
+ This->idxFrames[pos].dwChunkLength);
+ ERR(": Data says: '%4.4s'(0x%08lX) size 0x%08lX\n",
+ (char*)&This->lpBuffer[0], This->lpBuffer[0], This->lpBuffer[1]);
+ return AVIERR_FILEREAD;
+ }
+ } else {
+ if (mmioSeek(This->paf->hmmio, This->idxFrames[pos].dwChunkOffset + 2 * sizeof(DWORD), SEEK_SET) == -1)
+ return AVIERR_FILEREAD;
+ if (mmioRead(This->paf->hmmio, (HPSTR)buffer, size) != size)
+ return AVIERR_FILEREAD;
+ }
+
+ return AVIERR_OK;
+}
+
+static void AVIFILE_SamplesToBlock(IAVIStreamImpl *This, LPLONG pos,
+ LPLONG offset)
+{
+ LONG block;
+
+ /* pre-conditions */
+ assert(This != NULL);
+ assert(pos != NULL);
+ assert(offset != NULL);
+ assert(This->sInfo.dwSampleSize != 0);
+ assert(*pos >= This->sInfo.dwStart);
+
+ /* convert start sample to start bytes */
+ (*offset) = (*pos) - This->sInfo.dwStart;
+ (*offset) *= This->sInfo.dwSampleSize;
+
+ /* convert bytes to block number */
+ for (block = 0; block <= This->lLastFrame; block++) {
+ if (This->idxFrames[block].dwChunkLength <= *offset)
+ (*offset) -= This->idxFrames[block].dwChunkLength;
+ else
+ break;
+ }
+
+ *pos = block;
+}
+
+static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This)
+{
+ MainAVIHeader MainAVIHdr;
+ IAVIStreamImpl* pStream;
+ MMCKINFO ckRIFF;
+ MMCKINFO ckLIST1;
+ MMCKINFO ckLIST2;
+ MMCKINFO ck;
+ DWORD nStream;
+ DWORD dwPos;
+ HRESULT hr;
+
+ /* initialize some things */
+ if (This->dwMoviChunkPos == 0)
+ AVIFILE_ComputeMoviStart(This);
+
+ /* written one record to much? */
+ if (This->ckLastRecord.dwFlags & MMIO_DIRTY) {
+ This->dwNextFramePos -= 3 * sizeof(DWORD);
+ if (This->nIdxRecords > 0)
+ This->nIdxRecords--;
+ }
+
+ AVIFILE_UpdateInfo(This);
+
+ assert(This->fInfo.dwScale != 0);
+
+ memset(&MainAVIHdr, 0, sizeof(MainAVIHdr));
+ MainAVIHdr.dwMicroSecPerFrame = MulDiv(This->fInfo.dwRate, 1000000,
+ This->fInfo.dwScale);
+ MainAVIHdr.dwMaxBytesPerSec = This->fInfo.dwMaxBytesPerSec;
+ MainAVIHdr.dwPaddingGranularity = AVI_HEADERSIZE;
+ MainAVIHdr.dwFlags = This->fInfo.dwFlags;
+ MainAVIHdr.dwTotalFrames = This->fInfo.dwLength;
+ MainAVIHdr.dwInitialFrames = 0;
+ MainAVIHdr.dwStreams = This->fInfo.dwStreams;
+ MainAVIHdr.dwSuggestedBufferSize = This->fInfo.dwSuggestedBufferSize;
+ MainAVIHdr.dwWidth = This->fInfo.dwWidth;
+ MainAVIHdr.dwHeight = This->fInfo.dwHeight;
+ MainAVIHdr.dwInitialFrames = This->dwInitialFrames;
+
+ /* now begin writing ... */
+ mmioSeek(This->hmmio, 0, SEEK_SET);
+
+ /* RIFF chunk */
+ ckRIFF.cksize = 0;
+ ckRIFF.fccType = formtypeAVI;
+ if (mmioCreateChunk(This->hmmio, &ckRIFF, MMIO_CREATERIFF) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* AVI headerlist */
+ ckLIST1.cksize = 0;
+ ckLIST1.fccType = listtypeAVIHEADER;
+ if (mmioCreateChunk(This->hmmio, &ckLIST1, MMIO_CREATELIST) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* MainAVIHeader */
+ ck.ckid = ckidAVIMAINHDR;
+ ck.cksize = sizeof(MainAVIHdr);
+ ck.fccType = 0;
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (mmioWrite(This->hmmio, (HPSTR)&MainAVIHdr, ck.cksize) != ck.cksize)
+ return AVIERR_FILEWRITE;
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* write the headers of each stream into a separate streamheader list */
+ for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
+ AVIStreamHeader strHdr;
+
+ pStream = This->ppStreams[nStream];
+
+ /* begin the new streamheader list */
+ ckLIST2.cksize = 0;
+ ckLIST2.fccType = listtypeSTREAMHEADER;
+ if (mmioCreateChunk(This->hmmio, &ckLIST2, MMIO_CREATELIST) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* create an AVIStreamHeader from the AVSTREAMINFO */
+ strHdr.fccType = pStream->sInfo.fccType;
+ strHdr.fccHandler = pStream->sInfo.fccHandler;
+ strHdr.dwFlags = pStream->sInfo.dwFlags;
+ strHdr.wPriority = pStream->sInfo.wPriority;
+ strHdr.wLanguage = pStream->sInfo.wLanguage;
+ strHdr.dwInitialFrames = pStream->sInfo.dwInitialFrames;
+ strHdr.dwScale = pStream->sInfo.dwScale;
+ strHdr.dwRate = pStream->sInfo.dwRate;
+ strHdr.dwStart = pStream->sInfo.dwStart;
+ strHdr.dwLength = pStream->sInfo.dwLength;
+ strHdr.dwSuggestedBufferSize = pStream->sInfo.dwSuggestedBufferSize;
+ strHdr.dwQuality = pStream->sInfo.dwQuality;
+ strHdr.dwSampleSize = pStream->sInfo.dwSampleSize;
+ strHdr.rcFrame.left = pStream->sInfo.rcFrame.left;
+ strHdr.rcFrame.top = pStream->sInfo.rcFrame.top;
+ strHdr.rcFrame.right = pStream->sInfo.rcFrame.right;
+ strHdr.rcFrame.bottom = pStream->sInfo.rcFrame.bottom;
+
+ /* now write the AVIStreamHeader */
+ ck.ckid = ckidSTREAMHEADER;
+ ck.cksize = sizeof(strHdr);
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (mmioWrite(This->hmmio, (HPSTR)&strHdr, ck.cksize) != ck.cksize)
+ return AVIERR_FILEWRITE;
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* ... the hopefully ever present streamformat ... */
+ ck.ckid = ckidSTREAMFORMAT;
+ ck.cksize = pStream->cbFormat;
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (pStream->lpFormat != NULL && ck.cksize > 0) {
+ if (mmioWrite(This->hmmio, (HPSTR)pStream->lpFormat, ck.cksize) != ck.cksize)
+ return AVIERR_FILEWRITE;
+ }
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* ... some optional existing handler data ... */
+ if (pStream->lpHandlerData != NULL && pStream->cbHandlerData > 0) {
+ ck.ckid = ckidSTREAMHANDLERDATA;
+ ck.cksize = pStream->cbHandlerData;
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (mmioWrite(This->hmmio, (HPSTR)pStream->lpHandlerData, ck.cksize) != ck.cksize)
+ return AVIERR_FILEWRITE;
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ }
+
+ /* ... some optional additional extra chunk for this stream ... */
+ if (pStream->extra.lp != NULL && pStream->extra.cb > 0) {
+ /* the chunk header(s) are already in the strucuture */
+ if (mmioWrite(This->hmmio, (HPSTR)pStream->extra.lp, pStream->extra.cb) != pStream->extra.cb)
+ return AVIERR_FILEWRITE;
+ }
+
+ /* ... an optional name for this stream ... */
+ if (lstrlenW(pStream->sInfo.szName) > 0) {
+ LPSTR str;
+
+ ck.ckid = ckidSTREAMNAME;
+ ck.cksize = lstrlenW(pStream->sInfo.szName) + 1;
+ if (ck.cksize & 1) /* align */
+ ck.cksize++;
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* the streamname must be saved in ASCII not Unicode */
+ str = (LPSTR)LocalAlloc(LPTR, ck.cksize);
+ if (str == NULL)
+ return AVIERR_MEMORY;
+ WideCharToMultiByte(CP_ACP, 0, pStream->sInfo.szName, -1, str,
+ ck.cksize, NULL, NULL);
+
+ if (mmioWrite(This->hmmio, (HPSTR)str, ck.cksize) != ck.cksize) {
+ LocalFree((HLOCAL)str);
+ return AVIERR_FILEWRITE;
+ }
+
+ LocalFree((HLOCAL)str);
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ }
+
+ /* close streamheader list for this stream */
+ if (mmioAscend(This->hmmio, &ckLIST2, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ } /* for (0 <= nStream < MainAVIHdr.dwStreams) */
+
+ /* close the aviheader list */
+ if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* check for padding to pre-guessed 'movi'-chunk position */
+ dwPos = ckLIST1.dwDataOffset + ckLIST1.cksize;
+ if (This->dwMoviChunkPos - 2 * sizeof(DWORD) > dwPos) {
+ ck.ckid = ckidAVIPADDING;
+ ck.cksize = This->dwMoviChunkPos - dwPos - 4 * sizeof(DWORD);
+ assert((LONG)ck.cksize >= 0);
+
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (mmioSeek(This->hmmio, ck.cksize, SEEK_CUR) == -1)
+ return AVIERR_FILEWRITE;
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ }
+
+ /* now write the 'movi' chunk */
+ mmioSeek(This->hmmio, This->dwMoviChunkPos - 2 * sizeof(DWORD), SEEK_SET);
+ ckLIST1.cksize = 0;
+ ckLIST1.fccType = listtypeAVIMOVIE;
+ if (mmioCreateChunk(This->hmmio, &ckLIST1, MMIO_CREATELIST) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (mmioSeek(This->hmmio, This->dwNextFramePos, SEEK_SET) == -1)
+ return AVIERR_FILEWRITE;
+ if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* write 'idx1' chunk */
+ hr = AVIFILE_SaveIndex(This);
+ if (FAILED(hr))
+ return hr;
+
+ /* write optional extra file chunks */
+ if (This->fileextra.lp != NULL && This->fileextra.cb > 0) {
+ /* as for the streams, are the chunk header(s) in the structure */
+ if (mmioWrite(This->hmmio, (HPSTR)This->fileextra.lp, This->fileextra.cb) != This->fileextra.cb)
+ return AVIERR_FILEWRITE;
+ }
+
+ /* close RIFF chunk */
+ if (mmioAscend(This->hmmio, &ckRIFF, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* add some JUNK at end for bad parsers */
+ memset(&ckRIFF, 0, sizeof(ckRIFF));
+ mmioWrite(This->hmmio, (HPSTR)&ckRIFF, sizeof(ckRIFF));
+ mmioFlush(This->hmmio, 0);
+
+ return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This)
+{
+ IAVIStreamImpl *pStream;
+ AVIINDEXENTRY idx;
+ MMCKINFO ck;
+ DWORD nStream;
+ LONG n;
+
+ ck.ckid = ckidAVINEWINDEX;
+ ck.cksize = 0;
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ if (This->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) {
+ /* is interleaved -- write block of coresponding frames */
+ LONG lInitialFrames = 0;
+ LONG stepsize;
+ LONG i;
+
+ if (This->ppStreams[0]->sInfo.dwSampleSize == 0)
+ stepsize = 1;
+ else
+ stepsize = AVIStreamTimeToSample((PAVISTREAM)This->ppStreams[0], 1000000);
+
+ assert(stepsize > 0);
+
+ for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
+ if (lInitialFrames < This->ppStreams[nStream]->sInfo.dwInitialFrames)
+ lInitialFrames = This->ppStreams[nStream]->sInfo.dwInitialFrames;
+ }
+
+ for (i = -lInitialFrames; i < (LONG)This->fInfo.dwLength - lInitialFrames;
+ i += stepsize) {
+ DWORD nFrame = lInitialFrames + i;
+
+ assert(nFrame < This->nIdxRecords);
+
+ idx.ckid = listtypeAVIRECORD;
+ idx.dwFlags = AVIIF_LIST;
+ idx.dwChunkLength = This->idxRecords[nFrame].dwChunkLength;
+ idx.dwChunkOffset = This->idxRecords[nFrame].dwChunkOffset
+ - This->dwMoviChunkPos;
+ if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
+ return AVIERR_FILEWRITE;
+
+ for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
+ pStream = This->ppStreams[nStream];
+
+ /* heave we reached start of this stream? */
+ if (-(LONG)pStream->sInfo.dwInitialFrames > i)
+ continue;
+
+ if (pStream->sInfo.dwInitialFrames < lInitialFrames)
+ nFrame -= (lInitialFrames - pStream->sInfo.dwInitialFrames);
+
+ /* reached end of this stream? */
+ if (pStream->lLastFrame <= nFrame)
+ continue;
+
+ if ((pStream->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
+ pStream->sInfo.dwFormatChangeCount != 0 &&
+ pStream->idxFmtChanges != NULL) {
+ DWORD pos;
+
+ for (pos = 0; pos < pStream->sInfo.dwFormatChangeCount; pos++) {
+ if (pStream->idxFmtChanges[pos].ckid == nFrame) {
+ idx.dwFlags = AVIIF_NOTIME;
+ idx.ckid = MAKEAVICKID(cktypePALchange, pStream->nStream);
+ idx.dwChunkLength = pStream->idxFmtChanges[pos].dwChunkLength;
+ idx.dwChunkOffset = pStream->idxFmtChanges[pos].dwChunkOffset
+ - This->dwMoviChunkPos;
+
+ if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
+ return AVIERR_FILEWRITE;
+ break;
+ }
+ }
+ } /* if have formatchanges */
+
+ idx.ckid = pStream->idxFrames[nFrame].ckid;
+ idx.dwFlags = pStream->idxFrames[nFrame].dwFlags;
+ idx.dwChunkLength = pStream->idxFrames[nFrame].dwChunkLength;
+ idx.dwChunkOffset = pStream->idxFrames[nFrame].dwChunkOffset
+ - This->dwMoviChunkPos;
+ if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
+ return AVIERR_FILEWRITE;
+ }
+ }
+ } else {
+ /* not interleaved -- write index for each stream at once */
+ for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
+ pStream = This->ppStreams[nStream];
+
+ for (n = 0; n <= pStream->lLastFrame; n++) {
+ if ((pStream->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
+ (pStream->sInfo.dwFormatChangeCount != 0)) {
+ DWORD pos;
+
+ for (pos = 0; pos < pStream->sInfo.dwFormatChangeCount; pos++) {
+ if (pStream->idxFmtChanges[pos].ckid == n) {
+ idx.dwFlags = AVIIF_NOTIME;
+ idx.ckid = MAKEAVICKID(cktypePALchange, pStream->nStream);
+ idx.dwChunkLength = pStream->idxFmtChanges[pos].dwChunkLength;
+ idx.dwChunkOffset =
+ pStream->idxFmtChanges[pos].dwChunkOffset - This->dwMoviChunkPos;
+ if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
+ return AVIERR_FILEWRITE;
+ break;
+ }
+ }
+ } /* if have formatchanges */
+
+ idx.ckid = pStream->idxFrames[n].ckid;
+ idx.dwFlags = pStream->idxFrames[n].dwFlags;
+ idx.dwChunkLength = pStream->idxFrames[n].dwChunkLength;
+ idx.dwChunkOffset = pStream->idxFrames[n].dwChunkOffset
+ - This->dwMoviChunkPos;
+
+ if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
+ return AVIERR_FILEWRITE;
+ }
+ }
+ } /* if not interleaved */
+
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ return AVIERR_OK;
+}
+
+static ULONG AVIFILE_SearchStream(IAVIFileImpl *This, DWORD fcc, LONG lSkip)
+{
+ UINT i;
+ UINT nStream;
+
+ /* pre-condition */
+ assert(lSkip >= 0);
+
+ if (fcc != 0) {
+ /* search the number of the specified stream */
+ nStream = (ULONG)-1;
+ for (i = 0; i < This->fInfo.dwStreams; i++) {
+ assert(This->ppStreams[i] != NULL);
+
+ if (This->ppStreams[i]->sInfo.fccType == fcc) {
+ if (lSkip == 0) {
+ nStream = i;
+ break;
+ } else
+ lSkip--;
+ }
+ }
+ } else
+ nStream = lSkip;
+
+ return nStream;
+}
+
+static void AVIFILE_UpdateInfo(IAVIFileImpl *This)
+{
+ UINT i;
+
+ /* pre-conditions */
+ assert(This != NULL);
+
+ This->fInfo.dwMaxBytesPerSec = 0;
+ This->fInfo.dwCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
+ This->fInfo.dwSuggestedBufferSize = 0;
+ This->fInfo.dwWidth = 0;
+ This->fInfo.dwHeight = 0;
+ This->fInfo.dwScale = 0;
+ This->fInfo.dwRate = 0;
+ This->fInfo.dwLength = 0;
+ This->dwInitialFrames = 0;
+
+ for (i = 0; i < This->fInfo.dwStreams; i++) {
+ AVISTREAMINFOW *psi;
+ DWORD n;
+
+ /* pre-conditions */
+ assert(This->ppStreams[i] != NULL);
+
+ psi = &This->ppStreams[i]->sInfo;
+ assert(psi->dwScale != 0);
+ assert(psi->dwRate != 0);
+
+ if (i == 0) {
+ /* use first stream timings as base */
+ This->fInfo.dwScale = psi->dwScale;
+ This->fInfo.dwRate = psi->dwRate;
+ This->fInfo.dwLength = psi->dwLength;
+ } else {
+ n = AVIStreamSampleToSample((PAVISTREAM)This->ppStreams[0],
+ (PAVISTREAM)This->ppStreams[i],psi->dwLength);
+ if (This->fInfo.dwLength < n)
+ This->fInfo.dwLength = n;
+ }
+
+ if (This->dwInitialFrames < psi->dwInitialFrames)
+ This->dwInitialFrames = psi->dwInitialFrames;
+
+ if (This->fInfo.dwSuggestedBufferSize < psi->dwSuggestedBufferSize)
+ This->fInfo.dwSuggestedBufferSize = psi->dwSuggestedBufferSize;
+
+ if (psi->dwSampleSize != 0) {
+ /* fixed sample size -- exact computation */
+ This->fInfo.dwMaxBytesPerSec += MulDiv(psi->dwSampleSize, psi->dwRate,
+ psi->dwScale);
+ } else {
+ /* variable sample size -- only upper limit */
+ This->fInfo.dwMaxBytesPerSec += MulDiv(psi->dwSuggestedBufferSize,
+ psi->dwRate, psi->dwScale);
+
+ /* update dimensions */
+ n = psi->rcFrame.right - psi->rcFrame.left;
+ if (This->fInfo.dwWidth < n)
+ This->fInfo.dwWidth = n;
+ n = psi->rcFrame.bottom - psi->rcFrame.top;
+ if (This->fInfo.dwHeight < n)
+ This->fInfo.dwHeight = n;
+ }
+ }
+}
+
+static HRESULT AVIFILE_WriteBlock(IAVIStreamImpl *This, DWORD block,
+ FOURCC ckid, DWORD flags, LPVOID buffer,
+ LONG size)
+{
+ MMCKINFO ck;
+
+ ck.ckid = ckid;
+ ck.cksize = size;
+ ck.fccType = 0;
+
+ /* if no frame/block is already written, we must compute start of movi chunk */
+ if (This->paf->dwMoviChunkPos == 0)
+ AVIFILE_ComputeMoviStart(This->paf);
+
+ if (mmioSeek(This->paf->hmmio, This->paf->dwNextFramePos, SEEK_SET) == -1)
+ return AVIERR_FILEWRITE;
+
+ if (mmioCreateChunk(This->paf->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (buffer != NULL && size > 0) {
+ if (mmioWrite(This->paf->hmmio, (HPSTR)buffer, size) != size)
+ return AVIERR_FILEWRITE;
+ }
+ if (mmioAscend(This->paf->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ This->paf->fDirty = TRUE;
+ This->paf->dwNextFramePos = mmioSeek(This->paf->hmmio, 0, SEEK_CUR);
+
+ return AVIFILE_AddFrame(This, ckid, size,
+ ck.dwDataOffset - 2 * sizeof(DWORD), flags);
+}
--- /dev/null
+# I'm just using "long" instead of "ptr" for the interface pointers,
+# because they are 32-bit pointers, not converted to 16-bit format,
+# but the app doesn't really need to know, it should never need to
+# dereference the interface pointer itself (if we're lucky)...
+
+#1 stub WEP
+2 stub DLLGETCLASSOBJECT
+3 stub DLLCANUNLOADNOW
+4 stub ___EXPORTEDSTUB
+10 stub _IID_IAVISTREAM
+11 stub _IID_IAVIFILE
+12 stub _IID_IAVIEDITSTREAM
+13 stub _IID_IGETFRAME
+14 stub _CLSID_AVISIMPLEUNMARSHAL
+100 pascal AVIFileInit() AVIFileInit
+101 pascal AVIFileExit() AVIFileExit
+102 pascal AVIFileOpen(ptr str word ptr) AVIFileOpenA
+103 pascal AVIStreamOpenFromFile(ptr str long long word ptr) AVIStreamOpenFromFileA
+104 pascal AVIStreamCreate(ptr long long ptr) AVIStreamCreate
+105 stub AVIMAKECOMPRESSEDSTREAM
+106 stub AVIMAKEFILEFROMSTREAMS
+107 stub AVIMAKESTREAMFROMCLIPBOARD
+110 pascal AVIStreamGetFrame(long long) AVIStreamGetFrame
+111 pascal AVIStreamGetFrameClose(long) AVIStreamGetFrameClose
+112 pascal AVIStreamGetFrameOpen(long ptr) AVIStreamGetFrameOpen
+120 stub _AVISAVE
+121 stub AVISAVEV
+122 stub AVISAVEOPTIONS
+123 pascal AVIBuildFilter(str long word) AVIBuildFilterA
+124 pascal AVISaveOptionsFree(word ptr) AVISaveOptionsFree
+130 pascal AVIStreamStart(long) AVIStreamStart
+131 pascal AVIStreamLength(long) AVIStreamLength
+132 pascal AVIStreamTimeToSample(long long) AVIStreamTimeToSample
+133 pascal AVIStreamSampleToTime(long long) AVIStreamSampleToTime
+140 pascal AVIFileAddRef(long) AVIFileAddRef
+141 pascal AVIFileRelease(long) AVIFileRelease
+142 pascal AVIFileInfo(long ptr long) AVIFileInfoA
+143 pascal AVIFileGetStream(long ptr long long) AVIFileGetStream
+144 pascal AVIFileCreateStream(long ptr ptr) AVIFileCreateStreamA
+146 pascal AVIFileWriteData(long long ptr long) AVIFileWriteData
+147 pascal AVIFileReadData(long long ptr ptr) AVIFileReadData
+148 pascal AVIFileEndRecord(long) AVIFileEndRecord
+160 pascal AVIStreamAddRef(long) AVIStreamAddRef
+161 pascal AVIStreamRelease(long) AVIStreamRelease
+162 pascal AVIStreamInfo(long ptr long) AVIStreamInfoA
+163 pascal AVIStreamFindSample(long long long) AVIStreamFindSample
+164 pascal AVIStreamReadFormat(long long ptr ptr) AVIStreamReadFormat
+165 pascal AVIStreamReadData(long long ptr ptr) AVIStreamReadData
+166 pascal AVIStreamWriteData(long long ptr long) AVIStreamWriteData
+167 pascal AVIStreamRead(long long long ptr long ptr ptr) AVIStreamRead
+168 pascal AVIStreamWrite(long long long ptr long long ptr ptr) AVIStreamWrite
+169 pascal AVIStreamSetFormat(long long ptr long) AVIStreamSetFormat
+180 stub EDITSTREAMCOPY
+181 stub EDITSTREAMCUT
+182 stub EDITSTREAMPASTE
+184 stub CREATEEDITABLESTREAM
+185 stub AVIPUTFILEONCLIPBOARD
+187 stub AVIGETFROMCLIPBOARD
+188 stub AVICLEARCLIPBOARD
+190 stub EDITSTREAMCLONE
+191 stub EDITSTREAMSETNAME
+192 stub EDITSTREAMSETINFO
+200 stub AVISTREAMBEGINSTREAMING
+201 stub AVISTREAMENDSTREAMING
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * Czech resources for avifile
+ * Copyright 2004 David Kredba
+ *
+ * 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
+ */
+
+LANGUAGE LANG_CZECH, SUBLANG_DEFAULT
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Nastavení komprese"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Vyber datový proud:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "V&olby...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "Prolo¾&it ka¾dých",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "rámcù",-1,104,43,36,9
+ LTEXT "Souèasný formát:",-1,3,56,53,9
+ LTEXT "Zbývající místo",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "Budi¾",IDOK,145,42,45,14
+ PUSHBUTTON "Zru¹it",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Waveform: %s"
+ IDS_WAVEFILETYPE "Waveform"
+ IDS_ALLMULTIMEDIA "V¹echny soubory multimédií"
+ IDS_ALLFILES "V¹echny soubory (*.*)@*.*"
+ IDS_VIDEO "video"
+ IDS_AUDIO "audio"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Wine AVI-default-filehandler"
+ IDS_UNCOMPRESSED "nekomprimovaný"
+}
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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
+ */
+
+LANGUAGE LANG_GERMAN, SUBLANG_GERMAN
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Komprimierungsoptionen"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Wählen Sie die Eingangsdaten aus:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Optionen...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "&Interleave alle",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "Einzelbilder",-1,104,43,36,9
+ LTEXT "Akuelles Format:",-1,3,56,53,9
+ LTEXT "This space for rent",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "OK",IDOK,145,42,45,14
+ PUSHBUTTON "Abbrechen",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Waveform: %s"
+ IDS_WAVEFILETYPE "Waveform"
+ IDS_ALLMULTIMEDIA "Alle Multimedia-Dateien"
+ IDS_ALLFILES "Alle Dateien (*.*)@*.*"
+ IDS_VIDEO "Video"
+ IDS_AUDIO "Audio"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Wine AVI-Standard-Dateibehandlungsroutine"
+ IDS_UNCOMPRESSED "Unkomprimiert"
+}
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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
+ */
+
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Compress options"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Choose a stream:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Options...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "&Interleave every",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "frames",-1,104,43,36,9
+ LTEXT "Current format:",-1,3,56,53,9
+ LTEXT "This space for rent",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "OK",IDOK,145,42,45,14
+ PUSHBUTTON "Cancel",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Waveform: %s"
+ IDS_WAVEFILETYPE "Waveform"
+ IDS_ALLMULTIMEDIA "All multimedia files"
+ IDS_ALLFILES "All files (*.*)@*.*"
+ IDS_VIDEO "video"
+ IDS_AUDIO "audio"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Wine AVI-default-filehandler"
+ IDS_UNCOMPRESSED "uncompressed"
+}
--- /dev/null
+/*
+ * Copyright 2003 José Manuel Ferrer Ortiz
+ *
+ * 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
+ */
+
+LANGUAGE LANG_SPANISH, SUBLANG_NEUTRAL
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Opciones de compresión"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Elija un stream:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Opciones...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "&Interleave cada",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "cuadros",-1,104,43,36,9
+ LTEXT "Formato actual:",-1,3,56,53,9
+ LTEXT "Espacio en alquiler",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "Aceptar",IDOK,145,42,45,14
+ PUSHBUTTON "Cancelar",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Formato de ondas: %s"
+ IDS_WAVEFILETYPE "Formato de ondas"
+ IDS_ALLMULTIMEDIA "Todos los archivos multimedia"
+ IDS_ALLFILES "Todos los archivos (*.*)@*.*"
+ IDS_VIDEO "vídeo"
+ IDS_AUDIO "audio"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Manejador de archivo AVI por defecto de Wine"
+ IDS_UNCOMPRESSED "sin compresión"
+}
--- /dev/null
+/*
+ * Avifil32
+ * French language support
+ *
+ * Copyright 2002 Michael Günnewig
+ * Copyright 2003 Vincent Béron
+ *
+ * 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
+ */
+
+LANGUAGE LANG_FRENCH, SUBLANG_NEUTRAL
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Options de compression"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Sélectionnez un flux :",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Options...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "&Imbriquer à chaque",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "images",-1,104,43,36,9
+ LTEXT "Format actuel :",-1,3,56,53,9
+ LTEXT "Cet espace est à louer",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "OK",IDOK,145,42,45,14
+ PUSHBUTTON "Annuler",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Waveform: %s"
+ IDS_WAVEFILETYPE "Waveform"
+ IDS_ALLMULTIMEDIA "Tous les fichiers multimédias"
+ IDS_ALLFILES "Tous les fichier (*.*)@*.*"
+ IDS_VIDEO "vidéo"
+ IDS_AUDIO "audio"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Wine AVI-default-filehandler"
+ IDS_UNCOMPRESSED "non compressé"
+}
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ * Copyright 2003 Ivan Leo Puoti
+ *
+ * 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
+ */
+
+LANGUAGE LANG_ITALIAN, SUBLANG_DEFAULT
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Opzioni di compressione"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Scegliere un flusso:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Opzioni...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "&Interfoliazione ogni",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "fotogrammi",-1,104,43,36,9
+ LTEXT "Formato attuale:",-1,3,56,53,9
+ LTEXT "This space for rent",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "OK",IDOK,145,42,45,14
+ PUSHBUTTON "Annulla",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Formato wave: %s"
+ IDS_WAVEFILETYPE "Formato wave"
+ IDS_ALLMULTIMEDIA "Tutti i file multimediali"
+ IDS_ALLFILES "Tutti i file (*.*)@*.*"
+ IDS_VIDEO "Video"
+ IDS_AUDIO "Audio"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Gestore predefinito di Wine dei file AVI"
+ IDS_UNCOMPRESSED "Non compresso"
+}
--- /dev/null
+/*
+ * Copyright 2004 Hajime Segawa
+ *
+ * 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
+ */
+
+LANGUAGE LANG_JAPANESE, SUBLANG_DEFAULT
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "\88³\8fk\83I\83v\83V\83\87\83\93"
+FONT 9, "MS UI Gothic"
+BEGIN
+ LTEXT "\83X\83g\83\8a\81[\83\80\82ð\91I\91ð(&C):",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "\83I\83v\83V\83\87\83\93(&O)...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "\83C\83\93\83^\81[\83\8a\81[\83u(&I)",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "\83t\83\8c\81[\83\80",-1,104,43,36,9
+ LTEXT "\8c»\8dÝ\82Ì\83t\83H\81[\83}\83b\83g:",-1,3,56,53,9
+ LTEXT "This space for rent",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "OK",IDOK,145,42,45,14
+ PUSHBUTTON "\83L\83\83\83\93\83Z\83\8b",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Wave\83t\83@\83C\83\8b: %s"
+ IDS_WAVEFILETYPE "Wave\83t\83@\83C\83\8b"
+ IDS_ALLMULTIMEDIA "\91S\82Ä\82Ì\83}\83\8b\83`\83\81\83f\83B\83A\83t\83@\83C\83\8b"
+ IDS_ALLFILES "\91S\82Ä\82Ì\83t\83@\83C\83\8b (*.*)@*.*"
+ IDS_VIDEO "\83r\83f\83I"
+ IDS_AUDIO "\89¹\90º"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Wine AVI-default-filehandler"
+ IDS_UNCOMPRESSED "\96¢\88³\8fk"
+}
--- /dev/null
+/*
+ * avifile (Dutch resources)
+ *
+ * Copyright 2003 Hans Leidekker
+ *
+ * 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
+ */
+
+LANGUAGE LANG_DUTCH, SUBLANG_DEFAULT
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Compressie-instellingen"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Kies een invoerbestand:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Opties...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "&Interleave alle",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "Losse frames",-1,104,43,36,9
+ LTEXT "Huidig formaat:",-1,3,56,53,9
+ LTEXT "This space for rent",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "OK",IDOK,145,42,45,14
+ PUSHBUTTON "Annuleren",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Waveform: %s"
+ IDS_WAVEFILETYPE "Waveform"
+ IDS_ALLMULTIMEDIA "Alle multimediabestanden"
+ IDS_ALLFILES "Alle bestanden (*.*)@*.*"
+ IDS_VIDEO "video"
+ IDS_AUDIO "audio"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Wine AVI-standaard-bestandskoppeling"
+ IDS_UNCOMPRESSED "ongecomprimeerd"
+}
--- /dev/null
+/*
+ * Copyright 2005 Alexander N. Sørnes <alex@thehandofagony.com>
+ *
+ * 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
+ */
+
+LANGUAGE LANG_NORWEGIAN, SUBLANG_NORWEGIAN_BOKMAL
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Komprimeringsinnstillinger"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Velg en strøm:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "I&nnstillinger . . .",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "Sett &inn for hver",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "bilde",-1,104,43,36,9
+ LTEXT "Gjeldende format:",-1,3,56,53,9
+ LTEXT "Denne plassen er til leie",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "OK",IDOK,145,42,45,14
+ PUSHBUTTON "Avbryt",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Lydformat: %s"
+ IDS_WAVEFILETYPE "Lydformat"
+ IDS_ALLMULTIMEDIA "Alle multimedia-filer"
+ IDS_ALLFILES "Alle filer (*.*)@*.*"
+ IDS_VIDEO "video"
+ IDS_AUDIO "lyd"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Wine standardfilhåndterer for AVI"
+ IDS_UNCOMPRESSED "ukomprimert"
+}
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ * Copyright 2004 Piotr Caban
+ *
+ * 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
+ */
+
+LANGUAGE LANG_POLISH, SUBLANG_DEFAULT
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Opcje kompresji"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Wybierz strumieñ:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Opcje...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "&Przeplot co",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "klatek",-1,104,43,36,9
+ LTEXT "Wybrany format:",-1,2,56,53,9
+ LTEXT "Zarezerwownae miejsce",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "OK",IDOK,145,42,45,14
+ PUSHBUTTON "Anuluj",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Waveform: %s"
+ IDS_WAVEFILETYPE "Waveform"
+ IDS_ALLMULTIMEDIA "Wszystkie pliki multimedialne"
+ IDS_ALLFILES "Wszystkie pliki (*.*)@*.*"
+ IDS_VIDEO "obraz"
+ IDS_AUDIO "d\9fwiêk"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Wine AVI-domy\9clna-obs³uga-pliku"
+ IDS_UNCOMPRESSED "nie skompresowany"
+}
--- /dev/null
+/*
+ * Copyright 2003 Marcelo Duarte
+ *
+ * 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
+ */
+
+LANGUAGE LANG_PORTUGUESE, SUBLANG_DEFAULT
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Opções de compressão"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Escolha a stream:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Opções...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "&Interleave every",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "frames",-1,104,43,36,9
+ LTEXT "Formato atual:",-1,3,56,53,9
+ LTEXT "This space for rent",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "OK",IDOK,145,42,45,14
+ PUSHBUTTON "Cancelar",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Formato wave: %s"
+ IDS_WAVEFILETYPE "Formato wave"
+ IDS_ALLMULTIMEDIA "Todos arquivos multimídia"
+ IDS_ALLFILES "Todos os arquivos (*.*)@*.*"
+ IDS_VIDEO "vídeo"
+ IDS_AUDIO "áudio"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Wine AVI-manipulador padrão de arquivo"
+ IDS_UNCOMPRESSED "sem compressão"
+}
--- /dev/null
+/*
+ * avifil32.dll (Russian resources)
+ *
+ * Copyright 2003 Igor Stepin
+ *
+ * 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
+ */
+
+LANGUAGE LANG_RUSSIAN, SUBLANG_DEFAULT
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Íàñòðîéêè ñæàòèÿ"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Âûáåðèòå ïîòîê:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Îïöèè...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "&Ïðîñëàèâàòü êàæäûå",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "ôðåéìà",-1,104,43,36,9
+ LTEXT "Òåêóùèé ôîðìàò:",-1,3,56,53,9
+ LTEXT "Ýòî ìåñòî ñäà¸òñÿ â àðåíäó",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "OK",IDOK,145,42,45,14
+ PUSHBUTTON "Îòìåíà",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Çâóêîâîé ïîòîê: %s"
+ IDS_WAVEFILETYPE "Çâóêîâîé ïîòîê"
+ IDS_ALLMULTIMEDIA "Âñå ôàéëû ìóëüòèìåäèà"
+ IDS_ALLFILES "Âñå ôàéëû (*.*)@*.*"
+ IDS_VIDEO "âèäåî"
+ IDS_AUDIO "àóäèî"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Îáðàáîò÷èê ïî óìîë÷àíèþ avi-ôàéëîâ â Wine"
+ IDS_UNCOMPRESSED "áåç ñæàòèÿ"
+}
--- /dev/null
+/*
+ * Copyright 2003 Rok Mandeljc <rok.mandeljc@gimb.org>
+ *
+ * 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
+ */
+
+LANGUAGE LANG_SLOVENIAN, SUBLANG_DEFAULT
+
+IDD_SAVEOPTIONS DIALOG FIXED IMPURE 43, 37, 196, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Mo\9enosti za stiskanje"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Izbira toka:",-1,2,5,114,10
+ COMBOBOX IDC_STREAM,2,18,134,61,CBS_DROPDOWNLIST | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Mo\9enosti ...",IDC_OPTIONS,145,17,45,14
+ AUTOCHECKBOX "&Preplet vsake",IDC_INTERLEAVE,3,42,60,11,WS_TABSTOP
+ EDITTEXT IDC_INTERLEAVEEVERY,66,41,32,12,ES_AUTOHSCROLL
+ LTEXT "slike",-1,104,43,36,9
+ LTEXT "Trenutna oblika zapisa:",-1,3,56,53,9
+ LTEXT "This space for rent",IDC_FORMATTEXT,55,56,90,26
+ DEFPUSHBUTTON "V redu",IDOK,145,42,45,14
+ PUSHBUTTON "Preklièi",IDCANCEL,145,61,45,14
+END
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_WAVESTREAMFORMAT "Waveform: %s"
+ IDS_WAVEFILETYPE "Waveform"
+ IDS_ALLMULTIMEDIA "Vse veèpredstavnostne datoteke"
+ IDS_ALLFILES "Vse datoteke (*.*)@*.*"
+ IDS_VIDEO "video"
+ IDS_AUDIO "avdio"
+ IDS_AVISTREAMFORMAT "%s %s #%d"
+ IDS_AVIFILETYPE "Privzeti program za obravnavo AVI datotek"
+ IDS_UNCOMPRESSED "nestisnjeno"
+}
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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
+ */
+
+#ifndef __AVIFILE_PRIVATE_H
+#define __AVIFILE_PRIVATE_H
+
+#ifndef MAX_AVISTREAMS
+#define MAX_AVISTREAMS 8
+#endif
+
+#ifndef comptypeDIB
+#define comptypeDIB mmioFOURCC('D','I','B',' ')
+#endif
+
+#ifndef DIBWIDTHBYTES
+#define WIDTHBYTES(i) (((i+31)&(~31))/8)
+#define DIBWIDTHBYTES(bi) WIDTHBYTES((bi).biWidth * (bi).biBitCount)
+#endif
+
+#ifndef DIBPTR
+#define DIBPTR(lp) ((LPBYTE)(lp) + (lp)->biSize + \
+ (lp)->biClrUsed * sizeof(RGBQUAD))
+#endif
+
+#define IDD_SAVEOPTIONS 0x0100
+#define IDC_INTERLEAVE 0x0110
+#define IDC_INTERLEAVEEVERY 0x0111
+#define IDC_STREAM 0x0112
+#define IDC_OPTIONS 0x0113
+#define IDC_FORMATTEXT 0x0114
+
+#define IDS_WAVESTREAMFORMAT 0x0100
+#define IDS_WAVEFILETYPE 0x0101
+#define IDS_ALLMULTIMEDIA 0x0184
+#define IDS_ALLFILES 0x0185
+#define IDS_VIDEO 0x0189
+#define IDS_AUDIO 0x0190
+#define IDS_AVISTREAMFORMAT 0x0191
+#define IDS_AVIFILETYPE 0x0192
+#define IDS_UNCOMPRESSED 0x0193
+
+DEFINE_AVIGUID(CLSID_ICMStream, 0x00020001, 0, 0);
+DEFINE_AVIGUID(CLSID_WAVFile, 0x00020003, 0, 0);
+DEFINE_AVIGUID(CLSID_ACMStream, 0x0002000F, 0, 0);
+DEFINE_AVIGUID(IID_IEditStreamInternal, 0x0002000A,0,0);
+
+extern HMODULE AVIFILE_hModule;
+
+extern HRESULT AVIFILE_CreateAVIFile(REFIID riid, LPVOID *ppobj);
+extern HRESULT AVIFILE_CreateWAVFile(REFIID riid, LPVOID *ppobj);
+extern HRESULT AVIFILE_CreateACMStream(REFIID riid, LPVOID *ppobj);
+extern HRESULT AVIFILE_CreateICMStream(REFIID riid, LPVOID *ppobj);
+extern PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream);
+extern PGETFRAME AVIFILE_CreateGetFrame(PAVISTREAM pstream);
+extern PAVIFILE AVIFILE_CreateAVITempFile(int nStreams,PAVISTREAM *ppStreams);
+
+extern LPCWSTR AVIFILE_BasenameW(LPCWSTR szFileName);
+
+#endif
--- /dev/null
+/*
+ * Copyright 2003 Michael Günnewig
+ *
+ * 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
+ */
+
+#define COM_NO_WINDOWS_H
+#include <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "wingdi.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "windowsx.h"
+#include "mmsystem.h"
+#include "vfw.h"
+
+#include "avifile_private.h"
+#include "extrachunk.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+/***********************************************************************/
+
+/* internal interface to get access to table of stream in an editable stream */
+
+typedef struct _EditStreamTable {
+ PAVISTREAM pStream; /* stream which contains the data */
+ DWORD dwStart; /* where starts the part which is also our */
+ DWORD dwLength; /* how many is also in this stream */
+} EditStreamTable;
+
+#define INTERFACE IEditStreamInternal
+DECLARE_INTERFACE_(IEditStreamInternal,IUnknown)
+{
+ /*** IUnknown methods ***/
+ STDMETHOD_(HRESULT,QueryInterface)(THIS_ REFIID riid, void** ppvObject) PURE;
+ STDMETHOD_(ULONG,AddRef)(THIS) PURE;
+ STDMETHOD_(ULONG,Release)(THIS) PURE;
+ /*** IEditStreamInternal methods ***/
+ STDMETHOD(GetEditStreamImpl)(THIS_ LPVOID*) PURE;
+};
+#undef INTERFACE
+
+#define EditStreamEnd(This,streamNr) ((This)->pStreams[streamNr].dwStart + \
+ (This)->pStreams[streamNr].dwLength)
+
+/***********************************************************************/
+
+static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj);
+static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface);
+static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface);
+static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
+ LONG*plLength,PAVISTREAM*ppResult);
+static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
+ LONG*plLength,PAVISTREAM*ppResult);
+static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
+ LONG*plLength,PAVISTREAM pSource,
+ LONG lStart,LONG lEnd);
+static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
+ PAVISTREAM*ppResult);
+static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
+ LPAVISTREAMINFOW asi,LONG size);
+
+static const struct IAVIEditStreamVtbl ieditstream = {
+ IAVIEditStream_fnQueryInterface,
+ IAVIEditStream_fnAddRef,
+ IAVIEditStream_fnRelease,
+ IAVIEditStream_fnCut,
+ IAVIEditStream_fnCopy,
+ IAVIEditStream_fnPaste,
+ IAVIEditStream_fnClone,
+ IAVIEditStream_fnSetInfo
+};
+
+static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID*obj);
+static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface);
+static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface);
+static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
+static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
+static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
+ LONG flags);
+static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG*formatsize);
+static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
+static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
+ LONG samples,LPVOID buffer,
+ LONG buffersize,LONG*bytesread,
+ LONG*samplesread);
+static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
+ LONG samples,LPVOID buffer,
+ LONG buffersize,DWORD flags,
+ LONG*sampwritten,LONG*byteswritten);
+static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
+static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
+ LPVOID lp,LONG *lpread);
+static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
+ LPVOID lp,LONG size);
+static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
+
+static const struct IAVIStreamVtbl ieditstast = {
+ IEditAVIStream_fnQueryInterface,
+ IEditAVIStream_fnAddRef,
+ IEditAVIStream_fnRelease,
+ IEditAVIStream_fnCreate,
+ IEditAVIStream_fnInfo,
+ IEditAVIStream_fnFindSample,
+ IEditAVIStream_fnReadFormat,
+ IEditAVIStream_fnSetFormat,
+ IEditAVIStream_fnRead,
+ IEditAVIStream_fnWrite,
+ IEditAVIStream_fnDelete,
+ IEditAVIStream_fnReadData,
+ IEditAVIStream_fnWriteData,
+ IEditAVIStream_fnSetInfo
+};
+
+static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj);
+static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface);
+static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface);
+static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl);
+
+static const struct IEditStreamInternalVtbl ieditstreaminternal = {
+ IEditStreamInternal_fnQueryInterface,
+ IEditStreamInternal_fnAddRef,
+ IEditStreamInternal_fnRelease,
+ IEditStreamInternal_fnGetEditStreamImpl
+};
+
+typedef struct _IAVIEditStreamImpl IAVIEditStreamImpl;
+
+typedef struct _IEditAVIStreamImpl {
+ /* IUnknown stuff */
+ const IAVIStreamVtbl *lpVtbl;
+
+ /* IAVIStream stuff */
+ IAVIEditStreamImpl *pae;
+} IEditAVIStreamImpl;
+
+typedef struct _IEditStreamInternalImpl {
+ /* IUnknown stuff */
+ const IEditStreamInternalVtbl *lpVtbl;
+
+ /* IEditStreamInternal stuff */
+ IAVIEditStreamImpl *pae;
+} IEditStreamInternalImpl;
+
+struct _IAVIEditStreamImpl {
+ /* IUnknown stuff */
+ const IAVIEditStreamVtbl *lpVtbl;
+ LONG ref;
+
+ /* IAVIEditStream stuff */
+ IEditAVIStreamImpl iAVIStream;
+ IEditStreamInternalImpl iEditStreamInternal;
+
+ AVISTREAMINFOW sInfo;
+
+ EditStreamTable *pStreams;
+ DWORD nStreams; /* current fill level of pStreams table */
+ DWORD nTableSize; /* size of pStreams table */
+
+ BOOL bDecompress;
+ PAVISTREAM pCurStream;
+ PGETFRAME pg; /* IGetFrame for pCurStream */
+ LPBITMAPINFOHEADER lpFrame; /* frame of pCurStream */
+};
+
+/***********************************************************************/
+
+PAVIEDITSTREAM AVIFILE_CreateEditStream(PAVISTREAM pstream)
+{
+ IAVIEditStreamImpl *pedit = NULL;
+
+ pedit = (IAVIEditStreamImpl*)LocalAlloc(LPTR,sizeof(IAVIEditStreamImpl));
+ if (pedit == NULL)
+ return NULL;
+
+ pedit->lpVtbl = &ieditstream;
+ pedit->iAVIStream.lpVtbl = &ieditstast;
+ pedit->iAVIStream.pae = pedit;
+ pedit->iEditStreamInternal.lpVtbl = &ieditstreaminternal;
+ pedit->iEditStreamInternal.pae = pedit;
+ pedit->ref = 1;
+
+ IAVIStream_Create((PAVISTREAM)&pedit->iAVIStream,(LPARAM)pstream,0);
+
+ return (PAVIEDITSTREAM)pedit;
+}
+
+static HRESULT AVIFILE_FindStreamInTable(IAVIEditStreamImpl* const This,
+ DWORD pos,PAVISTREAM *ppStream,
+ DWORD* streamPos,
+ DWORD* streamNr,BOOL bFindSample)
+{
+ DWORD n;
+
+ TRACE("(%p,%lu,%p,%p,%p,%d)\n",This,pos,ppStream,streamPos,
+ streamNr,bFindSample);
+
+ if (pos < This->sInfo.dwStart)
+ return AVIERR_BADPARAM;
+
+ pos -= This->sInfo.dwStart;
+ for (n = 0; n < This->nStreams; n++) {
+ if (pos < This->pStreams[n].dwLength) {
+ *ppStream = This->pStreams[n].pStream;
+ *streamPos = This->pStreams[n].dwStart + pos;
+ if (streamNr != NULL)
+ *streamNr = n;
+
+ return AVIERR_OK;
+ }
+ pos -= This->pStreams[n].dwLength;
+ }
+ if (pos == 0 && bFindSample) {
+ *ppStream = This->pStreams[--n].pStream;
+ *streamPos = EditStreamEnd(This, n);
+ if (streamNr != NULL)
+ *streamNr = n;
+
+ TRACE(" -- pos=0 && b=1 -> (%p,%lu,%lu)\n",*ppStream, *streamPos, n);
+ return AVIERR_OK;
+ } else {
+ *ppStream = NULL;
+ *streamPos = 0;
+ if (streamNr != NULL)
+ *streamNr = 0;
+
+ TRACE(" -> ERROR (NULL,0,0)\n");
+ return AVIERR_BADPARAM;
+ }
+}
+
+static LPVOID AVIFILE_ReadFrame(IAVIEditStreamImpl* const This,
+ PAVISTREAM pstream, LONG pos)
+{
+ PGETFRAME pg;
+
+ TRACE("(%p,%p,%ld)\n",This,pstream,pos);
+
+ if (pstream == NULL)
+ return NULL;
+
+ /* if stream changes make sure that only palette changes */
+ if (This->pCurStream != pstream) {
+ pg = AVIStreamGetFrameOpen(pstream, NULL);
+ if (pg == NULL)
+ return NULL;
+ if (This->pg != NULL) {
+ if (IGetFrame_SetFormat(pg, This->lpFrame, NULL, 0, 0, -1, -1)) {
+ AVIStreamGetFrameClose(pg);
+ ERR(": IGetFrame_SetFormat failed\n");
+ return NULL;
+ }
+ AVIStreamGetFrameClose(This->pg);
+ }
+ This->pg = pg;
+ This->pCurStream = pstream;
+ }
+
+ /* now get the decompressed frame */
+ This->lpFrame = AVIStreamGetFrame(This->pg, pos);
+ if (This->lpFrame != NULL)
+ This->sInfo.dwSuggestedBufferSize = This->lpFrame->biSizeImage;
+
+ return This->lpFrame;
+}
+
+static HRESULT AVIFILE_RemoveStream(IAVIEditStreamImpl* const This, DWORD nr)
+{
+ assert(This != NULL);
+ assert(nr < This->nStreams);
+
+ /* remove part nr */
+ IAVIStream_Release(This->pStreams[nr].pStream);
+ This->nStreams--;
+ if (This->nStreams - nr > 0) {
+ memmove(This->pStreams + nr, This->pStreams + nr + 1,
+ (This->nStreams - nr) * sizeof(EditStreamTable));
+ }
+ This->pStreams[This->nStreams].pStream = NULL;
+ This->pStreams[This->nStreams].dwStart = 0;
+ This->pStreams[This->nStreams].dwLength = 0;
+
+ /* try to merge the part before the deleted one and the one after it */
+ if (0 < nr && 0 < This->nStreams &&
+ This->pStreams[nr - 1].pStream == This->pStreams[nr].pStream) {
+ if (EditStreamEnd(This, nr - 1) == This->pStreams[nr].dwStart) {
+ This->pStreams[nr - 1].dwLength += This->pStreams[nr].dwLength;
+ return AVIFILE_RemoveStream(This, nr);
+ }
+ }
+
+ return AVIERR_OK;
+}
+
+static BOOL AVIFILE_FormatsEqual(PAVISTREAM avi1, PAVISTREAM avi2)
+{
+ LPVOID fmt1 = NULL, fmt2 = NULL;
+ LONG size1, size2, start1, start2;
+ BOOL status = FALSE;
+
+ assert(avi1 != NULL && avi2 != NULL);
+
+ /* get stream starts and check format sizes */
+ start1 = AVIStreamStart(avi1);
+ start2 = AVIStreamStart(avi2);
+ if (FAILED(AVIStreamFormatSize(avi1, start1, &size1)))
+ return FALSE;
+ if (FAILED(AVIStreamFormatSize(avi2, start2, &size2)))
+ return FALSE;
+ if (size1 != size2)
+ return FALSE;
+
+ /* sizes match, now get formats and compare them */
+ fmt1 = GlobalAllocPtr(GHND, size1);
+ if (fmt1 == NULL)
+ return FALSE;
+ if (SUCCEEDED(AVIStreamReadFormat(avi1, start1, fmt1, &size1))) {
+ fmt2 = GlobalAllocPtr(GHND, size1);
+ if (fmt2 != NULL) {
+ if (SUCCEEDED(AVIStreamReadFormat(avi2, start2, fmt2, &size1)))
+ status = (memcmp(fmt1, fmt2, size1) == 0);
+ }
+ }
+
+ if (fmt2 != NULL)
+ GlobalFreePtr(fmt2);
+ GlobalFreePtr(fmt1);
+
+ return status;
+}
+
+/***********************************************************************/
+
+static HRESULT WINAPI IAVIEditStream_fnQueryInterface(IAVIEditStream*iface,REFIID refiid,LPVOID *obj)
+{
+ IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
+
+ TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
+
+ if (IsEqualGUID(&IID_IUnknown, refiid) ||
+ IsEqualGUID(&IID_IAVIEditStream, refiid)) {
+ *obj = iface;
+ IAVIEditStream_AddRef(iface);
+
+ return S_OK;
+ } else if (IsEqualGUID(&IID_IAVIStream, refiid)) {
+ *obj = &This->iAVIStream;
+ IAVIEditStream_AddRef(iface);
+
+ return S_OK;
+ } else if (IsEqualGUID(&IID_IEditStreamInternal, refiid)) {
+ *obj = &This->iEditStreamInternal;
+ IAVIEditStream_AddRef(iface);
+
+ return S_OK;
+ }
+
+ return OLE_E_ENUM_NOMORE;
+}
+
+static ULONG WINAPI IAVIEditStream_fnAddRef(IAVIEditStream*iface)
+{
+ IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI IAVIEditStream_fnRelease(IAVIEditStream*iface)
+{
+ IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
+ DWORD i;
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ if (!ref) {
+ /* release memory */
+ if (This->pg != NULL)
+ AVIStreamGetFrameClose(This->pg);
+ if (This->pStreams != NULL) {
+ for (i = 0; i < This->nStreams; i++) {
+ if (This->pStreams[i].pStream != NULL)
+ IAVIStream_Release(This->pStreams[i].pStream);
+ }
+ GlobalFreePtr(This->pStreams);
+ }
+
+ LocalFree((HLOCAL)This);
+ return 0;
+ }
+ return ref;
+}
+
+static HRESULT WINAPI IAVIEditStream_fnCut(IAVIEditStream*iface,LONG*plStart,
+ LONG*plLength,PAVISTREAM*ppResult)
+{
+ IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
+ PAVISTREAM stream;
+ DWORD start, len, streamPos, streamNr;
+ HRESULT hr;
+
+ TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
+
+ if (ppResult != NULL)
+ *ppResult = NULL;
+ if (plStart == NULL || plLength == NULL || *plStart < 0)
+ return AVIERR_BADPARAM;
+
+ /* if asked for cutted part copy it before deleting */
+ if (ppResult != NULL) {
+ hr = IAVIEditStream_Copy(iface, plStart, plLength, ppResult);
+ if (FAILED(hr))
+ return hr;
+ }
+
+ start = *plStart;
+ len = *plLength;
+
+ /* now delete the requested part */
+ while (len > 0) {
+ hr = AVIFILE_FindStreamInTable(This, start, &stream,
+ &streamPos, &streamNr, FALSE);
+ if (FAILED(hr))
+ return hr;
+ if (This->pStreams[streamNr].dwStart == streamPos) {
+ /* deleting from start of part */
+ if (len < This->pStreams[streamNr].dwLength) {
+ start += len;
+ This->pStreams[streamNr].dwStart += len;
+ This->pStreams[streamNr].dwLength -= len;
+ This->sInfo.dwLength -= len;
+ len = 0;
+
+ /* we must return decompressed data now */
+ This->bDecompress = TRUE;
+ } else {
+ /* deleting hole part */
+ len -= This->pStreams[streamNr].dwLength;
+ AVIFILE_RemoveStream(This,streamNr);
+ }
+ } else if (EditStreamEnd(This, streamNr) <= streamPos + len) {
+ /* deleting at end of a part */
+ DWORD count = EditStreamEnd(This, streamNr) - streamPos;
+ This->sInfo.dwLength -= count;
+ len -= count;
+ This->pStreams[streamNr].dwLength =
+ streamPos - This->pStreams[streamNr].dwStart;
+ } else {
+ /* splitting */
+ if (This->nStreams + 1 >= This->nTableSize) {
+ This->pStreams =
+ GlobalReAllocPtr(This->pStreams, (This->nTableSize + 32) * sizeof(EditStreamTable), GMEM_SHARE|GHND);
+ if (This->pStreams == NULL)
+ return AVIERR_MEMORY;
+ This->nTableSize += 32;
+ }
+ memmove(This->pStreams + streamNr + 1, This->pStreams + streamNr,
+ (This->nStreams - streamNr) * sizeof(EditStreamTable));
+ This->nStreams++;
+
+ IAVIStream_AddRef(This->pStreams[streamNr + 1].pStream);
+ This->pStreams[streamNr + 1].dwStart = streamPos + len;
+ This->pStreams[streamNr + 1].dwLength =
+ EditStreamEnd(This, streamNr) - This->pStreams[streamNr + 1].dwStart;
+
+ This->pStreams[streamNr].dwLength =
+ streamPos - This->pStreams[streamNr].dwStart;
+ This->sInfo.dwLength -= len;
+ len = 0;
+ }
+ }
+
+ This->sInfo.dwEditCount++;
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIEditStream_fnCopy(IAVIEditStream*iface,LONG*plStart,
+ LONG*plLength,PAVISTREAM*ppResult)
+{
+ IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
+ IAVIEditStreamImpl* pEdit;
+ HRESULT hr;
+ LONG start = 0;
+
+ TRACE("(%p,%p,%p,%p)\n",iface,plStart,plLength,ppResult);
+
+ if (ppResult == NULL)
+ return AVIERR_BADPARAM;
+ *ppResult = NULL;
+ if (plStart == NULL || plLength == NULL || *plStart < 0 || *plLength < 0)
+ return AVIERR_BADPARAM;
+
+ /* check bounds */
+ if (*(LPDWORD)plLength > This->sInfo.dwLength)
+ *(LPDWORD)plLength = This->sInfo.dwLength;
+ if (*(LPDWORD)plStart < This->sInfo.dwStart) {
+ *(LPDWORD)plLength -= This->sInfo.dwStart - *(LPDWORD)plStart;
+ *(LPDWORD)plStart = This->sInfo.dwStart;
+ if (*plLength < 0)
+ return AVIERR_BADPARAM;
+ }
+ if (*(LPDWORD)plStart + *(LPDWORD)plLength > This->sInfo.dwStart + This->sInfo.dwLength)
+ *(LPDWORD)plLength = This->sInfo.dwStart + This->sInfo.dwLength -
+ *(LPDWORD)plStart;
+
+ pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
+ if (pEdit == NULL)
+ return AVIERR_MEMORY;
+
+ hr = IAVIEditStream_Paste((PAVIEDITSTREAM)pEdit,&start,plLength,
+ (PAVISTREAM)&This->iAVIStream,*plStart,
+ *plStart + *plLength);
+ *plStart = start;
+ if (FAILED(hr))
+ IAVIEditStream_Release((PAVIEDITSTREAM)pEdit);
+ else
+ *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
+
+ return hr;
+}
+
+static HRESULT WINAPI IAVIEditStream_fnPaste(IAVIEditStream*iface,LONG*plStart,
+ LONG*plLength,PAVISTREAM pSource,
+ LONG lStart,LONG lLength)
+{
+ IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
+ AVISTREAMINFOW srcInfo;
+ IEditStreamInternal*pInternal = NULL;
+ IAVIEditStreamImpl *pEdit = NULL;
+ PAVISTREAM pStream;
+ DWORD startPos, endPos, streamNr, nStreams;
+ ULONG n;
+
+ TRACE("(%p,%p,%p,%p,%ld,%ld)\n",iface,plStart,plLength,
+ pSource,lStart,lLength);
+
+ if (pSource == NULL)
+ return AVIERR_BADHANDLE;
+ if (plStart == NULL || *plStart < 0)
+ return AVIERR_BADPARAM;
+ if (This->sInfo.dwStart + This->sInfo.dwLength < *plStart)
+ return AVIERR_BADPARAM; /* Can't paste with holes */
+ if (FAILED(IAVIStream_Info(pSource, &srcInfo, sizeof(srcInfo))))
+ return AVIERR_ERROR;
+ if (lStart < srcInfo.dwStart || lStart >= srcInfo.dwStart + srcInfo.dwLength)
+ return AVIERR_BADPARAM;
+ if (This->sInfo.fccType == 0) {
+ /* This stream is empty */
+ IAVIStream_Info(pSource, &This->sInfo, sizeof(This->sInfo));
+ This->sInfo.dwStart = *plStart;
+ This->sInfo.dwLength = 0;
+ }
+ if (This->sInfo.fccType != srcInfo.fccType)
+ return AVIERR_UNSUPPORTED; /* different stream types */
+ if (lLength == -1) /* Copy the hole stream */
+ lLength = srcInfo.dwLength;
+ if (lStart + lLength > srcInfo.dwStart + srcInfo.dwLength)
+ lLength = srcInfo.dwStart + srcInfo.dwLength - lStart;
+ if (lLength + *plStart >= 0x80000000)
+ return AVIERR_MEMORY;
+
+ /* streamtype specific tests */
+ if (srcInfo.fccType == streamtypeVIDEO) {
+ LONG size;
+
+ size = srcInfo.rcFrame.right - srcInfo.rcFrame.left;
+ if (size != This->sInfo.rcFrame.right - This->sInfo.rcFrame.left)
+ return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
+ size = srcInfo.rcFrame.bottom - srcInfo.rcFrame.top;
+ if (size != This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top)
+ return AVIERR_UNSUPPORTED; /* FIXME: Can't GetFrame convert it? */
+ } else if (srcInfo.fccType == streamtypeAUDIO) {
+ if (! AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))
+ return AVIERR_UNSUPPORTED;
+ } else {
+ /* FIXME: streamtypeMIDI and streamtypeTEXT */
+ return AVIERR_UNSUPPORTED;
+ }
+
+ /* try to get an IEditStreamInternal interface */
+ if (SUCCEEDED(IAVIStream_QueryInterface(pSource, &IID_IEditStreamInternal,
+ (LPVOID*)&pInternal))) {
+ pInternal->lpVtbl->GetEditStreamImpl(pInternal, (LPVOID*)&pEdit);
+ pInternal->lpVtbl->Release(pInternal);
+ }
+
+ /* for video must check for change of format */
+ if (This->sInfo.fccType == streamtypeVIDEO) {
+ if (! This->bDecompress) {
+ /* Need to decompress if any of the following conditions matches:
+ * - pSource is an editable stream which decompresses
+ * - the nearest keyframe of pSource isn't lStart
+ * - the nearest keyframe of this stream isn't *plStart
+ * - the format of pSource doesn't match this one
+ */
+ if ((pEdit != NULL && pEdit->bDecompress) ||
+ AVIStreamNearestKeyFrame(pSource, lStart) != lStart ||
+ AVIStreamNearestKeyFrame((PAVISTREAM)&This->iAVIStream, *plStart) != *plStart ||
+ (This->nStreams > 0 && !AVIFILE_FormatsEqual((PAVISTREAM)&This->iAVIStream, pSource))) {
+ /* Use first stream part to get format to convert everything to */
+ AVIFILE_ReadFrame(This, This->pStreams[0].pStream,
+ This->pStreams[0].dwStart);
+
+ /* Check if we could convert the source streams to the disired format... */
+ if (pEdit != NULL) {
+ if (FAILED(AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
+ &startPos, &streamNr, TRUE)))
+ return AVIERR_INTERNAL;
+ for (n = lStart; n < lStart + lLength; streamNr++) {
+ if (AVIFILE_ReadFrame(This, pEdit->pStreams[streamNr].pStream, startPos) == NULL)
+ return AVIERR_BADFORMAT;
+ startPos = pEdit->pStreams[streamNr].dwStart;
+ n += pEdit->pStreams[streamNr].dwLength;
+ }
+ } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
+ return AVIERR_BADFORMAT;
+
+ This->bDecompress = TRUE;
+ This->sInfo.fccHandler = 0;
+ }
+ } else if (AVIFILE_ReadFrame(This, pSource, lStart) == NULL)
+ return AVIERR_BADFORMAT; /* Can't convert source to own format */
+ } /* FIXME: something special for the other formats? */
+
+ /* Make sure we have enough memory for parts */
+ if (pEdit != NULL) {
+ DWORD nLastStream;
+
+ AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
+ &endPos, &nLastStream, TRUE);
+ AVIFILE_FindStreamInTable(pEdit, lStart, &pStream,
+ &startPos, &streamNr, FALSE);
+ if (nLastStream == streamNr)
+ nLastStream++;
+
+ nStreams = nLastStream - streamNr;
+ } else
+ nStreams = 1;
+ if (This->nStreams + nStreams + 1 > This->nTableSize) {
+ n = This->nStreams + nStreams + 33;
+
+ This->pStreams =
+ GlobalReAllocPtr(This->pStreams, n * sizeof(EditStreamTable), GMEM_SHARE|GHND);
+ if (This->pStreams == NULL)
+ return AVIERR_MEMORY;
+ This->nTableSize = n;
+ }
+
+ if (plLength != NULL)
+ *plLength = lLength;
+
+ /* now do the real work */
+ if (This->sInfo.dwStart + This->sInfo.dwLength > *plStart) {
+ AVIFILE_FindStreamInTable(This, *plStart, &pStream,
+ &startPos, &streamNr, FALSE);
+ if (startPos != This->pStreams[streamNr].dwStart) {
+ /* split stream streamNr at startPos */
+ memmove(This->pStreams + streamNr + nStreams + 1,
+ This->pStreams + streamNr,
+ (This->nStreams + nStreams - streamNr + 1) * sizeof(EditStreamTable));
+
+ This->pStreams[streamNr + 2].dwLength =
+ EditStreamEnd(This, streamNr + 2) - startPos;
+ This->pStreams[streamNr + 2].dwStart = startPos;
+ This->pStreams[streamNr].dwLength =
+ startPos - This->pStreams[streamNr].dwStart;
+ IAVIStream_AddRef(This->pStreams[streamNr].pStream);
+ streamNr++;
+ } else {
+ /* insert before stream at streamNr */
+ memmove(This->pStreams + streamNr + nStreams, This->pStreams + streamNr,
+ (This->nStreams + nStreams - streamNr) * sizeof(EditStreamTable));
+ }
+ } else /* append the streams */
+ streamNr = This->nStreams;
+
+ if (pEdit != NULL) {
+ /* insert the parts of the editable stream instead of itself */
+ AVIFILE_FindStreamInTable(pEdit, lStart + lLength, &pStream,
+ &endPos, NULL, FALSE);
+ AVIFILE_FindStreamInTable(pEdit, lStart, &pStream, &startPos, &n, FALSE);
+
+ memcpy(This->pStreams + streamNr, pEdit->pStreams + n,
+ nStreams * sizeof(EditStreamTable));
+ if (This->pStreams[streamNr].dwStart < startPos) {
+ This->pStreams[streamNr].dwLength =
+ EditStreamEnd(This, streamNr) - startPos;
+ This->pStreams[streamNr].dwStart = startPos;
+ }
+ if (endPos < EditStreamEnd(This, streamNr + nStreams))
+ This->pStreams[streamNr + nStreams].dwLength =
+ endPos - This->pStreams[streamNr + nStreams].dwStart;
+ } else {
+ /* a simple stream */
+ This->pStreams[streamNr].pStream = pSource;
+ This->pStreams[streamNr].dwStart = lStart;
+ This->pStreams[streamNr].dwLength = lLength;
+ }
+
+ for (n = 0; n < nStreams; n++) {
+ IAVIStream_AddRef(This->pStreams[streamNr + n].pStream);
+ if (0 < streamNr + n &&
+ This->pStreams[streamNr + n - 1].pStream != This->pStreams[streamNr + n].pStream) {
+ This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
+ This->sInfo.dwFormatChangeCount++;
+ }
+ }
+ This->sInfo.dwEditCount++;
+ This->sInfo.dwLength += lLength;
+ This->nStreams += nStreams;
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIEditStream_fnClone(IAVIEditStream*iface,
+ PAVISTREAM*ppResult)
+{
+ IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
+ IAVIEditStreamImpl* pEdit;
+ DWORD i;
+
+ TRACE("(%p,%p)\n",iface,ppResult);
+
+ if (ppResult == NULL)
+ return AVIERR_BADPARAM;
+ *ppResult = NULL;
+
+ pEdit = (IAVIEditStreamImpl*)AVIFILE_CreateEditStream(NULL);
+ if (pEdit == NULL)
+ return AVIERR_MEMORY;
+ if (This->nStreams > pEdit->nTableSize) {
+ pEdit->pStreams = GlobalReAllocPtr(pEdit->pStreams, This->nStreams * sizeof(EditStreamTable),GMEM_SHARE|GHND);
+ if (pEdit->pStreams == NULL)
+ return AVIERR_MEMORY;
+ pEdit->nTableSize = This->nStreams;
+ }
+ pEdit->nStreams = This->nStreams;
+ memcpy(pEdit->pStreams, This->pStreams,
+ This->nStreams * sizeof(EditStreamTable));
+ memcpy(&pEdit->sInfo,&This->sInfo,sizeof(This->sInfo));
+ for (i = 0; i < This->nStreams; i++) {
+ if (pEdit->pStreams[i].pStream != NULL)
+ IAVIStream_AddRef(pEdit->pStreams[i].pStream);
+ }
+
+ *ppResult = (PAVISTREAM)&pEdit->iAVIStream;
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIEditStream_fnSetInfo(IAVIEditStream*iface,
+ LPAVISTREAMINFOW asi,LONG size)
+{
+ IAVIEditStreamImpl *This = (IAVIEditStreamImpl *)iface;
+
+ TRACE("(%p,%p,%ld)\n",iface,asi,size);
+
+ /* check parameters */
+ if (asi == NULL)
+ return AVIERR_BADPARAM;
+ if (size != sizeof(AVISTREAMINFOW))
+ return AVIERR_BADSIZE;
+ if (asi->dwScale == 0 || asi->dwRate == 0 || (LONG)asi->dwQuality < -1 ||
+ asi->dwQuality > ICQUALITY_HIGH)
+ return AVIERR_ERROR;
+
+ This->sInfo.wLanguage = asi->wLanguage;
+ This->sInfo.wPriority = asi->wPriority;
+ This->sInfo.dwStart = asi->dwStart;
+ if (asi->dwRate != 0)
+ This->sInfo.dwRate = asi->dwRate;
+ if (asi->dwScale != 0)
+ This->sInfo.dwScale = asi->dwScale;
+ if (asi->dwQuality <= ICQUALITY_HIGH)
+ This->sInfo.dwQuality = ICQUALITY_HIGH;
+ CopyRect(&This->sInfo.rcFrame, &asi->rcFrame);
+ memcpy(&This->sInfo.szName, &asi->szName, sizeof(asi->szName));
+ This->sInfo.dwEditCount++;
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IEditAVIStream_fnQueryInterface(IAVIStream*iface,
+ REFIID refiid,LPVOID*obj)
+{
+ IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
+
+ assert(This->pae != NULL);
+
+ return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae,refiid,obj);
+}
+
+static ULONG WINAPI IEditAVIStream_fnAddRef(IAVIStream*iface)
+{
+ IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
+
+ assert(This->pae != NULL);
+
+ return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
+}
+
+static ULONG WINAPI IEditAVIStream_fnRelease(IAVIStream*iface)
+{
+ IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
+
+ assert(This->pae != NULL);
+
+ return IAVIEditStream_Release((IAVIEditStream*)This->pae);
+}
+
+static HRESULT WINAPI IEditAVIStream_fnCreate(IAVIStream*iface,
+ LPARAM lParam1,LPARAM lParam2)
+{
+ IAVIEditStreamImpl *This = ((IEditAVIStreamImpl*)iface)->pae;
+
+ if (lParam2 != 0)
+ return AVIERR_ERROR;
+
+ if (This->pStreams == NULL) {
+ This->pStreams =
+ GlobalAllocPtr(GMEM_SHARE|GHND, 256 * sizeof(EditStreamTable));
+ if (This->pStreams == NULL)
+ return AVIERR_MEMORY;
+ This->nTableSize = 256;
+ }
+
+ if (lParam1 != 0) {
+ IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
+ IAVIStream_AddRef((PAVISTREAM)lParam1);
+ This->pStreams[0].pStream = (PAVISTREAM)lParam1;
+ This->pStreams[0].dwStart = This->sInfo.dwStart;
+ This->pStreams[0].dwLength = This->sInfo.dwLength;
+ This->nStreams = 1;
+ }
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IEditAVIStream_fnInfo(IAVIStream*iface,
+ AVISTREAMINFOW *psi,LONG size)
+{
+ IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
+
+ TRACE("(%p,%p,%ld)\n",iface,psi,size);
+
+ assert(This->pae != NULL);
+
+ if (psi == NULL)
+ return AVIERR_BADPARAM;
+ if (size < 0)
+ return AVIERR_BADSIZE;
+
+ if (This->pae->bDecompress)
+ This->pae->sInfo.fccHandler = 0;
+
+ memcpy(psi, &This->pae->sInfo, min((DWORD)size, sizeof(This->pae->sInfo)));
+
+ if ((DWORD)size < sizeof(This->pae->sInfo))
+ return AVIERR_BUFFERTOOSMALL;
+ return AVIERR_OK;
+}
+
+static LONG WINAPI IEditAVIStream_fnFindSample(IAVIStream*iface,LONG pos,
+ LONG flags)
+{
+ IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
+ PAVISTREAM stream;
+ DWORD streamPos, streamNr;
+
+ TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
+
+ if (flags & FIND_FROM_START)
+ pos = (LONG)This->sInfo.dwStart;
+
+ /* outside of stream? */
+ if (pos < (LONG)This->sInfo.dwStart ||
+ (LONG)This->sInfo.dwStart + (LONG)This->sInfo.dwLength <= pos)
+ return -1;
+
+ /* map our position to a stream and position in it */
+ if (AVIFILE_FindStreamInTable(This, pos, &stream, &streamPos,
+ &streamNr, TRUE))
+ return -1; /* doesn't exist */
+
+ if (This->bDecompress) {
+ /* only one stream -- format changes only at start */
+ if (flags & FIND_FORMAT)
+ return (flags & FIND_NEXT ? -1 : 0);
+
+ /* FIXME: map positions back to us */
+ return IAVIStream_FindSample(stream, streamPos, flags);
+ } else {
+ /* assume change of format every frame */
+ return pos;
+ }
+}
+
+static HRESULT WINAPI IEditAVIStream_fnReadFormat(IAVIStream*iface,LONG pos,
+ LPVOID format,LONG*fmtsize)
+{
+ IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
+ LPBITMAPINFOHEADER lp;
+ PAVISTREAM stream;
+ DWORD n;
+ HRESULT hr;
+
+ TRACE("(%p,%ld,%p,%p)\n",iface,pos,format,fmtsize);
+
+ if (fmtsize == NULL || pos < This->sInfo.dwStart ||
+ This->sInfo.dwStart + This->sInfo.dwLength <= pos)
+ return AVIERR_BADPARAM;
+
+ /* find stream corresponding to position */
+ hr = AVIFILE_FindStreamInTable(This, pos, &stream, &n, NULL, FALSE);
+ if (FAILED(hr))
+ return hr;
+
+ if (! This->bDecompress)
+ return IAVIStream_ReadFormat(stream, n, format, fmtsize);
+
+ lp = (LPBITMAPINFOHEADER)AVIFILE_ReadFrame(This, stream, n);
+ if (lp == NULL)
+ return AVIERR_ERROR;
+ if (lp->biBitCount <= 8) {
+ n = (lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount);
+ n *= sizeof(RGBQUAD);
+ } else
+ n = 0;
+ n += lp->biSize;
+
+ memcpy(format, lp, min((LONG)n, *fmtsize));
+ hr = ((LONG)n > *fmtsize ? AVIERR_BUFFERTOOSMALL : AVIERR_OK);
+ *fmtsize = n;
+
+ return hr;
+}
+
+static HRESULT WINAPI IEditAVIStream_fnSetFormat(IAVIStream*iface,LONG pos,
+ LPVOID format,LONG formatsize)
+{
+ TRACE("(%p,%ld,%p,%ld)\n",iface,pos,format,formatsize);
+
+ return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IEditAVIStream_fnRead(IAVIStream*iface,LONG start,
+ LONG samples,LPVOID buffer,
+ LONG buffersize,LONG*bytesread,
+ LONG*samplesread)
+{
+ IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
+ PAVISTREAM stream;
+ DWORD streamPos, streamNr;
+ LONG readBytes, readSamples, count;
+ HRESULT hr;
+
+ TRACE("(%p,%ld,%ld,%p,%ld,%p,%p) -- 0x%08lX\n",iface,start,samples,
+ buffer,buffersize,bytesread,samplesread,This->sInfo.fccType);
+
+ /* check parameters */
+ if (bytesread != NULL)
+ *bytesread = 0;
+ if (samplesread != NULL)
+ *samplesread = 0;
+ if (buffersize < 0)
+ return AVIERR_BADSIZE;
+ if ((DWORD)start < This->sInfo.dwStart ||
+ This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
+ return AVIERR_BADPARAM;
+
+ if (! This->bDecompress) {
+ /* audio like data -- sample-based */
+ do {
+ if (samples == 0)
+ return AVIERR_OK; /* nothing at all or already done */
+
+ if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
+ &streamPos, &streamNr, FALSE)))
+ return AVIERR_ERROR;
+
+ /* limit to end of the stream */
+ count = samples;
+ if (streamPos + count > EditStreamEnd(This, streamNr))
+ count = EditStreamEnd(This, streamNr) - streamPos;
+
+ hr = IAVIStream_Read(stream, streamPos, count, buffer, buffersize,
+ &readBytes, &readSamples);
+ if (FAILED(hr))
+ return hr;
+ if (readBytes == 0 && readSamples == 0 && count != 0)
+ return AVIERR_FILEREAD; /* for bad stream implementations */
+
+ if (samplesread != NULL)
+ *samplesread += readSamples;
+ if (bytesread != NULL)
+ *bytesread += readBytes;
+ if (buffer != NULL) {
+ buffer = ((LPBYTE)buffer)+readBytes;
+ buffersize -= readBytes;
+ }
+ start += count;
+ samples -= count;
+ } while (This->sInfo.dwStart + This->sInfo.dwLength > start);
+ } else {
+ /* video like data -- frame-based */
+ LPBITMAPINFOHEADER lp;
+
+ if (samples == 0)
+ return AVIERR_OK;
+
+ if (FAILED(AVIFILE_FindStreamInTable(This, start, &stream,
+ &streamPos, &streamNr, FALSE)))
+ return AVIERR_ERROR;
+
+ lp = AVIFILE_ReadFrame(This, stream, streamPos);
+ if (lp == NULL)
+ return AVIERR_ERROR;
+
+ if (buffer != NULL) {
+ /* need size of format to skip */
+ if (lp->biBitCount <= 8) {
+ count = lp->biClrUsed > 0 ? lp->biClrUsed : 1 << lp->biBitCount;
+ count *= sizeof(RGBQUAD);
+ } else
+ count = 0;
+ count += lp->biSize;
+
+ if (buffersize < lp->biSizeImage)
+ return AVIERR_BUFFERTOOSMALL;
+ memcpy(buffer, (LPBYTE)lp + count, lp->biSizeImage);
+ }
+
+ if (bytesread != NULL)
+ *bytesread = lp->biSizeImage;
+ if (samplesread != NULL)
+ *samplesread = 1;
+ }
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IEditAVIStream_fnWrite(IAVIStream*iface,LONG start,
+ LONG samples,LPVOID buffer,
+ LONG buffersize,DWORD flags,
+ LONG*sampwritten,LONG*byteswritten)
+{
+ TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n",iface,start,samples,buffer,
+ buffersize,flags,sampwritten,byteswritten);
+
+ /* be sure return parameters have correct values */
+ if (sampwritten != NULL)
+ *sampwritten = 0;
+ if (byteswritten != NULL)
+ *byteswritten = 0;
+
+ return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IEditAVIStream_fnDelete(IAVIStream*iface,LONG start,
+ LONG samples)
+{
+ IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
+
+ TRACE("(%p,%ld,%ld)\n",iface,start,samples);
+
+ return IAVIEditStream_Cut((IAVIEditStream*)This->pae,&start,&samples,NULL);
+}
+
+static HRESULT WINAPI IEditAVIStream_fnReadData(IAVIStream*iface,DWORD fcc,
+ LPVOID lp,LONG *lpread)
+{
+ IAVIEditStreamImpl* const This = ((IEditAVIStreamImpl* const)iface)->pae;
+ DWORD n;
+
+ TRACE("(%p,0x%08lX,%p,%p)\n",iface,fcc,lp,lpread);
+
+ /* check parameters */
+ if (lp == NULL || lpread == NULL)
+ return AVIERR_BADPARAM;
+
+ /* simply ask every stream and return the first block found */
+ for (n = 0; n < This->nStreams; n++) {
+ HRESULT hr = IAVIStream_ReadData(This->pStreams[n].pStream,fcc,lp,lpread);
+
+ if (SUCCEEDED(hr))
+ return hr;
+ }
+
+ *lpread = 0;
+ return AVIERR_NODATA;
+}
+
+static HRESULT WINAPI IEditAVIStream_fnWriteData(IAVIStream*iface,DWORD fcc,
+ LPVOID lp,LONG size)
+{
+ TRACE("(%p,0x%08lX,%p,%ld)\n",iface,fcc,lp,size);
+
+ return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IEditAVIStream_fnSetInfo(IAVIStream*iface,
+ AVISTREAMINFOW*info,LONG len)
+{
+ IEditAVIStreamImpl *This = (IEditAVIStreamImpl *)iface;
+
+ TRACE("(%p,%p,%ld)\n",iface,info,len);
+
+ return IAVIEditStream_SetInfo((IAVIEditStream*)This->pae,info,len);
+}
+
+static HRESULT WINAPI IEditStreamInternal_fnQueryInterface(IEditStreamInternal*iface,REFIID refiid,LPVOID*obj)
+{
+ IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
+
+ assert(This->pae != NULL);
+
+ return IAVIEditStream_QueryInterface((IAVIEditStream*)This->pae, refiid, obj);
+}
+
+static ULONG WINAPI IEditStreamInternal_fnAddRef(IEditStreamInternal*iface)
+{
+ IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
+
+ assert(This->pae != NULL);
+
+ return IAVIEditStream_AddRef((IAVIEditStream*)This->pae);
+}
+
+static ULONG WINAPI IEditStreamInternal_fnRelease(IEditStreamInternal*iface)
+{
+ IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
+
+ assert(This->pae != NULL);
+
+ return IAVIEditStream_Release((IAVIEditStream*)This->pae);
+}
+
+static HRESULT WINAPI IEditStreamInternal_fnGetEditStreamImpl(IEditStreamInternal*iface,LPVOID*ppimpl)
+{
+ IEditStreamInternalImpl *This = (IEditStreamInternalImpl *)iface;
+
+ TRACE("(%p,%p) -> %p\n", iface, ppimpl, This->pae);
+
+ assert(This->pae != NULL);
+ assert(ppimpl != NULL);
+
+ *ppimpl = This->pae;
+ return AVIERR_OK;
+}
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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
+ */
+
+#define COM_NO_WINDOWS_H
+#include <assert.h>
+
+#include "extrachunk.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "windowsx.h"
+#include "vfw.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+/* reads a chunk outof the extrachunk-structure */
+HRESULT ReadExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPVOID lpData,
+ LPLONG size)
+{
+ LPBYTE lp;
+ DWORD cb;
+
+ /* pre-conditions */
+ assert(extra != NULL);
+ assert(size != NULL);
+
+ lp = extra->lp;
+ cb = extra->cb;
+
+ if (lp != NULL) {
+ while (cb > 0) {
+ if (((FOURCC*)lp)[0] == ckid) {
+ /* found correct chunk */
+ if (lpData != NULL && *size > 0)
+ memcpy(lpData, lp + 2 * sizeof(DWORD),
+ min(((LPDWORD)lp)[1], *(LPDWORD)size));
+
+ *(LPDWORD)size = ((LPDWORD)lp)[1];
+
+ return AVIERR_OK;
+ } else {
+ /* skip to next chunk */
+ cb -= ((LPDWORD)lp)[1] + 2 * sizeof(DWORD);
+ lp += ((LPDWORD)lp)[1] + 2 * sizeof(DWORD);
+ }
+ }
+ }
+
+ /* wanted chunk doesn't exist */
+ *size = 0;
+
+ return AVIERR_NODATA;
+}
+
+/* writes a chunk into the extrachunk-structure */
+HRESULT WriteExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPVOID lpData,
+ LONG size)
+{
+ LPDWORD lp;
+
+ /* pre-conditions */
+ assert(extra != NULL);
+ assert(lpData != NULL);
+ assert(size > 0);
+
+ if (extra->lp)
+ lp = (LPDWORD)GlobalReAllocPtr(extra->lp, extra->cb + size + 2 * sizeof(DWORD), GHND);
+ else
+ lp = (LPDWORD)GlobalAllocPtr(GHND, size + 2 * sizeof(DWORD));
+
+ if (lp == NULL)
+ return AVIERR_MEMORY;
+
+ extra->lp = lp;
+ lp = (LPDWORD) ((LPBYTE)lp + extra->cb);
+ extra->cb += size + 2 * sizeof(DWORD);
+
+ /* insert chunk-header in block */
+ lp[0] = ckid;
+ lp[1] = size;
+
+ if (lpData != NULL && size > 0)
+ memcpy(lp + 2, lpData, size);
+
+ return AVIERR_OK;
+}
+
+/* reads a chunk fomr the HMMIO into the extrachunk-structure */
+HRESULT ReadChunkIntoExtra(LPEXTRACHUNKS extra,HMMIO hmmio,MMCKINFO *lpck)
+{
+ LPDWORD lp;
+ DWORD cb;
+
+ /* pre-conditions */
+ assert(extra != NULL);
+ assert(hmmio != NULL);
+ assert(lpck != NULL);
+
+ cb = lpck->cksize + 2 * sizeof(DWORD);
+ cb += (cb & 1);
+
+ if (extra->lp != NULL) {
+ lp = (LPDWORD)GlobalReAllocPtr(extra->lp, extra->cb + cb, GHND);
+ } else
+ lp = (LPDWORD)GlobalAllocPtr(GHND, cb);
+
+ if (lp == NULL)
+ return AVIERR_MEMORY;
+
+ extra->lp = lp;
+ lp = (LPDWORD) ((LPBYTE)lp + extra->cb);
+ extra->cb += cb;
+
+ /* insert chunk-header in block */
+ lp[0] = lpck->ckid;
+ lp[1] = lpck->cksize;
+
+ if (lpck->cksize > 0) {
+ if (mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET) == -1)
+ return AVIERR_FILEREAD;
+ if (mmioRead(hmmio, (HPSTR)&lp[2], lpck->cksize) != (LONG)lpck->cksize)
+ return AVIERR_FILEREAD;
+ }
+
+ return AVIERR_OK;
+}
+
+/* reads all non-junk chunks into the extrachunk-structure until it finds
+ * the given chunk or the optional parent-chunk is at the end */
+HRESULT FindChunkAndKeepExtras(LPEXTRACHUNKS extra,HMMIO hmmio,MMCKINFO *lpck,
+ MMCKINFO *lpckParent,UINT flags)
+{
+ FOURCC ckid;
+ FOURCC fccType;
+ HRESULT hr;
+
+ /* pre-conditions */
+ assert(extra != NULL);
+ assert(hmmio != NULL);
+ assert(lpck != NULL);
+
+ TRACE("({%p,%lu},%p,%p,%p,0x%X)\n", extra->lp, extra->cb, hmmio, lpck,
+ lpckParent, flags);
+
+ /* what chunk id and form/list type should we search? */
+ if (flags & MMIO_FINDCHUNK) {
+ ckid = lpck->ckid;
+ fccType = 0;
+ } else if (flags & MMIO_FINDLIST) {
+ ckid = FOURCC_LIST;
+ fccType = lpck->fccType;
+ } else if (flags & MMIO_FINDRIFF) {
+ ckid = FOURCC_RIFF;
+ fccType = lpck->fccType;
+ } else
+ ckid = fccType = (FOURCC)-1; /* collect everything into extra! */
+
+ TRACE(": find ckid=0x%08lX fccType=0x%08lX\n", ckid, fccType);
+
+ for (;;) {
+ hr = mmioDescend(hmmio, lpck, lpckParent, 0);
+ if (hr != S_OK) {
+ /* No extra chunks in front of desired chunk? */
+ if (flags == 0 && hr == MMIOERR_CHUNKNOTFOUND)
+ hr = AVIERR_OK;
+ return hr;
+ }
+
+ /* Have we found what we search for? */
+ if ((lpck->ckid == ckid) &&
+ (fccType == (FOURCC)0 || lpck->fccType == fccType))
+ return AVIERR_OK;
+
+ /* Skip padding chunks, the others put into the extrachunk-structure */
+ if (lpck->ckid == ckidAVIPADDING ||
+ lpck->ckid == mmioFOURCC('p','a','d','d'))
+ hr = mmioAscend(hmmio, lpck, 0);
+ else
+ hr = ReadChunkIntoExtra(extra, hmmio, lpck);
+ if (FAILED(hr))
+ return hr;
+ }
+}
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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
+ */
+
+#ifndef __WINE_EXTRACHUNK_H
+#define __WINE_EXTRACHUNK_H
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "mmsystem.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _EXTRACHUNKS {
+ LPVOID lp;
+ DWORD cb;
+} EXTRACHUNKS, *LPEXTRACHUNKS;
+
+/* reads a chunk outof the extrachunk-structure */
+HRESULT ReadExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPVOID lp,LPLONG size);
+
+/* writes a chunk into the extrachunk-structure */
+HRESULT WriteExtraChunk(LPEXTRACHUNKS extra,FOURCC ckid,LPVOID lp,LONG size);
+
+/* reads a chunk fomr the HMMIO into the extrachunk-structure */
+HRESULT ReadChunkIntoExtra(LPEXTRACHUNKS extra,HMMIO hmmio,MMCKINFO *lpck);
+
+/* reads all non-junk chunks into the extrachunk-structure until it finds
+ * the given chunk or the optional parent-chunk is at the end */
+HRESULT FindChunkAndKeepExtras(LPEXTRACHUNKS extra,HMMIO hmmio,
+ MMCKINFO *lpck,MMCKINFO *lpckParent,UINT flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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 <assert.h>
+#include <stdarg.h>
+
+#define COBJMACROS
+#define COM_NO_WINDOWS_H
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winerror.h"
+
+#include "ole2.h"
+#include "vfw.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+#include "initguid.h"
+#include "avifile_private.h"
+
+HMODULE AVIFILE_hModule = NULL;
+
+BOOL AVIFILE_bLocked = FALSE;
+UINT AVIFILE_uUseCount = 0;
+
+static HRESULT WINAPI IClassFactory_fnQueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj);
+static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface);
+static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface);
+static HRESULT WINAPI IClassFactory_fnCreateInstance(LPCLASSFACTORY iface,LPUNKNOWN pOuter,REFIID riid,LPVOID *ppobj);
+static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface,BOOL dolock);
+
+static const IClassFactoryVtbl iclassfact = {
+ IClassFactory_fnQueryInterface,
+ IClassFactory_fnAddRef,
+ IClassFactory_fnRelease,
+ IClassFactory_fnCreateInstance,
+ IClassFactory_fnLockServer
+};
+
+typedef struct
+{
+ /* IUnknown fields */
+ const IClassFactoryVtbl *lpVtbl;
+ DWORD dwRef;
+
+ CLSID clsid;
+} IClassFactoryImpl;
+
+static HRESULT AVIFILE_CreateClassFactory(const CLSID *pclsid, const IID *riid,
+ LPVOID *ppv)
+{
+ IClassFactoryImpl *pClassFactory = NULL;
+ HRESULT hr;
+
+ *ppv = NULL;
+
+ pClassFactory = (IClassFactoryImpl*)LocalAlloc(LPTR, sizeof(*pClassFactory));
+ if (pClassFactory == NULL)
+ return E_OUTOFMEMORY;
+
+ pClassFactory->lpVtbl = &iclassfact;
+ pClassFactory->dwRef = 0;
+ memcpy(&pClassFactory->clsid, pclsid, sizeof(pClassFactory->clsid));
+
+ hr = IClassFactory_QueryInterface((IClassFactory*)pClassFactory, riid, ppv);
+ if (FAILED(hr)) {
+ LocalFree((HLOCAL)pClassFactory);
+ *ppv = NULL;
+ }
+
+ return hr;
+}
+
+static HRESULT WINAPI IClassFactory_fnQueryInterface(LPCLASSFACTORY iface,
+ REFIID riid,LPVOID *ppobj)
+{
+ TRACE("(%p,%p,%p)\n", iface, riid, ppobj);
+
+ if ((IsEqualGUID(&IID_IUnknown, riid)) ||
+ (IsEqualGUID(&IID_IClassFactory, riid))) {
+ *ppobj = iface;
+ IClassFactory_AddRef(iface);
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IClassFactory_fnAddRef(LPCLASSFACTORY iface)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+ TRACE("(%p)\n", iface);
+
+ return ++(This->dwRef);
+}
+
+static ULONG WINAPI IClassFactory_fnRelease(LPCLASSFACTORY iface)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+ TRACE("(%p)\n", iface);
+ if ((--(This->dwRef)) > 0)
+ return This->dwRef;
+
+ return 0;
+}
+
+static HRESULT WINAPI IClassFactory_fnCreateInstance(LPCLASSFACTORY iface,
+ LPUNKNOWN pOuter,
+ REFIID riid,LPVOID *ppobj)
+{
+ IClassFactoryImpl *This = (IClassFactoryImpl *)iface;
+
+ TRACE("(%p,%p,%s,%p)\n", iface, pOuter, debugstr_guid(riid),
+ ppobj);
+
+ if (ppobj == NULL || pOuter != NULL)
+ return E_FAIL;
+ *ppobj = NULL;
+
+ if (IsEqualGUID(&CLSID_AVIFile, &This->clsid))
+ return AVIFILE_CreateAVIFile(riid,ppobj);
+ if (IsEqualGUID(&CLSID_ICMStream, &This->clsid))
+ return AVIFILE_CreateICMStream(riid,ppobj);
+ if (IsEqualGUID(&CLSID_WAVFile, &This->clsid))
+ return AVIFILE_CreateWAVFile(riid,ppobj);
+ if (IsEqualGUID(&CLSID_ACMStream, &This->clsid))
+ return AVIFILE_CreateACMStream(riid,ppobj);
+
+ return E_NOINTERFACE;
+}
+
+static HRESULT WINAPI IClassFactory_fnLockServer(LPCLASSFACTORY iface,BOOL dolock)
+{
+ TRACE("(%p,%d)\n",iface,dolock);
+
+ AVIFILE_bLocked = dolock;
+
+ return S_OK;
+}
+
+LPCWSTR AVIFILE_BasenameW(LPCWSTR szPath)
+{
+#define SLASH(w) ((w) == '/' || (w) == '\\')
+
+ LPCWSTR szCur;
+
+ for (szCur = szPath + lstrlenW(szPath);
+ szCur > szPath && !SLASH(*szCur) && *szCur != ':';)
+ szCur--;
+
+ if (szCur == szPath)
+ return szCur;
+ else
+ return szCur + 1;
+
+#undef SLASH
+}
+
+/***********************************************************************
+ * DllGetClassObject (AVIFIL32.@)
+ */
+HRESULT WINAPI DllGetClassObject(REFCLSID pclsid, REFIID piid, LPVOID *ppv)
+{
+ TRACE("(%s,%s,%p)\n", debugstr_guid(pclsid), debugstr_guid(piid), ppv);
+
+ if (pclsid == NULL || piid == NULL || ppv == NULL)
+ return E_FAIL;
+
+ return AVIFILE_CreateClassFactory(pclsid,piid,ppv);
+}
+
+/*****************************************************************************
+ * DllCanUnloadNow (AVIFIL32.@)
+ */
+HRESULT WINAPI DllCanUnloadNow(void)
+{
+ return ((AVIFILE_bLocked || AVIFILE_uUseCount) ? S_FALSE : S_OK);
+}
+
+/*****************************************************************************
+ * DllMain [AVIFIL32.init]
+ */
+BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpvReserved)
+{
+ TRACE("(%p,%ld,%p)\n", hInstDll, fdwReason, lpvReserved);
+
+ switch (fdwReason) {
+ case DLL_PROCESS_ATTACH:
+ DisableThreadLibraryCalls(hInstDll);
+ AVIFILE_hModule = (HMODULE)hInstDll;
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ };
+
+ return TRUE;
+}
--- /dev/null
+/*
+ * Copyright 2002-2003 Michael Günnewig
+ *
+ * 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
+ */
+
+#define COM_NO_WINDOWS_H
+#include <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "winnls.h"
+#include "windowsx.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "vfw.h"
+
+#include "avifile_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+#ifndef DIBPTR
+#define DIBPTR(lp) ((LPBYTE)(lp) + (lp)->biSize + \
+ (lp)->biClrUsed * sizeof(RGBQUAD))
+#endif
+
+/***********************************************************************/
+
+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);
+
+static const struct IGetFrameVtbl igetframeVtbl = {
+ IGetFrame_fnQueryInterface,
+ IGetFrame_fnAddRef,
+ IGetFrame_fnRelease,
+ IGetFrame_fnGetFrame,
+ IGetFrame_fnBegin,
+ IGetFrame_fnEnd,
+ IGetFrame_fnSetFormat
+};
+
+typedef struct _IGetFrameImpl {
+ /* IUnknown stuff */
+ const IGetFrameVtbl *lpVtbl;
+ LONG ref;
+
+ /* IGetFrame stuff */
+ BOOL bFixedStream;
+ PAVISTREAM pStream;
+
+ LPVOID lpInBuffer;
+ LONG cbInBuffer;
+ LPBITMAPINFOHEADER lpInFormat;
+ LONG cbInFormat;
+
+ LONG lCurrentFrame;
+ LPBITMAPINFOHEADER lpOutFormat;
+ LPVOID lpOutBuffer;
+
+ HIC hic;
+ BOOL bResize;
+ DWORD x;
+ DWORD y;
+ DWORD dx;
+ DWORD dy;
+
+ BOOL bFormatChanges;
+ DWORD dwFormatChangeCount;
+ DWORD dwEditCount;
+} IGetFrameImpl;
+
+/***********************************************************************/
+
+static void AVIFILE_CloseCompressor(IGetFrameImpl *This)
+{
+ if (This->lpOutFormat != NULL && This->lpInFormat != This->lpOutFormat) {
+ GlobalFreePtr(This->lpOutFormat);
+ This->lpOutFormat = NULL;
+ }
+ if (This->lpInFormat != NULL) {
+ GlobalFreePtr(This->lpInFormat);
+ This->lpInFormat = NULL;
+ }
+ if (This->hic != NULL) {
+ if (This->bResize)
+ ICDecompressExEnd(This->hic);
+ else
+ ICDecompressEnd(This->hic);
+ ICClose(This->hic);
+ This->hic = NULL;
+ }
+}
+
+PGETFRAME AVIFILE_CreateGetFrame(PAVISTREAM pStream)
+{
+ IGetFrameImpl *pg;
+
+ /* check parameter */
+ if (pStream == NULL)
+ return NULL;
+
+ pg = (IGetFrameImpl*)LocalAlloc(LPTR, sizeof(IGetFrameImpl));
+ if (pg != NULL) {
+ pg->lpVtbl = &igetframeVtbl;
+ pg->ref = 1;
+ pg->lCurrentFrame = -1;
+ pg->pStream = pStream;
+ IAVIStream_AddRef(pStream);
+ }
+
+ return (PGETFRAME)pg;
+}
+
+static HRESULT WINAPI IGetFrame_fnQueryInterface(IGetFrame *iface,
+ REFIID refiid, LPVOID *obj)
+{
+ IGetFrameImpl *This = (IGetFrameImpl *)iface;
+
+ TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
+
+ if (IsEqualGUID(&IID_IUnknown, refiid) ||
+ IsEqualGUID(&IID_IGetFrame, refiid)) {
+ *obj = iface;
+ return S_OK;
+ }
+
+ return OLE_E_ENUM_NOMORE;
+}
+
+static ULONG WINAPI IGetFrame_fnAddRef(IGetFrame *iface)
+{
+ IGetFrameImpl *This = (IGetFrameImpl *)iface;
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p)\n", iface);
+
+ return ref;
+}
+
+static ULONG WINAPI IGetFrame_fnRelease(IGetFrame *iface)
+{
+ IGetFrameImpl *This = (IGetFrameImpl *)iface;
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p)\n", iface);
+
+ if (!ref) {
+ AVIFILE_CloseCompressor(This);
+ if (This->pStream != NULL) {
+ IAVIStream_Release(This->pStream);
+ This->pStream = NULL;
+ }
+
+ LocalFree((HLOCAL)iface);
+ return 0;
+ }
+
+ return ref;
+}
+
+static LPVOID WINAPI IGetFrame_fnGetFrame(IGetFrame *iface, LONG lPos)
+{
+ IGetFrameImpl *This = (IGetFrameImpl *)iface;
+
+ LONG readBytes;
+ LONG readSamples;
+
+ TRACE("(%p,%ld)\n", iface, lPos);
+
+ /* We don't want negative start values! -- marks invalid buffer content */
+ if (lPos < 0)
+ return NULL;
+
+ /* check state */
+ if (This->pStream == NULL)
+ return NULL;
+ if (This->lpInFormat == NULL)
+ return NULL;
+
+ /* Could stream have changed? */
+ if (! This->bFixedStream) {
+ AVISTREAMINFOW sInfo;
+
+ IAVIStream_Info(This->pStream, &sInfo, sizeof(sInfo));
+
+ if (sInfo.dwEditCount != This->dwEditCount) {
+ This->dwEditCount = sInfo.dwEditCount;
+ This->lCurrentFrame = -1;
+ }
+
+ if (sInfo.dwFormatChangeCount != This->dwFormatChangeCount) {
+ /* stream has changed */
+ if (This->lpOutFormat != NULL) {
+ BITMAPINFOHEADER bi;
+
+ memcpy(&bi, This->lpOutFormat, sizeof(bi));
+ AVIFILE_CloseCompressor(This);
+
+ if (FAILED(IGetFrame_SetFormat(iface, &bi, NULL, 0, 0, -1, -1))) {
+ if (FAILED(IGetFrame_SetFormat(iface, NULL, NULL, 0, 0, -1, -1)))
+ return NULL;
+ }
+ } else if (FAILED(IGetFrame_SetFormat(iface, NULL, NULL, 0, 0, -1, -1)))
+ return NULL;
+ }
+ }
+
+ if (lPos != This->lCurrentFrame) {
+ LONG lNext = IAVIStream_FindSample(This->pStream,lPos,FIND_KEY|FIND_PREV);
+
+ if (lNext == -1)
+ return NULL; /* frame doesn't exist */
+ if (lNext <= This->lCurrentFrame && This->lCurrentFrame < lPos)
+ lNext = This->lCurrentFrame + 1;
+
+ for (; lNext <= lPos; lNext++) {
+ /* new format for this frame? */
+ if (This->bFormatChanges) {
+ IAVIStream_ReadFormat(This->pStream, lNext,
+ This->lpInFormat, &This->cbInFormat);
+ if (This->lpOutFormat != NULL) {
+ if (This->lpOutFormat->biBitCount <= 8)
+ ICDecompressGetPalette(This->hic, This->lpInFormat,
+ This->lpOutFormat);
+ }
+ }
+
+ /* read input frame */
+ while (FAILED(AVIStreamRead(This->pStream, lNext, 1, This->lpInBuffer,
+ This->cbInBuffer, &readBytes, &readSamples))) {
+ /* not enough memory for input buffer? */
+ readBytes = 0;
+ if (FAILED(AVIStreamSampleSize(This->pStream, lNext, &readBytes)))
+ return NULL; /* bad thing, but bad things will happen */
+ if (readBytes <= 0) {
+ ERR(": IAVIStream::REad doesn't return needed bytes!\n");
+ return NULL;
+ }
+
+ /* IAVIStream::Read failed because of other reasons not buffersize? */
+ if (This->cbInBuffer >= readBytes)
+ break;
+ This->cbInBuffer = This->cbInFormat + readBytes;
+ This->lpInFormat = GlobalReAllocPtr(This->lpInFormat, This->cbInBuffer, 0);
+ if (This->lpInFormat == NULL)
+ return NULL; /* out of memory */
+ This->lpInBuffer = (BYTE*)This->lpInFormat + This->cbInFormat;
+ }
+
+ if (readSamples != 1) {
+ ERR(": no frames read\n");
+ return NULL;
+ }
+ if (readBytes != 0) {
+ This->lpInFormat->biSizeImage = readBytes;
+
+ /* nothing to decompress? */
+ if (This->hic == NULL) {
+ This->lCurrentFrame = lPos;
+ return This->lpInFormat;
+ }
+
+ if (This->bResize) {
+ ICDecompressEx(This->hic,0,This->lpInFormat,This->lpInBuffer,0,0,
+ This->lpInFormat->biWidth,This->lpInFormat->biHeight,
+ This->lpOutFormat,This->lpOutBuffer,This->x,This->y,
+ This->dx,This->dy);
+ } else {
+ ICDecompress(This->hic, 0, This->lpInFormat, This->lpInBuffer,
+ This->lpOutFormat, This->lpOutBuffer);
+ }
+ }
+ } /* for (lNext < lPos) */
+ } /* if (This->lCurrentFrame != lPos) */
+
+ return (This->hic == NULL ? This->lpInFormat : This->lpOutFormat);
+}
+
+static HRESULT WINAPI IGetFrame_fnBegin(IGetFrame *iface, LONG lStart,
+ LONG lEnd, LONG lRate)
+{
+ IGetFrameImpl *This = (IGetFrameImpl *)iface;
+
+ TRACE("(%p,%ld,%ld,%ld)\n", iface, lStart, lEnd, lRate);
+
+ This->bFixedStream = TRUE;
+
+ return (IGetFrame_GetFrame(iface, lStart) ? AVIERR_OK : AVIERR_ERROR);
+}
+
+static HRESULT WINAPI IGetFrame_fnEnd(IGetFrame *iface)
+{
+ IGetFrameImpl *This = (IGetFrameImpl *)iface;
+
+ TRACE("(%p)\n", iface);
+
+ This->bFixedStream = FALSE;
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IGetFrame_fnSetFormat(IGetFrame *iface,
+ LPBITMAPINFOHEADER lpbiWanted,
+ LPVOID lpBits, INT x, INT y,
+ INT dx, INT dy)
+{
+ IGetFrameImpl *This = (IGetFrameImpl *)iface;
+
+ AVISTREAMINFOW sInfo;
+ LPBITMAPINFOHEADER lpbi = lpbiWanted;
+ BOOL bBestDisplay = FALSE;
+
+ TRACE("(%p,%p,%p,%d,%d,%d,%d)\n", iface, lpbiWanted, lpBits,
+ x, y, dx, dy);
+
+ if (This->pStream == NULL)
+ return AVIERR_ERROR;
+
+ if (lpbiWanted == (LPBITMAPINFOHEADER)AVIGETFRAMEF_BESTDISPLAYFMT) {
+ lpbi = NULL;
+ bBestDisplay = TRUE;
+ }
+
+ IAVIStream_Info(This->pStream, &sInfo, sizeof(sInfo));
+ if (sInfo.fccType != streamtypeVIDEO)
+ return AVIERR_UNSUPPORTED;
+
+ This->bFormatChanges =
+ (sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES ? TRUE : FALSE );
+ This->dwFormatChangeCount = sInfo.dwFormatChangeCount;
+ This->dwEditCount = sInfo.dwEditCount;
+ This->lCurrentFrame = -1;
+
+ /* get input format from stream */
+ if (This->lpInFormat == NULL) {
+ HRESULT hr;
+
+ This->cbInBuffer = (LONG)sInfo.dwSuggestedBufferSize;
+ if (This->cbInBuffer == 0)
+ This->cbInBuffer = 1024;
+
+ IAVIStream_ReadFormat(This->pStream, sInfo.dwStart,
+ NULL, &This->cbInFormat);
+
+ This->lpInFormat =
+ (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, This->cbInFormat + This->cbInBuffer);
+ if (This->lpInFormat == NULL) {
+ AVIFILE_CloseCompressor(This);
+ return AVIERR_MEMORY;
+ }
+
+ hr = IAVIStream_ReadFormat(This->pStream, sInfo.dwStart, This->lpInFormat, &This->cbInFormat);
+ if (FAILED(hr)) {
+ AVIFILE_CloseCompressor(This);
+ return hr;
+ }
+
+ This->lpInBuffer = ((LPBYTE)This->lpInFormat) + This->cbInFormat;
+ }
+
+ /* check input format */
+ if (This->lpInFormat->biClrUsed == 0 && This->lpInFormat->biBitCount <= 8)
+ This->lpInFormat->biClrUsed = 1u << This->lpInFormat->biBitCount;
+ if (This->lpInFormat->biSizeImage == 0 &&
+ This->lpInFormat->biCompression == BI_RGB) {
+ This->lpInFormat->biSizeImage =
+ DIBWIDTHBYTES(*This->lpInFormat) * This->lpInFormat->biHeight;
+ }
+
+ /* only to pass through? */
+ if (This->lpInFormat->biCompression == BI_RGB && lpBits == NULL) {
+ if (lpbi == NULL ||
+ (lpbi->biCompression == BI_RGB &&
+ lpbi->biWidth == This->lpInFormat->biWidth &&
+ lpbi->biHeight == This->lpInFormat->biHeight &&
+ lpbi->biBitCount == This->lpInFormat->biBitCount)) {
+ This->lpOutFormat = This->lpInFormat;
+ This->lpOutBuffer = DIBPTR(This->lpInFormat);
+ return AVIERR_OK;
+ }
+ }
+
+ /* need memory for output format? */
+ if (This->lpOutFormat == NULL) {
+ This->lpOutFormat =
+ (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, sizeof(BITMAPINFOHEADER)
+ + 256 * sizeof(RGBQUAD));
+ if (This->lpOutFormat == NULL) {
+ AVIFILE_CloseCompressor(This);
+ return AVIERR_MEMORY;
+ }
+ }
+
+ /* need handle to video compressor */
+ if (This->hic == NULL) {
+ FOURCC fccHandler;
+
+ if (This->lpInFormat->biCompression == BI_RGB)
+ fccHandler = comptypeDIB;
+ else if (This->lpInFormat->biCompression == BI_RLE8)
+ fccHandler = mmioFOURCC('R','L','E',' ');
+ else
+ fccHandler = sInfo.fccHandler;
+
+ if (lpbi != NULL) {
+ if (lpbi->biWidth == 0)
+ lpbi->biWidth = This->lpInFormat->biWidth;
+ if (lpbi->biHeight == 0)
+ lpbi->biHeight = This->lpInFormat->biHeight;
+ }
+
+ This->hic = ICLocate(ICTYPE_VIDEO, fccHandler, This->lpInFormat, lpbi, ICMODE_DECOMPRESS);
+ if (This->hic == NULL) {
+ AVIFILE_CloseCompressor(This);
+ return AVIERR_NOCOMPRESSOR;
+ }
+ }
+
+ /* output format given? */
+ if (lpbi != NULL) {
+ /* check the given output format ... */
+ if (lpbi->biClrUsed == 0 && lpbi->biBitCount <= 8)
+ lpbi->biClrUsed = 1u << lpbi->biBitCount;
+
+ /* ... and remember it */
+ memcpy(This->lpOutFormat, lpbi,
+ lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD));
+ if (lpbi->biBitCount <= 8)
+ ICDecompressGetPalette(This->hic, This->lpInFormat, This->lpOutFormat);
+
+ return AVIERR_OK;
+ } else {
+ if (bBestDisplay) {
+ ICGetDisplayFormat(This->hic, This->lpInFormat,
+ This->lpOutFormat, 0, dx, dy);
+ } else if (ICDecompressGetFormat(This->hic, This->lpInFormat,
+ This->lpOutFormat) < 0) {
+ AVIFILE_CloseCompressor(This);
+ return AVIERR_NOCOMPRESSOR;
+ }
+
+ /* check output format */
+ if (This->lpOutFormat->biClrUsed == 0 &&
+ This->lpOutFormat->biBitCount <= 8)
+ This->lpOutFormat->biClrUsed = 1u << This->lpOutFormat->biBitCount;
+ if (This->lpOutFormat->biSizeImage == 0 &&
+ This->lpOutFormat->biCompression == BI_RGB) {
+ This->lpOutFormat->biSizeImage =
+ DIBWIDTHBYTES(*This->lpOutFormat) * This->lpOutFormat->biHeight;
+ }
+
+ if (lpBits == NULL) {
+ register DWORD size = This->lpOutFormat->biClrUsed * sizeof(RGBQUAD);
+
+ size += This->lpOutFormat->biSize + This->lpOutFormat->biSizeImage;
+ This->lpOutFormat =
+ (LPBITMAPINFOHEADER)GlobalReAllocPtr(This->lpOutFormat, size, GMEM_MOVEABLE);
+ if (This->lpOutFormat == NULL) {
+ AVIFILE_CloseCompressor(This);
+ return AVIERR_MEMORY;
+ }
+ This->lpOutBuffer = DIBPTR(This->lpOutFormat);
+ } else
+ This->lpOutBuffer = lpBits;
+
+ /* for user size was irrelevant */
+ if (dx == -1)
+ dx = This->lpOutFormat->biWidth;
+ if (dy == -1)
+ dy = This->lpOutFormat->biHeight;
+
+ /* need to resize? */
+ if (x != 0 || y != 0) {
+ if (dy == This->lpOutFormat->biHeight &&
+ dx == This->lpOutFormat->biWidth)
+ This->bResize = FALSE;
+ else
+ This->bResize = TRUE;
+ }
+
+ if (This->bResize) {
+ This->x = x;
+ This->y = y;
+ This->dx = dx;
+ This->dy = dy;
+
+ if (ICDecompressExBegin(This->hic,0,This->lpInFormat,This->lpInBuffer,0,
+ 0,This->lpInFormat->biWidth,
+ This->lpInFormat->biHeight,This->lpOutFormat,
+ This->lpOutBuffer, x, y, dx, dy) == ICERR_OK)
+ return AVIERR_OK;
+ } else if (ICDecompressBegin(This->hic, This->lpInFormat,
+ This->lpOutFormat) == ICERR_OK)
+ return AVIERR_OK;
+
+ AVIFILE_CloseCompressor(This);
+
+ return AVIERR_COMPRESSOR;
+ }
+}
+
+/***********************************************************************/
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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
+ */
+
+#define COM_NO_WINDOWS_H
+#include <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "windowsx.h"
+#include "mmsystem.h"
+#include "vfw.h"
+#include "msacm.h"
+
+#include "avifile_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+#define MAX_FRAMESIZE (16 * 1024 * 1024)
+#define MAX_FRAMESIZE_DIFF 512
+
+/***********************************************************************/
+
+static HRESULT WINAPI ICMStream_fnQueryInterface(IAVIStream*iface,REFIID refiid,LPVOID *obj);
+static ULONG WINAPI ICMStream_fnAddRef(IAVIStream*iface);
+static ULONG WINAPI ICMStream_fnRelease(IAVIStream* iface);
+static HRESULT WINAPI ICMStream_fnCreate(IAVIStream*iface,LPARAM lParam1,LPARAM lParam2);
+static HRESULT WINAPI ICMStream_fnInfo(IAVIStream*iface,AVISTREAMINFOW *psi,LONG size);
+static LONG WINAPI ICMStream_fnFindSample(IAVIStream*iface,LONG pos,LONG flags);
+static HRESULT WINAPI ICMStream_fnReadFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG *formatsize);
+static HRESULT WINAPI ICMStream_fnSetFormat(IAVIStream*iface,LONG pos,LPVOID format,LONG formatsize);
+static HRESULT WINAPI ICMStream_fnRead(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,LONG *bytesread,LONG *samplesread);
+static HRESULT WINAPI ICMStream_fnWrite(IAVIStream*iface,LONG start,LONG samples,LPVOID buffer,LONG buffersize,DWORD flags,LONG *sampwritten,LONG *byteswritten);
+static HRESULT WINAPI ICMStream_fnDelete(IAVIStream*iface,LONG start,LONG samples);
+static HRESULT WINAPI ICMStream_fnReadData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG *lpread);
+static HRESULT WINAPI ICMStream_fnWriteData(IAVIStream*iface,DWORD fcc,LPVOID lp,LONG size);
+static HRESULT WINAPI ICMStream_fnSetInfo(IAVIStream*iface,AVISTREAMINFOW*info,LONG infolen);
+
+static const struct IAVIStreamVtbl iicmst = {
+ ICMStream_fnQueryInterface,
+ ICMStream_fnAddRef,
+ ICMStream_fnRelease,
+ ICMStream_fnCreate,
+ ICMStream_fnInfo,
+ ICMStream_fnFindSample,
+ ICMStream_fnReadFormat,
+ ICMStream_fnSetFormat,
+ ICMStream_fnRead,
+ ICMStream_fnWrite,
+ ICMStream_fnDelete,
+ ICMStream_fnReadData,
+ ICMStream_fnWriteData,
+ ICMStream_fnSetInfo
+};
+
+typedef struct _IAVIStreamImpl {
+ /* IUnknown stuff */
+ const IAVIStreamVtbl *lpVtbl;
+ LONG ref;
+
+ /* IAVIStream stuff */
+ PAVISTREAM pStream;
+ AVISTREAMINFOW sInfo;
+
+ PGETFRAME pg;
+ HIC hic;
+ DWORD dwICMFlags;
+
+ LONG lCurrent;
+ LONG lLastKey;
+ LONG lKeyFrameEvery;
+ DWORD dwLastQuality;
+ DWORD dwBytesPerFrame;
+ DWORD dwUnusedBytes;
+
+ LPBITMAPINFOHEADER lpbiCur; /* current frame */
+ LPVOID lpCur;
+ LPBITMAPINFOHEADER lpbiPrev; /* previous frame */
+ LPVOID lpPrev;
+
+ LPBITMAPINFOHEADER lpbiOutput; /* output format of codec */
+ LONG cbOutput;
+ LPBITMAPINFOHEADER lpbiInput; /* input format for codec */
+ LONG cbInput;
+} IAVIStreamImpl;
+
+/***********************************************************************/
+
+static HRESULT AVIFILE_EncodeFrame(IAVIStreamImpl *This,
+ LPBITMAPINFOHEADER lpbi, LPVOID lpBits);
+static HRESULT AVIFILE_OpenGetFrame(IAVIStreamImpl *This);
+
+static inline void AVIFILE_Reset(IAVIStreamImpl *This)
+{
+ This->lCurrent = -1;
+ This->lLastKey = 0;
+ This->dwLastQuality = ICQUALITY_HIGH;
+ This->dwUnusedBytes = 0;
+}
+
+HRESULT AVIFILE_CreateICMStream(REFIID riid, LPVOID *ppv)
+{
+ IAVIStreamImpl *pstream;
+ HRESULT hr;
+
+ assert(riid != NULL && ppv != NULL);
+
+ *ppv = NULL;
+
+ pstream = (IAVIStreamImpl*)LocalAlloc(LPTR, sizeof(IAVIStreamImpl));
+ if (pstream == NULL)
+ return AVIERR_MEMORY;
+
+ pstream->lpVtbl = &iicmst;
+ AVIFILE_Reset(pstream);
+
+ hr = IAVIStream_QueryInterface((IAVIStream*)pstream, riid, ppv);
+ if (FAILED(hr))
+ LocalFree((HLOCAL)pstream);
+
+ return hr;
+}
+
+static HRESULT WINAPI ICMStream_fnQueryInterface(IAVIStream *iface,
+ REFIID refiid, LPVOID *obj)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%s,%p)\n", iface, debugstr_guid(refiid), obj);
+
+ if (IsEqualGUID(&IID_IUnknown, refiid) ||
+ IsEqualGUID(&IID_IAVIStream, refiid)) {
+ *obj = This;
+ IAVIStream_AddRef(iface);
+
+ return S_OK;
+ }
+
+ return OLE_E_ENUM_NOMORE;
+}
+
+static ULONG WINAPI ICMStream_fnAddRef(IAVIStream *iface)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ /* also add reference to the nested stream */
+ if (This->pStream != NULL)
+ IAVIStream_AddRef(This->pStream);
+
+ return ref;
+}
+
+static ULONG WINAPI ICMStream_fnRelease(IAVIStream* iface)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ if (ref == 0) {
+ /* destruct */
+ if (This->pg != NULL) {
+ AVIStreamGetFrameClose(This->pg);
+ This->pg = NULL;
+ }
+ if (This->pStream != NULL) {
+ IAVIStream_Release(This->pStream);
+ This->pStream = NULL;
+ }
+ if (This->hic != NULL) {
+ if (This->lpbiPrev != NULL) {
+ ICDecompressEnd(This->hic);
+ GlobalFreePtr(This->lpbiPrev);
+ This->lpbiPrev = NULL;
+ This->lpPrev = NULL;
+ }
+ ICCompressEnd(This->hic);
+ This->hic = NULL;
+ }
+ if (This->lpbiCur != NULL) {
+ GlobalFreePtr(This->lpbiCur);
+ This->lpbiCur = NULL;
+ This->lpCur = NULL;
+ }
+ if (This->lpbiOutput != NULL) {
+ GlobalFreePtr(This->lpbiOutput);
+ This->lpbiOutput = NULL;
+ This->cbOutput = 0;
+ }
+ if (This->lpbiInput != NULL) {
+ GlobalFreePtr(This->lpbiInput);
+ This->lpbiInput = NULL;
+ This->cbInput = 0;
+ }
+
+ LocalFree((HLOCAL)This);
+
+ return 0;
+ }
+
+ /* also release reference to the nested stream */
+ if (This->pStream != NULL)
+ IAVIStream_Release(This->pStream);
+
+ return ref;
+}
+
+/* lParam1: PAVISTREAM
+ * lParam2: LPAVICOMPRESSOPTIONS
+ */
+static HRESULT WINAPI ICMStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
+ LPARAM lParam2)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ ICINFO icinfo;
+ ICCOMPRESSFRAMES icFrames;
+ LPAVICOMPRESSOPTIONS pco = (LPAVICOMPRESSOPTIONS)lParam2;
+
+ TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
+
+ /* check parameter */
+ if ((LPVOID)lParam1 == NULL)
+ return AVIERR_BADPARAM;
+
+ /* get infos from stream */
+ IAVIStream_Info((PAVISTREAM)lParam1, &This->sInfo, sizeof(This->sInfo));
+ if (This->sInfo.fccType != streamtypeVIDEO)
+ return AVIERR_ERROR; /* error in registry or AVIMakeCompressedStream */
+
+ /* add reference to the stream */
+ This->pStream = (PAVISTREAM)lParam1;
+ IAVIStream_AddRef(This->pStream);
+
+ AVIFILE_Reset(This);
+
+ if (pco != NULL && pco->fccHandler != comptypeDIB) {
+ /* we should compress */
+ This->sInfo.fccHandler = pco->fccHandler;
+
+ This->hic = ICOpen(ICTYPE_VIDEO, pco->fccHandler, ICMODE_COMPRESS);
+ if (This->hic == NULL)
+ return AVIERR_NOCOMPRESSOR;
+
+ /* restore saved state of codec */
+ if (pco->cbParms > 0 && pco->lpParms != NULL) {
+ ICSetState(This->hic, pco->lpParms, pco->cbParms);
+ }
+
+ /* set quality -- resolve default quality */
+ This->sInfo.dwQuality = pco->dwQuality;
+ if (pco->dwQuality == ICQUALITY_DEFAULT)
+ This->sInfo.dwQuality = ICGetDefaultQuality(This->hic);
+
+ /* get capabilities of codec */
+ ICGetInfo(This->hic, &icinfo, sizeof(icinfo));
+ This->dwICMFlags = icinfo.dwFlags;
+
+ /* use keyframes? */
+ if ((pco->dwFlags & AVICOMPRESSF_KEYFRAMES) &&
+ (icinfo.dwFlags & (VIDCF_TEMPORAL|VIDCF_FASTTEMPORALC))) {
+ This->lKeyFrameEvery = pco->dwKeyFrameEvery;
+ } else
+ This->lKeyFrameEvery = 1;
+
+ /* use datarate? */
+ if ((pco->dwFlags & AVICOMPRESSF_DATARATE)) {
+ /* Do we have a chance to reduce size to desired one? */
+ if ((icinfo.dwFlags & (VIDCF_CRUNCH|VIDCF_QUALITY)) == 0)
+ return AVIERR_NOCOMPRESSOR;
+
+ assert(This->sInfo.dwRate != 0);
+
+ This->dwBytesPerFrame = MulDiv(pco->dwBytesPerSecond,
+ This->sInfo.dwScale, This->sInfo.dwRate);
+ } else {
+ pco->dwBytesPerSecond = 0;
+ This->dwBytesPerFrame = 0;
+ }
+
+ if (icinfo.dwFlags & VIDCF_COMPRESSFRAMES) {
+ memset(&icFrames, 0, sizeof(icFrames));
+ icFrames.lpbiOutput = This->lpbiOutput;
+ icFrames.lpbiInput = This->lpbiInput;
+ icFrames.lFrameCount = This->sInfo.dwLength;
+ icFrames.lQuality = This->sInfo.dwQuality;
+ icFrames.lDataRate = pco->dwBytesPerSecond;
+ icFrames.lKeyRate = This->lKeyFrameEvery;
+ icFrames.dwRate = This->sInfo.dwRate;
+ icFrames.dwScale = This->sInfo.dwScale;
+ ICSendMessage(This->hic, ICM_COMPRESS_FRAMES_INFO,
+ (LPARAM)&icFrames, (LPARAM)sizeof(icFrames));
+ }
+ } else
+ This->sInfo.fccHandler = comptypeDIB;
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI ICMStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
+ LONG size)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%p,%ld)\n", iface, psi, size);
+
+ if (psi == NULL)
+ return AVIERR_BADPARAM;
+ if (size < 0)
+ return AVIERR_BADSIZE;
+
+ memcpy(psi, &This->sInfo, min((DWORD)size, sizeof(This->sInfo)));
+
+ if ((DWORD)size < sizeof(This->sInfo))
+ return AVIERR_BUFFERTOOSMALL;
+ return AVIERR_OK;
+}
+
+static LONG WINAPI ICMStream_fnFindSample(IAVIStream *iface, LONG pos,
+ LONG flags)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
+
+ if (flags & FIND_FROM_START) {
+ pos = This->sInfo.dwStart;
+ flags &= ~(FIND_FROM_START|FIND_PREV);
+ flags |= FIND_NEXT;
+ }
+
+ if (flags & FIND_RET)
+ WARN(": FIND_RET flags will be ignored!\n");
+
+ if (flags & FIND_KEY) {
+ if (This->hic == NULL)
+ return pos; /* we decompress so every frame is a keyframe */
+
+ if (flags & FIND_PREV) {
+ /* need to read old or new frames? */
+ if (This->lLastKey <= pos || pos < This->lCurrent)
+ IAVIStream_Read(iface, pos, 1, NULL, 0, NULL, NULL);
+
+ return This->lLastKey;
+ }
+ } else if (flags & FIND_ANY) {
+ return pos; /* We really don't know, reread is to expensive, so guess. */
+ } else if (flags & FIND_FORMAT) {
+ if (flags & FIND_PREV)
+ return 0;
+ }
+
+ return -1;
+}
+
+static HRESULT WINAPI ICMStream_fnReadFormat(IAVIStream *iface, LONG pos,
+ LPVOID format, LONG *formatsize)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ LPBITMAPINFOHEADER lpbi;
+ HRESULT hr;
+
+ TRACE("(%p,%ld,%p,%p)\n", iface, pos, format, formatsize);
+
+ if (formatsize == NULL)
+ return AVIERR_BADPARAM;
+
+ if (This->pg == NULL) {
+ hr = AVIFILE_OpenGetFrame(This);
+
+ if (FAILED(hr))
+ return hr;
+ }
+
+ lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(This->pg, pos);
+ if (lpbi == NULL)
+ return AVIERR_MEMORY;
+
+ if (This->hic == NULL) {
+ LONG size = lpbi->biSize + lpbi->biClrUsed * sizeof(RGBQUAD);
+
+ if (size > 0) {
+ if (This->sInfo.dwSuggestedBufferSize < lpbi->biSizeImage)
+ This->sInfo.dwSuggestedBufferSize = lpbi->biSizeImage;
+
+ This->cbOutput = size;
+ if (format != NULL) {
+ if (This->lpbiOutput != NULL)
+ memcpy(format, This->lpbiOutput, min(*formatsize, This->cbOutput));
+ else
+ memcpy(format, lpbi, min(*formatsize, size));
+ }
+ }
+ } else if (format != NULL)
+ memcpy(format, This->lpbiOutput, min(*formatsize, This->cbOutput));
+
+ if (*formatsize < This->cbOutput)
+ hr = AVIERR_BUFFERTOOSMALL;
+ else
+ hr = AVIERR_OK;
+
+ *formatsize = This->cbOutput;
+ return hr;
+}
+
+static HRESULT WINAPI ICMStream_fnSetFormat(IAVIStream *iface, LONG pos,
+ LPVOID format, LONG formatsize)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%ld,%p,%ld)\n", iface, pos, format, formatsize);
+
+ /* check parameters */
+ if (format == NULL || formatsize <= 0)
+ return AVIERR_BADPARAM;
+
+ /* We can only accept RGB data for writing */
+ if (((LPBITMAPINFOHEADER)format)->biCompression != BI_RGB) {
+ WARN(": need RGB data as input\n");
+ return AVIERR_UNSUPPORTED;
+ }
+
+ /* Input format already known?
+ * Changing of palette is supported, but be quiet if it's the same */
+ if (This->lpbiInput != NULL) {
+ if (This->cbInput != formatsize)
+ return AVIERR_UNSUPPORTED;
+
+ if (memcmp(format, This->lpbiInput, formatsize) == 0)
+ return AVIERR_OK;
+ }
+
+ /* Does the nested stream support writing? */
+ if ((This->sInfo.dwCaps & AVIFILECAPS_CANWRITE) == 0)
+ return AVIERR_READONLY;
+
+ /* check if frame is already written */
+ if (This->sInfo.dwLength + This->sInfo.dwStart > pos)
+ return AVIERR_UNSUPPORTED;
+
+ /* check if we should compress */
+ if (This->sInfo.fccHandler == 0 ||
+ This->sInfo.fccHandler == mmioFOURCC('N','O','N','E'))
+ This->sInfo.fccHandler = comptypeDIB;
+
+ /* only pass through? */
+ if (This->sInfo.fccHandler == comptypeDIB)
+ return IAVIStream_SetFormat(This->pStream, pos, format, formatsize);
+
+ /* initial format setting? */
+ if (This->lpbiInput == NULL) {
+ ULONG size;
+
+ assert(This->hic != NULL);
+
+ /* get memory for input format */
+ This->lpbiInput = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, formatsize);
+ if (This->lpbiInput == NULL)
+ return AVIERR_MEMORY;
+ This->cbInput = formatsize;
+ memcpy(This->lpbiInput, format, formatsize);
+
+ /* get output format */
+ size = ICCompressGetFormatSize(This->hic, This->lpbiInput);
+ if (size < sizeof(BITMAPINFOHEADER))
+ return AVIERR_COMPRESSOR;
+ This->lpbiOutput = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, size);
+ if (This->lpbiOutput == NULL)
+ return AVIERR_MEMORY;
+ This->cbOutput = size;
+ if (ICCompressGetFormat(This->hic,This->lpbiInput,This->lpbiOutput) < S_OK)
+ return AVIERR_COMPRESSOR;
+
+ /* update AVISTREAMINFO structure */
+ This->sInfo.rcFrame.right =
+ This->sInfo.rcFrame.left + This->lpbiOutput->biWidth;
+ This->sInfo.rcFrame.bottom =
+ This->sInfo.rcFrame.top + This->lpbiOutput->biHeight;
+
+ /* prepare codec for compression */
+ if (ICCompressBegin(This->hic, This->lpbiInput, This->lpbiOutput) != S_OK)
+ return AVIERR_COMPRESSOR;
+
+ /* allocate memory for compressed frame */
+ size = ICCompressGetSize(This->hic, This->lpbiInput, This->lpbiOutput);
+ This->lpbiCur =
+ (LPBITMAPINFOHEADER)GlobalAllocPtr(GMEM_MOVEABLE, This->cbOutput + size);
+ if (This->lpbiCur == NULL)
+ return AVIERR_MEMORY;
+ memcpy(This->lpbiCur, This->lpbiOutput, This->cbOutput);
+ This->lpCur = DIBPTR(This->lpbiCur);
+
+ /* allocate memory for last frame if needed */
+ if (This->lKeyFrameEvery != 1 &&
+ (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
+ size = ICDecompressGetFormatSize(This->hic, This->lpbiOutput);
+ This->lpbiPrev = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, size);
+ if (This->lpbiPrev == NULL)
+ return AVIERR_MEMORY;
+ if (ICDecompressGetFormat(This->hic, This->lpbiOutput, This->lpbiPrev) < S_OK)
+ return AVIERR_COMPRESSOR;
+
+ if (This->lpbiPrev->biSizeImage == 0) {
+ This->lpbiPrev->biSizeImage =
+ DIBWIDTHBYTES(*This->lpbiPrev) * This->lpbiPrev->biHeight;
+ }
+
+ /* get memory for format and picture */
+ size += This->lpbiPrev->biSizeImage;
+ This->lpbiPrev =
+ (LPBITMAPINFOHEADER)GlobalReAllocPtr(This->lpbiPrev,size,GMEM_MOVEABLE);
+ if (This->lpbiPrev == NULL)
+ return AVIERR_MEMORY;
+ This->lpPrev = DIBPTR(This->lpbiPrev);
+
+ /* prepare codec also for decompression */
+ if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
+ return AVIERR_COMPRESSOR;
+ }
+ } else {
+ /* format change -- check that's only the palette */
+ LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)format;
+
+ if (lpbi->biSize != This->lpbiInput->biSize ||
+ lpbi->biWidth != This->lpbiInput->biWidth ||
+ lpbi->biHeight != This->lpbiInput->biHeight ||
+ lpbi->biBitCount != This->lpbiInput->biBitCount ||
+ lpbi->biPlanes != This->lpbiInput->biPlanes ||
+ lpbi->biCompression != This->lpbiInput->biCompression ||
+ lpbi->biClrUsed != This->lpbiInput->biClrUsed)
+ return AVIERR_UNSUPPORTED;
+
+ /* get new output format */
+ if (ICCompressGetFormat(This->hic, lpbi, This->lpbiOutput) < S_OK)
+ return AVIERR_BADFORMAT;
+
+ /* restart compression */
+ ICCompressEnd(This->hic);
+ if (ICCompressBegin(This->hic, lpbi, This->lpbiOutput) != S_OK)
+ return AVIERR_COMPRESSOR;
+
+ /* check if we need to restart decompresion also */
+ if (This->lKeyFrameEvery != 1 &&
+ (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
+ ICDecompressEnd(This->hic);
+ if (ICDecompressGetFormat(This->hic,This->lpbiOutput,This->lpbiPrev) < S_OK)
+ return AVIERR_COMPRESSOR;
+ if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
+ return AVIERR_COMPRESSOR;
+ }
+ }
+
+ /* tell nested stream the new format */
+ return IAVIStream_SetFormat(This->pStream, pos,
+ This->lpbiOutput, This->cbOutput);
+}
+
+static HRESULT WINAPI ICMStream_fnRead(IAVIStream *iface, LONG start,
+ LONG samples, LPVOID buffer,
+ LONG buffersize, LPLONG bytesread,
+ LPLONG samplesread)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ LPBITMAPINFOHEADER lpbi;
+
+ TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface, start, samples, buffer,
+ buffersize, bytesread, samplesread);
+
+ /* clear return parameters if given */
+ if (bytesread != NULL)
+ *bytesread = 0;
+ if (samplesread != NULL)
+ *samplesread = 0;
+
+ if (samples == 0)
+ return AVIERR_OK;
+
+ /* check parameters */
+ if (samples != 1 && (bytesread == NULL && samplesread == NULL))
+ return AVIERR_BADPARAM;
+ if (samples == -1) /* read as much as we could */
+ samples = 1;
+
+ if (This->pg == NULL) {
+ HRESULT hr = AVIFILE_OpenGetFrame(This);
+
+ if (FAILED(hr))
+ return hr;
+ }
+
+ /* compress or decompress? */
+ if (This->hic == NULL) {
+ /* decompress */
+ lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(This->pg, start);
+ if (lpbi == NULL)
+ return AVIERR_MEMORY;
+
+ if (buffer != NULL && buffersize > 0) {
+ /* check buffersize */
+ if (buffersize < lpbi->biSizeImage)
+ return AVIERR_BUFFERTOOSMALL;
+
+ memcpy(buffer, DIBPTR(lpbi), lpbi->biSizeImage);
+ }
+
+ /* fill out return parameters if given */
+ if (bytesread != NULL)
+ *bytesread = lpbi->biSizeImage;
+ } else {
+ /* compress */
+ if (This->lCurrent > start)
+ AVIFILE_Reset(This);
+
+ while (start > This->lCurrent) {
+ HRESULT hr;
+
+ lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(This->pg, ++This->lCurrent);
+ if (lpbi == NULL) {
+ AVIFILE_Reset(This);
+ return AVIERR_MEMORY;
+ }
+
+ hr = AVIFILE_EncodeFrame(This, lpbi, DIBPTR(lpbi));
+ if (FAILED(hr)) {
+ AVIFILE_Reset(This);
+ return hr;
+ }
+ }
+
+ if (buffer != NULL && buffersize > 0) {
+ /* check buffersize */
+ if (This->lpbiCur->biSizeImage > buffersize)
+ return AVIERR_BUFFERTOOSMALL;
+
+ memcpy(buffer, This->lpCur, This->lpbiCur->biSizeImage);
+ }
+
+ /* fill out return parameters if given */
+ if (bytesread != NULL)
+ *bytesread = This->lpbiCur->biSizeImage;
+ }
+
+ /* fill out return parameters if given */
+ if (samplesread != NULL)
+ *samplesread = 1;
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI ICMStream_fnWrite(IAVIStream *iface, LONG start,
+ LONG samples, LPVOID buffer,
+ LONG buffersize, DWORD flags,
+ LPLONG sampwritten,
+ LPLONG byteswritten)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ HRESULT hr;
+
+ TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface, start, samples,
+ buffer, buffersize, flags, sampwritten, byteswritten);
+
+ /* clear return parameters if given */
+ if (sampwritten != NULL)
+ *sampwritten = 0;
+ if (byteswritten != NULL)
+ *byteswritten = 0;
+
+ /* check parameters */
+ if (buffer == NULL && (buffersize > 0 || samples > 0))
+ return AVIERR_BADPARAM;
+
+ if (This->sInfo.fccHandler == comptypeDIB) {
+ /* only pass through */
+ flags |= AVIIF_KEYFRAME;
+
+ return IAVIStream_Write(This->pStream, start, samples, buffer, buffersize,
+ flags, sampwritten, byteswritten);
+ } else {
+ /* compress data before writing to pStream */
+ if (samples != 1 && (sampwritten == NULL && byteswritten == NULL))
+ return AVIERR_UNSUPPORTED;
+
+ This->lCurrent = start;
+ hr = AVIFILE_EncodeFrame(This, This->lpbiInput, buffer);
+ if (FAILED(hr))
+ return hr;
+
+ if (This->lLastKey == start)
+ flags |= AVIIF_KEYFRAME;
+
+ return IAVIStream_Write(This->pStream, start, samples, This->lpCur,
+ This->lpbiCur->biSizeImage, flags, byteswritten,
+ sampwritten);
+ }
+}
+
+static HRESULT WINAPI ICMStream_fnDelete(IAVIStream *iface, LONG start,
+ LONG samples)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%ld,%ld)\n", iface, start, samples);
+
+ return IAVIStream_Delete(This->pStream, start, samples);
+}
+
+static HRESULT WINAPI ICMStream_fnReadData(IAVIStream *iface, DWORD fcc,
+ LPVOID lp, LPLONG lpread)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,0x%08lX,%p,%p)\n", iface, fcc, lp, lpread);
+
+ assert(This->pStream != NULL);
+
+ return IAVIStream_ReadData(This->pStream, fcc, lp, lpread);
+}
+
+static HRESULT WINAPI ICMStream_fnWriteData(IAVIStream *iface, DWORD fcc,
+ LPVOID lp, LONG size)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,0x%08lx,%p,%ld)\n", iface, fcc, lp, size);
+
+ assert(This->pStream != NULL);
+
+ return IAVIStream_WriteData(This->pStream, fcc, lp, size);
+}
+
+static HRESULT WINAPI ICMStream_fnSetInfo(IAVIStream *iface,
+ LPAVISTREAMINFOW info, LONG infolen)
+{
+ FIXME("(%p,%p,%ld): stub\n", iface, info, infolen);
+
+ return E_FAIL;
+}
+
+/***********************************************************************/
+
+static HRESULT AVIFILE_EncodeFrame(IAVIStreamImpl *This,
+ LPBITMAPINFOHEADER lpbi, LPVOID lpBits)
+{
+ DWORD dwMinQual, dwMaxQual, dwCurQual;
+ DWORD dwRequest;
+ DWORD icmFlags = 0;
+ DWORD idxFlags = 0;
+ BOOL bDecreasedQual = FALSE;
+ BOOL doSizeCheck;
+ BOOL noPrev;
+
+ /* make lKeyFrameEvery and at start a keyframe */
+ if ((This->lKeyFrameEvery != 0 &&
+ (This->lCurrent - This->lLastKey) >= This->lKeyFrameEvery) ||
+ This->lCurrent == This->sInfo.dwStart) {
+ idxFlags = AVIIF_KEYFRAME;
+ icmFlags = ICCOMPRESS_KEYFRAME;
+ }
+
+ if (This->lKeyFrameEvery != 0) {
+ if (This->lCurrent == This->sInfo.dwStart) {
+ if (idxFlags & AVIIF_KEYFRAME) {
+ /* for keyframes allow to consume all unused bytes */
+ dwRequest = This->dwBytesPerFrame + This->dwUnusedBytes;
+ This->dwUnusedBytes = 0;
+ } else {
+ /* for non-keyframes only allow something of the unused bytes to be consumed */
+ DWORD tmp1 = 0;
+ DWORD tmp2;
+
+ if (This->dwBytesPerFrame >= This->dwUnusedBytes)
+ tmp1 = This->dwBytesPerFrame / This->lKeyFrameEvery;
+ tmp2 = (This->dwUnusedBytes + tmp1) / This->lKeyFrameEvery;
+
+ dwRequest = This->dwBytesPerFrame - tmp1 + tmp2;
+ This->dwUnusedBytes -= tmp2;
+ }
+ } else
+ dwRequest = MAX_FRAMESIZE;
+ } else {
+ /* only one keyframe at start desired */
+ if (This->lCurrent == This->sInfo.dwStart) {
+ dwRequest = This->dwBytesPerFrame + This->dwUnusedBytes;
+ This->dwUnusedBytes = 0;
+ } else
+ dwRequest = MAX_FRAMESIZE;
+ }
+
+ /* must we check for framesize to gain requested
+ * datarate or could we trust codec? */
+ doSizeCheck = (dwRequest != 0 && ((This->dwICMFlags & (VIDCF_CRUNCH|VIDCF_QUALITY)) == 0));
+
+ dwMaxQual = dwCurQual = This->sInfo.dwQuality;
+ dwMinQual = ICQUALITY_LOW;
+
+ noPrev = TRUE;
+ if ((icmFlags & ICCOMPRESS_KEYFRAME) == 0 &&
+ (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0)
+ noPrev = FALSE;
+
+ do {
+ DWORD idxCkid = 0;
+ HRESULT hr;
+
+ hr = ICCompress(This->hic,icmFlags,This->lpbiCur,This->lpCur,lpbi,lpBits,
+ &idxCkid, &idxFlags, This->lCurrent, dwRequest, dwCurQual,
+ noPrev ? NULL:This->lpbiPrev, noPrev ? NULL:This->lpPrev);
+ if (hr == ICERR_NEWPALETTE) {
+ FIXME(": codec has changed palette -- unhandled!\n");
+ } else if (hr != ICERR_OK)
+ return AVIERR_COMPRESSOR;
+
+ /* need to check for framesize */
+ if (! doSizeCheck)
+ break;
+
+ if (dwRequest >= This->lpbiCur->biSizeImage) {
+ /* frame is smaller -- try to maximize quality */
+ if (dwMaxQual - dwCurQual > 10) {
+ DWORD tmp = dwRequest / 8;
+
+ if (tmp < MAX_FRAMESIZE_DIFF)
+ tmp = MAX_FRAMESIZE_DIFF;
+
+ if (tmp < dwRequest - This->lpbiCur->biSizeImage && bDecreasedQual) {
+ tmp = dwCurQual;
+ dwCurQual = (dwMinQual + dwMaxQual) / 2;
+ dwMinQual = tmp;
+ continue;
+ }
+ } else
+ break;
+ } else if (dwMaxQual - dwMinQual <= 1) {
+ break;
+ } else {
+ dwMaxQual = dwCurQual;
+
+ if (bDecreasedQual || dwCurQual == This->dwLastQuality)
+ dwCurQual = (dwMinQual + dwMaxQual) / 2;
+ else
+ FIXME(": no new quality computed min=%lu cur=%lu max=%lu last=%lu\n",
+ dwMinQual, dwCurQual, dwMaxQual, This->dwLastQuality);
+
+ bDecreasedQual = TRUE;
+ }
+ } while (TRUE);
+
+ /* remember some values */
+ This->dwLastQuality = dwCurQual;
+ This->dwUnusedBytes = dwRequest - This->lpbiCur->biSizeImage;
+ if (icmFlags & ICCOMPRESS_KEYFRAME)
+ This->lLastKey = This->lCurrent;
+
+ /* Does we manage previous frame? */
+ if (This->lpPrev != NULL && This->lKeyFrameEvery != 1)
+ ICDecompress(This->hic, 0, This->lpbiCur, This->lpCur,
+ This->lpbiPrev, This->lpPrev);
+
+ return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_OpenGetFrame(IAVIStreamImpl *This)
+{
+ LPBITMAPINFOHEADER lpbi;
+ DWORD size;
+
+ /* pre-conditions */
+ assert(This != NULL);
+ assert(This->pStream != NULL);
+ assert(This->pg == NULL);
+
+ This->pg = AVIStreamGetFrameOpen(This->pStream, NULL);
+ if (This->pg == NULL)
+ return AVIERR_ERROR;
+
+ /* When we only decompress this is enough */
+ if (This->sInfo.fccHandler == comptypeDIB)
+ return AVIERR_OK;
+
+ assert(This->hic != NULL);
+ assert(This->lpbiOutput == NULL);
+
+ /* get input format */
+ lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(This->pg, This->sInfo.dwStart);
+ if (lpbi == NULL)
+ return AVIERR_MEMORY;
+
+ /* get memory for output format */
+ size = ICCompressGetFormatSize(This->hic, lpbi);
+ if ((LONG)size < (LONG)sizeof(BITMAPINFOHEADER))
+ return AVIERR_COMPRESSOR;
+ This->lpbiOutput = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, size);
+ if (This->lpbiOutput == NULL)
+ return AVIERR_MEMORY;
+ This->cbOutput = size;
+
+ if (ICCompressGetFormat(This->hic, lpbi, This->lpbiOutput) < S_OK)
+ return AVIERR_BADFORMAT;
+
+ /* update AVISTREAMINFO structure */
+ This->sInfo.rcFrame.right =
+ This->sInfo.rcFrame.left + This->lpbiOutput->biWidth;
+ This->sInfo.rcFrame.bottom =
+ This->sInfo.rcFrame.top + This->lpbiOutput->biHeight;
+ This->sInfo.dwSuggestedBufferSize =
+ ICCompressGetSize(This->hic, lpbi, This->lpbiOutput);
+
+ /* prepare codec for compression */
+ if (ICCompressBegin(This->hic, lpbi, This->lpbiOutput) != S_OK)
+ return AVIERR_COMPRESSOR;
+
+ /* allocate memory for current frame */
+ size += This->sInfo.dwSuggestedBufferSize;
+ This->lpbiCur = (LPBITMAPINFOHEADER)GlobalAllocPtr(GMEM_MOVEABLE, size);
+ if (This->lpbiCur == NULL)
+ return AVIERR_MEMORY;
+ memcpy(This->lpbiCur, This->lpbiOutput, This->cbOutput);
+ This->lpCur = DIBPTR(This->lpbiCur);
+
+ /* allocate memory for last frame if needed */
+ if (This->lKeyFrameEvery != 1 &&
+ (This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
+ size = ICDecompressGetFormatSize(This->hic, This->lpbiOutput);
+ This->lpbiPrev = (LPBITMAPINFOHEADER)GlobalAllocPtr(GHND, size);
+ if (This->lpbiPrev == NULL)
+ return AVIERR_MEMORY;
+ if (ICDecompressGetFormat(This->hic, This->lpbiOutput, This->lpbiPrev) < S_OK)
+ return AVIERR_COMPRESSOR;
+
+ if (This->lpbiPrev->biSizeImage == 0) {
+ This->lpbiPrev->biSizeImage =
+ DIBWIDTHBYTES(*This->lpbiPrev) * This->lpbiPrev->biHeight;
+ }
+
+ /* get memory for format and picture */
+ size += This->lpbiPrev->biSizeImage;
+ This->lpbiPrev =
+ (LPBITMAPINFOHEADER)GlobalReAllocPtr(This->lpbiPrev,size,GMEM_MOVEABLE);
+ if (This->lpbiPrev == NULL)
+ return AVIERR_MEMORY;
+ This->lpPrev = DIBPTR(This->lpbiPrev);
+
+ /* prepare codec also for decompression */
+ if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
+ return AVIERR_COMPRESSOR;
+ }
+
+ return AVIERR_OK;
+}
--- /dev/null
+/*
+ * self-registerable dll functions for avifile.dll and avifil32.dll
+ *
+ * Copyright (C) 2003 John K. Hohm
+ *
+ * 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
+ */
+
+#define COM_NO_WINDOWS_H
+#include <stdarg.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+
+#include "mmsystem.h"
+#include "vfw.h"
+#include "avifile_private.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+/*
+ * Near the bottom of this file are the exported DllRegisterServer and
+ * DllUnregisterServer, which make all this worthwhile.
+ */
+
+/***********************************************************************
+ * interface for self-registering
+ */
+struct regsvr_interface
+{
+ IID const *iid; /* NULL for end of list */
+ LPCSTR name; /* can be NULL to omit */
+ IID const *base_iid; /* can be NULL to omit */
+ int num_methods; /* can be <0 to omit */
+ CLSID const *ps_clsid; /* can be NULL to omit */
+ CLSID const *ps_clsid32; /* can be NULL to omit */
+};
+
+static HRESULT register_interfaces(struct regsvr_interface const *list);
+static HRESULT unregister_interfaces(struct regsvr_interface const *list);
+
+struct regsvr_coclass
+{
+ CLSID const *clsid; /* NULL for end of list */
+ LPCSTR name; /* can be NULL to omit */
+ LPCSTR ips; /* can be NULL to omit */
+ LPCSTR ips32; /* can be NULL to omit */
+ LPCSTR ips32_tmodel; /* can be NULL to omit */
+ LPCSTR progid; /* can be NULL to omit */
+ LPCSTR viprogid; /* can be NULL to omit */
+ LPCSTR progid_extra; /* can be NULL to omit */
+};
+
+static HRESULT register_coclasses(struct regsvr_coclass const *list);
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list);
+
+/***********************************************************************
+ * static string constants
+ */
+static WCHAR const interface_keyname[10] = {
+ 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c', 'e', 0 };
+static WCHAR const base_ifa_keyname[14] = {
+ 'B', 'a', 's', 'e', 'I', 'n', 't', 'e', 'r', 'f', 'a', 'c',
+ 'e', 0 };
+static WCHAR const num_methods_keyname[11] = {
+ 'N', 'u', 'm', 'M', 'e', 't', 'h', 'o', 'd', 's', 0 };
+static WCHAR const ps_clsid_keyname[15] = {
+ 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
+ 'i', 'd', 0 };
+static WCHAR const ps_clsid32_keyname[17] = {
+ 'P', 'r', 'o', 'x', 'y', 'S', 't', 'u', 'b', 'C', 'l', 's',
+ 'i', 'd', '3', '2', 0 };
+static WCHAR const clsid_keyname[6] = {
+ 'C', 'L', 'S', 'I', 'D', 0 };
+static WCHAR const curver_keyname[7] = {
+ 'C', 'u', 'r', 'V', 'e', 'r', 0 };
+static WCHAR const ips_keyname[13] = {
+ 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+ 0 };
+static WCHAR const ips32_keyname[15] = {
+ 'I', 'n', 'P', 'r', 'o', 'c', 'S', 'e', 'r', 'v', 'e', 'r',
+ '3', '2', 0 };
+static WCHAR const progid_keyname[7] = {
+ 'P', 'r', 'o', 'g', 'I', 'D', 0 };
+static WCHAR const viprogid_keyname[25] = {
+ 'V', 'e', 'r', 's', 'i', 'o', 'n', 'I', 'n', 'd', 'e', 'p',
+ 'e', 'n', 'd', 'e', 'n', 't', 'P', 'r', 'o', 'g', 'I', 'D',
+ 0 };
+static char const tmodel_valuename[] = "ThreadingModel";
+
+/***********************************************************************
+ * static helper functions
+ */
+static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid);
+static LONG register_key_defvalueW(HKEY base, WCHAR const *name,
+ WCHAR const *value);
+static LONG register_key_defvalueA(HKEY base, WCHAR const *name,
+ char const *value);
+static LONG register_progid(WCHAR const *clsid,
+ char const *progid, char const *curver_progid,
+ char const *name, char const *extra);
+static LONG recursive_delete_key(HKEY key);
+static LONG recursive_delete_keyA(HKEY base, char const *name);
+static LONG recursive_delete_keyW(HKEY base, WCHAR const *name);
+
+/***********************************************************************
+ * register_interfaces
+ */
+static HRESULT register_interfaces(struct regsvr_interface const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY interface_key;
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &interface_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->iid; ++list) {
+ WCHAR buf[39];
+ HKEY iid_key;
+
+ StringFromGUID2(list->iid, buf, 39);
+ res = RegCreateKeyExW(interface_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &iid_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_interface_key;
+
+ if (list->name) {
+ res = RegSetValueExA(iid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)(list->name),
+ strlen(list->name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->base_iid) {
+ register_key_guid(iid_key, base_ifa_keyname, list->base_iid);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (0 <= list->num_methods) {
+ static WCHAR const fmt[3] = { '%', 'd', 0 };
+ HKEY key;
+
+ res = RegCreateKeyExW(iid_key, num_methods_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+
+ wsprintfW(buf, fmt, list->num_methods);
+ res = RegSetValueExW(key, NULL, 0, REG_SZ,
+ (CONST BYTE*)buf,
+ (lstrlenW(buf) + 1) * sizeof(WCHAR));
+ RegCloseKey(key);
+
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->ps_clsid) {
+ register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ if (list->ps_clsid32) {
+ register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32);
+ if (res != ERROR_SUCCESS) goto error_close_iid_key;
+ }
+
+ error_close_iid_key:
+ RegCloseKey(iid_key);
+ }
+
+error_close_interface_key:
+ RegCloseKey(interface_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_interfaces
+ */
+static HRESULT unregister_interfaces(struct regsvr_interface const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY interface_key;
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, interface_keyname, 0,
+ KEY_READ | KEY_WRITE, &interface_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->iid; ++list) {
+ WCHAR buf[39];
+
+ StringFromGUID2(list->iid, buf, 39);
+ res = recursive_delete_keyW(interface_key, buf);
+ }
+
+ RegCloseKey(interface_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * register_coclasses
+ */
+static HRESULT register_coclasses(struct regsvr_coclass const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY coclass_key;
+
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &coclass_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+ WCHAR buf[39];
+ HKEY clsid_key;
+
+ StringFromGUID2(list->clsid, buf, 39);
+ res = RegCreateKeyExW(coclass_key, buf, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+ if (list->name) {
+ res = RegSetValueExA(clsid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)(list->name),
+ strlen(list->name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->ips) {
+ res = register_key_defvalueA(clsid_key, ips_keyname, list->ips);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->ips32) {
+ HKEY ips32_key;
+
+ res = RegCreateKeyExW(clsid_key, ips32_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL,
+ &ips32_key, NULL);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = RegSetValueExA(ips32_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)list->ips32,
+ lstrlenA(list->ips32) + 1);
+ if (res == ERROR_SUCCESS && list->ips32_tmodel)
+ res = RegSetValueExA(ips32_key, tmodel_valuename, 0, REG_SZ,
+ (CONST BYTE*)list->ips32_tmodel,
+ strlen(list->ips32_tmodel) + 1);
+ RegCloseKey(ips32_key);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->progid) {
+ res = register_key_defvalueA(clsid_key, progid_keyname,
+ list->progid);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = register_progid(buf, list->progid, NULL,
+ list->name, list->progid_extra);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ if (list->viprogid) {
+ res = register_key_defvalueA(clsid_key, viprogid_keyname,
+ list->viprogid);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+
+ res = register_progid(buf, list->viprogid, list->progid,
+ list->name, list->progid_extra);
+ if (res != ERROR_SUCCESS) goto error_close_clsid_key;
+ }
+
+ error_close_clsid_key:
+ RegCloseKey(clsid_key);
+ }
+
+error_close_coclass_key:
+ RegCloseKey(coclass_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * unregister_coclasses
+ */
+static HRESULT unregister_coclasses(struct regsvr_coclass const *list)
+{
+ LONG res = ERROR_SUCCESS;
+ HKEY coclass_key;
+
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0,
+ KEY_READ | KEY_WRITE, &coclass_key);
+ if (res == ERROR_FILE_NOT_FOUND) return S_OK;
+ if (res != ERROR_SUCCESS) goto error_return;
+
+ for (; res == ERROR_SUCCESS && list->clsid; ++list) {
+ WCHAR buf[39];
+
+ StringFromGUID2(list->clsid, buf, 39);
+ res = recursive_delete_keyW(coclass_key, buf);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+
+ if (list->progid) {
+ res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+ }
+
+ if (list->viprogid) {
+ res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid);
+ if (res != ERROR_SUCCESS) goto error_close_coclass_key;
+ }
+ }
+
+error_close_coclass_key:
+ RegCloseKey(coclass_key);
+error_return:
+ return res != ERROR_SUCCESS ? HRESULT_FROM_WIN32(res) : S_OK;
+}
+
+/***********************************************************************
+ * regsvr_key_guid
+ */
+static LONG register_key_guid(HKEY base, WCHAR const *name, GUID const *guid)
+{
+ WCHAR buf[39];
+
+ StringFromGUID2(guid, buf, 39);
+ return register_key_defvalueW(base, name, buf);
+}
+
+/***********************************************************************
+ * regsvr_key_defvalueW
+ */
+static LONG register_key_defvalueW(
+ HKEY base,
+ WCHAR const *name,
+ WCHAR const *value)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegCreateKeyExW(base, name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+ res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+ (lstrlenW(value) + 1) * sizeof(WCHAR));
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * regsvr_key_defvalueA
+ */
+static LONG register_key_defvalueA(
+ HKEY base,
+ WCHAR const *name,
+ char const *value)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegCreateKeyExW(base, name, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+ res = RegSetValueExA(key, NULL, 0, REG_SZ, (CONST BYTE*)value,
+ lstrlenA(value) + 1);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * regsvr_progid
+ */
+static LONG register_progid(
+ WCHAR const *clsid,
+ char const *progid,
+ char const *curver_progid,
+ char const *name,
+ char const *extra)
+{
+ LONG res;
+ HKEY progid_key;
+
+ res = RegCreateKeyExA(HKEY_CLASSES_ROOT, progid, 0,
+ NULL, 0, KEY_READ | KEY_WRITE, NULL,
+ &progid_key, NULL);
+ if (res != ERROR_SUCCESS) return res;
+
+ if (name) {
+ res = RegSetValueExA(progid_key, NULL, 0, REG_SZ,
+ (CONST BYTE*)name, strlen(name) + 1);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (clsid) {
+ res = register_key_defvalueW(progid_key, clsid_keyname, clsid);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (curver_progid) {
+ res = register_key_defvalueA(progid_key, curver_keyname,
+ curver_progid);
+ if (res != ERROR_SUCCESS) goto error_close_progid_key;
+ }
+
+ if (extra) {
+ HKEY extra_key;
+
+ res = RegCreateKeyExA(progid_key, extra, 0,
+ NULL, 0, KEY_READ | KEY_WRITE, NULL,
+ &extra_key, NULL);
+ if (res == ERROR_SUCCESS)
+ RegCloseKey(extra_key);
+ }
+
+error_close_progid_key:
+ RegCloseKey(progid_key);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_key
+ */
+static LONG recursive_delete_key(HKEY key)
+{
+ LONG res;
+ WCHAR subkey_name[MAX_PATH];
+ DWORD cName;
+ HKEY subkey;
+
+ for (;;) {
+ cName = sizeof(subkey_name) / sizeof(WCHAR);
+ res = RegEnumKeyExW(key, 0, subkey_name, &cName,
+ NULL, NULL, NULL, NULL);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) {
+ res = ERROR_SUCCESS; /* presumably we're done enumerating */
+ break;
+ }
+ res = RegOpenKeyExW(key, subkey_name, 0,
+ KEY_READ | KEY_WRITE, &subkey);
+ if (res == ERROR_FILE_NOT_FOUND) continue;
+ if (res != ERROR_SUCCESS) break;
+
+ res = recursive_delete_key(subkey);
+ RegCloseKey(subkey);
+ if (res != ERROR_SUCCESS) break;
+ }
+
+ if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_keyA
+ */
+static LONG recursive_delete_keyA(HKEY base, char const *name)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key);
+ if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
+ if (res != ERROR_SUCCESS) return res;
+ res = recursive_delete_key(key);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * recursive_delete_keyW
+ */
+static LONG recursive_delete_keyW(HKEY base, WCHAR const *name)
+{
+ LONG res;
+ HKEY key;
+
+ res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key);
+ if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS;
+ if (res != ERROR_SUCCESS) return res;
+ res = recursive_delete_key(key);
+ RegCloseKey(key);
+ return res;
+}
+
+/***********************************************************************
+ * coclass list
+ */
+static GUID const CLSID_AVIProxy = {
+ 0x0002000D, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
+
+static struct regsvr_coclass const coclass_list[] = {
+ { &CLSID_AVIFile,
+ "Microsoft AVI Files",
+ "avifile.dll",
+ "avifil32.dll",
+ "Apartment"
+ },
+ { &CLSID_ICMStream,
+ "AVI Compressed Stream",
+ "avifile.dll",
+ "avifil32.dll",
+ "Apartment"
+ },
+ { &CLSID_WAVFile,
+ "Microsoft Wave File",
+ "avifile.dll",
+ "avifil32.dll",
+ "Apartment"
+ },
+ { &CLSID_AVIProxy,
+ "IAVIStream & IAVIFile Proxy",
+ "avifile.dll",
+ "avifil32.dll",
+ "Apartment"
+ },
+ { &CLSID_ACMStream,
+ "ACM Compressed Audio Stream",
+ "avifile.dll",
+ "avifil32.dll",
+ "Apartment"
+ },
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * interface list
+ */
+
+static struct regsvr_interface const interface_list[] = {
+ { NULL } /* list terminator */
+};
+
+/***********************************************************************
+ * DllRegisterServer (AVIFILE.@)
+ */
+HRESULT WINAPI DllRegisterServer(void)
+{
+ HRESULT hr;
+
+ TRACE("\n");
+
+ hr = register_coclasses(coclass_list);
+ if (SUCCEEDED(hr))
+ hr = register_interfaces(interface_list);
+ return hr;
+}
+
+/***********************************************************************
+ * DllUnregisterServer (AVIFILE.@)
+ */
+HRESULT WINAPI DllUnregisterServer(void)
+{
+ HRESULT hr;
+
+ TRACE("\n");
+
+ hr = unregister_coclasses(coclass_list);
+ if (SUCCEEDED(hr))
+ hr = unregister_interfaces(interface_list);
+ return hr;
+}
--- /dev/null
+/*
+ * Top level resource file for avifil32.dll
+ *
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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 "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winver.h"
+#include "avifile_private.h"
+
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+
+#define WINE_OLESELFREGISTER
+#define WINE_FILEDESCRIPTION_STR "Wine AVI file support library"
+#define WINE_FILENAME_STR "avifil32.dll"
+#define WINE_FILEVERSION 4,0,3,1998
+#define WINE_FILEVERSION_STR "4.03.1998"
+
+#include "wine/wine_common_ver.rc"
+
+/*
+ * Everything specific to any language goes
+ * in one of the specific files.
+ */
+#include "avifile_Cs.rc"
+#include "avifile_De.rc"
+#include "avifile_En.rc"
+#include "avifile_Es.rc"
+#include "avifile_Fr.rc"
+#include "avifile_It.rc"
+#include "avifile_Ja.rc"
+#include "avifile_Nl.rc"
+#include "avifile_No.rc"
+#include "avifile_Pl.rc"
+#include "avifile_Pt.rc"
+#include "avifile_Ru.rc"
+#include "avifile_Si.rc"
--- /dev/null
+/*
+ * Copyright 2003 Michael Günnewig
+ *
+ * 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
+ */
+
+#define COM_NO_WINDOWS_H
+#include <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "windowsx.h"
+#include "mmsystem.h"
+#include "vfw.h"
+
+#include "avifile_private.h"
+#include "extrachunk.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+/***********************************************************************/
+
+static HRESULT WINAPI ITmpFile_fnQueryInterface(IAVIFile* iface,REFIID refiid,LPVOID *obj);
+static ULONG WINAPI ITmpFile_fnAddRef(IAVIFile* iface);
+static ULONG WINAPI ITmpFile_fnRelease(IAVIFile* iface);
+static HRESULT WINAPI ITmpFile_fnInfo(IAVIFile*iface,AVIFILEINFOW*afi,LONG size);
+static HRESULT WINAPI ITmpFile_fnGetStream(IAVIFile*iface,PAVISTREAM*avis,DWORD fccType,LONG lParam);
+static HRESULT WINAPI ITmpFile_fnCreateStream(IAVIFile*iface,PAVISTREAM*avis,AVISTREAMINFOW*asi);
+static HRESULT WINAPI ITmpFile_fnWriteData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG size);
+static HRESULT WINAPI ITmpFile_fnReadData(IAVIFile*iface,DWORD ckid,LPVOID lpData,LONG *size);
+static HRESULT WINAPI ITmpFile_fnEndRecord(IAVIFile*iface);
+static HRESULT WINAPI ITmpFile_fnDeleteStream(IAVIFile*iface,DWORD fccType,LONG lParam);
+
+static const struct IAVIFileVtbl itmpft = {
+ ITmpFile_fnQueryInterface,
+ ITmpFile_fnAddRef,
+ ITmpFile_fnRelease,
+ ITmpFile_fnInfo,
+ ITmpFile_fnGetStream,
+ ITmpFile_fnCreateStream,
+ ITmpFile_fnWriteData,
+ ITmpFile_fnReadData,
+ ITmpFile_fnEndRecord,
+ ITmpFile_fnDeleteStream
+};
+
+typedef struct _ITmpFileImpl {
+ /* IUnknown stuff */
+ const IAVIFileVtbl *lpVtbl;
+ LONG ref;
+
+ /* IAVIFile stuff */
+ AVIFILEINFOW fInfo;
+ PAVISTREAM *ppStreams;
+} ITmpFileImpl;
+
+PAVIFILE AVIFILE_CreateAVITempFile(int nStreams, PAVISTREAM *ppStreams) {
+ ITmpFileImpl *tmpFile;
+ int i;
+
+ tmpFile = LocalAlloc(LPTR, sizeof(ITmpFileImpl));
+ if (tmpFile == NULL)
+ return NULL;
+
+ tmpFile->lpVtbl = &itmpft;
+ tmpFile->ref = 1;
+ memset(&tmpFile->fInfo, 0, sizeof(tmpFile->fInfo));
+
+ tmpFile->fInfo.dwStreams = nStreams;
+ tmpFile->ppStreams = LocalAlloc(LPTR, nStreams * sizeof(PAVISTREAM));
+ if (tmpFile->ppStreams == NULL) {
+ LocalFree((HLOCAL)tmpFile);
+ return NULL;
+ }
+
+ for (i = 0; i < nStreams; i++) {
+ AVISTREAMINFOW sInfo;
+
+ tmpFile->ppStreams[i] = ppStreams[i];
+
+ AVIStreamAddRef(ppStreams[i]);
+ AVIStreamInfoW(ppStreams[i], &sInfo, sizeof(sInfo));
+ if (i == 0) {
+ tmpFile->fInfo.dwScale = sInfo.dwScale;
+ tmpFile->fInfo.dwRate = sInfo.dwRate;
+ if (!sInfo.dwScale || !sInfo.dwRate) {
+ tmpFile->fInfo.dwScale = 1;
+ tmpFile->fInfo.dwRate = 100;
+ }
+ }
+
+ if (tmpFile->fInfo.dwSuggestedBufferSize < sInfo.dwSuggestedBufferSize)
+ tmpFile->fInfo.dwSuggestedBufferSize = sInfo.dwSuggestedBufferSize;
+
+ {
+ register DWORD tmp;
+
+ tmp = MulDiv(AVIStreamSampleToTime(ppStreams[i], sInfo.dwLength), \
+ tmpFile->fInfo.dwScale, tmpFile->fInfo.dwRate * 1000);
+ if (tmpFile->fInfo.dwLength < tmp)
+ tmpFile->fInfo.dwLength = tmp;
+
+ tmp = sInfo.rcFrame.right - sInfo.rcFrame.left;
+ if (tmpFile->fInfo.dwWidth < tmp)
+ tmpFile->fInfo.dwWidth = tmp;
+ tmp = sInfo.rcFrame.bottom - sInfo.rcFrame.top;
+ if (tmpFile->fInfo.dwHeight < tmp)
+ tmpFile->fInfo.dwHeight = tmp;
+ }
+ }
+
+ return (PAVIFILE)tmpFile;
+}
+
+static HRESULT WINAPI ITmpFile_fnQueryInterface(IAVIFile *iface, REFIID refiid,
+ LPVOID *obj)
+{
+ ITmpFileImpl *This = (ITmpFileImpl *)iface;
+
+ TRACE("(%p,%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 ITmpFile_fnAddRef(IAVIFile *iface)
+{
+ ITmpFileImpl *This = (ITmpFileImpl *)iface;
+ ULONG ref = InterlockedIncrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ return ref;
+}
+
+static ULONG WINAPI ITmpFile_fnRelease(IAVIFile *iface)
+{
+ ITmpFileImpl *This = (ITmpFileImpl *)iface;
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p) -> %ld\n", iface, ref);
+
+ if (!ref) {
+ unsigned int i;
+
+ for (i = 0; i < This->fInfo.dwStreams; i++) {
+ if (This->ppStreams[i] != NULL) {
+ AVIStreamRelease(This->ppStreams[i]);
+
+ This->ppStreams[i] = NULL;
+ }
+ }
+
+ LocalFree((HLOCAL)This);
+ return 0;
+ }
+
+ return ref;
+}
+
+static HRESULT WINAPI ITmpFile_fnInfo(IAVIFile *iface,
+ AVIFILEINFOW *afi, LONG size)
+{
+ ITmpFileImpl *This = (ITmpFileImpl *)iface;
+
+ TRACE("(%p,%p,%ld)\n",iface,afi,size);
+
+ if (afi == NULL)
+ return AVIERR_BADPARAM;
+ if (size < 0)
+ return AVIERR_BADSIZE;
+
+ memcpy(afi, &This->fInfo, min((DWORD)size, sizeof(This->fInfo)));
+
+ if ((DWORD)size < sizeof(This->fInfo))
+ return AVIERR_BUFFERTOOSMALL;
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI ITmpFile_fnGetStream(IAVIFile *iface, PAVISTREAM *avis,
+ DWORD fccType, LONG lParam)
+{
+ ITmpFileImpl *This = (ITmpFileImpl *)iface;
+
+ ULONG nStream = (ULONG)-1;
+
+ TRACE("(%p,%p,0x%08lX,%ld)\n", iface, avis, fccType, lParam);
+
+ if (avis == NULL || lParam < 0)
+ return AVIERR_BADPARAM;
+
+ if (fccType != streamtypeANY) {
+ /* search the number of the specified stream */
+ ULONG i;
+
+ for (i = 0; i < This->fInfo.dwStreams; i++) {
+ AVISTREAMINFOW sInfo;
+ HRESULT hr;
+
+ hr = AVIStreamInfoW(This->ppStreams[i], &sInfo, sizeof(sInfo));
+ if (FAILED(hr))
+ return hr;
+
+ if (sInfo.fccType == fccType) {
+ if (lParam == 0) {
+ nStream = i;
+ break;
+ } else
+ lParam--;
+ }
+ }
+ } else
+ nStream = lParam;
+
+ /* Does the requested stream exist ? */
+ if (nStream < This->fInfo.dwStreams && This->ppStreams[nStream] != NULL) {
+ *avis = This->ppStreams[nStream];
+ AVIStreamAddRef(*avis);
+
+ return AVIERR_OK;
+ }
+
+ /* Sorry, but the specified stream doesn't exist */
+ return AVIERR_NODATA;
+}
+
+static HRESULT WINAPI ITmpFile_fnCreateStream(IAVIFile *iface,PAVISTREAM *avis,
+ AVISTREAMINFOW *asi)
+{
+ TRACE("(%p,%p,%p)\n",iface,avis,asi);
+
+ return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI ITmpFile_fnWriteData(IAVIFile *iface, DWORD ckid,
+ LPVOID lpData, LONG size)
+{
+ TRACE("(%p,0x%08lX,%p,%ld)\n", iface, ckid, lpData, size);
+
+ return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI ITmpFile_fnReadData(IAVIFile *iface, DWORD ckid,
+ LPVOID lpData, LONG *size)
+{
+ TRACE("(%p,0x%08lX,%p,%p)\n", iface, ckid, lpData, size);
+
+ return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI ITmpFile_fnEndRecord(IAVIFile *iface)
+{
+ TRACE("(%p)\n",iface);
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI ITmpFile_fnDeleteStream(IAVIFile *iface, DWORD fccType,
+ LONG lParam)
+{
+ TRACE("(%p,0x%08lX,%ld)\n", iface, fccType, lParam);
+
+ return AVIERR_UNSUPPORTED;
+}
--- /dev/null
+/*
+ * Copyright 2002 Michael Günnewig
+ *
+ * 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
+ */
+
+#define COM_NO_WINDOWS_H
+#include <assert.h>
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wingdi.h"
+#include "winuser.h"
+#include "winnls.h"
+#include "winerror.h"
+#include "windowsx.h"
+#include "mmsystem.h"
+#include "vfw.h"
+#include "msacm.h"
+
+#include "avifile_private.h"
+#include "extrachunk.h"
+
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(avifile);
+
+/***********************************************************************/
+
+#define formtypeWAVE mmioFOURCC('W','A','V','E')
+#define ckidWAVEFORMAT mmioFOURCC('f','m','t',' ')
+#define ckidWAVEFACT mmioFOURCC('f','a','c','t')
+#define ckidWAVEDATA mmioFOURCC('d','a','t','a')
+
+/***********************************************************************/
+
+#define ENDIAN_SWAPWORD(x) ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8))
+#define ENDIAN_SWAPDWORD(x) (ENDIAN_SWAPWORD((x >> 16) & 0xFFFF) | \
+ ENDIAN_SWAPWORD(x & 0xFFFF) << 16)
+
+#ifdef WORDS_BIGENDIAN
+#define BE2H_WORD(x) (x)
+#define BE2H_DWORD(x) (x)
+#define LE2H_WORD(x) ENDIAN_SWAPWORD(x)
+#define LE2H_DWORD(x) ENDIAN_SWAPDWORD(x)
+#else
+#define BE2H_WORD(x) ENDIAN_SWAPWORD(x)
+#define BE2H_DWORD(x) ENDIAN_SWAPDWORD(x)
+#define LE2H_WORD(x) (x)
+#define LE2H_DWORD(x) (x)
+#endif
+
+typedef struct {
+ FOURCC fccType;
+ DWORD offset;
+ DWORD size;
+ INT encoding;
+ DWORD sampleRate;
+ DWORD channels;
+} SUNAUDIOHEADER;
+
+#define AU_ENCODING_ULAW_8 1
+#define AU_ENCODING_PCM_8 2
+#define AU_ENCODING_PCM_16 3
+#define AU_ENCODING_PCM_24 4
+#define AU_ENCODING_PCM_32 5
+#define AU_ENCODING_FLOAT 6
+#define AU_ENCODING_DOUBLE 7
+#define AU_ENCODING_ADPCM_G721_32 23
+#define AU_ENCODING_ADPCM_G722 24
+#define AU_ENCODING_ADPCM_G723_24 25
+#define AU_ENCODING_ADPCM_G723_5 26
+#define AU_ENCODING_ALAW_8 27
+
+/***********************************************************************/
+
+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);
+
+static const struct IAVIFileVtbl iwavft = {
+ IAVIFile_fnQueryInterface,
+ IAVIFile_fnAddRef,
+ IAVIFile_fnRelease,
+ IAVIFile_fnInfo,
+ IAVIFile_fnGetStream,
+ IAVIFile_fnCreateStream,
+ IAVIFile_fnWriteData,
+ IAVIFile_fnReadData,
+ IAVIFile_fnEndRecord,
+ IAVIFile_fnDeleteStream
+};
+
+static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile*iface,REFIID refiid,LPVOID*obj);
+static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile*iface);
+static ULONG WINAPI IPersistFile_fnRelease(IPersistFile*iface);
+static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile*iface,CLSID*pClassID);
+static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile*iface);
+static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile*iface,LPCOLESTR pszFileName,DWORD dwMode);
+static HRESULT WINAPI IPersistFile_fnSave(IPersistFile*iface,LPCOLESTR pszFileName,BOOL fRemember);
+static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile*iface,LPCOLESTR pszFileName);
+static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile*iface,LPOLESTR*ppszFileName);
+
+static const struct IPersistFileVtbl iwavpft = {
+ IPersistFile_fnQueryInterface,
+ IPersistFile_fnAddRef,
+ IPersistFile_fnRelease,
+ IPersistFile_fnGetClassID,
+ IPersistFile_fnIsDirty,
+ IPersistFile_fnLoad,
+ IPersistFile_fnSave,
+ IPersistFile_fnSaveCompleted,
+ IPersistFile_fnGetCurFile
+};
+
+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);
+
+static const struct IAVIStreamVtbl iwavst = {
+ 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 _IAVIFileImpl IAVIFileImpl;
+
+typedef struct _IPersistFileImpl {
+ /* IUnknown stuff */
+ const IPersistFileVtbl *lpVtbl;
+
+ /* IPersistFile stuff */
+ IAVIFileImpl *paf;
+} IPersistFileImpl;
+
+typedef struct _IAVIStreamImpl {
+ /* IUnknown stuff */
+ const IAVIStreamVtbl *lpVtbl;
+
+ /* IAVIStream stuff */
+ IAVIFileImpl *paf;
+} IAVIStreamImpl;
+
+struct _IAVIFileImpl {
+ /* IUnknown stuff */
+ const IAVIFileVtbl *lpVtbl;
+ LONG ref;
+
+ /* IAVIFile, IAVIStream stuff... */
+ IPersistFileImpl iPersistFile;
+ IAVIStreamImpl iAVIStream;
+
+ AVIFILEINFOW fInfo;
+ AVISTREAMINFOW sInfo;
+
+ LPWAVEFORMATEX lpFormat;
+ LONG cbFormat;
+
+ MMCKINFO ckData;
+
+ EXTRACHUNKS extra;
+
+ /* IPersistFile stuff ... */
+ HMMIO hmmio;
+ LPWSTR szFileName;
+ UINT uMode;
+ BOOL fDirty;
+};
+
+/***********************************************************************/
+
+static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This);
+static HRESULT AVIFILE_LoadSunFile(IAVIFileImpl *This);
+static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This);
+
+HRESULT AVIFILE_CreateWAVFile(REFIID riid, LPVOID *ppv)
+{
+ IAVIFileImpl *pfile;
+ HRESULT hr;
+
+ assert(riid != NULL && ppv != NULL);
+
+ *ppv = NULL;
+
+ pfile = (IAVIFileImpl*)LocalAlloc(LPTR, sizeof(IAVIFileImpl));
+ if (pfile == NULL)
+ return AVIERR_MEMORY;
+
+ pfile->lpVtbl = &iwavft;
+ pfile->iPersistFile.lpVtbl = &iwavpft;
+ pfile->iAVIStream.lpVtbl = &iwavst;
+ pfile->ref = 0;
+ pfile->iPersistFile.paf = pfile;
+ pfile->iAVIStream.paf = pfile;
+
+ hr = IAVIFile_QueryInterface((IAVIFile*)pfile, riid, ppv);
+ if (FAILED(hr))
+ LocalFree((HLOCAL)pfile);
+
+ return hr;
+}
+
+static HRESULT WINAPI IAVIFile_fnQueryInterface(IAVIFile *iface, REFIID refiid,
+ LPVOID *obj)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,%s,%p)\n", This, debugstr_guid(refiid), obj);
+
+ if (IsEqualGUID(&IID_IUnknown, refiid) ||
+ IsEqualGUID(&IID_IAVIFile, refiid)) {
+ *obj = iface;
+ return S_OK;
+ } else if (This->fInfo.dwStreams == 1 &&
+ IsEqualGUID(&IID_IAVIStream, refiid)) {
+ *obj = &This->iAVIStream;
+ return S_OK;
+ } else if (IsEqualGUID(&IID_IPersistFile, refiid)) {
+ *obj = &This->iPersistFile;
+ return S_OK;
+ }
+
+ return OLE_E_ENUM_NOMORE;
+}
+
+static ULONG WINAPI IAVIFile_fnAddRef(IAVIFile *iface)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p)\n",iface);
+
+ return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI IAVIFile_fnRelease(IAVIFile *iface)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+ ULONG ref = InterlockedDecrement(&This->ref);
+
+ TRACE("(%p)\n",iface);
+
+ if (!ref) {
+ if (This->fDirty) {
+ /* need to write headers to file */
+ AVIFILE_SaveFile(This);
+ }
+
+ if (This->lpFormat != NULL) {
+ GlobalFreePtr(This->lpFormat);
+ This->lpFormat = NULL;
+ This->cbFormat = 0;
+ }
+ if (This->extra.lp != NULL) {
+ GlobalFreePtr(This->extra.lp);
+ This->extra.lp = NULL;
+ This->extra.cb = 0;
+ }
+ if (This->szFileName != NULL) {
+ LocalFree((HLOCAL)This->szFileName);
+ This->szFileName = NULL;
+ }
+ if (This->hmmio != NULL) {
+ mmioClose(This->hmmio, 0);
+ This->hmmio = NULL;
+ }
+
+ LocalFree((HLOCAL)This);
+ return 0;
+ }
+ return ref;
+}
+
+static HRESULT WINAPI IAVIFile_fnInfo(IAVIFile *iface, LPAVIFILEINFOW afi,
+ LONG size)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,%p,%ld)\n",iface,afi,size);
+
+ if (afi == NULL)
+ return AVIERR_BADPARAM;
+ if (size < 0)
+ return AVIERR_BADSIZE;
+
+ /* update file info */
+ This->fInfo.dwFlags = 0;
+ This->fInfo.dwCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
+ if (This->lpFormat != NULL) {
+ assert(This->sInfo.dwScale != 0);
+
+ This->fInfo.dwStreams = 1;
+ This->fInfo.dwScale = This->sInfo.dwScale;
+ This->fInfo.dwRate = This->sInfo.dwRate;
+ This->fInfo.dwLength = This->sInfo.dwLength;
+ This->fInfo.dwSuggestedBufferSize = This->ckData.cksize;
+ This->fInfo.dwMaxBytesPerSec =
+ MulDiv(This->sInfo.dwSampleSize,This->sInfo.dwRate,This->sInfo.dwScale);
+ }
+
+ memcpy(afi, &This->fInfo, min((DWORD)size, sizeof(This->fInfo)));
+
+ if ((DWORD)size < sizeof(This->fInfo))
+ return AVIERR_BUFFERTOOSMALL;
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnGetStream(IAVIFile *iface, PAVISTREAM *avis,
+ DWORD fccType, LONG lParam)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,%p,0x%08lX,%ld)\n", iface, avis, fccType, lParam);
+
+ /* check parameter */
+ if (avis == NULL)
+ return AVIERR_BADPARAM;
+
+ *avis = NULL;
+
+ /* Does our stream exists? */
+ if (lParam != 0 || This->fInfo.dwStreams == 0)
+ return AVIERR_NODATA;
+ if (fccType != 0 && fccType != streamtypeAUDIO)
+ return AVIERR_NODATA;
+
+ *avis = (PAVISTREAM)&This->iAVIStream;
+ IAVIFile_AddRef(iface);
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnCreateStream(IAVIFile *iface,PAVISTREAM *avis,
+ LPAVISTREAMINFOW asi)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,%p,%p)\n", iface, avis, asi);
+
+ /* check parameters */
+ if (avis == NULL || asi == NULL)
+ return AVIERR_BADPARAM;
+
+ *avis = NULL;
+
+ /* We only support one audio stream */
+ if (This->fInfo.dwStreams != 0 || This->lpFormat != NULL)
+ return AVIERR_UNSUPPORTED;
+ if (asi->fccType != streamtypeAUDIO)
+ return AVIERR_UNSUPPORTED;
+
+ /* Does the user have write permission? */
+ if ((This->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ This->cbFormat = 0;
+ This->lpFormat = NULL;
+
+ memcpy(&This->sInfo, asi, sizeof(This->sInfo));
+
+ /* make sure streaminfo if okay for us */
+ This->sInfo.fccHandler = 0;
+ This->sInfo.dwFlags = 0;
+ This->sInfo.dwCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
+ This->sInfo.dwStart = 0;
+ This->sInfo.dwInitialFrames = 0;
+ This->sInfo.dwFormatChangeCount = 0;
+ memset(&This->sInfo.rcFrame, 0, sizeof(This->sInfo.rcFrame));
+
+ This->fInfo.dwStreams = 1;
+ This->fInfo.dwScale = This->sInfo.dwScale;
+ This->fInfo.dwRate = This->sInfo.dwRate;
+ This->fInfo.dwLength = This->sInfo.dwLength;
+
+ This->ckData.dwDataOffset = 0;
+ This->ckData.cksize = 0;
+
+ *avis = (PAVISTREAM)&This->iAVIStream;
+ IAVIFile_AddRef(iface);
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnWriteData(IAVIFile *iface, DWORD ckid,
+ LPVOID lpData, LONG size)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,0x%08lX,%p,%ld)\n", iface, ckid, lpData, size);
+
+ /* check parameters */
+ if (lpData == NULL)
+ return AVIERR_BADPARAM;
+ if (size < 0)
+ return AVIERR_BADSIZE;
+
+ /* Do we have write permission? */
+ if ((This->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ This->fDirty = TRUE;
+
+ return WriteExtraChunk(&This->extra, ckid, lpData, size);
+}
+
+static HRESULT WINAPI IAVIFile_fnReadData(IAVIFile *iface, DWORD ckid,
+ LPVOID lpData, LONG *size)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,0x%08lX,%p,%p)\n", iface, ckid, lpData, size);
+
+ return ReadExtraChunk(&This->extra, ckid, lpData, size);
+}
+
+static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface)
+{
+ TRACE("(%p)\n",iface);
+
+ /* This is only needed for interleaved files.
+ * We have only one stream, which can't be interleaved.
+ */
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile *iface, DWORD fccType,
+ LONG lParam)
+{
+ IAVIFileImpl *This = (IAVIFileImpl *)iface;
+
+ TRACE("(%p,0x%08lX,%ld)\n", iface, fccType, lParam);
+
+ /* check parameter */
+ if (lParam < 0)
+ return AVIERR_BADPARAM;
+
+ /* Do we have our audio stream? */
+ if (lParam != 0 || This->fInfo.dwStreams == 0 ||
+ (fccType != 0 && fccType != streamtypeAUDIO))
+ return AVIERR_NODATA;
+
+ /* Have user write permissions? */
+ if ((This->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ GlobalFreePtr(This->lpFormat);
+ This->lpFormat = NULL;
+ This->cbFormat = 0;
+
+ /* update infos */
+ This->ckData.dwDataOffset = 0;
+ This->ckData.cksize = 0;
+
+ This->sInfo.dwScale = 0;
+ This->sInfo.dwRate = 0;
+ This->sInfo.dwLength = 0;
+ This->sInfo.dwSuggestedBufferSize = 0;
+
+ This->fInfo.dwStreams = 0;
+ This->fInfo.dwEditCount++;
+
+ This->fDirty = TRUE;
+
+ return AVIERR_OK;
+}
+
+/***********************************************************************/
+
+static HRESULT WINAPI IPersistFile_fnQueryInterface(IPersistFile *iface,
+ REFIID refiid, LPVOID *obj)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ assert(This->paf != NULL);
+
+ return IAVIFile_QueryInterface((PAVIFILE)This->paf, refiid, obj);
+}
+
+static ULONG WINAPI IPersistFile_fnAddRef(IPersistFile *iface)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ assert(This->paf != NULL);
+
+ return IAVIFile_AddRef((PAVIFILE)This->paf);
+}
+
+static ULONG WINAPI IPersistFile_fnRelease(IPersistFile *iface)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ assert(This->paf != NULL);
+
+ return IAVIFile_Release((PAVIFILE)This->paf);
+}
+
+static HRESULT WINAPI IPersistFile_fnGetClassID(IPersistFile *iface,
+ LPCLSID pClassID)
+{
+ TRACE("(%p,%p)\n", iface, pClassID);
+
+ if (pClassID == NULL)
+ return AVIERR_BADPARAM;
+
+ memcpy(pClassID, &CLSID_WAVFile, sizeof(CLSID_WAVFile));
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IPersistFile_fnIsDirty(IPersistFile *iface)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ TRACE("(%p)\n", iface);
+
+ assert(This->paf != NULL);
+
+ return (This->paf->fDirty ? S_OK : S_FALSE);
+}
+
+static HRESULT WINAPI IPersistFile_fnLoad(IPersistFile *iface,
+ LPCOLESTR pszFileName, DWORD dwMode)
+{
+ IAVIFileImpl *This = ((IPersistFileImpl*)iface)->paf;
+
+ WCHAR wszStreamFmt[50];
+ INT len;
+
+ TRACE("(%p,%s,0x%08lX)\n", iface, debugstr_w(pszFileName), dwMode);
+
+ /* check parameter */
+ if (pszFileName == NULL)
+ return AVIERR_BADPARAM;
+
+ assert(This != NULL);
+ if (This->hmmio != NULL)
+ return AVIERR_ERROR; /* No reuse of this object for another file! */
+
+ /* remeber mode and name */
+ This->uMode = dwMode;
+
+ len = lstrlenW(pszFileName) + 1;
+ This->szFileName = LocalAlloc(LPTR, len * sizeof(WCHAR));
+ if (This->szFileName == NULL)
+ return AVIERR_MEMORY;
+ lstrcpyW(This->szFileName, pszFileName);
+
+ /* try to open the file */
+ This->hmmio = mmioOpenW(This->szFileName, NULL, MMIO_ALLOCBUF | dwMode);
+ if (This->hmmio == NULL) {
+ /* mmioOpenW not in native DLLs of Win9x -- try mmioOpenA */
+ LPSTR szFileName;
+ len = WideCharToMultiByte(CP_ACP, 0, This->szFileName, -1,
+ NULL, 0, NULL, NULL);
+ szFileName = LocalAlloc(LPTR, len * sizeof(CHAR));
+ if (szFileName == NULL)
+ return AVIERR_MEMORY;
+
+ WideCharToMultiByte(CP_ACP, 0, This->szFileName, -1, szFileName,
+ len, NULL, NULL);
+
+ This->hmmio = mmioOpenA(szFileName, NULL, MMIO_ALLOCBUF | dwMode);
+ LocalFree((HLOCAL)szFileName);
+ if (This->hmmio == NULL)
+ return AVIERR_FILEOPEN;
+ }
+
+ memset(& This->fInfo, 0, sizeof(This->fInfo));
+ memset(& This->sInfo, 0, sizeof(This->sInfo));
+
+ LoadStringW(AVIFILE_hModule, IDS_WAVEFILETYPE, This->fInfo.szFileType,
+ sizeof(This->fInfo.szFileType));
+ if (LoadStringW(AVIFILE_hModule, IDS_WAVESTREAMFORMAT,
+ wszStreamFmt, sizeof(wszStreamFmt)) > 0) {
+ wsprintfW(This->sInfo.szName, wszStreamFmt,
+ AVIFILE_BasenameW(This->szFileName));
+ }
+
+ /* should we create a new file? */
+ if (dwMode & OF_CREATE) {
+ /* nothing more to do */
+ return AVIERR_OK;
+ } else
+ return AVIFILE_LoadFile(This);
+}
+
+static HRESULT WINAPI IPersistFile_fnSave(IPersistFile *iface,
+ LPCOLESTR pszFileName,BOOL fRemember)
+{
+ TRACE("(%p,%s,%d)\n", iface, debugstr_w(pszFileName), fRemember);
+
+ /* We write directly to disk, so nothing to do. */
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IPersistFile_fnSaveCompleted(IPersistFile *iface,
+ LPCOLESTR pszFileName)
+{
+ TRACE("(%p,%s)\n", iface, debugstr_w(pszFileName));
+
+ /* We write directly to disk, so nothing to do. */
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IPersistFile_fnGetCurFile(IPersistFile *iface,
+ LPOLESTR *ppszFileName)
+{
+ IPersistFileImpl *This = (IPersistFileImpl *)iface;
+
+ TRACE("(%p,%p)\n", iface, ppszFileName);
+
+ if (ppszFileName == NULL)
+ return AVIERR_BADPARAM;
+
+ *ppszFileName = NULL;
+
+ assert(This->paf != NULL);
+
+ if (This->paf->szFileName != NULL) {
+ int len = lstrlenW(This->paf->szFileName) + 1;
+
+ *ppszFileName = GlobalAllocPtr(GHND, len * sizeof(WCHAR));
+ if (*ppszFileName == NULL)
+ return AVIERR_MEMORY;
+
+ strcpyW(*ppszFileName, This->paf->szFileName);
+ }
+
+ return AVIERR_OK;
+}
+
+/***********************************************************************/
+
+static HRESULT WINAPI IAVIStream_fnQueryInterface(IAVIStream *iface,
+ REFIID refiid, LPVOID *obj)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ assert(This->paf != NULL);
+
+ return IAVIFile_QueryInterface((PAVIFILE)This->paf, refiid, obj);
+}
+
+static ULONG WINAPI IAVIStream_fnAddRef(IAVIStream *iface)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ assert(This->paf != NULL);
+
+ return IAVIFile_AddRef((PAVIFILE)This->paf);
+}
+
+static ULONG WINAPI IAVIStream_fnRelease(IAVIStream* iface)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ assert(This->paf != NULL);
+
+ return IAVIFile_Release((PAVIFILE)This->paf);
+}
+
+static HRESULT WINAPI IAVIStream_fnCreate(IAVIStream *iface, LPARAM lParam1,
+ LPARAM lParam2)
+{
+ TRACE("(%p,0x%08lX,0x%08lX)\n", iface, lParam1, lParam2);
+
+ /* This IAVIStream interface needs an WAVFile */
+ return AVIERR_UNSUPPORTED;
+}
+
+static HRESULT WINAPI IAVIStream_fnInfo(IAVIStream *iface,LPAVISTREAMINFOW psi,
+ LONG size)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%p,%ld)\n", iface, psi, size);
+
+ if (psi == NULL)
+ return AVIERR_BADPARAM;
+ if (size < 0)
+ return AVIERR_BADSIZE;
+
+ memcpy(psi, &This->paf->sInfo, min((DWORD)size, sizeof(This->paf->sInfo)));
+
+ if ((DWORD)size < sizeof(This->paf->sInfo))
+ return AVIERR_BUFFERTOOSMALL;
+ return AVIERR_OK;
+}
+
+static LONG WINAPI IAVIStream_fnFindSample(IAVIStream *iface, LONG pos,
+ LONG flags)
+{
+ IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
+
+ TRACE("(%p,%ld,0x%08lX)\n",iface,pos,flags);
+
+ /* Do we have data? */
+ if (This->lpFormat == NULL)
+ return -1;
+
+ /* We don't have an index */
+ if (flags & FIND_INDEX)
+ return -1;
+
+ if (flags & FIND_FROM_START) {
+ pos = This->sInfo.dwStart;
+ flags &= ~(FIND_FROM_START|FIND_PREV);
+ flags |= FIND_NEXT;
+ }
+
+ if (flags & FIND_FORMAT) {
+ if ((flags & FIND_NEXT) && pos > 0)
+ pos = -1;
+ else
+ pos = 0;
+ }
+
+ if ((flags & FIND_RET) == FIND_LENGTH ||
+ (flags & FIND_RET) == FIND_SIZE)
+ return This->sInfo.dwSampleSize;
+ if ((flags & FIND_RET) == FIND_OFFSET)
+ return This->ckData.dwDataOffset + pos * This->sInfo.dwSampleSize;
+
+ return pos;
+}
+
+static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream *iface, LONG pos,
+ LPVOID format, LONG *formatsize)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ TRACE("(%p,%ld,%p,%p)\n", iface, pos, format, formatsize);
+
+ if (formatsize == NULL)
+ return AVIERR_BADPARAM;
+
+ /* only interested in needed buffersize? */
+ if (format == NULL || *formatsize <= 0) {
+ *formatsize = This->paf->cbFormat;
+
+ return AVIERR_OK;
+ }
+
+ /* copy initial format (only as much as will fit) */
+ memcpy(format, This->paf->lpFormat, min(*formatsize, This->paf->cbFormat));
+ if (*formatsize < This->paf->cbFormat) {
+ *formatsize = This->paf->cbFormat;
+ return AVIERR_BUFFERTOOSMALL;
+ }
+
+ *formatsize = This->paf->cbFormat;
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream *iface, LONG pos,
+ LPVOID format, LONG formatsize)
+{
+ IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
+
+ TRACE("(%p,%ld,%p,%ld)\n", iface, pos, format, formatsize);
+
+ /* check parameters */
+ if (format == NULL || formatsize <= sizeof(PCMWAVEFORMAT))
+ return AVIERR_BADPARAM;
+
+ /* We can only do this to an empty wave file, but ignore call
+ * if still same format */
+ if (This->lpFormat != NULL) {
+ if (formatsize != This->cbFormat ||
+ memcmp(format, This->lpFormat, formatsize) != 0)
+ return AVIERR_UNSUPPORTED;
+
+ return AVIERR_OK;
+ }
+
+ /* only support start at position 0 */
+ if (pos != 0)
+ return AVIERR_UNSUPPORTED;
+
+ /* Do we have write permission? */
+ if ((This->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ /* get memory for format and copy it */
+ This->lpFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GMEM_MOVEABLE, formatsize);
+ if (This->lpFormat == NULL)
+ return AVIERR_MEMORY;
+
+ This->cbFormat = formatsize;
+ memcpy(This->lpFormat, format, formatsize);
+
+ /* update info's about 'data' chunk */
+ This->ckData.dwDataOffset = formatsize + 7 * sizeof(DWORD);
+ This->ckData.cksize = 0;
+
+ /* for non-pcm format we need also a 'fact' chunk */
+ if (This->lpFormat->wFormatTag != WAVE_FORMAT_PCM)
+ This->ckData.dwDataOffset += 3 * sizeof(DWORD);
+
+ /* update stream and file info */
+ This->sInfo.dwSampleSize = This->lpFormat->nBlockAlign;
+ This->sInfo.dwScale = This->lpFormat->nBlockAlign;
+ This->sInfo.dwRate = This->lpFormat->nAvgBytesPerSec;
+ This->sInfo.dwLength = 0;
+ This->sInfo.dwSuggestedBufferSize = 0;
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnRead(IAVIStream *iface, LONG start,
+ LONG samples, LPVOID buffer,
+ LONG buffersize, LPLONG bytesread,
+ LPLONG samplesread)
+{
+ IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
+
+ TRACE("(%p,%ld,%ld,%p,%ld,%p,%p)\n", iface, start, samples, buffer,
+ buffersize, bytesread, samplesread);
+
+ /* clear return parameters if given */
+ if (bytesread != NULL)
+ *bytesread = 0;
+ if (samplesread != NULL)
+ *samplesread = 0;
+
+ /* positions without data */
+ if (start < 0 || (DWORD)start > This->sInfo.dwLength)
+ return AVIERR_OK;
+
+ /* check samples */
+ if (samples < 0)
+ samples = 0;
+ if (buffersize > 0) {
+ if (samples > 0)
+ samples = min((DWORD)samples, buffersize / This->sInfo.dwSampleSize);
+ else
+ samples = buffersize / This->sInfo.dwSampleSize;
+ }
+
+ /* limit to end of stream */
+ if ((DWORD)(start + samples) > This->sInfo.dwLength)
+ samples = This->sInfo.dwLength - start;
+
+ /* request only the sizes? */
+ if (buffer == NULL || buffersize <= 0) {
+ /* then I need at least one parameter for it */
+ if (bytesread == NULL && samplesread == NULL)
+ return AVIERR_BADPARAM;
+
+ if (bytesread != NULL)
+ *bytesread = samples * This->sInfo.dwSampleSize;
+ if (samplesread != NULL)
+ *samplesread = samples;
+
+ return AVIERR_OK;
+ }
+
+ /* nothing to read? */
+ if (samples == 0)
+ return AVIERR_OK;
+
+ /* Can I read at least one sample? */
+ if ((DWORD)buffersize < This->sInfo.dwSampleSize)
+ return AVIERR_BUFFERTOOSMALL;
+
+ buffersize = samples * This->sInfo.dwSampleSize;
+
+ if (mmioSeek(This->hmmio, This->ckData.dwDataOffset
+ + start * This->sInfo.dwSampleSize, SEEK_SET) == -1)
+ return AVIERR_FILEREAD;
+ if (mmioRead(This->hmmio, (HPSTR)buffer, buffersize) != buffersize)
+ return AVIERR_FILEREAD;
+
+ /* fill out return parameters if given */
+ if (bytesread != NULL)
+ *bytesread = buffersize;
+ if (samplesread != NULL)
+ *samplesread = samples;
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream *iface, LONG start,
+ LONG samples, LPVOID buffer,
+ LONG buffersize, DWORD flags,
+ LPLONG sampwritten,
+ LPLONG byteswritten)
+{
+ IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
+
+ TRACE("(%p,%ld,%ld,%p,%ld,0x%08lX,%p,%p)\n", iface, start, samples,
+ buffer, buffersize, flags, sampwritten, byteswritten);
+
+ /* clear return parameters if given */
+ if (sampwritten != NULL)
+ *sampwritten = 0;
+ if (byteswritten != NULL)
+ *byteswritten = 0;
+
+ /* check parameters */
+ if (buffer == NULL && (buffersize > 0 || samples > 0))
+ return AVIERR_BADPARAM;
+
+ /* Do we have write permission? */
+ if ((This->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ /* < 0 means "append" */
+ if (start < 0)
+ start = This->sInfo.dwStart + This->sInfo.dwLength;
+
+ /* check buffersize -- must multiple of samplesize */
+ if (buffersize & ~(This->sInfo.dwSampleSize - 1))
+ return AVIERR_BADSIZE;
+
+ /* do we have anything to write? */
+ if (buffer != NULL && buffersize > 0) {
+ This->fDirty = 1;
+
+ if (mmioSeek(This->hmmio, This->ckData.dwDataOffset +
+ start * This->sInfo.dwSampleSize, SEEK_SET) == -1)
+ return AVIERR_FILEWRITE;
+ if (mmioWrite(This->hmmio, (HPSTR)buffer, buffersize) != buffersize)
+ return AVIERR_FILEWRITE;
+
+ This->sInfo.dwLength = max(This->sInfo.dwLength, (DWORD)start + samples);
+ This->ckData.cksize = max(This->ckData.cksize,
+ start * This->sInfo.dwSampleSize + buffersize);
+
+ /* fill out return parameters if given */
+ if (sampwritten != NULL)
+ *sampwritten = samples;
+ if (byteswritten != NULL)
+ *byteswritten = buffersize;
+ }
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream *iface, LONG start,
+ LONG samples)
+{
+ IAVIFileImpl *This = ((IAVIStreamImpl*)iface)->paf;
+
+ TRACE("(%p,%ld,%ld)\n", iface, start, samples);
+
+ /* check parameters */
+ if (start < 0 || samples < 0)
+ return AVIERR_BADPARAM;
+
+ /* Delete before start of stream? */
+ if ((DWORD)(start + samples) < This->sInfo.dwStart)
+ return AVIERR_OK;
+
+ /* Delete after end of stream? */
+ if ((DWORD)start > This->sInfo.dwLength)
+ return AVIERR_OK;
+
+ /* For the rest we need write permissions */
+ if ((This->uMode & MMIO_RWMODE) == 0)
+ return AVIERR_READONLY;
+
+ if ((DWORD)(start + samples) >= This->sInfo.dwLength) {
+ /* deletion at end */
+ samples = This->sInfo.dwLength - start;
+ This->sInfo.dwLength -= samples;
+ This->ckData.cksize -= samples * This->sInfo.dwSampleSize;
+ } else if ((DWORD)start <= This->sInfo.dwStart) {
+ /* deletion at start */
+ samples = This->sInfo.dwStart - start;
+ start = This->sInfo.dwStart;
+ This->ckData.dwDataOffset += samples * This->sInfo.dwSampleSize;
+ This->ckData.cksize -= samples * This->sInfo.dwSampleSize;
+ } else {
+ /* deletion inside stream -- needs playlist and cue's */
+ FIXME(": deletion inside of stream not supported!\n");
+
+ return AVIERR_UNSUPPORTED;
+ }
+
+ This->fDirty = 1;
+
+ return AVIERR_OK;
+}
+
+static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream *iface, DWORD fcc,
+ LPVOID lp, LPLONG lpread)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ assert(This->paf != NULL);
+
+ return IAVIFile_ReadData((PAVIFILE)This->paf, fcc, lp, lpread);
+}
+
+static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc,
+ LPVOID lp, LONG size)
+{
+ IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
+
+ return IAVIFile_WriteData((PAVIFILE)This->paf, fcc, lp, size);
+}
+
+static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream *iface,
+ LPAVISTREAMINFOW info, LONG infolen)
+{
+ FIXME("(%p,%p,%ld): stub\n", iface, info, infolen);
+
+ return E_FAIL;
+}
+
+/***********************************************************************/
+
+static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This)
+{
+ MMCKINFO ckRIFF;
+ MMCKINFO ck;
+
+ This->sInfo.dwLength = 0; /* just to be sure */
+ This->fDirty = FALSE;
+
+ /* search for RIFF chunk */
+ ckRIFF.fccType = 0; /* find any */
+ if (mmioDescend(This->hmmio, &ckRIFF, NULL, MMIO_FINDRIFF) != S_OK) {
+ return AVIFILE_LoadSunFile(This);
+ }
+
+ if (ckRIFF.fccType != formtypeWAVE)
+ return AVIERR_BADFORMAT;
+
+ /* search WAVE format chunk */
+ ck.ckid = ckidWAVEFORMAT;
+ if (FindChunkAndKeepExtras(&This->extra, This->hmmio, &ck,
+ &ckRIFF, MMIO_FINDCHUNK) != S_OK)
+ return AVIERR_FILEREAD;
+
+ /* get memory for format and read it */
+ This->lpFormat = (LPWAVEFORMATEX)GlobalAllocPtr(GMEM_MOVEABLE, ck.cksize);
+ if (This->lpFormat == NULL)
+ return AVIERR_FILEREAD;
+ This->cbFormat = ck.cksize;
+
+ if (mmioRead(This->hmmio, (HPSTR)This->lpFormat, ck.cksize) != ck.cksize)
+ return AVIERR_FILEREAD;
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEREAD;
+
+ /* Non-pcm formats have a fact chunk.
+ * We don't need it, so simply add it to the extra chunks.
+ */
+
+ /* find the big data chunk */
+ This->ckData.ckid = ckidWAVEDATA;
+ if (FindChunkAndKeepExtras(&This->extra, This->hmmio, &This->ckData,
+ &ckRIFF, MMIO_FINDCHUNK) != S_OK)
+ return AVIERR_FILEREAD;
+
+ memset(&This->sInfo, 0, sizeof(This->sInfo));
+ This->sInfo.fccType = streamtypeAUDIO;
+ This->sInfo.dwRate = This->lpFormat->nAvgBytesPerSec;
+ This->sInfo.dwSampleSize =
+ This->sInfo.dwScale = This->lpFormat->nBlockAlign;
+ This->sInfo.dwLength = This->ckData.cksize / This->lpFormat->nBlockAlign;
+ This->sInfo.dwSuggestedBufferSize = This->ckData.cksize;
+
+ This->fInfo.dwStreams = 1;
+
+ if (mmioAscend(This->hmmio, &This->ckData, 0) != S_OK) {
+ /* seems to be truncated */
+ WARN(": file seems to be truncated!\n");
+ This->ckData.cksize = mmioSeek(This->hmmio, 0, SEEK_END) -
+ This->ckData.dwDataOffset;
+ This->sInfo.dwLength = This->ckData.cksize / This->lpFormat->nBlockAlign;
+ This->sInfo.dwSuggestedBufferSize = This->ckData.cksize;
+ }
+
+ /* ignore errors */
+ FindChunkAndKeepExtras(&This->extra, This->hmmio, &ck, &ckRIFF, 0);
+
+ return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_LoadSunFile(IAVIFileImpl *This)
+{
+ SUNAUDIOHEADER auhdr;
+
+ mmioSeek(This->hmmio, 0, SEEK_SET);
+ if (mmioRead(This->hmmio, (HPSTR)&auhdr, sizeof(auhdr)) != sizeof(auhdr))
+ return AVIERR_FILEREAD;
+
+ if (auhdr.fccType == 0x0064732E) {
+ /* header in little endian */
+ This->ckData.dwDataOffset = LE2H_DWORD(auhdr.offset);
+ This->ckData.cksize = LE2H_DWORD(auhdr.size);
+
+ auhdr.encoding = LE2H_DWORD(auhdr.encoding);
+ auhdr.sampleRate = LE2H_DWORD(auhdr.sampleRate);
+ auhdr.channels = LE2H_DWORD(auhdr.channels);
+ } else if (auhdr.fccType == mmioFOURCC('.','s','n','d')) {
+ /* header in big endian */
+ This->ckData.dwDataOffset = BE2H_DWORD(auhdr.offset);
+ This->ckData.cksize = BE2H_DWORD(auhdr.size);
+
+ auhdr.encoding = BE2H_DWORD(auhdr.encoding);
+ auhdr.sampleRate = BE2H_DWORD(auhdr.sampleRate);
+ auhdr.channels = BE2H_DWORD(auhdr.channels);
+ } else
+ return AVIERR_FILEREAD;
+
+ if (auhdr.channels < 1)
+ return AVIERR_BADFORMAT;
+
+ /* get size of header */
+ switch(auhdr.encoding) {
+ case AU_ENCODING_ADPCM_G721_32:
+ This->cbFormat = sizeof(G721_ADPCMWAVEFORMAT); break;
+ case AU_ENCODING_ADPCM_G723_24:
+ This->cbFormat = sizeof(G723_ADPCMWAVEFORMAT); break;
+ case AU_ENCODING_ADPCM_G722:
+ case AU_ENCODING_ADPCM_G723_5:
+ WARN("unsupported Sun audio format %d\n", auhdr.encoding);
+ return AVIERR_UNSUPPORTED; /* FIXME */
+ default:
+ This->cbFormat = sizeof(WAVEFORMATEX); break;
+ };
+
+ This->lpFormat =
+ (LPWAVEFORMATEX)GlobalAllocPtr(GMEM_MOVEABLE, This->cbFormat);
+ if (This->lpFormat == NULL)
+ return AVIERR_MEMORY;
+
+ This->lpFormat->nChannels = auhdr.channels;
+ This->lpFormat->nSamplesPerSec = auhdr.sampleRate;
+ switch(auhdr.encoding) {
+ case AU_ENCODING_ULAW_8:
+ This->lpFormat->wFormatTag = WAVE_FORMAT_MULAW;
+ This->lpFormat->wBitsPerSample = 8;
+ break;
+ case AU_ENCODING_PCM_8:
+ This->lpFormat->wFormatTag = WAVE_FORMAT_PCM;
+ This->lpFormat->wBitsPerSample = 8;
+ break;
+ case AU_ENCODING_PCM_16:
+ This->lpFormat->wFormatTag = WAVE_FORMAT_PCM;
+ This->lpFormat->wBitsPerSample = 16;
+ break;
+ case AU_ENCODING_PCM_24:
+ This->lpFormat->wFormatTag = WAVE_FORMAT_PCM;
+ This->lpFormat->wBitsPerSample = 24;
+ break;
+ case AU_ENCODING_PCM_32:
+ This->lpFormat->wFormatTag = WAVE_FORMAT_PCM;
+ This->lpFormat->wBitsPerSample = 32;
+ break;
+ case AU_ENCODING_ALAW_8:
+ This->lpFormat->wFormatTag = WAVE_FORMAT_ALAW;
+ This->lpFormat->wBitsPerSample = 8;
+ break;
+ case AU_ENCODING_ADPCM_G721_32:
+ This->lpFormat->wFormatTag = WAVE_FORMAT_G721_ADPCM;
+ This->lpFormat->wBitsPerSample = (3*5*8);
+ This->lpFormat->nBlockAlign = 15*15*8;
+ This->lpFormat->cbSize = sizeof(WORD);
+ ((LPG721_ADPCMWAVEFORMAT)This->lpFormat)->nAuxBlockSize = 0;
+ break;
+ case AU_ENCODING_ADPCM_G723_24:
+ This->lpFormat->wFormatTag = WAVE_FORMAT_G723_ADPCM;
+ This->lpFormat->wBitsPerSample = (3*5*8);
+ This->lpFormat->nBlockAlign = 15*15*8;
+ This->lpFormat->cbSize = 2*sizeof(WORD);
+ ((LPG723_ADPCMWAVEFORMAT)This->lpFormat)->cbExtraSize = 0;
+ ((LPG723_ADPCMWAVEFORMAT)This->lpFormat)->nAuxBlockSize = 0;
+ break;
+ default:
+ WARN("unsupported Sun audio format %d\n", auhdr.encoding);
+ return AVIERR_UNSUPPORTED;
+ };
+
+ This->lpFormat->nBlockAlign =
+ (This->lpFormat->nChannels * This->lpFormat->wBitsPerSample) / 8;
+ if (This->lpFormat->nBlockAlign == 0 && This->lpFormat->wBitsPerSample < 8)
+ This->lpFormat->nBlockAlign++;
+ This->lpFormat->nAvgBytesPerSec =
+ This->lpFormat->nBlockAlign * This->lpFormat->nSamplesPerSec;
+
+ This->fDirty = 0;
+
+ This->sInfo.fccType = streamtypeAUDIO;
+ This->sInfo.fccHandler = 0;
+ This->sInfo.dwFlags = 0;
+ This->sInfo.wPriority = 0;
+ This->sInfo.wLanguage = 0;
+ This->sInfo.dwInitialFrames = 0;
+ This->sInfo.dwScale = This->lpFormat->nBlockAlign;
+ This->sInfo.dwRate = This->lpFormat->nAvgBytesPerSec;
+ This->sInfo.dwStart = 0;
+ This->sInfo.dwLength =
+ This->ckData.cksize / This->lpFormat->nBlockAlign;
+ This->sInfo.dwSuggestedBufferSize = This->sInfo.dwLength;
+ This->sInfo.dwSampleSize = This->lpFormat->nBlockAlign;
+
+ This->fInfo.dwStreams = 1;
+ This->fInfo.dwScale = 1;
+ This->fInfo.dwRate = This->lpFormat->nSamplesPerSec;
+ This->fInfo.dwLength =
+ MulDiv(This->ckData.cksize, This->lpFormat->nSamplesPerSec,
+ This->lpFormat->nAvgBytesPerSec);
+
+ return AVIERR_OK;
+}
+
+static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This)
+{
+ MMCKINFO ckRIFF;
+ MMCKINFO ck;
+
+ mmioSeek(This->hmmio, 0, SEEK_SET);
+
+ /* create the RIFF chunk with formtype WAVE */
+ ckRIFF.fccType = formtypeWAVE;
+ ckRIFF.cksize = 0;
+ if (mmioCreateChunk(This->hmmio, &ckRIFF, MMIO_CREATERIFF) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* the next chunk is the format */
+ ck.ckid = ckidWAVEFORMAT;
+ ck.cksize = This->cbFormat;
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (This->lpFormat != NULL && This->cbFormat > 0) {
+ if (mmioWrite(This->hmmio, (HPSTR)This->lpFormat, ck.cksize) != ck.cksize)
+ return AVIERR_FILEWRITE;
+ }
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* fact chunk is needed for non-pcm waveforms */
+ if (This->lpFormat != NULL && This->cbFormat > sizeof(PCMWAVEFORMAT) &&
+ This->lpFormat->wFormatTag != WAVE_FORMAT_PCM) {
+ WAVEFORMATEX wfx;
+ DWORD dwFactLength;
+ HACMSTREAM has;
+
+ /* try to open an appropriate audio codec to figure out
+ * data for fact-chunk */
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ if (acmFormatSuggest(NULL, This->lpFormat, &wfx,
+ sizeof(wfx), ACM_FORMATSUGGESTF_WFORMATTAG)) {
+ acmStreamOpen(&has, NULL, This->lpFormat, &wfx, NULL,
+ 0, 0, ACM_STREAMOPENF_NONREALTIME);
+ acmStreamSize(has, This->ckData.cksize, &dwFactLength,
+ ACM_STREAMSIZEF_SOURCE);
+ dwFactLength /= wfx.nBlockAlign;
+ acmStreamClose(has, 0);
+
+ /* create the fact chunk */
+ ck.ckid = ckidWAVEFACT;
+ ck.cksize = sizeof(dwFactLength);
+
+ /* test for enough space before data chunk */
+ if (mmioSeek(This->hmmio, 0, SEEK_CUR) > This->ckData.dwDataOffset
+ - ck.cksize - 4 * sizeof(DWORD))
+ return AVIERR_FILEWRITE;
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (mmioWrite(This->hmmio, (HPSTR)&dwFactLength, ck.cksize) != ck.cksize)
+ return AVIERR_FILEWRITE;
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ } else
+ ERR(": fact chunk is needed for non-pcm files -- currently no codec found, so skipped!\n");
+ }
+
+ /* if there was extra stuff, we need to fill it with JUNK */
+ if (mmioSeek(This->hmmio, 0, SEEK_CUR) + 2 * sizeof(DWORD) < This->ckData.dwDataOffset) {
+ ck.ckid = ckidAVIPADDING;
+ ck.cksize = 0;
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ if (mmioSeek(This->hmmio, This->ckData.dwDataOffset
+ - 2 * sizeof(DWORD), SEEK_SET) == -1)
+ return AVIERR_FILEWRITE;
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ }
+
+ /* create the data chunk */
+ ck.ckid = ckidWAVEDATA;
+ ck.cksize = This->ckData.cksize;
+ if (mmioCreateChunk(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (mmioSeek(This->hmmio, This->ckData.cksize, SEEK_CUR) == -1)
+ return AVIERR_FILEWRITE;
+ if (mmioAscend(This->hmmio, &ck, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ /* some optional extra chunks? */
+ if (This->extra.lp != NULL && This->extra.cb > 0) {
+ /* chunk headers are already in structure */
+ if (mmioWrite(This->hmmio, This->extra.lp, This->extra.cb) != This->extra.cb)
+ return AVIERR_FILEWRITE;
+ }
+
+ /* close RIFF chunk */
+ if (mmioAscend(This->hmmio, &ckRIFF, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+ if (mmioFlush(This->hmmio, 0) != S_OK)
+ return AVIERR_FILEWRITE;
+
+ return AVIERR_OK;
+}
<directory name="authz">
<xi:include href="authz/authz.xml" />
</directory>
+<directory name="avifil32">
+ <xi:include href="avifil32/avifil32.xml" />
+</directory>
<directory name="cabinet">
<xi:include href="cabinet/cabinet.xml" />
</directory>