📄 icmstream.c
字号:
if (size < sizeof(BITMAPINFOHEADER))
return AVIERR_COMPRESSOR;
This->lpbiOutput = HeapAlloc(GetProcessHeap(), 0, size);
if (This->lpbiOutput == NULL)
return AVIERR_MEMORY;
This->cbOutput = size;
if (ICCompressGetFormat(This->hic,This->lpbiInput,This->lpbiOutput) < S_OK)
return AVIERR_COMPRESSOR;
/* update AVISTREAMINFO structure */
This->sInfo.rcFrame.right =
This->sInfo.rcFrame.left + This->lpbiOutput->biWidth;
This->sInfo.rcFrame.bottom =
This->sInfo.rcFrame.top + This->lpbiOutput->biHeight;
/* prepare codec for compression */
if (ICCompressBegin(This->hic, This->lpbiInput, This->lpbiOutput) != S_OK)
return AVIERR_COMPRESSOR;
/* allocate memory for compressed frame */
size = ICCompressGetSize(This->hic, This->lpbiInput, This->lpbiOutput);
This->lpbiCur = HeapAlloc(GetProcessHeap(), 0, This->cbOutput + size);
if (This->lpbiCur == NULL)
return AVIERR_MEMORY;
memcpy(This->lpbiCur, This->lpbiOutput, This->cbOutput);
This->lpCur = DIBPTR(This->lpbiCur);
/* allocate memory for last frame if needed */
if (This->lKeyFrameEvery != 1 &&
(This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
size = ICDecompressGetFormatSize(This->hic, This->lpbiOutput);
This->lpbiPrev = HeapAlloc(GetProcessHeap(), 0, size);
if (This->lpbiPrev == NULL)
return AVIERR_MEMORY;
if (ICDecompressGetFormat(This->hic, This->lpbiOutput, This->lpbiPrev) < S_OK)
return AVIERR_COMPRESSOR;
if (This->lpbiPrev->biSizeImage == 0) {
This->lpbiPrev->biSizeImage =
DIBWIDTHBYTES(*This->lpbiPrev) * This->lpbiPrev->biHeight;
}
/* get memory for format and picture */
size += This->lpbiPrev->biSizeImage;
This->lpbiPrev = HeapReAlloc(GetProcessHeap(), 0, This->lpbiPrev, size);
if (This->lpbiPrev == NULL)
return AVIERR_MEMORY;
This->lpPrev = DIBPTR(This->lpbiPrev);
/* prepare codec also for decompression */
if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
return AVIERR_COMPRESSOR;
}
} else {
/* format change -- check that's only the palette */
LPBITMAPINFOHEADER lpbi = (LPBITMAPINFOHEADER)format;
if (lpbi->biSize != This->lpbiInput->biSize ||
lpbi->biWidth != This->lpbiInput->biWidth ||
lpbi->biHeight != This->lpbiInput->biHeight ||
lpbi->biBitCount != This->lpbiInput->biBitCount ||
lpbi->biPlanes != This->lpbiInput->biPlanes ||
lpbi->biCompression != This->lpbiInput->biCompression ||
lpbi->biClrUsed != This->lpbiInput->biClrUsed)
return AVIERR_UNSUPPORTED;
/* get new output format */
if (ICCompressGetFormat(This->hic, lpbi, This->lpbiOutput) < S_OK)
return AVIERR_BADFORMAT;
/* restart compression */
ICCompressEnd(This->hic);
if (ICCompressBegin(This->hic, lpbi, This->lpbiOutput) != S_OK)
return AVIERR_COMPRESSOR;
/* check if we need to restart decompresion also */
if (This->lKeyFrameEvery != 1 &&
(This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
ICDecompressEnd(This->hic);
if (ICDecompressGetFormat(This->hic,This->lpbiOutput,This->lpbiPrev) < S_OK)
return AVIERR_COMPRESSOR;
if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
return AVIERR_COMPRESSOR;
}
}
/* tell nested stream the new format */
return IAVIStream_SetFormat(This->pStream, pos,
This->lpbiOutput, This->cbOutput);
}
static HRESULT WINAPI ICMStream_fnRead(IAVIStream *iface, LONG start,
LONG samples, LPVOID buffer,
LONG buffersize, LPLONG bytesread,
LPLONG samplesread)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
LPBITMAPINFOHEADER lpbi;
TRACE("(%p,%d,%d,%p,%d,%p,%p)\n", iface, start, samples, buffer,
buffersize, bytesread, samplesread);
/* clear return parameters if given */
if (bytesread != NULL)
*bytesread = 0;
if (samplesread != NULL)
*samplesread = 0;
if (samples == 0)
return AVIERR_OK;
/* check parameters */
if (samples != 1 && (bytesread == NULL && samplesread == NULL))
return AVIERR_BADPARAM;
if (samples == -1) /* read as much as we could */
samples = 1;
if (This->pg == NULL) {
HRESULT hr = AVIFILE_OpenGetFrame(This);
if (FAILED(hr))
return hr;
}
/* compress or decompress? */
if (This->hic == NULL) {
/* decompress */
lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(This->pg, start);
if (lpbi == NULL)
return AVIERR_MEMORY;
if (buffer != NULL && buffersize > 0) {
/* check buffersize */
if (buffersize < lpbi->biSizeImage)
return AVIERR_BUFFERTOOSMALL;
memcpy(buffer, DIBPTR(lpbi), lpbi->biSizeImage);
}
/* fill out return parameters if given */
if (bytesread != NULL)
*bytesread = lpbi->biSizeImage;
} else {
/* compress */
if (This->lCurrent > start)
AVIFILE_Reset(This);
while (start > This->lCurrent) {
HRESULT hr;
lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(This->pg, ++This->lCurrent);
if (lpbi == NULL) {
AVIFILE_Reset(This);
return AVIERR_MEMORY;
}
hr = AVIFILE_EncodeFrame(This, lpbi, DIBPTR(lpbi));
if (FAILED(hr)) {
AVIFILE_Reset(This);
return hr;
}
}
if (buffer != NULL && buffersize > 0) {
/* check buffersize */
if (This->lpbiCur->biSizeImage > buffersize)
return AVIERR_BUFFERTOOSMALL;
memcpy(buffer, This->lpCur, This->lpbiCur->biSizeImage);
}
/* fill out return parameters if given */
if (bytesread != NULL)
*bytesread = This->lpbiCur->biSizeImage;
}
/* fill out return parameters if given */
if (samplesread != NULL)
*samplesread = 1;
return AVIERR_OK;
}
static HRESULT WINAPI ICMStream_fnWrite(IAVIStream *iface, LONG start,
LONG samples, LPVOID buffer,
LONG buffersize, DWORD flags,
LPLONG sampwritten,
LPLONG byteswritten)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
HRESULT hr;
TRACE("(%p,%d,%d,%p,%d,0x%08X,%p,%p)\n", iface, start, samples,
buffer, buffersize, flags, sampwritten, byteswritten);
/* clear return parameters if given */
if (sampwritten != NULL)
*sampwritten = 0;
if (byteswritten != NULL)
*byteswritten = 0;
/* check parameters */
if (buffer == NULL && (buffersize > 0 || samples > 0))
return AVIERR_BADPARAM;
if (This->sInfo.fccHandler == comptypeDIB) {
/* only pass through */
flags |= AVIIF_KEYFRAME;
return IAVIStream_Write(This->pStream, start, samples, buffer, buffersize,
flags, sampwritten, byteswritten);
} else {
/* compress data before writing to pStream */
if (samples != 1 && (sampwritten == NULL && byteswritten == NULL))
return AVIERR_UNSUPPORTED;
This->lCurrent = start;
hr = AVIFILE_EncodeFrame(This, This->lpbiInput, buffer);
if (FAILED(hr))
return hr;
if (This->lLastKey == start)
flags |= AVIIF_KEYFRAME;
return IAVIStream_Write(This->pStream, start, samples, This->lpCur,
This->lpbiCur->biSizeImage, flags, byteswritten,
sampwritten);
}
}
static HRESULT WINAPI ICMStream_fnDelete(IAVIStream *iface, LONG start,
LONG samples)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
TRACE("(%p,%d,%d)\n", iface, start, samples);
return IAVIStream_Delete(This->pStream, start, samples);
}
static HRESULT WINAPI ICMStream_fnReadData(IAVIStream *iface, DWORD fcc,
LPVOID lp, LPLONG lpread)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
TRACE("(%p,0x%08X,%p,%p)\n", iface, fcc, lp, lpread);
assert(This->pStream != NULL);
return IAVIStream_ReadData(This->pStream, fcc, lp, lpread);
}
static HRESULT WINAPI ICMStream_fnWriteData(IAVIStream *iface, DWORD fcc,
LPVOID lp, LONG size)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
TRACE("(%p,0x%08x,%p,%d)\n", iface, fcc, lp, size);
assert(This->pStream != NULL);
return IAVIStream_WriteData(This->pStream, fcc, lp, size);
}
static HRESULT WINAPI ICMStream_fnSetInfo(IAVIStream *iface,
LPAVISTREAMINFOW info, LONG infolen)
{
FIXME("(%p,%p,%d): stub\n", iface, info, infolen);
return E_FAIL;
}
/***********************************************************************/
static HRESULT AVIFILE_EncodeFrame(IAVIStreamImpl *This,
LPBITMAPINFOHEADER lpbi, LPVOID lpBits)
{
DWORD dwMinQual, dwMaxQual, dwCurQual;
DWORD dwRequest;
DWORD icmFlags = 0;
DWORD idxFlags = 0;
BOOL bDecreasedQual = FALSE;
BOOL doSizeCheck;
BOOL noPrev;
/* make lKeyFrameEvery and at start a keyframe */
if ((This->lKeyFrameEvery != 0 &&
(This->lCurrent - This->lLastKey) >= This->lKeyFrameEvery) ||
This->lCurrent == This->sInfo.dwStart) {
idxFlags = AVIIF_KEYFRAME;
icmFlags = ICCOMPRESS_KEYFRAME;
}
if (This->lKeyFrameEvery != 0) {
if (This->lCurrent == This->sInfo.dwStart) {
if (idxFlags & AVIIF_KEYFRAME) {
/* for keyframes allow to consume all unused bytes */
dwRequest = This->dwBytesPerFrame + This->dwUnusedBytes;
This->dwUnusedBytes = 0;
} else {
/* for non-keyframes only allow something of the unused bytes to be consumed */
DWORD tmp1 = 0;
DWORD tmp2;
if (This->dwBytesPerFrame >= This->dwUnusedBytes)
tmp1 = This->dwBytesPerFrame / This->lKeyFrameEvery;
tmp2 = (This->dwUnusedBytes + tmp1) / This->lKeyFrameEvery;
dwRequest = This->dwBytesPerFrame - tmp1 + tmp2;
This->dwUnusedBytes -= tmp2;
}
} else
dwRequest = MAX_FRAMESIZE;
} else {
/* only one keyframe at start desired */
if (This->lCurrent == This->sInfo.dwStart) {
dwRequest = This->dwBytesPerFrame + This->dwUnusedBytes;
This->dwUnusedBytes = 0;
} else
dwRequest = MAX_FRAMESIZE;
}
/* must we check for framesize to gain requested
* datarate or could we trust codec? */
doSizeCheck = (dwRequest != 0 && ((This->dwICMFlags & (VIDCF_CRUNCH|VIDCF_QUALITY)) == 0));
dwMaxQual = dwCurQual = This->sInfo.dwQuality;
dwMinQual = ICQUALITY_LOW;
noPrev = TRUE;
if ((icmFlags & ICCOMPRESS_KEYFRAME) == 0 &&
(This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0)
noPrev = FALSE;
do {
DWORD idxCkid = 0;
HRESULT hr;
hr = ICCompress(This->hic,icmFlags,This->lpbiCur,This->lpCur,lpbi,lpBits,
&idxCkid, &idxFlags, This->lCurrent, dwRequest, dwCurQual,
noPrev ? NULL:This->lpbiPrev, noPrev ? NULL:This->lpPrev);
if (hr == ICERR_NEWPALETTE) {
FIXME(": codec has changed palette -- unhandled!\n");
} else if (hr != ICERR_OK)
return AVIERR_COMPRESSOR;
/* need to check for framesize */
if (! doSizeCheck)
break;
if (dwRequest >= This->lpbiCur->biSizeImage) {
/* frame is smaller -- try to maximize quality */
if (dwMaxQual - dwCurQual > 10) {
DWORD tmp = dwRequest / 8;
if (tmp < MAX_FRAMESIZE_DIFF)
tmp = MAX_FRAMESIZE_DIFF;
if (tmp < dwRequest - This->lpbiCur->biSizeImage && bDecreasedQual) {
tmp = dwCurQual;
dwCurQual = (dwMinQual + dwMaxQual) / 2;
dwMinQual = tmp;
continue;
}
} else
break;
} else if (dwMaxQual - dwMinQual <= 1) {
break;
} else {
dwMaxQual = dwCurQual;
if (bDecreasedQual || dwCurQual == This->dwLastQuality)
dwCurQual = (dwMinQual + dwMaxQual) / 2;
else
FIXME(": no new quality computed min=%u cur=%u max=%u last=%u\n",
dwMinQual, dwCurQual, dwMaxQual, This->dwLastQuality);
bDecreasedQual = TRUE;
}
} while (TRUE);
/* remember some values */
This->dwLastQuality = dwCurQual;
This->dwUnusedBytes = dwRequest - This->lpbiCur->biSizeImage;
if (icmFlags & ICCOMPRESS_KEYFRAME)
This->lLastKey = This->lCurrent;
/* Does we manage previous frame? */
if (This->lpPrev != NULL && This->lKeyFrameEvery != 1)
ICDecompress(This->hic, 0, This->lpbiCur, This->lpCur,
This->lpbiPrev, This->lpPrev);
return AVIERR_OK;
}
static HRESULT AVIFILE_OpenGetFrame(IAVIStreamImpl *This)
{
LPBITMAPINFOHEADER lpbi;
DWORD size;
/* pre-conditions */
assert(This != NULL);
assert(This->pStream != NULL);
assert(This->pg == NULL);
This->pg = AVIStreamGetFrameOpen(This->pStream, NULL);
if (This->pg == NULL)
return AVIERR_ERROR;
/* When we only decompress this is enough */
if (This->sInfo.fccHandler == comptypeDIB)
return AVIERR_OK;
assert(This->hic != NULL);
assert(This->lpbiOutput == NULL);
/* get input format */
lpbi = (LPBITMAPINFOHEADER)AVIStreamGetFrame(This->pg, This->sInfo.dwStart);
if (lpbi == NULL)
return AVIERR_MEMORY;
/* get memory for output format */
size = ICCompressGetFormatSize(This->hic, lpbi);
if ((LONG)size < (LONG)sizeof(BITMAPINFOHEADER))
return AVIERR_COMPRESSOR;
This->lpbiOutput = HeapAlloc(GetProcessHeap(), 0, size);
if (This->lpbiOutput == NULL)
return AVIERR_MEMORY;
This->cbOutput = size;
if (ICCompressGetFormat(This->hic, lpbi, This->lpbiOutput) < S_OK)
return AVIERR_BADFORMAT;
/* update AVISTREAMINFO structure */
This->sInfo.rcFrame.right =
This->sInfo.rcFrame.left + This->lpbiOutput->biWidth;
This->sInfo.rcFrame.bottom =
This->sInfo.rcFrame.top + This->lpbiOutput->biHeight;
This->sInfo.dwSuggestedBufferSize =
ICCompressGetSize(This->hic, lpbi, This->lpbiOutput);
/* prepare codec for compression */
if (ICCompressBegin(This->hic, lpbi, This->lpbiOutput) != S_OK)
return AVIERR_COMPRESSOR;
/* allocate memory for current frame */
size += This->sInfo.dwSuggestedBufferSize;
This->lpbiCur = HeapAlloc(GetProcessHeap(), 0, size);
if (This->lpbiCur == NULL)
return AVIERR_MEMORY;
memcpy(This->lpbiCur, This->lpbiOutput, This->cbOutput);
This->lpCur = DIBPTR(This->lpbiCur);
/* allocate memory for last frame if needed */
if (This->lKeyFrameEvery != 1 &&
(This->dwICMFlags & VIDCF_FASTTEMPORALC) == 0) {
size = ICDecompressGetFormatSize(This->hic, This->lpbiOutput);
This->lpbiPrev = HeapAlloc(GetProcessHeap(), 0, size);
if (This->lpbiPrev == NULL)
return AVIERR_MEMORY;
if (ICDecompressGetFormat(This->hic, This->lpbiOutput, This->lpbiPrev) < S_OK)
return AVIERR_COMPRESSOR;
if (This->lpbiPrev->biSizeImage == 0) {
This->lpbiPrev->biSizeImage =
DIBWIDTHBYTES(*This->lpbiPrev) * This->lpbiPrev->biHeight;
}
/* get memory for format and picture */
size += This->lpbiPrev->biSizeImage;
This->lpbiPrev = HeapReAlloc(GetProcessHeap(), 0, This->lpbiPrev, size );
if (This->lpbiPrev == NULL)
return AVIERR_MEMORY;
This->lpPrev = DIBPTR(This->lpbiPrev);
/* prepare codec also for decompression */
if (ICDecompressBegin(This->hic,This->lpbiOutput,This->lpbiPrev) != S_OK)
return AVIERR_COMPRESSOR;
}
return AVIERR_OK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -