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