| File: | root/firefox-clang/dom/media/MediaFormatReader.h |
| Warning: | line 365, column 10 Excessive padding in 'struct mozilla::MediaFormatReader::DecoderData' (34 padding bytes, where 2 is optimal). Optimal fields order: mOwner, mTrackDemuxer, mTaskQueue, mDecoder, mDecodePerfRecorder, mSeekRequest, mQueuedSamples, mDemuxRequest, mWaitingPromise, mDecodeRequest, mShutdownPromise, mDrainRequest, mOutput, mNumSamplesInput, mNumSamplesOutput, mNumSamplesOutputTotal, mNumSamplesSkippedTotal, mSizeOfQueue, mOriginalInfo, mWorkingInfo, mInfo, mDescription, mProcessName, mCodecName, mWaitingForDataStartTime, mMeanRate, mFirstFrameTime, mLastTimeRangesEnd, mFirstDemuxedSampleTime, mError, mMutex, mLastDecodedSampleTime, mTimeThreshold, mTimeRanges, mDrainState, mNumOfConsecutiveDecodingError, mMaxConsecutiveDecodingError, mNumOfConsecutiveRDDOrGPUCrashes, mMaxConsecutiveRDDOrGPUCrashes, mNumOfConsecutiveUtilityCrashes, mMaxConsecutiveUtilityCrashes, mIsHardwareAccelerated, mLastStreamSourceID, mNextStreamSourceID, mType, mUpdateScheduled, mDemuxEOS, mWaitingForKey, mReceivedNewData, mFlushing, mFlushed, mIsNullDecode, mHardwareDecodingDisabled, mHasReportedVideoHardwareSupportTelemtry, consider reordering the fields or adding explicit padding members |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
| 2 | /* vim:set ts=2 sw=2 sts=2 et cindent: */ |
| 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
| 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
| 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
| 6 | |
| 7 | #if !defined(MediaFormatReader_h_) |
| 8 | # define MediaFormatReader_h_ |
| 9 | |
| 10 | # include "FrameStatistics.h" |
| 11 | # include "MediaDataDemuxer.h" |
| 12 | # include "MediaEventSource.h" |
| 13 | # include "MediaMetadataManager.h" |
| 14 | # include "MediaPromiseDefs.h" |
| 15 | # include "PlatformDecoderModule.h" |
| 16 | # include "SeekTarget.h" |
| 17 | # include "mozilla/Atomics.h" |
| 18 | # include "mozilla/Maybe.h" |
| 19 | # include "mozilla/MozPromise.h" |
| 20 | # include "mozilla/Mutex.h" |
| 21 | # include "mozilla/StateMirroring.h" |
| 22 | # include "mozilla/StaticPrefs_media.h" |
| 23 | # include "mozilla/TaskQueue.h" |
| 24 | # include "mozilla/TimeStamp.h" |
| 25 | # include "mozilla/ThreadSafeWeakPtr.h" |
| 26 | # include "mozilla/dom/MediaDebugInfoBinding.h" |
| 27 | |
| 28 | namespace mozilla { |
| 29 | |
| 30 | class CDMProxy; |
| 31 | class GMPCrashHelper; |
| 32 | class MediaResource; |
| 33 | class VideoFrameContainer; |
| 34 | |
| 35 | struct WaitForDataRejectValue { |
| 36 | enum Reason { SHUTDOWN, CANCELED }; |
| 37 | |
| 38 | WaitForDataRejectValue(MediaData::Type aType, Reason aReason) |
| 39 | : mType(aType), mReason(aReason) {} |
| 40 | MediaData::Type mType; |
| 41 | Reason mReason; |
| 42 | }; |
| 43 | |
| 44 | struct SeekRejectValue { |
| 45 | MOZ_IMPLICIT SeekRejectValue(const MediaResult& aError) |
| 46 | : mType(MediaData::Type::NULL_DATA), mError(aError) {} |
| 47 | MOZ_IMPLICIT SeekRejectValue(nsresult aResult) |
| 48 | : mType(MediaData::Type::NULL_DATA), mError(aResult) {} |
| 49 | SeekRejectValue(MediaData::Type aType, const MediaResult& aError) |
| 50 | : mType(aType), mError(aError) {} |
| 51 | MediaData::Type mType; |
| 52 | MediaResult mError; |
| 53 | }; |
| 54 | |
| 55 | struct MetadataHolder { |
| 56 | UniquePtr<MediaInfo> mInfo; |
| 57 | UniquePtr<MetadataTags> mTags; |
| 58 | }; |
| 59 | |
| 60 | using MediaDecoderOwnerID = void*; |
| 61 | |
| 62 | struct MOZ_STACK_CLASS MediaFormatReaderInit { |
| 63 | MediaResource* mResource = nullptr; |
| 64 | VideoFrameContainer* mVideoFrameContainer = nullptr; |
| 65 | FrameStatistics* mFrameStats = nullptr; |
| 66 | already_AddRefed<layers::KnowsCompositor> mKnowsCompositor; |
| 67 | already_AddRefed<GMPCrashHelper> mCrashHelper; |
| 68 | // Used in bug 1393399 for temporary telemetry. |
| 69 | MediaDecoderOwnerID mMediaDecoderOwnerID = nullptr; |
| 70 | Maybe<TrackingId> mTrackingId; |
| 71 | }; |
| 72 | |
| 73 | DDLoggedTypeDeclName(MediaFormatReader)class MediaFormatReader; template <> struct DDLoggedTypeTraits <MediaFormatReader> { using Type = MediaFormatReader; static constexpr const char* Name() { return "MediaFormatReader"; } using HasBase = std::false_type; using BaseType = MediaFormatReader ; static constexpr const char* BaseTypeName() { return ""; } } ;; |
| 74 | |
| 75 | class MediaFormatReader final |
| 76 | : public SupportsThreadSafeWeakPtr<MediaFormatReader>, |
| 77 | public DecoderDoctorLifeLogger<MediaFormatReader> { |
| 78 | static const bool IsExclusive = true; |
| 79 | using TrackType = TrackInfo::TrackType; |
| 80 | using NotifyDataArrivedPromise = MozPromise<bool, MediaResult, IsExclusive>; |
| 81 | |
| 82 | public: |
| 83 | MOZ_DECLARE_REFCOUNTED_TYPENAME(MediaFormatReader)const char* typeName() const { return "MediaFormatReader"; } size_t typeSize() const { return sizeof(*this); } |
| 84 | |
| 85 | using TrackSet = EnumSet<TrackInfo::TrackType>; |
| 86 | using MetadataPromise = MozPromise<MetadataHolder, MediaResult, IsExclusive>; |
| 87 | |
| 88 | template <typename Type> |
| 89 | using DataPromise = MozPromise<RefPtr<Type>, MediaResult, IsExclusive>; |
| 90 | using AudioDataPromise = DataPromise<AudioData>; |
| 91 | using VideoDataPromise = DataPromise<VideoData>; |
| 92 | |
| 93 | using SeekPromise = MozPromise<media::TimeUnit, SeekRejectValue, IsExclusive>; |
| 94 | |
| 95 | // Note that, conceptually, WaitForData makes sense in a non-exclusive sense. |
| 96 | // But in the current architecture it's only ever used exclusively (by MDSM), |
| 97 | // so we mark it that way to verify our assumptions. If you have a use-case |
| 98 | // for multiple WaitForData consumers, feel free to flip the exclusivity here. |
| 99 | using WaitForDataPromise = |
| 100 | MozPromise<MediaData::Type, WaitForDataRejectValue, IsExclusive>; |
| 101 | |
| 102 | MediaFormatReader(MediaFormatReaderInit& aInit, MediaDataDemuxer* aDemuxer); |
| 103 | virtual ~MediaFormatReader(); |
| 104 | |
| 105 | // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE |
| 106 | // on failure. |
| 107 | nsresult Init(); |
| 108 | |
| 109 | size_t SizeOfVideoQueueInFrames(); |
| 110 | size_t SizeOfAudioQueueInFrames(); |
| 111 | |
| 112 | // Requests one video sample from the reader. |
| 113 | RefPtr<VideoDataPromise> RequestVideoData( |
| 114 | const media::TimeUnit& aTimeThreshold, |
| 115 | bool aRequestNextVideoKeyFrame = false); |
| 116 | |
| 117 | // Requests one audio sample from the reader. |
| 118 | // |
| 119 | // The decode should be performed asynchronously, and the promise should |
| 120 | // be resolved when it is complete. |
| 121 | RefPtr<AudioDataPromise> RequestAudioData(); |
| 122 | |
| 123 | // The default implementation of AsyncReadMetadata is implemented in terms of |
| 124 | // synchronous ReadMetadata() calls. Implementations may also |
| 125 | // override AsyncReadMetadata to create a more proper async implementation. |
| 126 | RefPtr<MetadataPromise> AsyncReadMetadata(); |
| 127 | |
| 128 | // Fills aInfo with the latest cached data required to present the media, |
| 129 | // ReadUpdatedMetadata will always be called once ReadMetadata has succeeded. |
| 130 | void ReadUpdatedMetadata(MediaInfo* aInfo); |
| 131 | |
| 132 | RefPtr<SeekPromise> Seek(const SeekTarget& aTarget); |
| 133 | |
| 134 | // Called once new data has been cached by the MediaResource. |
| 135 | // mBuffered should be recalculated and updated accordingly. |
| 136 | void NotifyDataArrived(); |
| 137 | |
| 138 | // Update ID for the external playback engine. Currently it's only used on |
| 139 | // Windows when the media engine playback is enabled. |
| 140 | void UpdateMediaEngineId(uint64_t aMediaEngineId); |
| 141 | |
| 142 | // This function will be called if the media key is set before playback |
| 143 | // starts, indicating the playback should be encrypted. |
| 144 | void SetEncryptedCustomIdent(); |
| 145 | |
| 146 | bool IsEncryptedCustomIdent() const { return mEncryptedCustomIdent; } |
| 147 | |
| 148 | protected: |
| 149 | // Recomputes mBuffered. |
| 150 | void UpdateBuffered(); |
| 151 | |
| 152 | public: |
| 153 | // Called by MDSM in dormant state to release resources allocated by this |
| 154 | // reader. The reader can resume decoding by calling Seek() to a specific |
| 155 | // position. |
| 156 | void ReleaseResources(); |
| 157 | |
| 158 | bool OnTaskQueue() const { return OwnerThread()->IsCurrentThreadIn(); } |
| 159 | |
| 160 | // Resets all state related to decoding, emptying all buffers etc. |
| 161 | // Cancels all pending Request*Data() request callbacks, rejects any |
| 162 | // outstanding seek promises, and flushes the decode pipeline. The |
| 163 | // decoder must not call any of the callbacks for outstanding |
| 164 | // Request*Data() calls after this is called. Calls to Request*Data() |
| 165 | // made after this should be processed as usual. |
| 166 | // |
| 167 | // Normally this call preceedes a Seek() call, or shutdown. |
| 168 | // |
| 169 | // aParam is a set of TrackInfo::TrackType enums specifying which |
| 170 | // queues need to be reset, defaulting to both audio and video tracks. |
| 171 | nsresult ResetDecode(const TrackSet& aTracks); |
| 172 | |
| 173 | // Destroys the decoding state. The reader cannot be made usable again. |
| 174 | // This is different from ReleaseMediaResources() as it is irreversable, |
| 175 | // whereas ReleaseMediaResources() is. Must be called on the decode |
| 176 | // thread. |
| 177 | RefPtr<ShutdownPromise> Shutdown(); |
| 178 | |
| 179 | // Returns true if this decoder reader uses hardware accelerated video |
| 180 | // decoding. |
| 181 | bool VideoIsHardwareAccelerated() const; |
| 182 | |
| 183 | // By default, the state machine polls the reader once per second when it's |
| 184 | // in buffering mode. Some readers support a promise-based mechanism by which |
| 185 | // they notify the state machine when the data arrives. |
| 186 | bool IsWaitForDataSupported() const { return true; } |
| 187 | |
| 188 | RefPtr<WaitForDataPromise> WaitForData(MediaData::Type aType); |
| 189 | |
| 190 | // The MediaDecoderStateMachine uses various heuristics that assume that |
| 191 | // raw media data is arriving sequentially from a network channel. This |
| 192 | // makes sense in the <video src="foo"> case, but not for more advanced use |
| 193 | // cases like MSE. |
| 194 | bool UseBufferingHeuristics() const { return mTrackDemuxersMayBlock; } |
| 195 | |
| 196 | RefPtr<SetCDMPromise> SetCDMProxy(CDMProxy* aProxy); |
| 197 | |
| 198 | // Requests that the MediaFormatReader populates aInfo with debug information. |
| 199 | // This may be done asynchronously, and aInfo should *not* be accessed by the |
| 200 | // caller until the returned promise is resolved or rejected. |
| 201 | RefPtr<GenericPromise> RequestDebugInfo( |
| 202 | dom::MediaFormatReaderDebugInfo& aInfo); |
| 203 | |
| 204 | // Switch the video decoder to NullDecoderModule. It might takes effective |
| 205 | // since a few samples later depends on how much demuxed samples are already |
| 206 | // queued in the original video decoder. |
| 207 | void SetVideoNullDecode(bool aIsNullDecode); |
| 208 | |
| 209 | void UpdateCompositor(already_AddRefed<layers::KnowsCompositor>); |
| 210 | |
| 211 | void UpdateDuration(const media::TimeUnit& aDuration) { |
| 212 | MOZ_ASSERT(OnTaskQueue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(OnTaskQueue())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(OnTaskQueue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("OnTaskQueue()", "/root/firefox-clang/dom/media/MediaFormatReader.h", 212); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "OnTaskQueue()" ")"); do { MOZ_CrashSequence (__null, 212); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 213 | UpdateBuffered(); |
| 214 | } |
| 215 | |
| 216 | AbstractCanonical<media::TimeIntervals>* CanonicalBuffered() { |
| 217 | return &mBuffered; |
| 218 | } |
| 219 | |
| 220 | TaskQueue* OwnerThread() const { return mTaskQueue; } |
| 221 | |
| 222 | TimedMetadataEventSource& TimedMetadataEvent() { return mTimedMetadataEvent; } |
| 223 | |
| 224 | // Notified by the OggDemuxer during playback when chained ogg is detected. |
| 225 | MediaEventSource<void>& OnMediaNotSeekable() { return mOnMediaNotSeekable; } |
| 226 | |
| 227 | TimedMetadataEventProducer& TimedMetadataProducer() { |
| 228 | return mTimedMetadataEvent; |
| 229 | } |
| 230 | |
| 231 | MediaEventProducer<void>& MediaNotSeekableProducer() { |
| 232 | return mOnMediaNotSeekable; |
| 233 | } |
| 234 | |
| 235 | // Notified if the reader can't decode a sample due to a missing decryption |
| 236 | // key. |
| 237 | MediaEventSource<TrackInfo::TrackType>& OnTrackWaitingForKey() { |
| 238 | return mOnTrackWaitingForKey; |
| 239 | } |
| 240 | |
| 241 | MediaEventProducer<TrackInfo::TrackType>& OnTrackWaitingForKeyProducer() { |
| 242 | return mOnTrackWaitingForKey; |
| 243 | } |
| 244 | |
| 245 | MediaEventSource<nsTArray<uint8_t>, nsString>& OnEncrypted() { |
| 246 | return mOnEncrypted; |
| 247 | } |
| 248 | |
| 249 | MediaEventSource<void>& OnWaitingForKey() { return mOnWaitingForKey; } |
| 250 | |
| 251 | MediaEventSource<MediaResult>& OnDecodeWarning() { return mOnDecodeWarning; } |
| 252 | |
| 253 | MediaEventProducer<VideoInfo, AudioInfo>& OnTrackInfoUpdatedEvent() { |
| 254 | return mTrackInfoUpdatedEvent; |
| 255 | } |
| 256 | |
| 257 | template <typename T> |
| 258 | friend struct DDLoggedTypeTraits; // For DecoderData |
| 259 | |
| 260 | private: |
| 261 | bool HasVideo() const { return mVideo.mTrackDemuxer; } |
| 262 | bool HasAudio() const { return mAudio.mTrackDemuxer; } |
| 263 | |
| 264 | bool IsWaitingOnCDMResource(); |
| 265 | |
| 266 | bool InitDemuxer(); |
| 267 | // Notify the track demuxers that new data has been received. |
| 268 | void NotifyTrackDemuxers(); |
| 269 | void ReturnOutput(MediaData* aData, TrackType aTrack); |
| 270 | |
| 271 | // Enqueues a task to call Update(aTrack) on the decoder task queue. |
| 272 | // Lock for corresponding track must be held. |
| 273 | void ScheduleUpdate(TrackType aTrack); |
| 274 | void Update(TrackType aTrack); |
| 275 | // Handle actions should more data be received. |
| 276 | // Returns true if no more action is required. |
| 277 | bool UpdateReceivedNewData(TrackType aTrack); |
| 278 | // Called when new samples need to be demuxed. |
| 279 | void RequestDemuxSamples(TrackType aTrack); |
| 280 | // Handle demuxed samples by the input behavior. |
| 281 | void HandleDemuxedSamples(TrackType aTrack, |
| 282 | FrameStatistics::AutoNotifyDecoded& aA); |
| 283 | // Decode any pending already demuxed samples. |
| 284 | void DecodeDemuxedSamples(TrackType aTrack, MediaRawData* aSample); |
| 285 | |
| 286 | struct InternalSeekTarget { |
| 287 | InternalSeekTarget(const media::TimeInterval& aTime, bool aDropTarget) |
| 288 | : mTime(aTime), |
| 289 | mDropTarget(aDropTarget), |
| 290 | mWaiting(false), |
| 291 | mHasSeeked(false) {} |
| 292 | |
| 293 | media::TimeUnit Time() const { return mTime.mStart; } |
| 294 | media::TimeUnit EndTime() const { return mTime.mEnd; } |
| 295 | bool Contains(const media::TimeUnit& aTime) const { |
| 296 | return mTime.Contains(aTime); |
| 297 | } |
| 298 | |
| 299 | media::TimeInterval mTime; |
| 300 | bool mDropTarget; |
| 301 | // Whether known waiting for more raw packets, either for the random |
| 302 | // access point or dependent frames. |
| 303 | bool mWaiting; |
| 304 | // Whether `MediaTrackDemuxer::Seek()` has found the preceding random |
| 305 | // access point. |
| 306 | bool mHasSeeked; |
| 307 | }; |
| 308 | |
| 309 | // Perform an internal seek to aTime. If aDropTarget is true then |
| 310 | // the first sample past the target will be dropped. |
| 311 | void InternalSeek(TrackType aTrack, const InternalSeekTarget& aTarget); |
| 312 | // Return the end time of the internal seek target if it exists. Otherwise, |
| 313 | // return infinity. |
| 314 | media::TimeUnit GetInternalSeekTargetEndTime() const; |
| 315 | |
| 316 | // Drain the current decoder. |
| 317 | void DrainDecoder(TrackType aTrack); |
| 318 | void NotifyNewOutput(TrackType aTrack, |
| 319 | MediaDataDecoder::DecodedData&& aResults); |
| 320 | void NotifyError(TrackType aTrack, const MediaResult& aError); |
| 321 | void NotifyWaitingForData(TrackType aTrack); |
| 322 | void NotifyWaitingForKey(TrackType aTrack); |
| 323 | void NotifyEndOfStream(TrackType aTrack); |
| 324 | |
| 325 | void ExtractCryptoInitData(nsTArray<uint8_t>& aInitData); |
| 326 | |
| 327 | // Initializes mLayersBackendType if possible. |
| 328 | void InitLayersBackendType(); |
| 329 | |
| 330 | void Reset(TrackType aTrack); |
| 331 | void DropDecodedSamples(TrackType aTrack); |
| 332 | |
| 333 | // Return a target timeunit which the reader should skip to, this would be |
| 334 | // either the timethreshold we pass, or the time of the next keyframe. Return |
| 335 | // nothing if we don't need to skip. |
| 336 | // @param aTimeThreshold |
| 337 | // The time that we expect the time of next video frame should be or go beyond |
| 338 | // @param aRequestNextVideoKeyFrame |
| 339 | // If true and the next keyframe's time is larger than aTimeThreshold, skip to |
| 340 | // the next keyframe time instead of aTimeThreshold. |
| 341 | Maybe<media::TimeUnit> ShouldSkip(media::TimeUnit aTimeThreshold, |
| 342 | bool aRequestNextVideoKeyFrame); |
| 343 | |
| 344 | void SetVideoDecodeThreshold(); |
| 345 | |
| 346 | size_t SizeOfQueue(TrackType aTrack); |
| 347 | |
| 348 | void NotifyTrackInfoUpdated(); |
| 349 | |
| 350 | enum class DrainState { |
| 351 | None, |
| 352 | DrainRequested, |
| 353 | Draining, |
| 354 | PartialDrainPending, |
| 355 | DrainCompleted, |
| 356 | DrainAborted, |
| 357 | }; |
| 358 | |
| 359 | class SharedShutdownPromiseHolder : public MozPromiseHolder<ShutdownPromise> { |
| 360 | NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedShutdownPromiseHolder)public: MozExternalRefCountType AddRef(void) { static_assert( !std::is_destructible_v<SharedShutdownPromiseHolder>, "Reference-counted class " "SharedShutdownPromiseHolder" " should not have a public destructor. " "Make this class's destructor non-public"); do { static_assert ( mozilla::detail::AssertionConditionType<decltype(int32_t (mRefCnt) >= 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0" " (" "illegal refcnt" ")", "/root/firefox-clang/dom/media/MediaFormatReader.h" , 360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 360 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count ), ("SharedShutdownPromiseHolder"), (uint32_t)(sizeof(*this)) ); return (nsrefcnt)count; } MozExternalRefCountType Release( void) { do { static_assert( mozilla::detail::AssertionConditionType <decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0 ))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release" ")", "/root/firefox-clang/dom/media/MediaFormatReader.h" , 360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 360 ); __attribute__((nomerge)) ::abort(); } while (false); } } while (false); nsrefcnt count = --mRefCnt; NS_LogRelease((this), ( count), ("SharedShutdownPromiseHolder")); if (count == 0) { delete (this); return 0; } return count; } using HasThreadSafeRefCnt = std::true_type; protected: ::mozilla::ThreadSafeAutoRefCnt mRefCnt; public: |
| 361 | private: |
| 362 | ~SharedShutdownPromiseHolder() = default; |
| 363 | }; |
| 364 | |
| 365 | struct DecoderData { |
Excessive padding in 'struct mozilla::MediaFormatReader::DecoderData' (34 padding bytes, where 2 is optimal). Optimal fields order: mOwner, mTrackDemuxer, mTaskQueue, mDecoder, mDecodePerfRecorder, mSeekRequest, mQueuedSamples, mDemuxRequest, mWaitingPromise, mDecodeRequest, mShutdownPromise, mDrainRequest, mOutput, mNumSamplesInput, mNumSamplesOutput, mNumSamplesOutputTotal, mNumSamplesSkippedTotal, mSizeOfQueue, mOriginalInfo, mWorkingInfo, mInfo, mDescription, mProcessName, mCodecName, mWaitingForDataStartTime, mMeanRate, mFirstFrameTime, mLastTimeRangesEnd, mFirstDemuxedSampleTime, mError, mMutex, mLastDecodedSampleTime, mTimeThreshold, mTimeRanges, mDrainState, mNumOfConsecutiveDecodingError, mMaxConsecutiveDecodingError, mNumOfConsecutiveRDDOrGPUCrashes, mMaxConsecutiveRDDOrGPUCrashes, mNumOfConsecutiveUtilityCrashes, mMaxConsecutiveUtilityCrashes, mIsHardwareAccelerated, mLastStreamSourceID, mNextStreamSourceID, mType, mUpdateScheduled, mDemuxEOS, mWaitingForKey, mReceivedNewData, mFlushing, mFlushed, mIsNullDecode, mHardwareDecodingDisabled, mHasReportedVideoHardwareSupportTelemtry, consider reordering the fields or adding explicit padding members | |
| 366 | DecoderData(MediaFormatReader* aOwner, MediaData::Type aType, |
| 367 | uint32_t aNumOfMaxError) |
| 368 | : mOwner(aOwner), |
| 369 | mType(aType), |
| 370 | mMutex("DecoderData"), |
| 371 | mDescription("uninitialized"), |
| 372 | mProcessName(""), |
| 373 | mCodecName(""), |
| 374 | mUpdateScheduled(false), |
| 375 | mDemuxEOS(false), |
| 376 | mWaitingForDataStartTime(Nothing()), |
| 377 | mWaitingForKey(false), |
| 378 | mReceivedNewData(false), |
| 379 | mFlushing(false), |
| 380 | mFlushed(true), |
| 381 | mDrainState(DrainState::None), |
| 382 | mNumOfConsecutiveDecodingError(0), |
| 383 | mMaxConsecutiveDecodingError(aNumOfMaxError), |
| 384 | mNumOfConsecutiveRDDOrGPUCrashes(0), |
| 385 | mMaxConsecutiveRDDOrGPUCrashes( |
| 386 | StaticPrefs::media_rdd_process_max_crashes()), |
| 387 | mNumOfConsecutiveUtilityCrashes(0), |
| 388 | mMaxConsecutiveUtilityCrashes( |
| 389 | StaticPrefs::media_utility_process_max_crashes()), |
| 390 | mFirstFrameTime(Some(media::TimeUnit::Zero())), |
| 391 | mNumSamplesInput(0), |
| 392 | mNumSamplesOutput(0), |
| 393 | mNumSamplesOutputTotal(0), |
| 394 | mNumSamplesSkippedTotal(0), |
| 395 | mSizeOfQueue(0), |
| 396 | mIsHardwareAccelerated(false), |
| 397 | mLastStreamSourceID(UINT32_MAX(4294967295U)), |
| 398 | mIsNullDecode(false), |
| 399 | mHardwareDecodingDisabled(false) { |
| 400 | DecoderDoctorLogger::LogConstruction("MediaFormatReader::DecoderData", |
| 401 | this); |
| 402 | } |
| 403 | |
| 404 | ~DecoderData() { |
| 405 | DecoderDoctorLogger::LogDestruction("MediaFormatReader::DecoderData", |
| 406 | this); |
| 407 | } |
| 408 | |
| 409 | MediaFormatReader* mOwner; |
| 410 | // Disambiguate Audio vs Video. |
| 411 | MediaData::Type mType; |
| 412 | RefPtr<MediaTrackDemuxer> mTrackDemuxer; |
| 413 | // TaskQueue on which decoder can choose to decode. |
| 414 | // Only non-null up until the decoder is created. |
| 415 | RefPtr<TaskQueue> mTaskQueue; |
| 416 | |
| 417 | // Mutex protecting mDescription, mDecoder, mTrackDemuxer, mWorkingInfo, |
| 418 | // mProcessName and mCodecName as those can be read outside the TaskQueue. |
| 419 | // They are only written on the TaskQueue however, as such mMutex doesn't |
| 420 | // need to be held when those members are read on the TaskQueue. |
| 421 | Mutex mMutex MOZ_UNANNOTATED; |
| 422 | // The platform decoder. |
| 423 | RefPtr<MediaDataDecoder> mDecoder; |
| 424 | nsCString mDescription; |
| 425 | nsCString mProcessName; |
| 426 | nsCString mCodecName; |
| 427 | void ShutdownDecoder(); |
| 428 | |
| 429 | // Only accessed from reader's task queue. |
| 430 | bool mUpdateScheduled; |
| 431 | bool mDemuxEOS; |
| 432 | Maybe<TimeStamp> mWaitingForDataStartTime; |
| 433 | bool mWaitingForKey; |
| 434 | bool mReceivedNewData; |
| 435 | UniquePtr<PerformanceRecorderMulti<PlaybackStage>> mDecodePerfRecorder; |
| 436 | |
| 437 | // Pending seek. |
| 438 | MozPromiseRequestHolder<MediaTrackDemuxer::SeekPromise> mSeekRequest; |
| 439 | |
| 440 | // Queued demuxed samples waiting to be decoded. |
| 441 | nsTArray<RefPtr<MediaRawData>> mQueuedSamples; |
| 442 | MozPromiseRequestHolder<MediaTrackDemuxer::SamplesPromise> mDemuxRequest; |
| 443 | // A WaitingPromise is pending if the demuxer is waiting for data or |
| 444 | // if the decoder is waiting for a key. |
| 445 | MozPromiseHolder<WaitForDataPromise> mWaitingPromise; |
| 446 | bool HasWaitingPromise() const { |
| 447 | MOZ_ASSERT(mOwner->OnTaskQueue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mOwner->OnTaskQueue())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mOwner->OnTaskQueue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mOwner->OnTaskQueue()" , "/root/firefox-clang/dom/media/MediaFormatReader.h", 447); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { MOZ_CrashSequence (__null, 447); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 448 | return !mWaitingPromise.IsEmpty(); |
| 449 | } |
| 450 | |
| 451 | bool IsWaitingForData() const { |
| 452 | MOZ_ASSERT(mOwner->OnTaskQueue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mOwner->OnTaskQueue())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mOwner->OnTaskQueue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mOwner->OnTaskQueue()" , "/root/firefox-clang/dom/media/MediaFormatReader.h", 452); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { MOZ_CrashSequence (__null, 452); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 453 | return !!mWaitingForDataStartTime; |
| 454 | } |
| 455 | |
| 456 | bool IsWaitingForKey() const { |
| 457 | MOZ_ASSERT(mOwner->OnTaskQueue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mOwner->OnTaskQueue())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mOwner->OnTaskQueue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mOwner->OnTaskQueue()" , "/root/firefox-clang/dom/media/MediaFormatReader.h", 457); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { MOZ_CrashSequence (__null, 457); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 458 | return mWaitingForKey && mDecodeRequest.Exists(); |
| 459 | } |
| 460 | |
| 461 | // MediaDataDecoder handler's variables. |
| 462 | MozPromiseRequestHolder<MediaDataDecoder::DecodePromise> mDecodeRequest; |
| 463 | bool mFlushing; // True if flush is in action. |
| 464 | // Set to true if the last operation run on the decoder was a flush. |
| 465 | bool mFlushed; |
| 466 | RefPtr<SharedShutdownPromiseHolder> mShutdownPromise; |
| 467 | |
| 468 | MozPromiseRequestHolder<MediaDataDecoder::DecodePromise> mDrainRequest; |
| 469 | DrainState mDrainState; |
| 470 | bool HasPendingDrain() const { return mDrainState != DrainState::None; } |
| 471 | bool HasCompletedDrain() const { |
| 472 | return mDrainState == DrainState::DrainCompleted || |
| 473 | mDrainState == DrainState::DrainAborted; |
| 474 | } |
| 475 | void RequestDrain(); |
| 476 | |
| 477 | void StartRecordDecodingPerf(const TrackType aTrack, |
| 478 | const MediaRawData* aSample); |
| 479 | |
| 480 | // Track decoding error and fail when we hit the limit. |
| 481 | uint32_t mNumOfConsecutiveDecodingError; |
| 482 | uint32_t mMaxConsecutiveDecodingError; |
| 483 | |
| 484 | // Track RDD or GPU process crashes and fail when we hit the limit. |
| 485 | uint32_t mNumOfConsecutiveRDDOrGPUCrashes; |
| 486 | uint32_t mMaxConsecutiveRDDOrGPUCrashes; |
| 487 | |
| 488 | // Track Utility process crashes and fail when we hit the limit. |
| 489 | uint32_t mNumOfConsecutiveUtilityCrashes; |
| 490 | uint32_t mMaxConsecutiveUtilityCrashes; |
| 491 | |
| 492 | // Set when we haven't yet decoded the first frame. |
| 493 | // Cleared once the first frame has been decoded. |
| 494 | // This is used to determine, upon error, if we should try again to decode |
| 495 | // the frame, or skip to the next keyframe. |
| 496 | Maybe<media::TimeUnit> mFirstFrameTime; |
| 497 | |
| 498 | Maybe<MediaResult> mError; |
| 499 | bool HasFatalError() const { |
| 500 | if (!mError.isSome()) { |
| 501 | return false; |
| 502 | } |
| 503 | if (mError.ref() == NS_ERROR_DOM_MEDIA_DECODE_ERR) { |
| 504 | // Allow decode errors to be non-fatal, but give up |
| 505 | // if we have too many, or if warnings should be treated as errors. |
| 506 | return mNumOfConsecutiveDecodingError > mMaxConsecutiveDecodingError || |
| 507 | StaticPrefs::media_playback_warnings_as_errors(); |
| 508 | } |
| 509 | if (mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER) { |
| 510 | // If the caller asked for a new decoder we shouldn't treat |
| 511 | // it as fatal. |
| 512 | return false; |
| 513 | } |
| 514 | if (mError.ref() == NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_RDD_OR_GPU_ERR) { |
| 515 | // Allow RDD crashes to be non-fatal, but give up |
| 516 | // if we have too many, or if warnings should be treated as errors. |
| 517 | return mNumOfConsecutiveRDDOrGPUCrashes > |
| 518 | mMaxConsecutiveRDDOrGPUCrashes || |
| 519 | StaticPrefs::media_playback_warnings_as_errors(); |
| 520 | } |
| 521 | if (mError.ref() == NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_UTILITY_ERR) { |
| 522 | bool tooManyConsecutiveCrashes = |
| 523 | mNumOfConsecutiveUtilityCrashes > mMaxConsecutiveUtilityCrashes; |
| 524 | // TODO: Telemetry? |
| 525 | return tooManyConsecutiveCrashes || |
| 526 | StaticPrefs::media_playback_warnings_as_errors(); |
| 527 | } |
| 528 | if (mError.ref() == NS_ERROR_DOM_MEDIA_REMOTE_CRASHED_MF_CDM_ERR) { |
| 529 | return false; |
| 530 | } |
| 531 | // All other error types are fatal |
| 532 | return true; |
| 533 | } |
| 534 | |
| 535 | // If set, all decoded samples prior mTimeThreshold will be dropped. |
| 536 | // Used for internal seeking when a change of stream is detected or when |
| 537 | // encountering data discontinuity. |
| 538 | Maybe<InternalSeekTarget> mTimeThreshold; |
| 539 | // Time of last decoded sample returned. |
| 540 | Maybe<media::TimeInterval> mLastDecodedSampleTime; |
| 541 | |
| 542 | // Decoded samples returned my mDecoder awaiting being returned to |
| 543 | // state machine upon request. |
| 544 | nsTArray<RefPtr<MediaData>> mOutput; |
| 545 | uint64_t mNumSamplesInput; |
| 546 | uint64_t mNumSamplesOutput; |
| 547 | uint64_t mNumSamplesOutputTotal; |
| 548 | uint64_t mNumSamplesSkippedTotal; |
| 549 | |
| 550 | // These get overridden in the templated concrete class. |
| 551 | // Indicate if we have a pending promise for decoded frame. |
| 552 | // Rejecting the promise will stop the reader from decoding ahead. |
| 553 | virtual bool HasPromise() const = 0; |
| 554 | virtual void RejectPromise(const MediaResult& aError, |
| 555 | StaticString aMethodName) = 0; |
| 556 | |
| 557 | // Clear track demuxer related data. |
| 558 | void ResetDemuxer() { |
| 559 | mDemuxRequest.DisconnectIfExists(); |
| 560 | mSeekRequest.DisconnectIfExists(); |
| 561 | mTrackDemuxer->Reset(); |
| 562 | mQueuedSamples.Clear(); |
| 563 | } |
| 564 | |
| 565 | // Flush the decoder if present and reset decoding related data. |
| 566 | // Following a flush, the decoder is ready to accept any new data. |
| 567 | void Flush(); |
| 568 | |
| 569 | bool CancelWaitingForKey() { |
| 570 | if (!mWaitingForKey) { |
| 571 | return false; |
| 572 | } |
| 573 | mWaitingForKey = false; |
| 574 | if (IsWaitingForData() || !HasWaitingPromise()) { |
| 575 | return false; |
| 576 | } |
| 577 | mWaitingPromise.Resolve(mType, __func__); |
| 578 | return true; |
| 579 | } |
| 580 | |
| 581 | // Reset the state of the DecoderData, clearing all queued frames |
| 582 | // (pending demuxed and decoded). |
| 583 | // The track demuxer is *not* reset. |
| 584 | void ResetState() { |
| 585 | MOZ_ASSERT(mOwner->OnTaskQueue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mOwner->OnTaskQueue())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mOwner->OnTaskQueue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mOwner->OnTaskQueue()" , "/root/firefox-clang/dom/media/MediaFormatReader.h", 585); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { MOZ_CrashSequence (__null, 585); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 586 | mDemuxEOS = false; |
| 587 | mWaitingForDataStartTime.reset(); |
| 588 | mQueuedSamples.Clear(); |
| 589 | mDecodeRequest.DisconnectIfExists(); |
| 590 | mDrainRequest.DisconnectIfExists(); |
| 591 | mDrainState = DrainState::None; |
| 592 | CancelWaitingForKey(); |
| 593 | mTimeThreshold.reset(); |
| 594 | mLastDecodedSampleTime.reset(); |
| 595 | mOutput.Clear(); |
| 596 | mNumSamplesInput = 0; |
| 597 | mNumSamplesOutput = 0; |
| 598 | mSizeOfQueue = 0; |
| 599 | mNextStreamSourceID.reset(); |
| 600 | if (!HasFatalError()) { |
| 601 | mError.reset(); |
| 602 | } |
| 603 | } |
| 604 | |
| 605 | // Return whether an InternalSeek() has been requested but has not yet |
| 606 | // seeked to the random access point preceding that target. |
| 607 | bool HasInternalSeekPending() const { |
| 608 | return mTimeThreshold && !mTimeThreshold.ref().mHasSeeked; |
| 609 | } |
| 610 | |
| 611 | // Return the current TrackInfo in the stream. If the stream content never |
| 612 | // changed since AsyncReadMetadata was called then the TrackInfo used is |
| 613 | // mOriginalInfo, other it will be mInfo. The later case is only ever true |
| 614 | // with MSE or the WebMDemuxer. |
| 615 | const TrackInfo* GetCurrentInfo() const { |
| 616 | if (mInfo) { |
| 617 | return *mInfo; |
| 618 | } |
| 619 | return mOriginalInfo.get(); |
| 620 | } |
| 621 | // Return the current TrackInfo updated as per the decoder output. |
| 622 | // Typically for audio, the number of channels and/or sampling rate can vary |
| 623 | // between what was found in the metadata and what the decoder returned. |
| 624 | const TrackInfo* GetWorkingInfo() const { return mWorkingInfo.get(); } |
| 625 | bool IsEncrypted() const { return GetCurrentInfo()->mCrypto.IsEncrypted(); } |
| 626 | |
| 627 | // Used by the MDSM for logging purposes. |
| 628 | Atomic<size_t> mSizeOfQueue; |
| 629 | // Used by the MDSM to determine if video decoding is hardware accelerated. |
| 630 | // This value is updated after a frame is successfully decoded. |
| 631 | Atomic<bool> mIsHardwareAccelerated; |
| 632 | // Sample format monitoring. |
| 633 | uint32_t mLastStreamSourceID; |
| 634 | Maybe<uint32_t> mNextStreamSourceID; |
| 635 | media::TimeIntervals mTimeRanges; |
| 636 | Maybe<media::TimeUnit> mLastTimeRangesEnd; |
| 637 | // TrackInfo as first discovered during ReadMetadata. |
| 638 | UniquePtr<TrackInfo> mOriginalInfo; |
| 639 | // Written exclusively on the TaskQueue, can be read on MDSM's TaskQueue. |
| 640 | // Must be read with parent's mutex held. |
| 641 | UniquePtr<TrackInfo> mWorkingInfo; |
| 642 | RefPtr<TrackInfoSharedPtr> mInfo; |
| 643 | Maybe<media::TimeUnit> mFirstDemuxedSampleTime; |
| 644 | // Use NullDecoderModule or not. |
| 645 | bool mIsNullDecode; |
| 646 | bool mHardwareDecodingDisabled; |
| 647 | // Whether we have reported hardware decoding support for video. Used only |
| 648 | // on reader's task queue, |
| 649 | bool mHasReportedVideoHardwareSupportTelemtry = false; |
| 650 | |
| 651 | class { |
| 652 | public: |
| 653 | float Mean() const { return mMean; } |
| 654 | |
| 655 | void Update(const media::TimeUnit& aValue) { |
| 656 | if (aValue == media::TimeUnit::Zero()) { |
| 657 | return; |
| 658 | } |
| 659 | mMean += static_cast<float>((1.0f / aValue.ToSeconds() - mMean) / |
| 660 | static_cast<double>(++mCount)); |
| 661 | } |
| 662 | |
| 663 | void Reset() { |
| 664 | mMean = 0; |
| 665 | mCount = 0; |
| 666 | } |
| 667 | |
| 668 | private: |
| 669 | float mMean = 0; |
| 670 | uint64_t mCount = 0; |
| 671 | } mMeanRate; |
| 672 | }; |
| 673 | |
| 674 | template <typename Type> |
| 675 | class DecoderDataWithPromise : public DecoderData { |
| 676 | public: |
| 677 | DecoderDataWithPromise(MediaFormatReader* aOwner, MediaData::Type aType, |
| 678 | uint32_t aNumOfMaxError) |
| 679 | : DecoderData(aOwner, aType, aNumOfMaxError), mHasPromise(false) { |
| 680 | DecoderDoctorLogger::LogConstructionAndBase( |
| 681 | "MediaFormatReader::DecoderDataWithPromise", this, |
| 682 | "MediaFormatReader::DecoderData", |
| 683 | static_cast<const MediaFormatReader::DecoderData*>(this)); |
| 684 | } |
| 685 | |
| 686 | ~DecoderDataWithPromise() { |
| 687 | DecoderDoctorLogger::LogDestruction( |
| 688 | "MediaFormatReader::DecoderDataWithPromise", this); |
| 689 | } |
| 690 | |
| 691 | bool HasPromise() const override { return mHasPromise; } |
| 692 | |
| 693 | RefPtr<DataPromise<Type>> EnsurePromise(StaticString aMethodName) { |
| 694 | MOZ_ASSERT(mOwner->OnTaskQueue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mOwner->OnTaskQueue())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mOwner->OnTaskQueue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mOwner->OnTaskQueue()" , "/root/firefox-clang/dom/media/MediaFormatReader.h", 694); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { MOZ_CrashSequence (__null, 694); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 695 | mHasPromise = true; |
| 696 | return mPromise.Ensure(aMethodName); |
| 697 | } |
| 698 | |
| 699 | void ResolvePromise(Type* aData, StaticString aMethodName) { |
| 700 | MOZ_ASSERT(mOwner->OnTaskQueue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mOwner->OnTaskQueue())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mOwner->OnTaskQueue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mOwner->OnTaskQueue()" , "/root/firefox-clang/dom/media/MediaFormatReader.h", 700); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { MOZ_CrashSequence (__null, 700); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 701 | mPromise.Resolve(aData, aMethodName); |
| 702 | mHasPromise = false; |
| 703 | } |
| 704 | |
| 705 | void RejectPromise(const MediaResult& aError, |
| 706 | StaticString aMethodName) override { |
| 707 | MOZ_ASSERT(mOwner->OnTaskQueue())do { static_assert( mozilla::detail::AssertionConditionType< decltype(mOwner->OnTaskQueue())>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mOwner->OnTaskQueue()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mOwner->OnTaskQueue()" , "/root/firefox-clang/dom/media/MediaFormatReader.h", 707); AnnotateMozCrashReason ("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { MOZ_CrashSequence (__null, 707); __attribute__((nomerge)) ::abort(); } while (false ); } } while (false); |
| 708 | mPromise.Reject(aError, aMethodName); |
| 709 | mHasPromise = false; |
| 710 | } |
| 711 | |
| 712 | private: |
| 713 | MozPromiseHolder<DataPromise<Type>> mPromise; |
| 714 | Atomic<bool> mHasPromise; |
| 715 | }; |
| 716 | |
| 717 | // Decode task queue. |
| 718 | RefPtr<TaskQueue> mTaskQueue; |
| 719 | |
| 720 | DecoderDataWithPromise<AudioData> mAudio; |
| 721 | DecoderDataWithPromise<VideoData> mVideo; |
| 722 | |
| 723 | Watchable<bool> mWorkingInfoChanged; |
| 724 | WatchManager<MediaFormatReader> mWatchManager; |
| 725 | bool mIsWatchingWorkingInfo; |
| 726 | |
| 727 | // Returns true when the decoder for this track needs input. |
| 728 | bool NeedInput(DecoderData& aDecoder); |
| 729 | |
| 730 | DecoderData& GetDecoderData(TrackType aTrack); |
| 731 | |
| 732 | // Demuxer objects. |
| 733 | class DemuxerProxy; |
| 734 | UniquePtr<DemuxerProxy> mDemuxer; |
| 735 | bool mDemuxerInitDone; |
| 736 | void OnDemuxerInitDone(const MediaResult& aResult); |
| 737 | void OnDemuxerInitFailed(const MediaResult& aError); |
| 738 | MozPromiseRequestHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest; |
| 739 | MozPromiseRequestHolder<NotifyDataArrivedPromise> mNotifyDataArrivedPromise; |
| 740 | bool mPendingNotifyDataArrived; |
| 741 | void OnDemuxFailed(TrackType aTrack, const MediaResult& aError); |
| 742 | |
| 743 | void DoDemuxVideo(); |
| 744 | void OnVideoDemuxCompleted( |
| 745 | const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples); |
| 746 | void OnVideoDemuxFailed(const MediaResult& aError) { |
| 747 | OnDemuxFailed(TrackType::kVideoTrack, aError); |
| 748 | } |
| 749 | |
| 750 | void DoDemuxAudio(); |
| 751 | void OnAudioDemuxCompleted( |
| 752 | const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples); |
| 753 | void OnAudioDemuxFailed(const MediaResult& aError) { |
| 754 | OnDemuxFailed(TrackType::kAudioTrack, aError); |
| 755 | } |
| 756 | |
| 757 | void SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold); |
| 758 | MozPromiseRequestHolder<MediaTrackDemuxer::SkipAccessPointPromise> |
| 759 | mSkipRequest; |
| 760 | void VideoSkipReset(uint32_t aSkipped); |
| 761 | void OnVideoSkipCompleted(uint32_t aSkipped); |
| 762 | void OnVideoSkipFailed(MediaTrackDemuxer::SkipFailureHolder aFailure); |
| 763 | |
| 764 | // The last number of decoded output frames that we've reported to |
| 765 | // MediaDecoder::NotifyDecoded(). We diff the number of output video |
| 766 | // frames every time that DecodeVideoData() is called, and report the |
| 767 | // delta there. |
| 768 | uint64_t mLastReportedNumDecodedFrames; |
| 769 | |
| 770 | // Timestamp of the previous decoded video keyframe, in microseconds. |
| 771 | int64_t mPreviousDecodedKeyframeTime_us; |
| 772 | // Default mLastDecodedKeyframeTime_us value, must be bigger than anything. |
| 773 | static const int64_t sNoPreviousDecodedKeyframe = INT64_MAX(9223372036854775807L); |
| 774 | |
| 775 | RefPtr<layers::KnowsCompositor> mKnowsCompositor; |
| 776 | |
| 777 | // Metadata objects |
| 778 | // True if we've read the streams' metadata. |
| 779 | bool mInitDone; |
| 780 | MozPromiseHolder<MetadataPromise> mMetadataPromise; |
| 781 | bool IsEncrypted() const; |
| 782 | |
| 783 | // Set to true if any of our track buffers may be blocking. |
| 784 | bool mTrackDemuxersMayBlock; |
| 785 | |
| 786 | // Seeking objects. |
| 787 | void SetSeekTarget(const SeekTarget& aTarget); |
| 788 | bool IsSeeking() const { return mPendingSeekTime.isSome(); } |
| 789 | bool IsVideoOnlySeeking() const { |
| 790 | return IsSeeking() && mOriginalSeekTarget.IsVideoOnly(); |
| 791 | } |
| 792 | bool IsAudioOnlySeeking() const { |
| 793 | return IsSeeking() && mOriginalSeekTarget.IsAudioOnly(); |
| 794 | } |
| 795 | void ScheduleSeek(); |
| 796 | void AttemptSeek(); |
| 797 | void OnSeekFailed(TrackType aTrack, const MediaResult& aError); |
| 798 | void DoVideoSeek(); |
| 799 | void OnVideoSeekCompleted(media::TimeUnit aTime); |
| 800 | void OnVideoSeekFailed(const MediaResult& aError); |
| 801 | bool mSeekScheduled; |
| 802 | |
| 803 | void DoAudioSeek(); |
| 804 | void OnAudioSeekCompleted(media::TimeUnit aTime); |
| 805 | void OnAudioSeekFailed(const MediaResult& aError); |
| 806 | // The SeekTarget that was last given to Seek() |
| 807 | SeekTarget mOriginalSeekTarget; |
| 808 | // Temporary seek information while we wait for the data |
| 809 | Maybe<media::TimeUnit> mFallbackSeekTime; |
| 810 | Maybe<media::TimeUnit> mPendingSeekTime; |
| 811 | MozPromiseHolder<SeekPromise> mSeekPromise; |
| 812 | |
| 813 | RefPtr<VideoFrameContainer> mVideoFrameContainer; |
| 814 | layers::ImageContainer* GetImageContainer(); |
| 815 | |
| 816 | RefPtr<CDMProxy> mCDMProxy; |
| 817 | |
| 818 | RefPtr<GMPCrashHelper> mCrashHelper; |
| 819 | |
| 820 | void SetNullDecode(TrackType aTrack, bool aIsNullDecode); |
| 821 | |
| 822 | class DecoderFactory; |
| 823 | UniquePtr<DecoderFactory> mDecoderFactory; |
| 824 | |
| 825 | class ShutdownPromisePool; |
| 826 | UniquePtr<ShutdownPromisePool> mShutdownPromisePool; |
| 827 | |
| 828 | MediaEventListener mOnTrackWaitingForKeyListener; |
| 829 | |
| 830 | void OnFirstDemuxCompleted( |
| 831 | TrackInfo::TrackType aType, |
| 832 | const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples); |
| 833 | |
| 834 | void OnFirstDemuxFailed(TrackInfo::TrackType aType, |
| 835 | const MediaResult& aError); |
| 836 | |
| 837 | void MaybeResolveMetadataPromise(); |
| 838 | |
| 839 | // Stores presentation info required for playback. |
| 840 | MediaInfo mInfo; |
| 841 | |
| 842 | UniquePtr<MetadataTags> mTags; |
| 843 | |
| 844 | // A flag indicating if the start time is known or not. |
| 845 | bool mHasStartTime = false; |
| 846 | |
| 847 | void ShutdownDecoder(TrackType aTrack); |
| 848 | RefPtr<ShutdownPromise> TearDownDecoders(); |
| 849 | |
| 850 | bool mShutdown = false; |
| 851 | |
| 852 | // Buffered range. |
| 853 | Canonical<media::TimeIntervals> mBuffered; |
| 854 | |
| 855 | // Used to send TimedMetadata to the listener. |
| 856 | TimedMetadataEventProducer mTimedMetadataEvent; |
| 857 | |
| 858 | // Notify if this media is not seekable. |
| 859 | MediaEventProducer<void> mOnMediaNotSeekable; |
| 860 | |
| 861 | // Notify if we are waiting for a decryption key. |
| 862 | MediaEventProducer<TrackInfo::TrackType> mOnTrackWaitingForKey; |
| 863 | |
| 864 | MediaEventProducer<nsTArray<uint8_t>, nsString> mOnEncrypted; |
| 865 | |
| 866 | MediaEventProducer<void> mOnWaitingForKey; |
| 867 | |
| 868 | MediaEventProducer<MediaResult> mOnDecodeWarning; |
| 869 | |
| 870 | MediaEventProducer<VideoInfo, AudioInfo> mTrackInfoUpdatedEvent; |
| 871 | |
| 872 | RefPtr<FrameStatistics> mFrameStats; |
| 873 | |
| 874 | // Used in bug 1393399 for telemetry. |
| 875 | const MediaDecoderOwnerID mMediaDecoderOwnerID; |
| 876 | |
| 877 | bool ResolveSetCDMPromiseIfDone(TrackType aTrack); |
| 878 | void PrepareToSetCDMForTrack(TrackType aTrack); |
| 879 | MozPromiseHolder<SetCDMPromise> mSetCDMPromise; |
| 880 | TrackSet mSetCDMForTracks{}; |
| 881 | bool IsDecoderWaitingForCDM(TrackType aTrack); |
| 882 | |
| 883 | void GetDebugInfo(dom::MediaFormatReaderDebugInfo& aInfo); |
| 884 | |
| 885 | // Only be used on Windows when the media engine playback is enabled. |
| 886 | Maybe<uint64_t> mMediaEngineId; |
| 887 | |
| 888 | const Maybe<TrackingId> mTrackingId; |
| 889 | |
| 890 | // The start time of reading the metdata and how long does it take. This |
| 891 | // measurement includes the time of downloading media resource over the |
| 892 | // internet. |
| 893 | Maybe<TimeStamp> mReadMetadataStartTime; |
| 894 | TimeDuration mReadMetaDataTime; |
| 895 | |
| 896 | // The total amount of time we have been waiting for the video data due to |
| 897 | // lacking of data. |
| 898 | TimeDuration mTotalWaitingForVideoDataTime; |
| 899 | |
| 900 | // https://github.com/w3c/encrypted-media/issues/251#issuecomment-819783073 |
| 901 | // Treat playback as encrypted if the media key is set before playback starts, |
| 902 | // this allows websites to start with non-encrypted stream and switch to |
| 903 | // encrypted stream later. |
| 904 | Atomic<bool> mEncryptedCustomIdent; |
| 905 | }; |
| 906 | |
| 907 | DDLoggedTypeCustomName(MediaFormatReader::DecoderData, DecoderData)template <> struct DDLoggedTypeTraits<MediaFormatReader ::DecoderData> { using Type = MediaFormatReader::DecoderData ; static constexpr const char* Name() { return "DecoderData"; } using HasBase = std::false_type; using BaseType = MediaFormatReader ::DecoderData; static constexpr const char* BaseTypeName() { return ""; } }; |
| 908 | |
| 909 | } // namespace mozilla |
| 910 | |
| 911 | #endif |