#include #include #include "debug.h" #include "aviidx.h" #include "buffer.h" #include #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 && lpx->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++; lpx->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); }