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