diff --git a/src/kits/media/ChunkCache.cpp b/src/kits/media/ChunkCache.cpp index 94d9c151ca..68de9df754 100644 --- a/src/kits/media/ChunkCache.cpp +++ b/src/kits/media/ChunkCache.cpp @@ -10,23 +10,7 @@ #include #include -#include - - -chunk_buffer::chunk_buffer() - : - buffer(NULL), - size(0), - capacity(0) -{ -} - - -chunk_buffer::~chunk_buffer() -{ - rtm_free(buffer); -} - +#include "debug.h" // #pragma mark - @@ -62,8 +46,11 @@ ChunkCache::MakeEmpty() { ASSERT(IsLocked()); - fUnusedChunks.MoveFrom(&fChunks); - + while (!fChunkCache.empty()) { + RecycleChunk(fChunkCache.front()); + fChunkCache.pop(); + } + release_sem(fWaitSem); } @@ -73,18 +60,31 @@ ChunkCache::SpaceLeft() const { ASSERT(IsLocked()); + if (fChunkCache.size() >= CACHE_MAX_ENTRIES) { + return false; + } + + // If there is no more memory we are likely to fail soon after return sizeof(chunk_buffer) + 2048 < rtm_available(fRealTimePool); } chunk_buffer* -ChunkCache::NextChunk() +ChunkCache::NextChunk(Reader* reader, void* cookie) { ASSERT(IsLocked()); - chunk_buffer* chunk = fChunks.RemoveHead(); - if (chunk != NULL) { - fInFlightChunks.Add(chunk); + chunk_buffer* chunk = NULL; + + if (fChunkCache.empty()) { + TRACE("ChunkCache is empty, going direct to reader\n"); + if (ReadNextChunk(reader, cookie)) { + return NextChunk(reader, cookie); + } + } else { + chunk = fChunkCache.front(); + fChunkCache.pop(); + release_sem(fWaitSem); } @@ -92,7 +92,7 @@ ChunkCache::NextChunk() } -/*! Moves the specified chunk from the in-flight list to the unused list. +/* Moves the specified chunk to the unused list. This means the chunk data can be overwritten again. */ void @@ -100,8 +100,11 @@ ChunkCache::RecycleChunk(chunk_buffer* chunk) { ASSERT(IsLocked()); - fInFlightChunks.Remove(chunk); - fUnusedChunks.Add(chunk); + rtm_free(chunk->buffer); + chunk->capacity = 0; + chunk->size = 0; + chunk->buffer = NULL; + fUnusedChunks.push_back(chunk); } @@ -111,14 +114,22 @@ ChunkCache::ReadNextChunk(Reader* reader, void* cookie) ASSERT(IsLocked()); // retrieve chunk buffer - chunk_buffer* chunk = fUnusedChunks.RemoveHead(); - if (chunk == NULL) { + chunk_buffer* chunk = NULL; + if (fUnusedChunks.empty()) { // allocate a new one chunk = (chunk_buffer*)rtm_alloc(fRealTimePool, sizeof(chunk_buffer)); - if (chunk == NULL) + if (chunk == NULL) { + ERROR("RTM Pool empty allocating chunk buffer structure"); return false; + } + + chunk->size = 0; + chunk->capacity = 0; + chunk->buffer = NULL; - new(chunk) chunk_buffer; + } else { + chunk = fUnusedChunks.front(); + fUnusedChunks.pop_front(); } const void* buffer; @@ -133,6 +144,7 @@ ChunkCache::ReadNextChunk(Reader* reader, void* cookie) chunk->buffer = rtm_alloc(fRealTimePool, chunk->capacity); if (chunk->buffer == NULL) { rtm_free(chunk); + ERROR("RTM Pool empty allocating chunk buffer\n"); return false; } } @@ -141,6 +153,6 @@ ChunkCache::ReadNextChunk(Reader* reader, void* cookie) chunk->size = bufferSize; } - fChunks.Add(chunk); + fChunkCache.push(chunk); return chunk->status == B_OK; } diff --git a/src/kits/media/ChunkCache.h b/src/kits/media/ChunkCache.h index 3b912c6076..b0b4204a63 100644 --- a/src/kits/media/ChunkCache.h +++ b/src/kits/media/ChunkCache.h @@ -9,8 +9,8 @@ #include #include #include - -#include +#include +#include #include "ReaderPlugin.h" @@ -18,14 +18,10 @@ namespace BPrivate { namespace media { +// Limit to 10 entries, we might want to instead limit to a length of time +#define CACHE_MAX_ENTRIES 10 -struct chunk_buffer; -typedef DoublyLinkedList ChunkList; - -struct chunk_buffer : public DoublyLinkedListLinkImpl { - chunk_buffer(); - ~chunk_buffer(); - +struct chunk_buffer { void* buffer; size_t size; size_t capacity; @@ -33,6 +29,8 @@ struct chunk_buffer : public DoublyLinkedListLinkImpl { status_t status; }; +typedef queue ChunkQueue; +typedef deque ChunkList; class ChunkCache : public BLocker { public: @@ -44,7 +42,7 @@ public: void MakeEmpty(); bool SpaceLeft() const; - chunk_buffer* NextChunk(); + chunk_buffer* NextChunk(Reader* reader, void* cookie); void RecycleChunk(chunk_buffer* chunk); bool ReadNextChunk(Reader* reader, void* cookie); @@ -52,9 +50,8 @@ private: rtm_pool* fRealTimePool; sem_id fWaitSem; size_t fMaxBytes; - ChunkList fChunks; + ChunkQueue fChunkCache; ChunkList fUnusedChunks; - ChunkList fInFlightChunks; }; diff --git a/src/kits/media/MediaExtractor.cpp b/src/kits/media/MediaExtractor.cpp index 84d35ccda1..16f0e61df7 100644 --- a/src/kits/media/MediaExtractor.cpp +++ b/src/kits/media/MediaExtractor.cpp @@ -274,16 +274,7 @@ MediaExtractor::FindKeyFrame(int32 stream, uint32 seekTo, int64* _frame, if (info.status != B_OK) return info.status; - BAutolock _(info.chunkCache); - - status_t status = fReader->FindKeyFrame(info.cookie, seekTo, _frame, _time); - if (status != B_OK) - return status; - - // clear buffered chunks after seek - info.chunkCache->MakeEmpty(); - - return B_OK; + return fReader->FindKeyFrame(info.cookie, seekTo, _frame, _time); } @@ -307,13 +298,7 @@ MediaExtractor::GetNextChunk(int32 stream, const void** _chunkBuffer, _RecycleLastChunk(info); // Retrieve next chunk - read it directly, if the cache is drained - chunk_buffer* chunk; - do { - chunk = info.chunkCache->NextChunk(); - if (chunk == NULL - && !info.chunkCache->ReadNextChunk(fReader, info.cookie)) - break; - } while (chunk == NULL); + chunk_buffer* chunk = info.chunkCache->NextChunk(fReader, info.cookie); if (chunk == NULL) return B_NO_MEMORY;