switch to use STL containers, limit to 10 cache entries, don't clear cache on findkeyframe, removed inflight list as it was not needed, report error conditions better. This makes video work again
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34650 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
42ee486389
commit
2a9896ce47
@ -10,23 +10,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <Debug.h>
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
chunk_buffer::chunk_buffer()
|
|
||||||
:
|
|
||||||
buffer(NULL),
|
|
||||||
size(0),
|
|
||||||
capacity(0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
chunk_buffer::~chunk_buffer()
|
|
||||||
{
|
|
||||||
rtm_free(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
// #pragma mark -
|
||||||
|
|
||||||
@ -62,8 +46,11 @@ ChunkCache::MakeEmpty()
|
|||||||
{
|
{
|
||||||
ASSERT(IsLocked());
|
ASSERT(IsLocked());
|
||||||
|
|
||||||
fUnusedChunks.MoveFrom(&fChunks);
|
while (!fChunkCache.empty()) {
|
||||||
|
RecycleChunk(fChunkCache.front());
|
||||||
|
fChunkCache.pop();
|
||||||
|
}
|
||||||
|
|
||||||
release_sem(fWaitSem);
|
release_sem(fWaitSem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,18 +60,31 @@ ChunkCache::SpaceLeft() const
|
|||||||
{
|
{
|
||||||
ASSERT(IsLocked());
|
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);
|
return sizeof(chunk_buffer) + 2048 < rtm_available(fRealTimePool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
chunk_buffer*
|
chunk_buffer*
|
||||||
ChunkCache::NextChunk()
|
ChunkCache::NextChunk(Reader* reader, void* cookie)
|
||||||
{
|
{
|
||||||
ASSERT(IsLocked());
|
ASSERT(IsLocked());
|
||||||
|
|
||||||
chunk_buffer* chunk = fChunks.RemoveHead();
|
chunk_buffer* chunk = NULL;
|
||||||
if (chunk != NULL) {
|
|
||||||
fInFlightChunks.Add(chunk);
|
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);
|
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.
|
This means the chunk data can be overwritten again.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
@ -100,8 +100,11 @@ ChunkCache::RecycleChunk(chunk_buffer* chunk)
|
|||||||
{
|
{
|
||||||
ASSERT(IsLocked());
|
ASSERT(IsLocked());
|
||||||
|
|
||||||
fInFlightChunks.Remove(chunk);
|
rtm_free(chunk->buffer);
|
||||||
fUnusedChunks.Add(chunk);
|
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());
|
ASSERT(IsLocked());
|
||||||
|
|
||||||
// retrieve chunk buffer
|
// retrieve chunk buffer
|
||||||
chunk_buffer* chunk = fUnusedChunks.RemoveHead();
|
chunk_buffer* chunk = NULL;
|
||||||
if (chunk == NULL) {
|
if (fUnusedChunks.empty()) {
|
||||||
// allocate a new one
|
// allocate a new one
|
||||||
chunk = (chunk_buffer*)rtm_alloc(fRealTimePool, sizeof(chunk_buffer));
|
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;
|
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;
|
const void* buffer;
|
||||||
@ -133,6 +144,7 @@ ChunkCache::ReadNextChunk(Reader* reader, void* cookie)
|
|||||||
chunk->buffer = rtm_alloc(fRealTimePool, chunk->capacity);
|
chunk->buffer = rtm_alloc(fRealTimePool, chunk->capacity);
|
||||||
if (chunk->buffer == NULL) {
|
if (chunk->buffer == NULL) {
|
||||||
rtm_free(chunk);
|
rtm_free(chunk);
|
||||||
|
ERROR("RTM Pool empty allocating chunk buffer\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -141,6 +153,6 @@ ChunkCache::ReadNextChunk(Reader* reader, void* cookie)
|
|||||||
chunk->size = bufferSize;
|
chunk->size = bufferSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
fChunks.Add(chunk);
|
fChunkCache.push(chunk);
|
||||||
return chunk->status == B_OK;
|
return chunk->status == B_OK;
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,8 @@
|
|||||||
#include <Locker.h>
|
#include <Locker.h>
|
||||||
#include <MediaDefs.h>
|
#include <MediaDefs.h>
|
||||||
#include <RealtimeAlloc.h>
|
#include <RealtimeAlloc.h>
|
||||||
|
#include <queue>
|
||||||
#include <kernel/util/DoublyLinkedList.h>
|
#include <deque>
|
||||||
|
|
||||||
#include "ReaderPlugin.h"
|
#include "ReaderPlugin.h"
|
||||||
|
|
||||||
@ -18,14 +18,10 @@
|
|||||||
namespace BPrivate {
|
namespace BPrivate {
|
||||||
namespace media {
|
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;
|
struct chunk_buffer {
|
||||||
typedef DoublyLinkedList<chunk_buffer> ChunkList;
|
|
||||||
|
|
||||||
struct chunk_buffer : public DoublyLinkedListLinkImpl<chunk_buffer> {
|
|
||||||
chunk_buffer();
|
|
||||||
~chunk_buffer();
|
|
||||||
|
|
||||||
void* buffer;
|
void* buffer;
|
||||||
size_t size;
|
size_t size;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
@ -33,6 +29,8 @@ struct chunk_buffer : public DoublyLinkedListLinkImpl<chunk_buffer> {
|
|||||||
status_t status;
|
status_t status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef queue<chunk_buffer*> ChunkQueue;
|
||||||
|
typedef deque<chunk_buffer*> ChunkList;
|
||||||
|
|
||||||
class ChunkCache : public BLocker {
|
class ChunkCache : public BLocker {
|
||||||
public:
|
public:
|
||||||
@ -44,7 +42,7 @@ public:
|
|||||||
void MakeEmpty();
|
void MakeEmpty();
|
||||||
bool SpaceLeft() const;
|
bool SpaceLeft() const;
|
||||||
|
|
||||||
chunk_buffer* NextChunk();
|
chunk_buffer* NextChunk(Reader* reader, void* cookie);
|
||||||
void RecycleChunk(chunk_buffer* chunk);
|
void RecycleChunk(chunk_buffer* chunk);
|
||||||
bool ReadNextChunk(Reader* reader, void* cookie);
|
bool ReadNextChunk(Reader* reader, void* cookie);
|
||||||
|
|
||||||
@ -52,9 +50,8 @@ private:
|
|||||||
rtm_pool* fRealTimePool;
|
rtm_pool* fRealTimePool;
|
||||||
sem_id fWaitSem;
|
sem_id fWaitSem;
|
||||||
size_t fMaxBytes;
|
size_t fMaxBytes;
|
||||||
ChunkList fChunks;
|
ChunkQueue fChunkCache;
|
||||||
ChunkList fUnusedChunks;
|
ChunkList fUnusedChunks;
|
||||||
ChunkList fInFlightChunks;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -274,16 +274,7 @@ MediaExtractor::FindKeyFrame(int32 stream, uint32 seekTo, int64* _frame,
|
|||||||
if (info.status != B_OK)
|
if (info.status != B_OK)
|
||||||
return info.status;
|
return info.status;
|
||||||
|
|
||||||
BAutolock _(info.chunkCache);
|
return fReader->FindKeyFrame(info.cookie, seekTo, _frame, _time);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -307,13 +298,7 @@ MediaExtractor::GetNextChunk(int32 stream, const void** _chunkBuffer,
|
|||||||
_RecycleLastChunk(info);
|
_RecycleLastChunk(info);
|
||||||
|
|
||||||
// Retrieve next chunk - read it directly, if the cache is drained
|
// Retrieve next chunk - read it directly, if the cache is drained
|
||||||
chunk_buffer* chunk;
|
chunk_buffer* chunk = info.chunkCache->NextChunk(fReader, info.cookie);
|
||||||
do {
|
|
||||||
chunk = info.chunkCache->NextChunk();
|
|
||||||
if (chunk == NULL
|
|
||||||
&& !info.chunkCache->ReadNextChunk(fReader, info.cookie))
|
|
||||||
break;
|
|
||||||
} while (chunk == NULL);
|
|
||||||
|
|
||||||
if (chunk == NULL)
|
if (chunk == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user