--- a/dom/media/MediaDecoderReader.cpp
+++ b/dom/media/MediaDecoderReader.cpp
@@ -33,54 +33,19 @@ extern LazyLogModule gMediaDecoderLog;
#undef DECODER_LOG
#undef DECODER_WARN
#define FMT(x, ...) "Decoder=%p " x, mDecoder, ##__VA_ARGS__
#define DECODER_LOG(...) MOZ_LOG(gMediaDecoderLog, LogLevel::Debug, (FMT(__VA_ARGS__)))
#define DECODER_WARN(...) NS_WARNING(nsPrintfCString(FMT(__VA_ARGS__)).get())
MediaDecoderReader::MediaDecoderReader(MediaDecoderReaderInit& aInit)
- : mDecoder(aInit.mDecoder)
- , mTaskQueue(new TaskQueue(
- GetMediaThreadPool(MediaThreadType::PLAYBACK),
- "MediaDecoderReader::mTaskQueue",
- /* aSupportsTailDispatch = */ true))
- , mBuffered(mTaskQueue, TimeIntervals(), "MediaDecoderReader::mBuffered (Canonical)")
- , mShutdown(false)
{
MOZ_COUNT_CTOR(MediaDecoderReader);
MOZ_ASSERT(NS_IsMainThread());
}
-nsresult
-MediaDecoderReader::Init()
-{
- return InitInternal();
-}
-
MediaDecoderReader::~MediaDecoderReader()
{
- MOZ_ASSERT(mShutdown);
MOZ_COUNT_DTOR(MediaDecoderReader);
}
-void
-MediaDecoderReader::UpdateDuration(const media::TimeUnit& aDuration)
-{
- MOZ_ASSERT(OnTaskQueue());
- UpdateBuffered();
-}
-
-RefPtr<ShutdownPromise>
-MediaDecoderReader::Shutdown()
-{
- MOZ_ASSERT(OnTaskQueue());
- mShutdown = true;
-
- ReleaseResources();
- mBuffered.DisconnectAll();
-
- mDecoder = nullptr;
-
- return mTaskQueue->BeginShutdown();
-}
-
} // namespace mozilla
--- a/dom/media/MediaDecoderReader.h
+++ b/dom/media/MediaDecoderReader.h
@@ -24,50 +24,16 @@
namespace mozilla {
class CDMProxy;
class GMPCrashHelper;
class MediaDecoderReader;
class TaskQueue;
class VideoFrameContainer;
-struct WaitForDataRejectValue
-{
- enum Reason
- {
- SHUTDOWN,
- CANCELED
- };
-
- WaitForDataRejectValue(MediaData::Type aType, Reason aReason)
- :mType(aType), mReason(aReason)
- {
- }
- MediaData::Type mType;
- Reason mReason;
-};
-
-struct SeekRejectValue
-{
- MOZ_IMPLICIT SeekRejectValue(const MediaResult& aError)
- : mType(MediaData::NULL_DATA), mError(aError) { }
- MOZ_IMPLICIT SeekRejectValue(nsresult aResult)
- : mType(MediaData::NULL_DATA), mError(aResult) { }
- SeekRejectValue(MediaData::Type aType, const MediaResult& aError)
- : mType(aType), mError(aError) { }
- MediaData::Type mType;
- MediaResult mError;
-};
-
-struct MetadataHolder
-{
- UniquePtr<MediaInfo> mInfo;
- UniquePtr<MetadataTags> mTags;
-};
-
struct MOZ_STACK_CLASS MediaDecoderReaderInit
{
AbstractMediaDecoder* const mDecoder;
MediaResource* mResource = nullptr;
VideoFrameContainer* mVideoFrameContainer = nullptr;
already_AddRefed<layers::KnowsCompositor> mKnowsCompositor;
already_AddRefed<GMPCrashHelper> mCrashHelper;
@@ -80,221 +46,22 @@ struct MOZ_STACK_CLASS MediaDecoderReade
// Encapsulates the decoding and reading of media data. Reading can either
// synchronous and done on the calling "decode" thread, or asynchronous and
// performed on a background thread, with the result being returned by
// callback.
// Unless otherwise specified, methods and fields of this class can only
// be accessed on the decode task queue.
class MediaDecoderReader
{
- static const bool IsExclusive = true;
-
public:
- using TrackSet = EnumSet<TrackInfo::TrackType>;
-
- using MetadataPromise = MozPromise<MetadataHolder, MediaResult, IsExclusive>;
-
- template <typename Type>
- using DataPromise = MozPromise<RefPtr<Type>, MediaResult, IsExclusive>;
- using AudioDataPromise = DataPromise<AudioData>;
- using VideoDataPromise = DataPromise<VideoData>;
-
- using SeekPromise = MozPromise<media::TimeUnit, SeekRejectValue, IsExclusive>;
-
- // Note that, conceptually, WaitForData makes sense in a non-exclusive sense.
- // But in the current architecture it's only ever used exclusively (by MDSM),
- // so we mark it that way to verify our assumptions. If you have a use-case
- // for multiple WaitForData consumers, feel free to flip the exclusivity here.
- using WaitForDataPromise =
- MozPromise<MediaData::Type, WaitForDataRejectValue, IsExclusive>;
-
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReader)
// The caller must ensure that Shutdown() is called before aDecoder is
// destroyed.
explicit MediaDecoderReader(MediaDecoderReaderInit& aInit);
- // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
- // on failure.
- nsresult Init();
-
- // Called by MDSM in dormant state to release resources allocated by this
- // reader. The reader can resume decoding by calling Seek() to a specific
- // position.
- virtual void ReleaseResources() = 0;
-
- // Destroys the decoding state. The reader cannot be made usable again.
- // This is different from ReleaseMediaResources() as it is irreversable,
- // whereas ReleaseMediaResources() is. Must be called on the decode
- // thread.
- virtual RefPtr<ShutdownPromise> Shutdown();
-
- virtual bool OnTaskQueue() const
- {
- return OwnerThread()->IsCurrentThreadIn();
- }
-
- void UpdateDuration(const media::TimeUnit& aDuration);
-
- virtual void UpdateCompositor(already_AddRefed<layers::KnowsCompositor>) = 0;
-
- // Resets all state related to decoding, emptying all buffers etc.
- // Cancels all pending Request*Data() request callbacks, rejects any
- // outstanding seek promises, and flushes the decode pipeline. The
- // decoder must not call any of the callbacks for outstanding
- // Request*Data() calls after this is called. Calls to Request*Data()
- // made after this should be processed as usual.
- //
- // Normally this call preceedes a Seek() call, or shutdown.
- //
- // aParam is a set of TrackInfo::TrackType enums specifying which
- // queues need to be reset, defaulting to both audio and video tracks.
- virtual nsresult ResetDecode(
- TrackSet aTracks = TrackSet(TrackInfo::kAudioTrack,
- TrackInfo::kVideoTrack)) = 0;
-
- // Requests one audio sample from the reader.
- //
- // The decode should be performed asynchronously, and the promise should
- // be resolved when it is complete.
- virtual RefPtr<AudioDataPromise> RequestAudioData() = 0;
-
- // Requests one video sample from the reader.
- virtual RefPtr<VideoDataPromise>
- RequestVideoData(const media::TimeUnit& aTimeThreshold) = 0;
-
- // By default, the state machine polls the reader once per second when it's
- // in buffering mode. Some readers support a promise-based mechanism by which
- // they notify the state machine when the data arrives.
- virtual bool IsWaitForDataSupported() const = 0;
-
- virtual RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) = 0;
-
- // The default implementation of AsyncReadMetadata is implemented in terms of
- // synchronous ReadMetadata() calls. Implementations may also
- // override AsyncReadMetadata to create a more proper async implementation.
- virtual RefPtr<MetadataPromise> AsyncReadMetadata() = 0;
-
- // Fills aInfo with the latest cached data required to present the media,
- // ReadUpdatedMetadata will always be called once ReadMetadata has succeeded.
- virtual void ReadUpdatedMetadata(MediaInfo* aInfo) = 0;
-
- // Moves the decode head to aTime microseconds.
- virtual RefPtr<SeekPromise> Seek(const SeekTarget& aTarget) = 0;
-
- virtual void SetCDMProxy(CDMProxy* aProxy) = 0;
-
- // The MediaDecoderStateMachine uses various heuristics that assume that
- // raw media data is arriving sequentially from a network channel. This
- // makes sense in the <video src="foo"> case, but not for more advanced use
- // cases like MSE.
- virtual bool UseBufferingHeuristics() const = 0;
-
- virtual size_t SizeOfVideoQueueInFrames() = 0;
- virtual size_t SizeOfAudioQueueInFrames() = 0;
-
- // Called once new data has been cached by the MediaResource.
- // mBuffered should be recalculated and updated accordingly.
- virtual void NotifyDataArrived() = 0;
-
- AbstractCanonical<media::TimeIntervals>* CanonicalBuffered()
- {
- return &mBuffered;
- }
-
- TaskQueue* OwnerThread() const
- {
- return mTaskQueue;
- }
-
- // Returns true if this decoder reader uses hardware accelerated video
- // decoding.
- virtual bool VideoIsHardwareAccelerated() const = 0;
-
- TimedMetadataEventSource& TimedMetadataEvent()
- {
- return mTimedMetadataEvent;
- }
-
- // Notified by the OggDemuxer during playback when chained ogg is detected.
- MediaEventSource<void>& OnMediaNotSeekable() { return mOnMediaNotSeekable; }
-
- TimedMetadataEventProducer& TimedMetadataProducer()
- {
- return mTimedMetadataEvent;
- }
-
- MediaEventProducer<void>& MediaNotSeekableProducer()
- {
- 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;
- }
-
- MediaEventSource<nsTArray<uint8_t>, nsString>& OnEncrypted()
- {
- return mOnEncrypted;
- }
-
- MediaEventSource<void>& OnWaitingForKey()
- {
- return mOnWaitingForKey;
- }
-
- MediaEventSource<MediaResult>& OnDecodeWarning()
- {
- return mOnDecodeWarning;
- }
-
- // Switch the video decoder to NullDecoderModule. It might takes effective
- // since a few samples later depends on how much demuxed samples are already
- // queued in the original video decoder.
- virtual void SetVideoNullDecode(bool aIsNullDecode) = 0;
-
protected:
virtual ~MediaDecoderReader();
-
- // Recomputes mBuffered.
- virtual void UpdateBuffered() = 0;
-
- // Reference to the owning decoder object.
- AbstractMediaDecoder* mDecoder;
-
- // Decode task queue.
- RefPtr<TaskQueue> mTaskQueue;
-
- // Buffered range.
- Canonical<media::TimeIntervals> mBuffered;
-
- bool mShutdown;
-
- // Used to send TimedMetadata to the listener.
- TimedMetadataEventProducer mTimedMetadataEvent;
-
- // Notify if this media is not seekable.
- MediaEventProducer<void> mOnMediaNotSeekable;
-
- // Notify if we are waiting for a decryption key.
- MediaEventProducer<TrackInfo::TrackType> mOnTrackWaitingForKey;
-
- MediaEventProducer<nsTArray<uint8_t>, nsString> mOnEncrypted;
-
- MediaEventProducer<void> mOnWaitingForKey;
-
- MediaEventProducer<MediaResult> mOnDecodeWarning;
-
-private:
- virtual nsresult InitInternal() = 0;
};
} // namespace mozilla
#endif
--- a/dom/media/MediaDecoderReaderWrapper.cpp
+++ b/dom/media/MediaDecoderReaderWrapper.cpp
@@ -97,17 +97,17 @@ MediaDecoderReaderWrapper::RequestVideoD
return VideoDataPromise::CreateAndResolve(aVideo.forget(),
__func__);
},
[](const MediaResult& aError) {
return VideoDataPromise::CreateAndReject(aError, __func__);
});
}
-RefPtr<MediaDecoderReader::SeekPromise>
+RefPtr<MediaDecoderReaderWrapper::SeekPromise>
MediaDecoderReaderWrapper::Seek(const SeekTarget& aTarget)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
SeekTarget adjustedTarget = aTarget;
adjustedTarget.SetTime(adjustedTarget.GetTime() + StartTime());
return InvokeAsync(mReader->OwnerThread(),
mReader.get(),
__func__,
--- a/dom/media/MediaDecoderReaderWrapper.h
+++ b/dom/media/MediaDecoderReaderWrapper.h
@@ -7,34 +7,34 @@
#ifndef MediaDecoderReaderWrapper_h_
#define MediaDecoderReaderWrapper_h_
#include "mozilla/AbstractThread.h"
#include "mozilla/RefPtr.h"
#include "mozilla/Variant.h"
#include "nsISupportsImpl.h"
-#include "MediaDecoderReader.h"
#include "MediaEventSource.h"
+#include "MediaFormatReader.h"
namespace mozilla {
/**
* A wrapper around MediaFormatReader to offset the timestamps of Audio/Video
* samples by the start time to ensure MDSM can always assume zero start time.
* It also adjusts the seek target passed to Seek() to ensure correct seek time
* is passed to the underlying reader.
*/
class MediaDecoderReaderWrapper {
- typedef MediaDecoderReader::MetadataPromise MetadataPromise;
- typedef MediaDecoderReader::AudioDataPromise AudioDataPromise;
- typedef MediaDecoderReader::VideoDataPromise VideoDataPromise;
- typedef MediaDecoderReader::SeekPromise SeekPromise;
- typedef MediaDecoderReader::WaitForDataPromise WaitForDataPromise;
- typedef MediaDecoderReader::TrackSet TrackSet;
+ using MetadataPromise = MediaFormatReader::MetadataPromise;
+ using AudioDataPromise = MediaFormatReader::AudioDataPromise;
+ using VideoDataPromise = MediaFormatReader::VideoDataPromise;
+ using SeekPromise = MediaFormatReader::SeekPromise;
+ using WaitForDataPromise = MediaFormatReader::WaitForDataPromise;
+ using TrackSet = MediaFormatReader::TrackSet;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper);
public:
MediaDecoderReaderWrapper(AbstractThread* aOwnerThread,
MediaFormatReader* aReader);
media::TimeUnit StartTime() const;
RefPtr<MetadataPromise> ReadMetadata();
--- a/dom/media/MediaDecoderStateMachine.cpp
+++ b/dom/media/MediaDecoderStateMachine.cpp
@@ -385,17 +385,17 @@ private:
void OnMetadataNotRead(const MediaResult& aError)
{
mMetadataRequest.Complete();
SLOGW("Decode metadata failed, shutting down decoder");
mMaster->DecodeError(aError);
}
- MozPromiseRequestHolder<MediaDecoderReader::MetadataPromise> mMetadataRequest;
+ MozPromiseRequestHolder<MediaFormatReader::MetadataPromise> mMetadataRequest;
};
/**
* Purpose: wait for the CDM to start decoding.
*
* Transition to other states when CDM is ready:
* SEEKING if any pending seek request.
* DECODING_FIRSTFRAME otherwise.
@@ -1390,17 +1390,17 @@ protected:
if (mDoneAudioSeeking && mDoneVideoSeeking) {
SeekCompleted();
}
}
/*
* Track the current seek promise made by the reader.
*/
- MozPromiseRequestHolder<MediaDecoderReader::SeekPromise> mSeekRequest;
+ MozPromiseRequestHolder<MediaFormatReader::SeekPromise> mSeekRequest;
/*
* Internal state.
*/
media::TimeUnit mCurrentTimeBeforeSeek;
bool mDoneAudioSeeking = false;
bool mDoneVideoSeeking = false;
MozPromiseRequestHolder<WaitForDataPromise> mWaitRequest;
--- a/dom/media/MediaDecoderStateMachine.h
+++ b/dom/media/MediaDecoderStateMachine.h
@@ -84,19 +84,19 @@ hardware (via AudioStream).
#include "mozilla/Attributes.h"
#include "mozilla/ReentrantMonitor.h"
#include "mozilla/StateMirroring.h"
#include "nsAutoPtr.h"
#include "nsThreadUtils.h"
#include "MediaDecoder.h"
-#include "MediaDecoderReader.h"
#include "MediaDecoderOwner.h"
#include "MediaEventSource.h"
+#include "MediaFormatReader.h"
#include "MediaMetadataManager.h"
#include "MediaStatistics.h"
#include "MediaTimer.h"
#include "ImageContainer.h"
#include "SeekJob.h"
namespace mozilla {
@@ -144,17 +144,17 @@ enum class VideoDecodeMode : uint8_t
shared state machine thread.
See MediaDecoder.h for more details.
*/
class MediaDecoderStateMachine
{
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderStateMachine)
- using TrackSet = MediaDecoderReader::TrackSet;
+ using TrackSet = MediaFormatReader::TrackSet;
public:
typedef MediaDecoderOwner::NextFrameStatus NextFrameStatus;
typedef mozilla::layers::ImageContainer::FrameID FrameID;
MediaDecoderStateMachine(MediaDecoder* aDecoder, MediaFormatReader* aReader);
nsresult Init(MediaDecoder* aDecoder);
@@ -576,19 +576,19 @@ private:
uint32_t GetAmpleVideoFrames() const;
// Our "ample" audio threshold. Once we've this much audio decoded, we
// pause decoding.
media::TimeUnit mAmpleAudioThreshold;
// Only one of a given pair of ({Audio,Video}DataPromise, WaitForDataPromise)
// should exist at any given moment.
- using AudioDataPromise = MediaDecoderReader::AudioDataPromise;
- using VideoDataPromise = MediaDecoderReader::VideoDataPromise;
- using WaitForDataPromise = MediaDecoderReader::WaitForDataPromise;
+ using AudioDataPromise = MediaFormatReader::AudioDataPromise;
+ using VideoDataPromise = MediaFormatReader::VideoDataPromise;
+ using WaitForDataPromise = MediaFormatReader::WaitForDataPromise;
MozPromiseRequestHolder<AudioDataPromise> mAudioDataRequest;
MozPromiseRequestHolder<VideoDataPromise> mVideoDataRequest;
MozPromiseRequestHolder<WaitForDataPromise> mAudioWaitRequest;
MozPromiseRequestHolder<WaitForDataPromise> mVideoWaitRequest;
const char* AudioRequestStatus() const;
const char* VideoRequestStatus() const;
--- a/dom/media/MediaFormatReader.cpp
+++ b/dom/media/MediaFormatReader.cpp
@@ -1091,43 +1091,49 @@ MediaFormatReader::DemuxerProxy::NotifyD
}
return NotifyDataArrivedPromise::CreateAndResolve(true, __func__);
});
}
MediaFormatReader::MediaFormatReader(MediaDecoderReaderInit& aInit,
MediaDataDemuxer* aDemuxer)
: MediaDecoderReader(aInit)
- , mAudio(this, MediaData::AUDIO_DATA,
- MediaPrefs::MaxAudioDecodeError())
- , mVideo(this, MediaData::VIDEO_DATA,
- MediaPrefs::MaxVideoDecodeError())
+ , mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
+ "MediaFormatReader::mTaskQueue",
+ /* aSupportsTailDispatch = */ true))
+ , mAudio(this, MediaData::AUDIO_DATA, MediaPrefs::MaxAudioDecodeError())
+ , mVideo(this, MediaData::VIDEO_DATA, MediaPrefs::MaxVideoDecodeError())
, mDemuxer(new DemuxerProxy(aDemuxer))
, mDemuxerInitDone(false)
, mPendingNotifyDataArrived(false)
, mLastReportedNumDecodedFrames(0)
, mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe)
, mKnowsCompositor(aInit.mKnowsCompositor)
, mInitDone(false)
, mTrackDemuxersMayBlock(false)
, mSeekScheduled(false)
, mVideoFrameContainer(aInit.mVideoFrameContainer)
, mCrashHelper(aInit.mCrashHelper)
, mDecoderFactory(new DecoderFactory(this))
, mShutdownPromisePool(new ShutdownPromisePool())
+ , mDecoder(aInit.mDecoder)
+ , mBuffered(mTaskQueue,
+ TimeIntervals(),
+ "MediaFormatReader::mBuffered (Canonical)")
{
MOZ_ASSERT(aDemuxer);
MOZ_COUNT_CTOR(MediaFormatReader);
mOnTrackWaitingForKeyListener = OnTrackWaitingForKey().Connect(
mTaskQueue, this, &MediaFormatReader::NotifyWaitingForKey);
}
MediaFormatReader::~MediaFormatReader()
{
MOZ_COUNT_DTOR(MediaFormatReader);
+ MOZ_ASSERT(mShutdown);
}
RefPtr<ShutdownPromise>
MediaFormatReader::Shutdown()
{
MOZ_ASSERT(OnTaskQueue());
LOG("");
@@ -1200,21 +1206,24 @@ MediaFormatReader::TearDownDecoders()
mVideo.mTaskQueue->AwaitShutdownAndIdle();
mVideo.mTaskQueue = nullptr;
}
mDecoderFactory = nullptr;
mPlatform = nullptr;
mVideoFrameContainer = nullptr;
- return MediaDecoderReader::Shutdown();
+ ReleaseResources();
+ mBuffered.DisconnectAll();
+ mDecoder = nullptr;
+ return mTaskQueue->BeginShutdown();
}
nsresult
-MediaFormatReader::InitInternal()
+MediaFormatReader::Init()
{
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
mAudio.mTaskQueue = new TaskQueue(
GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
"MFR::mAudio::mTaskQueue");
mVideo.mTaskQueue = new TaskQueue(
@@ -1239,17 +1248,17 @@ MediaFormatReader::SetCDMProxy(CDMProxy*
bool
MediaFormatReader::IsWaitingOnCDMResource()
{
MOZ_ASSERT(OnTaskQueue());
return IsEncrypted() && !mCDMProxy;
}
-RefPtr<MediaDecoderReader::MetadataPromise>
+RefPtr<MediaFormatReader::MetadataPromise>
MediaFormatReader::AsyncReadMetadata()
{
MOZ_ASSERT(OnTaskQueue());
MOZ_DIAGNOSTIC_ASSERT(mMetadataPromise.IsEmpty());
if (mInitDone) {
// We are returning from dormant.
@@ -1483,17 +1492,17 @@ MediaFormatReader::ShouldSkip(TimeUnit a
}
return (nextKeyframe <= aTimeThreshold
|| (mVideo.mTimeThreshold
&& mVideo.mTimeThreshold.ref().EndTime() < aTimeThreshold))
&& nextKeyframe.ToMicroseconds() >= 0
&& !nextKeyframe.IsInfinite();
}
-RefPtr<MediaDecoderReader::VideoDataPromise>
+RefPtr<MediaFormatReader::VideoDataPromise>
MediaFormatReader::RequestVideoData(const TimeUnit& aTimeThreshold)
{
MOZ_ASSERT(OnTaskQueue());
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(),
"No sample requests allowed while seeking");
MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists()
|| mVideo.mTimeThreshold.isSome());
@@ -1600,17 +1609,17 @@ MediaFormatReader::OnVideoDemuxCompleted
aSamples->mSamples[0]->mTrackInfo
? aSamples->mSamples[0]->mTrackInfo->GetID()
: 0);
mVideo.mDemuxRequest.Complete();
mVideo.mQueuedSamples.AppendElements(aSamples->mSamples);
ScheduleUpdate(TrackInfo::kVideoTrack);
}
-RefPtr<MediaDecoderReader::AudioDataPromise>
+RefPtr<MediaFormatReader::AudioDataPromise>
MediaFormatReader::RequestAudioData()
{
MOZ_ASSERT(OnTaskQueue());
MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise(), "No duplicate sample requests");
MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || mSeekPromise.IsEmpty(),
"No sample requests allowed while seeking");
MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking()
|| !mAudio.mSeekRequest.Exists()
@@ -2416,17 +2425,17 @@ MediaFormatReader::SizeOfAudioQueueInFra
size_t
MediaFormatReader::SizeOfQueue(TrackType aTrack)
{
auto& decoder = GetDecoderData(aTrack);
return decoder.mSizeOfQueue;
}
-RefPtr<MediaDecoderReader::WaitForDataPromise>
+RefPtr<MediaFormatReader::WaitForDataPromise>
MediaFormatReader::WaitForData(MediaData::Type aType)
{
MOZ_ASSERT(OnTaskQueue());
TrackType trackType = aType == MediaData::VIDEO_DATA ?
TrackType::kVideoTrack : TrackType::kAudioTrack;
auto& decoder = GetDecoderData(trackType);
if (!decoder.IsWaiting()) {
// We aren't waiting for anything.
@@ -2596,17 +2605,17 @@ MediaFormatReader::OnVideoSkipFailed(
}
break;
default:
NotifyError(TrackType::kVideoTrack, aFailure.mFailure);
break;
}
}
-RefPtr<MediaDecoderReader::SeekPromise>
+RefPtr<MediaFormatReader::SeekPromise>
MediaFormatReader::Seek(const SeekTarget& aTarget)
{
MOZ_ASSERT(OnTaskQueue());
LOG("aTarget=(%" PRId64 ")", aTarget.GetTime().ToMicroseconds());
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty());
MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise());
--- a/dom/media/MediaFormatReader.h
+++ b/dom/media/MediaFormatReader.h
@@ -18,76 +18,231 @@
#include "MediaPrefs.h"
#include "nsAutoPtr.h"
#include "PDMFactory.h"
namespace mozilla {
class CDMProxy;
+struct WaitForDataRejectValue
+{
+ enum Reason
+ {
+ SHUTDOWN,
+ CANCELED
+ };
+
+ WaitForDataRejectValue(MediaData::Type aType, Reason aReason)
+ : mType(aType)
+ , mReason(aReason)
+ {
+ }
+ MediaData::Type mType;
+ Reason mReason;
+};
+
+struct SeekRejectValue
+{
+ MOZ_IMPLICIT SeekRejectValue(const MediaResult& aError)
+ : mType(MediaData::NULL_DATA)
+ , mError(aError)
+ {
+ }
+ MOZ_IMPLICIT SeekRejectValue(nsresult aResult)
+ : mType(MediaData::NULL_DATA)
+ , mError(aResult)
+ {
+ }
+ SeekRejectValue(MediaData::Type aType, const MediaResult& aError)
+ : mType(aType)
+ , mError(aError)
+ {
+ }
+ MediaData::Type mType;
+ MediaResult mError;
+};
+
+struct MetadataHolder
+{
+ UniquePtr<MediaInfo> mInfo;
+ UniquePtr<MetadataTags> mTags;
+};
+
class MediaFormatReader final : public MediaDecoderReader
{
+ static const bool IsExclusive = true;
typedef TrackInfo::TrackType TrackType;
- typedef MozPromise<bool, MediaResult, /* IsExclusive = */ true> NotifyDataArrivedPromise;
+ typedef MozPromise<bool, MediaResult, IsExclusive> NotifyDataArrivedPromise;
public:
+ using TrackSet = EnumSet<TrackInfo::TrackType>;
+ using MetadataPromise = MozPromise<MetadataHolder, MediaResult, IsExclusive>;
+
+ template<typename Type>
+ using DataPromise = MozPromise<RefPtr<Type>, MediaResult, IsExclusive>;
+ using AudioDataPromise = DataPromise<AudioData>;
+ using VideoDataPromise = DataPromise<VideoData>;
+
+ using SeekPromise = MozPromise<media::TimeUnit, SeekRejectValue, IsExclusive>;
+
+ // Note that, conceptually, WaitForData makes sense in a non-exclusive sense.
+ // But in the current architecture it's only ever used exclusively (by MDSM),
+ // so we mark it that way to verify our assumptions. If you have a use-case
+ // for multiple WaitForData consumers, feel free to flip the exclusivity here.
+ using WaitForDataPromise =
+ MozPromise<MediaData::Type, WaitForDataRejectValue, IsExclusive>;
+
MediaFormatReader(MediaDecoderReaderInit& aInit, MediaDataDemuxer* aDemuxer);
virtual ~MediaFormatReader();
- size_t SizeOfVideoQueueInFrames() override;
- size_t SizeOfAudioQueueInFrames() override;
+ // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
+ // on failure.
+ nsresult Init();
- RefPtr<VideoDataPromise>
- RequestVideoData(const media::TimeUnit& aTimeThreshold) override;
+ size_t SizeOfVideoQueueInFrames();
+ size_t SizeOfAudioQueueInFrames();
- RefPtr<AudioDataPromise> RequestAudioData() override;
+ // Requests one video sample from the reader.
+ RefPtr<VideoDataPromise> RequestVideoData(
+ const media::TimeUnit& aTimeThreshold);
- RefPtr<MetadataPromise> AsyncReadMetadata() override;
-
- void ReadUpdatedMetadata(MediaInfo* aInfo) override;
+ // Requests one audio sample from the reader.
+ //
+ // The decode should be performed asynchronously, and the promise should
+ // be resolved when it is complete.
+ RefPtr<AudioDataPromise> RequestAudioData();
- RefPtr<SeekPromise> Seek(const SeekTarget& aTarget) override;
+ // The default implementation of AsyncReadMetadata is implemented in terms of
+ // synchronous ReadMetadata() calls. Implementations may also
+ // override AsyncReadMetadata to create a more proper async implementation.
+ RefPtr<MetadataPromise> AsyncReadMetadata();
- void NotifyDataArrived() override;
+ // Fills aInfo with the latest cached data required to present the media,
+ // ReadUpdatedMetadata will always be called once ReadMetadata has succeeded.
+ void ReadUpdatedMetadata(MediaInfo* aInfo);
+
+ RefPtr<SeekPromise> Seek(const SeekTarget& aTarget);
+
+ // Called once new data has been cached by the MediaResource.
+ // mBuffered should be recalculated and updated accordingly.
+ void NotifyDataArrived();
protected:
- void UpdateBuffered() override;
+ // Recomputes mBuffered.
+ void UpdateBuffered();
public:
- // For Media Resource Management
- void ReleaseResources() override;
+ // Called by MDSM in dormant state to release resources allocated by this
+ // reader. The reader can resume decoding by calling Seek() to a specific
+ // position.
+ void ReleaseResources();
+
+ bool OnTaskQueue() const { return OwnerThread()->IsCurrentThreadIn(); }
- nsresult ResetDecode(TrackSet aTracks) override;
-
- RefPtr<ShutdownPromise> Shutdown() override;
-
- bool VideoIsHardwareAccelerated() const override;
+ // Resets all state related to decoding, emptying all buffers etc.
+ // Cancels all pending Request*Data() request callbacks, rejects any
+ // outstanding seek promises, and flushes the decode pipeline. The
+ // decoder must not call any of the callbacks for outstanding
+ // Request*Data() calls after this is called. Calls to Request*Data()
+ // made after this should be processed as usual.
+ //
+ // Normally this call preceedes a Seek() call, or shutdown.
+ //
+ // aParam is a set of TrackInfo::TrackType enums specifying which
+ // queues need to be reset, defaulting to both audio and video tracks.
+ nsresult ResetDecode(TrackSet aTracks);
- bool IsWaitForDataSupported() const override { return true; }
- RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType) override;
+ // Destroys the decoding state. The reader cannot be made usable again.
+ // This is different from ReleaseMediaResources() as it is irreversable,
+ // whereas ReleaseMediaResources() is. Must be called on the decode
+ // thread.
+ RefPtr<ShutdownPromise> Shutdown();
+
+ // Returns true if this decoder reader uses hardware accelerated video
+ // decoding.
+ bool VideoIsHardwareAccelerated() const;
- bool UseBufferingHeuristics() const override
- {
- return mTrackDemuxersMayBlock;
- }
+ // By default, the state machine polls the reader once per second when it's
+ // in buffering mode. Some readers support a promise-based mechanism by which
+ // they notify the state machine when the data arrives.
+ bool IsWaitForDataSupported() const { return true; }
+
+ RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType);
- void SetCDMProxy(CDMProxy* aProxy) override;
+ // The MediaDecoderStateMachine uses various heuristics that assume that
+ // raw media data is arriving sequentially from a network channel. This
+ // makes sense in the <video src="foo"> case, but not for more advanced use
+ // cases like MSE.
+ bool UseBufferingHeuristics() const { return mTrackDemuxersMayBlock; }
+
+ void SetCDMProxy(CDMProxy* aProxy);
// Returns a string describing the state of the decoder data.
// Used for debugging purposes.
void GetMozDebugReaderData(nsACString& aString);
- void SetVideoNullDecode(bool aIsNullDecode) override;
+ // Switch the video decoder to NullDecoderModule. It might takes effective
+ // since a few samples later depends on how much demuxed samples are already
+ // queued in the original video decoder.
+ void SetVideoNullDecode(bool aIsNullDecode);
+
+ void UpdateCompositor(already_AddRefed<layers::KnowsCompositor>);
+
+ void UpdateDuration(const media::TimeUnit& aDuration)
+ {
+ MOZ_ASSERT(OnTaskQueue());
+ UpdateBuffered();
+ }
+
+ AbstractCanonical<media::TimeIntervals>* CanonicalBuffered()
+ {
+ return &mBuffered;
+ }
+
+ TaskQueue* OwnerThread() const { return mTaskQueue; }
+
+ TimedMetadataEventSource& TimedMetadataEvent() { return mTimedMetadataEvent; }
+
+ // Notified by the OggDemuxer during playback when chained ogg is detected.
+ MediaEventSource<void>& OnMediaNotSeekable() { return mOnMediaNotSeekable; }
- void UpdateCompositor(already_AddRefed<layers::KnowsCompositor>) override;
+ TimedMetadataEventProducer& TimedMetadataProducer()
+ {
+ return mTimedMetadataEvent;
+ }
+
+ MediaEventProducer<void>& MediaNotSeekableProducer()
+ {
+ 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;
+ }
+
+ MediaEventSource<nsTArray<uint8_t>, nsString>& OnEncrypted()
+ {
+ return mOnEncrypted;
+ }
+
+ MediaEventSource<void>& OnWaitingForKey() { return mOnWaitingForKey; }
+
+ MediaEventSource<MediaResult>& OnDecodeWarning() { return mOnDecodeWarning; }
private:
- nsresult InitInternal() override;
-
bool HasVideo() const { return mVideo.mTrackDemuxer; }
bool HasAudio() const { return mAudio.mTrackDemuxer; }
bool IsWaitingOnCDMResource();
bool InitDemuxer();
// Notify the track demuxers that new data has been received.
void NotifyTrackDemuxers();
@@ -440,16 +595,19 @@ private:
mHasPromise = false;
}
private:
MozPromiseHolder<DataPromise<Type>> mPromise;
Atomic<bool> mHasPromise;
};
+ // Decode task queue.
+ RefPtr<TaskQueue> mTaskQueue;
+
DecoderDataWithPromise<AudioData> mAudio;
DecoderDataWithPromise<VideoData> mVideo;
// Returns true when the decoder for this track needs input.
bool NeedInput(DecoderData& aDecoder);
DecoderData& GetDecoderData(TrackType aTrack);
@@ -560,13 +718,36 @@ private:
UniquePtr<MetadataTags> mTags;
// A flag indicating if the start time is known or not.
bool mHasStartTime = false;
void ShutdownDecoder(TrackType aTrack);
RefPtr<ShutdownPromise> TearDownDecoders();
+
+ // Reference to the owning decoder object.
+ AbstractMediaDecoder* mDecoder;
+
+ bool mShutdown = false;
+
+ // Buffered range.
+ Canonical<media::TimeIntervals> mBuffered;
+
+ // Used to send TimedMetadata to the listener.
+ TimedMetadataEventProducer mTimedMetadataEvent;
+
+ // Notify if this media is not seekable.
+ MediaEventProducer<void> mOnMediaNotSeekable;
+
+ // Notify if we are waiting for a decryption key.
+ MediaEventProducer<TrackInfo::TrackType> mOnTrackWaitingForKey;
+
+ MediaEventProducer<nsTArray<uint8_t>, nsString> mOnEncrypted;
+
+ MediaEventProducer<void> mOnWaitingForKey;
+
+ MediaEventProducer<MediaResult> mOnDecodeWarning;
};
} // namespace mozilla
#endif