summaryrefslogtreecommitdiffstats
path: root/dom/media/MediaDecoderReader.h
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /dom/media/MediaDecoderReader.h
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/media/MediaDecoderReader.h')
-rw-r--r--dom/media/MediaDecoderReader.h445
1 files changed, 445 insertions, 0 deletions
diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h
new file mode 100644
index 000000000..8a6997826
--- /dev/null
+++ b/dom/media/MediaDecoderReader.h
@@ -0,0 +1,445 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+#if !defined(MediaDecoderReader_h_)
+#define MediaDecoderReader_h_
+
+#include "mozilla/EnumSet.h"
+#include "mozilla/MozPromise.h"
+#include "nsAutoPtr.h"
+
+#include "AbstractMediaDecoder.h"
+#include "MediaInfo.h"
+#include "MediaData.h"
+#include "MediaResult.h"
+#include "MediaMetadataManager.h"
+#include "MediaQueue.h"
+#include "MediaTimer.h"
+#include "AudioCompactor.h"
+#include "Intervals.h"
+#include "TimeUnits.h"
+#include "SeekTarget.h"
+
+namespace mozilla {
+
+class CDMProxy;
+class MediaDecoderReader;
+
+struct WaitForDataRejectValue
+{
+ enum Reason {
+ SHUTDOWN,
+ CANCELED
+ };
+
+ WaitForDataRejectValue(MediaData::Type aType, Reason aReason)
+ :mType(aType), mReason(aReason) {}
+ MediaData::Type mType;
+ Reason mReason;
+};
+
+class MetadataHolder
+{
+public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MetadataHolder)
+ MediaInfo mInfo;
+ nsAutoPtr<MetadataTags> mTags;
+
+private:
+ virtual ~MetadataHolder() {}
+};
+
+// 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. Never hold the decoder monitor when calling into this class.
+// Unless otherwise specified, methods and fields of this class can only
+// be accessed on the decode task queue.
+class MediaDecoderReader {
+ friend class ReRequestVideoWithSkipTask;
+ friend class ReRequestAudioTask;
+
+ static const bool IsExclusive = true;
+
+public:
+ using TrackSet = EnumSet<TrackInfo::TrackType>;
+
+ using MetadataPromise =
+ MozPromise<RefPtr<MetadataHolder>, MediaResult, IsExclusive>;
+ using MediaDataPromise =
+ MozPromise<RefPtr<MediaData>, MediaResult, IsExclusive>;
+ using SeekPromise = MozPromise<media::TimeUnit, nsresult, 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>;
+
+ using BufferedUpdatePromise = MozPromise<bool, bool, IsExclusive>;
+
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReader)
+
+ // The caller must ensure that Shutdown() is called before aDecoder is
+ // destroyed.
+ explicit MediaDecoderReader(AbstractMediaDecoder* aDecoder);
+
+ // 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() {}
+
+ // 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();
+ }
+
+ // 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.
+ //
+ // The first samples of every stream produced after a ResetDecode() call
+ // *must* be marked as "discontinuities". If it's not, seeking work won't
+ // properly!
+ //
+ // 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));
+
+ // Requests one audio sample from the reader.
+ //
+ // The decode should be performed asynchronously, and the promise should
+ // be resolved when it is complete. Don't hold the decoder
+ // monitor while calling this, as the implementation may try to wait
+ // on something that needs the monitor and deadlock.
+ virtual RefPtr<MediaDataPromise> RequestAudioData();
+
+ // Requests one video sample from the reader.
+ //
+ // Don't hold the decoder monitor while calling this, as the implementation
+ // may try to wait on something that needs the monitor and deadlock.
+ // If aSkipToKeyframe is true, the decode should skip ahead to the
+ // the next keyframe at or after aTimeThreshold microseconds.
+ virtual RefPtr<MediaDataPromise>
+ RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold);
+
+ // 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 { return false; }
+
+ virtual RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType)
+ {
+ MOZ_CRASH();
+ }
+
+ // By default, the reader return the decoded data. Some readers support
+ // retuning demuxed data.
+ virtual bool IsDemuxOnlySupported() const { return false; }
+
+ // Configure the reader to return demuxed or decoded data
+ // upon calls to Request{Audio,Video}Data.
+ virtual void SetDemuxOnly(bool /*aDemuxedOnly*/) {}
+
+ // 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();
+
+ // 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) {}
+
+ // Moves the decode head to aTime microseconds. aEndTime denotes the end
+ // time of the media in usecs. This is only needed for OggReader, and should
+ // probably be removed somehow.
+ virtual RefPtr<SeekPromise> Seek(SeekTarget aTarget, int64_t aEndTime) = 0;
+
+ // Called to move the reader into idle state. When the reader is
+ // created it is assumed to be active (i.e. not idle). When the media
+ // element is paused and we don't need to decode any more data, the state
+ // machine calls SetIdle() to inform the reader that its decoder won't be
+ // needed for a while. The reader can use these notifications to enter
+ // a low power state when the decoder isn't needed, if desired.
+ // This is most useful on mobile.
+ // Note: DecodeVideoFrame, DecodeAudioData, ReadMetadata and Seek should
+ // activate the decoder if necessary. The state machine only needs to know
+ // when to call SetIdle().
+ virtual void SetIdle() {}
+
+ virtual void SetCDMProxy(CDMProxy* aProxy) {}
+
+ // Tell the reader that the data decoded are not for direct playback, so it
+ // can accept more files, in particular those which have more channels than
+ // available in the audio output.
+ void SetIgnoreAudioOutputFormat()
+ {
+ mIgnoreAudioOutputFormat = true;
+ }
+
+ // MediaSourceReader opts out of the start-time-guessing mechanism.
+ virtual bool ForceZeroStartTime() const { return false; }
+
+ // 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 { return true; }
+
+ // Returns the number of bytes of memory allocated by structures/frames in
+ // the video queue.
+ size_t SizeOfVideoQueueInBytes() const;
+
+ // Returns the number of bytes of memory allocated by structures/frames in
+ // the audio queue.
+ size_t SizeOfAudioQueueInBytes() const;
+
+ virtual size_t SizeOfVideoQueueInFrames();
+ virtual size_t SizeOfAudioQueueInFrames();
+
+ void NotifyDataArrived()
+ {
+ MOZ_ASSERT(OnTaskQueue());
+ NS_ENSURE_TRUE_VOID(!mShutdown);
+ NotifyDataArrivedInternal();
+ UpdateBuffered();
+ }
+
+ // Update the buffered ranges and upon doing so return a promise
+ // to indicate success. Overrides may need to do extra work to ensure
+ // buffered is up to date.
+ virtual RefPtr<BufferedUpdatePromise> UpdateBufferedWithPromise()
+ {
+ MOZ_ASSERT(OnTaskQueue());
+ UpdateBuffered();
+ return BufferedUpdatePromise::CreateAndResolve(true, __func__);
+ }
+
+ virtual MediaQueue<AudioData>& AudioQueue() { return mAudioQueue; }
+ virtual MediaQueue<VideoData>& VideoQueue() { return mVideoQueue; }
+
+ AbstractCanonical<media::TimeIntervals>* CanonicalBuffered()
+ {
+ return &mBuffered;
+ }
+
+ void DispatchSetStartTime(int64_t aStartTime)
+ {
+ RefPtr<MediaDecoderReader> self = this;
+ nsCOMPtr<nsIRunnable> r =
+ NS_NewRunnableFunction([self, aStartTime] () -> void
+ {
+ MOZ_ASSERT(self->OnTaskQueue());
+ MOZ_ASSERT(!self->HaveStartTime());
+ self->mStartTime.emplace(aStartTime);
+ self->UpdateBuffered();
+ });
+ OwnerThread()->Dispatch(r.forget());
+ }
+
+ TaskQueue* OwnerThread() const
+ {
+ return mTaskQueue;
+ }
+
+ // Returns true if the reader implements RequestAudioData()
+ // and RequestVideoData() asynchronously, rather than using the
+ // implementation in this class to adapt the old synchronous to
+ // the newer async model.
+ virtual bool IsAsync() const { return false; }
+
+ // Returns true if this decoder reader uses hardware accelerated video
+ // decoding.
+ virtual bool VideoIsHardwareAccelerated() const { return false; }
+
+ TimedMetadataEventSource& TimedMetadataEvent()
+ {
+ return mTimedMetadataEvent;
+ }
+
+ // Notified by the OggReader during playback when chained ogg is detected.
+ MediaEventSource<void>& OnMediaNotSeekable() { return mOnMediaNotSeekable; }
+
+ TimedMetadataEventProducer& TimedMetadataProducer()
+ {
+ return mTimedMetadataEvent;
+ }
+
+ MediaEventProducer<void>& MediaNotSeekableProducer()
+ {
+ return mOnMediaNotSeekable;
+ }
+
+ // 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.
+ virtual void SetVideoBlankDecode(bool aIsBlankDecode) {}
+
+protected:
+ virtual ~MediaDecoderReader();
+
+ // Populates aBuffered with the time ranges which are buffered. This may only
+ // be called on the decode task queue, and should only be used internally by
+ // UpdateBuffered - mBuffered (or mirrors of it) should be used for everything
+ // else.
+ //
+ // This base implementation in MediaDecoderReader estimates the time ranges
+ // buffered by interpolating the cached byte ranges with the duration
+ // of the media. Reader subclasses should override this method if they
+ // can quickly calculate the buffered ranges more accurately.
+ //
+ // The primary advantage of this implementation in the reader base class
+ // is that it's a fast approximation, which does not perform any I/O.
+ //
+ // The OggReader relies on this base implementation not performing I/O,
+ // since in FirefoxOS we can't do I/O on the main thread, where this is
+ // called.
+ virtual media::TimeIntervals GetBuffered();
+
+ RefPtr<MediaDataPromise> DecodeToFirstVideoData();
+
+ bool HaveStartTime()
+ {
+ MOZ_ASSERT(OnTaskQueue());
+ return mStartTime.isSome();
+ }
+
+ int64_t StartTime() { MOZ_ASSERT(HaveStartTime()); return mStartTime.ref(); }
+
+ // Queue of audio frames. This queue is threadsafe, and is accessed from
+ // the audio, decoder, state machine, and main threads.
+ MediaQueue<AudioData> mAudioQueue;
+
+ // Queue of video frames. This queue is threadsafe, and is accessed from
+ // the decoder, state machine, and main threads.
+ MediaQueue<VideoData> mVideoQueue;
+
+ // An adapter to the audio queue which first copies data to buffers with
+ // minimal allocation slop and then pushes them to the queue. This is
+ // useful for decoders working with formats that give awkward numbers of
+ // frames such as mp3.
+ AudioCompactor mAudioCompactor;
+
+ // Reference to the owning decoder object.
+ AbstractMediaDecoder* mDecoder;
+
+ // Decode task queue.
+ RefPtr<TaskQueue> mTaskQueue;
+
+ // State-watching manager.
+ WatchManager<MediaDecoderReader> mWatchManager;
+
+ // Buffered range.
+ Canonical<media::TimeIntervals> mBuffered;
+
+ // Stores presentation info required for playback.
+ MediaInfo mInfo;
+
+ // Duration, mirrored from the state machine task queue.
+ Mirror<media::NullableTimeUnit> mDuration;
+
+ // Whether we should accept media that we know we can't play
+ // directly, because they have a number of channel higher than
+ // what we support.
+ bool mIgnoreAudioOutputFormat;
+
+ // The start time of the media, in microseconds. This is the presentation
+ // time of the first frame decoded from the media. This is initialized to -1,
+ // and then set to a value >= by MediaDecoderStateMachine::SetStartTime(),
+ // after which point it never changes (though SetStartTime may be called
+ // multiple times with the same value).
+ //
+ // This is an ugly breach of abstractions - it's currently necessary for the
+ // readers to return the correct value of GetBuffered. We should refactor
+ // things such that all GetBuffered calls go through the MDSM, which would
+ // offset the range accordingly.
+ Maybe<int64_t> mStartTime;
+
+ // This is a quick-and-dirty way for DecodeAudioData implementations to
+ // communicate the presence of a decoding error to RequestAudioData. We should
+ // replace this with a promise-y mechanism as we make this stuff properly
+ // async.
+ bool mHitAudioDecodeError;
+ bool mShutdown;
+
+ // Used to send TimedMetadata to the listener.
+ TimedMetadataEventProducer mTimedMetadataEvent;
+
+ // Notify if this media is not seekable.
+ MediaEventProducer<void> mOnMediaNotSeekable;
+
+private:
+ virtual nsresult InitInternal() { return NS_OK; }
+
+ // Does any spinup that needs to happen on this task queue. This runs on a
+ // different thread than Init, and there should not be ordering dependencies
+ // between the two (even though in practice, Init will always run first right
+ // now thanks to the tail dispatcher).
+ void InitializationTask();
+
+ // Read header data for all bitstreams in the file. Fills aInfo with
+ // the data required to present the media, and optionally fills *aTags
+ // with tag metadata from the file.
+ // Returns NS_OK on success, or NS_ERROR_FAILURE on failure.
+ virtual nsresult ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
+ {
+ MOZ_CRASH();
+ }
+
+ // Recomputes mBuffered.
+ virtual void UpdateBuffered();
+
+ virtual void VisibilityChanged();
+
+ virtual void NotifyDataArrivedInternal() {}
+
+ // Overrides of this function should decodes an unspecified amount of
+ // audio data, enqueuing the audio data in mAudioQueue. Returns true
+ // when there's more audio to decode, false if the audio is finished,
+ // end of file has been reached, or an un-recoverable read error has
+ // occured. This function blocks until the decode is complete.
+ virtual bool DecodeAudioData()
+ {
+ return false;
+ }
+
+ // Overrides of this function should read and decodes one video frame.
+ // Packets with a timestamp less than aTimeThreshold will be decoded
+ // (unless they're not keyframes and aKeyframeSkip is true), but will
+ // not be added to the queue. This function blocks until the decode
+ // is complete.
+ virtual bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold)
+ {
+ return false;
+ }
+
+ // Promises used only for the base-class (sync->async adapter) implementation
+ // of Request{Audio,Video}Data.
+ MozPromiseHolder<MediaDataPromise> mBaseAudioPromise;
+ MozPromiseHolder<MediaDataPromise> mBaseVideoPromise;
+
+ MediaEventListener mDataArrivedListener;
+};
+
+} // namespace mozilla
+
+#endif