зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset abaadd5361ad (bug 1198664) for B2G build bustage ON A CLOSED TREE
This commit is contained in:
Родитель
8a586a51d4
Коммит
7e537c9909
|
@ -34,15 +34,18 @@ typedef android::MediaCodecProxy MediaCodecProxy;
|
|||
namespace mozilla {
|
||||
|
||||
GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig)
|
||||
: mAudioChannels(aConfig.mChannels)
|
||||
: mLastDecodedTime(0)
|
||||
, mAudioChannels(aConfig.mChannels)
|
||||
, mAudioRate(aConfig.mRate)
|
||||
, mAudioProfile(aConfig.mProfile)
|
||||
, mAudioBuffer(nullptr)
|
||||
, mMonitor("GonkAudioDecoderManager")
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkAudioDecoderManager);
|
||||
MOZ_ASSERT(mAudioChannels);
|
||||
mCodecSpecificData = aConfig.mCodecSpecificConfig;
|
||||
mMimeType = aConfig.mMimeType;
|
||||
|
||||
}
|
||||
|
||||
GonkAudioDecoderManager::~GonkAudioDecoderManager()
|
||||
|
@ -51,9 +54,9 @@ GonkAudioDecoderManager::~GonkAudioDecoderManager()
|
|||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder::InitPromise>
|
||||
GonkAudioDecoderManager::Init()
|
||||
GonkAudioDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
if (InitMediaCodecProxy()) {
|
||||
if (InitMediaCodecProxy(aCallback)) {
|
||||
return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__);
|
||||
} else {
|
||||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
|
@ -61,14 +64,18 @@ GonkAudioDecoderManager::Init()
|
|||
}
|
||||
|
||||
bool
|
||||
GonkAudioDecoderManager::InitMediaCodecProxy()
|
||||
GonkAudioDecoderManager::InitMediaCodecProxy(MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
status_t rv = OK;
|
||||
if (!InitLoopers(MediaData::AUDIO_DATA)) {
|
||||
if (mLooper != nullptr) {
|
||||
return false;
|
||||
}
|
||||
// Create ALooper
|
||||
mLooper = new ALooper;
|
||||
mLooper->setName("GonkAudioDecoderManager");
|
||||
mLooper->start();
|
||||
|
||||
mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false, nullptr);
|
||||
mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, nullptr);
|
||||
if (!mDecoder.get()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -103,6 +110,52 @@ GonkAudioDecoderManager::InitMediaCodecProxy()
|
|||
}
|
||||
}
|
||||
|
||||
bool
|
||||
GonkAudioDecoderManager::HasQueuedSample()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
return mQueueSample.Length();
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
|
||||
if (aSample) {
|
||||
sample = aSample;
|
||||
} else {
|
||||
// It means EOS with empty sample.
|
||||
sample = new MediaRawData();
|
||||
}
|
||||
|
||||
mQueueSample.AppendElement(sample);
|
||||
|
||||
status_t rv;
|
||||
while (mQueueSample.Length()) {
|
||||
nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
|
||||
{
|
||||
MonitorAutoUnlock mon_exit(mMonitor);
|
||||
rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
|
||||
data->Size(),
|
||||
data->mTime,
|
||||
0);
|
||||
}
|
||||
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_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
|
||||
if (!(mAudioBuffer != nullptr && mAudioBuffer->data() != nullptr)) {
|
||||
|
@ -122,13 +175,13 @@ GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
if (mLastTime > timeUs) {
|
||||
if (mLastDecodedTime > timeUs) {
|
||||
ReleaseAudioBuffer();
|
||||
GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
|
||||
MOZ_ASSERT(false);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mLastTime = timeUs;
|
||||
mLastDecodedTime = timeUs;
|
||||
|
||||
const uint8_t *data = static_cast<const uint8_t*>(mAudioBuffer->data());
|
||||
size_t dataOffset = mAudioBuffer->range_offset();
|
||||
|
@ -154,6 +207,23 @@ GonkAudioDecoderManager::CreateAudioData(int64_t aStreamOffset, AudioData **v) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::Flush()
|
||||
{
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mQueueSample.Clear();
|
||||
}
|
||||
|
||||
mLastDecodedTime = 0;
|
||||
|
||||
if (mDecoder->flush() != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkAudioDecoderManager::Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutData)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
using namespace android;
|
||||
|
||||
namespace android {
|
||||
struct MOZ_EXPORT ALooper;
|
||||
class MOZ_EXPORT MediaBuffer;
|
||||
} // namespace android
|
||||
|
||||
|
@ -23,26 +24,44 @@ typedef android::MediaCodecProxy MediaCodecProxy;
|
|||
public:
|
||||
GonkAudioDecoderManager(const AudioInfo& aConfig);
|
||||
|
||||
virtual ~GonkAudioDecoderManager();
|
||||
virtual ~GonkAudioDecoderManager() override;
|
||||
|
||||
nsRefPtr<InitPromise> Init() override;
|
||||
nsRefPtr<InitPromise> Init(MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
nsresult Input(MediaRawData* aSample) override;
|
||||
|
||||
nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) override;
|
||||
|
||||
nsresult Flush() override;
|
||||
|
||||
bool HasQueuedSample() override;
|
||||
|
||||
private:
|
||||
bool InitMediaCodecProxy();
|
||||
bool InitMediaCodecProxy(MediaDataDecoderCallback* aCallback);
|
||||
|
||||
nsresult CreateAudioData(int64_t aStreamOffset,
|
||||
AudioData** aOutData);
|
||||
|
||||
void ReleaseAudioBuffer();
|
||||
|
||||
int64_t mLastDecodedTime;
|
||||
|
||||
uint32_t mAudioChannels;
|
||||
uint32_t mAudioRate;
|
||||
const uint32_t mAudioProfile;
|
||||
|
||||
MediaDataDecoderCallback* mReaderCallback;
|
||||
android::MediaBuffer* mAudioBuffer;
|
||||
android::sp<ALooper> mLooper;
|
||||
|
||||
// This monitor protects mQueueSample.
|
||||
Monitor 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.
|
||||
nsTArray<nsRefPtr<MediaRawData>> mQueueSample;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -8,8 +8,6 @@
|
|||
#include "nsTArray.h"
|
||||
#include "MediaCodecProxy.h"
|
||||
|
||||
#include <stagefright/foundation/ADebug.h>
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
#include <android/log.h>
|
||||
#define GMDD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkMediaDataDecoder", __VA_ARGS__)
|
||||
|
@ -21,87 +19,6 @@ using namespace android;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
bool
|
||||
GonkDecoderManager::InitLoopers(MediaData::Type aType)
|
||||
{
|
||||
MOZ_ASSERT(mDecodeLooper.get() == nullptr && mTaskLooper.get() == nullptr);
|
||||
MOZ_ASSERT(aType == MediaData::VIDEO_DATA || aType == MediaData::AUDIO_DATA);
|
||||
|
||||
const char* suffix = (aType == MediaData::VIDEO_DATA ? "video" : "audio");
|
||||
mDecodeLooper = new ALooper;
|
||||
android::AString name("MediaCodecProxy/");
|
||||
name.append(suffix);
|
||||
mDecodeLooper->setName(name.c_str());
|
||||
|
||||
mTaskLooper = new ALooper;
|
||||
name.setTo("GonkDecoderManager/");
|
||||
name.append(suffix);
|
||||
mTaskLooper->setName(name.c_str());
|
||||
mTaskLooper->registerHandler(this);
|
||||
|
||||
return mDecodeLooper->start() == OK && mTaskLooper->start() == OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
|
||||
if (!aSample) {
|
||||
// It means EOS with empty sample.
|
||||
sample = new MediaRawData();
|
||||
} else {
|
||||
sample = aSample;
|
||||
}
|
||||
|
||||
mQueuedSamples.AppendElement(sample);
|
||||
|
||||
status_t rv;
|
||||
while (mQueuedSamples.Length()) {
|
||||
nsRefPtr<MediaRawData> data = mQueuedSamples.ElementAt(0);
|
||||
{
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
|
||||
data->Size(),
|
||||
data->mTime,
|
||||
0);
|
||||
}
|
||||
if (rv == OK) {
|
||||
mQueuedSamples.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_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Flush()
|
||||
{
|
||||
if (mDecoder == nullptr) {
|
||||
GMDD_LOG("Decoder is not initialized");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mQueuedSamples.Clear();
|
||||
}
|
||||
|
||||
mLastTime = 0;
|
||||
|
||||
if (mDecoder->flush() != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkDecoderManager::Shutdown()
|
||||
{
|
||||
|
@ -116,25 +33,6 @@ GonkDecoderManager::Shutdown()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
GonkDecoderManager::HasQueuedSample()
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mQueuedSamples.Length();
|
||||
}
|
||||
|
||||
void
|
||||
GonkDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
|
||||
{
|
||||
switch (aMessage->what()) {
|
||||
default:
|
||||
{
|
||||
TRESPASS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager,
|
||||
FlushableTaskQueue* aTaskQueue,
|
||||
MediaDataDecoderCallback* aCallback)
|
||||
|
@ -145,7 +43,6 @@ GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager,
|
|||
, mDrainComplete(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkMediaDataDecoder);
|
||||
mManager->SetDecodeCallback(aCallback);
|
||||
}
|
||||
|
||||
GonkMediaDataDecoder::~GonkMediaDataDecoder()
|
||||
|
@ -158,7 +55,7 @@ GonkMediaDataDecoder::Init()
|
|||
{
|
||||
mDrainComplete = false;
|
||||
|
||||
return mManager->Init();
|
||||
return mManager->Init(mCallback);
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
#if !defined(GonkMediaDataDecoder_h_)
|
||||
#define GonkMediaDataDecoder_h_
|
||||
#include "PlatformDecoderModule.h"
|
||||
#include <stagefright/foundation/AHandler.h>
|
||||
|
||||
namespace android {
|
||||
struct ALooper;
|
||||
class MediaCodecProxy;
|
||||
} // namespace android
|
||||
|
||||
|
@ -18,7 +16,7 @@ namespace mozilla {
|
|||
class MediaRawData;
|
||||
|
||||
// Manage the data flow from inputting encoded data and outputting decode data.
|
||||
class GonkDecoderManager : public android::AHandler {
|
||||
class GonkDecoderManager {
|
||||
public:
|
||||
typedef TrackInfo::TrackType TrackType;
|
||||
typedef MediaDataDecoder::InitPromise InitPromise;
|
||||
|
@ -26,8 +24,10 @@ public:
|
|||
|
||||
virtual ~GonkDecoderManager() {}
|
||||
|
||||
virtual nsRefPtr<InitPromise> Init(MediaDataDecoderCallback* aCallback) = 0;
|
||||
|
||||
// Add samples into OMX decoder or queue them if decoder is out of input buffer.
|
||||
nsresult Input(MediaRawData* aSample);
|
||||
virtual nsresult Input(MediaRawData* aSample) = 0;
|
||||
|
||||
// Produces decoded output, it blocks until output can be produced or a timeout
|
||||
// is expired or until EOS. Returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE
|
||||
|
@ -37,57 +37,26 @@ public:
|
|||
// The overrided class should follow the same behaviour.
|
||||
virtual nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) = 0;
|
||||
virtual nsRefPtr<InitPromise> Init() = 0;
|
||||
|
||||
// Flush the queued sample.
|
||||
nsresult Flush();
|
||||
virtual nsresult Flush() = 0;
|
||||
|
||||
// Shutdown decoder and rejects the init promise.
|
||||
nsresult Shutdown();
|
||||
|
||||
// True if sample is queued.
|
||||
bool HasQueuedSample();
|
||||
|
||||
// Set callback for decoder events, such as requesting more input,
|
||||
// returning output, or reporting error.
|
||||
void SetDecodeCallback(MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
mDecodeCallback = aCallback;
|
||||
}
|
||||
virtual bool HasQueuedSample() = 0;
|
||||
|
||||
protected:
|
||||
GonkDecoderManager()
|
||||
: mMutex("GonkDecoderManager")
|
||||
, mLastTime(0)
|
||||
, mDecodeCallback(nullptr)
|
||||
{}
|
||||
|
||||
bool InitLoopers(MediaData::Type aType);
|
||||
|
||||
void onMessageReceived(const android::sp<android::AMessage> &aMessage) override;
|
||||
|
||||
nsRefPtr<MediaByteBuffer> mCodecSpecificData;
|
||||
|
||||
nsAutoCString mMimeType;
|
||||
|
||||
// MediaCodedc's wrapper that performs the decoding.
|
||||
android::sp<android::MediaCodecProxy> mDecoder;
|
||||
// Looper for mDecoder to run on.
|
||||
android::sp<android::ALooper> mDecodeLooper;
|
||||
// Looper to run decode tasks such as recycling output buffers.
|
||||
android::sp<android::ALooper> mTaskLooper;
|
||||
|
||||
MozPromiseHolder<InitPromise> mInitPromise;
|
||||
|
||||
Mutex mMutex; // Protects mQueuedSamples.
|
||||
// A queue that stores the samples waiting to be sent to mDecoder.
|
||||
// Empty element means EOS and there shouldn't be any sample be queued after it.
|
||||
// Samples are queued in caller's thread and dequeued in mTaskLooper.
|
||||
nsTArray<nsRefPtr<MediaRawData>> mQueuedSamples;
|
||||
|
||||
int64_t mLastTime; // The last decoded frame presentation time.
|
||||
|
||||
MediaDataDecoderCallback* mDecodeCallback; // Reports decoder output or error.
|
||||
};
|
||||
|
||||
// Samples are decoded using the GonkDecoder (MediaCodec)
|
||||
|
@ -132,7 +101,7 @@ private:
|
|||
RefPtr<FlushableTaskQueue> mTaskQueue;
|
||||
MediaDataDecoderCallback* mCallback;
|
||||
|
||||
android::sp<GonkDecoderManager> mManager;
|
||||
nsAutoPtr<GonkDecoderManager> mManager;
|
||||
|
||||
// The last offset into the media resource that was passed into Input().
|
||||
// This is used to approximate the decoder's position in the media resource.
|
||||
|
|
|
@ -17,7 +17,10 @@
|
|||
#include "stagefright/MediaBuffer.h"
|
||||
#include "stagefright/MetaData.h"
|
||||
#include "stagefright/MediaErrors.h"
|
||||
#include <stagefright/foundation/ADebug.h>
|
||||
#include <stagefright/foundation/AMessage.h>
|
||||
#include <stagefright/foundation/AString.h>
|
||||
#include <stagefright/foundation/ALooper.h>
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "GonkNativeWindowClient.h"
|
||||
#include "mozilla/layers/GrallocTextureClient.h"
|
||||
|
@ -41,9 +44,12 @@ GonkVideoDecoderManager::GonkVideoDecoderManager(
|
|||
mozilla::layers::ImageContainer* aImageContainer,
|
||||
const VideoInfo& aConfig)
|
||||
: mImageContainer(aImageContainer)
|
||||
, mReaderCallback(nullptr)
|
||||
, mLastDecodedTime(0)
|
||||
, mColorConverterBufferSize(0)
|
||||
, mNativeWindow(nullptr)
|
||||
, mPendingReleaseItemsLock("GonkVideoDecoderManager::mPendingReleaseItemsLock")
|
||||
, mMonitor("GonkVideoDecoderManager")
|
||||
{
|
||||
MOZ_COUNT_CTOR(GonkVideoDecoderManager);
|
||||
mMimeType = aConfig.mMimeType;
|
||||
|
@ -58,6 +64,7 @@ GonkVideoDecoderManager::GonkVideoDecoderManager(
|
|||
nsIntSize frameSize(mVideoWidth, mVideoHeight);
|
||||
mPicture = pictureRect;
|
||||
mInitialFrame = frameSize;
|
||||
mHandler = new MessageHandler(this);
|
||||
mVideoListener = new VideoResourceListener(this);
|
||||
|
||||
}
|
||||
|
@ -69,7 +76,7 @@ GonkVideoDecoderManager::~GonkVideoDecoderManager()
|
|||
}
|
||||
|
||||
nsRefPtr<MediaDataDecoder::InitPromise>
|
||||
GonkVideoDecoderManager::Init()
|
||||
GonkVideoDecoderManager::Init(MediaDataDecoderCallback* aCallback)
|
||||
{
|
||||
nsIntSize displaySize(mDisplayWidth, mDisplayHeight);
|
||||
nsIntRect pictureRect(0, 0, mVideoWidth, mVideoHeight);
|
||||
|
@ -94,19 +101,26 @@ GonkVideoDecoderManager::Init()
|
|||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
}
|
||||
|
||||
mReaderCallback = aCallback;
|
||||
|
||||
mReaderTaskQueue = AbstractThread::GetCurrent()->AsTaskQueue();
|
||||
MOZ_ASSERT(mReaderTaskQueue);
|
||||
|
||||
if (mDecodeLooper.get() != nullptr) {
|
||||
if (mLooper.get() != nullptr) {
|
||||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
}
|
||||
|
||||
if (!InitLoopers(MediaData::VIDEO_DATA)) {
|
||||
// Create ALooper
|
||||
mLooper = new ALooper;
|
||||
mManagerLooper = new ALooper;
|
||||
mManagerLooper->setName("GonkVideoDecoderManager");
|
||||
// Register AMessage handler to ALooper.
|
||||
mManagerLooper->registerHandler(mHandler);
|
||||
// Start ALooper thread.
|
||||
if (mLooper->start() != OK || mManagerLooper->start() != OK ) {
|
||||
return InitPromise::CreateAndReject(DecoderFailureReason::INIT_ERROR, __func__);
|
||||
}
|
||||
|
||||
nsRefPtr<InitPromise> p = mInitPromise.Ensure(__func__);
|
||||
mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false, mVideoListener);
|
||||
mDecoder = MediaCodecProxy::CreateByType(mLooper, mMimeType.get(), false, mVideoListener);
|
||||
mDecoder->AsyncAskMediaCodec();
|
||||
|
||||
uint32_t capability = MediaCodecProxy::kEmptyCapability;
|
||||
|
@ -118,6 +132,52 @@ GonkVideoDecoderManager::Init()
|
|||
return p;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::Input(MediaRawData* aSample)
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
nsRefPtr<MediaRawData> sample;
|
||||
|
||||
if (!aSample) {
|
||||
// It means EOS with empty sample.
|
||||
sample = new MediaRawData();
|
||||
} else {
|
||||
sample = aSample;
|
||||
}
|
||||
|
||||
mQueueSample.AppendElement(sample);
|
||||
|
||||
status_t rv;
|
||||
while (mQueueSample.Length()) {
|
||||
nsRefPtr<MediaRawData> data = mQueueSample.ElementAt(0);
|
||||
{
|
||||
MonitorAutoUnlock mon_unlock(mMonitor);
|
||||
rv = mDecoder->Input(reinterpret_cast<const uint8_t*>(data->Data()),
|
||||
data->Size(),
|
||||
data->mTime,
|
||||
0);
|
||||
}
|
||||
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_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
GonkVideoDecoderManager::HasQueuedSample()
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
return mQueueSample.Length();
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
|
||||
{
|
||||
|
@ -137,12 +197,12 @@ GonkVideoDecoderManager::CreateVideoData(int64_t aStreamOffset, VideoData **v)
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (mLastTime > timeUs) {
|
||||
if (mLastDecodedTime > timeUs) {
|
||||
ReleaseVideoBuffer();
|
||||
GVDM_LOG("Output decoded sample time is revert. time=%lld", timeUs);
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mLastTime = timeUs;
|
||||
mLastDecodedTime = timeUs;
|
||||
|
||||
if (mVideoBuffer->range_length() == 0) {
|
||||
// Some decoders may return spurious empty buffers that we just want to ignore
|
||||
|
@ -307,6 +367,27 @@ GonkVideoDecoderManager::SetVideoFormat()
|
|||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkVideoDecoderManager::Flush()
|
||||
{
|
||||
if (mDecoder == nullptr) {
|
||||
GVDM_LOG("Decoder is not inited");
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
{
|
||||
MonitorAutoLock mon(mMonitor);
|
||||
mQueueSample.Clear();
|
||||
}
|
||||
|
||||
mLastDecodedTime = 0;
|
||||
|
||||
if (mDecoder->flush() != OK) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Blocks until decoded sample is produced by the deoder.
|
||||
nsresult
|
||||
GonkVideoDecoderManager::Output(int64_t aStreamOffset,
|
||||
|
@ -435,7 +516,7 @@ GonkVideoDecoderManager::codecCanceled()
|
|||
mInitPromise.RejectIfExists(DecoderFailureReason::CANCELED, __func__);
|
||||
}
|
||||
|
||||
// Called on GonkDecoderManager::mTaskLooper thread.
|
||||
// Called on GonkVideoDecoderManager::mManagerLooper thread.
|
||||
void
|
||||
GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
|
||||
{
|
||||
|
@ -447,10 +528,26 @@ GonkVideoDecoderManager::onMessageReceived(const sp<AMessage> &aMessage)
|
|||
}
|
||||
|
||||
default:
|
||||
{
|
||||
GonkDecoderManager::onMessageReceived(aMessage);
|
||||
TRESPASS();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GonkVideoDecoderManager::MessageHandler::MessageHandler(GonkVideoDecoderManager *aManager)
|
||||
: mManager(aManager)
|
||||
{
|
||||
}
|
||||
|
||||
GonkVideoDecoderManager::MessageHandler::~MessageHandler()
|
||||
{
|
||||
mManager = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GonkVideoDecoderManager::MessageHandler::onMessageReceived(const android::sp<android::AMessage> &aMessage)
|
||||
{
|
||||
if (mManager != nullptr) {
|
||||
mManager->onMessageReceived(aMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -555,7 +652,7 @@ void GonkVideoDecoderManager::PostReleaseVideoBuffer(
|
|||
}
|
||||
}
|
||||
sp<AMessage> notify =
|
||||
new AMessage(kNotifyPostReleaseBuffer, id());
|
||||
new AMessage(kNotifyPostReleaseBuffer, mHandler->id());
|
||||
notify->post();
|
||||
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
#if !defined(GonkVideoDecoderManager_h_)
|
||||
#define GonkVideoDecoderManager_h_
|
||||
|
||||
#include <set>
|
||||
#include "nsRect.h"
|
||||
#include "GonkMediaDataDecoder.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "I420ColorConverterHelper.h"
|
||||
#include "MediaCodecProxy.h"
|
||||
#include <stagefright/foundation/AHandler.h>
|
||||
#include "GonkNativeWindow.h"
|
||||
#include "GonkNativeWindowClient.h"
|
||||
#include "mozilla/layers/FenceUtils.h"
|
||||
|
@ -20,6 +22,7 @@
|
|||
using namespace android;
|
||||
|
||||
namespace android {
|
||||
struct ALooper;
|
||||
class MediaBuffer;
|
||||
struct MOZ_EXPORT AString;
|
||||
class GonkNativeWindow;
|
||||
|
@ -39,13 +42,19 @@ public:
|
|||
GonkVideoDecoderManager(mozilla::layers::ImageContainer* aImageContainer,
|
||||
const VideoInfo& aConfig);
|
||||
|
||||
virtual ~GonkVideoDecoderManager();
|
||||
virtual ~GonkVideoDecoderManager() override;
|
||||
|
||||
nsRefPtr<InitPromise> Init() override;
|
||||
nsRefPtr<InitPromise> Init(MediaDataDecoderCallback* aCallback) override;
|
||||
|
||||
nsresult Input(MediaRawData* aSample) override;
|
||||
|
||||
nsresult Output(int64_t aStreamOffset,
|
||||
nsRefPtr<MediaData>& aOutput) override;
|
||||
|
||||
nsresult Flush() override;
|
||||
|
||||
bool HasQueuedSample() override;
|
||||
|
||||
static void RecycleCallback(TextureClient* aClient, void* aClosure);
|
||||
|
||||
private:
|
||||
|
@ -61,8 +70,23 @@ private:
|
|||
int32_t mCropRight = 0;
|
||||
int32_t mCropBottom = 0;
|
||||
};
|
||||
class MessageHandler : public android::AHandler
|
||||
{
|
||||
public:
|
||||
MessageHandler(GonkVideoDecoderManager *aManager);
|
||||
~MessageHandler();
|
||||
|
||||
void onMessageReceived(const android::sp<android::AMessage> &aMessage) override;
|
||||
void onMessageReceived(const android::sp<android::AMessage> &aMessage) override;
|
||||
|
||||
private:
|
||||
// Forbidden
|
||||
MessageHandler() = delete;
|
||||
MessageHandler(const MessageHandler &rhs) = delete;
|
||||
const MessageHandler &operator=(const MessageHandler &rhs) = delete;
|
||||
|
||||
GonkVideoDecoderManager *mManager;
|
||||
};
|
||||
friend class MessageHandler;
|
||||
|
||||
class VideoResourceListener : public android::MediaCodecProxy::CodecResourceListener
|
||||
{
|
||||
|
@ -95,6 +119,7 @@ private:
|
|||
// For codec resource management
|
||||
void codecReserved();
|
||||
void codecCanceled();
|
||||
void onMessageReceived(const sp<AMessage> &aMessage);
|
||||
|
||||
void ReleaseAllPendingVideoBuffers();
|
||||
void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer,
|
||||
|
@ -111,10 +136,16 @@ private:
|
|||
|
||||
android::MediaBuffer* mVideoBuffer;
|
||||
|
||||
MediaDataDecoderCallback* mReaderCallback;
|
||||
MediaInfo mInfo;
|
||||
android::sp<VideoResourceListener> mVideoListener;
|
||||
android::sp<MessageHandler> mHandler;
|
||||
android::sp<ALooper> mLooper;
|
||||
android::sp<ALooper> mManagerLooper;
|
||||
FrameInfo mFrameInfo;
|
||||
|
||||
int64_t mLastDecodedTime; // The last decoded frame presentation time.
|
||||
|
||||
// color converter
|
||||
android::I420ColorConverterHelper mColorConverter;
|
||||
nsAutoArrayPtr<uint8_t> mColorConverterBuffer;
|
||||
|
@ -137,9 +168,17 @@ private:
|
|||
// The lock protects mPendingReleaseItems.
|
||||
Mutex mPendingReleaseItemsLock;
|
||||
|
||||
// This TaskQueue should be the same one in mDecodeCallback->OnReaderTaskQueue().
|
||||
// This monitor protects mQueueSample.
|
||||
Monitor mMonitor;
|
||||
|
||||
// This TaskQueue should be the same one in mReaderCallback->OnReaderTaskQueue().
|
||||
// It is for codec resource mangement, decoding task should not dispatch to it.
|
||||
nsRefPtr<TaskQueue> mReaderTaskQueue;
|
||||
|
||||
// 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.
|
||||
nsTArray<nsRefPtr<MediaRawData>> mQueueSample;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
Загрузка…
Ссылка в новой задаче