Bug 1319987: P7. Re-implement handling for WaitingForKey in MFR. r=cpearce,gerald

MozReview-Commit-ID: FCiAO54oiH3

--HG--
extra : rebase_source : 898e175742ae4db13c48cf75463a9775968b0030
This commit is contained in:
Jean-Yves Avenard 2017-01-27 11:48:00 +01:00
Родитель 5e2e07649c
Коммит e2abc1a523
9 изменённых файлов: 116 добавлений и 24 удалений

Просмотреть файл

@ -243,6 +243,18 @@ public:
return mOnMediaNotSeekable;
}
// Notified if the reader can't decode a sample due to a missing decryption
// key.
MediaEventSource<TrackInfo::TrackType>& OnTrackWaitingForKey()
{
return mOnTrackWaitingForKey;
}
MediaEventProducer<TrackInfo::TrackType>& OnTrackWaitingForKeyProducer()
{
return mOnTrackWaitingForKey;
}
// Switch the video decoder to BlankDecoderModule. It might takes effective
// since a few samples later depends on how much demuxed samples are already
// queued in the original video decoder.
@ -306,6 +318,9 @@ protected:
// Notify if this media is not seekable.
MediaEventProducer<void> mOnMediaNotSeekable;
// Notify if we are waiting for a decryption key.
MediaEventProducer<TrackInfo::TrackType> mOnTrackWaitingForKey;
private:
virtual nsresult InitInternal() { return NS_OK; }

Просмотреть файл

@ -389,7 +389,9 @@ MediaFormatReader::DecoderFactory::DoCreateDecoder(TrackType aTrack)
ownerData.mTaskQueue,
mOwner->mCrashHelper,
ownerData.mIsBlankDecode,
&result
&result,
aTrack,
&mOwner->OnTrackWaitingForKeyProducer()
});
break;
}
@ -406,7 +408,9 @@ MediaFormatReader::DecoderFactory::DoCreateDecoder(TrackType aTrack)
mOwner->GetImageContainer(),
mOwner->mCrashHelper,
ownerData.mIsBlankDecode,
&result
&result,
aTrack,
&mOwner->OnTrackWaitingForKeyProducer()
});
break;
}
@ -847,6 +851,8 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder,
aDecoder->CompositorUpdatedEvent()->Connect(
mTaskQueue, this, &MediaFormatReader::NotifyCompositorUpdated);
}
mOnTrackWaitingForKeyListener = OnTrackWaitingForKey().Connect(
mTaskQueue, this, &MediaFormatReader::NotifyWaitingForKey);
}
MediaFormatReader::~MediaFormatReader()
@ -895,6 +901,7 @@ MediaFormatReader::Shutdown()
mDemuxer = nullptr;
mCompositorUpdatedListener.DisconnectIfExists();
mOnTrackWaitingForKeyListener.Disconnect();
RefPtr<ShutdownPromise> p = mShutdownPromise.Ensure(__func__);
ShutdownPromise::All(OwnerThread(), promises)
@ -1523,6 +1530,21 @@ MediaFormatReader::NotifyWaitingForData(TrackType aTrack)
ScheduleUpdate(aTrack);
}
void
MediaFormatReader::NotifyWaitingForKey(TrackType aTrack)
{
MOZ_ASSERT(OnTaskQueue());
auto& decoder = GetDecoderData(aTrack);
if (mDecoder) {
mDecoder->NotifyWaitingForKey();
}
if (!decoder.mDecodeRequest.Exists()) {
LOGV("WaitingForKey received while no pending decode. Ignoring");
}
decoder.mWaitingForKey = true;
ScheduleUpdate(aTrack);
}
void
MediaFormatReader::NotifyEndOfStream(TrackType aTrack)
{
@ -2013,6 +2035,10 @@ MediaFormatReader::Update(TrackType aTrack)
// EOS state. We can immediately reject the data promise.
LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
} else if (decoder.mWaitingForKey) {
LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for key",
TrackTypeToStr(aTrack));
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
}
}
@ -2054,13 +2080,23 @@ MediaFormatReader::Update(TrackType aTrack)
decoder.mWaitingForData, decoder.HasPromise(),
decoder.mLastStreamSourceID);
if ((decoder.mWaitingForData &&
(!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting))) {
if ((decoder.mWaitingForData
&& (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting))
|| (decoder.mWaitingForKey && decoder.mDecodeRequest.Exists())) {
// Nothing more we can do at present.
LOGV("Still waiting for data or key.");
return;
}
if (decoder.mWaitingForKey) {
decoder.mWaitingForKey = false;
if (decoder.HasWaitingPromise() && !decoder.IsWaiting()) {
LOGV("No longer waiting for key. Resolving waiting promise");
decoder.mWaitingPromise.Resolve(decoder.mType, __func__);
return;
}
}
if (!needInput) {
LOGV("No need for additional input (pending:%u)",
uint32_t(decoder.mOutput.Length()));

Просмотреть файл

@ -141,6 +141,7 @@ private:
void NotifyDrainComplete(TrackType aTrack);
void NotifyError(TrackType aTrack, const MediaResult& aError);
void NotifyWaitingForData(TrackType aTrack);
void NotifyWaitingForKey(TrackType aTrack);
void NotifyEndOfStream(TrackType aTrack);
void ExtractCryptoInitData(nsTArray<uint8_t>& aInitData);
@ -170,6 +171,7 @@ private:
, mUpdateScheduled(false)
, mDemuxEOS(false)
, mWaitingForData(false)
, mWaitingForKey(false)
, mReceivedNewData(false)
, mNeedDraining(false)
, mDraining(false)
@ -226,6 +228,7 @@ private:
bool mUpdateScheduled;
bool mDemuxEOS;
bool mWaitingForData;
bool mWaitingForKey;
bool mReceivedNewData;
// Pending seek.
@ -245,7 +248,7 @@ private:
bool IsWaiting() const
{
MOZ_ASSERT(mOwner->OnTaskQueue());
return mWaitingForData;
return mWaitingForData || mWaitingForKey;
}
// MediaDataDecoder handler's variables.
@ -373,6 +376,7 @@ private:
MOZ_ASSERT(mOwner->OnTaskQueue());
mDemuxEOS = false;
mWaitingForData = false;
mWaitingForKey = false;
mQueuedSamples.Clear();
mNeedDraining = false;
mDecodeRequest.DisconnectIfExists();
@ -560,6 +564,7 @@ private:
UniquePtr<DecoderFactory> mDecoderFactory;
MediaEventListener mCompositorUpdatedListener;
MediaEventListener mOnTrackWaitingForKeyListener;
void OnFirstDemuxCompleted(TrackInfo::TrackType aType,
RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples);

Просмотреть файл

@ -81,6 +81,8 @@ struct MOZ_STACK_CLASS CreateDecoderParams final
RefPtr<layers::KnowsCompositor> mKnowsCompositor;
RefPtr<GMPCrashHelper> mCrashHelper;
bool mUseBlankDecoder = false;
TrackInfo::TrackType mType = TrackInfo::kUndefinedTrack;
MediaEventProducer<TrackInfo::TrackType>* mOnWaitingForKeyEvent = nullptr;
private:
void Set(TaskQueue* aTaskQueue) { mTaskQueue = aTaskQueue; }
@ -99,6 +101,14 @@ private:
{
mKnowsCompositor = aKnowsCompositor;
}
void Set(TrackInfo::TrackType aType)
{
mType = aType;
}
void Set(MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey)
{
mOnWaitingForKeyEvent = aOnWaitingForKey;
}
template <typename T1, typename T2, typename... Ts>
void Set(T1&& a1, T2&& a2, Ts&&... args)
{

Просмотреть файл

@ -27,13 +27,14 @@ extern already_AddRefed<PlatformDecoderModule> CreateBlankDecoderModule();
class EMEDecryptor : public MediaDataDecoder
{
public:
EMEDecryptor(MediaDataDecoder* aDecoder,
CDMProxy* aProxy,
TaskQueue* aDecodeTaskQueue)
EMEDecryptor(MediaDataDecoder* aDecoder, CDMProxy* aProxy,
TaskQueue* aDecodeTaskQueue, TrackInfo::TrackType aType,
MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey)
: mDecoder(aDecoder)
, mTaskQueue(aDecodeTaskQueue)
, mProxy(aProxy)
, mSamplesWaitingForKey(new SamplesWaitingForKey(mProxy))
, mSamplesWaitingForKey(
new SamplesWaitingForKey(mProxy, aType, aOnWaitingForKey))
, mIsShutdown(false)
{
}
@ -204,12 +205,15 @@ private:
class EMEMediaDataDecoderProxy : public MediaDataDecoderProxy
{
public:
EMEMediaDataDecoderProxy(already_AddRefed<AbstractThread> aProxyThread,
CDMProxy* aProxy)
: MediaDataDecoderProxy(Move(aProxyThread))
, mTaskQueue(AbstractThread::GetCurrent()->AsTaskQueue())
, mSamplesWaitingForKey(new SamplesWaitingForKey(aProxy))
, mProxy(aProxy)
EMEMediaDataDecoderProxy(
already_AddRefed<AbstractThread> aProxyThread, CDMProxy* aProxy,
TrackInfo::TrackType aType,
MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey)
: MediaDataDecoderProxy(Move(aProxyThread))
, mTaskQueue(AbstractThread::GetCurrent()->AsTaskQueue())
, mSamplesWaitingForKey(
new SamplesWaitingForKey(aProxy, aType, aOnWaitingForKey))
, mProxy(aProxy)
{
}
@ -289,7 +293,7 @@ EMEDecoderModule::~EMEDecoderModule()
}
static already_AddRefed<MediaDataDecoderProxy>
CreateDecoderWrapper(CDMProxy* aProxy)
CreateDecoderWrapper(CDMProxy* aProxy, const CreateDecoderParams& aParams)
{
RefPtr<gmp::GeckoMediaPluginService> s(gmp::GeckoMediaPluginService::GetGeckoMediaPluginService());
if (!s) {
@ -299,8 +303,8 @@ CreateDecoderWrapper(CDMProxy* aProxy)
if (!thread) {
return nullptr;
}
RefPtr<MediaDataDecoderProxy> decoder(
new EMEMediaDataDecoderProxy(thread.forget(), aProxy));
RefPtr<MediaDataDecoderProxy> decoder(new EMEMediaDataDecoderProxy(
thread.forget(), aProxy, aParams.mType, aParams.mOnWaitingForKeyEvent));
return decoder.forget();
}
@ -317,7 +321,8 @@ EMEDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
if (SupportsMimeType(aParams.mConfig.mMimeType, nullptr)) {
// GMP decodes. Assume that means it can decrypt too.
RefPtr<MediaDataDecoderProxy> wrapper = CreateDecoderWrapper(mProxy);
RefPtr<MediaDataDecoderProxy> wrapper =
CreateDecoderWrapper(mProxy, aParams);
auto params = GMPVideoDecoderParams(aParams);
wrapper->SetProxyTarget(new EMEVideoDecoder(mProxy, params));
return wrapper.forget();
@ -330,7 +335,8 @@ EMEDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams)
}
RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(
decoder, mProxy, AbstractThread::GetCurrent()->AsTaskQueue()));
decoder, mProxy, AbstractThread::GetCurrent()->AsTaskQueue(),
aParams.mType, aParams.mOnWaitingForKeyEvent));
return emeDecoder.forget();
}
@ -355,7 +361,8 @@ EMEDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams)
}
RefPtr<MediaDataDecoder> emeDecoder(new EMEDecryptor(
decoder, mProxy, AbstractThread::GetCurrent()->AsTaskQueue()));
decoder, mProxy, AbstractThread::GetCurrent()->AsTaskQueue(),
aParams.mType, aParams.mOnWaitingForKeyEvent));
return emeDecoder.forget();
}

Просмотреть файл

@ -8,13 +8,18 @@
#include "mozilla/CDMCaps.h"
#include "mozilla/TaskQueue.h"
#include "MediaData.h"
#include "MediaEventSource.h"
#include "SamplesWaitingForKey.h"
namespace mozilla {
SamplesWaitingForKey::SamplesWaitingForKey(CDMProxy* aProxy)
SamplesWaitingForKey::SamplesWaitingForKey(
CDMProxy* aProxy, TrackInfo::TrackType aType,
MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey)
: mMutex("SamplesWaitingForKey")
, mProxy(aProxy)
, mType(aType)
, mOnWaitingForKeyEvent(aOnWaitingForKey)
{
}
@ -41,6 +46,9 @@ SamplesWaitingForKey::WaitIfKeyNotUsable(MediaRawData* aSample)
MutexAutoLock lock(mMutex);
mSamples.AppendElement(Move(entry));
}
if (mOnWaitingForKeyEvent) {
mOnWaitingForKeyEvent->Notify(mType);
}
caps.NotifyWhenKeyIdUsable(aSample->mCrypto.mKeyId, this);
return p;
}

Просмотреть файл

@ -10,12 +10,14 @@
#include "mozilla/MozPromise.h"
#include "mozilla/Mutex.h"
#include "mozilla/RefPtr.h"
#include "MediaInfo.h"
namespace mozilla {
typedef nsTArray<uint8_t> CencKeyId;
class CDMProxy;
template <typename... Es> class MediaEventProducer;
class MediaRawData;
// Encapsulates the task of waiting for the CDMProxy to have the necessary
@ -28,7 +30,8 @@ public:
typedef MozPromise<RefPtr<MediaRawData>, bool, /* IsExclusive = */ true>
WaitForKeyPromise;
explicit SamplesWaitingForKey(CDMProxy* aProxy);
SamplesWaitingForKey(CDMProxy* aProxy, TrackInfo::TrackType aType,
MediaEventProducer<TrackInfo::TrackType>* aOnWaitingForKey);
// Returns a promise that will be resolved if or when a key for decoding the
// sample becomes usable.
@ -50,6 +53,8 @@ private:
MozPromiseHolder<WaitForKeyPromise> mPromise;
};
nsTArray<SampleEntry> mSamples;
const TrackInfo::TrackType mType;
MediaEventProducer<TrackInfo::TrackType>* const mOnWaitingForKeyEvent;
};
} // namespace mozilla

Просмотреть файл

@ -28,6 +28,8 @@ H264Converter::H264Converter(PlatformDecoderModule* aPDM,
, mNeedAVCC(aPDM->DecoderNeedsConversion(aParams.mConfig)
== PlatformDecoderModule::ConversionRequired::kNeedAVCC)
, mLastError(NS_OK)
, mType(aParams.mType)
, mOnWaitingForKeyEvent(aParams.mOnWaitingForKeyEvent)
{
CreateDecoder(aParams.mDiagnostics);
}
@ -194,7 +196,9 @@ H264Converter::CreateDecoder(DecoderDoctorDiagnostics* aDiagnostics)
aDiagnostics,
mImageContainer,
mKnowsCompositor,
mGMPCrashHelper
mGMPCrashHelper,
mType,
mOnWaitingForKeyEvent
});
if (!mDecoder) {

Просмотреть файл

@ -76,6 +76,8 @@ private:
bool mNeedAVCC;
nsresult mLastError;
bool mNeedKeyframe = true;
const TrackInfo::TrackType mType;
MediaEventProducer<TrackInfo::TrackType>* const mOnWaitingForKeyEvent;
};
} // namespace mozilla