зеркало из https://github.com/mozilla/gecko-dev.git
Backed out changeset ab6ddc8ac28a (bug 1097823)
This commit is contained in:
Родитель
5864562a3f
Коммит
60f876f46a
|
@ -317,4 +317,65 @@ MediaDecoderReader::Shutdown()
|
||||||
mTaskQueue = nullptr;
|
mTaskQueue = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AudioDecodeRendezvous::AudioDecodeRendezvous(MediaDecoderReader *aReader)
|
||||||
|
: mReader(aReader)
|
||||||
|
, mMonitor("AudioDecodeRendezvous")
|
||||||
|
, mHaveResult(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioDecodeRendezvous::~AudioDecodeRendezvous()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioDecodeRendezvous::OnAudioDecoded(AudioData* aSample)
|
||||||
|
{
|
||||||
|
MonitorAutoLock mon(mMonitor);
|
||||||
|
mSample = aSample;
|
||||||
|
mStatus = NS_OK;
|
||||||
|
mHaveResult = true;
|
||||||
|
mon.NotifyAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioDecodeRendezvous::OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
|
||||||
|
{
|
||||||
|
MonitorAutoLock mon(mMonitor);
|
||||||
|
mSample = nullptr;
|
||||||
|
mStatus = aReason == MediaDecoderReader::DECODE_ERROR ? NS_ERROR_FAILURE : NS_OK;
|
||||||
|
mHaveResult = true;
|
||||||
|
mon.NotifyAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AudioDecodeRendezvous::Reset()
|
||||||
|
{
|
||||||
|
MonitorAutoLock mon(mMonitor);
|
||||||
|
mHaveResult = false;
|
||||||
|
mStatus = NS_OK;
|
||||||
|
mSample = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
AudioDecodeRendezvous::RequestAndWait(nsRefPtr<AudioData>& aSample)
|
||||||
|
{
|
||||||
|
MonitorAutoLock mon(mMonitor);
|
||||||
|
// XXXbholley: We hackily use the main thread for calling back the rendezvous,
|
||||||
|
// since the decode thread is blocked. This is fine for correctness but not
|
||||||
|
// for jank, and so it goes away in a subsequent patch.
|
||||||
|
nsCOMPtr<nsIThread> mainThread;
|
||||||
|
nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
mReader->RequestAudioData()->Then(mainThread.get(), __func__, this,
|
||||||
|
&AudioDecodeRendezvous::OnAudioDecoded,
|
||||||
|
&AudioDecodeRendezvous::OnAudioNotDecoded);
|
||||||
|
while (!mHaveResult) {
|
||||||
|
mon.Wait();
|
||||||
|
}
|
||||||
|
mHaveResult = false;
|
||||||
|
aSample = mSample;
|
||||||
|
return mStatus;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
|
@ -334,6 +334,38 @@ protected:
|
||||||
virtual ~RequestSampleCallback() {}
|
virtual ~RequestSampleCallback() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// A RequestSampleCallback implementation that can be passed to the
|
||||||
|
// MediaDecoderReader to block the thread requesting an audio sample until
|
||||||
|
// the audio decode is complete. This is used to adapt the asynchronous
|
||||||
|
// model of the MediaDecoderReader to a synchronous model.
|
||||||
|
class AudioDecodeRendezvous {
|
||||||
|
public:
|
||||||
|
AudioDecodeRendezvous(MediaDecoderReader *aReader);
|
||||||
|
|
||||||
|
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AudioDecodeRendezvous)
|
||||||
|
|
||||||
|
void OnAudioDecoded(AudioData* aSample);
|
||||||
|
void OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
// Returns failure on error, or NS_OK.
|
||||||
|
// If *aSample is null, EOS has been reached.
|
||||||
|
nsresult RequestAndWait(nsRefPtr<AudioData>& aSample);
|
||||||
|
|
||||||
|
// Interrupts a call to Wait().
|
||||||
|
void Cancel();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
~AudioDecodeRendezvous();
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsRefPtr<MediaDecoderReader> mReader;
|
||||||
|
Monitor mMonitor;
|
||||||
|
nsresult mStatus;
|
||||||
|
nsRefPtr<AudioData> mSample;
|
||||||
|
bool mHaveResult;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace mozilla
|
} // namespace mozilla
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
extern PRLogModuleInfo* gMediaPromiseLog;
|
extern PRLogModuleInfo* gMediaPromiseLog;
|
||||||
|
void EnsureMediaPromiseLog();
|
||||||
|
|
||||||
#define PROMISE_LOG(x, ...) \
|
#define PROMISE_LOG(x, ...) \
|
||||||
MOZ_ASSERT(gMediaPromiseLog); \
|
MOZ_ASSERT(gMediaPromiseLog); \
|
||||||
|
@ -232,9 +233,8 @@ protected:
|
||||||
void DispatchAll()
|
void DispatchAll()
|
||||||
{
|
{
|
||||||
mMutex.AssertCurrentThreadOwns();
|
mMutex.AssertCurrentThreadOwns();
|
||||||
for (size_t i = 0; i < mThenValues.Length(); ++i) {
|
for (size_t i = 0; i < mThenValues.Length(); ++i)
|
||||||
mThenValues[i]->Dispatch(this);
|
mThenValues[i]->Dispatch(this);
|
||||||
}
|
|
||||||
mThenValues.Clear();
|
mThenValues.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -976,7 +976,7 @@ bool OggReader::ReadOggPage(ogg_page* aPage)
|
||||||
|
|
||||||
ogg_packet* OggReader::NextOggPacket(OggCodecState* aCodecState)
|
ogg_packet* OggReader::NextOggPacket(OggCodecState* aCodecState)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread.");
|
||||||
|
|
||||||
if (!aCodecState || !aCodecState->mActive) {
|
if (!aCodecState || !aCodecState->mActive) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -474,7 +474,7 @@ AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
|
||||||
uint8_t* data = static_cast<uint8_t*>(JS_StealArrayBufferContents(cx, obj));
|
uint8_t* data = static_cast<uint8_t*>(JS_StealArrayBufferContents(cx, obj));
|
||||||
|
|
||||||
// Sniff the content of the media.
|
// Sniff the content of the media.
|
||||||
// Failed type sniffing will be handled by AsyncDecodeWebAudio.
|
// Failed type sniffing will be handled by AsyncDecodeMedia.
|
||||||
nsAutoCString contentType;
|
nsAutoCString contentType;
|
||||||
NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, length, contentType);
|
NS_SniffContent(NS_DATA_SNIFFER_CATEGORY, nullptr, data, length, contentType);
|
||||||
|
|
||||||
|
@ -489,7 +489,7 @@ AudioContext::DecodeAudioData(const ArrayBuffer& aBuffer,
|
||||||
nsRefPtr<WebAudioDecodeJob> job(
|
nsRefPtr<WebAudioDecodeJob> job(
|
||||||
new WebAudioDecodeJob(contentType, this,
|
new WebAudioDecodeJob(contentType, this,
|
||||||
promise, successCallback, failureCallback));
|
promise, successCallback, failureCallback));
|
||||||
AsyncDecodeWebAudio(contentType.get(), data, length, *job);
|
mDecoder.AsyncDecodeMedia(contentType.get(), data, length, *job);
|
||||||
// Transfer the ownership to mDecodeJobs
|
// Transfer the ownership to mDecodeJobs
|
||||||
mDecodeJobs.AppendElement(job.forget());
|
mDecodeJobs.AppendElement(job.forget());
|
||||||
|
|
||||||
|
@ -585,6 +585,8 @@ AudioContext::Shutdown()
|
||||||
Mute();
|
Mute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDecoder.Shutdown();
|
||||||
|
|
||||||
// Release references to active nodes.
|
// Release references to active nodes.
|
||||||
// Active AudioNodes don't unregister in destructors, at which point the
|
// Active AudioNodes don't unregister in destructors, at which point the
|
||||||
// Node is already unregistered.
|
// Node is already unregistered.
|
||||||
|
@ -699,6 +701,7 @@ AudioContext::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||||
if (mListener) {
|
if (mListener) {
|
||||||
amount += mListener->SizeOfIncludingThis(aMallocSizeOf);
|
amount += mListener->SizeOfIncludingThis(aMallocSizeOf);
|
||||||
}
|
}
|
||||||
|
amount += mDecoder.SizeOfExcludingThis(aMallocSizeOf);
|
||||||
amount += mDecodeJobs.SizeOfExcludingThis(aMallocSizeOf);
|
amount += mDecodeJobs.SizeOfExcludingThis(aMallocSizeOf);
|
||||||
for (uint32_t i = 0; i < mDecodeJobs.Length(); ++i) {
|
for (uint32_t i = 0; i < mDecodeJobs.Length(); ++i) {
|
||||||
amount += mDecodeJobs[i]->SizeOfIncludingThis(aMallocSizeOf);
|
amount += mDecodeJobs[i]->SizeOfIncludingThis(aMallocSizeOf);
|
||||||
|
|
|
@ -271,6 +271,7 @@ private:
|
||||||
const float mSampleRate;
|
const float mSampleRate;
|
||||||
nsRefPtr<AudioDestinationNode> mDestination;
|
nsRefPtr<AudioDestinationNode> mDestination;
|
||||||
nsRefPtr<AudioListener> mListener;
|
nsRefPtr<AudioListener> mListener;
|
||||||
|
MediaBufferDecoder mDecoder;
|
||||||
nsTArray<nsRefPtr<WebAudioDecodeJob> > mDecodeJobs;
|
nsTArray<nsRefPtr<WebAudioDecodeJob> > mDecodeJobs;
|
||||||
// See RegisterActiveNode. These will keep the AudioContext alive while it
|
// See RegisterActiveNode. These will keep the AudioContext alive while it
|
||||||
// is rendering and the window remains alive.
|
// is rendering and the window remains alive.
|
||||||
|
|
|
@ -37,10 +37,10 @@ BufferDecoder::~BufferDecoder()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
BufferDecoder::BeginDecoding(MediaTaskQueue* aTaskQueueIdentity)
|
BufferDecoder::BeginDecoding(nsIThread* aDecodeThread)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!mTaskQueueIdentity && aTaskQueueIdentity);
|
MOZ_ASSERT(!mDecodeThread && aDecodeThread);
|
||||||
mTaskQueueIdentity = aTaskQueueIdentity;
|
mDecodeThread = aDecodeThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReentrantMonitor&
|
ReentrantMonitor&
|
||||||
|
@ -66,8 +66,8 @@ BufferDecoder::OnStateMachineThread() const
|
||||||
bool
|
bool
|
||||||
BufferDecoder::OnDecodeThread() const
|
BufferDecoder::OnDecodeThread() const
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(mTaskQueueIdentity, "Forgot to call BeginDecoding?");
|
MOZ_ASSERT(mDecodeThread, "Forgot to call BeginDecoding?");
|
||||||
return mTaskQueueIdentity->IsCurrentThreadIn();
|
return IsCurrentThread(mDecodeThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
MediaResource*
|
MediaResource*
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#define BUFFER_DECODER_H_
|
#define BUFFER_DECODER_H_
|
||||||
|
|
||||||
#include "AbstractMediaDecoder.h"
|
#include "AbstractMediaDecoder.h"
|
||||||
#include "MediaTaskQueue.h"
|
|
||||||
#include "mozilla/Attributes.h"
|
#include "mozilla/Attributes.h"
|
||||||
#include "mozilla/ReentrantMonitor.h"
|
#include "mozilla/ReentrantMonitor.h"
|
||||||
|
|
||||||
|
@ -28,7 +27,7 @@ public:
|
||||||
NS_DECL_THREADSAFE_ISUPPORTS
|
NS_DECL_THREADSAFE_ISUPPORTS
|
||||||
|
|
||||||
// This has to be called before decoding begins
|
// This has to be called before decoding begins
|
||||||
void BeginDecoding(MediaTaskQueue* aTaskQueueIdentity);
|
void BeginDecoding(nsIThread* aDecodeThread);
|
||||||
|
|
||||||
virtual ReentrantMonitor& GetReentrantMonitor() MOZ_FINAL MOZ_OVERRIDE;
|
virtual ReentrantMonitor& GetReentrantMonitor() MOZ_FINAL MOZ_OVERRIDE;
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ private:
|
||||||
// It's just there in order for us to be able to override
|
// It's just there in order for us to be able to override
|
||||||
// GetReentrantMonitor correctly.
|
// GetReentrantMonitor correctly.
|
||||||
ReentrantMonitor mReentrantMonitor;
|
ReentrantMonitor mReentrantMonitor;
|
||||||
nsRefPtr<MediaTaskQueue> mTaskQueueIdentity;
|
nsCOMPtr<nsIThread> mDecodeThread;
|
||||||
nsRefPtr<MediaResource> mResource;
|
nsRefPtr<MediaResource> mResource;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -20,9 +20,11 @@
|
||||||
#include "nsIScriptObjectPrincipal.h"
|
#include "nsIScriptObjectPrincipal.h"
|
||||||
#include "nsIScriptError.h"
|
#include "nsIScriptError.h"
|
||||||
#include "nsMimeTypes.h"
|
#include "nsMimeTypes.h"
|
||||||
#include "VideoUtils.h"
|
|
||||||
#include "WebAudioUtils.h"
|
#include "WebAudioUtils.h"
|
||||||
#include "mozilla/dom/Promise.h"
|
#include "mozilla/dom/Promise.h"
|
||||||
|
#ifdef XP_WIN
|
||||||
|
#include "ThreadPoolCOMListener.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace mozilla {
|
namespace mozilla {
|
||||||
|
|
||||||
|
@ -93,12 +95,14 @@ class MediaDecodeTask : public nsRunnable
|
||||||
public:
|
public:
|
||||||
MediaDecodeTask(const char* aContentType, uint8_t* aBuffer,
|
MediaDecodeTask(const char* aContentType, uint8_t* aBuffer,
|
||||||
uint32_t aLength,
|
uint32_t aLength,
|
||||||
WebAudioDecodeJob& aDecodeJob)
|
WebAudioDecodeJob& aDecodeJob,
|
||||||
|
nsIThreadPool* aThreadPool)
|
||||||
: mContentType(aContentType)
|
: mContentType(aContentType)
|
||||||
, mBuffer(aBuffer)
|
, mBuffer(aBuffer)
|
||||||
, mLength(aLength)
|
, mLength(aLength)
|
||||||
, mDecodeJob(aDecodeJob)
|
, mDecodeJob(aDecodeJob)
|
||||||
, mPhase(PhaseEnum::Decode)
|
, mPhase(PhaseEnum::Decode)
|
||||||
|
, mThreadPool(aThreadPool)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aBuffer);
|
MOZ_ASSERT(aBuffer);
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
@ -113,7 +117,6 @@ public:
|
||||||
|
|
||||||
NS_IMETHOD Run();
|
NS_IMETHOD Run();
|
||||||
bool CreateReader();
|
bool CreateReader();
|
||||||
MediaDecoderReader* Reader() { MOZ_ASSERT(mDecoderReader); return mDecoderReader; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ReportFailureOnMainThread(WebAudioDecodeJob::ErrorCode aErrorCode) {
|
void ReportFailureOnMainThread(WebAudioDecodeJob::ErrorCode aErrorCode) {
|
||||||
|
@ -131,10 +134,6 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void Decode();
|
void Decode();
|
||||||
void RequestSample();
|
|
||||||
void SampleDecoded(AudioData* aData);
|
|
||||||
void SampleNotDecoded(MediaDecoderReader::NotDecodedReason aReason);
|
|
||||||
void FinishDecode();
|
|
||||||
void AllocateBuffer();
|
void AllocateBuffer();
|
||||||
void CallbackTheResult();
|
void CallbackTheResult();
|
||||||
|
|
||||||
|
@ -155,11 +154,10 @@ private:
|
||||||
uint32_t mLength;
|
uint32_t mLength;
|
||||||
WebAudioDecodeJob& mDecodeJob;
|
WebAudioDecodeJob& mDecodeJob;
|
||||||
PhaseEnum mPhase;
|
PhaseEnum mPhase;
|
||||||
|
nsCOMPtr<nsIThreadPool> mThreadPool;
|
||||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||||
nsRefPtr<BufferDecoder> mBufferDecoder;
|
nsRefPtr<BufferDecoder> mBufferDecoder;
|
||||||
nsRefPtr<MediaDecoderReader> mDecoderReader;
|
nsRefPtr<MediaDecoderReader> mDecoderReader;
|
||||||
MediaInfo mMediaInfo;
|
|
||||||
MediaQueue<AudioData> mAudioQueue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_IMETHODIMP
|
NS_IMETHODIMP
|
||||||
|
@ -207,10 +205,6 @@ MediaDecodeTask::CreateReader()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mDecoderReader->EnsureTaskQueue()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,15 +238,16 @@ MediaDecodeTask::Decode()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
|
||||||
mBufferDecoder->BeginDecoding(mDecoderReader->GetTaskQueue());
|
mBufferDecoder->BeginDecoding(NS_GetCurrentThread());
|
||||||
|
|
||||||
// Tell the decoder reader that we are not going to play the data directly,
|
// Tell the decoder reader that we are not going to play the data directly,
|
||||||
// and that we should not reject files with more channels than the audio
|
// and that we should not reject files with more channels than the audio
|
||||||
// bakend support.
|
// bakend support.
|
||||||
mDecoderReader->SetIgnoreAudioOutputFormat();
|
mDecoderReader->SetIgnoreAudioOutputFormat();
|
||||||
|
|
||||||
|
MediaInfo mediaInfo;
|
||||||
nsAutoPtr<MetadataTags> tags;
|
nsAutoPtr<MetadataTags> tags;
|
||||||
nsresult rv = mDecoderReader->ReadMetadata(&mMediaInfo, getter_Transfers(tags));
|
nsresult rv = mDecoderReader->ReadMetadata(&mediaInfo, getter_Transfers(tags));
|
||||||
if (NS_FAILED(rv)) {
|
if (NS_FAILED(rv)) {
|
||||||
mDecoderReader->Shutdown();
|
mDecoderReader->Shutdown();
|
||||||
ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
|
ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
|
||||||
|
@ -265,46 +260,26 @@ MediaDecodeTask::Decode()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestSample();
|
MediaQueue<AudioData> audioQueue;
|
||||||
}
|
nsRefPtr<AudioDecodeRendezvous> barrier(new AudioDecodeRendezvous(mDecoderReader));
|
||||||
|
while (1) {
|
||||||
void
|
nsRefPtr<AudioData> audio;
|
||||||
MediaDecodeTask::RequestSample()
|
if (NS_FAILED(barrier->RequestAndWait(audio))) {
|
||||||
{
|
mDecoderReader->Shutdown();
|
||||||
mDecoderReader->RequestAudioData()->Then(mDecoderReader->GetTaskQueue(), __func__, this,
|
ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
|
||||||
&MediaDecodeTask::SampleDecoded,
|
return;
|
||||||
&MediaDecodeTask::SampleNotDecoded);
|
}
|
||||||
}
|
if (!audio) {
|
||||||
|
// End of stream.
|
||||||
void
|
break;
|
||||||
MediaDecodeTask::SampleDecoded(AudioData* aData)
|
}
|
||||||
{
|
audioQueue.Push(audio);
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
|
||||||
mAudioQueue.Push(aData);
|
|
||||||
RequestSample();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MediaDecodeTask::SampleNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
|
|
||||||
{
|
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
|
||||||
if (aReason == MediaDecoderReader::DECODE_ERROR) {
|
|
||||||
mDecoderReader->Shutdown();
|
|
||||||
ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
|
|
||||||
} else {
|
|
||||||
MOZ_ASSERT(aReason == MediaDecoderReader::END_OF_STREAM);
|
|
||||||
FinishDecode();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
MediaDecodeTask::FinishDecode()
|
|
||||||
{
|
|
||||||
mDecoderReader->Shutdown();
|
mDecoderReader->Shutdown();
|
||||||
|
|
||||||
uint32_t frameCount = mAudioQueue.FrameCount();
|
uint32_t frameCount = audioQueue.FrameCount();
|
||||||
uint32_t channelCount = mMediaInfo.mAudio.mChannels;
|
uint32_t channelCount = mediaInfo.mAudio.mChannels;
|
||||||
uint32_t sampleRate = mMediaInfo.mAudio.mRate;
|
uint32_t sampleRate = mediaInfo.mAudio.mRate;
|
||||||
|
|
||||||
if (!frameCount || !channelCount || !sampleRate) {
|
if (!frameCount || !channelCount || !sampleRate) {
|
||||||
ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
|
ReportFailureOnMainThread(WebAudioDecodeJob::InvalidContent);
|
||||||
|
@ -352,7 +327,7 @@ MediaDecodeTask::FinishDecode()
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRefPtr<AudioData> audioData;
|
nsRefPtr<AudioData> audioData;
|
||||||
while ((audioData = mAudioQueue.PopFront())) {
|
while ((audioData = audioQueue.PopFront())) {
|
||||||
audioData->EnsureAudioBuffer(); // could lead to a copy :(
|
audioData->EnsureAudioBuffer(); // could lead to a copy :(
|
||||||
AudioDataValue* bufferData = static_cast<AudioDataValue*>
|
AudioDataValue* bufferData = static_cast<AudioDataValue*>
|
||||||
(audioData->mAudioBuffer->Data());
|
(audioData->mAudioBuffer->Data());
|
||||||
|
@ -465,8 +440,9 @@ WebAudioDecodeJob::AllocateBuffer()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
AsyncDecodeWebAudio(const char* aContentType, uint8_t* aBuffer,
|
MediaBufferDecoder::AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
|
||||||
uint32_t aLength, WebAudioDecodeJob& aDecodeJob)
|
uint32_t aLength,
|
||||||
|
WebAudioDecodeJob& aDecodeJob)
|
||||||
{
|
{
|
||||||
// Do not attempt to decode the media if we were not successful at sniffing
|
// Do not attempt to decode the media if we were not successful at sniffing
|
||||||
// the content type.
|
// the content type.
|
||||||
|
@ -481,8 +457,20 @@ AsyncDecodeWebAudio(const char* aContentType, uint8_t* aBuffer,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RefPtr<MediaDecodeTask> task =
|
if (!EnsureThreadPoolInitialized()) {
|
||||||
new MediaDecodeTask(aContentType, aBuffer, aLength, aDecodeJob);
|
nsCOMPtr<nsIRunnable> event =
|
||||||
|
new ReportResultTask(aDecodeJob,
|
||||||
|
&WebAudioDecodeJob::OnFailure,
|
||||||
|
WebAudioDecodeJob::UnknownError);
|
||||||
|
JS_free(nullptr, aBuffer);
|
||||||
|
NS_DispatchToMainThread(event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(mThreadPool);
|
||||||
|
|
||||||
|
nsRefPtr<MediaDecodeTask> task =
|
||||||
|
new MediaDecodeTask(aContentType, aBuffer, aLength, aDecodeJob, mThreadPool);
|
||||||
if (!task->CreateReader()) {
|
if (!task->CreateReader()) {
|
||||||
nsCOMPtr<nsIRunnable> event =
|
nsCOMPtr<nsIRunnable> event =
|
||||||
new ReportResultTask(aDecodeJob,
|
new ReportResultTask(aDecodeJob,
|
||||||
|
@ -490,7 +478,37 @@ AsyncDecodeWebAudio(const char* aContentType, uint8_t* aBuffer,
|
||||||
WebAudioDecodeJob::UnknownError);
|
WebAudioDecodeJob::UnknownError);
|
||||||
NS_DispatchToMainThread(event);
|
NS_DispatchToMainThread(event);
|
||||||
} else {
|
} else {
|
||||||
task->Reader()->GetTaskQueue()->Dispatch(task);
|
mThreadPool->Dispatch(task, nsIThreadPool::DISPATCH_NORMAL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MediaBufferDecoder::EnsureThreadPoolInitialized()
|
||||||
|
{
|
||||||
|
if (!mThreadPool) {
|
||||||
|
mThreadPool = do_CreateInstance(NS_THREADPOOL_CONTRACTID);
|
||||||
|
if (!mThreadPool) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mThreadPool->SetName(NS_LITERAL_CSTRING("MediaBufferDecoder"));
|
||||||
|
#ifdef XP_WIN
|
||||||
|
// Ensure MSCOM is initialized on the thread pools threads.
|
||||||
|
nsCOMPtr<nsIThreadPoolListener> listener = new MSCOMInitThreadPoolListener();
|
||||||
|
nsresult rv = mThreadPool->SetListener(listener);
|
||||||
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MediaBufferDecoder::Shutdown() {
|
||||||
|
if (mThreadPool) {
|
||||||
|
// Setting threadLimit to 0 causes threads to exit when all events have
|
||||||
|
// been run, like nsIThreadPool::Shutdown(), but doesn't run a nested event
|
||||||
|
// loop nor wait until this has happened.
|
||||||
|
mThreadPool->SetThreadLimit(0);
|
||||||
|
mThreadPool = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "nsWrapperCache.h"
|
#include "nsWrapperCache.h"
|
||||||
#include "nsCOMPtr.h"
|
#include "nsCOMPtr.h"
|
||||||
|
#include "nsIThreadPool.h"
|
||||||
#include "nsString.h"
|
#include "nsString.h"
|
||||||
#include "nsTArray.h"
|
#include "nsTArray.h"
|
||||||
#include "mozilla/dom/TypedArray.h"
|
#include "mozilla/dom/TypedArray.h"
|
||||||
|
@ -69,8 +70,32 @@ private:
|
||||||
~WebAudioDecodeJob();
|
~WebAudioDecodeJob();
|
||||||
};
|
};
|
||||||
|
|
||||||
void AsyncDecodeWebAudio(const char* aContentType, uint8_t* aBuffer,
|
/**
|
||||||
uint32_t aLength, WebAudioDecodeJob& aDecodeJob);
|
* This class is used to decode media buffers on a dedicated threadpool.
|
||||||
|
*
|
||||||
|
* This class manages the resources that it uses internally (such as the
|
||||||
|
* thread-pool) and provides a clean external interface.
|
||||||
|
*/
|
||||||
|
class MediaBufferDecoder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void AsyncDecodeMedia(const char* aContentType, uint8_t* aBuffer,
|
||||||
|
uint32_t aLength, WebAudioDecodeJob& aDecodeJob);
|
||||||
|
|
||||||
|
~MediaBufferDecoder() { Shutdown(); }
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool EnsureThreadPoolInitialized();
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsCOMPtr<nsIThreadPool> mThreadPool;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче