📄 acmstream.c
字号:
/*
* Copyright 2002 Michael G黱newig
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#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 "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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IAVIStreamImpl));
if (pstream == NULL)
return AVIERR_MEMORY;
pstream->lpVtbl = &iacmst;
hr = IAVIStream_QueryInterface((IAVIStream*)pstream, riid, ppv);
if (FAILED(hr))
HeapFree(GetProcessHeap(), 0, 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) -> %d\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) -> %d\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;
}
HeapFree(GetProcessHeap(), 0, This->acmStreamHdr.pbSrc);
This->acmStreamHdr.pbSrc = NULL;
HeapFree(GetProcessHeap(), 0, This->acmStreamHdr.pbDst);
This->acmStreamHdr.pbDst = NULL;
if (This->lpInFormat != NULL) {
HeapFree(GetProcessHeap(), 0, This->lpInFormat);
This->lpInFormat = NULL;
This->cbInFormat = 0;
}
if (This->lpOutFormat != NULL) {
HeapFree(GetProcessHeap(), 0, This->lpOutFormat);
This->lpOutFormat = NULL;
This->cbOutFormat = 0;
}
if (This->pStream != NULL) {
IAVIStream_Release(This->pStream);
This->pStream = NULL;
}
HeapFree(GetProcessHeap(), 0, 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 = HeapAlloc(GetProcessHeap(), 0, 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,%d)\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,%d,0x%08X)\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,%d,%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,%d,%p,%d)\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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -