📄 avifile.c
字号:
if (This->idxFrames[pos].dwChunkLength > 0)
goto RETURN_FOUND;
if (flags & FIND_NEXT)
pos++;
else
pos--;
};
} else if ((flags & FIND_FORMAT) && This->idxFmtChanges != NULL &&
This->sInfo.fccType == streamtypeVIDEO) {
if (flags & FIND_NEXT) {
ULONG n;
for (n = 0; n < This->sInfo.dwFormatChangeCount; n++)
if (This->idxFmtChanges[n].ckid >= pos) {
pos = This->idxFmtChanges[n].ckid;
goto RETURN_FOUND;
}
} else {
LONG n;
for (n = (LONG)This->sInfo.dwFormatChangeCount; n >= 0; n--) {
if (This->idxFmtChanges[n].ckid <= pos) {
pos = This->idxFmtChanges[n].ckid;
goto RETURN_FOUND;
}
}
if (pos > (LONG)This->sInfo.dwStart)
return 0; /* format changes always for first frame */
}
}
return -1;
}
RETURN_FOUND:
if (pos < (LONG)This->sInfo.dwStart)
return -1;
switch (flags & FIND_RET) {
case FIND_LENGTH:
/* physical size */
pos = This->idxFrames[pos].dwChunkLength;
break;
case FIND_OFFSET:
/* physical position */
pos = This->idxFrames[pos].dwChunkOffset + 2 * sizeof(DWORD)
+ offset * This->sInfo.dwSampleSize;
break;
case FIND_SIZE:
/* logical size */
if (This->sInfo.dwSampleSize)
pos = This->sInfo.dwSampleSize;
else
pos = 1;
break;
case FIND_INDEX:
FIXME(": FIND_INDEX flag is not supported!\n");
/* This is an index in the index-table on disc. */
break;
}; /* else logical position */
return pos;
}
static HRESULT WINAPI IAVIStream_fnReadFormat(IAVIStream *iface, LONG pos,
LPVOID format, LONG *formatsize)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
TRACE("(%p,%d,%p,%p)\n", iface, pos, format, formatsize);
if (formatsize == NULL)
return AVIERR_BADPARAM;
/* only interested in needed buffersize? */
if (format == NULL || *formatsize <= 0) {
*formatsize = This->cbFormat;
return AVIERR_OK;
}
/* copy initial format (only as much as will fit) */
memcpy(format, This->lpFormat, min(*(DWORD*)formatsize, This->cbFormat));
if (*(DWORD*)formatsize < This->cbFormat) {
*formatsize = This->cbFormat;
return AVIERR_BUFFERTOOSMALL;
}
/* Could format change? When yes will it change? */
if ((This->sInfo.dwFlags & AVISTREAMINFO_FORMATCHANGES) &&
pos > This->sInfo.dwStart) {
LONG lLastFmt;
lLastFmt = IAVIStream_fnFindSample(iface, pos, FIND_FORMAT|FIND_PREV);
if (lLastFmt > 0) {
FIXME(": need to read formatchange for %d -- unimplemented!\n",lLastFmt);
}
}
*formatsize = This->cbFormat;
return AVIERR_OK;
}
static HRESULT WINAPI IAVIStream_fnSetFormat(IAVIStream *iface, LONG pos,
LPVOID format, LONG formatsize)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
LPBITMAPINFOHEADER lpbiNew = (LPBITMAPINFOHEADER)format;
TRACE("(%p,%d,%p,%d)\n", iface, pos, format, formatsize);
/* check parameters */
if (format == NULL || formatsize <= 0)
return AVIERR_BADPARAM;
/* Do we have write permission? */
if ((This->paf->uMode & MMIO_RWMODE) == 0)
return AVIERR_READONLY;
/* can only set format before frame is written! */
if (This->lLastFrame > pos)
return AVIERR_UNSUPPORTED;
/* initial format or a formatchange? */
if (This->lpFormat == NULL) {
/* initial format */
if (This->paf->dwMoviChunkPos != 0)
return AVIERR_ERROR; /* user has used API in wrong sequnece! */
This->lpFormat = HeapAlloc(GetProcessHeap(), 0, formatsize);
if (This->lpFormat == NULL)
return AVIERR_MEMORY;
This->cbFormat = formatsize;
memcpy(This->lpFormat, format, formatsize);
/* update some infos about stream */
if (This->sInfo.fccType == streamtypeVIDEO) {
LONG lDim;
lDim = This->sInfo.rcFrame.right - This->sInfo.rcFrame.left;
if (lDim < lpbiNew->biWidth)
This->sInfo.rcFrame.right = This->sInfo.rcFrame.left + lpbiNew->biWidth;
lDim = This->sInfo.rcFrame.bottom - This->sInfo.rcFrame.top;
if (lDim < lpbiNew->biHeight)
This->sInfo.rcFrame.bottom = This->sInfo.rcFrame.top + lpbiNew->biHeight;
} else if (This->sInfo.fccType == streamtypeAUDIO)
This->sInfo.dwSampleSize = ((LPWAVEFORMATEX)This->lpFormat)->nBlockAlign;
return AVIERR_OK;
} else {
MMCKINFO ck;
LPBITMAPINFOHEADER lpbiOld = (LPBITMAPINFOHEADER)This->lpFormat;
RGBQUAD *rgbNew = (RGBQUAD*)((LPBYTE)lpbiNew + lpbiNew->biSize);
AVIPALCHANGE *lppc = NULL;
UINT n;
/* perhaps format change, check it ... */
if (This->cbFormat != formatsize)
return AVIERR_UNSUPPORTED;
/* no format change, only the initial one */
if (memcmp(This->lpFormat, format, formatsize) == 0)
return AVIERR_OK;
/* check that's only the palette, which changes */
if (lpbiOld->biSize != lpbiNew->biSize ||
lpbiOld->biWidth != lpbiNew->biWidth ||
lpbiOld->biHeight != lpbiNew->biHeight ||
lpbiOld->biPlanes != lpbiNew->biPlanes ||
lpbiOld->biBitCount != lpbiNew->biBitCount ||
lpbiOld->biCompression != lpbiNew->biCompression ||
lpbiOld->biClrUsed != lpbiNew->biClrUsed)
return AVIERR_UNSUPPORTED;
This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
/* simply say all colors have changed */
ck.ckid = MAKEAVICKID(cktypePALchange, This->nStream);
ck.cksize = 2 * sizeof(WORD) + lpbiOld->biClrUsed * sizeof(PALETTEENTRY);
lppc = HeapAlloc(GetProcessHeap(), 0, ck.cksize);
if (lppc == NULL)
return AVIERR_MEMORY;
lppc->bFirstEntry = 0;
lppc->bNumEntries = (lpbiOld->biClrUsed < 256 ? lpbiOld->biClrUsed : 0);
lppc->wFlags = 0;
for (n = 0; n < lpbiOld->biClrUsed; n++) {
lppc->peNew[n].peRed = rgbNew[n].rgbRed;
lppc->peNew[n].peGreen = rgbNew[n].rgbGreen;
lppc->peNew[n].peBlue = rgbNew[n].rgbBlue;
lppc->peNew[n].peFlags = 0;
}
if (mmioSeek(This->paf->hmmio, This->paf->dwNextFramePos, SEEK_SET) == -1)
return AVIERR_FILEWRITE;
if (mmioCreateChunk(This->paf->hmmio, &ck, 0) != S_OK)
return AVIERR_FILEWRITE;
if (mmioWrite(This->paf->hmmio, (HPSTR)lppc, ck.cksize) != ck.cksize)
return AVIERR_FILEWRITE;
if (mmioAscend(This->paf->hmmio, &ck, 0) != S_OK)
return AVIERR_FILEWRITE;
This->paf->dwNextFramePos += ck.cksize + 2 * sizeof(DWORD);
HeapFree(GetProcessHeap(), 0, lppc);
return AVIFILE_AddFrame(This, cktypePALchange, n, ck.dwDataOffset, 0);
}
}
static HRESULT WINAPI IAVIStream_fnRead(IAVIStream *iface, LONG start,
LONG samples, LPVOID buffer,
LONG buffersize, LPLONG bytesread,
LPLONG samplesread)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
DWORD size;
HRESULT hr;
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;
/* check parameters */
if ((LONG)This->sInfo.dwStart > start)
return AVIERR_NODATA; /* couldn't read before start of stream */
if (This->sInfo.dwStart + This->sInfo.dwLength < (DWORD)start)
return AVIERR_NODATA; /* start is past end of stream */
/* should we read as much as possible? */
if (samples == -1) {
/* User should know how much we have read */
if (bytesread == NULL && samplesread == NULL)
return AVIERR_BADPARAM;
if (This->sInfo.dwSampleSize != 0)
samples = buffersize / This->sInfo.dwSampleSize;
else
samples = 1;
}
/* limit to end of stream */
if ((LONG)This->sInfo.dwLength < samples)
samples = This->sInfo.dwLength;
if ((start - This->sInfo.dwStart) > (This->sInfo.dwLength - samples))
samples = This->sInfo.dwLength - (start - This->sInfo.dwStart);
/* nothing to read? Then leave ... */
if (samples == 0)
return AVIERR_OK;
if (This->sInfo.dwSampleSize != 0) {
/* fixed samplesize -- we can read over frame/block boundaries */
LONG block = start;
LONG offset = 0;
/* convert start sample to block,offset pair */
AVIFILE_SamplesToBlock(This, &block, &offset);
/* convert samples to bytes */
samples *= This->sInfo.dwSampleSize;
while (samples > 0 && buffersize > 0) {
if (block != This->dwCurrentFrame) {
hr = AVIFILE_ReadBlock(This, block, NULL, 0);
if (FAILED(hr))
return hr;
}
size = min((DWORD)samples, (DWORD)buffersize);
size = min(size, This->cbBuffer - offset);
memcpy(buffer, ((BYTE*)&This->lpBuffer[2]) + offset, size);
block++;
offset = 0;
buffer = ((LPBYTE)buffer)+size;
samples -= size;
buffersize -= size;
/* fill out return parameters if given */
if (bytesread != NULL)
*bytesread += size;
if (samplesread != NULL)
*samplesread += size / This->sInfo.dwSampleSize;
}
if (samples == 0)
return AVIERR_OK;
else
return AVIERR_BUFFERTOOSMALL;
} else {
/* variable samplesize -- we can only read one full frame/block */
if (samples > 1)
samples = 1;
assert(start <= This->lLastFrame);
size = This->idxFrames[start].dwChunkLength;
if (buffer != NULL && buffersize >= size) {
hr = AVIFILE_ReadBlock(This, start, buffer, size);
if (FAILED(hr))
return hr;
} else if (buffer != NULL)
return AVIERR_BUFFERTOOSMALL;
/* fill out return parameters if given */
if (bytesread != NULL)
*bytesread = size;
if (samplesread != NULL)
*samplesread = samples;
return AVIERR_OK;
}
}
static HRESULT WINAPI IAVIStream_fnWrite(IAVIStream *iface, LONG start,
LONG samples, LPVOID buffer,
LONG buffersize, DWORD flags,
LPLONG sampwritten,
LPLONG byteswritten)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
FOURCC ckid;
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;
/* Have we write permission? */
if ((This->paf->uMode & MMIO_RWMODE) == 0)
return AVIERR_READONLY;
switch (This->sInfo.fccType) {
case streamtypeAUDIO:
ckid = MAKEAVICKID(cktypeWAVEbytes, This->nStream);
break;
default:
if ((flags & AVIIF_KEYFRAME) && buffersize != 0)
ckid = MAKEAVICKID(cktypeDIBbits, This->nStream);
else
ckid = MAKEAVICKID(cktypeDIBcompressed, This->nStream);
break;
};
/* append to end of stream? */
if (start == -1) {
if (This->lLastFrame == -1)
start = This->sInfo.dwStart;
else
start = This->sInfo.dwLength;
} else if (This->lLastFrame == -1)
This->sInfo.dwStart = start;
if (This->sInfo.dwSampleSize != 0) {
/* fixed sample size -- audio like */
if (samples * This->sInfo.dwSampleSize != buffersize)
return AVIERR_BADPARAM;
/* Couldn't skip audio-like data -- User must supply appropriate silence */
if (This->sInfo.dwLength != start)
return AVIERR_UNSUPPORTED;
/* Convert position to frame/block */
start = This->lLastFrame + 1;
if ((This->paf->fInfo.dwFlags & AVIFILEINFO_ISINTERLEAVED) == 0) {
FIXME(": not interleaved, could collect audio data!\n");
}
} else {
/* variable sample size -- video like */
if (samples > 1)
return AVIERR_UNSUPPORTED;
/* must we fill up with empty frames? */
if (This->lLastFrame != -1) {
FOURCC ckid2 = MAKEAVICKID(cktypeDIBcompressed, This->nStream);
while (start > This->lLastFrame + 1) {
hr = AVIFILE_WriteBlock(This, This->lLastFrame + 1, ckid2, 0, NULL, 0);
if (FAILED(hr))
return hr;
}
}
}
/* write the block now */
hr = AVIFILE_WriteBlock(This, start, ckid, flags, buffer, buffersize);
if (SUCCEEDED(hr)) {
/* fill out return parameters if given */
if (sampwritten != NULL)
*sampwritten = samples;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -