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