Commit c783c202 authored by Michael Günnewig's avatar Michael Günnewig Committed by Alexandre Julliard

- Fixed memory leak in AVISaveOptions.

- Implemented AVISaveVW method. - Semi-stub implementation for CreateEditableStream method. - Added support for creation of interleaved AVI files. - Fixed creation of index table in AVI files. - Added declaration for IAVIStreaming interface. - Added some more macros. - Fixed some minor bugs.
parent 9a9fcd1a
/* /*
* Copyright 1999 Marcus Meissner * Copyright 1999 Marcus Meissner
* Copyright 2002 Michael Gnnewig * Copyright 2002-2003 Michael Gnnewig
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
...@@ -18,12 +18,16 @@ ...@@ -18,12 +18,16 @@
*/ */
/* TODO: /* TODO:
* - IAVIFile_fnEndRecord: a stub -- needed for creating interleaved AVIs.
* - IAVIStreaming interface is missing for the IAVIStreamImpl * - IAVIStreaming interface is missing for the IAVIStreamImpl
* - IAVIStream_fnFindSample: FIND_INDEX isn't supported. * - IAVIStream_fnFindSample: FIND_INDEX isn't supported.
* - IAVIStream_fnReadFormat: formatchanges aren't read in. * - IAVIStream_fnReadFormat: formatchanges aren't read in.
* - IAVIStream_fnDelete: a stub. * - IAVIStream_fnDelete: a stub.
* - IAVIStream_fnSetInfo: 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 #define COM_NO_WINDOWS_H
...@@ -186,9 +190,12 @@ struct _IAVIFileImpl { ...@@ -186,9 +190,12 @@ struct _IAVIFileImpl {
DWORD dwMoviChunkPos; /* some stuff for saving ... */ DWORD dwMoviChunkPos; /* some stuff for saving ... */
DWORD dwIdxChunkPos; DWORD dwIdxChunkPos;
DWORD dwNextFramePos; DWORD dwNextFramePos;
DWORD dwInitialFrames;
MMCKINFO ckLastRecord;
AVIINDEXENTRY *idxRecords; /* won't be updated while loading */ AVIINDEXENTRY *idxRecords; /* won't be updated while loading */
DWORD nIdxRecords; DWORD nIdxRecords; /* current fill level */
DWORD cbIdxRecords; /* size of idxRecords */
/* IPersistFile stuff ... */ /* IPersistFile stuff ... */
HMMIO hmmio; HMMIO hmmio;
...@@ -201,6 +208,7 @@ struct _IAVIFileImpl { ...@@ -201,6 +208,7 @@ struct _IAVIFileImpl {
static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size, static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size,
DWORD offset, DWORD flags); DWORD offset, DWORD flags);
static HRESULT AVIFILE_AddRecord(IAVIFileImpl *This);
static DWORD AVIFILE_ComputeMoviStart(IAVIFileImpl *This); static DWORD AVIFILE_ComputeMoviStart(IAVIFileImpl *This);
static void AVIFILE_ConstructAVIStream(IAVIFileImpl *paf, DWORD nr, static void AVIFILE_ConstructAVIStream(IAVIFileImpl *paf, DWORD nr,
LPAVISTREAMINFOW asi); LPAVISTREAMINFOW asi);
...@@ -468,16 +476,41 @@ static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface) ...@@ -468,16 +476,41 @@ static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface)
{ {
ICOM_THIS(IAVIFileImpl,iface); ICOM_THIS(IAVIFileImpl,iface);
FIXME("(%p): stub\n",iface); TRACE("(%p)\n",iface);
if ((This->uMode & MMIO_RWMODE) == 0) if ((This->uMode & MMIO_RWMODE) == 0)
return AVIERR_READONLY; return AVIERR_READONLY;
This->fDirty = TRUE; This->fDirty = TRUE;
/* FIXME: end record -- for interleaved files */ /* no frames written to any stream? -- compute start of 'movi'-chunk */
if (This->dwMoviChunkPos == 0)
AVIFILE_ComputeMoviStart(This);
return E_FAIL; 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, static HRESULT WINAPI IAVIFile_fnDeleteStream(IAVIFile *iface, DWORD fccType,
...@@ -1273,7 +1306,7 @@ static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc, ...@@ -1273,7 +1306,7 @@ static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc,
/* ckid,size => 2 * sizeof(DWORD) */ /* ckid,size => 2 * sizeof(DWORD) */
dwPos += 2 * sizeof(DWORD) + size; dwPos += 2 * sizeof(DWORD) + size;
if (size >= This->paf->dwMoviChunkPos) if (size >= This->paf->dwMoviChunkPos - 2 * sizeof(DWORD))
return AVIERR_UNSUPPORTED; /* not enough space left */ return AVIERR_UNSUPPORTED; /* not enough space left */
} }
...@@ -1375,8 +1408,33 @@ static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size, DW ...@@ -1375,8 +1408,33 @@ static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size, DW
This->idxFrames[This->lLastFrame].dwChunkLength = size; This->idxFrames[This->lLastFrame].dwChunkLength = size;
/* update AVISTREAMINFO structure if necessary */ /* update AVISTREAMINFO structure if necessary */
if (This->sInfo.dwLength < This->lLastFrame) if (This->sInfo.dwLength <= This->lLastFrame)
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; return AVIERR_OK;
} }
...@@ -1751,7 +1809,7 @@ static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This) ...@@ -1751,7 +1809,7 @@ static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This)
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
This->dwMoviChunkPos = ckLIST1.dwDataOffset - 2 * sizeof(DWORD); This->dwMoviChunkPos = ckLIST1.dwDataOffset;
This->dwIdxChunkPos = ckLIST1.cksize + ckLIST1.dwDataOffset; This->dwIdxChunkPos = ckLIST1.cksize + ckLIST1.dwDataOffset;
if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK) if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
return AVIERR_FILEREAD; return AVIERR_FILEREAD;
...@@ -1874,6 +1932,15 @@ static HRESULT AVIFILE_LoadIndex(IAVIFileImpl *This, DWORD size, DWORD offset) ...@@ -1874,6 +1932,15 @@ static HRESULT AVIFILE_LoadIndex(IAVIFileImpl *This, DWORD size, DWORD offset)
if (lp != NULL) if (lp != NULL)
GlobalFreePtr(lp); GlobalFreePtr(lp);
/* checking ... */
for (n = 0; n < This->fInfo.dwStreams; n++) {
IAVIStreamImpl *pStream = This->ppStreams[n];
if (pStream->sInfo.dwLength != pStream->lLastFrame+1)
ERR("stream %lu length mismatch: dwLength=%lu found=%ld\n",
n, pStream->sInfo.dwLength, pStream->lLastFrame);
}
return hr; return hr;
} }
...@@ -2005,6 +2072,13 @@ static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This) ...@@ -2005,6 +2072,13 @@ static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This)
if (This->dwMoviChunkPos == 0) if (This->dwMoviChunkPos == 0)
AVIFILE_ComputeMoviStart(This); 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); AVIFILE_UpdateInfo(This);
assert(This->fInfo.dwScale != 0); assert(This->fInfo.dwScale != 0);
...@@ -2021,12 +2095,7 @@ static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This) ...@@ -2021,12 +2095,7 @@ static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This)
MainAVIHdr.dwSuggestedBufferSize = This->fInfo.dwSuggestedBufferSize; MainAVIHdr.dwSuggestedBufferSize = This->fInfo.dwSuggestedBufferSize;
MainAVIHdr.dwWidth = This->fInfo.dwWidth; MainAVIHdr.dwWidth = This->fInfo.dwWidth;
MainAVIHdr.dwHeight = This->fInfo.dwHeight; MainAVIHdr.dwHeight = This->fInfo.dwHeight;
for (nStream = 0; nStream < MainAVIHdr.dwStreams; nStream++) { MainAVIHdr.dwInitialFrames = This->dwInitialFrames;
pStream = This->ppStreams[nStream];
if (MainAVIHdr.dwInitialFrames < pStream->sInfo.dwInitialFrames)
MainAVIHdr.dwInitialFrames = pStream->sInfo.dwInitialFrames;
}
/* now begin writing ... */ /* now begin writing ... */
mmioSeek(This->hmmio, 0, SEEK_SET); mmioSeek(This->hmmio, 0, SEEK_SET);
...@@ -2237,6 +2306,8 @@ static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This) ...@@ -2237,6 +2306,8 @@ static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This)
else else
stepsize = AVIStreamTimeToSample((PAVISTREAM)This->ppStreams[0], 1000000); stepsize = AVIStreamTimeToSample((PAVISTREAM)This->ppStreams[0], 1000000);
assert(stepsize > 0);
for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) { for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
if (lInitialFrames < This->ppStreams[nStream]->sInfo.dwInitialFrames) if (lInitialFrames < This->ppStreams[nStream]->sInfo.dwInitialFrames)
lInitialFrames = This->ppStreams[nStream]->sInfo.dwInitialFrames; lInitialFrames = This->ppStreams[nStream]->sInfo.dwInitialFrames;
...@@ -2256,7 +2327,7 @@ static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This) ...@@ -2256,7 +2327,7 @@ static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This)
if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx)) if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
return AVIERR_FILEWRITE; return AVIERR_FILEWRITE;
for (nStream = 0; nStream < This->fInfo.dwStreams; n++) { for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
pStream = This->ppStreams[nStream]; pStream = This->ppStreams[nStream];
/* heave we reached start of this stream? */ /* heave we reached start of this stream? */
...@@ -2307,7 +2378,7 @@ static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This) ...@@ -2307,7 +2378,7 @@ static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This)
if (pStream->lLastFrame == -1) if (pStream->lLastFrame == -1)
pStream->lLastFrame = 0; pStream->lLastFrame = 0;
for (n = 0; n < pStream->lLastFrame; n++) { for (n = 0; n <= pStream->lLastFrame; n++) {
if ((pStream->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) && if ((pStream->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
(pStream->sInfo.dwFormatChangeCount != 0)) { (pStream->sInfo.dwFormatChangeCount != 0)) {
DWORD pos; DWORD pos;
...@@ -2387,6 +2458,7 @@ static void AVIFILE_UpdateInfo(IAVIFileImpl *This) ...@@ -2387,6 +2458,7 @@ static void AVIFILE_UpdateInfo(IAVIFileImpl *This)
This->fInfo.dwScale = 0; This->fInfo.dwScale = 0;
This->fInfo.dwRate = 0; This->fInfo.dwRate = 0;
This->fInfo.dwLength = 0; This->fInfo.dwLength = 0;
This->dwInitialFrames = 0;
for (i = 0; i < This->fInfo.dwStreams; i++) { for (i = 0; i < This->fInfo.dwStreams; i++) {
AVISTREAMINFOW *psi; AVISTREAMINFOW *psi;
...@@ -2411,6 +2483,9 @@ static void AVIFILE_UpdateInfo(IAVIFileImpl *This) ...@@ -2411,6 +2483,9 @@ static void AVIFILE_UpdateInfo(IAVIFileImpl *This)
This->fInfo.dwLength = n; This->fInfo.dwLength = n;
} }
if (This->dwInitialFrames < psi->dwInitialFrames)
This->dwInitialFrames = psi->dwInitialFrames;
if (This->fInfo.dwSuggestedBufferSize < psi->dwSuggestedBufferSize) if (This->fInfo.dwSuggestedBufferSize < psi->dwSuggestedBufferSize)
This->fInfo.dwSuggestedBufferSize = psi->dwSuggestedBufferSize; This->fInfo.dwSuggestedBufferSize = psi->dwSuggestedBufferSize;
...@@ -2463,5 +2538,6 @@ static HRESULT AVIFILE_WriteBlock(IAVIStreamImpl *This, DWORD block, ...@@ -2463,5 +2538,6 @@ static HRESULT AVIFILE_WriteBlock(IAVIStreamImpl *This, DWORD block,
This->paf->fDirty = TRUE; This->paf->fDirty = TRUE;
This->paf->dwNextFramePos = mmioSeek(This->paf->hmmio, 0, SEEK_CUR); This->paf->dwNextFramePos = mmioSeek(This->paf->hmmio, 0, SEEK_CUR);
return AVIFILE_AddFrame(This, ckid, size, ck.dwDataOffset, flags); return AVIFILE_AddFrame(This, ckid, size,
ck.dwDataOffset - 2 * sizeof(DWORD), flags);
} }
...@@ -43,6 +43,7 @@ typedef struct IAVIStream IAVIStream,*PAVISTREAM; ...@@ -43,6 +43,7 @@ typedef struct IAVIStream IAVIStream,*PAVISTREAM;
typedef struct IAVIFile IAVIFile,*PAVIFILE; typedef struct IAVIFile IAVIFile,*PAVIFILE;
typedef struct IGetFrame IGetFrame,*PGETFRAME; typedef struct IGetFrame IGetFrame,*PGETFRAME;
typedef struct IAVIEditStream IAVIEditStream, *PAVIEDITSTREAM; typedef struct IAVIEditStream IAVIEditStream, *PAVIEDITSTREAM;
typedef struct IAVIStreaming IAVIStreaming;
/* Installable Compressor Manager */ /* Installable Compressor Manager */
...@@ -1094,6 +1095,41 @@ LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime); ...@@ -1094,6 +1095,41 @@ LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime);
#define AVIStreamStartTime(pavi) \ #define AVIStreamStartTime(pavi) \
AVIStreamSampleToTime(pavi, AVIStreamStart(pavi)) AVIStreamSampleToTime(pavi, AVIStreamStart(pavi))
#define AVIStreamNextSample(pavi, pos) \
AVIStreamFindSample(pavi, pos + 1, FIND_NEXT | FIND_ANY)
#define AVIStreamPrevSample(pavi, pos) \
AVIStreamFindSample(pavi, pos - 1, FIND_PREV | FIND_ANY)
#define AVIStreamNearestSample(pavi, pos) \
AVIStreamFindSample(pavi, pos, FIND_PREV | FIND_ANY)
#define AVStreamNextKeyFrame(pavi,pos) \
AVIStreamFindSample(pavi, pos + 1, FIND_NEXT | FIND_KEY)
#define AVStreamPrevKeyFrame(pavi,pos) \
AVIStreamFindSample(pavi, pos - 1, FIND_NEXT | FIND_KEY)
#define AVIStreamNearestKeyFrame(pavi,pos) \
AVIStreamFindSample(pavi, pos, FIND_PREV | FIND_KEY)
#define AVIStreamIsKeyFrame(pavi, pos) \
(AVIStreamNearestKeyFrame(pavi, pos) == pos)
/*****************************************************************************
* IAVIStreaming interface
*/
#define INTERFACE IAVIStreaming
#define IAVIStreaming_METHODS \
IUnknown_METHODS \
STDMETHOD(Begin)(IAVIStreaming*iface,LONG lStart,LONG lEnd,LONG lRate) PURE; \
STDMETHOD(End)(IAVIStreaming*iface) PURE;
#undef INTERFACE
#ifdef COBJMACROS
/*** IUnknown methods ***/
#define IAVIStreaming_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b)
#define IAVIStreaming_AddRef(p) (p)->lpVtbl->AddRef(p)
#define IAVIStreaming_Release(p) (p)->lpVtbl->Release(p)
/*** IAVIStreaming methods ***/
#define IAVIStreaming_Begin(p,a,b,c) (p)->lpVtbl->Begin(p,a,b,c)
#define IAVIStreaming_End(p) (p)->lpVtbl->End(p)
#endif
/***************************************************************************** /*****************************************************************************
* IAVIEditStream interface * IAVIEditStream interface
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment