зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1154512 - Remove MediaTaskQueue::SyncDispatch() from PDM. r=cpearce
--HG-- extra : rebase_source : 1aac8eec5a39097d5cb17dac529578a6af053bd0
This commit is contained in:
Родитель
27ead4e7d8
Коммит
e727de4c04
|
@ -26,94 +26,55 @@ using namespace android;
|
|||
namespace mozilla {
|
||||
|
||||
GonkDecoderManager::GonkDecoderManager(MediaTaskQueue* aTaskQueue)
|
||||
: mTaskQueue(aTaskQueue)
|
||||
: mMonitor("GonkDecoderManager")
|
||||
, mTaskQueue(aTaskQueue)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
|
||||
// To maintain the order of the MP4Sample, it needs to send the queued samples
|
||||
// to OMX first. And then the current input aSample.
|
||||
// If it fails to input sample to OMX, it needs to add current into queue
|
||||
// for next round.
|
||||
uint32_t len = mQueueSample.Length();
|
||||
status_t rv = OK;
|
||||
|
||||
for (uint32_t i = 0; i < len; i++) {
|
||||
rv = SendSampleToOMX(mQueueSample.ElementAt(0));
|
||||
if (rv != OK) {
|
||||
break;
|
||||
}
|
||||
mQueueSample.RemoveElementAt(0);
|
||||
}
|
||||
|
||||
// When EOS, aSample will be null and sends this empty MediaRawData to nofity
|
||||
// OMX it reachs EOS.
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
|
||||
if (!aSample) {
|
||||
// It means EOS with empty sample.
|
||||
sample = new MediaRawData();
|
||||
}
|
||||
|
||||
// If rv is OK, that means mQueueSample is empty, now try to queue current input
|
||||
// aSample.
|
||||
if (rv == OK) {
|
||||
MOZ_ASSERT(!mQueueSample.Length());
|
||||
MediaRawData* tmp;
|
||||
if (aSample) {
|
||||
tmp = aSample;
|
||||
if (!PerformFormatSpecificProcess(aSample)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
} else {
|
||||
tmp = sample;
|
||||
}
|
||||
rv = SendSampleToOMX(tmp);
|
||||
if (rv == OK) {
|
||||
return NS_OK;
|
||||
} else {
|
||||
sample = aSample;
|
||||
if (!PerformFormatSpecificProcess(sample)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
// Current valid sample can't be sent into OMX, adding the clone one into queue
|
||||
// for next round.
|
||||
if (!sample) {
|
||||
sample = aSample->Clone();
|
||||
if (!sample) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
}
|
||||
mQueueSample.AppendElement(sample);
|
||||
|
||||
// In most cases, EAGAIN or ETIMEOUT safe due to OMX can't process the
|
||||
// filled buffer on time. It should be gone When requeuing sample next time.
|
||||
if (rv == -EAGAIN || rv == -ETIMEDOUT) {
|
||||
return NS_OK;
|
||||
status_t rv;
|
||||
while (mQueueSample.Length()) {
|
||||
nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
|
||||
{
|
||||
ReentrantMonitorAutoExit mon_exit(mMonitor);
|
||||
rv = SendSampleToOMX(data);
|
||||
}
|
||||
if (rv == OK) {
|
||||
mQueueSample.RemoveElementAt(0);
|
||||
} else if (rv == -EAGAIN || rv == -ETIMEDOUT) {
|
||||
// In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill
|
||||
// buffer on time.
|
||||
return NS_OK;
|
||||
} else {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Flush()
|
||||
{
|
||||
class ClearQueueRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit ClearQueueRunnable(GonkDecoderManager* aManager)
|
||||
: mManager(aManager) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mManager->ClearQueuedSample();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GonkDecoderManager* mManager;
|
||||
};
|
||||
|
||||
mTaskQueue->SyncDispatch(new ClearQueueRunnable(this));
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
mQueueSample.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -44,17 +44,12 @@ public:
|
|||
// in the overrided function.
|
||||
virtual nsresult Flush();
|
||||
|
||||
// It should be called in MediaTash thread.
|
||||
// It should be called in MediaTask thread.
|
||||
bool HasQueuedSample() {
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
return mQueueSample.Length();
|
||||
}
|
||||
|
||||
void ClearQueuedSample() {
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
mQueueSample.Clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
// It performs special operation to MP4 sample, the real action is depended on
|
||||
// the codec type.
|
||||
|
@ -63,6 +58,9 @@ protected:
|
|||
// It sends MP4Sample to OMX layer. It must be overrided by subclass.
|
||||
virtual android::status_t SendSampleToOMX(MediaRawData* aSample) = 0;
|
||||
|
||||
// This monitor protects mQueueSample.
|
||||
ReentrantMonitor mMonitor;
|
||||
|
||||
// An queue with the MP4 samples which are waiting to be sent into OMX.
|
||||
// If an element is an empty MP4Sample, that menas EOS. There should not
|
||||
// any sample be queued after EOS.
|
||||
|
|
|
@ -50,6 +50,7 @@ GonkVideoDecoderManager::GonkVideoDecoderManager(
|
|||
: GonkDecoderManager(aTaskQueue)
|
||||
, mImageContainer(aImageContainer)
|
||||
, mReaderCallback(nullptr)
|
||||
, mLastDecodedTime(0)
|
||||
, mColorConverterBufferSize(0)
|
||||
, mNativeWindow(nullptr)
|
||||
, mPendingVideoBuffersLock("GonkVideoDecoderManager::mPendingVideoBuffersLock")
|
||||
|
@ -118,51 +119,6 @@ GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
|||
return mDecoder;
|
||||
}
|
||||
|
||||
void
|
||||
GonkVideoDecoderManager::QueueFrameTimeIn(int64_t aPTS, int64_t aDuration)
|
||||
{
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
|
||||
FrameTimeInfo timeInfo = {aPTS, aDuration};
|
||||
mFrameTimeInfo.AppendElement(timeInfo);
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::QueueFrameTimeOut(int64_t aPTS, int64_t& aDuration)
|
||||
{
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
|
||||
// Set default to 1 here.
|
||||
// During seeking, frames could still in MediaCodec and the mFrameTimeInfo could
|
||||
// be cleared before these frames are out from MediaCodec. This is ok because
|
||||
// these frames are old frame before seeking.
|
||||
aDuration = 1;
|
||||
for (uint32_t i = 0; i < mFrameTimeInfo.Length(); i++) {
|
||||
const FrameTimeInfo& entry = mFrameTimeInfo.ElementAt(i);
|
||||
if (i == 0) {
|
||||
if (entry.pts > aPTS) {
|
||||
// Codec sent a frame with rollbacked PTS time. It could
|
||||
// be codec's problem.
|
||||
ReleaseVideoBuffer();
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
// Ideally, the first entry in mFrameTimeInfo should be the one we are looking
|
||||
// for. However, MediaCodec could dropped frame and the first entry doesn't
|
||||
// match current decoded frame's PTS.
|
||||
if (entry.pts == aPTS) {
|
||||
aDuration = entry.duration;
|
||||
if (i > 0) {
|
||||
LOG("Frame could be dropped by MediaCodec, %d dropped frames.", i);
|
||||
}
|
||||
mFrameTimeInfo.RemoveElementsAt(0, i+1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
|
||||
{
|
||||
|
@ -181,9 +137,12 @@ GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
int64_t duration;
|
||||
nsresult rv = QueueFrameTimeOut(timeUs, duration);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (mLastDecodedTime > timeUs) {
|
||||
ReleaseVideoBuffer();
|
||||
GVDM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mLastDecodedTime = timeUs;
|
||||
|
||||
if (mVideoBuffer->range_length() == 0) {
|
||||
// Some decoders may return spurious empty buffers that we just want to ignore
|
||||
|
@ -224,7 +183,8 @@ GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
|
|||
mImageContainer,
|
||||
aStreamOffset,
|
||||
timeUs,
|
||||
duration,
|
||||
1, // No way to pass sample duration from muxer to
|
||||
// OMX codec, so we hardcode the duration here.
|
||||
textureClient,
|
||||
keyFrame,
|
||||
-1,
|
||||
|
@ -438,47 +398,17 @@ void GonkVideoDecoderManager::ReleaseVideoBuffer() {
|
|||
status_t
|
||||
GonkVideoDecoderManager::SendSampleToOMX(MediaRawData* aSample)
|
||||
{
|
||||
// An empty MediaRawData is going to notify EOS to decoder. It doesn't need
|
||||
// to keep PTS and duration.
|
||||
if (aSample->mData && aSample->mDuration && aSample->mTime) {
|
||||
QueueFrameTimeIn(aSample->mTime, aSample->mDuration);
|
||||
}
|
||||
|
||||
return mDecoder->Input(reinterpret_cast<const uint8_t*>(aSample->mData),
|
||||
aSample->mSize,
|
||||
aSample->mTime,
|
||||
0);
|
||||
}
|
||||
|
||||
void
|
||||
GonkVideoDecoderManager::ClearQueueFrameTime()
|
||||
{
|
||||
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
|
||||
mFrameTimeInfo.Clear();
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::Flush()
|
||||
{
|
||||
GonkDecoderManager::Flush();
|
||||
|
||||
class ClearFrameTimeRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
explicit ClearFrameTimeRunnable(GonkVideoDecoderManager* aManager)
|
||||
: mManager(aManager) {}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mManager->ClearQueueFrameTime();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GonkVideoDecoderManager* mManager;
|
||||
};
|
||||
|
||||
mTaskQueue->SyncDispatch(new ClearFrameTimeRunnable(this));
|
||||
|
||||
mLastDecodedTime = 0;
|
||||
status_t err = mDecoder->flush();
|
||||
if (err != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
|
|
|
@ -108,15 +108,6 @@ private:
|
|||
};
|
||||
friend class VideoResourceListener;
|
||||
|
||||
// FrameTimeInfo keeps the presentation time stamp (pts) and its duration.
|
||||
// On MediaDecoderStateMachine, it needs pts and duration to display decoded
|
||||
// frame correctly. But OMX can carry one field of time info (kKeyTime) so
|
||||
// we use FrameTimeInfo to keep pts and duration.
|
||||
struct FrameTimeInfo {
|
||||
int64_t pts; // presentation time stamp of this frame.
|
||||
int64_t duration; // the playback duration.
|
||||
};
|
||||
|
||||
bool SetVideoFormat();
|
||||
|
||||
nsresult CreateVideoData(int64_t aStreamOffset, VideoData** aOutData);
|
||||
|
@ -131,10 +122,6 @@ private:
|
|||
void ReleaseAllPendingVideoBuffers();
|
||||
void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer);
|
||||
|
||||
void QueueFrameTimeIn(int64_t aPTS, int64_t aDuration);
|
||||
nsresult QueueFrameTimeOut(int64_t aPTS, int64_t& aDuration);
|
||||
void ClearQueueFrameTime();
|
||||
|
||||
uint32_t mVideoWidth;
|
||||
uint32_t mVideoHeight;
|
||||
uint32_t mDisplayWidth;
|
||||
|
@ -155,11 +142,7 @@ private:
|
|||
android::sp<ALooper> mManagerLooper;
|
||||
FrameInfo mFrameInfo;
|
||||
|
||||
// Array of FrameTimeInfo whose corresponding frames are sent to OMX.
|
||||
// Ideally, it is a FIFO. Input() adds the entry to the end element and
|
||||
// CreateVideoData() takes the first entry. However, there are exceptions
|
||||
// due to MediaCodec error or seeking.
|
||||
nsTArray<FrameTimeInfo> mFrameTimeInfo;
|
||||
int64_t mLastDecodedTime; // The last decoded frame presentation time.
|
||||
|
||||
// color converter
|
||||
android::I420ColorConverterHelper mColorConverter;
|
||||
|
|
Загрузка…
Ссылка в новой задаче