|
|
/******************************************************************************
Copyright (C) Microsoft Corporation 1985-1995. All rights reserved.
AVIIDX.C - AVI Index stuff
*****************************************************************************/
#include <win32.h> // Win16/32 porting
#include <vfw.h>
#include "aviidx.h"
#ifdef AVIIDX_READONLY
#include "common.h" // for DEBUG
#else
#include "debug.h" // for DEBUG
#endif
/***************************************************************************
***************************************************************************/
#define INDEXALLOC 512
#define STACK _based(_segname("_STACK"))
/***************************************************************************
***************************************************************************/
//
// used by SearchIndex() to return where a sample is
//
typedef struct { LONG lx; // index position
LONG lPos; // position in samples.
LONG lSize; // size in samples.
LONG lOffset; // file offset.
LONG lLength; // size in bytes.
} IDXPOS;
/***************************************************************************
* * @doc INTERNAL * * @api PAVIINDEX | IndexAddFileIndex * * add a bunch of entries from a AVIFILE index to the index. * ***************************************************************************/
EXTERN_C PAVIINDEX IndexAddFileIndex(PAVIINDEX px, AVIINDEXENTRY _huge *pidx, LONG cnt, LONG lAdjust, BOOL fRle) { LONG lx; LONG l; LONG lxRec; DWORD ckid; UINT stream; DWORD offset; DWORD length; UINT flags;
Assert(px); Assert(pidx);
if (px == NULL || pidx == NULL) return NULL;
Assert(sizeof(AVIINDEXENTRY) > sizeof(AVIIDX));
//
// grow the index if needed.
//
if (px->nIndex + cnt > px->nIndexSize) {
LONG grow = px->nIndex + cnt - px->nIndexSize; LPVOID p;
if (grow < INDEXALLOC) grow = INDEXALLOC;
p = (LPVOID)GlobalReAllocPtr(px,sizeof(AVIINDEX) + (px->nIndexSize + grow) * sizeof(AVIIDX), GMEM_MOVEABLE | GMEM_SHARE);
if (!p) return NULL; px = (PAVIINDEX)p; px->nIndexSize += grow; }
for (lxRec=-1,l=0; l < cnt; l++,pidx++) {
lx = px->nIndex + l;
//
// adjust the offset to be absolute
//
offset = pidx->dwChunkOffset + lAdjust; length = pidx->dwChunkLength; ckid = pidx->ckid; stream = StreamFromFOURCC(ckid); flags = 0;
if (ckid == listtypeAVIRECORD) stream = STREAM_REC;
if (ckid == listtypeAVIRECORD) lxRec = lx;
//
// handle over flows in a "sane" way.
//
if (offset >= MAX_OFFSET) break;
if (stream >= MAX_STREAM) break;
if (length >= MAX_LENGTH) length = MAX_LENGTH-1;
if (pidx->dwFlags & AVIIF_KEYFRAME) flags |= IDX_KEY; else flags |= IDX_NONKEY;
//
// length == 0 samples are not real
//
if (length == 0) flags &= ~(IDX_NONKEY|IDX_KEY);
//
// mark palette changes
//
if (TWOCCFromFOURCC(ckid) == cktypePALchange) { flags |= IDX_PAL; flags &= ~(IDX_NONKEY|IDX_KEY); }
//
// fix up bogus index's by adding any missing KEYFRAME
// bits. ie this only applies for RLE files.
//
if (fRle && length > 0 && TWOCCFromFOURCC(ckid) == cktypeDIBbits) flags |= IDX_KEY;
//
// do we need to support these?
//
if (fRle && TWOCCFromFOURCC(ckid) == aviTWOCC('d', 'x')) flags |= IDX_HALF;
//
// audio is always a key.
//
if (TWOCCFromFOURCC(ckid) == cktypeWAVEbytes) flags |= IDX_KEY|IDX_NONKEY; //hack to get audio back!
//
// make sure records are marked as contining a key
//
//if (lxRec > 0 && (flags & IDX_KEY))
// IndexSetKey(px, lxRec);
IndexSetFlags(px,lx,flags); IndexSetOffset(px,lx,offset); IndexSetLength(px,lx,length); IndexSetStream(px,lx,stream);
}
cnt = l; px->nIndex += cnt;
return px; }
/***************************************************************************
***************************************************************************/
static LONG FAR PASCAL mmioReadProc(HMMIO hmmio, LONG lSeek, LONG lRead, LPVOID lpBuffer) { if (mmioSeek(hmmio, lSeek, SEEK_SET) == -1) return -1;
if (mmioRead(hmmio, (HPSTR)lpBuffer, lRead) != lRead) return -1;
return lRead; }
/***************************************************************************
***************************************************************************/
static LONG FAR PASCAL mmioWriteProc(HMMIO hmmio, LONG lSeek, LONG lWrite, LPVOID lpBuffer) { if (mmioSeek(hmmio, lSeek, SEEK_SET) == -1) return -1;
if (mmioWrite(hmmio, (HPSTR)lpBuffer, lWrite) != lWrite) return -1;
return lWrite; }
/***************************************************************************
* * @doc INTERNAL * * @api PSTREAMINDEX | MakeStreamIndex * * makes a STREAMINDEX structure that will be used later to read/find * samples in a stream. * ***************************************************************************/
EXTERN_C PSTREAMINDEX MakeStreamIndex(PAVIINDEX px, UINT stream, LONG lStart, LONG lSampleSize, HANDLE hFile, STREAMIOPROC ReadProc, STREAMIOPROC WriteProc) { LONG lPos; LONG lx; PSTREAMINDEX psx;
Assert(px);
if (px == NULL) return NULL;
psx = (PSTREAMINDEX)LocalAlloc(LPTR, sizeof(STREAMINDEX));
if (psx == NULL) return NULL;
//!!! fixed length sample streams should never have this
if (lSampleSize != 0 && lStart < 0) { #ifdef DEBUG
//AssertSz(0, "Audio streams should not have initial frames");
#endif
lStart = 0; }
psx->px = px; psx->lStart = lStart; psx->lSampleSize = lSampleSize; psx->lMaxSampleSize = 0; psx->stream = stream; psx->flags = 0;
psx->lStart = lStart; psx->lxStart = IndexFirst(px, stream);
psx->lPos = lStart; psx->lx = psx->lxStart;
psx->lFrames = 0; psx->lKeyFrames = 0; psx->lPalFrames = 0; psx->lNulFrames = 0;
psx->hFile = hFile;
if (ReadProc == NULL) psx->Read = (STREAMIOPROC)mmioReadProc; else psx->Read = ReadProc;
if (WriteProc == NULL) psx->Write = (STREAMIOPROC)mmioWriteProc; else psx->Write = WriteProc;
lPos = lStart;
for (lx = psx->lxStart; lx >= 0 && lx < px->nIndex; lx=IndexNext(px, lx, 0)) {
if (psx->lMaxSampleSize < IndexLength(px, lx)) psx->lMaxSampleSize = IndexLength(px, lx);
//
// make sure the start sample is a key frame (unless it's wave data!)
//
if (lPos == 0 || (lPos >= 0 && lPos == psx->lStart)) { if ((IndexFlags(px, lx) & (IDX_KEY|IDX_NONKEY)) != (IDX_KEY|IDX_NONKEY)) { IndexSetKey(px, lx); } }
//
// make sure sample size is correct
//
if (psx->lSampleSize && ((IndexLength(px, lx) % lSampleSize) != 0)) { DPF("!!! Bad chunk size found: force sample size to 0???\n"); // psx->lSampleSize = 0; !!! turned off because of possible
// partial audio chunks at file's end.....
}
//
// or all the flags together so we can see what a stream has.
//
psx->flags |= IndexFlags(px, lx);
//
// check for all key frames.
//
if (IndexFlags(px, lx) & IDX_KEY) psx->lKeyFrames++;
//
// check for all palette changes
//
if (IndexFlags(px, lx) & IDX_PAL) psx->lPalFrames++;
//
// check for empty frames
//
if (IndexLength(px, lx) == 0) psx->lNulFrames++;
//
// advance the position
//
if (!(IndexFlags(px,lx) & IDX_NOTIME)) { if (lSampleSize) lPos += IndexLength(px, lx) / lSampleSize; else lPos++; }
psx->lFrames++; }
//
// correct the length
//
psx->lEnd = lPos;
DPF("MakeStreamIndex stream=#%d lStart=%ld, lEnd=%ld\n", stream, psx->lStart, psx->lEnd); DPF(" lFrames = %ld, lKeys = %ld, lPals = %ld, lEmpty = %ld\n", psx->lFrames, psx->lKeyFrames, psx->lPalFrames, psx->lNulFrames);
return psx; }
#ifndef AVIIDX_READONLY
/***************************************************************************
* * @doc INTERNAL * * @api PAVIINDEX | IndexGetFileIndex * * make a file index out of a in memory index * ***************************************************************************/
EXTERN_C LONG IndexGetFileIndex(PAVIINDEX px, LONG l, LONG cnt, PAVIINDEXENTRY pidx, LONG lAdjust) { LONG lx; DWORD ckid; UINT stream; DWORD offset; DWORD length; UINT flags; DWORD dwFlags;
Assert(pidx); Assert(px);
if (pidx == NULL || px == NULL) return NULL;
Assert(sizeof(AVIINDEXENTRY) > sizeof(AVIIDX));
for (lx=l; lx < px->nIndex && lx < l+cnt; lx++) { //
// adjust the offset to be relative
//
offset = IndexOffset(px,lx) + lAdjust; length = IndexLength(px,lx); stream = IndexStream(px,lx); flags = IndexFlags(px, lx);
if (length == MAX_LENGTH-1) { }
ckid = MAKEAVICKID(0, stream); dwFlags = 0;
//
// set the flags, there are only a few flags in file index's
// AVIIF_KEYFRAME, AVIIF_LIST, AVIIF_NOTIME
//
if (flags & IDX_KEY) dwFlags |= AVIIF_KEYFRAME;
if (flags & IDX_PAL) dwFlags |= AVIIF_NOTIME;
if (stream == STREAM_REC) dwFlags |= AVIIF_LIST;
//
// now figure out the ckid
//
if (stream == STREAM_REC) ckid = listtypeAVIRECORD;
else if ((flags & (IDX_KEY|IDX_NONKEY)) == (IDX_KEY|IDX_NONKEY)) ckid |= MAKELONG(0, aviTWOCC('w', 'b'));
else if (flags & IDX_PAL) ckid |= MAKELONG(0, aviTWOCC('p', 'c'));
else if (flags & IDX_HALF) ckid |= MAKELONG(0, aviTWOCC('d', 'x'));
else if (flags & IDX_KEY) ckid |= MAKELONG(0, aviTWOCC('d', 'b'));
else ckid |= MAKELONG(0, aviTWOCC('d', 'c'));
//
// set the info
//
pidx->dwChunkOffset = offset; pidx->dwChunkLength = length; pidx->dwFlags = dwFlags; pidx->ckid = ckid;
pidx++; }
return lx - l; // return count copied
}
/***************************************************************************
* * @doc INTERNAL * * @api PAVIINDEX | IndexCreate | make a index. * ***************************************************************************/
EXTERN_C PAVIINDEX IndexCreate(void) { PAVIINDEX px;
px = (PAVIINDEX)GlobalAllocPtr(GHND | GMEM_SHARE, sizeof(AVIINDEX) + INDEXALLOC * sizeof(AVIIDX));
if (px == NULL) return NULL;
px->nIndex = 0; // index size
px->nIndexSize = INDEXALLOC; // allocated size
return px; }
#endif // AVIIDX_READONLY
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api LONG | IndexFirst | returns the first index entry for a stream * * @rdesc returns the first index entry, -1 for error * ***************************************************************************/
EXTERN_C LONG IndexFirst(PAVIINDEX px, UINT stream) { LONG l;
Assert(px);
for (l=0; l<px->nIndex; l++) {
if (IndexStream(px, l) == stream) return l; }
return ERR_IDX; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api LONG | IndexNext | go forward in a index * ***************************************************************************/
EXTERN_C LONG IndexNext(PAVIINDEX px, LONG l, UINT f) { WORD bStream;
Assert(px);
if (l < 0 || l >= px->nIndex) return ERR_IDX;
bStream = IndexStream(px, l);
for (l++; l<px->nIndex; l++) {
if (IndexStream(px, l) != bStream) continue;
if (!f || (IndexFlags(px, l) & f)) return l; }
return ERR_IDX; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api LONG | IndexPrev | step backward in a stream * ***************************************************************************/ EXTERN_C LONG IndexPrev(PAVIINDEX px, LONG l, UINT f) { WORD bStream;
Assert(px);
if (l < 0 || l >= px->nIndex) return ERR_IDX;
bStream = IndexStream(px, l);
for (l--; l>=0; l--) {
if (IndexStream(px, l) != bStream) continue;
if (!f || (IndexFlags(px, l) & f)) return l; }
return ERR_IDX; }
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
INLINE BOOL StreamNext(PSTREAMINDEX psx, LONG FAR& l, LONG FAR& lPos, UINT flags) { BYTE bStream = (BYTE) psx->stream; LONG lSampleSize = psx->lSampleSize; LONG lSave = l; LONG lPosSave = lPos; PAVIINDEX px = psx->px;
Assert(px && l >= 0 && l < px->nIndex);
if (lSampleSize == 0) {
lPos += 1; l++;
for (; l<px->nIndex; l++) {
if (IndexStream(px, l) != bStream) continue;
if (!flags || (IndexFlags(px, l) & flags)) return TRUE;
if (!(IndexFlags(px, l) & IDX_NOTIME)) lPos += 1; } } else {
lPos += IndexLength(px, l) / lSampleSize; l++;
for (; l<px->nIndex; l++) {
if (IndexStream(px, l) != bStream) continue;
if (!flags || (IndexFlags(px, l) & flags)) return TRUE;
lPos += IndexLength(px, l) / lSampleSize; } }
lPos = lPosSave; l = lSave;
return FALSE; }
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
INLINE BOOL StreamPrev(PSTREAMINDEX psx, LONG FAR& l, LONG FAR& lPos, UINT flags) { BYTE bStream = (BYTE) psx->stream; LONG lSampleSize = psx->lSampleSize; LONG lSave = l; LONG lPosSave = lPos; PAVIINDEX px = psx->px;
Assert(px && l >= 0 && l < px->nIndex);
if (lSampleSize == 0) {
for (l--;l>=0;l--) {
if (IndexStream(px, l) != bStream) continue;
if (!(IndexFlags(px, l) & IDX_NOTIME)) lPos -= 1;
if (!flags || (IndexFlags(px, l) & flags)) return TRUE; } } else { for (l--;l>=0;l--) {
if (IndexStream(px, l) != bStream) continue;
lPos -= IndexLength(px, l) / lSampleSize;
if (!flags || (IndexFlags(px, l) & flags)) return TRUE; } }
lPos = lPosSave; l = lSave;
return FALSE; }
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
static LONG SearchIndex(PSTREAMINDEX psx,LONG lPos,UINT uFlags,IDXPOS FAR *pos) { LONG l; LONG lScan; LONG lFound; LONG lFoundPos; LONG lLen; UINT flags; PAVIINDEX px = psx->px;
Assert(psx); Assert(psx->px);
if (psx == NULL) return ERR_POS;
if (lPos < psx->lStart) return ERR_POS;
if (lPos >= psx->lEnd) return ERR_POS;
//
// figure out where to start in the index.
//
if (psx->lx != -1) { lScan = psx->lPos; l = psx->lx; } else { DPF3("Starting index search at begining\n"); lScan = psx->lStart;
for (l=0; l<px->nIndex; l++) if (IndexStream(px, l) == (UINT)psx->stream) break; }
Assert(l >= 0 && l < px->nIndex); Assert(IndexStream(px, l) == psx->stream);
#ifdef DEBUG
if (!(uFlags & FIND_DIR)) uFlags |= FIND_PREV;
switch (uFlags & (FIND_TYPE|FIND_DIR)) { case FIND_NEXT|FIND_KEY: DPF3("SearchIndex(%d): %ld next key, start=%ld",psx->stream, lPos, lScan); break; case FIND_NEXT|FIND_ANY: DPF3("SearchIndex(%d): %ld next any, start=%ld",psx->stream, lPos, lScan); break; case FIND_NEXT|FIND_FORMAT: DPF3("SearchIndex(%d): %ld next fmt, start=%ld",psx->stream, lPos, lScan); break; case FIND_NEXT: DPF3("SearchIndex(%d): %ld next , start=%ld",psx->stream, lPos, lScan); break;
case FIND_PREV|FIND_KEY: DPF3("SearchIndex(%d): %ld prev key, start=%ld",psx->stream, lPos, lScan); break; case FIND_PREV|FIND_ANY: DPF3("SearchIndex(%d): %ld prev any, start=%ld",psx->stream, lPos, lScan); break; case FIND_PREV|FIND_FORMAT: DPF3("SearchIndex(%d): %ld prev fmt, start=%ld",psx->stream, lPos, lScan); break; case FIND_PREV: DPF3("SearchIndex(%d): %ld prev , start=%ld",psx->stream, lPos, lScan); break; }
LONG time = timeGetTime(); #endif
lLen = psx->lSampleSize == 0 ? 1 : IndexLength(px, l) / psx->lSampleSize;
if (lScan+lLen <= lPos) { //
// search forward for this position
//
while (lScan <= lPos) {
lFound = l; lFoundPos = lScan;
if (lScan == lPos) break;
if (!StreamNext(psx, l, lScan, IDX_KEY|IDX_NONKEY)) break; }
if ((lScan > lPos) && !(uFlags & FIND_NEXT)) { lScan = lFoundPos; l = lFound; } } else if (lScan > lPos) { //
// search backward for this position
//
while (lScan >= lPos) {
lFound = l; lFoundPos = lScan;
if (lScan == lPos) break;
if (!StreamPrev(psx, l, lScan, IDX_KEY|IDX_NONKEY)) break; }
if (uFlags & FIND_NEXT) { lScan = lFoundPos; l = lFound; } } else { Assert(lScan <= lPos && lPos < lScan+lLen); }
Assert(l >= 0 && l < px->nIndex); Assert(IndexStream(px, l) == psx->stream);
//
// cache what we found.
//
psx->lx = l; psx->lPos = lScan;
if (uFlags & FIND_TYPE) {
switch (uFlags & FIND_TYPE) { case FIND_ANY: flags = IDX_KEY|IDX_NONKEY; break; case FIND_FORMAT: flags = IDX_PAL; break; case FIND_KEY: flags = IDX_KEY; break; }
if (!(IndexFlags(px, l) & flags)) {
if (!(uFlags & FIND_NEXT)) { if (!StreamPrev(psx, l, lScan, flags)) { DPF3("!, EOI, time = %ld\n", timeGetTime() - time); return ERR_POS; } } else { if (!StreamNext(psx, l, lScan, flags)) { DPF3("!, EOI, time = %ld\n", timeGetTime() - time); return ERR_POS; } } }
Assert(l >= 0 && l < px->nIndex); Assert(IndexStream(px, l) == psx->stream); Assert(IndexFlags(px, l) & flags); }
Assert(lScan >= psx->lStart && lScan < psx->lEnd);
DPF3("!, found %ld, time = %ld\n", lScan, timeGetTime() - time);
if (pos == NULL) return lScan;
if (psx->lSampleSize != 0) {
lLen = IndexLength(px, l);
if (lLen == MAX_LENGTH-1) lLen = 0x7FFFFFFF;
if (psx->lSampleSize > 1) lLen /= psx->lSampleSize; } else { lLen = 1; }
pos->lx = l; pos->lPos = lScan; pos->lSize = lLen; pos->lOffset = IndexOffset(px, l); pos->lLength = IndexLength(px, l);
//
// if the FIND_TYPE is not one of FIND_ANY, FIND_KEY, FIND_FORMAT
// make sure we realy found the wanted sample.
//
if ((uFlags & FIND_TYPE) == 0) { if (lPos < lScan || lPos >= lScan+lLen) { pos->lOffset = -1; pos->lLength = 0; pos->lSize = 0; pos->lPos = lPos; } else if (psx->lSampleSize > 0) { pos->lOffset += (lPos - lScan) * psx->lSampleSize; pos->lLength -= (lPos - lScan) * psx->lSampleSize; pos->lSize -= (lPos - lScan); pos->lPos = lPos; } }
return pos->lPos; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api LONG | FindSample | find a sample in a stream * ***************************************************************************/
EXTERN_C LONG StreamFindSample(PSTREAMINDEX psx,LONG lPos,UINT uFlags) { Assert(psx); Assert(psx->px);
if (lPos < psx->lStart) return ERR_POS;
if (lPos >= psx->lEnd) return ERR_POS;
if ((uFlags & FIND_RET) == FIND_POS) {
switch (uFlags & FIND_TYPE) { case FIND_FORMAT: if (psx->lPalFrames == 0) { if ((uFlags & FIND_NEXT) && lPos > psx->lStart) return ERR_POS; else return psx->lStart; } break;
case FIND_ANY: if (psx->lNulFrames == 0) { return lPos; } break;
case FIND_KEY: if (psx->lKeyFrames == psx->lFrames) { return lPos; } break;
default: return lPos; }
return SearchIndex(psx, lPos, uFlags, NULL); } else { IDXPOS pos;
if (SearchIndex(psx, lPos, uFlags, &pos) == ERR_POS) return ERR_POS;
switch (uFlags & FIND_RET) { case FIND_POS: return pos.lPos;
case FIND_OFFSET: return pos.lOffset + 8;
case FIND_LENGTH: return pos.lLength;
case FIND_SIZE: return pos.lSize;
case FIND_INDEX: return pos.lx; } }
return ERR_POS; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api LONG | StreamRead | read from a stream * ***************************************************************************/
EXTERN_C LONG StreamRead( PSTREAMINDEX psx, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer) { LONG lBytes; LONG lSampleSize; LONG lSeek; LONG lRead; IDXPOS pos;
Assert(psx); Assert(psx->px); Assert(psx->hFile); Assert(psx->Read);
if (lStart < psx->lStart) return -1;
if (lStart >= psx->lEnd) return -1;
//DPF("%cst: %d : %d\n", psx->stream ? '\t':' ', psx->stream, lStart);
//
// find nearest chunk
//
if (SearchIndex(psx, lStart, FIND_PREV, &pos) == ERR_POS) return -1;
//
// only continue if the sample we want is in here.
//
if (lStart < pos.lPos || lStart >= pos.lPos + pos.lSize) return 0;
//
// if they give us a NULL buffer dummy up the cbBuffer so we return
// what we would have read if we had enough room
//
if (lpBuffer == NULL && cbBuffer == 0 && lSamples != 0) cbBuffer = 0x7FFFFFFF;
if (lSampleSize = psx->lSampleSize) {
// If they wanted to read/write only a "convenient amount",
// pretend the buffer is only large enough to hold the
// rest of this chunk.
if (lSamples == -1l) cbBuffer = min(cbBuffer, pos.lLength);
/* Fixed-length samples, if lSamples is zero, just fill the buffer. */
if (lSamples > 0) lSamples = min(lSamples, cbBuffer / lSampleSize); else lSamples = cbBuffer / lSampleSize;
lBytes = lSamples * lSampleSize; } else { lBytes = pos.lLength; }
if (lpBuffer == NULL) return lBytes;
if (cbBuffer < lBytes) return -1; // buffer is too small
#define WORDALIGN(x) ((x) + ((x) & 1))
if (lSampleSize == 0) { DWORD adw[2]; psx->Read(psx->hFile, pos.lOffset, sizeof(adw), adw); if (StreamFromFOURCC(adw[0]) != psx->stream) { Assert(0); } else { Assert(WORDALIGN(adw[1]) == WORDALIGN((DWORD)pos.lLength)); pos.lLength = adw[1]; // !!! Make netware video work!
lBytes = pos.lLength; } } else { #ifdef DEBUG
IDXPOS x; DWORD adw[2]; SearchIndex(psx, lStart, FIND_PREV|FIND_ANY, &x); psx->Read(psx->hFile, x.lOffset, sizeof(adw), adw); Assert(StreamFromFOURCC(adw[0]) == psx->stream); Assert(WORDALIGN(adw[1]) == WORDALIGN((DWORD)x.lLength)); #endif
}
cbBuffer = lBytes; lBytes = 0;
while (cbBuffer > 0) {
lSeek = pos.lOffset + 8; lRead = min(pos.lLength,cbBuffer);
if (lRead <= 0) { DPF3("!!!! lRead <= 0 in AVIStreamRead\n"); break; }
DPF3("StreamRead: %ld bytes @%ld\n", lRead, lSeek);
if (psx->Read(psx->hFile, lSeek, lRead, lpBuffer) != lRead) return -1;
lBytes += lRead; cbBuffer -= lRead;
if (cbBuffer > 0) { if (lSampleSize == 0) { DPF("%ld bytes to read, but sample size is 0!\n", cbBuffer); break; }
lpBuffer = (LPVOID) (((BYTE _huge *)lpBuffer) + lRead);
lStart += lRead / lSampleSize; lStart = SearchIndex(psx, lStart, FIND_PREV, &pos);
if (lStart == ERR_POS) break; } }
//
// success return number of bytes read
//
return lBytes; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api LONG | StreamWrite | write to a stream * ***************************************************************************/
EXTERN_C LONG StreamWrite( PSTREAMINDEX psx, LONG lStart, LONG lSamples, LPVOID lpBuffer, LONG cbBuffer) { return -1; }
|