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 |