Added an extra thread for chunk extraction. Using the ChunkCache, the ReadFrames call no longer needs to wait for the extractor, but can read it from a cache.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9481 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -13,6 +13,9 @@ MediaExtractor::MediaExtractor(BDataIO *source, int32 flags)
|
|||||||
CALLED();
|
CALLED();
|
||||||
fSource = source;
|
fSource = source;
|
||||||
fStreamInfo = 0;
|
fStreamInfo = 0;
|
||||||
|
fExtractorThread = -1;
|
||||||
|
fExtractorWaitSem = -1;
|
||||||
|
fTerminateExtractor = false;
|
||||||
|
|
||||||
fErr = _CreateReader(&fReader, &fStreamCount, &fMff, source);
|
fErr = _CreateReader(&fReader, &fStreamCount, &fMff, source);
|
||||||
if (fErr) {
|
if (fErr) {
|
||||||
@@ -30,6 +33,7 @@ MediaExtractor::MediaExtractor(BDataIO *source, int32 flags)
|
|||||||
fStreamInfo[i].hasCookie = true;
|
fStreamInfo[i].hasCookie = true;
|
||||||
fStreamInfo[i].infoBuffer = 0;
|
fStreamInfo[i].infoBuffer = 0;
|
||||||
fStreamInfo[i].infoBufferSize = 0;
|
fStreamInfo[i].infoBufferSize = 0;
|
||||||
|
fStreamInfo[i].chunkCache = new ChunkCache;
|
||||||
memset(&fStreamInfo[i].encodedFormat, 0, sizeof(fStreamInfo[i].encodedFormat));
|
memset(&fStreamInfo[i].encodedFormat, 0, sizeof(fStreamInfo[i].encodedFormat));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,16 +61,31 @@ MediaExtractor::MediaExtractor(BDataIO *source, int32 flags)
|
|||||||
printf("MediaExtractor::MediaExtractor: GetStreamInfo for stream %ld failed\n", i);
|
printf("MediaExtractor::MediaExtractor: GetStreamInfo for stream %ld failed\n", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// start extractor thread
|
||||||
|
fExtractorWaitSem = create_sem(0, "media extractor thread sem");
|
||||||
|
fExtractorThread = spawn_thread(extractor_thread, "media extractor thread", 10, this);
|
||||||
|
resume_thread(fExtractorThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MediaExtractor::~MediaExtractor()
|
MediaExtractor::~MediaExtractor()
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
|
|
||||||
|
// terminate extractor thread
|
||||||
|
fTerminateExtractor = true;
|
||||||
|
release_sem(fExtractorWaitSem);
|
||||||
|
status_t err;
|
||||||
|
wait_for_thread(fExtractorThread, &err);
|
||||||
|
delete_sem(fExtractorWaitSem);
|
||||||
|
|
||||||
// free all stream cookies
|
// free all stream cookies
|
||||||
|
// and chunk caches
|
||||||
for (int32 i = 0; i < fStreamCount; i++) {
|
for (int32 i = 0; i < fStreamCount; i++) {
|
||||||
if (fStreamInfo[i].hasCookie)
|
if (fStreamInfo[i].hasCookie)
|
||||||
fReader->FreeCookie(fStreamInfo[i].cookie);
|
fReader->FreeCookie(fStreamInfo[i].cookie);
|
||||||
|
delete fStreamInfo[i].chunkCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fReader)
|
if (fReader)
|
||||||
@@ -76,6 +95,7 @@ MediaExtractor::~MediaExtractor()
|
|||||||
// fSource is owned by the BMediaFile
|
// fSource is owned by the BMediaFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
MediaExtractor::InitCheck()
|
MediaExtractor::InitCheck()
|
||||||
{
|
{
|
||||||
@@ -83,6 +103,7 @@ MediaExtractor::InitCheck()
|
|||||||
return fErr;
|
return fErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
MediaExtractor::GetFileFormatInfo(media_file_format *mfi) const
|
MediaExtractor::GetFileFormatInfo(media_file_format *mfi) const
|
||||||
{
|
{
|
||||||
@@ -90,6 +111,7 @@ MediaExtractor::GetFileFormatInfo(media_file_format *mfi) const
|
|||||||
*mfi = fMff;
|
*mfi = fMff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int32
|
int32
|
||||||
MediaExtractor::StreamCount()
|
MediaExtractor::StreamCount()
|
||||||
{
|
{
|
||||||
@@ -97,12 +119,14 @@ MediaExtractor::StreamCount()
|
|||||||
return fStreamCount;
|
return fStreamCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const media_format *
|
const media_format *
|
||||||
MediaExtractor::EncodedFormat(int32 stream)
|
MediaExtractor::EncodedFormat(int32 stream)
|
||||||
{
|
{
|
||||||
return &fStreamInfo[stream].encodedFormat;
|
return &fStreamInfo[stream].encodedFormat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int64
|
int64
|
||||||
MediaExtractor::CountFrames(int32 stream) const
|
MediaExtractor::CountFrames(int32 stream) const
|
||||||
{
|
{
|
||||||
@@ -118,6 +142,7 @@ MediaExtractor::CountFrames(int32 stream) const
|
|||||||
return frameCount;
|
return frameCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bigtime_t
|
bigtime_t
|
||||||
MediaExtractor::Duration(int32 stream) const
|
MediaExtractor::Duration(int32 stream) const
|
||||||
{
|
{
|
||||||
@@ -133,6 +158,7 @@ MediaExtractor::Duration(int32 stream) const
|
|||||||
return duration;
|
return duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
MediaExtractor::Seek(int32 stream, uint32 seekTo,
|
MediaExtractor::Seek(int32 stream, uint32 seekTo,
|
||||||
int64 *frame, bigtime_t *time)
|
int64 *frame, bigtime_t *time)
|
||||||
@@ -143,27 +169,26 @@ MediaExtractor::Seek(int32 stream, uint32 seekTo,
|
|||||||
if (result != B_OK)
|
if (result != B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
// XXX clear buffered chunks
|
// clear buffered chunks
|
||||||
|
fStreamInfo[stream].chunkCache->MakeEmpty();
|
||||||
|
release_sem(fExtractorWaitSem);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
MediaExtractor::GetNextChunk(int32 stream,
|
MediaExtractor::GetNextChunk(int32 stream,
|
||||||
void **chunkBuffer, int32 *chunkSize,
|
void **chunkBuffer, int32 *chunkSize,
|
||||||
media_header *mediaHeader)
|
media_header *mediaHeader)
|
||||||
{
|
{
|
||||||
//CALLED();
|
status_t err;
|
||||||
// get buffered chunk
|
err = fStreamInfo[stream].chunkCache->GetNextChunk(chunkBuffer, chunkSize, mediaHeader);
|
||||||
|
release_sem(fExtractorWaitSem);
|
||||||
// XXX until this is done in a single extractor thread,
|
return err;
|
||||||
// XXX make calls to GetNextChunk thread save
|
|
||||||
static BLocker locker;
|
|
||||||
BAutolock lock(locker);
|
|
||||||
|
|
||||||
// XXX this should be done in a different thread, and double buffered for each stream
|
|
||||||
return fReader->GetNextChunk(fStreamInfo[stream].cookie, chunkBuffer, chunkSize, mediaHeader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MediaExtractorChunkProvider : public ChunkProvider
|
class MediaExtractorChunkProvider : public ChunkProvider
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@@ -183,6 +208,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
MediaExtractor::CreateDecoder(int32 stream, Decoder **decoder, media_codec_info *mci)
|
MediaExtractor::CreateDecoder(int32 stream, Decoder **decoder, media_codec_info *mci)
|
||||||
{
|
{
|
||||||
@@ -211,7 +237,43 @@ MediaExtractor::CreateDecoder(int32 stream, Decoder **decoder, media_codec_info
|
|||||||
}
|
}
|
||||||
|
|
||||||
(*decoder)->GetCodecInfo(mci);
|
(*decoder)->GetCodecInfo(mci);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
MediaExtractor::extractor_thread(void *arg)
|
||||||
|
{
|
||||||
|
static_cast<MediaExtractor *>(arg)->ExtractorThread();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaExtractor::ExtractorThread()
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
acquire_sem(fExtractorWaitSem);
|
||||||
|
if (fTerminateExtractor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool refill_done;
|
||||||
|
do {
|
||||||
|
refill_done = false;
|
||||||
|
for (int32 stream = 0; stream < fStreamCount; stream++) {
|
||||||
|
if (fStreamInfo[stream].chunkCache->NeedsRefill()) {
|
||||||
|
media_header mediaHeader;
|
||||||
|
void *chunkBuffer;
|
||||||
|
int32 chunkSize;
|
||||||
|
status_t err;
|
||||||
|
err = fReader->GetNextChunk(fStreamInfo[stream].cookie, &chunkBuffer, &chunkSize, &mediaHeader);
|
||||||
|
fStreamInfo[stream].chunkCache->PutNextChunk(chunkBuffer, chunkSize, mediaHeader, err);
|
||||||
|
refill_done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fTerminateExtractor)
|
||||||
|
return;
|
||||||
|
} while (refill_done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user