--- a/dom/media/fmp4/eme/EMEAudioDecoder.cpp
+++ b/dom/media/fmp4/eme/EMEAudioDecoder.cpp
@@ -1,343 +1,37 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EMEAudioDecoder.h"
-#include "mp4_demuxer/DecoderData.h"
-#include "mozilla/EMELog.h"
-#include "gmp-audio-host.h"
-#include "gmp-audio-decode.h"
-#include "gmp-audio-samples.h"
-#include "GMPAudioHost.h"
-#include "GMPAudioDecoderProxy.h"
#include "mozilla/CDMProxy.h"
-#include "nsServiceManagerUtils.h"
-#include "prsystem.h"
namespace mozilla {
-EMEAudioDecoder::EMEAudioDecoder(CDMProxy* aProxy,
- const AudioDecoderConfig& aConfig,
- MediaTaskQueue* aTaskQueue,
- MediaDataDecoderCallback* aCallback)
- : mAudioRate(0)
- , mAudioBytesPerSample(0)
- , mAudioChannels(0)
- , mMustRecaptureAudioPosition(true)
- , mAudioFrameSum(0)
- , mAudioFrameOffset(0)
- , mStreamOffset(0)
- , mProxy(aProxy)
- , mGMP(nullptr)
- , mConfig(aConfig)
- , mTaskQueue(aTaskQueue)
- , mCallback(aCallback)
- , mSamplesWaitingForKey(new SamplesWaitingForKey(this, mTaskQueue, mProxy))
- , mMonitor("EMEAudioDecoder")
- , mFlushComplete(false)
-#ifdef DEBUG
- , mIsShutdown(false)
-#endif
-{
-}
-
-EMEAudioDecoder::~EMEAudioDecoder()
-{
-}
-
-nsresult
-EMEAudioDecoder::Init()
-{
- // Note: this runs on the decode task queue.
- MOZ_ASSERT(!mIsShutdown);
-
- MOZ_ASSERT((mConfig.bits_per_sample / 8) == 2); // Demuxer guarantees this.
-
- mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
- MOZ_ASSERT(mMPS);
-
- nsresult rv = mMPS->GetThread(getter_AddRefs(mGMPThread));
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsRefPtr<InitTask> task(new InitTask(this));
- rv = mGMPThread->Dispatch(task, NS_DISPATCH_SYNC);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ENSURE_SUCCESS(task->mResult, task->mResult);
-
- return NS_OK;
-}
-
-nsresult
-EMEAudioDecoder::Input(MP4Sample* aSample)
-{
- MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
- MOZ_ASSERT(!mIsShutdown);
-
- if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
- return NS_OK;
- }
-
- nsRefPtr<nsIRunnable> task(new DeliverSample(this, aSample));
- nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
- NS_ENSURE_SUCCESS(rv, rv);
-
- return NS_OK;
-}
-
-nsresult
-EMEAudioDecoder::Flush()
-{
- MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
- MOZ_ASSERT(!mIsShutdown);
-
- {
- MonitorAutoLock mon(mMonitor);
- mFlushComplete = false;
- }
-
- nsRefPtr<nsIRunnable> task;
- task = NS_NewRunnableMethod(this, &EMEAudioDecoder::GmpFlush);
- nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
- NS_ENSURE_SUCCESS(rv, rv);
-
- {
- MonitorAutoLock mon(mMonitor);
- while (!mFlushComplete) {
- mon.Wait();
- }
- }
-
- return NS_OK;
-}
-
-nsresult
-EMEAudioDecoder::Drain()
-{
- MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
- MOZ_ASSERT(!mIsShutdown);
-
- nsRefPtr<nsIRunnable> task;
- task = NS_NewRunnableMethod(this, &EMEAudioDecoder::GmpDrain);
- nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
- NS_ENSURE_SUCCESS(rv, rv);
- return NS_OK;
-}
-
-nsresult
-EMEAudioDecoder::Shutdown()
+void
+EMEAudioCallbackAdapter::Error(GMPErr aErr)
{
- MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
- MOZ_ASSERT(!mIsShutdown);
-#ifdef DEBUG
- mIsShutdown = true;
-#endif
-
- nsRefPtr<nsIRunnable> task;
- task = NS_NewRunnableMethod(this, &EMEAudioDecoder::GmpShutdown);
- nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_SYNC);
- NS_ENSURE_SUCCESS(rv, rv);
-
- mSamplesWaitingForKey->BreakCycles();
- mSamplesWaitingForKey = nullptr;
-
- return NS_OK;
-}
-
-void
-EMEAudioDecoder::Decoded(const nsTArray<int16_t>& aPCM,
- uint64_t aTimeStamp,
- uint32_t aChannels,
- uint32_t aRate)
-{
- MOZ_ASSERT(IsOnGMPThread());
-
- if (aRate == 0 || aChannels == 0) {
- NS_WARNING("Invalid rate or num channels returned on GMP audio samples");
- mCallback->Error();
- return;
- }
-
- size_t numFrames = aPCM.Length() / aChannels;
- MOZ_ASSERT((aPCM.Length() % aChannels) == 0);
- nsAutoArrayPtr<AudioDataValue> audioData(new AudioDataValue[aPCM.Length()]);
-
- for (size_t i = 0; i < aPCM.Length(); ++i) {
- audioData[i] = AudioSampleToFloat(aPCM[i]);
- }
-
- if (mMustRecaptureAudioPosition) {
- mAudioFrameSum = 0;
- auto timestamp = UsecsToFrames(aTimeStamp, aRate);
- if (!timestamp.isValid()) {
- NS_WARNING("Invalid timestamp");
- mCallback->Error();
- return;
- }
- mAudioFrameOffset = timestamp.value();
- MOZ_ASSERT(mAudioFrameOffset >= 0);
- mMustRecaptureAudioPosition = false;
- }
-
- auto timestamp = FramesToUsecs(mAudioFrameOffset + mAudioFrameSum, aRate);
- if (!timestamp.isValid()) {
- NS_WARNING("Invalid timestamp on audio samples");
- mCallback->Error();
- return;
- }
- mAudioFrameSum += numFrames;
-
- auto duration = FramesToUsecs(numFrames, aRate);
- if (!duration.isValid()) {
- NS_WARNING("Invalid duration on audio samples");
- mCallback->Error();
- return;
- }
-
- nsRefPtr<AudioData> audio(new AudioData(mStreamOffset,
- timestamp.value(),
- duration.value(),
- numFrames,
- audioData.forget(),
- aChannels,
- aRate));
-
- #ifdef LOG_SAMPLE_DECODE
- LOG("Decoded audio sample! timestamp=%lld duration=%lld currentLength=%u",
- timestamp, duration, currentLength);
- #endif
-
- mCallback->Output(audio);
-}
-
-void
-EMEAudioDecoder::InputDataExhausted()
-{
- MOZ_ASSERT(IsOnGMPThread());
- mCallback->InputExhausted();
-}
-
-void
-EMEAudioDecoder::DrainComplete()
-{
- MOZ_ASSERT(IsOnGMPThread());
- mCallback->DrainComplete();
-}
-
-void
-EMEAudioDecoder::ResetComplete()
-{
- MOZ_ASSERT(IsOnGMPThread());
- mMustRecaptureAudioPosition = true;
- {
- MonitorAutoLock mon(mMonitor);
- mFlushComplete = true;
- mon.NotifyAll();
- }
-}
-
-void
-EMEAudioDecoder::Error(GMPErr aErr)
-{
- MOZ_ASSERT(IsOnGMPThread());
- EME_LOG("EMEAudioDecoder::Error %d", aErr);
if (aErr == GMPNoKeyErr) {
// The GMP failed to decrypt a frame due to not having a key. This can
// happen if a key expires or a session is closed during playback.
NS_WARNING("GMP failed to decrypt due to lack of key");
- } else {
- mCallback->Error();
- GmpShutdown();
+ return;
}
+ AudioCallbackAdapter::Error(aErr);
}
void
-EMEAudioDecoder::Terminated()
-{
- MOZ_ASSERT(IsOnGMPThread());
- GmpShutdown();
-}
-
-nsresult
-EMEAudioDecoder::GmpInit()
+EMEAudioDecoder::InitTags(nsTArray<nsCString>& aTags)
{
- MOZ_ASSERT(IsOnGMPThread());
-
- nsTArray<nsCString> tags;
- tags.AppendElement(NS_LITERAL_CSTRING("aac"));
- tags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
- nsresult rv = mMPS->GetGMPAudioDecoder(&tags,
- mProxy->GetNodeId(),
- &mGMP);
- NS_ENSURE_SUCCESS(rv, rv);
- MOZ_ASSERT(mGMP);
-
- mAudioRate = mConfig.samples_per_second;
- mAudioBytesPerSample = mConfig.bits_per_sample / 8;
- mAudioChannels = mConfig.channel_count;
-
- nsTArray<uint8_t> extraData;
- extraData.AppendElements(mConfig.audio_specific_config->Elements(),
- mConfig.audio_specific_config->Length());
- mGMP->InitDecode(kGMPAudioCodecAAC,
- mAudioChannels,
- mConfig.bits_per_sample,
- mAudioRate,
- extraData,
- this);
-
- return NS_OK;
+ GMPAudioDecoder::InitTags(aTags);
+ aTags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
}
-nsresult
-EMEAudioDecoder::GmpInput(MP4Sample* aSample)
-{
- MOZ_ASSERT(IsOnGMPThread());
- nsAutoPtr<MP4Sample> sample(aSample);
- if (!mGMP) {
- mCallback->Error();
- return NS_ERROR_FAILURE;
- }
-
- gmp::GMPAudioSamplesImpl samples(sample, mAudioChannels, mAudioRate);
- mGMP->Decode(samples);
-
- mStreamOffset = sample->byte_offset;
-
- return NS_OK;
-}
-
-void
-EMEAudioDecoder::GmpFlush()
+nsCString
+EMEAudioDecoder::GetNodeId()
{
- MOZ_ASSERT(IsOnGMPThread());
- if (!mGMP || NS_FAILED(mGMP->Reset())) {
- // Abort the flush...
- MonitorAutoLock mon(mMonitor);
- mFlushComplete = true;
- mon.NotifyAll();
- }
-}
-
-void
-EMEAudioDecoder::GmpDrain()
-{
- MOZ_ASSERT(IsOnGMPThread());
- if (!mGMP || NS_FAILED(mGMP->Drain())) {
- mCallback->DrainComplete();
- }
-}
-
-void
-EMEAudioDecoder::GmpShutdown()
-{
- MOZ_ASSERT(IsOnGMPThread());
- if (!mGMP) {
- return;
- }
- mGMP->Close();
- mGMP = nullptr;
+ return mProxy->GetNodeId();
}
} // namespace mozilla
--- a/dom/media/fmp4/eme/EMEAudioDecoder.h
+++ b/dom/media/fmp4/eme/EMEAudioDecoder.h
@@ -1,124 +1,44 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifndef EMEAACDecoder_h_
-#define EMEAACDecoder_h_
+#ifndef EMEAudioDecoder_h_
+#define EMEAudioDecoder_h_
+#include "GMPAudioDecoder.h"
#include "PlatformDecoderModule.h"
-#include "mp4_demuxer/DecoderData.h"
-#include "mozIGeckoMediaPluginService.h"
-#include "nsServiceManagerUtils.h"
-#include "GMPAudioHost.h"
-#include "GMPAudioDecoderProxy.h"
-#include "SamplesWaitingForKey.h"
namespace mozilla {
-class EMEAudioDecoder : public MediaDataDecoder
- , public GMPAudioDecoderCallbackProxy
-{
- typedef mp4_demuxer::MP4Sample MP4Sample;
- typedef mp4_demuxer::AudioDecoderConfig AudioDecoderConfig;
+class EMEAudioCallbackAdapter : public AudioCallbackAdapter {
+public:
+ explicit EMEAudioCallbackAdapter(MediaDataDecoderCallbackProxy* aCallback)
+ : AudioCallbackAdapter(aCallback)
+ {}
+
+ virtual void Error(GMPErr aErr) MOZ_OVERRIDE;
+};
+
+class EMEAudioDecoder : public GMPAudioDecoder {
public:
EMEAudioDecoder(CDMProxy* aProxy,
- const AudioDecoderConfig& aConfig,
+ const mp4_demuxer::AudioDecoderConfig& aConfig,
MediaTaskQueue* aTaskQueue,
- MediaDataDecoderCallback* aCallback);
-
- ~EMEAudioDecoder();
-
- // MediaDataDecoder implementation.
- virtual nsresult Init() MOZ_OVERRIDE;
- virtual nsresult Input(MP4Sample* aSample) MOZ_OVERRIDE;
- virtual nsresult Flush() MOZ_OVERRIDE;
- virtual nsresult Drain() MOZ_OVERRIDE;
- virtual nsresult Shutdown() MOZ_OVERRIDE;
-
- // GMPAudioDecoderCallbackProxy implementation.
- virtual void Decoded(const nsTArray<int16_t>& aPCM,
- uint64_t aTimeStamp,
- uint32_t aChannels,
- uint32_t aRate) MOZ_OVERRIDE;
- virtual void InputDataExhausted() MOZ_OVERRIDE;
- virtual void DrainComplete() MOZ_OVERRIDE;
- virtual void ResetComplete() MOZ_OVERRIDE;
- virtual void Error(GMPErr aErr) MOZ_OVERRIDE;
- virtual void Terminated() MOZ_OVERRIDE;
+ MediaDataDecoderCallbackProxy* aCallback)
+ : GMPAudioDecoder(aConfig, aTaskQueue, aCallback, new EMEAudioCallbackAdapter(aCallback))
+ , mProxy(aProxy)
+ {
+ }
private:
-
- class DeliverSample : public nsRunnable {
- public:
- DeliverSample(EMEAudioDecoder* aDecoder,
- mp4_demuxer::MP4Sample* aSample)
- : mDecoder(aDecoder)
- , mSample(aSample)
- {}
-
- NS_IMETHOD Run() {
- mDecoder->GmpInput(mSample.forget());
- return NS_OK;
- }
- private:
- nsRefPtr<EMEAudioDecoder> mDecoder;
- nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
- };
-
- class InitTask : public nsRunnable {
- public:
- explicit InitTask(EMEAudioDecoder* aDecoder)
- : mDecoder(aDecoder)
- {}
- NS_IMETHOD Run() {
- mResult = mDecoder->GmpInit();
- return NS_OK;
- }
- nsresult mResult;
- EMEAudioDecoder* mDecoder;
- };
+ virtual void InitTags(nsTArray<nsCString>& aTags) MOZ_OVERRIDE;
+ virtual nsCString GetNodeId() MOZ_OVERRIDE;
- nsresult GmpInit();
- nsresult GmpInput(MP4Sample* aSample);
- void GmpFlush();
- void GmpDrain();
- void GmpShutdown();
-
-#ifdef DEBUG
- bool IsOnGMPThread() {
- return NS_GetCurrentThread() == mGMPThread;
- }
-#endif
-
- uint32_t mAudioRate;
- uint32_t mAudioBytesPerSample;
- uint32_t mAudioChannels;
- bool mMustRecaptureAudioPosition;
- int64_t mAudioFrameSum;
- int64_t mAudioFrameOffset;
- int64_t mStreamOffset;
-
- nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
- nsCOMPtr<nsIThread> mGMPThread;
nsRefPtr<CDMProxy> mProxy;
- GMPAudioDecoderProxy* mGMP;
-
- const mp4_demuxer::AudioDecoderConfig& mConfig;
- nsRefPtr<MediaTaskQueue> mTaskQueue;
- MediaDataDecoderCallback* mCallback;
-
- nsRefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
-
- Monitor mMonitor;
- bool mFlushComplete;
-
-#ifdef DEBUG
- bool mIsShutdown;
-#endif
};
} // namespace mozilla
#endif
--- a/dom/media/fmp4/eme/EMEDecoderModule.cpp
+++ b/dom/media/fmp4/eme/EMEDecoderModule.cpp
@@ -1,33 +1,22 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "EMEDecoderModule.h"
+#include "EMEAudioDecoder.h"
+#include "EMEVideoDecoder.h"
+#include "MediaDataDecoderProxy.h"
#include "mozIGeckoMediaPluginService.h"
-#include "nsServiceManagerUtils.h"
-#include "nsThreadUtils.h"
-#include "ImageContainer.h"
-#include "prsystem.h"
-#include "mp4_demuxer/DecoderData.h"
-#include "gfx2DGlue.h"
-#include "nsContentUtils.h"
#include "mozilla/CDMProxy.h"
-#include "mozilla/EMELog.h"
-#include "MediaTaskQueue.h"
-#include "SharedThreadPool.h"
-#include "mozilla/EMELog.h"
-#include "EMEH264Decoder.h"
-#include "EMEAudioDecoder.h"
#include "mozilla/unused.h"
-#include "SamplesWaitingForKey.h"
-#include <string>
+#include "nsServiceManagerUtils.h"
namespace mozilla {
class EMEDecryptor : public MediaDataDecoder {
typedef mp4_demuxer::MP4Sample MP4Sample;
public:
@@ -163,16 +152,52 @@ private:
nsRefPtr<FlushableMediaTaskQueue> mTaskQueue;
nsRefPtr<CDMProxy> mProxy;
nsRefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
#ifdef DEBUG
bool mIsShutdown;
#endif
};
+class EMEMediaDataDecoderProxy : public MediaDataDecoderProxy {
+public:
+ EMEMediaDataDecoderProxy(nsIThread* aProxyThread, MediaDataDecoderCallback* aCallback, CDMProxy* aProxy, FlushableMediaTaskQueue* aTaskQueue)
+ : MediaDataDecoderProxy(aProxyThread, aCallback)
+ , mSamplesWaitingForKey(new SamplesWaitingForKey(this, aTaskQueue, aProxy))
+ {
+ }
+
+ virtual nsresult Input(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
+ virtual nsresult Shutdown() MOZ_OVERRIDE;
+
+private:
+ nsRefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
+};
+
+nsresult
+EMEMediaDataDecoderProxy::Input(mp4_demuxer::MP4Sample* aSample)
+{
+ if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
+ return NS_OK;
+ }
+
+ return MediaDataDecoderProxy::Input(aSample);
+}
+
+nsresult
+EMEMediaDataDecoderProxy::Shutdown()
+{
+ nsresult rv = MediaDataDecoderProxy::Shutdown();
+
+ mSamplesWaitingForKey->BreakCycles();
+ mSamplesWaitingForKey = nullptr;
+
+ return rv;
+}
+
EMEDecoderModule::EMEDecoderModule(CDMProxy* aProxy,
PlatformDecoderModule* aPDM,
bool aCDMDecodesAudio,
bool aCDMDecodesVideo)
: mProxy(aProxy)
, mPDM(aPDM)
, mCDMDecodesAudio(aCDMDecodesAudio)
, mCDMDecodesVideo(aCDMDecodesVideo)
@@ -187,31 +212,50 @@ nsresult
EMEDecoderModule::Shutdown()
{
if (mPDM) {
return mPDM->Shutdown();
}
return NS_OK;
}
+static already_AddRefed<MediaDataDecoderProxy>
+CreateDecoderWrapper(MediaDataDecoderCallback* aCallback, CDMProxy* aProxy, FlushableMediaTaskQueue* aTaskQueue)
+{
+ nsCOMPtr<mozIGeckoMediaPluginService> gmpService = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
+ if (!gmpService) {
+ return nullptr;
+ }
+
+ nsCOMPtr<nsIThread> thread;
+ nsresult rv = gmpService->GetThread(getter_AddRefs(thread));
+ if (NS_FAILED(rv)) {
+ return nullptr;
+ }
+
+ nsRefPtr<MediaDataDecoderProxy> decoder(new EMEMediaDataDecoderProxy(thread, aCallback, aProxy, aTaskQueue));
+ return decoder.forget();
+}
+
already_AddRefed<MediaDataDecoder>
EMEDecoderModule::CreateVideoDecoder(const VideoDecoderConfig& aConfig,
layers::LayersBackend aLayersBackend,
layers::ImageContainer* aImageContainer,
FlushableMediaTaskQueue* aVideoTaskQueue,
MediaDataDecoderCallback* aCallback)
{
if (mCDMDecodesVideo && aConfig.crypto.valid) {
- nsRefPtr<MediaDataDecoder> decoder(new EMEH264Decoder(mProxy,
- aConfig,
- aLayersBackend,
- aImageContainer,
- aVideoTaskQueue,
- aCallback));
- return decoder.forget();
+ nsRefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aVideoTaskQueue);
+ wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy,
+ aConfig,
+ aLayersBackend,
+ aImageContainer,
+ aVideoTaskQueue,
+ wrapper->Callback()));
+ return wrapper.forget();
}
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateVideoDecoder(aConfig,
aLayersBackend,
aImageContainer,
aVideoTaskQueue,
aCallback));
if (!decoder) {
@@ -229,21 +273,22 @@ EMEDecoderModule::CreateVideoDecoder(con
}
already_AddRefed<MediaDataDecoder>
EMEDecoderModule::CreateAudioDecoder(const AudioDecoderConfig& aConfig,
FlushableMediaTaskQueue* aAudioTaskQueue,
MediaDataDecoderCallback* aCallback)
{
if (mCDMDecodesAudio && aConfig.crypto.valid) {
- nsRefPtr<MediaDataDecoder> decoder(new EMEAudioDecoder(mProxy,
- aConfig,
- aAudioTaskQueue,
- aCallback));
- return decoder.forget();
+ nsRefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(aCallback, mProxy, aAudioTaskQueue);
+ wrapper->SetProxyTarget(new EMEAudioDecoder(mProxy,
+ aConfig,
+ aAudioTaskQueue,
+ wrapper->Callback()));
+ return wrapper.forget();
}
nsRefPtr<MediaDataDecoder> decoder(mPDM->CreateAudioDecoder(aConfig,
aAudioTaskQueue,
aCallback));
if (!decoder) {
return nullptr;
}
rename from dom/media/fmp4/eme/EMEH264Decoder.cpp
rename to dom/media/fmp4/eme/EMEVideoDecoder.cpp
--- a/dom/media/fmp4/eme/EMEH264Decoder.cpp
+++ b/dom/media/fmp4/eme/EMEVideoDecoder.cpp
@@ -1,377 +1,48 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#include "EMEH264Decoder.h"
-#include "gmp-video-host.h"
-#include "gmp-video-decode.h"
-#include "gmp-video-frame-i420.h"
-#include "gmp-video-frame-encoded.h"
+#include "EMEVideoDecoder.h"
#include "GMPVideoEncodedFrameImpl.h"
-#include "mp4_demuxer/AnnexB.h"
#include "mozilla/CDMProxy.h"
-#include "nsServiceManagerUtils.h"
-#include "prsystem.h"
-#include "gfx2DGlue.h"
-#include "mozilla/EMELog.h"
-#include "mozilla/Move.h"
namespace mozilla {
-EMEH264Decoder::EMEH264Decoder(CDMProxy* aProxy,
- const mp4_demuxer::VideoDecoderConfig& aConfig,
- layers::LayersBackend aLayersBackend,
- layers::ImageContainer* aImageContainer,
- MediaTaskQueue* aTaskQueue,
- MediaDataDecoderCallback* aCallback)
- : mProxy(aProxy)
- , mGMP(nullptr)
- , mHost(nullptr)
- , mConfig(aConfig)
- , mImageContainer(aImageContainer)
- , mTaskQueue(aTaskQueue)
- , mCallback(aCallback)
- , mLastStreamOffset(0)
- , mSamplesWaitingForKey(new SamplesWaitingForKey(this, mTaskQueue, mProxy))
- , mMonitor("EMEH264Decoder")
- , mFlushComplete(false)
-#ifdef DEBUG
- , mIsShutdown(false)
-#endif
-{
-}
-
-EMEH264Decoder::~EMEH264Decoder() {
-}
-
-nsresult
-EMEH264Decoder::Init()
-{
- // Note: this runs on the decode task queue.
- MOZ_ASSERT(!mIsShutdown);
-
- mMPS = do_GetService("@mozilla.org/gecko-media-plugin-service;1");
- MOZ_ASSERT(mMPS);
-
- nsresult rv = mMPS->GetThread(getter_AddRefs(mGMPThread));
- NS_ENSURE_SUCCESS(rv, rv);
-
- nsRefPtr<InitTask> task(new InitTask(this));
- rv = mGMPThread->Dispatch(task, NS_DISPATCH_SYNC);
- NS_ENSURE_SUCCESS(rv, rv);
- NS_ENSURE_SUCCESS(task->mResult, task->mResult);
-
- return NS_OK;
-}
-
-nsresult
-EMEH264Decoder::Input(MP4Sample* aSample)
-{
- MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
- MOZ_ASSERT(!mIsShutdown);
-
- if (mSamplesWaitingForKey->WaitIfKeyNotUsable(aSample)) {
- return NS_OK;
- }
-
- nsRefPtr<nsIRunnable> task(new DeliverSample(this, aSample));
- nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
- NS_ENSURE_SUCCESS(rv, rv);
-
- return NS_OK;
-}
-
-nsresult
-EMEH264Decoder::Flush()
-{
- MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
- MOZ_ASSERT(!mIsShutdown);
-
- {
- MonitorAutoLock mon(mMonitor);
- mFlushComplete = false;
- }
-
- nsRefPtr<nsIRunnable> task;
- task = NS_NewRunnableMethod(this, &EMEH264Decoder::GmpFlush);
- nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
- NS_ENSURE_SUCCESS(rv, rv);
-
- {
- MonitorAutoLock mon(mMonitor);
- while (!mFlushComplete) {
- mon.Wait();
- }
- }
-
- return NS_OK;
-}
-
-nsresult
-EMEH264Decoder::Drain()
-{
- MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
- MOZ_ASSERT(!mIsShutdown);
-
- nsRefPtr<nsIRunnable> task;
- task = NS_NewRunnableMethod(this, &EMEH264Decoder::GmpDrain);
- nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_NORMAL);
- NS_ENSURE_SUCCESS(rv, rv);
- return NS_OK;
-}
-
-nsresult
-EMEH264Decoder::Shutdown()
+void
+EMEVideoCallbackAdapter::Error(GMPErr aErr)
{
- MOZ_ASSERT(!IsOnGMPThread()); // Runs on the decode task queue.
- MOZ_ASSERT(!mIsShutdown);
-#ifdef DEBUG
- mIsShutdown = true;
-#endif
-
- nsRefPtr<nsIRunnable> task;
- task = NS_NewRunnableMethod(this, &EMEH264Decoder::GmpShutdown);
- nsresult rv = mGMPThread->Dispatch(task, NS_DISPATCH_SYNC);
- NS_ENSURE_SUCCESS(rv, rv);
-
- mSamplesWaitingForKey->BreakCycles();
- mSamplesWaitingForKey = nullptr;
-
- return NS_OK;
-}
-
-void
-EMEH264Decoder::Decoded(GMPVideoi420Frame* aDecodedFrame)
-{
- MOZ_ASSERT(IsOnGMPThread());
-
- VideoData::YCbCrBuffer b;
-
- auto height = aDecodedFrame->Height();
- auto width = aDecodedFrame->Width();
-
- // Y (Y') plane
- b.mPlanes[0].mData = aDecodedFrame->Buffer(kGMPYPlane);
- b.mPlanes[0].mStride = aDecodedFrame->Stride(kGMPYPlane);
- b.mPlanes[0].mHeight = height;
- b.mPlanes[0].mWidth = width;
- b.mPlanes[0].mOffset = 0;
- b.mPlanes[0].mSkip = 0;
-
- // U plane (Cb)
- b.mPlanes[1].mData = aDecodedFrame->Buffer(kGMPUPlane);
- b.mPlanes[1].mStride = aDecodedFrame->Stride(kGMPUPlane);
- b.mPlanes[1].mHeight = height / 2;
- b.mPlanes[1].mWidth = width / 2;
- b.mPlanes[1].mOffset = 0;
- b.mPlanes[1].mSkip = 0;
-
- // V plane (Cr)
- b.mPlanes[2].mData = aDecodedFrame->Buffer(kGMPVPlane);
- b.mPlanes[2].mStride = aDecodedFrame->Stride(kGMPVPlane);
- b.mPlanes[2].mHeight = height / 2;
- b.mPlanes[2].mWidth = width / 2;
- b.mPlanes[2].mOffset = 0;
- b.mPlanes[2].mSkip = 0;
-
- gfx::IntRect pictureRegion(0, 0, width, height);
- nsRefPtr<VideoData> v = VideoData::Create(mVideoInfo,
- mImageContainer,
- mLastStreamOffset,
- aDecodedFrame->Timestamp(),
- aDecodedFrame->Duration(),
- b,
- false,
- -1,
- pictureRegion);
- aDecodedFrame->Destroy();
- mCallback->Output(v);
-}
-
-void
-EMEH264Decoder::ReceivedDecodedReferenceFrame(const uint64_t aPictureId)
-{
- // Ignore.
-}
-
-void
-EMEH264Decoder::ReceivedDecodedFrame(const uint64_t aPictureId)
-{
- // Ignore.
-}
-
-void
-EMEH264Decoder::InputDataExhausted()
-{
- MOZ_ASSERT(IsOnGMPThread());
- mCallback->InputExhausted();
-}
-
-void
-EMEH264Decoder::DrainComplete()
-{
- MOZ_ASSERT(IsOnGMPThread());
- mCallback->DrainComplete();
-}
-
-void
-EMEH264Decoder::ResetComplete()
-{
- MOZ_ASSERT(IsOnGMPThread());
- {
- MonitorAutoLock mon(mMonitor);
- mFlushComplete = true;
- mon.NotifyAll();
- }
-}
-
-void
-EMEH264Decoder::Error(GMPErr aErr)
-{
- MOZ_ASSERT(IsOnGMPThread());
- EME_LOG("EMEH264Decoder::Error %d", aErr);
if (aErr == GMPNoKeyErr) {
// The GMP failed to decrypt a frame due to not having a key. This can
// happen if a key expires or a session is closed during playback.
NS_WARNING("GMP failed to decrypt due to lack of key");
- } else {
- mCallback->Error();
- GmpShutdown();
+ return;
}
+ VideoCallbackAdapter::Error(aErr);
}
void
-EMEH264Decoder::Terminated()
-{
- MOZ_ASSERT(IsOnGMPThread());
-
- NS_WARNING("H.264 GMP decoder terminated.");
- GmpShutdown();
-}
-
-nsresult
-EMEH264Decoder::GmpInit()
+EMEVideoDecoder::InitTags(nsTArray<nsCString>& aTags)
{
- MOZ_ASSERT(IsOnGMPThread());
-
- nsTArray<nsCString> tags;
- tags.AppendElement(NS_LITERAL_CSTRING("h264"));
- tags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
- nsresult rv = mMPS->GetGMPVideoDecoder(&tags,
- mProxy->GetNodeId(),
- &mHost,
- &mGMP);
- NS_ENSURE_SUCCESS(rv, rv);
- MOZ_ASSERT(mHost && mGMP);
-
- GMPVideoCodec codec;
- memset(&codec, 0, sizeof(codec));
-
- codec.mGMPApiVersion = kGMPVersion33;
-
- codec.mCodecType = kGMPVideoCodecH264;
- codec.mWidth = mConfig.display_width;
- codec.mHeight = mConfig.display_height;
-
- nsTArray<uint8_t> codecSpecific;
- codecSpecific.AppendElement(0); // mPacketizationMode.
- codecSpecific.AppendElements(mConfig.extra_data->Elements(),
- mConfig.extra_data->Length());
-
- rv = mGMP->InitDecode(codec,
- codecSpecific,
- this,
- PR_GetNumberOfProcessors());
- NS_ENSURE_SUCCESS(rv, rv);
-
- mVideoInfo.mDisplay = nsIntSize(mConfig.display_width, mConfig.display_height);
- mVideoInfo.mHasVideo = true;
-
- return NS_OK;
+ GMPVideoDecoder::InitTags(aTags);
+ aTags.AppendElement(NS_ConvertUTF16toUTF8(mProxy->KeySystem()));
}
-nsresult
-EMEH264Decoder::GmpInput(MP4Sample* aSample)
+nsCString
+EMEVideoDecoder::GetNodeId()
{
- MOZ_ASSERT(IsOnGMPThread());
-
- nsAutoPtr<MP4Sample> sample(aSample);
- if (!mGMP) {
- mCallback->Error();
- return NS_ERROR_FAILURE;
- }
-
- mLastStreamOffset = sample->byte_offset;
-
- GMPVideoFrame* ftmp = nullptr;
- GMPErr err = mHost->CreateFrame(kGMPEncodedVideoFrame, &ftmp);
- if (GMP_FAILED(err)) {
- mCallback->Error();
- return NS_ERROR_FAILURE;
- }
-
- GMPUniquePtr<gmp::GMPVideoEncodedFrameImpl> frame(static_cast<gmp::GMPVideoEncodedFrameImpl*>(ftmp));
- err = frame->CreateEmptyFrame(sample->size);
- if (GMP_FAILED(err)) {
- mCallback->Error();
- return NS_ERROR_FAILURE;
- }
-
- memcpy(frame->Buffer(), sample->data, frame->Size());
-
- frame->SetEncodedWidth(mConfig.display_width);
- frame->SetEncodedHeight(mConfig.display_height);
- frame->SetTimeStamp(sample->composition_timestamp);
- frame->SetCompleteFrame(true);
- frame->SetDuration(sample->duration);
- if (sample->crypto.valid) {
- frame->InitCrypto(sample->crypto);
- }
- frame->SetFrameType(sample->is_sync_point ? kGMPKeyFrame : kGMPDeltaFrame);
- frame->SetBufferType(GMP_BufferLength32);
-
- nsTArray<uint8_t> info; // No codec specific per-frame info to pass.
- nsresult rv = mGMP->Decode(GMPUniquePtr<GMPVideoEncodedFrame>(frame.release()), false, info, 0);
- if (NS_FAILED(rv)) {
- mCallback->Error();
- return rv;
- }
-
- return NS_OK;
+ return mProxy->GetNodeId();
}
-void
-EMEH264Decoder::GmpFlush()
-{
- MOZ_ASSERT(IsOnGMPThread());
- if (!mGMP || NS_FAILED(mGMP->Reset())) {
- // Abort the flush...
- MonitorAutoLock mon(mMonitor);
- mFlushComplete = true;
- mon.NotifyAll();
- }
-}
-
-void
-EMEH264Decoder::GmpDrain()
+GMPUniquePtr<GMPVideoEncodedFrame>
+EMEVideoDecoder::CreateFrame(mp4_demuxer::MP4Sample* aSample)
{
- MOZ_ASSERT(IsOnGMPThread());
- if (!mGMP || NS_FAILED(mGMP->Drain())) {
- mCallback->DrainComplete();
+ GMPUniquePtr<GMPVideoEncodedFrame> frame = GMPVideoDecoder::CreateFrame(aSample);
+ if (frame && aSample->crypto.valid) {
+ static_cast<gmp::GMPVideoEncodedFrameImpl*>(frame.get())->InitCrypto(aSample->crypto);
}
-}
-
-void
-EMEH264Decoder::GmpShutdown()
-{
- MOZ_ASSERT(IsOnGMPThread());
- if (!mGMP) {
- return;
- }
- mGMP->Close();
- mGMP = nullptr;
+ return frame;
}
} // namespace mozilla
rename from dom/media/fmp4/eme/EMEH264Decoder.h
rename to dom/media/fmp4/eme/EMEVideoDecoder.h
--- a/dom/media/fmp4/eme/EMEH264Decoder.h
+++ b/dom/media/fmp4/eme/EMEVideoDecoder.h
@@ -1,121 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-#ifndef EMEH264Decoder_h_
-#define EMEH264Decoder_h_
+#ifndef EMEVideoDecoder_h_
+#define EMEVideoDecoder_h_
+#include "GMPVideoDecoder.h"
#include "PlatformDecoderModule.h"
-#include "mp4_demuxer/DecoderData.h"
-#include "ImageContainer.h"
-#include "GMPVideoDecoderProxy.h"
-#include "mozIGeckoMediaPluginService.h"
-#include "SamplesWaitingForKey.h"
namespace mozilla {
class CDMProxy;
class MediaTaskQueue;
-class EMEH264Decoder : public MediaDataDecoder
- , public GMPVideoDecoderCallbackProxy
-{
- typedef mp4_demuxer::MP4Sample MP4Sample;
+class EMEVideoCallbackAdapter : public VideoCallbackAdapter {
public:
- EMEH264Decoder(CDMProxy* aProxy,
- const mp4_demuxer::VideoDecoderConfig& aConfig,
- layers::LayersBackend aLayersBackend,
- layers::ImageContainer* aImageContainer,
- MediaTaskQueue* aTaskQueue,
- MediaDataDecoderCallback* aCallback);
- ~EMEH264Decoder();
+ EMEVideoCallbackAdapter(MediaDataDecoderCallbackProxy* aCallback,
+ VideoInfo aVideoInfo,
+ layers::ImageContainer* aImageContainer)
+ : VideoCallbackAdapter(aCallback, aVideoInfo, aImageContainer)
+ {}
+
+ virtual void Error(GMPErr aErr) MOZ_OVERRIDE;
+};
- // MediaDataDecoder
- virtual nsresult Init() MOZ_OVERRIDE;
- virtual nsresult Input(MP4Sample* aSample) MOZ_OVERRIDE;
- virtual nsresult Flush() MOZ_OVERRIDE;
- virtual nsresult Drain() MOZ_OVERRIDE;
- virtual nsresult Shutdown() MOZ_OVERRIDE;
-
- // GMPVideoDecoderProxyCallback
- virtual void Decoded(GMPVideoi420Frame* aDecodedFrame) MOZ_OVERRIDE;
- virtual void ReceivedDecodedReferenceFrame(const uint64_t aPictureId) MOZ_OVERRIDE;
- virtual void ReceivedDecodedFrame(const uint64_t aPictureId) MOZ_OVERRIDE;
- virtual void InputDataExhausted() MOZ_OVERRIDE;
- virtual void DrainComplete() MOZ_OVERRIDE;
- virtual void ResetComplete() MOZ_OVERRIDE;
- virtual void Error(GMPErr aErr) MOZ_OVERRIDE;
- virtual void Terminated() MOZ_OVERRIDE;
+class EMEVideoDecoder : public GMPVideoDecoder {
+public:
+ EMEVideoDecoder(CDMProxy* aProxy,
+ const mp4_demuxer::VideoDecoderConfig& aConfig,
+ layers::LayersBackend aLayersBackend,
+ layers::ImageContainer* aImageContainer,
+ MediaTaskQueue* aTaskQueue,
+ MediaDataDecoderCallbackProxy* aCallback)
+ : GMPVideoDecoder(aConfig, aLayersBackend, aImageContainer, aTaskQueue, aCallback,
+ new EMEVideoCallbackAdapter(aCallback, VideoInfo(aConfig.display_width,
+ aConfig.display_height), aImageContainer))
+ , mProxy(aProxy)
+ {
+ }
private:
-
- nsresult GmpInit();
- nsresult GmpInput(MP4Sample* aSample);
- void GmpFlush();
- void GmpDrain();
- void GmpShutdown();
-
-#ifdef DEBUG
- bool IsOnGMPThread() {
- return NS_GetCurrentThread() == mGMPThread;
- }
-#endif
-
- class DeliverSample : public nsRunnable {
- public:
- DeliverSample(EMEH264Decoder* aDecoder,
- mp4_demuxer::MP4Sample* aSample)
- : mDecoder(aDecoder)
- , mSample(aSample)
- {}
-
- NS_IMETHOD Run() {
- mDecoder->GmpInput(mSample.forget());
- return NS_OK;
- }
- private:
- nsRefPtr<EMEH264Decoder> mDecoder;
- nsAutoPtr<mp4_demuxer::MP4Sample> mSample;
- };
+ virtual void InitTags(nsTArray<nsCString>& aTags) MOZ_OVERRIDE;
+ virtual nsCString GetNodeId() MOZ_OVERRIDE;
+ virtual GMPUniquePtr<GMPVideoEncodedFrame> CreateFrame(mp4_demuxer::MP4Sample* aSample) MOZ_OVERRIDE;
- class InitTask : public nsRunnable {
- public:
- explicit InitTask(EMEH264Decoder* aDecoder)
- : mDecoder(aDecoder)
- {}
- NS_IMETHOD Run() {
- mResult = mDecoder->GmpInit();
- return NS_OK;
- }
- nsresult mResult;
- EMEH264Decoder* mDecoder;
- };
-
- nsCOMPtr<mozIGeckoMediaPluginService> mMPS;
- nsCOMPtr<nsIThread> mGMPThread;
nsRefPtr<CDMProxy> mProxy;
- GMPVideoDecoderProxy* mGMP;
- GMPVideoHost* mHost;
-
- VideoInfo mVideoInfo;
- const mp4_demuxer::VideoDecoderConfig& mConfig;
- nsRefPtr<layers::ImageContainer> mImageContainer;
- nsRefPtr<MediaTaskQueue> mTaskQueue;
- MediaDataDecoderCallback* mCallback;
- int64_t mLastStreamOffset;
-
- nsRefPtr<SamplesWaitingForKey> mSamplesWaitingForKey;
-
- Monitor mMonitor;
- bool mFlushComplete;
-
-#ifdef DEBUG
- bool mIsShutdown;
-#endif
};
}
-#endif // EMEH264Decoder_h_
+#endif // EMEVideoDecoder_h_
--- a/dom/media/fmp4/eme/moz.build
+++ b/dom/media/fmp4/eme/moz.build
@@ -2,24 +2,24 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
EXPORTS += [
'EMEAudioDecoder.h',
'EMEDecoderModule.h',
- 'EMEH264Decoder.h',
+ 'EMEVideoDecoder.h',
'SamplesWaitingForKey.h',
]
UNIFIED_SOURCES += [
'EMEAudioDecoder.cpp',
'EMEDecoderModule.cpp',
- 'EMEH264Decoder.cpp',
+ 'EMEVideoDecoder.cpp',
'SamplesWaitingForKey.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'
FAIL_ON_WARNINGS = True