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
This commit is contained in:
@@ -1,38 +1,118 @@
|
|||||||
|
#include <Locker.h>
|
||||||
|
|
||||||
#include "ChunkCache.h"
|
#include "ChunkCache.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
ChunkCache::ChunkCache()
|
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()
|
ChunkCache::~ChunkCache()
|
||||||
{
|
{
|
||||||
|
delete_sem(fGetWaitSem);
|
||||||
|
delete fLocker;
|
||||||
|
for (int i = 0; i < CHUNK_COUNT; i++) {
|
||||||
|
free(fChunkInfos[i].buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ChunkCache::MakeEmpty()
|
ChunkCache::MakeEmpty()
|
||||||
{
|
{
|
||||||
|
fLocker->Lock();
|
||||||
|
fEmptyChunkCount = CHUNK_COUNT - 1;
|
||||||
|
fReadyChunkCount = 0;
|
||||||
|
atomic_or(&fNeedsRefill, 1);
|
||||||
|
fLocker->Unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ChunkCache::NeedsRefill()
|
ChunkCache::NeedsRefill()
|
||||||
{
|
{
|
||||||
return false;
|
return atomic_or(&fNeedsRefill, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ChunkCache::GetNextChunk(void **chunkBuffer, int32 *chunkSize, media_header *mediaHeader)
|
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
|
void
|
||||||
ChunkCache::PutNextChunk(void *chunkBuffer, int32 chunkSize, const media_header &mediaHeader, status_t err)
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,17 @@ namespace BPrivate {
|
|||||||
namespace media {
|
namespace media {
|
||||||
|
|
||||||
|
|
||||||
|
struct chunk_info
|
||||||
|
{
|
||||||
|
chunk_info * next;
|
||||||
|
void * buffer;
|
||||||
|
int32 sizeUsed;
|
||||||
|
int32 sizeMax;
|
||||||
|
media_header mediaHeader;
|
||||||
|
status_t err;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class ChunkCache
|
class ChunkCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -20,9 +31,21 @@ public:
|
|||||||
void PutNextChunk(void *chunkBuffer, int32 chunkSize, const media_header &mediaHeader, status_t err);
|
void PutNextChunk(void *chunkBuffer, int32 chunkSize, const media_header &mediaHeader, status_t err);
|
||||||
|
|
||||||
private:
|
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 media
|
||||||
}; // namespace BPrivate
|
}; // namespace BPrivate
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ MediaExtractor::MediaExtractor(BDataIO *source, int32 flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start extractor thread
|
// 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);
|
fExtractorThread = spawn_thread(extractor_thread, "media extractor thread", 10, this);
|
||||||
resume_thread(fExtractorThread);
|
resume_thread(fExtractorThread);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user