/* -*- 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/. */ #if !defined(MediaFormatReader_h_) # define MediaFormatReader_h_ # include "FrameStatistics.h" # include "MediaDataDemuxer.h" # include "MediaEventSource.h" # include "MediaMetadataManager.h" # include "MediaPromiseDefs.h" # include "PlatformDecoderModule.h" # include "SeekTarget.h" # include "mozilla/Atomics.h" # include "mozilla/Maybe.h" # include "mozilla/MozPromise.h" # include "mozilla/Mutex.h" # include "mozilla/StateMirroring.h" # include "mozilla/StaticPrefs_media.h" # include "mozilla/TaskQueue.h" # include "mozilla/ThreadSafeWeakPtr.h" # include "mozilla/dom/MediaDebugInfoBinding.h" namespace mozilla { class CDMProxy; class GMPCrashHelper; class MediaResource; 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::Type::NULL_DATA), mError(aError) {} MOZ_IMPLICIT SeekRejectValue(nsresult aResult) : mType(MediaData::Type::NULL_DATA), mError(aResult) {} SeekRejectValue(MediaData::Type aType, const MediaResult& aError) : mType(aType), mError(aError) {} MediaData::Type mType; MediaResult mError; }; struct MetadataHolder { UniquePtr mInfo; UniquePtr mTags; }; typedef void* MediaDecoderOwnerID; struct MOZ_STACK_CLASS MediaFormatReaderInit { MediaResource* mResource = nullptr; VideoFrameContainer* mVideoFrameContainer = nullptr; FrameStatistics* mFrameStats = nullptr; already_AddRefed mKnowsCompositor; already_AddRefed mCrashHelper; // Used in bug 1393399 for temporary telemetry. MediaDecoderOwnerID mMediaDecoderOwnerID = nullptr; Maybe mTrackingId; }; DDLoggedTypeDeclName(MediaFormatReader); class MediaFormatReader final : public SupportsThreadSafeWeakPtr, public DecoderDoctorLifeLogger { static const bool IsExclusive = true; typedef TrackInfo::TrackType TrackType; typedef MozPromise NotifyDataArrivedPromise; public: MOZ_DECLARE_REFCOUNTED_TYPENAME(MediaFormatReader) using TrackSet = EnumSet; using MetadataPromise = MozPromise; template using DataPromise = MozPromise, MediaResult, IsExclusive>; using AudioDataPromise = DataPromise; using VideoDataPromise = DataPromise; using SeekPromise = MozPromise; // 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; MediaFormatReader(MediaFormatReaderInit& aInit, MediaDataDemuxer* aDemuxer); virtual ~MediaFormatReader(); // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE // on failure. nsresult Init(); size_t SizeOfVideoQueueInFrames(); size_t SizeOfAudioQueueInFrames(); // Requests one video sample from the reader. RefPtr RequestVideoData( const media::TimeUnit& aTimeThreshold, bool aRequestNextVideoKeyFrame = false); // Requests one audio sample from the reader. // // The decode should be performed asynchronously, and the promise should // be resolved when it is complete. RefPtr RequestAudioData(); // 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 AsyncReadMetadata(); // 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 Seek(const SeekTarget& aTarget); // Called once new data has been cached by the MediaResource. // mBuffered should be recalculated and updated accordingly. void NotifyDataArrived(); // Update ID for the external playback engine. Currently it's only used on // Windows when the media engine playback is enabled. void UpdateMediaEngineId(uint64_t aMediaEngineId); protected: // Recomputes mBuffered. void UpdateBuffered(); public: // 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(); } // 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); // 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 Shutdown(); // Returns true if this decoder reader uses hardware accelerated video // decoding. bool VideoIsHardwareAccelerated() const; // 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 WaitForData(MediaData::Type aType); // The MediaDecoderStateMachine uses various heuristics that assume that // raw media data is arriving sequentially from a network channel. This // makes sense in the