|
|
#include <win32.h>
#include <mmsystem.h>
#include "debug.h"
#include "aviidx.h"
#include "buffer.h"
#include <vfw.h>
#ifndef _WIN32
LONG glDosBufUsage; LPVOID glpDosBuf; LONG glDosBufSize; #endif
// Idea: keep a bunch (five, maybe) of buffers.
PBUFSYSTEM PASCAL InitBuffered(int nBuffers, LONG lBufSize, HSHFILE hshfile, PAVIINDEX px) { PBUFSYSTEM pb = (PBUFSYSTEM)LocalAlloc(LPTR, sizeof(BUFSYSTEM) + sizeof(BUFFER) * nBuffers);
int i; LONG l;
if (!pb) return NULL;
DPF("InitBuffered (%04x): %dx%ldK, pIndex = %p\n", pb, nBuffers, lBufSize / 1024, (DWORD_PTR) (LPVOID) px);
pb->nBuffers = nBuffers; pb->lBufSize = lBufSize;
pb->px = px; pb->lx = 0;
pb->lpBufMem = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE, lBufSize * nBuffers);
if (!pb->lpBufMem) { DPF("Couldn't allocate buffer memory!\n"); EndBuffered(pb); return NULL; }
pb->hshfile = hshfile;
l = shfileSeek(hshfile, 0, SEEK_CUR); pb->lFileLength = shfileSeek(hshfile, 0, SEEK_END); shfileSeek(hshfile, l, SEEK_SET);
for (i = 0; i < nBuffers; i++) { pb->aBuf[i].lpBuffer = (BYTE _huge *) pb->lpBufMem + i * lBufSize; pb->aBuf[i].lOffset = -1; }
return pb; }
LONG FAR PASCAL BufferedRead(PBUFSYSTEM pb, LONG lPos, LONG cb, LPVOID lp) { int i; LPVOID lpCopy; LONG cbCopy; LONG cbRead = cb; LONG l;
#if 0
if (cb > pb->lBufSize) { if (shfileSeek(pb->hshfile, lPos, SEEK_SET) == -1) return 0;
if (shfileRead(pb->hshfile, lp, cb) != cb) return 0;
return cb; } #endif
while (cb > 0) {
if (lPos >= pb->lFileLength) break; // Find a buffer.
for (i = 0; i < pb->nBuffers; i++) { if (pb->aBuf[i].lOffset < 0) continue;
if (pb->aBuf[i].lOffset <= lPos && pb->aBuf[i].lOffset + pb->aBuf[i].lLength > lPos) break; }
// If we didn't find a buffer with valid data, read more.
if (i >= pb->nBuffers) { i = pb->iNextBuf;
if (pb->px) {
LONG off,len;
for (l = pb->lx; l>=0 && l<pb->px->nIndex; ) {
off = IndexOffset(pb->px, l); len = IndexLength(pb->px, l) + 2*sizeof(DWORD);
if (off <= lPos && lPos < off + len) break;
if (lPos < off) l--; else l++; }
if (l == pb->px->nIndex || l < 0) { DPF("Ran out of index!\n"); goto ack; }
if (len > pb->lBufSize) { DPF("Chunk is bigger than buffer.\n"); goto ack; }
pb->aBuf[i].lOffset = off; pb->aBuf[i].lLength = len;
DPF2("Buffer: Reading %lx bytes at %lx\n", pb->aBuf[i].lLength, pb->aBuf[i].lOffset);
//
// read as many records that will fit in our buffer
//
// we should scan backward!
//
for (l++; l<pb->px->nIndex; l++) {
off = IndexOffset(pb->px, l); len = IndexLength(pb->px, l) + 2*sizeof(DWORD);
if (off < pb->aBuf[i].lOffset + pb->aBuf[i].lLength) continue;
if (off != pb->aBuf[i].lOffset + pb->aBuf[i].lLength) break;
if (pb->aBuf[i].lLength + len > pb->lBufSize) break;
pb->aBuf[i].lLength += len;
DPF2(" Reading %lx bytes at %lx\n", pb->aBuf[i].lLength, pb->aBuf[i].lOffset); }
if (l < pb->px->nIndex) pb->lx = l; // save this for next time.
} else { ack: // Always read aligned with the buffer size....
pb->aBuf[i].lOffset = lPos - (lPos % pb->lBufSize);
pb->aBuf[i].lLength = min(pb->lFileLength - pb->aBuf[i].lOffset, pb->lBufSize);
DPF("Buffer: Reading %lx bytes at %lx\n", pb->aBuf[i].lLength, pb->aBuf[i].lOffset); }
shfileSeek(pb->hshfile, pb->aBuf[i].lOffset, SEEK_SET); #ifndef _WIN32
if (glpDosBuf) { if (shfileRead(pb->hshfile, glpDosBuf, pb->aBuf[i].lLength) != pb->aBuf[i].lLength) return 0; hmemcpy(pb->aBuf[i].lpBuffer, glpDosBuf, pb->aBuf[i].lLength); } else #endif
{ if (shfileRead(pb->hshfile, pb->aBuf[i].lpBuffer, pb->aBuf[i].lLength) != pb->aBuf[i].lLength) return 0; }
// !!! We should use an LRU algorithm or something here....
pb->iNextBuf = (i + 1) % pb->nBuffers; }
lpCopy = (BYTE _huge *) pb->aBuf[i].lpBuffer + lPos - pb->aBuf[i].lOffset;
cbCopy = min(cb, pb->aBuf[i].lLength - (lPos - pb->aBuf[i].lOffset));
hmemcpy(lp, lpCopy, cbCopy);
lp = (BYTE _huge *) lp + cbCopy; cb -= cbCopy; lPos += cbCopy; }
return cbRead; }
LONG FAR PASCAL BeginBufferedStreaming(PBUFSYSTEM pb, BOOL fForward) { if (pb->fStreaming++) return 0;
DPF("Streaming....\n");
#ifndef _WIN32
if (pb->px) { if (glDosBufSize < pb->lBufSize #ifdef DEBUG
&& GetProfileInt("avifile", "dosbuffer", 1) #endif
) { LPVOID lpDosBuf; lpDosBuf = (LPVOID)MAKELONG(0, LOWORD(GlobalDosAlloc(pb->lBufSize))); if (!lpDosBuf) { DPF("Couldn't get DOS buffer!\n"); } else { GlobalReAlloc((HANDLE)HIWORD(lpDosBuf), 0, GMEM_MODIFY|GMEM_SHARE);
if (glpDosBuf) GlobalDosFree(HIWORD(glpDosBuf));
glpDosBuf = lpDosBuf; glDosBufSize = pb->lBufSize; } } if (glpDosBuf && (glDosBufSize >= pb->lBufSize)) { pb->fUseDOSBuf = TRUE; glDosBufUsage++; } else pb->fUseDOSBuf = FALSE; } #endif
return 0; }
LONG FAR PASCAL EndBufferedStreaming(PBUFSYSTEM pb) { if (!pb->fStreaming) return AVIERR_INTERNAL;
if (--pb->fStreaming) return 0;
DPF("No longer streaming....\n");
#ifndef _WIN32
if (pb->fUseDOSBuf) { if (--glDosBufUsage == 0) { if (glpDosBuf) GlobalDosFree(HIWORD(glpDosBuf));
glpDosBuf = NULL; }
pb->fUseDOSBuf = FALSE; } #endif
return 0; }
void FAR PASCAL EndBuffered(PBUFSYSTEM pb) { DPF("Freeing bufsystem %04x....\n", pb);
if (pb->lpBufMem) GlobalFreePtr(pb->lpBufMem);
#ifndef _WIN32
if (pb->fUseDOSBuf) { if (--glDosBufUsage == 0) { if (glpDosBuf) GlobalDosFree(HIWORD(glpDosBuf));
glpDosBuf = NULL; glDosBufSize = 0; } } #endif
LocalFree((HLOCAL)pb); }
|