From f14dfaa7b961af138737d0e09cd80ae61a29c9aa Mon Sep 17 00:00:00 2001 From: beveloper Date: Sun, 24 Oct 2004 17:15:50 +0000 Subject: [PATCH] Completed implementation of chunk caching. Playback from harddisk is now much better, crackling should be gone. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9485 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kits/media/ChunkCache.cpp | 84 ++++++++++++++++++++++++++++++- src/kits/media/ChunkCache.h | 25 ++++++++- src/kits/media/MediaExtractor.cpp | 2 +- 3 files changed, 107 insertions(+), 4 deletions(-) diff --git a/src/kits/media/ChunkCache.cpp b/src/kits/media/ChunkCache.cpp index ff301e8a2d..c88570d542 100644 --- a/src/kits/media/ChunkCache.cpp +++ b/src/kits/media/ChunkCache.cpp @@ -1,38 +1,118 @@ +#include + #include "ChunkCache.h" #include "debug.h" ChunkCache::ChunkCache() { + fLocker = new BLocker("media chunk cache locker"); + + // fEmptyChunkCount must be one less than the real chunk count, + // because the buffer returned by GetNextChunk must be preserved + // until the next call of that function, and must not be overwritten. + fEmptyChunkCount = CHUNK_COUNT - 1; + fReadyChunkCount = 0; + fNeedsRefill = 1; + + fGetWaitSem = create_sem(0, "media chunk cache sem"); + + fNextPut = &fChunkInfos[0]; + fNextGet = &fChunkInfos[0]; + + for (int i = 0; i < CHUNK_COUNT; i++) { + fChunkInfos[i].next = (i == CHUNK_COUNT -1) ? &fChunkInfos[0] : &fChunkInfos[i + 1]; + fChunkInfos[i].buffer = NULL; + fChunkInfos[i].sizeUsed = 0; + fChunkInfos[i].sizeMax = 0; + fChunkInfos[i].err = B_ERROR; + } } ChunkCache::~ChunkCache() { + delete_sem(fGetWaitSem); + delete fLocker; + for (int i = 0; i < CHUNK_COUNT; i++) { + free(fChunkInfos[i].buffer); + } } void ChunkCache::MakeEmpty() { + fLocker->Lock(); + fEmptyChunkCount = CHUNK_COUNT - 1; + fReadyChunkCount = 0; + atomic_or(&fNeedsRefill, 1); + fLocker->Unlock(); } bool ChunkCache::NeedsRefill() { - return false; + return atomic_or(&fNeedsRefill, 0); } status_t ChunkCache::GetNextChunk(void **chunkBuffer, int32 *chunkSize, media_header *mediaHeader) { - return B_ERROR; +// printf("ChunkCache::GetNextChunk: %p fEmptyChunkCount %ld, fReadyChunkCount %ld\n", fNextGet, fEmptyChunkCount, fReadyChunkCount); +retry: + acquire_sem(fGetWaitSem); + + fLocker->Lock(); + if (fReadyChunkCount == 0) { + fLocker->Unlock(); + printf("ChunkCache::GetNextChunk: %p retrying\n", fNextGet); + goto retry; + } + fEmptyChunkCount++; + fReadyChunkCount--; + atomic_or(&fNeedsRefill, 1); + fLocker->Unlock(); + + *chunkBuffer = fNextGet->buffer; + *chunkSize = fNextGet->sizeUsed; + *mediaHeader = fNextGet->mediaHeader; + status_t err = fNextGet->err; + fNextGet = fNextGet->next; + + return err; } void ChunkCache::PutNextChunk(void *chunkBuffer, int32 chunkSize, const media_header &mediaHeader, status_t err) { +// printf("ChunkCache::PutNextChunk: %p fEmptyChunkCount %ld, fReadyChunkCount %ld\n", fNextPut, fEmptyChunkCount, fReadyChunkCount); + + if (err == B_OK) { + if (fNextPut->sizeMax < chunkSize) { +// printf("ChunkCache::PutNextChunk: %p resizing from %ld to %ld\n", fNextPut, fNextPut->sizeMax, chunkSize); + free(fNextPut->buffer); + fNextPut->buffer = malloc((chunkSize + 1024) & ~1023); + fNextPut->sizeMax = chunkSize; + } + memcpy(fNextPut->buffer, chunkBuffer, chunkSize); + fNextPut->sizeUsed = chunkSize; + } + + fNextPut->mediaHeader = mediaHeader; + fNextPut->err = err; + + fNextPut = fNextPut->next; + + fLocker->Lock(); + fEmptyChunkCount--; + fReadyChunkCount++; + if (fEmptyChunkCount == 0) + atomic_and(&fNeedsRefill, 0); + fLocker->Unlock(); + + release_sem(fGetWaitSem); } diff --git a/src/kits/media/ChunkCache.h b/src/kits/media/ChunkCache.h index 3bcfb768a2..255dd57dd0 100644 --- a/src/kits/media/ChunkCache.h +++ b/src/kits/media/ChunkCache.h @@ -7,6 +7,17 @@ namespace BPrivate { namespace media { +struct chunk_info +{ + chunk_info * next; + void * buffer; + int32 sizeUsed; + int32 sizeMax; + media_header mediaHeader; + status_t err; +}; + + class ChunkCache { public: @@ -20,9 +31,21 @@ public: void PutNextChunk(void *chunkBuffer, int32 chunkSize, const media_header &mediaHeader, status_t err); private: - + enum { CHUNK_COUNT = 5 }; + + chunk_info * fNextPut; + chunk_info * fNextGet; + chunk_info fChunkInfos[CHUNK_COUNT]; + + sem_id fGetWaitSem; + int32 fEmptyChunkCount; + int32 fReadyChunkCount; + int32 fNeedsRefill; + + BLocker * fLocker; }; + }; // namespace media }; // namespace BPrivate diff --git a/src/kits/media/MediaExtractor.cpp b/src/kits/media/MediaExtractor.cpp index ae5760cc0e..d9caadf737 100644 --- a/src/kits/media/MediaExtractor.cpp +++ b/src/kits/media/MediaExtractor.cpp @@ -63,7 +63,7 @@ MediaExtractor::MediaExtractor(BDataIO *source, int32 flags) } // start extractor thread - fExtractorWaitSem = create_sem(0, "media extractor thread sem"); + fExtractorWaitSem = create_sem(1, "media extractor thread sem"); fExtractorThread = spawn_thread(extractor_thread, "media extractor thread", 10, this); resume_thread(fExtractorThread); }