windows-nt/Source/XPSP1/NT/multimedia/media/avi/avifile/aviidx.cpp

1091 lines
27 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/******************************************************************************
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;
}