File: | var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h |
Warning: | line 371, 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()", "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 212); AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnTaskQueue()" ")"); do { *((volatile int*)__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 | MediaEventSource<VideoInfo>& OnStoreDecoderBenchmark() { |
254 | return mOnStoreDecoderBenchmark; |
255 | } |
256 | |
257 | MediaEventProducer<VideoInfo, AudioInfo>& OnTrackInfoUpdatedEvent() { |
258 | return mTrackInfoUpdatedEvent; |
259 | } |
260 | |
261 | private: |
262 | bool HasVideo() const { return mVideo.mTrackDemuxer; } |
263 | bool HasAudio() const { return mAudio.mTrackDemuxer; } |
264 | |
265 | bool IsWaitingOnCDMResource(); |
266 | |
267 | bool InitDemuxer(); |
268 | // Notify the track demuxers that new data has been received. |
269 | void NotifyTrackDemuxers(); |
270 | void ReturnOutput(MediaData* aData, TrackType aTrack); |
271 | |
272 | // Enqueues a task to call Update(aTrack) on the decoder task queue. |
273 | // Lock for corresponding track must be held. |
274 | void ScheduleUpdate(TrackType aTrack); |
275 | void Update(TrackType aTrack); |
276 | // Handle actions should more data be received. |
277 | // Returns true if no more action is required. |
278 | bool UpdateReceivedNewData(TrackType aTrack); |
279 | // Called when new samples need to be demuxed. |
280 | void RequestDemuxSamples(TrackType aTrack); |
281 | // Handle demuxed samples by the input behavior. |
282 | void HandleDemuxedSamples(TrackType aTrack, |
283 | FrameStatistics::AutoNotifyDecoded& aA); |
284 | // Decode any pending already demuxed samples. |
285 | void DecodeDemuxedSamples(TrackType aTrack, MediaRawData* aSample); |
286 | |
287 | struct InternalSeekTarget { |
288 | InternalSeekTarget(const media::TimeInterval& aTime, bool aDropTarget) |
289 | : mTime(aTime), |
290 | mDropTarget(aDropTarget), |
291 | mWaiting(false), |
292 | mHasSeeked(false) {} |
293 | |
294 | media::TimeUnit Time() const { return mTime.mStart; } |
295 | media::TimeUnit EndTime() const { return mTime.mEnd; } |
296 | bool Contains(const media::TimeUnit& aTime) const { |
297 | return mTime.Contains(aTime); |
298 | } |
299 | |
300 | media::TimeInterval mTime; |
301 | bool mDropTarget; |
302 | // Whether known waiting for more raw packets, either for the random |
303 | // access point or dependent frames. |
304 | bool mWaiting; |
305 | // Whether `MediaTrackDemuxer::Seek()` has found the preceding random |
306 | // access point. |
307 | bool mHasSeeked; |
308 | }; |
309 | |
310 | // Perform an internal seek to aTime. If aDropTarget is true then |
311 | // the first sample past the target will be dropped. |
312 | void InternalSeek(TrackType aTrack, const InternalSeekTarget& aTarget); |
313 | // Return the end time of the internal seek target if it exists. Otherwise, |
314 | // return infinity. |
315 | media::TimeUnit GetInternalSeekTargetEndTime() const; |
316 | |
317 | // Drain the current decoder. |
318 | void DrainDecoder(TrackType aTrack); |
319 | void NotifyNewOutput(TrackType aTrack, |
320 | MediaDataDecoder::DecodedData&& aResults); |
321 | void NotifyError(TrackType aTrack, const MediaResult& aError); |
322 | void NotifyWaitingForData(TrackType aTrack); |
323 | void NotifyWaitingForKey(TrackType aTrack); |
324 | void NotifyEndOfStream(TrackType aTrack); |
325 | |
326 | void ExtractCryptoInitData(nsTArray<uint8_t>& aInitData); |
327 | |
328 | // Initializes mLayersBackendType if possible. |
329 | void InitLayersBackendType(); |
330 | |
331 | void Reset(TrackType aTrack); |
332 | void DropDecodedSamples(TrackType aTrack); |
333 | |
334 | // Return a target timeunit which the reader should skip to, this would be |
335 | // either the timethreshold we pass, or the time of the next keyframe. Return |
336 | // nothing if we don't need to skip. |
337 | // @param aTimeThreshold |
338 | // The time that we expect the time of next video frame should be or go beyond |
339 | // @param aRequestNextVideoKeyFrame |
340 | // If true and the next keyframe's time is larger than aTimeThreshold, skip to |
341 | // the next keyframe time instead of aTimeThreshold. |
342 | Maybe<media::TimeUnit> ShouldSkip(media::TimeUnit aTimeThreshold, |
343 | bool aRequestNextVideoKeyFrame); |
344 | |
345 | void SetVideoDecodeThreshold(); |
346 | |
347 | size_t SizeOfQueue(TrackType aTrack); |
348 | |
349 | // Fire a new OnStoreDecoderBenchmark event that will create new |
350 | // storage of the decoder benchmark. |
351 | // This is called only on TaskQueue. |
352 | void NotifyDecoderBenchmarkStore(); |
353 | |
354 | void NotifyTrackInfoUpdated(); |
355 | |
356 | enum class DrainState { |
357 | None, |
358 | DrainRequested, |
359 | Draining, |
360 | PartialDrainPending, |
361 | DrainCompleted, |
362 | DrainAborted, |
363 | }; |
364 | |
365 | class SharedShutdownPromiseHolder : public MozPromiseHolder<ShutdownPromise> { |
366 | 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" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 366); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0" ") (" "illegal refcnt" ")"); do { *((volatile int*)__null) = 366; __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" ")", "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 366); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release" ")"); do { *((volatile int*)__null) = 366 ; __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: |
367 | private: |
368 | ~SharedShutdownPromiseHolder() = default; |
369 | }; |
370 | |
371 | 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 | |
372 | DecoderData(MediaFormatReader* aOwner, MediaData::Type aType, |
373 | uint32_t aNumOfMaxError) |
374 | : mOwner(aOwner), |
375 | mType(aType), |
376 | mMutex("DecoderData"), |
377 | mDescription("uninitialized"), |
378 | mProcessName(""), |
379 | mCodecName(""), |
380 | mUpdateScheduled(false), |
381 | mDemuxEOS(false), |
382 | mWaitingForDataStartTime(Nothing()), |
383 | mWaitingForKey(false), |
384 | mReceivedNewData(false), |
385 | mFlushing(false), |
386 | mFlushed(true), |
387 | mDrainState(DrainState::None), |
388 | mNumOfConsecutiveDecodingError(0), |
389 | mMaxConsecutiveDecodingError(aNumOfMaxError), |
390 | mNumOfConsecutiveRDDOrGPUCrashes(0), |
391 | mMaxConsecutiveRDDOrGPUCrashes( |
392 | StaticPrefs::media_rdd_process_max_crashes()), |
393 | mNumOfConsecutiveUtilityCrashes(0), |
394 | mMaxConsecutiveUtilityCrashes( |
395 | StaticPrefs::media_utility_process_max_crashes()), |
396 | mFirstFrameTime(Some(media::TimeUnit::Zero())), |
397 | mNumSamplesInput(0), |
398 | mNumSamplesOutput(0), |
399 | mNumSamplesOutputTotal(0), |
400 | mNumSamplesSkippedTotal(0), |
401 | mSizeOfQueue(0), |
402 | mIsHardwareAccelerated(false), |
403 | mLastStreamSourceID(UINT32_MAX(4294967295U)), |
404 | mIsNullDecode(false), |
405 | mHardwareDecodingDisabled(false) { |
406 | DecoderDoctorLogger::LogConstruction("MediaFormatReader::DecoderData", |
407 | this); |
408 | } |
409 | |
410 | ~DecoderData() { |
411 | DecoderDoctorLogger::LogDestruction("MediaFormatReader::DecoderData", |
412 | this); |
413 | } |
414 | |
415 | MediaFormatReader* mOwner; |
416 | // Disambiguate Audio vs Video. |
417 | MediaData::Type mType; |
418 | RefPtr<MediaTrackDemuxer> mTrackDemuxer; |
419 | // TaskQueue on which decoder can choose to decode. |
420 | // Only non-null up until the decoder is created. |
421 | RefPtr<TaskQueue> mTaskQueue; |
422 | |
423 | // Mutex protecting mDescription, mDecoder, mTrackDemuxer, mWorkingInfo, |
424 | // mProcessName and mCodecName as those can be read outside the TaskQueue. |
425 | // They are only written on the TaskQueue however, as such mMutex doesn't |
426 | // need to be held when those members are read on the TaskQueue. |
427 | Mutex mMutex MOZ_UNANNOTATED; |
428 | // The platform decoder. |
429 | RefPtr<MediaDataDecoder> mDecoder; |
430 | nsCString mDescription; |
431 | nsCString mProcessName; |
432 | nsCString mCodecName; |
433 | void ShutdownDecoder(); |
434 | |
435 | // Only accessed from reader's task queue. |
436 | bool mUpdateScheduled; |
437 | bool mDemuxEOS; |
438 | Maybe<TimeStamp> mWaitingForDataStartTime; |
439 | bool mWaitingForKey; |
440 | bool mReceivedNewData; |
441 | UniquePtr<PerformanceRecorderMulti<PlaybackStage>> mDecodePerfRecorder; |
442 | |
443 | // Pending seek. |
444 | MozPromiseRequestHolder<MediaTrackDemuxer::SeekPromise> mSeekRequest; |
445 | |
446 | // Queued demuxed samples waiting to be decoded. |
447 | nsTArray<RefPtr<MediaRawData>> mQueuedSamples; |
448 | MozPromiseRequestHolder<MediaTrackDemuxer::SamplesPromise> mDemuxRequest; |
449 | // A WaitingPromise is pending if the demuxer is waiting for data or |
450 | // if the decoder is waiting for a key. |
451 | MozPromiseHolder<WaitForDataPromise> mWaitingPromise; |
452 | bool HasWaitingPromise() const { |
453 | 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()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 453); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { *((volatile int*)__null) = 453; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
454 | return !mWaitingPromise.IsEmpty(); |
455 | } |
456 | |
457 | bool IsWaitingForData() const { |
458 | 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()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 458); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { *((volatile int*)__null) = 458; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
459 | return !!mWaitingForDataStartTime; |
460 | } |
461 | |
462 | bool IsWaitingForKey() const { |
463 | 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()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 463); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { *((volatile int*)__null) = 463; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
464 | return mWaitingForKey && mDecodeRequest.Exists(); |
465 | } |
466 | |
467 | // MediaDataDecoder handler's variables. |
468 | MozPromiseRequestHolder<MediaDataDecoder::DecodePromise> mDecodeRequest; |
469 | bool mFlushing; // True if flush is in action. |
470 | // Set to true if the last operation run on the decoder was a flush. |
471 | bool mFlushed; |
472 | RefPtr<SharedShutdownPromiseHolder> mShutdownPromise; |
473 | |
474 | MozPromiseRequestHolder<MediaDataDecoder::DecodePromise> mDrainRequest; |
475 | DrainState mDrainState; |
476 | bool HasPendingDrain() const { return mDrainState != DrainState::None; } |
477 | bool HasCompletedDrain() const { |
478 | return mDrainState == DrainState::DrainCompleted || |
479 | mDrainState == DrainState::DrainAborted; |
480 | } |
481 | void RequestDrain() { |
482 | MOZ_RELEASE_ASSERT(mDrainState == DrainState::None)do { static_assert( mozilla::detail::AssertionConditionType< decltype(mDrainState == DrainState::None)>::isValid, "invalid assertion condition" ); if ((__builtin_expect(!!(!(!!(mDrainState == DrainState::None ))), 0))) { do { } while (false); MOZ_ReportAssertionFailure( "mDrainState == DrainState::None", "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 482); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "mDrainState == DrainState::None" ")"); do { *((volatile int*)__null) = 482; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
483 | mDrainState = DrainState::DrainRequested; |
484 | } |
485 | |
486 | void StartRecordDecodingPerf(const TrackType aTrack, |
487 | const MediaRawData* aSample); |
488 | |
489 | // Track decoding error and fail when we hit the limit. |
490 | uint32_t mNumOfConsecutiveDecodingError; |
491 | uint32_t mMaxConsecutiveDecodingError; |
492 | |
493 | // Track RDD or GPU process crashes and fail when we hit the limit. |
494 | uint32_t mNumOfConsecutiveRDDOrGPUCrashes; |
495 | uint32_t mMaxConsecutiveRDDOrGPUCrashes; |
496 | |
497 | // Track Utility process crashes and fail when we hit the limit. |
498 | uint32_t mNumOfConsecutiveUtilityCrashes; |
499 | uint32_t mMaxConsecutiveUtilityCrashes; |
500 | |
501 | // Set when we haven't yet decoded the first frame. |
502 | // Cleared once the first frame has been decoded. |
503 | // This is used to determine, upon error, if we should try again to decode |
504 | // the frame, or skip to the next keyframe. |
505 | Maybe<media::TimeUnit> mFirstFrameTime; |
506 | |
507 | Maybe<MediaResult> mError; |
508 | bool HasFatalError() const { |
509 | if (!mError.isSome()) { |
510 | return false; |
511 | } |
512 | if (mError.ref() == NS_ERROR_DOM_MEDIA_DECODE_ERR) { |
513 | // Allow decode errors to be non-fatal, but give up |
514 | // if we have too many, or if warnings should be treated as errors. |
515 | return mNumOfConsecutiveDecodingError > mMaxConsecutiveDecodingError || |
516 | StaticPrefs::media_playback_warnings_as_errors(); |
517 | } |
518 | if (mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER) { |
519 | // If the caller asked for a new decoder we shouldn't treat |
520 | // it as fatal. |
521 | return false; |
522 | } |
523 | if (mError.ref() == |
524 | NS_ERROR_DOM_MEDIA_REMOTE_DECODER_CRASHED_RDD_OR_GPU_ERR) { |
525 | // Allow RDD crashes to be non-fatal, but give up |
526 | // if we have too many, or if warnings should be treated as errors. |
527 | return mNumOfConsecutiveRDDOrGPUCrashes > |
528 | mMaxConsecutiveRDDOrGPUCrashes || |
529 | StaticPrefs::media_playback_warnings_as_errors(); |
530 | } |
531 | if (mError.ref() == |
532 | NS_ERROR_DOM_MEDIA_REMOTE_DECODER_CRASHED_UTILITY_ERR) { |
533 | bool tooManyConsecutiveCrashes = |
534 | mNumOfConsecutiveUtilityCrashes > mMaxConsecutiveUtilityCrashes; |
535 | // TODO: Telemetry? |
536 | return tooManyConsecutiveCrashes || |
537 | StaticPrefs::media_playback_warnings_as_errors(); |
538 | } |
539 | if (mError.ref() == |
540 | NS_ERROR_DOM_MEDIA_REMOTE_DECODER_CRASHED_MF_CDM_ERR) { |
541 | return false; |
542 | } |
543 | // All other error types are fatal |
544 | return true; |
545 | } |
546 | |
547 | // If set, all decoded samples prior mTimeThreshold will be dropped. |
548 | // Used for internal seeking when a change of stream is detected or when |
549 | // encountering data discontinuity. |
550 | Maybe<InternalSeekTarget> mTimeThreshold; |
551 | // Time of last decoded sample returned. |
552 | Maybe<media::TimeInterval> mLastDecodedSampleTime; |
553 | |
554 | // Decoded samples returned my mDecoder awaiting being returned to |
555 | // state machine upon request. |
556 | nsTArray<RefPtr<MediaData>> mOutput; |
557 | uint64_t mNumSamplesInput; |
558 | uint64_t mNumSamplesOutput; |
559 | uint64_t mNumSamplesOutputTotal; |
560 | uint64_t mNumSamplesSkippedTotal; |
561 | |
562 | // These get overridden in the templated concrete class. |
563 | // Indicate if we have a pending promise for decoded frame. |
564 | // Rejecting the promise will stop the reader from decoding ahead. |
565 | virtual bool HasPromise() const = 0; |
566 | virtual void RejectPromise(const MediaResult& aError, |
567 | StaticString aMethodName) = 0; |
568 | |
569 | // Clear track demuxer related data. |
570 | void ResetDemuxer() { |
571 | mDemuxRequest.DisconnectIfExists(); |
572 | mSeekRequest.DisconnectIfExists(); |
573 | mTrackDemuxer->Reset(); |
574 | mQueuedSamples.Clear(); |
575 | } |
576 | |
577 | // Flush the decoder if present and reset decoding related data. |
578 | // Following a flush, the decoder is ready to accept any new data. |
579 | void Flush(); |
580 | |
581 | bool CancelWaitingForKey() { |
582 | if (!mWaitingForKey) { |
583 | return false; |
584 | } |
585 | mWaitingForKey = false; |
586 | if (IsWaitingForData() || !HasWaitingPromise()) { |
587 | return false; |
588 | } |
589 | mWaitingPromise.Resolve(mType, __func__); |
590 | return true; |
591 | } |
592 | |
593 | // Reset the state of the DecoderData, clearing all queued frames |
594 | // (pending demuxed and decoded). |
595 | // The track demuxer is *not* reset. |
596 | void ResetState() { |
597 | 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()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 597); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { *((volatile int*)__null) = 597; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
598 | mDemuxEOS = false; |
599 | mWaitingForDataStartTime.reset(); |
600 | mQueuedSamples.Clear(); |
601 | mDecodeRequest.DisconnectIfExists(); |
602 | mDrainRequest.DisconnectIfExists(); |
603 | mDrainState = DrainState::None; |
604 | CancelWaitingForKey(); |
605 | mTimeThreshold.reset(); |
606 | mLastDecodedSampleTime.reset(); |
607 | mOutput.Clear(); |
608 | mNumSamplesInput = 0; |
609 | mNumSamplesOutput = 0; |
610 | mSizeOfQueue = 0; |
611 | mNextStreamSourceID.reset(); |
612 | if (!HasFatalError()) { |
613 | mError.reset(); |
614 | } |
615 | } |
616 | |
617 | // Return whether an InternalSeek() has been requested but has not yet |
618 | // seeked to the random access point preceding that target. |
619 | bool HasInternalSeekPending() const { |
620 | return mTimeThreshold && !mTimeThreshold.ref().mHasSeeked; |
621 | } |
622 | |
623 | // Return the current TrackInfo in the stream. If the stream content never |
624 | // changed since AsyncReadMetadata was called then the TrackInfo used is |
625 | // mOriginalInfo, other it will be mInfo. The later case is only ever true |
626 | // with MSE or the WebMDemuxer. |
627 | const TrackInfo* GetCurrentInfo() const { |
628 | if (mInfo) { |
629 | return *mInfo; |
630 | } |
631 | return mOriginalInfo.get(); |
632 | } |
633 | // Return the current TrackInfo updated as per the decoder output. |
634 | // Typically for audio, the number of channels and/or sampling rate can vary |
635 | // between what was found in the metadata and what the decoder returned. |
636 | const TrackInfo* GetWorkingInfo() const { return mWorkingInfo.get(); } |
637 | bool IsEncrypted() const { return GetCurrentInfo()->mCrypto.IsEncrypted(); } |
638 | |
639 | // Used by the MDSM for logging purposes. |
640 | Atomic<size_t> mSizeOfQueue; |
641 | // Used by the MDSM to determine if video decoding is hardware accelerated. |
642 | // This value is updated after a frame is successfully decoded. |
643 | Atomic<bool> mIsHardwareAccelerated; |
644 | // Sample format monitoring. |
645 | uint32_t mLastStreamSourceID; |
646 | Maybe<uint32_t> mNextStreamSourceID; |
647 | media::TimeIntervals mTimeRanges; |
648 | Maybe<media::TimeUnit> mLastTimeRangesEnd; |
649 | // TrackInfo as first discovered during ReadMetadata. |
650 | UniquePtr<TrackInfo> mOriginalInfo; |
651 | // Written exclusively on the TaskQueue, can be read on MDSM's TaskQueue. |
652 | // Must be read with parent's mutex held. |
653 | UniquePtr<TrackInfo> mWorkingInfo; |
654 | RefPtr<TrackInfoSharedPtr> mInfo; |
655 | Maybe<media::TimeUnit> mFirstDemuxedSampleTime; |
656 | // Use NullDecoderModule or not. |
657 | bool mIsNullDecode; |
658 | bool mHardwareDecodingDisabled; |
659 | // Whether we have reported hardware decoding support for video. Used only |
660 | // on reader's task queue, |
661 | bool mHasReportedVideoHardwareSupportTelemtry = false; |
662 | |
663 | class { |
664 | public: |
665 | float Mean() const { return mMean; } |
666 | |
667 | void Update(const media::TimeUnit& aValue) { |
668 | if (aValue == media::TimeUnit::Zero()) { |
669 | return; |
670 | } |
671 | mMean += static_cast<float>((1.0f / aValue.ToSeconds() - mMean) / |
672 | static_cast<double>(++mCount)); |
673 | } |
674 | |
675 | void Reset() { |
676 | mMean = 0; |
677 | mCount = 0; |
678 | } |
679 | |
680 | private: |
681 | float mMean = 0; |
682 | uint64_t mCount = 0; |
683 | } mMeanRate; |
684 | }; |
685 | |
686 | template <typename Type> |
687 | class DecoderDataWithPromise : public DecoderData { |
688 | public: |
689 | DecoderDataWithPromise(MediaFormatReader* aOwner, MediaData::Type aType, |
690 | uint32_t aNumOfMaxError) |
691 | : DecoderData(aOwner, aType, aNumOfMaxError), mHasPromise(false) { |
692 | DecoderDoctorLogger::LogConstructionAndBase( |
693 | "MediaFormatReader::DecoderDataWithPromise", this, |
694 | "MediaFormatReader::DecoderData", |
695 | static_cast<const MediaFormatReader::DecoderData*>(this)); |
696 | } |
697 | |
698 | ~DecoderDataWithPromise() { |
699 | DecoderDoctorLogger::LogDestruction( |
700 | "MediaFormatReader::DecoderDataWithPromise", this); |
701 | } |
702 | |
703 | bool HasPromise() const override { return mHasPromise; } |
704 | |
705 | RefPtr<DataPromise<Type>> EnsurePromise(StaticString aMethodName) { |
706 | 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()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 706); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { *((volatile int*)__null) = 706; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
707 | mHasPromise = true; |
708 | return mPromise.Ensure(aMethodName); |
709 | } |
710 | |
711 | void ResolvePromise(Type* aData, StaticString aMethodName) { |
712 | 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()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 712); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { *((volatile int*)__null) = 712; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
713 | mPromise.Resolve(aData, aMethodName); |
714 | mHasPromise = false; |
715 | } |
716 | |
717 | void RejectPromise(const MediaResult& aError, |
718 | StaticString aMethodName) override { |
719 | 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()" , "/var/lib/jenkins/workspace/firefox-scan-build/dom/media/MediaFormatReader.h" , 719); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mOwner->OnTaskQueue()" ")"); do { *((volatile int*)__null) = 719; __attribute__((nomerge )) ::abort(); } while (false); } } while (false); |
720 | mPromise.Reject(aError, aMethodName); |
721 | mHasPromise = false; |
722 | } |
723 | |
724 | private: |
725 | MozPromiseHolder<DataPromise<Type>> mPromise; |
726 | Atomic<bool> mHasPromise; |
727 | }; |
728 | |
729 | // Decode task queue. |
730 | RefPtr<TaskQueue> mTaskQueue; |
731 | |
732 | DecoderDataWithPromise<AudioData> mAudio; |
733 | DecoderDataWithPromise<VideoData> mVideo; |
734 | |
735 | Watchable<bool> mWorkingInfoChanged; |
736 | WatchManager<MediaFormatReader> mWatchManager; |
737 | bool mIsWatchingWorkingInfo; |
738 | |
739 | // Returns true when the decoder for this track needs input. |
740 | bool NeedInput(DecoderData& aDecoder); |
741 | |
742 | DecoderData& GetDecoderData(TrackType aTrack); |
743 | |
744 | // Demuxer objects. |
745 | class DemuxerProxy; |
746 | UniquePtr<DemuxerProxy> mDemuxer; |
747 | bool mDemuxerInitDone; |
748 | void OnDemuxerInitDone(const MediaResult& aResult); |
749 | void OnDemuxerInitFailed(const MediaResult& aError); |
750 | MozPromiseRequestHolder<MediaDataDemuxer::InitPromise> mDemuxerInitRequest; |
751 | MozPromiseRequestHolder<NotifyDataArrivedPromise> mNotifyDataArrivedPromise; |
752 | bool mPendingNotifyDataArrived; |
753 | void OnDemuxFailed(TrackType aTrack, const MediaResult& aError); |
754 | |
755 | void DoDemuxVideo(); |
756 | void OnVideoDemuxCompleted( |
757 | const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples); |
758 | void OnVideoDemuxFailed(const MediaResult& aError) { |
759 | OnDemuxFailed(TrackType::kVideoTrack, aError); |
760 | } |
761 | |
762 | void DoDemuxAudio(); |
763 | void OnAudioDemuxCompleted( |
764 | const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples); |
765 | void OnAudioDemuxFailed(const MediaResult& aError) { |
766 | OnDemuxFailed(TrackType::kAudioTrack, aError); |
767 | } |
768 | |
769 | void SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold); |
770 | MozPromiseRequestHolder<MediaTrackDemuxer::SkipAccessPointPromise> |
771 | mSkipRequest; |
772 | void VideoSkipReset(uint32_t aSkipped); |
773 | void OnVideoSkipCompleted(uint32_t aSkipped); |
774 | void OnVideoSkipFailed(MediaTrackDemuxer::SkipFailureHolder aFailure); |
775 | |
776 | // The last number of decoded output frames that we've reported to |
777 | // MediaDecoder::NotifyDecoded(). We diff the number of output video |
778 | // frames every time that DecodeVideoData() is called, and report the |
779 | // delta there. |
780 | uint64_t mLastReportedNumDecodedFrames; |
781 | |
782 | // Timestamp of the previous decoded video keyframe, in microseconds. |
783 | int64_t mPreviousDecodedKeyframeTime_us; |
784 | // Default mLastDecodedKeyframeTime_us value, must be bigger than anything. |
785 | static const int64_t sNoPreviousDecodedKeyframe = INT64_MAX(9223372036854775807L); |
786 | |
787 | RefPtr<layers::KnowsCompositor> mKnowsCompositor; |
788 | |
789 | // Metadata objects |
790 | // True if we've read the streams' metadata. |
791 | bool mInitDone; |
792 | MozPromiseHolder<MetadataPromise> mMetadataPromise; |
793 | bool IsEncrypted() const; |
794 | |
795 | // Set to true if any of our track buffers may be blocking. |
796 | bool mTrackDemuxersMayBlock; |
797 | |
798 | // Seeking objects. |
799 | void SetSeekTarget(const SeekTarget& aTarget); |
800 | bool IsSeeking() const { return mPendingSeekTime.isSome(); } |
801 | bool IsVideoOnlySeeking() const { |
802 | return IsSeeking() && mOriginalSeekTarget.IsVideoOnly(); |
803 | } |
804 | bool IsAudioOnlySeeking() const { |
805 | return IsSeeking() && mOriginalSeekTarget.IsAudioOnly(); |
806 | } |
807 | void ScheduleSeek(); |
808 | void AttemptSeek(); |
809 | void OnSeekFailed(TrackType aTrack, const MediaResult& aError); |
810 | void DoVideoSeek(); |
811 | void OnVideoSeekCompleted(media::TimeUnit aTime); |
812 | void OnVideoSeekFailed(const MediaResult& aError); |
813 | bool mSeekScheduled; |
814 | |
815 | void DoAudioSeek(); |
816 | void OnAudioSeekCompleted(media::TimeUnit aTime); |
817 | void OnAudioSeekFailed(const MediaResult& aError); |
818 | // The SeekTarget that was last given to Seek() |
819 | SeekTarget mOriginalSeekTarget; |
820 | // Temporary seek information while we wait for the data |
821 | Maybe<media::TimeUnit> mFallbackSeekTime; |
822 | Maybe<media::TimeUnit> mPendingSeekTime; |
823 | MozPromiseHolder<SeekPromise> mSeekPromise; |
824 | |
825 | RefPtr<VideoFrameContainer> mVideoFrameContainer; |
826 | layers::ImageContainer* GetImageContainer(); |
827 | |
828 | RefPtr<CDMProxy> mCDMProxy; |
829 | |
830 | RefPtr<GMPCrashHelper> mCrashHelper; |
831 | |
832 | void SetNullDecode(TrackType aTrack, bool aIsNullDecode); |
833 | |
834 | class DecoderFactory; |
835 | UniquePtr<DecoderFactory> mDecoderFactory; |
836 | |
837 | class ShutdownPromisePool; |
838 | UniquePtr<ShutdownPromisePool> mShutdownPromisePool; |
839 | |
840 | MediaEventListener mOnTrackWaitingForKeyListener; |
841 | |
842 | void OnFirstDemuxCompleted( |
843 | TrackInfo::TrackType aType, |
844 | const RefPtr<MediaTrackDemuxer::SamplesHolder>& aSamples); |
845 | |
846 | void OnFirstDemuxFailed(TrackInfo::TrackType aType, |
847 | const MediaResult& aError); |
848 | |
849 | void MaybeResolveMetadataPromise(); |
850 | |
851 | // Stores presentation info required for playback. |
852 | MediaInfo mInfo; |
853 | |
854 | UniquePtr<MetadataTags> mTags; |
855 | |
856 | // A flag indicating if the start time is known or not. |
857 | bool mHasStartTime = false; |
858 | |
859 | void ShutdownDecoder(TrackType aTrack); |
860 | RefPtr<ShutdownPromise> TearDownDecoders(); |
861 | |
862 | bool mShutdown = false; |
863 | |
864 | // Buffered range. |
865 | Canonical<media::TimeIntervals> mBuffered; |
866 | |
867 | // Used to send TimedMetadata to the listener. |
868 | TimedMetadataEventProducer mTimedMetadataEvent; |
869 | |
870 | // Notify if this media is not seekable. |
871 | MediaEventProducer<void> mOnMediaNotSeekable; |
872 | |
873 | // Notify if we are waiting for a decryption key. |
874 | MediaEventProducer<TrackInfo::TrackType> mOnTrackWaitingForKey; |
875 | |
876 | MediaEventProducer<nsTArray<uint8_t>, nsString> mOnEncrypted; |
877 | |
878 | MediaEventProducer<void> mOnWaitingForKey; |
879 | |
880 | MediaEventProducer<MediaResult> mOnDecodeWarning; |
881 | |
882 | MediaEventProducer<VideoInfo> mOnStoreDecoderBenchmark; |
883 | |
884 | MediaEventProducer<VideoInfo, AudioInfo> mTrackInfoUpdatedEvent; |
885 | |
886 | RefPtr<FrameStatistics> mFrameStats; |
887 | |
888 | // Used in bug 1393399 for telemetry. |
889 | const MediaDecoderOwnerID mMediaDecoderOwnerID; |
890 | |
891 | bool ResolveSetCDMPromiseIfDone(TrackType aTrack); |
892 | void PrepareToSetCDMForTrack(TrackType aTrack); |
893 | MozPromiseHolder<SetCDMPromise> mSetCDMPromise; |
894 | TrackSet mSetCDMForTracks{}; |
895 | bool IsDecoderWaitingForCDM(TrackType aTrack); |
896 | |
897 | void GetDebugInfo(dom::MediaFormatReaderDebugInfo& aInfo); |
898 | |
899 | // Only be used on Windows when the media engine playback is enabled. |
900 | Maybe<uint64_t> mMediaEngineId; |
901 | |
902 | const Maybe<TrackingId> mTrackingId; |
903 | |
904 | // The start time of reading the metdata and how long does it take. This |
905 | // measurement includes the time of downloading media resource over the |
906 | // internet. |
907 | Maybe<TimeStamp> mReadMetadataStartTime; |
908 | TimeDuration mReadMetaDataTime; |
909 | |
910 | // The total amount of time we have been waiting for the video data due to |
911 | // lacking of data. |
912 | TimeDuration mTotalWaitingForVideoDataTime; |
913 | |
914 | // https://github.com/w3c/encrypted-media/issues/251#issuecomment-819783073 |
915 | // Treat playback as encrypted if the media key is set before playback starts, |
916 | // this allows websites to start with non-encrypted stream and switch to |
917 | // encrypted stream later. |
918 | Atomic<bool> mEncryptedCustomIdent; |
919 | }; |
920 | |
921 | } // namespace mozilla |
922 | |
923 | #endif |