- 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.
This commit is contained in:
parent
9a9fcd1ad4
commit
c783c20288
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright 1999 Marcus Meissner
|
||||
* Copyright 2002 Michael Günnewig
|
||||
* 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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1529,20 +1531,443 @@ HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
|
|||
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 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;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Copyright 1999 Marcus Meissner
|
||||
* Copyright 2002 Michael Günnewig
|
||||
* 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
|
||||
|
@ -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
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue