- 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 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
|
* 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
|
||||||
|
@ -1388,7 +1388,7 @@ INT_PTR CALLBACK AVISaveOptionsDlgProc(HWND hWnd, UINT uMsg,
|
||||||
}
|
}
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case IDCANCEL:
|
case IDCANCEL:
|
||||||
EndDialog(hWnd, GET_WM_COMMAND_CMD(wParam, lParam) == IDOK);
|
EndDialog(hWnd, GET_WM_COMMAND_ID(wParam, lParam) == IDOK);
|
||||||
break;
|
break;
|
||||||
case IDC_INTERLEAVE:
|
case IDC_INTERLEAVE:
|
||||||
EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
|
EnableWindow(GetDlgItem(hWnd, IDC_INTERLEAVEEVERY),
|
||||||
|
@ -1450,10 +1450,12 @@ BOOL WINAPI AVISaveOptions(HWND hWnd, UINT uFlags, INT nStreams,
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
|
|
||||||
/* restore options when user pressed cancel */
|
/* restore options when user pressed cancel */
|
||||||
if (pSavedOptions != NULL && ret == FALSE) {
|
if (pSavedOptions != NULL) {
|
||||||
for (n = 0; n < nStreams; n++) {
|
if (ret == FALSE) {
|
||||||
if (ppOptions[n] != NULL)
|
for (n = 0; n < nStreams; n++) {
|
||||||
memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
|
if (ppOptions[n] != NULL)
|
||||||
|
memcpy(ppOptions[n], pSavedOptions + n, sizeof(AVICOMPRESSOPTIONS));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
GlobalFreePtr(pSavedOptions);
|
GlobalFreePtr(pSavedOptions);
|
||||||
}
|
}
|
||||||
|
@ -1529,20 +1531,443 @@ HRESULT WINAPI AVISaveVA(LPCSTR szFile, CLSID *pclsidHandler,
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* AVIFILE_AVISaveDefaultCallback (internal)
|
||||||
|
*/
|
||||||
|
static BOOL WINAPI AVIFILE_AVISaveDefaultCallback(INT progress)
|
||||||
|
{
|
||||||
|
TRACE("(%d)\n", progress);
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* AVISaveVW (AVIFIL32.@)
|
* AVISaveVW (AVIFIL32.@)
|
||||||
*/
|
*/
|
||||||
HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
|
HRESULT WINAPI AVISaveVW(LPCWSTR szFile, CLSID *pclsidHandler,
|
||||||
AVISAVECALLBACK lpfnCallback, int nStream,
|
AVISAVECALLBACK lpfnCallback, int nStreams,
|
||||||
PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
|
PAVISTREAM *ppavi, LPAVICOMPRESSOPTIONS *plpOptions)
|
||||||
{
|
{
|
||||||
FIXME("(%s,%p,%p,%d,%p,%p), stub!\n", debugstr_w(szFile), pclsidHandler,
|
LONG lStart[MAX_AVISTREAMS];
|
||||||
lpfnCallback, nStream, ppavi, plpOptions);
|
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)
|
if (szFile == NULL || ppavi == NULL || plpOptions == NULL)
|
||||||
return AVIERR_BADPARAM;
|
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)
|
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)
|
if (ppEditable == NULL)
|
||||||
return AVIERR_BADPARAM;
|
return AVIERR_BADPARAM;
|
||||||
|
|
||||||
*ppEditable = NULL;
|
*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 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
|
* 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 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* 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 {
|
||||||
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 {
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
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,
|
||||||
|
|
||||||
/* 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
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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,
|
||||||
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;
|
||||||
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);
|
||||||
#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
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue