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 2002 Michael Gnnewig
* Copyright 2002-2003 Michael Gnnewig
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -1388,7 +1388,7 @@ INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
}
/* fall through */
case IDCANCEL:
EndDialog(hWnd, GET_WM_COMMAND_CMD(wParam, lParam) == IDOK);
EndDialog(hWnd, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
break;
case IDC_INTERLEAVE:
EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
......@@ -1450,10 +1450,12 @@ BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
ret = FALSE;
/* restore options when user pressed cancel */
if (pSavedOptions != NULL && ret == FALSE) {
for (n = 0; n < nStreams; n++) {
if (ppOptions[n] != NULL)
memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
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);
}
......@@ -1530,19 +1532,442 @@ HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
}
/***********************************************************************
* 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 nStream,
AVISAVECALLBACK lpfnCallback, int nStreams,
PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
{
FIXME("(%s,%p,%p,%d,%p,%p), stub!\n", debugstr_w(szFile), pclsidHandler,
lpfnCallback, nStream, ppavi, 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;
}
return AVIERR_UNSUPPORTED;
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 initiale size of 64 kByte */
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 atleast 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 for 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 for 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 got it, or error occures */
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 for 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 neccessary */
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;
}
/***********************************************************************
......@@ -1550,16 +1975,30 @@ HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
*/
HRESULT WINAPI CreateEditableStream(PAVISTREAM *ppEditable, PAVISTREAM pSource)
{
FIXME("(%p,%p), stub!\n", ppEditable, pSource);
IAVIEditStream *pEdit = NULL;
HRESULT hr;
FIXME("(%p,%p), semi stub!\n", ppEditable, pSource);
if (pSource == NULL)
return AVIERR_BADHANDLE;
if (ppEditable == NULL)
return AVIERR_BADPARAM;
*ppEditable = NULL;
return AVIERR_UNSUPPORTED;
if (pSource != NULL) {
hr = IAVIStream_QueryInterface(pSource, &IID_IAVIEditStream,
(LPVOID*)&pEdit);
if (FAILED(hr) || pEdit == NULL) {
/* need own implementation of IAVIEditStream */
return AVIERR_UNSUPPORTED;
}
}
hr = IAVIEditStream_Clone(pEdit, ppEditable);
IAVIEditStream_Release(pEdit);
return hr;
}
/***********************************************************************
......
/*
* Copyright 1999 Marcus Meissner
* Copyright 2002 Michael Gnnewig
* Copyright 2002-2003 Michael Gnnewig
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
......@@ -18,12 +18,16 @@
*/
/* TODO:
* - IAVIFile_fnEndRecord: a stub -- needed for creating interleaved AVIs.
* - 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
......@@ -186,9 +190,12 @@ struct _IAVIFileImpl {
DWORD dwMoviChunkPos; /* some stuff for saving ... */
DWORD dwIdxChunkPos;
DWORD dwNextFramePos;
DWORD dwInitialFrames;
MMCKINFO ckLastRecord;
AVIINDEXENTRY *idxRecords; /* won't be updated while loading */
DWORD nIdxRecords;
DWORD nIdxRecords; /* current fill level */
DWORD cbIdxRecords; /* size of idxRecords */
/* IPersistFile stuff ... */
HMMIO hmmio;
......@@ -201,6 +208,7 @@ struct _IAVIFileImpl {
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);
......@@ -468,16 +476,41 @@ static HRESULT WINAPI IAVIFile_fnEndRecord(IAVIFile *iface)
{
ICOM_THIS(IAVIFileImpl,iface);
FIXME("(%p): stub\n",iface);
TRACE("(%p)\n",iface);
if ((This->uMode & MMIO_RWMODE) == 0)
return AVIERR_READONLY;
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,
......@@ -1273,7 +1306,7 @@ static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc,
/* ckid,size => 2 * sizeof(DWORD) */
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 */
}
......@@ -1375,8 +1408,33 @@ static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size, DW
This->idxFrames[This->lLastFrame].dwChunkLength = size;
/* update AVISTREAMINFO structure if necessary */
if (This->sInfo.dwLength < This->lLastFrame)
This->sInfo.dwLength = This->lLastFrame;
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;
}
......@@ -1751,7 +1809,7 @@ static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This)
if (FAILED(hr))
return hr;
This->dwMoviChunkPos = ckLIST1.dwDataOffset - 2 * sizeof(DWORD);
This->dwMoviChunkPos = ckLIST1.dwDataOffset;
This->dwIdxChunkPos = ckLIST1.cksize + ckLIST1.dwDataOffset;
if (mmioAscend(This->hmmio, &ckLIST1, 0) != S_OK)
return AVIERR_FILEREAD;
......@@ -1874,6 +1932,15 @@ static HRESULT AVIFILE_LoadIndex(IAVIFileImpl *This, DWORD size, DWORD offset)
if (lp != NULL)
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;
}
......@@ -2005,6 +2072,13 @@ static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This)
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);
......@@ -2021,12 +2095,7 @@ static HRESULT AVIFILE_SaveFile(IAVIFileImpl *This)
MainAVIHdr.dwSuggestedBufferSize = This->fInfo.dwSuggestedBufferSize;
MainAVIHdr.dwWidth = This->fInfo.dwWidth;
MainAVIHdr.dwHeight = This->fInfo.dwHeight;
for (nStream = 0; nStream < MainAVIHdr.dwStreams; nStream++) {
pStream = This->ppStreams[nStream];
if (MainAVIHdr.dwInitialFrames < pStream->sInfo.dwInitialFrames)
MainAVIHdr.dwInitialFrames = pStream->sInfo.dwInitialFrames;
}
MainAVIHdr.dwInitialFrames = This->dwInitialFrames;
/* now begin writing ... */
mmioSeek(This->hmmio, 0, SEEK_SET);
......@@ -2237,6 +2306,8 @@ static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This)
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;
......@@ -2256,7 +2327,7 @@ static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This)
if (mmioWrite(This->hmmio, (HPSTR)&idx, sizeof(idx)) != sizeof(idx))
return AVIERR_FILEWRITE;
for (nStream = 0; nStream < This->fInfo.dwStreams; n++) {
for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
pStream = This->ppStreams[nStream];
/* heave we reached start of this stream? */
......@@ -2307,7 +2378,7 @@ static HRESULT AVIFILE_SaveIndex(IAVIFileImpl *This)
if (pStream->lLastFrame == -1)
pStream->lLastFrame = 0;
for (n = 0; n < pStream->lLastFrame; n++) {
for (n = 0; n <= pStream->lLastFrame; n++) {
if ((pStream->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
(pStream->sInfo.dwFormatChangeCount != 0)) {
DWORD pos;
......@@ -2387,6 +2458,7 @@ static void AVIFILE_UpdateInfo(IAVIFileImpl *This)
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;
......@@ -2411,6 +2483,9 @@ static void AVIFILE_UpdateInfo(IAVIFileImpl *This)
This->fInfo.dwLength = n;
}
if (This->dwInitialFrames < psi->dwInitialFrames)
This->dwInitialFrames = psi->dwInitialFrames;
if (This->fInfo.dwSuggestedBufferSize < psi->dwSuggestedBufferSize)
This->fInfo.dwSuggestedBufferSize = psi->dwSuggestedBufferSize;
......@@ -2463,5 +2538,6 @@ static HRESULT AVIFILE_WriteBlock(IAVIStreamImpl *This, DWORD block,
This->paf->fDirty = TRUE;
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;
typedef struct IAVIFile IAVIFile,*PAVIFILE;
typedef struct IGetFrame IGetFrame,*PGETFRAME;
typedef struct IAVIEditStream IAVIEditStream, *PAVIEDITSTREAM;
typedef struct IAVIStreaming IAVIStreaming;
/* Installable Compressor Manager */
......@@ -1094,6 +1095,41 @@ LONG WINAPI AVIStreamTimeToSample(PAVISTREAM pstream, LONG lTime);
#define AVIStreamStartTime(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
*/
......
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