FastReadStream.cpp
上传用户:tuheem
上传日期:2007-05-01
资源大小:21889k
文件大小:7k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. // VirtualDub - Video processing and capture application
  2. // Copyright (C) 1998-2001 Avery Lee
  3. //
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; either version 2 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program; if not, write to the Free Software
  16. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. #include <windows.h>
  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <io.h>
  21. #include <crtdbg.h>
  22. #include "Error.h"
  23. #include "FastReadStream.h"
  24. class FastReadStreamHeader {
  25. public:
  26. __int64 i64BlockNo;
  27. long fAccessedBits;
  28. long lBytes;
  29. long lAge;
  30. long lHistoryVal;
  31. };
  32. FastReadStream::FastReadStream(HANDLE hFile, long lBlockCount, long lBlockSize) {
  33. this->hFile = hFile;
  34. this->iFile = -1;
  35. _Init(lBlockCount, lBlockSize);
  36. }
  37. FastReadStream::FastReadStream(int iFile, long lBlockCount, long lBlockSize) {
  38. this->hFile = INVALID_HANDLE_VALUE;
  39. this->iFile = iFile;
  40. _Init(lBlockCount, lBlockSize);
  41. }
  42. void FastReadStream::_Init(long lBlockCount, long lBlockSize) {
  43. this->lBlockCount = lBlockCount;
  44. this->lBlockSize = (lBlockSize + 4095) & -4096;
  45. this->pHeaders = new FastReadStreamHeader[this->lBlockCount];
  46. this->pBuffer = VirtualAlloc(NULL, this->lBlockCount * this->lBlockSize, MEM_COMMIT, PAGE_READWRITE);
  47. if (!this->pHeaders || !this->pBuffer) {
  48. delete this->pHeaders;
  49. if (this->pBuffer) VirtualFree(this->pBuffer, 0, MEM_RELEASE);
  50. this->pHeaders = NULL;
  51. this->pBuffer = NULL;
  52. } else {
  53. Flush();
  54. }
  55. lHistory = 0;
  56. }
  57. bool FastReadStream::Ready() {
  58. return pHeaders && pBuffer;
  59. }
  60. FastReadStream::~FastReadStream() {
  61. delete pHeaders;
  62. if (pBuffer) VirtualFree(pBuffer, 0, MEM_RELEASE);
  63. }
  64. ///////////////////////////////////////////////////////////////////////////
  65. #pragma function(memcpy)
  66. long FastReadStream::Read(int stream, __int64 i64Pos, void *pDest, long lBytes) {
  67. long lOffset, lActual = 0, lToCopy;
  68. __int64 i64BlockNo;
  69. char *pBuffer2 = (char *)pDest;
  70. int iCacheBlock;
  71. // First block number and offset...
  72. i64BlockNo = i64Pos / lBlockSize;
  73. lOffset = i64Pos % lBlockSize;
  74. // _RPT3(0,"Read request: %ld bytes, pos %I64x, first block %I64dn", lBytes, i64Pos, i64BlockNo);
  75. while(lBytes) {
  76. long lInBlock;
  77. lToCopy = lBlockSize - lOffset;
  78. if (lToCopy > lBytes) lToCopy = lBytes;
  79. iCacheBlock = _Commit(stream, i64BlockNo);
  80. lInBlock = pHeaders[iCacheBlock].lBytes - lOffset;
  81. // _RPT4(0,"(%ld) Reading %ld from cache block %d, offset %ldn", stream, lToCopy, iCacheBlock, lOffset);
  82. if (lInBlock < lToCopy) {
  83. if (lInBlock > 0) {
  84. memcpy(pBuffer2, (char *)pBuffer + iCacheBlock * lBlockSize + lOffset, lInBlock);
  85. lActual += lInBlock;
  86. }
  87. break;
  88. } else
  89. memcpy(pBuffer2, (char *)pBuffer + iCacheBlock * lBlockSize + lOffset, lToCopy);
  90. pBuffer2 += lToCopy;
  91. lBytes -= lToCopy;
  92. lActual += lToCopy;
  93. ++i64BlockNo;
  94. lOffset = 0;
  95. }
  96. return lActual;
  97. }
  98. void FastReadStream::Flush() {
  99. for(int i=0; i<lBlockCount; i++) {
  100. pHeaders[i].i64BlockNo = -1;
  101. pHeaders[i].fAccessedBits = 0;
  102. pHeaders[i].lHistoryVal = 0;
  103. }
  104. lHistory = 0;
  105. }
  106. ///////////////////////////////////////////////////////////////////////////
  107. int FastReadStream::_PickVictim(int stream) {
  108. int i;
  109. int iLoneBlock = -1;
  110. long fStreamEncounteredBits=0, fStreamNotLoneBits=0;
  111. int iOurLowest=-1, iGlobalLowest=-1, iPreferred=-1;
  112. long fStreamMask = 1L<<stream;
  113. // Look for an unused block.
  114. for(i=0; i<lBlockCount; i++)
  115. if (pHeaders[i].i64BlockNo == -1)
  116. return i;
  117. // Compile a list of streams with lone blocks.  These can't be replaced.
  118. // Look for our lone block.
  119. for(i=0; i<lBlockCount; i++) {
  120. // Encountered bits -> NotLone bits
  121. fStreamNotLoneBits |= fStreamEncounteredBits & pHeaders[i].fAccessedBits;
  122. fStreamEncounteredBits |= pHeaders[i].fAccessedBits;
  123. }
  124. // Look at the histories, and choose a few candidates.
  125. for(i=0; i<lBlockCount; i++) {
  126. long lThisHistory = lHistory - pHeaders[i].lHistoryVal;
  127. if (lThisHistory<0) lThisHistory = 0x7FFFFFFF;
  128. pHeaders[i].lAge = lThisHistory;
  129. // Our oldest block
  130. if (pHeaders[i].fAccessedBits & fStreamMask)
  131. if (iOurLowest<0 || lThisHistory > pHeaders[iOurLowest].lAge)
  132. iOurLowest = i;
  133. // Global oldest block
  134. if (iGlobalLowest<0 || lThisHistory > pHeaders[iGlobalLowest].lAge)
  135. iGlobalLowest = i;
  136. // Preferred lowest block
  137. if (pHeaders[i].fAccessedBits & fStreamMask
  138. && !(pHeaders[i].fAccessedBits & ~fStreamNotLoneBits))
  139. if (iPreferred<0 || lThisHistory > pHeaders[iPreferred].lAge)
  140. iPreferred = i;
  141. }
  142. return iPreferred>=0 ? iPreferred : iOurLowest>=0 ? iOurLowest : iGlobalLowest;
  143. }
  144. int FastReadStream::_Commit(int stream, __int64 i64BlockNo) {
  145. int iCacheBlock;
  146. int i;
  147. // Already have the block?
  148. for(i=0; i<lBlockCount; i++)
  149. if (pHeaders[i].i64BlockNo == i64BlockNo) {
  150. pHeaders[i].fAccessedBits |= 1L<<stream;
  151. // _RPT1(0,"Commit(%I64d): cache hitn", i64BlockNo);
  152. return i;
  153. }
  154. // Pick a replacement candidate.
  155. iCacheBlock = _PickVictim(stream);
  156. // Replace it.
  157. try {
  158. ++lHistory;
  159. _RPT2(0,"Commit(%I64d): cache miss (stream %d)n", i64BlockNo, stream);
  160. if (iFile >= 0) {
  161. int iActual;
  162. if (-1 == _lseeki64(iFile, i64BlockNo * lBlockSize, SEEK_SET))
  163. throw MyError("FastRead seek error: %s.", strerror(errno));
  164. iActual = _read(iFile, (char *)pBuffer + iCacheBlock * lBlockSize, lBlockSize);
  165. if (iActual < 0)
  166. throw MyError("FastRead read error: %s.", strerror(errno));
  167. pHeaders[iCacheBlock].lBytes = iActual;
  168. } else {
  169. LONG lLow = (LONG)i64BlockNo*lBlockSize;
  170. LONG lHigh = (LONG)((i64BlockNo*lBlockSize) >> 32);
  171. DWORD err, dwActual;
  172. if (0xFFFFFFFF == SetFilePointer(hFile, lLow, &lHigh, FILE_BEGIN))
  173. if ((err = GetLastError()) != NO_ERROR)
  174. throw MyWin32Error("FastRead seek error: %%s", GetLastError());
  175. if (!ReadFile(hFile, (char *)pBuffer + iCacheBlock * lBlockSize, lBlockSize, &dwActual, NULL))
  176. throw MyWin32Error("FastRead read error: %%s", GetLastError());
  177. pHeaders[iCacheBlock].lBytes = dwActual;
  178. }
  179. pHeaders[iCacheBlock].i64BlockNo = i64BlockNo;
  180. pHeaders[iCacheBlock].fAccessedBits = 1L<<stream;
  181. pHeaders[iCacheBlock].lHistoryVal = lHistory;
  182. } catch(...) {
  183. pHeaders[iCacheBlock].i64BlockNo = -1;
  184. pHeaders[iCacheBlock].fAccessedBits = 0;
  185. }
  186. return iCacheBlock;
  187. }