www.pudn.com > XvidQP.rar > FastReadStream.cpp
// VirtualDub - Video processing and capture application // Copyright (C) 1998-2001 Avery Lee // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include#include #include #include #include #include "Error.h" #include "FastReadStream.h" class FastReadStreamHeader { public: __int64 i64BlockNo; long fAccessedBits; long lBytes; long lAge; long lHistoryVal; }; FastReadStream::FastReadStream(HANDLE hFile, long lBlockCount, long lBlockSize) { this->hFile = hFile; this->iFile = -1; _Init(lBlockCount, lBlockSize); } FastReadStream::FastReadStream(int iFile, long lBlockCount, long lBlockSize) { this->hFile = INVALID_HANDLE_VALUE; this->iFile = iFile; _Init(lBlockCount, lBlockSize); } void FastReadStream::_Init(long lBlockCount, long lBlockSize) { this->lBlockCount = lBlockCount; this->lBlockSize = (lBlockSize + 4095) & -4096; this->pHeaders = new FastReadStreamHeader[this->lBlockCount]; this->pBuffer = VirtualAlloc(NULL, this->lBlockCount * this->lBlockSize, MEM_COMMIT, PAGE_READWRITE); if (!this->pHeaders || !this->pBuffer) { delete this->pHeaders; if (this->pBuffer) VirtualFree(this->pBuffer, 0, MEM_RELEASE); this->pHeaders = NULL; this->pBuffer = NULL; } else { Flush(); } lHistory = 0; } bool FastReadStream::Ready() { return pHeaders && pBuffer; } FastReadStream::~FastReadStream() { delete pHeaders; if (pBuffer) VirtualFree(pBuffer, 0, MEM_RELEASE); } /////////////////////////////////////////////////////////////////////////// #pragma function(memcpy) long FastReadStream::Read(int stream, __int64 i64Pos, void *pDest, long lBytes) { long lOffset, lActual = 0, lToCopy; __int64 i64BlockNo; char *pBuffer2 = (char *)pDest; int iCacheBlock; // First block number and offset... i64BlockNo = i64Pos / lBlockSize; lOffset = i64Pos % lBlockSize; // _RPT3(0,"Read request: %ld bytes, pos %I64x, first block %I64d\n", lBytes, i64Pos, i64BlockNo); while(lBytes) { long lInBlock; lToCopy = lBlockSize - lOffset; if (lToCopy > lBytes) lToCopy = lBytes; iCacheBlock = _Commit(stream, i64BlockNo); lInBlock = pHeaders[iCacheBlock].lBytes - lOffset; // _RPT4(0,"(%ld) Reading %ld from cache block %d, offset %ld\n", stream, lToCopy, iCacheBlock, lOffset); if (lInBlock < lToCopy) { if (lInBlock > 0) { memcpy(pBuffer2, (char *)pBuffer + iCacheBlock * lBlockSize + lOffset, lInBlock); lActual += lInBlock; } break; } else memcpy(pBuffer2, (char *)pBuffer + iCacheBlock * lBlockSize + lOffset, lToCopy); pBuffer2 += lToCopy; lBytes -= lToCopy; lActual += lToCopy; ++i64BlockNo; lOffset = 0; } return lActual; } void FastReadStream::Flush() { for(int i=0; i NotLone bits fStreamNotLoneBits |= fStreamEncounteredBits & pHeaders[i].fAccessedBits; fStreamEncounteredBits |= pHeaders[i].fAccessedBits; } // Look at the histories, and choose a few candidates. for(i=0; i pHeaders[iOurLowest].lAge) iOurLowest = i; // Global oldest block if (iGlobalLowest<0 || lThisHistory > pHeaders[iGlobalLowest].lAge) iGlobalLowest = i; // Preferred lowest block if (pHeaders[i].fAccessedBits & fStreamMask && !(pHeaders[i].fAccessedBits & ~fStreamNotLoneBits)) if (iPreferred<0 || lThisHistory > pHeaders[iPreferred].lAge) iPreferred = i; } return iPreferred>=0 ? iPreferred : iOurLowest>=0 ? iOurLowest : iGlobalLowest; } int FastReadStream::_Commit(int stream, __int64 i64BlockNo) { int iCacheBlock; int i; // Already have the block? for(i=0; i = 0) { int iActual; if (-1 == _lseeki64(iFile, i64BlockNo * lBlockSize, SEEK_SET)) throw MyError("FastRead seek error: %s.", strerror(errno)); iActual = _read(iFile, (char *)pBuffer + iCacheBlock * lBlockSize, lBlockSize); if (iActual < 0) throw MyError("FastRead read error: %s.", strerror(errno)); pHeaders[iCacheBlock].lBytes = iActual; } else { LONG lLow = (LONG)i64BlockNo*lBlockSize; LONG lHigh = (LONG)((i64BlockNo*lBlockSize) >> 32); DWORD err, dwActual; if (0xFFFFFFFF == SetFilePointer(hFile, lLow, &lHigh, FILE_BEGIN)) if ((err = GetLastError()) != NO_ERROR) throw MyWin32Error("FastRead seek error: %%s", GetLastError()); if (!ReadFile(hFile, (char *)pBuffer + iCacheBlock * lBlockSize, lBlockSize, &dwActual, NULL)) throw MyWin32Error("FastRead read error: %%s", GetLastError()); pHeaders[iCacheBlock].lBytes = dwActual; } pHeaders[iCacheBlock].i64BlockNo = i64BlockNo; pHeaders[iCacheBlock].fAccessedBits = 1L<