* ChunkCache::fLocker is now aggregated.

* Cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34239 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2009-11-25 11:51:24 +00:00
parent 40fddd06d6
commit 608d959d73
4 changed files with 229 additions and 235 deletions

View File

@ -1,78 +1,85 @@
/*
* Copyright 2004-2007, Marcus Overhagen. All rights reserved.
* Copyright 2008, Maurice Kalinowski. All rights reserved.
* Distributed under the terms of the MIT License.
*/
#ifndef _MEDIA_EXTRACTOR_H #ifndef _MEDIA_EXTRACTOR_H
#define _MEDIA_EXTRACTOR_H #define _MEDIA_EXTRACTOR_H
#include "ReaderPlugin.h" #include "ReaderPlugin.h"
#include "DecoderPlugin.h" #include "DecoderPlugin.h"
namespace BPrivate { namespace BPrivate {
namespace media { namespace media {
class ChunkCache; class ChunkCache;
struct stream_info struct stream_info {
{
status_t status; status_t status;
void * cookie; void* cookie;
bool hasCookie; bool hasCookie;
const void * infoBuffer; const void* infoBuffer;
size_t infoBufferSize; size_t infoBufferSize;
ChunkCache * chunkCache; ChunkCache* chunkCache;
media_format encodedFormat; media_format encodedFormat;
}; };
class MediaExtractor class MediaExtractor {
{
public: public:
MediaExtractor(BDataIO * source, int32 flags); MediaExtractor(BDataIO* source, int32 flags);
~MediaExtractor(); ~MediaExtractor();
status_t InitCheck(); status_t InitCheck();
void GetFileFormatInfo(media_file_format *mfi) const; void GetFileFormatInfo(
media_file_format* fileFormat) const;
int32 StreamCount(); int32 StreamCount();
const char* Copyright(); const char* Copyright();
const media_format * EncodedFormat(int32 stream); const media_format* EncodedFormat(int32 stream);
int64 CountFrames(int32 stream) const; int64 CountFrames(int32 stream) const;
bigtime_t Duration(int32 stream) const; bigtime_t Duration(int32 stream) const;
status_t Seek(int32 stream, uint32 seekTo, status_t Seek(int32 stream, uint32 seekTo, int64* _frame,
int64 *frame, bigtime_t *time); bigtime_t* _time);
status_t FindKeyFrame(int32 stream, uint32 seekTo, status_t FindKeyFrame(int32 stream, uint32 seekTo,
int64 *frame, bigtime_t *time) const; int64* _frame, bigtime_t* _time) const;
status_t GetNextChunk(int32 stream, status_t GetNextChunk(int32 stream,
const void **chunkBuffer, size_t *chunkSize, const void** _chunkBuffer,
media_header *mediaHeader); size_t* _chunkSize,
media_header* mediaHeader);
status_t CreateDecoder(int32 stream, Decoder **decoder, status_t CreateDecoder(int32 stream, Decoder** _decoder,
media_codec_info *mci); media_codec_info* codecInfo);
private: private:
static int32 extractor_thread(void *arg); static int32 _ExtractorEntry(void* arg);
void ExtractorThread(); void _ExtractorThread();
private: private:
status_t fErr; status_t fInitStatus;
sem_id fExtractorWaitSem; sem_id fExtractorWaitSem;
thread_id fExtractorThread; thread_id fExtractorThread;
volatile bool fTerminateExtractor; volatile bool fTerminateExtractor;
BDataIO *fSource; BDataIO* fSource;
Reader *fReader; Reader* fReader;
stream_info * fStreamInfo; stream_info* fStreamInfo;
int32 fStreamCount; int32 fStreamCount;
media_file_format fMff; media_file_format fFileFormat;
}; };
}; // namespace media } // namespace media
}; // namespace BPrivate } // namespace BPrivate
using namespace BPrivate::media; using namespace BPrivate::media;
#endif #endif // _MEDIA_EXTRACTOR_H

View File

@ -1,42 +1,26 @@
/* /*
* Copyright (c) 2004, Marcus Overhagen * Copyright 2004, Marcus Overhagen. All rights reserved.
* All rights reserved. * Distributed under the terms of the MIT License.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include <string.h>
#include <Locker.h>
#include "ChunkCache.h" #include "ChunkCache.h"
#include <string.h>
#include <Autolock.h>
#include "debug.h" #include "debug.h"
ChunkCache::ChunkCache() ChunkCache::ChunkCache()
:
fLocker("media chunk cache locker")
{ {
fLocker = new BLocker("media chunk cache locker");
// fEmptyChunkCount must be one less than the real chunk count, // fEmptyChunkCount must be one less than the real chunk count,
// because the buffer returned by GetNextChunk must be preserved // because the buffer returned by GetNextChunk must be preserved
// until the next call of that function, and must not be overwritten. // until the next call of that function, and must not be overwritten.
fEmptyChunkCount = CHUNK_COUNT - 1; fEmptyChunkCount = CHUNK_COUNT - 1;
fReadyChunkCount = 0; fReadyChunkCount = 0;
fNeedsRefill = 1; fNeedsRefill = 1;
@ -45,13 +29,14 @@ ChunkCache::ChunkCache()
fNextPut = &fChunkInfos[0]; fNextPut = &fChunkInfos[0];
fNextGet = &fChunkInfos[0]; fNextGet = &fChunkInfos[0];
for (int i = 0; i < CHUNK_COUNT; i++) { for (int i = 0; i < CHUNK_COUNT; i++) {
fChunkInfos[i].next = (i == CHUNK_COUNT -1) ? &fChunkInfos[0] : &fChunkInfos[i + 1]; fChunkInfos[i].next = i == CHUNK_COUNT - 1
? &fChunkInfos[0] : &fChunkInfos[i + 1];
fChunkInfos[i].buffer = NULL; fChunkInfos[i].buffer = NULL;
fChunkInfos[i].sizeUsed = 0; fChunkInfos[i].sizeUsed = 0;
fChunkInfos[i].sizeMax = 0; fChunkInfos[i].sizeMax = 0;
fChunkInfos[i].err = B_ERROR; fChunkInfos[i].status = B_ERROR;
} }
} }
@ -59,7 +44,7 @@ ChunkCache::ChunkCache()
ChunkCache::~ChunkCache() ChunkCache::~ChunkCache()
{ {
delete_sem(fGetWaitSem); delete_sem(fGetWaitSem);
delete fLocker;
for (int i = 0; i < CHUNK_COUNT; i++) { for (int i = 0; i < CHUNK_COUNT; i++) {
free(fChunkInfos[i].buffer); free(fChunkInfos[i].buffer);
} }
@ -69,13 +54,13 @@ ChunkCache::~ChunkCache()
void void
ChunkCache::MakeEmpty() ChunkCache::MakeEmpty()
{ {
fLocker->Lock(); BAutolock _(fLocker);
fEmptyChunkCount = CHUNK_COUNT - 1; fEmptyChunkCount = CHUNK_COUNT - 1;
fReadyChunkCount = 0; fReadyChunkCount = 0;
fNextPut = &fChunkInfos[0]; fNextPut = &fChunkInfos[0];
fNextGet = &fChunkInfos[0]; fNextGet = &fChunkInfos[0];
atomic_or(&fNeedsRefill, 1); atomic_or(&fNeedsRefill, 1);
fLocker->Unlock();
} }
@ -85,48 +70,53 @@ ChunkCache::NeedsRefill()
return atomic_or(&fNeedsRefill, 0); return atomic_or(&fNeedsRefill, 0);
} }
status_t status_t
ChunkCache::GetNextChunk(const void **chunkBuffer, size_t *chunkSize, media_header *mediaHeader) ChunkCache::GetNextChunk(const void** _chunkBuffer, size_t* _chunkSize,
media_header* mediaHeader)
{ {
uint8 retry_count = 0; uint8 retryCount = 0;
// printf("ChunkCache::GetNextChunk: %p fEmptyChunkCount %ld, fReadyChunkCount %ld\n", fNextGet, fEmptyChunkCount, fReadyChunkCount); // printf("ChunkCache::GetNextChunk: %p fEmptyChunkCount %ld, fReadyChunkCount %ld\n", fNextGet, fEmptyChunkCount, fReadyChunkCount);
retry: retry:
acquire_sem(fGetWaitSem); acquire_sem(fGetWaitSem);
fLocker->Lock(); BAutolock locker(fLocker);
if (fReadyChunkCount == 0) { if (fReadyChunkCount == 0) {
fLocker->Unlock(); locker.Unlock();
printf("ChunkCache::GetNextChunk: %p retrying\n", fNextGet); printf("ChunkCache::GetNextChunk: %p retrying\n", fNextGet);
// Limit to 5 retries // Limit to 5 retries
retry_count++; retryCount++;
if (retry_count > 4) { if (retryCount > 4)
return B_ERROR; return B_ERROR;
}
goto retry; goto retry;
} }
fEmptyChunkCount++; fEmptyChunkCount++;
fReadyChunkCount--; fReadyChunkCount--;
atomic_or(&fNeedsRefill, 1); atomic_or(&fNeedsRefill, 1);
fLocker->Unlock();
locker.Unlock();
*chunkBuffer = fNextGet->buffer;
*chunkSize = fNextGet->sizeUsed; *_chunkBuffer = fNextGet->buffer;
*_chunkSize = fNextGet->sizeUsed;
*mediaHeader = fNextGet->mediaHeader; *mediaHeader = fNextGet->mediaHeader;
status_t err = fNextGet->err; status_t status = fNextGet->status;
fNextGet = fNextGet->next; fNextGet = fNextGet->next;
return err; return status;
} }
void void
ChunkCache::PutNextChunk(const void *chunkBuffer, size_t chunkSize, const media_header &mediaHeader, status_t err) ChunkCache::PutNextChunk(const void* chunkBuffer, size_t chunkSize,
const media_header& mediaHeader, status_t status)
{ {
// printf("ChunkCache::PutNextChunk: %p fEmptyChunkCount %ld, fReadyChunkCount %ld\n", fNextPut, fEmptyChunkCount, fReadyChunkCount); // printf("ChunkCache::PutNextChunk: %p fEmptyChunkCount %ld, fReadyChunkCount %ld\n", fNextPut, fEmptyChunkCount, fReadyChunkCount);
if (err == B_OK) { if (status == B_OK) {
if (fNextPut->sizeMax < chunkSize) { if (fNextPut->sizeMax < chunkSize) {
// printf("ChunkCache::PutNextChunk: %p resizing from %ld to %ld\n", fNextPut, fNextPut->sizeMax, chunkSize); // printf("ChunkCache::PutNextChunk: %p resizing from %ld to %ld\n", fNextPut, fNextPut->sizeMax, chunkSize);
free(fNextPut->buffer); free(fNextPut->buffer);
@ -136,18 +126,18 @@ ChunkCache::PutNextChunk(const void *chunkBuffer, size_t chunkSize, const media_
memcpy(fNextPut->buffer, chunkBuffer, chunkSize); memcpy(fNextPut->buffer, chunkBuffer, chunkSize);
fNextPut->sizeUsed = chunkSize; fNextPut->sizeUsed = chunkSize;
} }
fNextPut->mediaHeader = mediaHeader; fNextPut->mediaHeader = mediaHeader;
fNextPut->err = err; fNextPut->status = status;
fNextPut = fNextPut->next; fNextPut = fNextPut->next;
fLocker->Lock(); fLocker.Lock();
fEmptyChunkCount--; fEmptyChunkCount--;
fReadyChunkCount++; fReadyChunkCount++;
if (fEmptyChunkCount == 0) if (fEmptyChunkCount == 0)
atomic_and(&fNeedsRefill, 0); atomic_and(&fNeedsRefill, 0);
fLocker->Unlock(); fLocker.Unlock();
release_sem(fGetWaitSem); release_sem(fGetWaitSem);
} }

View File

@ -1,78 +1,64 @@
/* /*
* Copyright (c) 2004, Marcus Overhagen * Copyright 2004, Marcus Overhagen. All rights reserved.
* All rights reserved. * Distributed under the terms of the MIT License.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef _CHUNK_CACHE_H #ifndef _CHUNK_CACHE_H
#define _CHUNK_CACHE_H #define _CHUNK_CACHE_H
#include <Locker.h>
#include <MediaDefs.h> #include <MediaDefs.h>
namespace BPrivate { namespace BPrivate {
namespace media { namespace media {
struct chunk_info struct chunk_info {
{ chunk_info* next;
chunk_info * next; void* buffer;
void * buffer;
size_t sizeUsed; size_t sizeUsed;
size_t sizeMax; size_t sizeMax;
media_header mediaHeader; media_header mediaHeader;
status_t err; status_t status;
}; };
class ChunkCache class ChunkCache {
{
public: public:
ChunkCache(); ChunkCache();
~ChunkCache(); ~ChunkCache();
void MakeEmpty();
bool NeedsRefill();
status_t GetNextChunk(const void** _chunkBuffer,
size_t* _chunkSize,
media_header* mediaHeader);
void PutNextChunk(const void* chunkBuffer,
size_t chunkSize,
const media_header& mediaHeader,
status_t status);
void MakeEmpty();
bool NeedsRefill();
status_t GetNextChunk(const void **chunkBuffer, size_t *chunkSize, media_header *mediaHeader);
void PutNextChunk(const void *chunkBuffer, size_t chunkSize, const media_header &mediaHeader, status_t err);
private: private:
enum { CHUNK_COUNT = 5 }; enum { CHUNK_COUNT = 5 };
chunk_info * fNextPut; chunk_info* fNextPut;
chunk_info * fNextGet; chunk_info* fNextGet;
chunk_info fChunkInfos[CHUNK_COUNT]; chunk_info fChunkInfos[CHUNK_COUNT];
sem_id fGetWaitSem; sem_id fGetWaitSem;
int32 fEmptyChunkCount; int32 fEmptyChunkCount;
int32 fReadyChunkCount; int32 fReadyChunkCount;
int32 fNeedsRefill; int32 fNeedsRefill;
BLocker * fLocker; BLocker fLocker;
}; };
}; // namespace media } // namespace media
}; // namespace BPrivate } // namespace BPrivate
using namespace BPrivate::media; using namespace BPrivate::media;
#endif #endif // _CHUNK_CACHE_H

View File

@ -6,22 +6,48 @@
#include "MediaExtractor.h" #include "MediaExtractor.h"
#include "PluginManager.h"
#include "ChunkCache.h" #include <new>
#include "debug.h" #include <stdio.h>
#include <string.h>
#include <Autolock.h> #include <Autolock.h>
#include <stdio.h> #include "debug.h"
#include <string.h> #include "ChunkCache.h"
#include <new> #include "PluginManager.h"
// should be 0, to disable the chunk cache set it to 1 // should be 0, to disable the chunk cache set it to 1
#define DISABLE_CHUNK_CACHE 0 #define DISABLE_CHUNK_CACHE 0
MediaExtractor::MediaExtractor(BDataIO *source, int32 flags) class MediaExtractorChunkProvider : public ChunkProvider {
public:
MediaExtractorChunkProvider(MediaExtractor* extractor, int32 stream)
:
fExtractor(extractor),
fStream(stream)
{
}
virtual status_t GetNextChunk(const void** _chunkBuffer, size_t* _chunkSize,
media_header *mediaHeader)
{
return fExtractor->GetNextChunk(fStream, _chunkBuffer, _chunkSize,
mediaHeader);
}
private:
MediaExtractor* fExtractor;
int32 fStream;
};
// #pragma mark -
MediaExtractor::MediaExtractor(BDataIO* source, int32 flags)
{ {
CALLED(); CALLED();
fSource = source; fSource = source;
@ -30,8 +56,9 @@ MediaExtractor::MediaExtractor(BDataIO *source, int32 flags)
fExtractorWaitSem = -1; fExtractorWaitSem = -1;
fTerminateExtractor = false; fTerminateExtractor = false;
fErr = _plugin_manager.CreateReader(&fReader, &fStreamCount, &fMff, source); fInitStatus = _plugin_manager.CreateReader(&fReader, &fStreamCount,
if (fErr) { &fFileFormat, source);
if (fInitStatus != B_OK) {
fStreamCount = 0; fStreamCount = 0;
fReader = NULL; fReader = NULL;
return; return;
@ -66,11 +93,13 @@ MediaExtractor::MediaExtractor(BDataIO *source, int32 flags)
for (int32 i = 0; i < fStreamCount; i++) { for (int32 i = 0; i < fStreamCount; i++) {
if (fStreamInfo[i].status != B_OK) if (fStreamInfo[i].status != B_OK)
continue; continue;
int64 frameCount; int64 frameCount;
bigtime_t duration; bigtime_t duration;
if (B_OK != fReader->GetStreamInfo(fStreamInfo[i].cookie, &frameCount, if (fReader->GetStreamInfo(fStreamInfo[i].cookie, &frameCount,
&duration, &fStreamInfo[i].encodedFormat, &duration, &fStreamInfo[i].encodedFormat,
&fStreamInfo[i].infoBuffer, &fStreamInfo[i].infoBufferSize)) { &fStreamInfo[i].infoBuffer, &fStreamInfo[i].infoBufferSize)
!= B_OK) {
fStreamInfo[i].status = B_ERROR; fStreamInfo[i].status = B_ERROR;
ERROR("MediaExtractor::MediaExtractor: GetStreamInfo for " ERROR("MediaExtractor::MediaExtractor: GetStreamInfo for "
"stream %ld failed\n", i); "stream %ld failed\n", i);
@ -80,8 +109,8 @@ MediaExtractor::MediaExtractor(BDataIO *source, int32 flags)
#if DISABLE_CHUNK_CACHE == 0 #if DISABLE_CHUNK_CACHE == 0
// start extractor thread // start extractor thread
fExtractorWaitSem = create_sem(1, "media extractor thread sem"); fExtractorWaitSem = create_sem(1, "media extractor thread sem");
fExtractorThread = spawn_thread(extractor_thread, "media extractor thread", fExtractorThread = spawn_thread(_ExtractorEntry, "media extractor thread",
10, this); 40, this);
resume_thread(fExtractorThread); resume_thread(fExtractorThread);
#endif #endif
} }
@ -117,15 +146,15 @@ status_t
MediaExtractor::InitCheck() MediaExtractor::InitCheck()
{ {
CALLED(); CALLED();
return fErr; return fInitStatus;
} }
void void
MediaExtractor::GetFileFormatInfo(media_file_format *mfi) const MediaExtractor::GetFileFormatInfo(media_file_format* fileFormat) const
{ {
CALLED(); CALLED();
*mfi = fMff; *fileFormat = fFileFormat;
} }
@ -144,7 +173,7 @@ MediaExtractor::Copyright()
} }
const media_format * const media_format*
MediaExtractor::EncodedFormat(int32 stream) MediaExtractor::EncodedFormat(int32 stream)
{ {
return &fStreamInfo[stream].encodedFormat; return &fStreamInfo[stream].encodedFormat;
@ -161,7 +190,7 @@ MediaExtractor::CountFrames(int32 stream) const
int64 frameCount; int64 frameCount;
bigtime_t duration; bigtime_t duration;
media_format format; media_format format;
const void *infoBuffer; const void* infoBuffer;
size_t infoSize; size_t infoSize;
fReader->GetStreamInfo(fStreamInfo[stream].cookie, &frameCount, &duration, fReader->GetStreamInfo(fStreamInfo[stream].cookie, &frameCount, &duration,
@ -193,8 +222,7 @@ MediaExtractor::Duration(int32 stream) const
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)
{ {
CALLED(); CALLED();
if (fStreamInfo[stream].status != B_OK) if (fStreamInfo[stream].status != B_OK)
@ -214,22 +242,21 @@ MediaExtractor::Seek(int32 stream, uint32 seekTo,
status_t status_t
MediaExtractor::FindKeyFrame(int32 stream, uint32 seekTo, int64 *frame, MediaExtractor::FindKeyFrame(int32 stream, uint32 seekTo, int64* _frame,
bigtime_t *time) const bigtime_t* _time) const
{ {
CALLED(); CALLED();
if (fStreamInfo[stream].status != B_OK) if (fStreamInfo[stream].status != B_OK)
return fStreamInfo[stream].status; return fStreamInfo[stream].status;
return fReader->FindKeyFrame(fStreamInfo[stream].cookie, return fReader->FindKeyFrame(fStreamInfo[stream].cookie,
seekTo, frame, time); seekTo, _frame, _time);
} }
status_t status_t
MediaExtractor::GetNextChunk(int32 stream, MediaExtractor::GetNextChunk(int32 stream, const void** _chunkBuffer,
const void **chunkBuffer, size_t *chunkSize, size_t* _chunkSize, media_header* mediaHeader)
media_header *mediaHeader)
{ {
if (fStreamInfo[stream].status != B_OK) if (fStreamInfo[stream].status != B_OK)
return fStreamInfo[stream].status; return fStreamInfo[stream].status;
@ -237,68 +264,51 @@ MediaExtractor::GetNextChunk(int32 stream,
#if DISABLE_CHUNK_CACHE > 0 #if DISABLE_CHUNK_CACHE > 0
static BLocker locker("media extractor next chunk"); static BLocker locker("media extractor next chunk");
BAutolock lock(locker); BAutolock lock(locker);
return fReader->GetNextChunk(fStreamInfo[stream].cookie, chunkBuffer, return fReader->GetNextChunk(fStreamInfo[stream].cookie, _chunkBuffer,
chunkSize, mediaHeader); _chunkSize, mediaHeader);
#endif #endif
status_t err; status_t status = fStreamInfo[stream].chunkCache->GetNextChunk(_chunkBuffer,
err = fStreamInfo[stream].chunkCache->GetNextChunk(chunkBuffer, chunkSize, _chunkSize, mediaHeader);
mediaHeader);
release_sem(fExtractorWaitSem); release_sem(fExtractorWaitSem);
return err; return status;
} }
class MediaExtractorChunkProvider : public ChunkProvider {
private:
MediaExtractor * fExtractor;
int32 fStream;
public:
MediaExtractorChunkProvider(MediaExtractor * extractor, int32 stream)
{
fExtractor = extractor;
fStream = stream;
}
virtual status_t GetNextChunk(const void **chunkBuffer, size_t *chunkSize,
media_header *mediaHeader)
{
return fExtractor->GetNextChunk(fStream, chunkBuffer, chunkSize,
mediaHeader);
}
};
status_t status_t
MediaExtractor::CreateDecoder(int32 stream, Decoder **out_decoder, MediaExtractor::CreateDecoder(int32 stream, Decoder** _decoder,
media_codec_info *mci) media_codec_info* codecInfo)
{ {
CALLED(); CALLED();
status_t res;
Decoder *decoder;
res = fStreamInfo[stream].status; status_t status = fStreamInfo[stream].status;
if (res != B_OK) { if (status != B_OK) {
ERROR("MediaExtractor::CreateDecoder can't create decoder for " ERROR("MediaExtractor::CreateDecoder can't create decoder for "
"stream %ld\n", stream); "stream %ld: %s\n", stream, strerror(status));
return res; return status;
} }
// TODO Here we should work out a way so that if there is a setup failure we can try the next decoder // TODO: Here we should work out a way so that if there is a setup
res = _plugin_manager.CreateDecoder(&decoder, // failure we can try the next decoder
Decoder* decoder;
status = _plugin_manager.CreateDecoder(&decoder,
fStreamInfo[stream].encodedFormat); fStreamInfo[stream].encodedFormat);
if (res != B_OK) { if (status != B_OK) {
#if DEBUG
char formatString[256]; char formatString[256];
string_for_format(fStreamInfo[stream].encodedFormat, formatString, string_for_format(fStreamInfo[stream].encodedFormat, formatString,
256); sizeof(formatString));
ERROR("MediaExtractor::CreateDecoder _plugin_manager.CreateDecoder " ERROR("MediaExtractor::CreateDecoder _plugin_manager.CreateDecoder "
"failed for stream %ld, format: %s\n", stream, formatString); "failed for stream %ld, format: %s: %s\n", stream, formatString,
return res; strerror(status));
#endif
return status;
} }
ChunkProvider *chunkProvider ChunkProvider* chunkProvider
= new(std::nothrow) MediaExtractorChunkProvider(this, stream); = new(std::nothrow) MediaExtractorChunkProvider(this, stream);
if (!chunkProvider) { if (chunkProvider == NULL) {
_plugin_manager.DestroyDecoder(decoder); _plugin_manager.DestroyDecoder(decoder);
ERROR("MediaExtractor::CreateDecoder can't create chunk provider " ERROR("MediaExtractor::CreateDecoder can't create chunk provider "
"for stream %ld\n", stream); "for stream %ld\n", stream);
@ -307,64 +317,65 @@ MediaExtractor::CreateDecoder(int32 stream, Decoder **out_decoder,
decoder->SetChunkProvider(chunkProvider); decoder->SetChunkProvider(chunkProvider);
res = decoder->Setup(&fStreamInfo[stream].encodedFormat, status = decoder->Setup(&fStreamInfo[stream].encodedFormat,
fStreamInfo[stream].infoBuffer, fStreamInfo[stream].infoBufferSize); fStreamInfo[stream].infoBuffer, fStreamInfo[stream].infoBufferSize);
if (res != B_OK) { if (status != B_OK) {
_plugin_manager.DestroyDecoder(decoder); _plugin_manager.DestroyDecoder(decoder);
ERROR("MediaExtractor::CreateDecoder Setup failed for stream %ld: " ERROR("MediaExtractor::CreateDecoder Setup failed for stream %ld: %s\n",
"%ld (%s)\n", stream, res, strerror(res)); stream, strerror(status));
return res; return status;
} }
res = _plugin_manager.GetDecoderInfo(decoder, mci); status = _plugin_manager.GetDecoderInfo(decoder, codecInfo);
if (res != B_OK) { if (status != B_OK) {
_plugin_manager.DestroyDecoder(decoder); _plugin_manager.DestroyDecoder(decoder);
ERROR("MediaExtractor::CreateDecoder GetCodecInfo failed for stream " ERROR("MediaExtractor::CreateDecoder GetCodecInfo failed for stream "
"%ld: %ld (%s)\n", stream, res, strerror(res)); "%ld: %s\n", stream, strerror(status));
return res; return status;
} }
*out_decoder = decoder; *_decoder = decoder;
return B_OK; return B_OK;
} }
int32 status_t
MediaExtractor::extractor_thread(void *arg) MediaExtractor::_ExtractorEntry(void* extractor)
{ {
static_cast<MediaExtractor *>(arg)->ExtractorThread(); static_cast<MediaExtractor*>(extractor)->_ExtractorThread();
return 0; return B_OK;
} }
void void
MediaExtractor::ExtractorThread() MediaExtractor::_ExtractorThread()
{ {
for (;;) { while (true) {
acquire_sem(fExtractorWaitSem); acquire_sem(fExtractorWaitSem);
if (fTerminateExtractor) if (fTerminateExtractor)
return; return;
bool refill_done; bool refillDone;
do { do {
refill_done = false; refillDone = false;
for (int32 stream = 0; stream < fStreamCount; stream++) { for (int32 stream = 0; stream < fStreamCount; stream++) {
if (fStreamInfo[stream].status != B_OK) if (fStreamInfo[stream].status != B_OK)
continue; continue;
if (fStreamInfo[stream].chunkCache->NeedsRefill()) { if (fStreamInfo[stream].chunkCache->NeedsRefill()) {
media_header mediaHeader; media_header mediaHeader;
const void *chunkBuffer; const void* chunkBuffer;
size_t chunkSize; size_t chunkSize;
status_t err; status_t status = fReader->GetNextChunk(
err = fReader->GetNextChunk(fStreamInfo[stream].cookie, fStreamInfo[stream].cookie, &chunkBuffer, &chunkSize,
&chunkBuffer, &chunkSize, &mediaHeader); &mediaHeader);
fStreamInfo[stream].chunkCache->PutNextChunk(chunkBuffer, fStreamInfo[stream].chunkCache->PutNextChunk(chunkBuffer,
chunkSize, mediaHeader, err); chunkSize, mediaHeader, status);
refill_done = true; refillDone = true;
} }
} }
if (fTerminateExtractor) if (fTerminateExtractor)
return; return;
} while (refill_done); } while (refillDone);
} }
} }