📄 avifile.c
字号:
if (byteswritten != NULL)
*byteswritten = buffersize;
}
return hr;
}
static HRESULT WINAPI IAVIStream_fnDelete(IAVIStream *iface, LONG start,
LONG samples)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
FIXME("(%p,%d,%d): stub\n", iface, start, samples);
/* check parameters */
if (start < 0 || samples < 0)
return AVIERR_BADPARAM;
/* Delete before start of stream? */
if (start + samples < This->sInfo.dwStart)
return AVIERR_OK;
/* Delete after end of stream? */
if (start > This->sInfo.dwLength)
return AVIERR_OK;
/* For the rest we need write permissions */
if ((This->paf->uMode & MMIO_RWMODE) == 0)
return AVIERR_READONLY;
/* 1. overwrite the data with JUNK
*
* if ISINTERLEAVED {
* 2. concat all neighboured JUNK-blocks in this record to one
* 3. if this record only contains JUNK and is at end set dwNextFramePos
* to start of this record, repeat this.
* } else {
* 2. concat all neighboured JUNK-blocks.
* 3. if the JUNK block is at the end, then set dwNextFramePos to
* start of this block.
* }
*/
return AVIERR_UNSUPPORTED;
}
static HRESULT WINAPI IAVIStream_fnReadData(IAVIStream *iface, DWORD fcc,
LPVOID lp, LPLONG lpread)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
TRACE("(%p,0x%08X,%p,%p)\n", iface, fcc, lp, lpread);
if (fcc == ckidSTREAMHANDLERDATA) {
if (This->lpHandlerData != NULL && This->cbHandlerData > 0) {
if (lp == NULL || *lpread <= 0) {
*lpread = This->cbHandlerData;
return AVIERR_OK;
}
memcpy(lp, This->lpHandlerData, min(This->cbHandlerData, *lpread));
if (*lpread < This->cbHandlerData)
return AVIERR_BUFFERTOOSMALL;
return AVIERR_OK;
} else
return AVIERR_NODATA;
} else
return ReadExtraChunk(&This->extra, fcc, lp, lpread);
}
static HRESULT WINAPI IAVIStream_fnWriteData(IAVIStream *iface, DWORD fcc,
LPVOID lp, LONG size)
{
IAVIStreamImpl *This = (IAVIStreamImpl *)iface;
TRACE("(%p,0x%08x,%p,%d)\n", iface, fcc, lp, size);
/* check parameters */
if (lp == NULL)
return AVIERR_BADPARAM;
if (size <= 0)
return AVIERR_BADSIZE;
/* need write permission */
if ((This->paf->uMode & MMIO_RWMODE) == 0)
return AVIERR_READONLY;
/* already written something to this file? */
if (This->paf->dwMoviChunkPos != 0) {
/* the data will be inserted before the 'movi' chunk, so check for
* enough space */
DWORD dwPos = AVIFILE_ComputeMoviStart(This->paf);
/* ckid,size => 2 * sizeof(DWORD) */
dwPos += 2 * sizeof(DWORD) + size;
if (size >= This->paf->dwMoviChunkPos - 2 * sizeof(DWORD))
return AVIERR_UNSUPPORTED; /* not enough space left */
}
This->paf->fDirty = TRUE;
if (fcc == ckidSTREAMHANDLERDATA) {
if (This->lpHandlerData != NULL) {
FIXME(": handler data already set -- overwirte?\n");
return AVIERR_UNSUPPORTED;
}
This->lpHandlerData = HeapAlloc(GetProcessHeap(), 0, size);
if (This->lpHandlerData == NULL)
return AVIERR_MEMORY;
This->cbHandlerData = size;
memcpy(This->lpHandlerData, lp, size);
return AVIERR_OK;
} else
return WriteExtraChunk(&This->extra, fcc, lp, size);
}
static HRESULT WINAPI IAVIStream_fnSetInfo(IAVIStream *iface,
LPAVISTREAMINFOW info, LONG infolen)
{
FIXME("(%p,%p,%d): stub\n", iface, info, infolen);
return E_FAIL;
}
/***********************************************************************/
static HRESULT AVIFILE_AddFrame(IAVIStreamImpl *This, DWORD ckid, DWORD size, DWORD offset, DWORD flags)
{
/* pre-conditions */
assert(This != NULL);
switch (TWOCCFromFOURCC(ckid)) {
case cktypeDIBbits:
if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
flags |= AVIIF_KEYFRAME;
break;
case cktypeDIBcompressed:
if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
flags &= ~AVIIF_KEYFRAME;
break;
case cktypePALchange:
if (This->sInfo.fccType != streamtypeVIDEO) {
ERR(": found palette change in non-video stream!\n");
return AVIERR_BADFORMAT;
}
This->sInfo.dwFlags |= AVISTREAMINFO_FORMATCHANGES;
This->sInfo.dwFormatChangeCount++;
if (This->idxFmtChanges == NULL || This->sInfo.dwFormatChangeCount < This->nIdxFmtChanges) {
UINT n = This->sInfo.dwFormatChangeCount;
This->nIdxFmtChanges += 16;
if (This->idxFmtChanges == NULL)
This->idxFmtChanges =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->nIdxFmtChanges * sizeof(AVIINDEXENTRY));
else
This->idxFmtChanges =
HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->idxFmtChanges,
This->nIdxFmtChanges * sizeof(AVIINDEXENTRY));
if (This->idxFmtChanges == NULL)
return AVIERR_MEMORY;
This->idxFmtChanges[n].ckid = This->lLastFrame;
This->idxFmtChanges[n].dwFlags = 0;
This->idxFmtChanges[n].dwChunkOffset = offset;
This->idxFmtChanges[n].dwChunkLength = size;
return AVIERR_OK;
}
break;
case cktypeWAVEbytes:
if (This->paf->fInfo.dwFlags & AVIFILEINFO_TRUSTCKTYPE)
flags |= AVIIF_KEYFRAME;
break;
default:
WARN(": unknown TWOCC 0x%04X found\n", TWOCCFromFOURCC(ckid));
break;
};
/* first frame is alwasy a keyframe */
if (This->lLastFrame == -1)
flags |= AVIIF_KEYFRAME;
if (This->sInfo.dwSuggestedBufferSize < size)
This->sInfo.dwSuggestedBufferSize = size;
/* get memory for index */
if (This->idxFrames == NULL || This->lLastFrame + 1 >= This->nIdxFrames) {
This->nIdxFrames += 512;
if (This->idxFrames == NULL)
This->idxFrames = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->nIdxFrames * sizeof(AVIINDEXENTRY));
else
This->idxFrames = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->idxFrames,
This->nIdxFrames * sizeof(AVIINDEXENTRY));
if (This->idxFrames == NULL)
return AVIERR_MEMORY;
}
This->lLastFrame++;
This->idxFrames[This->lLastFrame].ckid = ckid;
This->idxFrames[This->lLastFrame].dwFlags = flags;
This->idxFrames[This->lLastFrame].dwChunkOffset = offset;
This->idxFrames[This->lLastFrame].dwChunkLength = size;
/* update AVISTREAMINFO structure if necessary */
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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 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;
}
static DWORD AVIFILE_ComputeMoviStart(IAVIFileImpl *This)
{
DWORD dwPos;
DWORD nStream;
/* RIFF,hdrl,movi,avih => (3 * 3 + 2) * sizeof(DWORD) = 11 * sizeof(DWORD) */
dwPos = 11 * sizeof(DWORD) + sizeof(MainAVIHeader);
for (nStream = 0; nStream < This->fInfo.dwStreams; nStream++) {
IAVIStreamImpl *pStream = This->ppStreams[nStream];
/* strl,strh,strf => (3 + 2 * 2) * sizeof(DWORD) = 7 * sizeof(DWORD) */
dwPos += 7 * sizeof(DWORD) + sizeof(AVIStreamHeader);
dwPos += ((pStream->cbFormat + 1) & ~1U);
if (pStream->lpHandlerData != NULL && pStream->cbHandlerData > 0)
dwPos += 2 * sizeof(DWORD) + ((pStream->cbHandlerData + 1) & ~1U);
if (lstrlenW(pStream->sInfo.szName) > 0)
dwPos += 2 * sizeof(DWORD) + ((lstrlenW(pStream->sInfo.szName) + 1) & ~1U);
}
if (This->dwMoviChunkPos == 0) {
This->dwNextFramePos = dwPos;
/* pad to multiple of AVI_HEADERSIZE only if we are more than 8 bytes away from it */
if (((dwPos + AVI_HEADERSIZE) & ~(AVI_HEADERSIZE - 1)) - dwPos > 2 * sizeof(DWORD))
This->dwNextFramePos = (dwPos + AVI_HEADERSIZE) & ~(AVI_HEADERSIZE - 1);
This->dwMoviChunkPos = This->dwNextFramePos - sizeof(DWORD);
}
return dwPos;
}
static void AVIFILE_ConstructAVIStream(IAVIFileImpl *paf, DWORD nr, LPAVISTREAMINFOW asi)
{
IAVIStreamImpl *pstream;
/* pre-conditions */
assert(paf != NULL);
assert(nr < MAX_AVISTREAMS);
assert(paf->ppStreams[nr] != NULL);
pstream = paf->ppStreams[nr];
pstream->lpVtbl = &iavist;
pstream->ref = 0;
pstream->paf = paf;
pstream->nStream = nr;
pstream->dwCurrentFrame = (DWORD)-1;
pstream->lLastFrame = -1;
if (asi != NULL) {
memcpy(&pstream->sInfo, asi, sizeof(pstream->sInfo));
if (asi->dwLength > 0) {
/* pre-allocate mem for frame-index structure */
pstream->idxFrames =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, asi->dwLength * sizeof(AVIINDEXENTRY));
if (pstream->idxFrames != NULL)
pstream->nIdxFrames = asi->dwLength;
}
if (asi->dwFormatChangeCount > 0) {
/* pre-allocate mem for formatchange-index structure */
pstream->idxFmtChanges =
HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, asi->dwFormatChangeCount * sizeof(AVIINDEXENTRY));
if (pstream->idxFmtChanges != NULL)
pstream->nIdxFmtChanges = asi->dwFormatChangeCount;
}
/* These values will be computed */
pstream->sInfo.dwLength = 0;
pstream->sInfo.dwSuggestedBufferSize = 0;
pstream->sInfo.dwFormatChangeCount = 0;
pstream->sInfo.dwEditCount = 1;
if (pstream->sInfo.dwSampleSize > 0)
SetRectEmpty(&pstream->sInfo.rcFrame);
}
pstream->sInfo.dwCaps = AVIFILECAPS_CANREAD|AVIFILECAPS_CANWRITE;
}
static void AVIFILE_DestructAVIStream(IAVIStreamImpl *This)
{
/* pre-conditions */
assert(This != NULL);
This->dwCurrentFrame = (DWORD)-1;
This->lLastFrame = -1;
This->paf = NULL;
if (This->idxFrames != NULL) {
HeapFree(GetProcessHeap(), 0, This->idxFrames);
This->idxFrames = NULL;
This->nIdxFrames = 0;
}
HeapFree(GetProcessHeap(), 0, This->idxFmtChanges);
This->idxFmtChanges = NULL;
if (This->lpBuffer != NULL) {
HeapFree(GetProcessHeap(), 0, This->lpBuffer);
This->lpBuffer = NULL;
This->cbBuffer = 0;
}
if (This->lpHandlerData != NULL) {
HeapFree(GetProcessHeap(), 0, This->lpHandlerData);
This->lpHandlerData = NULL;
This->cbHandlerData = 0;
}
if (This->extra.lp != NULL) {
HeapFree(GetProcessHeap(), 0, This->extra.lp);
This->extra.lp = NULL;
This->extra.cb = 0;
}
if (This->lpFormat != NULL) {
HeapFree(GetProcessHeap(), 0, This->lpFormat);
This->lpFormat = NULL;
This->cbFormat = 0;
}
}
static HRESULT AVIFILE_LoadFile(IAVIFileImpl *This)
{
MainAVIHeader MainAVIHdr;
MMCKINFO ckRIFF;
MMCKINFO ckLIST1;
MMCKINFO ckLIST2;
MMCKINFO ck;
IAVIStreamImpl *pStream;
DWORD nStream;
HRESULT hr;
if (This->hmmio == NULL)
return AVIERR_FILEOPEN;
/* initialize stream ptr's */
memset(This->ppStreams, 0, sizeof(This->ppStreams));
/* try to get "RIFF" chunk -- must not be at beginning of file! */
ckRIFF.fccType = formtypeAVI;
if (mmioDescend(This->hmmio, &ckRIFF, NULL, MMIO_FINDRIFF) != S_OK) {
ERR(": not an AVI!\n");
return AVIERR_FILEREAD;
}
/* get "LIST" "hdrl" */
ckLIST1.fccType = listtypeAVIHEADER;
hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ckLIST1, &ckRIFF, MMIO_FINDLIST);
if (FAILED(hr))
return hr;
/* get "avih" chunk */
ck.ckid = ckidAVIMAINHDR;
hr = FindChunkAndKeepExtras(&This->fileextra, This->hmmio, &ck, &ckLIST1, MMIO_FINDCHUNK);
if (FAILED(hr))
return hr;
if (ck.cksize != sizeof(MainAVIHdr)) {
ERR(": invalid size of %d for MainAVIHeader!\n", ck.cksize);
return AVIERR_BADFORMAT;
}
if (mmioRead(This->hmmio, (HPSTR)&MainAVIHdr, ck.cksize) != ck.cksize)
return AVIERR_FILEREAD;
/* check for MAX_AVISTREAMS limit */
if (MainAVIHdr.dwStreams > MAX_AVISTREAMS) {
WARN("file contains %u streams, but only supports %d -- change MAX_AVISTREAMS!\n", MainAVIHdr.dwStreams, MAX_AVISTREAMS);
return AVIERR_UNSUPPORTED;
}
/* adjust permissions if copyrighted material in file */
if (MainAVIHdr.dwFlags & AVIFILEINFO_COPYRIGHTED) {
This->uMode &= ~MMIO_RWMODE;
This->uMode |= MMIO_READ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -