Line data Source code
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 : #include "MediaFormatReader.h"
8 :
9 : #include "AutoTaskQueue.h"
10 : #include "Layers.h"
11 : #include "MediaData.h"
12 : #include "MediaInfo.h"
13 : #include "MediaResource.h"
14 : #include "VideoFrameContainer.h"
15 : #include "VideoUtils.h"
16 : #include "mozilla/AbstractThread.h"
17 : #include "mozilla/CDMProxy.h"
18 : #include "mozilla/ClearOnShutdown.h"
19 : #include "mozilla/Preferences.h"
20 : #include "mozilla/SharedThreadPool.h"
21 : #include "mozilla/SizePrintfMacros.h"
22 : #include "mozilla/SyncRunnable.h"
23 : #include "mozilla/Telemetry.h"
24 : #include "mozilla/Unused.h"
25 : #include "mozilla/dom/HTMLMediaElement.h"
26 : #include "mozilla/layers/ShadowLayers.h"
27 : #include "nsContentUtils.h"
28 : #include "nsPrintfCString.h"
29 : #include "nsSize.h"
30 :
31 : #include <algorithm>
32 : #include <queue>
33 :
34 : using namespace mozilla::media;
35 :
36 : using mozilla::layers::Image;
37 : using mozilla::layers::LayerManager;
38 : using mozilla::layers::LayersBackend;
39 :
40 : static mozilla::LazyLogModule sFormatDecoderLog("MediaFormatReader");
41 : mozilla::LazyLogModule gMediaDemuxerLog("MediaDemuxer");
42 :
43 : #define LOG(arg, ...) MOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Debug, ("MediaFormatReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
44 : #define LOGV(arg, ...) MOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Verbose, ("MediaFormatReader(%p)::%s: " arg, this, __func__, ##__VA_ARGS__))
45 :
46 : #define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
47 :
48 : namespace mozilla {
49 :
50 : /**
51 : * This is a singleton which controls the number of decoders that can be
52 : * created concurrently. Before calling PDMFactory::CreateDecoder(), Alloc()
53 : * must be called to get a token object as a permission to create a decoder.
54 : * The token should stay alive until Shutdown() is called on the decoder.
55 : * The destructor of the token will restore the decoder count so it is available
56 : * for next calls of Alloc().
57 : */
58 : class GlobalAllocPolicy
59 : {
60 : using TrackType = TrackInfo::TrackType;
61 :
62 : public:
63 0 : class Token
64 : {
65 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Token)
66 : protected:
67 0 : virtual ~Token() {}
68 : };
69 :
70 : using Promise = MozPromise<RefPtr<Token>, bool, true>;
71 :
72 : // Acquire a token for decoder creation. Thread-safe.
73 : auto Alloc() -> RefPtr<Promise>;
74 :
75 : // Called by ClearOnShutdown() to delete the singleton.
76 : void operator=(decltype(nullptr));
77 :
78 : // Get the singleton for the given track type. Thread-safe.
79 : static GlobalAllocPolicy& Instance(TrackType aTrack);
80 :
81 : private:
82 : class AutoDeallocToken;
83 : using PromisePrivate = Promise::Private;
84 : GlobalAllocPolicy();
85 : ~GlobalAllocPolicy();
86 : // Called by the destructor of TokenImpl to restore the decoder limit.
87 : void Dealloc();
88 : // Decrement the decoder limit and resolve a promise if available.
89 : void ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock);
90 :
91 : // Protect access to Instance().
92 : static StaticMutex sMutex;
93 :
94 : ReentrantMonitor mMonitor;
95 : // The number of decoders available for creation.
96 : int mDecoderLimit;
97 : // Requests to acquire tokens.
98 : std::queue<RefPtr<PromisePrivate>> mPromises;
99 : };
100 :
101 3 : StaticMutex GlobalAllocPolicy::sMutex;
102 :
103 : class GlobalAllocPolicy::AutoDeallocToken : public Token
104 : {
105 : public:
106 0 : explicit AutoDeallocToken(GlobalAllocPolicy& aPolicy) : mPolicy(aPolicy) { }
107 :
108 : private:
109 0 : ~AutoDeallocToken()
110 0 : {
111 0 : mPolicy.Dealloc();
112 0 : }
113 :
114 : GlobalAllocPolicy& mPolicy; // reference to a singleton object.
115 : };
116 :
117 0 : GlobalAllocPolicy::GlobalAllocPolicy()
118 : : mMonitor("DecoderAllocPolicy::mMonitor")
119 0 : , mDecoderLimit(MediaPrefs::MediaDecoderLimit())
120 : {
121 0 : SystemGroup::Dispatch(
122 : "GlobalAllocPolicy::ClearOnShutdown",
123 : TaskCategory::Other,
124 0 : NS_NewRunnableFunction("GlobalAllocPolicy::GlobalAllocPolicy", [this]() {
125 0 : ClearOnShutdown(this, ShutdownPhase::ShutdownThreads);
126 0 : }));
127 0 : }
128 :
129 0 : GlobalAllocPolicy::~GlobalAllocPolicy()
130 : {
131 0 : while (!mPromises.empty()) {
132 0 : RefPtr<PromisePrivate> p = mPromises.front().forget();
133 0 : mPromises.pop();
134 0 : p->Reject(true, __func__);
135 : }
136 0 : }
137 :
138 : GlobalAllocPolicy&
139 0 : GlobalAllocPolicy::Instance(TrackType aTrack)
140 : {
141 0 : StaticMutexAutoLock lock(sMutex);
142 0 : if (aTrack == TrackType::kAudioTrack) {
143 0 : static auto sAudioPolicy = new GlobalAllocPolicy();
144 0 : return *sAudioPolicy;
145 : } else {
146 0 : static auto sVideoPolicy = new GlobalAllocPolicy();
147 0 : return *sVideoPolicy;
148 : }
149 : }
150 :
151 : auto
152 0 : GlobalAllocPolicy::Alloc() -> RefPtr<Promise>
153 : {
154 : // No decoder limit set.
155 0 : if (mDecoderLimit < 0) {
156 0 : return Promise::CreateAndResolve(new Token(), __func__);
157 : }
158 :
159 0 : ReentrantMonitorAutoEnter mon(mMonitor);
160 0 : RefPtr<PromisePrivate> p = new PromisePrivate(__func__);
161 0 : mPromises.push(p);
162 0 : ResolvePromise(mon);
163 0 : return p.forget();
164 : }
165 :
166 : void
167 0 : GlobalAllocPolicy::Dealloc()
168 : {
169 0 : ReentrantMonitorAutoEnter mon(mMonitor);
170 0 : ++mDecoderLimit;
171 0 : ResolvePromise(mon);
172 0 : }
173 :
174 : void
175 0 : GlobalAllocPolicy::ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock)
176 : {
177 0 : MOZ_ASSERT(mDecoderLimit >= 0);
178 :
179 0 : if (mDecoderLimit > 0 && !mPromises.empty()) {
180 0 : --mDecoderLimit;
181 0 : RefPtr<PromisePrivate> p = mPromises.front().forget();
182 0 : mPromises.pop();
183 0 : p->Resolve(new AutoDeallocToken(*this), __func__);
184 : }
185 0 : }
186 :
187 : void
188 0 : GlobalAllocPolicy::operator=(std::nullptr_t)
189 : {
190 0 : delete this;
191 0 : }
192 :
193 : /**
194 : * This class addresses the concern of bug 1339310 comment 4 where the Widevine
195 : * CDM doesn't support running multiple instances of a video decoder at once per
196 : * CDM instance by sequencing the order of decoder creation and shutdown. Note
197 : * this class addresses a different concern from that of GlobalAllocPolicy which
198 : * controls a system-wide number of decoders while this class control a per-MFR
199 : * number (which is one per CDM requirement).
200 : */
201 : class LocalAllocPolicy
202 : {
203 : using TrackType = TrackInfo::TrackType;
204 : using Promise = GlobalAllocPolicy::Promise;
205 : using Token = GlobalAllocPolicy::Token;
206 :
207 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(LocalAllocPolicy)
208 :
209 : public:
210 0 : LocalAllocPolicy(TrackType aTrack, TaskQueue* aOwnerThread)
211 0 : : mTrack(aTrack)
212 0 : , mOwnerThread(aOwnerThread)
213 : {
214 0 : }
215 :
216 : // Acquire a token for decoder creation. Note the resolved token will
217 : // aggregate a GlobalAllocPolicy token to comply to its policy. Note
218 : // this function shouldn't be called again until the returned promise
219 : // is resolved or rejected.
220 : RefPtr<Promise> Alloc();
221 :
222 : // Cancel the request to GlobalAllocPolicy and reject the current token
223 : // request. Note this must happen before mOwnerThread->BeginShutdown().
224 : void Cancel();
225 :
226 : private:
227 : /*
228 : * An RAII class to manage LocalAllocPolicy::mDecoderLimit.
229 : */
230 : class AutoDeallocToken : public Token
231 : {
232 : public:
233 0 : explicit AutoDeallocToken(LocalAllocPolicy* aOwner)
234 0 : : mOwner(aOwner)
235 : {
236 0 : MOZ_DIAGNOSTIC_ASSERT(mOwner->mDecoderLimit > 0);
237 0 : --mOwner->mDecoderLimit;
238 0 : }
239 : // Aggregate a GlobalAllocPolicy token to present a single instance of
240 : // Token to the client so the client doesn't have to deal with
241 : // GlobalAllocPolicy and LocalAllocPolicy separately.
242 0 : void Append(Token* aToken)
243 : {
244 0 : mToken = aToken;
245 0 : }
246 : private:
247 : // Release tokens allocated from GlobalAllocPolicy and LocalAllocPolicy
248 : // and process next token request if any.
249 0 : ~AutoDeallocToken()
250 0 : {
251 0 : mToken = nullptr; // Dealloc the global token.
252 0 : ++mOwner->mDecoderLimit; // Dealloc the local token.
253 0 : mOwner->ProcessRequest(); // Process next pending request.
254 0 : }
255 : RefPtr<LocalAllocPolicy> mOwner;
256 : RefPtr<Token> mToken;
257 : };
258 :
259 0 : ~LocalAllocPolicy() { }
260 : void ProcessRequest();
261 :
262 : int mDecoderLimit = 1;
263 : const TrackType mTrack;
264 : RefPtr<TaskQueue> mOwnerThread;
265 : MozPromiseHolder<Promise> mPendingPromise;
266 : MozPromiseRequestHolder<Promise> mTokenRequest;
267 : };
268 :
269 : RefPtr<LocalAllocPolicy::Promise>
270 0 : LocalAllocPolicy::Alloc()
271 : {
272 0 : MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
273 0 : MOZ_DIAGNOSTIC_ASSERT(mPendingPromise.IsEmpty());
274 0 : RefPtr<Promise> p = mPendingPromise.Ensure(__func__);
275 0 : if (mDecoderLimit > 0) {
276 0 : ProcessRequest();
277 : }
278 0 : return p.forget();
279 : }
280 :
281 : void
282 0 : LocalAllocPolicy::ProcessRequest()
283 : {
284 0 : MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
285 0 : MOZ_DIAGNOSTIC_ASSERT(mDecoderLimit > 0);
286 :
287 : // No pending request.
288 0 : if (mPendingPromise.IsEmpty()) {
289 0 : return;
290 : }
291 :
292 0 : RefPtr<AutoDeallocToken> token = new AutoDeallocToken(this);
293 0 : RefPtr<LocalAllocPolicy> self = this;
294 :
295 0 : GlobalAllocPolicy::Instance(mTrack).Alloc()->Then(
296 : mOwnerThread, __func__,
297 0 : [self, token](RefPtr<Token> aToken) {
298 0 : self->mTokenRequest.Complete();
299 0 : token->Append(aToken);
300 0 : self->mPendingPromise.Resolve(token, __func__);
301 0 : },
302 0 : [self, token]() {
303 0 : self->mTokenRequest.Complete();
304 0 : self->mPendingPromise.Reject(true, __func__);
305 0 : })->Track(mTokenRequest);
306 : }
307 :
308 : void
309 0 : LocalAllocPolicy::Cancel()
310 : {
311 0 : MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
312 0 : mPendingPromise.RejectIfExists(true, __func__);
313 0 : mTokenRequest.DisconnectIfExists();
314 0 : }
315 :
316 : /**
317 : * This class tracks shutdown promises to ensure all decoders are shut down
318 : * completely before MFR continues the rest of the shutdown procedure.
319 : */
320 0 : class MediaFormatReader::ShutdownPromisePool
321 : {
322 : public:
323 0 : ShutdownPromisePool()
324 0 : : mOnShutdownComplete(new ShutdownPromise::Private(__func__))
325 : {
326 0 : }
327 :
328 : // Return a promise which will be resolved when all the tracking promises
329 : // are resolved. Note no more promises should be added for tracking once
330 : // this function is called.
331 : RefPtr<ShutdownPromise> Shutdown();
332 :
333 : // Track a shutdown promise.
334 : void Track(RefPtr<ShutdownPromise> aPromise);
335 :
336 : // Shut down a decoder and track its shutdown promise.
337 0 : void ShutdownDecoder(already_AddRefed<MediaDataDecoder> aDecoder)
338 : {
339 0 : Track(RefPtr<MediaDataDecoder>(aDecoder)->Shutdown());
340 0 : }
341 :
342 : private:
343 : bool mShutdown = false;
344 : const RefPtr<ShutdownPromise::Private> mOnShutdownComplete;
345 : nsTHashtable<nsRefPtrHashKey<ShutdownPromise>> mPromises;
346 : };
347 :
348 : RefPtr<ShutdownPromise>
349 0 : MediaFormatReader::ShutdownPromisePool::Shutdown()
350 : {
351 0 : MOZ_DIAGNOSTIC_ASSERT(!mShutdown);
352 0 : mShutdown = true;
353 0 : if (mPromises.Count() == 0) {
354 0 : mOnShutdownComplete->Resolve(true, __func__);
355 : }
356 0 : return mOnShutdownComplete;
357 : }
358 :
359 : void
360 0 : MediaFormatReader::ShutdownPromisePool::Track(RefPtr<ShutdownPromise> aPromise)
361 : {
362 0 : MOZ_DIAGNOSTIC_ASSERT(!mShutdown);
363 0 : MOZ_DIAGNOSTIC_ASSERT(!mPromises.Contains(aPromise));
364 0 : mPromises.PutEntry(aPromise);
365 : aPromise->Then(
366 0 : AbstractThread::GetCurrent(), __func__,
367 0 : [aPromise, this]() {
368 0 : MOZ_DIAGNOSTIC_ASSERT(mPromises.Contains(aPromise));
369 0 : mPromises.RemoveEntry(aPromise);
370 0 : if (mShutdown && mPromises.Count() == 0) {
371 0 : mOnShutdownComplete->Resolve(true, __func__);
372 : }
373 0 : });
374 0 : }
375 :
376 : void
377 0 : MediaFormatReader::DecoderData::ShutdownDecoder()
378 : {
379 0 : MutexAutoLock lock(mMutex);
380 :
381 0 : if (!mDecoder) {
382 : // No decoder to shut down.
383 0 : return;
384 : }
385 :
386 0 : if (mFlushing) {
387 : // Flush is is in action. Shutdown will be initiated after flush completes.
388 0 : MOZ_DIAGNOSTIC_ASSERT(mShutdownPromise);
389 0 : mOwner->mShutdownPromisePool->Track(mShutdownPromise->Ensure(__func__));
390 : // The order of decoder creation and shutdown is handled by LocalAllocPolicy
391 : // and ShutdownPromisePool. MFR can now reset these members to a fresh state
392 : // and be ready to create new decoders again without explicitly waiting for
393 : // flush/shutdown to complete.
394 0 : mShutdownPromise = nullptr;
395 0 : mFlushing = false;
396 : } else {
397 : // No flush is in action. We can shut down the decoder now.
398 0 : mOwner->mShutdownPromisePool->Track(mDecoder->Shutdown());
399 : }
400 :
401 : // mShutdownPromisePool will handle the order of decoder shutdown so
402 : // we can forget mDecoder and be ready to create a new one.
403 0 : mDecoder = nullptr;
404 0 : mDescription = "shutdown";
405 0 : mOwner->ScheduleUpdate(mType == MediaData::AUDIO_DATA
406 : ? TrackType::kAudioTrack
407 0 : : TrackType::kVideoTrack);
408 : }
409 :
410 : void
411 0 : MediaFormatReader::DecoderData::Flush()
412 : {
413 0 : if (mFlushing || mFlushed) {
414 : // Flush still pending or already flushed, nothing more to do.
415 0 : return;
416 : }
417 0 : mDecodeRequest.DisconnectIfExists();
418 0 : mDrainRequest.DisconnectIfExists();
419 0 : mDrainState = DrainState::None;
420 0 : CancelWaitingForKey();
421 0 : mOutput.Clear();
422 0 : mNumSamplesInput = 0;
423 0 : mNumSamplesOutput = 0;
424 0 : mSizeOfQueue = 0;
425 0 : if (mDecoder) {
426 0 : TrackType type = mType == MediaData::AUDIO_DATA
427 0 : ? TrackType::kAudioTrack
428 0 : : TrackType::kVideoTrack;
429 0 : mFlushing = true;
430 0 : MOZ_DIAGNOSTIC_ASSERT(!mShutdownPromise);
431 0 : mShutdownPromise = new SharedShutdownPromiseHolder();
432 0 : RefPtr<SharedShutdownPromiseHolder> p = mShutdownPromise;
433 0 : RefPtr<MediaDataDecoder> d = mDecoder;
434 0 : mDecoder->Flush()
435 0 : ->Then(mOwner->OwnerThread(), __func__,
436 0 : [type, this, p, d]() {
437 0 : if (!p->IsEmpty()) {
438 : // Shutdown happened before flush completes. Let's continue to
439 : // shut down the decoder. Note we don't access |this| because
440 : // this decoder is no longer managed by MFR::DecoderData.
441 0 : d->Shutdown()->ChainTo(p->Steal(), __func__);
442 0 : return;
443 : }
444 0 : mFlushing = false;
445 0 : mShutdownPromise = nullptr;
446 0 : mOwner->ScheduleUpdate(type);
447 : },
448 0 : [type, this, p, d](const MediaResult& aError) {
449 0 : if (!p->IsEmpty()) {
450 0 : d->Shutdown()->ChainTo(p->Steal(), __func__);
451 0 : return;
452 : }
453 0 : mFlushing = false;
454 0 : mShutdownPromise = nullptr;
455 0 : mOwner->NotifyError(type, aError);
456 0 : });
457 : }
458 0 : mFlushed = true;
459 : }
460 :
461 0 : class MediaFormatReader::DecoderFactory
462 : {
463 : using InitPromise = MediaDataDecoder::InitPromise;
464 : using TokenPromise = GlobalAllocPolicy::Promise;
465 : using Token = GlobalAllocPolicy::Token;
466 :
467 : public:
468 0 : explicit DecoderFactory(MediaFormatReader* aOwner)
469 0 : : mAudio(aOwner->mAudio, TrackInfo::kAudioTrack, aOwner->OwnerThread())
470 : , mVideo(aOwner->mVideo, TrackInfo::kVideoTrack, aOwner->OwnerThread())
471 0 : , mOwner(WrapNotNull(aOwner)) { }
472 :
473 : void CreateDecoder(TrackType aTrack);
474 :
475 : // Shutdown any decoder pending initialization and reset mAudio/mVideo to its
476 : // pristine state so CreateDecoder() is ready to be called again immediately.
477 0 : void ShutdownDecoder(TrackType aTrack)
478 : {
479 0 : MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
480 : || aTrack == TrackInfo::kVideoTrack);
481 0 : auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
482 0 : data.mPolicy->Cancel();
483 0 : data.mTokenRequest.DisconnectIfExists();
484 0 : data.mInitRequest.DisconnectIfExists();
485 0 : if (data.mDecoder) {
486 0 : mOwner->mShutdownPromisePool->ShutdownDecoder(data.mDecoder.forget());
487 : }
488 0 : data.mStage = Stage::None;
489 0 : MOZ_ASSERT(!data.mToken);
490 0 : }
491 :
492 : private:
493 : class Wrapper;
494 :
495 : enum class Stage : int8_t
496 : {
497 : None,
498 : WaitForToken,
499 : CreateDecoder,
500 : WaitForInit
501 : };
502 :
503 0 : struct Data
504 : {
505 0 : Data(DecoderData& aOwnerData, TrackType aTrack, TaskQueue* aThread)
506 0 : : mOwnerData(aOwnerData)
507 : , mTrack(aTrack)
508 0 : , mPolicy(new LocalAllocPolicy(aTrack, aThread)) { }
509 : DecoderData& mOwnerData;
510 : const TrackType mTrack;
511 : RefPtr<LocalAllocPolicy> mPolicy;
512 : Stage mStage = Stage::None;
513 : RefPtr<Token> mToken;
514 : RefPtr<MediaDataDecoder> mDecoder;
515 : MozPromiseRequestHolder<TokenPromise> mTokenRequest;
516 : MozPromiseRequestHolder<InitPromise> mInitRequest;
517 : } mAudio, mVideo;
518 :
519 : void RunStage(Data& aData);
520 : MediaResult DoCreateDecoder(Data& aData);
521 : void DoInitDecoder(Data& aData);
522 :
523 : // guaranteed to be valid by the owner.
524 : const NotNull<MediaFormatReader*> mOwner;
525 : };
526 :
527 : void
528 0 : MediaFormatReader::DecoderFactory::CreateDecoder(TrackType aTrack)
529 : {
530 0 : MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
531 : || aTrack == TrackInfo::kVideoTrack);
532 0 : RunStage(aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo);
533 0 : }
534 :
535 0 : class MediaFormatReader::DecoderFactory::Wrapper : public MediaDataDecoder
536 : {
537 : using Token = GlobalAllocPolicy::Token;
538 :
539 : public:
540 0 : Wrapper(already_AddRefed<MediaDataDecoder> aDecoder,
541 : already_AddRefed<Token> aToken)
542 0 : : mDecoder(aDecoder), mToken(aToken) {}
543 :
544 0 : RefPtr<InitPromise> Init() override { return mDecoder->Init(); }
545 0 : RefPtr<DecodePromise> Decode(MediaRawData* aSample) override
546 : {
547 0 : return mDecoder->Decode(aSample);
548 : }
549 0 : RefPtr<DecodePromise> Drain() override { return mDecoder->Drain(); }
550 0 : RefPtr<FlushPromise> Flush() override { return mDecoder->Flush(); }
551 0 : bool IsHardwareAccelerated(nsACString& aFailureReason) const override
552 : {
553 0 : return mDecoder->IsHardwareAccelerated(aFailureReason);
554 : }
555 0 : const char* GetDescriptionName() const override
556 : {
557 0 : return mDecoder->GetDescriptionName();
558 : }
559 0 : void SetSeekThreshold(const TimeUnit& aTime) override
560 : {
561 0 : mDecoder->SetSeekThreshold(aTime);
562 0 : }
563 0 : bool SupportDecoderRecycling() const override
564 : {
565 0 : return mDecoder->SupportDecoderRecycling();
566 : }
567 0 : RefPtr<ShutdownPromise> Shutdown() override
568 : {
569 0 : RefPtr<MediaDataDecoder> decoder = mDecoder.forget();
570 0 : RefPtr<Token> token = mToken.forget();
571 0 : return decoder->Shutdown()->Then(
572 0 : AbstractThread::GetCurrent(), __func__,
573 0 : [token]() {
574 : return ShutdownPromise::CreateAndResolve(true, __func__);
575 0 : });
576 : }
577 :
578 : private:
579 : RefPtr<MediaDataDecoder> mDecoder;
580 : RefPtr<Token> mToken;
581 : };
582 :
583 : void
584 0 : MediaFormatReader::DecoderFactory::RunStage(Data& aData)
585 : {
586 0 : switch (aData.mStage) {
587 : case Stage::None: {
588 0 : MOZ_ASSERT(!aData.mToken);
589 0 : aData.mPolicy->Alloc()->Then(
590 0 : mOwner->OwnerThread(), __func__,
591 0 : [this, &aData] (RefPtr<Token> aToken) {
592 0 : aData.mTokenRequest.Complete();
593 0 : aData.mToken = aToken.forget();
594 0 : aData.mStage = Stage::CreateDecoder;
595 0 : RunStage(aData);
596 0 : },
597 0 : [&aData] () {
598 0 : aData.mTokenRequest.Complete();
599 0 : aData.mStage = Stage::None;
600 0 : })->Track(aData.mTokenRequest);
601 0 : aData.mStage = Stage::WaitForToken;
602 0 : break;
603 : }
604 :
605 : case Stage::WaitForToken: {
606 0 : MOZ_ASSERT(!aData.mToken);
607 0 : MOZ_ASSERT(aData.mTokenRequest.Exists());
608 0 : break;
609 : }
610 :
611 : case Stage::CreateDecoder: {
612 0 : MOZ_ASSERT(aData.mToken);
613 0 : MOZ_ASSERT(!aData.mDecoder);
614 0 : MOZ_ASSERT(!aData.mInitRequest.Exists());
615 :
616 0 : MediaResult rv = DoCreateDecoder(aData);
617 0 : if (NS_FAILED(rv)) {
618 0 : NS_WARNING("Error constructing decoders");
619 0 : aData.mToken = nullptr;
620 0 : aData.mStage = Stage::None;
621 0 : mOwner->NotifyError(aData.mTrack, rv);
622 0 : return;
623 : }
624 :
625 0 : aData.mDecoder = new Wrapper(aData.mDecoder.forget(), aData.mToken.forget());
626 0 : DoInitDecoder(aData);
627 0 : aData.mStage = Stage::WaitForInit;
628 0 : break;
629 : }
630 :
631 : case Stage::WaitForInit: {
632 0 : MOZ_ASSERT(aData.mDecoder);
633 0 : MOZ_ASSERT(aData.mInitRequest.Exists());
634 0 : break;
635 : }
636 : }
637 : }
638 :
639 : MediaResult
640 0 : MediaFormatReader::DecoderFactory::DoCreateDecoder(Data& aData)
641 : {
642 0 : auto& ownerData = aData.mOwnerData;
643 :
644 0 : auto decoderCreatingError = "error creating audio decoder";
645 : MediaResult result =
646 0 : MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, decoderCreatingError);
647 :
648 0 : if (!mOwner->mPlatform) {
649 0 : mOwner->mPlatform = new PDMFactory();
650 0 : if (mOwner->IsEncrypted()) {
651 0 : MOZ_ASSERT(mOwner->mCDMProxy);
652 0 : mOwner->mPlatform->SetCDMProxy(mOwner->mCDMProxy);
653 : }
654 : }
655 :
656 0 : switch (aData.mTrack) {
657 : case TrackInfo::kAudioTrack: {
658 0 : aData.mDecoder = mOwner->mPlatform->CreateDecoder({
659 : ownerData.mInfo
660 0 : ? *ownerData.mInfo->GetAsAudioInfo()
661 0 : : *ownerData.mOriginalInfo->GetAsAudioInfo(),
662 : ownerData.mTaskQueue,
663 0 : mOwner->mCrashHelper,
664 : ownerData.mIsNullDecode,
665 0 : &result,
666 : TrackInfo::kAudioTrack,
667 0 : &mOwner->OnTrackWaitingForKeyProducer()
668 0 : });
669 0 : break;
670 : }
671 :
672 : case TrackType::kVideoTrack: {
673 : // Decoders use the layers backend to decide if they can use hardware decoding,
674 : // so specify LAYERS_NONE if we want to forcibly disable it.
675 0 : aData.mDecoder = mOwner->mPlatform->CreateDecoder({
676 : ownerData.mInfo
677 0 : ? *ownerData.mInfo->GetAsVideoInfo()
678 0 : : *ownerData.mOriginalInfo->GetAsVideoInfo(),
679 : ownerData.mTaskQueue,
680 0 : mOwner->mKnowsCompositor,
681 0 : mOwner->GetImageContainer(),
682 0 : mOwner->mCrashHelper,
683 : ownerData.mIsNullDecode,
684 0 : &result,
685 : TrackType::kVideoTrack,
686 0 : &mOwner->OnTrackWaitingForKeyProducer()
687 0 : });
688 0 : break;
689 : }
690 :
691 : default:
692 0 : break;
693 : }
694 :
695 0 : if (aData.mDecoder) {
696 0 : return NS_OK;
697 : }
698 :
699 0 : ownerData.mDescription = decoderCreatingError;
700 0 : return result;
701 : }
702 :
703 : void
704 0 : MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData)
705 : {
706 0 : auto& ownerData = aData.mOwnerData;
707 :
708 0 : aData.mDecoder->Init()
709 0 : ->Then(mOwner->OwnerThread(), __func__,
710 0 : [this, &aData, &ownerData](TrackType aTrack) {
711 0 : aData.mInitRequest.Complete();
712 0 : aData.mStage = Stage::None;
713 0 : MutexAutoLock lock(ownerData.mMutex);
714 0 : ownerData.mDecoder = aData.mDecoder.forget();
715 0 : ownerData.mDescription = ownerData.mDecoder->GetDescriptionName();
716 0 : mOwner->SetVideoDecodeThreshold();
717 0 : mOwner->ScheduleUpdate(aTrack);
718 0 : },
719 0 : [this, &aData, &ownerData](const MediaResult& aError) {
720 0 : aData.mInitRequest.Complete();
721 0 : MOZ_RELEASE_ASSERT(!ownerData.mDecoder,
722 : "Can't have a decoder already set");
723 0 : aData.mStage = Stage::None;
724 0 : mOwner->mShutdownPromisePool->ShutdownDecoder(aData.mDecoder.forget());
725 0 : mOwner->NotifyError(aData.mTrack, aError);
726 0 : })
727 0 : ->Track(aData.mInitRequest);
728 0 : }
729 :
730 : // DemuxerProxy ensures that the original main demuxer is only ever accessed
731 : // via its own dedicated task queue.
732 : // This ensure that the reader's taskqueue will never blocked while a demuxer
733 : // is itself blocked attempting to access the MediaCache or the MediaResource.
734 : class MediaFormatReader::DemuxerProxy
735 : {
736 : using TrackType = TrackInfo::TrackType;
737 : class Wrapper;
738 :
739 : public:
740 0 : explicit DemuxerProxy(MediaDataDemuxer* aDemuxer)
741 0 : : mTaskQueue(new AutoTaskQueue(
742 0 : GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
743 0 : "DemuxerProxy::mTaskQueue"))
744 0 : , mData(new Data(aDemuxer))
745 : {
746 0 : MOZ_COUNT_CTOR(DemuxerProxy);
747 0 : }
748 :
749 0 : ~DemuxerProxy()
750 0 : {
751 0 : MOZ_COUNT_DTOR(DemuxerProxy);
752 0 : }
753 :
754 0 : RefPtr<ShutdownPromise> Shutdown()
755 : {
756 0 : RefPtr<Data> data = mData.forget();
757 0 : return InvokeAsync(mTaskQueue, __func__, [data]() {
758 : // We need to clear our reference to the demuxer now. So that in the event
759 : // the init promise wasn't resolved, such as what can happen with the
760 : // mediasource demuxer that is waiting on more data, it will force the
761 : // init promise to be rejected.
762 0 : data->mDemuxer = nullptr;
763 0 : data->mAudioDemuxer = nullptr;
764 0 : data->mVideoDemuxer = nullptr;
765 0 : return ShutdownPromise::CreateAndResolve(true, __func__);
766 0 : });
767 : }
768 :
769 : RefPtr<MediaDataDemuxer::InitPromise> Init();
770 :
771 : Wrapper*
772 0 : GetTrackDemuxer(TrackType aTrack, uint32_t aTrackNumber)
773 : {
774 0 : MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
775 :
776 0 : switch (aTrack) {
777 : case TrackInfo::kAudioTrack:
778 0 : return mData->mAudioDemuxer;
779 : case TrackInfo::kVideoTrack:
780 0 : return mData->mVideoDemuxer;
781 : default:
782 0 : return nullptr;
783 : }
784 : }
785 :
786 0 : uint32_t GetNumberTracks(TrackType aTrack) const
787 : {
788 0 : MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
789 :
790 0 : switch (aTrack) {
791 : case TrackInfo::kAudioTrack:
792 0 : return mData->mNumAudioTrack;
793 : case TrackInfo::kVideoTrack:
794 0 : return mData->mNumVideoTrack;
795 : default:
796 0 : return 0;
797 : }
798 : }
799 :
800 0 : bool IsSeekable() const
801 : {
802 0 : MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
803 :
804 0 : return mData->mSeekable;
805 : }
806 :
807 0 : bool IsSeekableOnlyInBufferedRanges() const
808 : {
809 0 : MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
810 :
811 0 : return mData->mSeekableOnlyInBufferedRange;
812 : }
813 :
814 0 : UniquePtr<EncryptionInfo> GetCrypto() const
815 : {
816 0 : MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
817 :
818 0 : if (!mData->mCrypto) {
819 0 : return nullptr;
820 : }
821 0 : auto crypto = MakeUnique<EncryptionInfo>();
822 0 : *crypto = *mData->mCrypto;
823 0 : return crypto;
824 : }
825 :
826 : RefPtr<NotifyDataArrivedPromise> NotifyDataArrived();
827 :
828 0 : bool ShouldComputeStartTime() const
829 : {
830 0 : MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
831 :
832 0 : return mData->mShouldComputeStartTime;
833 : }
834 :
835 : private:
836 : const RefPtr<AutoTaskQueue> mTaskQueue;
837 : struct Data
838 : {
839 0 : NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Data)
840 :
841 0 : explicit Data(MediaDataDemuxer* aDemuxer)
842 0 : : mInitDone(false)
843 0 : , mDemuxer(aDemuxer)
844 : {
845 0 : }
846 :
847 : Atomic<bool> mInitDone;
848 : // Only ever accessed over mTaskQueue once.
849 : RefPtr<MediaDataDemuxer> mDemuxer;
850 : // Only accessed once InitPromise has been resolved and immutable after.
851 : // So we can safely access them without the use of the mutex.
852 : uint32_t mNumAudioTrack = 0;
853 : RefPtr<Wrapper> mAudioDemuxer;
854 : uint32_t mNumVideoTrack = 0;
855 : RefPtr<Wrapper> mVideoDemuxer;
856 : bool mSeekable = false;
857 : bool mSeekableOnlyInBufferedRange = false;
858 : bool mShouldComputeStartTime = true;
859 : UniquePtr<EncryptionInfo> mCrypto;
860 : private:
861 0 : ~Data() { }
862 : };
863 : RefPtr<Data> mData;
864 : };
865 :
866 : class MediaFormatReader::DemuxerProxy::Wrapper : public MediaTrackDemuxer
867 : {
868 : public:
869 0 : Wrapper(MediaTrackDemuxer* aTrackDemuxer, AutoTaskQueue* aTaskQueue)
870 0 : : mMutex("TrackDemuxer Mutex")
871 : , mTaskQueue(aTaskQueue)
872 0 : , mGetSamplesMayBlock(aTrackDemuxer->GetSamplesMayBlock())
873 0 : , mInfo(aTrackDemuxer->GetInfo())
874 0 : , mTrackDemuxer(aTrackDemuxer)
875 : {
876 0 : }
877 :
878 0 : UniquePtr<TrackInfo> GetInfo() const override
879 : {
880 0 : if (!mInfo) {
881 0 : return nullptr;
882 : }
883 0 : return mInfo->Clone();
884 : }
885 :
886 0 : RefPtr<SeekPromise> Seek(const TimeUnit& aTime) override
887 : {
888 0 : RefPtr<Wrapper> self = this;
889 0 : return InvokeAsync(
890 : mTaskQueue, __func__,
891 0 : [self, aTime]() { return self->mTrackDemuxer->Seek(aTime); })
892 0 : ->Then(mTaskQueue, __func__,
893 0 : [self](const TimeUnit& aTime) {
894 0 : self->UpdateRandomAccessPoint();
895 0 : return SeekPromise::CreateAndResolve(aTime, __func__);
896 : },
897 0 : [self](const MediaResult& aError) {
898 0 : self->UpdateRandomAccessPoint();
899 0 : return SeekPromise::CreateAndReject(aError, __func__);
900 0 : });
901 : }
902 :
903 0 : RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples) override
904 : {
905 0 : RefPtr<Wrapper> self = this;
906 0 : return InvokeAsync(mTaskQueue, __func__,
907 0 : [self, aNumSamples]() {
908 0 : return self->mTrackDemuxer->GetSamples(aNumSamples);
909 0 : })
910 0 : ->Then(mTaskQueue, __func__,
911 0 : [self](RefPtr<SamplesHolder> aSamples) {
912 0 : self->UpdateRandomAccessPoint();
913 0 : return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
914 : },
915 0 : [self](const MediaResult& aError) {
916 0 : self->UpdateRandomAccessPoint();
917 0 : return SamplesPromise::CreateAndReject(aError, __func__);
918 0 : });
919 : }
920 :
921 0 : bool GetSamplesMayBlock() const override
922 : {
923 0 : return mGetSamplesMayBlock;
924 : }
925 :
926 0 : void Reset() override
927 : {
928 0 : RefPtr<Wrapper> self = this;
929 0 : mTaskQueue->Dispatch(
930 0 : NS_NewRunnableFunction("MediaFormatReader::DemuxerProxy::Wrapper::Reset",
931 0 : [self]() { self->mTrackDemuxer->Reset(); }));
932 0 : }
933 :
934 0 : nsresult GetNextRandomAccessPoint(TimeUnit* aTime) override
935 : {
936 0 : MutexAutoLock lock(mMutex);
937 0 : if (NS_SUCCEEDED(mNextRandomAccessPointResult)) {
938 0 : *aTime = mNextRandomAccessPoint;
939 : }
940 0 : return mNextRandomAccessPointResult;
941 : }
942 :
943 : RefPtr<SkipAccessPointPromise>
944 0 : SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold) override
945 : {
946 0 : RefPtr<Wrapper> self = this;
947 0 : return InvokeAsync(
948 : mTaskQueue, __func__,
949 0 : [self, aTimeThreshold]() {
950 0 : return self->mTrackDemuxer->SkipToNextRandomAccessPoint(
951 0 : aTimeThreshold);
952 0 : })
953 0 : ->Then(mTaskQueue, __func__,
954 0 : [self](uint32_t aVal) {
955 0 : self->UpdateRandomAccessPoint();
956 0 : return SkipAccessPointPromise::CreateAndResolve(aVal, __func__);
957 : },
958 0 : [self](const SkipFailureHolder& aError) {
959 0 : self->UpdateRandomAccessPoint();
960 0 : return SkipAccessPointPromise::CreateAndReject(aError, __func__);
961 0 : });
962 : }
963 :
964 0 : TimeIntervals GetBuffered() override
965 : {
966 0 : MutexAutoLock lock(mMutex);
967 0 : return mBuffered;
968 : }
969 :
970 0 : void BreakCycles() override { }
971 :
972 : private:
973 : Mutex mMutex;
974 : const RefPtr<AutoTaskQueue> mTaskQueue;
975 : const bool mGetSamplesMayBlock;
976 : const UniquePtr<TrackInfo> mInfo;
977 : // mTrackDemuxer is only ever accessed on demuxer's task queue.
978 : RefPtr<MediaTrackDemuxer> mTrackDemuxer;
979 : // All following members are protected by mMutex
980 : nsresult mNextRandomAccessPointResult = NS_OK;
981 : TimeUnit mNextRandomAccessPoint;
982 : TimeIntervals mBuffered;
983 : friend class DemuxerProxy;
984 :
985 0 : ~Wrapper()
986 0 : {
987 0 : RefPtr<MediaTrackDemuxer> trackDemuxer = mTrackDemuxer.forget();
988 0 : mTaskQueue->Dispatch(NS_NewRunnableFunction(
989 : "MediaFormatReader::DemuxerProxy::Wrapper::~Wrapper",
990 0 : [trackDemuxer]() { trackDemuxer->BreakCycles(); }));
991 0 : }
992 :
993 0 : void UpdateRandomAccessPoint()
994 : {
995 0 : MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
996 0 : if (!mTrackDemuxer) {
997 : // Detached.
998 0 : return;
999 : }
1000 0 : MutexAutoLock lock(mMutex);
1001 0 : mNextRandomAccessPointResult =
1002 0 : mTrackDemuxer->GetNextRandomAccessPoint(&mNextRandomAccessPoint);
1003 : }
1004 :
1005 0 : void UpdateBuffered()
1006 : {
1007 0 : MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
1008 0 : if (!mTrackDemuxer) {
1009 : // Detached.
1010 0 : return;
1011 : }
1012 0 : MutexAutoLock lock(mMutex);
1013 0 : mBuffered = mTrackDemuxer->GetBuffered();
1014 : }
1015 : };
1016 :
1017 : RefPtr<MediaDataDemuxer::InitPromise>
1018 0 : MediaFormatReader::DemuxerProxy::Init()
1019 : {
1020 : using InitPromise = MediaDataDemuxer::InitPromise;
1021 :
1022 0 : RefPtr<Data> data = mData;
1023 0 : RefPtr<AutoTaskQueue> taskQueue = mTaskQueue;
1024 0 : return InvokeAsync(mTaskQueue, __func__,
1025 0 : [data, taskQueue]() {
1026 0 : if (!data->mDemuxer) {
1027 : return InitPromise::CreateAndReject(
1028 0 : NS_ERROR_DOM_MEDIA_CANCELED, __func__);
1029 : }
1030 0 : return data->mDemuxer->Init();
1031 0 : })
1032 0 : ->Then(taskQueue, __func__,
1033 0 : [data, taskQueue]() {
1034 0 : if (!data->mDemuxer) { // Was shutdown.
1035 : return InitPromise::CreateAndReject(
1036 0 : NS_ERROR_DOM_MEDIA_CANCELED, __func__);
1037 : }
1038 0 : data->mNumAudioTrack =
1039 0 : data->mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
1040 0 : if (data->mNumAudioTrack) {
1041 : RefPtr<MediaTrackDemuxer> d =
1042 0 : data->mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
1043 0 : if (d) {
1044 : RefPtr<Wrapper> wrapper =
1045 0 : new DemuxerProxy::Wrapper(d, taskQueue);
1046 0 : wrapper->UpdateBuffered();
1047 0 : data->mAudioDemuxer = wrapper;
1048 : }
1049 : }
1050 0 : data->mNumVideoTrack =
1051 0 : data->mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack);
1052 0 : if (data->mNumVideoTrack) {
1053 : RefPtr<MediaTrackDemuxer> d =
1054 0 : data->mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
1055 0 : if (d) {
1056 : RefPtr<Wrapper> wrapper =
1057 0 : new DemuxerProxy::Wrapper(d, taskQueue);
1058 0 : wrapper->UpdateBuffered();
1059 0 : data->mVideoDemuxer = wrapper;
1060 : }
1061 : }
1062 0 : data->mCrypto = data->mDemuxer->GetCrypto();
1063 0 : data->mSeekable = data->mDemuxer->IsSeekable();
1064 0 : data->mSeekableOnlyInBufferedRange =
1065 0 : data->mDemuxer->IsSeekableOnlyInBufferedRanges();
1066 0 : data->mShouldComputeStartTime =
1067 0 : data->mDemuxer->ShouldComputeStartTime();
1068 0 : data->mInitDone = true;
1069 0 : return InitPromise::CreateAndResolve(NS_OK, __func__);
1070 : },
1071 0 : [](const MediaResult& aError) {
1072 : return InitPromise::CreateAndReject(aError, __func__);
1073 0 : });
1074 : }
1075 :
1076 : RefPtr<MediaFormatReader::NotifyDataArrivedPromise>
1077 0 : MediaFormatReader::DemuxerProxy::NotifyDataArrived()
1078 : {
1079 0 : RefPtr<Data> data = mData;
1080 0 : return InvokeAsync(mTaskQueue, __func__, [data]() {
1081 0 : if (!data->mDemuxer) {
1082 : // Was shutdown.
1083 : return NotifyDataArrivedPromise::CreateAndReject(
1084 0 : NS_ERROR_DOM_MEDIA_CANCELED, __func__);
1085 : }
1086 0 : data->mDemuxer->NotifyDataArrived();
1087 0 : if (data->mAudioDemuxer) {
1088 0 : data->mAudioDemuxer->UpdateBuffered();
1089 : }
1090 0 : if (data->mVideoDemuxer) {
1091 0 : data->mVideoDemuxer->UpdateBuffered();
1092 : }
1093 0 : return NotifyDataArrivedPromise::CreateAndResolve(true, __func__);
1094 0 : });
1095 : }
1096 :
1097 0 : MediaFormatReader::MediaFormatReader(const MediaDecoderReaderInit& aInit,
1098 0 : MediaDataDemuxer* aDemuxer)
1099 : : MediaDecoderReader(aInit)
1100 : , mAudio(this, MediaData::AUDIO_DATA,
1101 0 : MediaPrefs::MaxAudioDecodeError())
1102 : , mVideo(this, MediaData::VIDEO_DATA,
1103 0 : MediaPrefs::MaxVideoDecodeError())
1104 0 : , mDemuxer(new DemuxerProxy(aDemuxer))
1105 : , mDemuxerInitDone(false)
1106 : , mPendingNotifyDataArrived(false)
1107 : , mLastReportedNumDecodedFrames(0)
1108 : , mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe)
1109 : , mInitDone(false)
1110 : , mTrackDemuxersMayBlock(false)
1111 : , mSeekScheduled(false)
1112 0 : , mVideoFrameContainer(aInit.mVideoFrameContainer)
1113 0 : , mDecoderFactory(new DecoderFactory(this))
1114 0 : , mShutdownPromisePool(new ShutdownPromisePool())
1115 : {
1116 0 : MOZ_ASSERT(aDemuxer);
1117 0 : MOZ_COUNT_CTOR(MediaFormatReader);
1118 :
1119 0 : AbstractMediaDecoder* decoder = aInit.mDecoder;
1120 0 : if (decoder && decoder->CompositorUpdatedEvent()) {
1121 0 : mCompositorUpdatedListener = decoder->CompositorUpdatedEvent()->Connect(
1122 0 : mTaskQueue, this, &MediaFormatReader::NotifyCompositorUpdated);
1123 : }
1124 0 : mOnTrackWaitingForKeyListener = OnTrackWaitingForKey().Connect(
1125 0 : mTaskQueue, this, &MediaFormatReader::NotifyWaitingForKey);
1126 0 : }
1127 :
1128 0 : MediaFormatReader::~MediaFormatReader()
1129 : {
1130 0 : MOZ_COUNT_DTOR(MediaFormatReader);
1131 0 : }
1132 :
1133 : RefPtr<ShutdownPromise>
1134 0 : MediaFormatReader::Shutdown()
1135 : {
1136 0 : MOZ_ASSERT(OnTaskQueue());
1137 0 : LOG("");
1138 :
1139 0 : mDemuxerInitRequest.DisconnectIfExists();
1140 0 : mNotifyDataArrivedPromise.DisconnectIfExists();
1141 0 : mMetadataPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
1142 0 : mSeekPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
1143 0 : mSkipRequest.DisconnectIfExists();
1144 :
1145 0 : if (mAudio.HasPromise()) {
1146 0 : mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
1147 : }
1148 0 : if (mVideo.HasPromise()) {
1149 0 : mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
1150 : }
1151 :
1152 0 : if (HasAudio()) {
1153 0 : mAudio.ResetDemuxer();
1154 0 : mAudio.mTrackDemuxer->BreakCycles();
1155 0 : mAudio.mTrackDemuxer = nullptr;
1156 0 : mAudio.ResetState();
1157 0 : ShutdownDecoder(TrackInfo::kAudioTrack);
1158 : }
1159 :
1160 0 : if (HasVideo()) {
1161 0 : mVideo.ResetDemuxer();
1162 0 : mVideo.mTrackDemuxer->BreakCycles();
1163 0 : mVideo.mTrackDemuxer = nullptr;
1164 0 : mVideo.ResetState();
1165 0 : ShutdownDecoder(TrackInfo::kVideoTrack);
1166 : }
1167 :
1168 0 : mShutdownPromisePool->Track(mDemuxer->Shutdown());
1169 0 : mDemuxer = nullptr;
1170 :
1171 0 : mCompositorUpdatedListener.DisconnectIfExists();
1172 0 : mOnTrackWaitingForKeyListener.Disconnect();
1173 :
1174 0 : mShutdown = true;
1175 0 : return mShutdownPromisePool->Shutdown()
1176 0 : ->Then(OwnerThread(), __func__, this,
1177 : &MediaFormatReader::TearDownDecoders,
1178 0 : &MediaFormatReader::TearDownDecoders);
1179 : }
1180 :
1181 : void
1182 0 : MediaFormatReader::ShutdownDecoder(TrackType aTrack)
1183 : {
1184 0 : LOGV("%s", TrackTypeToStr(aTrack));
1185 :
1186 : // Shut down the pending decoder if any.
1187 0 : mDecoderFactory->ShutdownDecoder(aTrack);
1188 :
1189 0 : auto& decoder = GetDecoderData(aTrack);
1190 : // Flush the decoder if necessary.
1191 0 : decoder.Flush();
1192 : // Shut down the decoder if any.
1193 0 : decoder.ShutdownDecoder();
1194 0 : }
1195 :
1196 : RefPtr<ShutdownPromise>
1197 0 : MediaFormatReader::TearDownDecoders()
1198 : {
1199 0 : if (mAudio.mTaskQueue) {
1200 0 : mAudio.mTaskQueue->BeginShutdown();
1201 0 : mAudio.mTaskQueue->AwaitShutdownAndIdle();
1202 0 : mAudio.mTaskQueue = nullptr;
1203 : }
1204 0 : if (mVideo.mTaskQueue) {
1205 0 : mVideo.mTaskQueue->BeginShutdown();
1206 0 : mVideo.mTaskQueue->AwaitShutdownAndIdle();
1207 0 : mVideo.mTaskQueue = nullptr;
1208 : }
1209 :
1210 0 : mDecoderFactory = nullptr;
1211 0 : mPlatform = nullptr;
1212 0 : mVideoFrameContainer = nullptr;
1213 :
1214 0 : return MediaDecoderReader::Shutdown();
1215 : }
1216 :
1217 : void
1218 0 : MediaFormatReader::InitLayersBackendType()
1219 : {
1220 : // Extract the layer manager backend type so that platform decoders
1221 : // can determine whether it's worthwhile using hardware accelerated
1222 : // video decoding.
1223 0 : if (!mDecoder) {
1224 0 : return;
1225 : }
1226 0 : MediaDecoderOwner* owner = mDecoder->GetOwner();
1227 0 : if (!owner) {
1228 0 : NS_WARNING("MediaFormatReader without a decoder owner, can't get HWAccel");
1229 0 : return;
1230 : }
1231 :
1232 0 : dom::HTMLMediaElement* element = owner->GetMediaElement();
1233 0 : NS_ENSURE_TRUE_VOID(element);
1234 :
1235 : RefPtr<LayerManager> layerManager =
1236 0 : nsContentUtils::LayerManagerForDocument(element->OwnerDoc());
1237 0 : NS_ENSURE_TRUE_VOID(layerManager);
1238 :
1239 0 : mKnowsCompositor = layerManager->AsShadowForwarder();
1240 : }
1241 :
1242 : nsresult
1243 0 : MediaFormatReader::InitInternal()
1244 : {
1245 0 : MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
1246 :
1247 0 : InitLayersBackendType();
1248 :
1249 : mAudio.mTaskQueue = new TaskQueue(
1250 0 : GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
1251 0 : "MFR::mAudio::mTaskQueue");
1252 :
1253 : mVideo.mTaskQueue = new TaskQueue(
1254 0 : GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
1255 0 : "MFR::mVideo::mTaskQueue");
1256 :
1257 0 : if (mDecoder) {
1258 : // Note: GMPCrashHelper must be created on main thread, as it may use
1259 : // weak references, which aren't threadsafe.
1260 0 : mCrashHelper = mDecoder->GetCrashHelper();
1261 : }
1262 0 : return NS_OK;
1263 : }
1264 :
1265 0 : class DispatchKeyNeededEvent : public Runnable
1266 : {
1267 : public:
1268 0 : DispatchKeyNeededEvent(AbstractMediaDecoder* aDecoder,
1269 : nsTArray<uint8_t>& aInitData,
1270 : const nsString& aInitDataType)
1271 0 : : Runnable("DispatchKeyNeededEvent")
1272 : , mDecoder(aDecoder)
1273 : , mInitData(aInitData)
1274 0 : , mInitDataType(aInitDataType)
1275 : {
1276 0 : }
1277 0 : NS_IMETHOD Run() override
1278 : {
1279 : // Note: Null check the owner, as the decoder could have been shutdown
1280 : // since this event was dispatched.
1281 0 : MediaDecoderOwner* owner = mDecoder->GetOwner();
1282 0 : if (owner) {
1283 0 : owner->DispatchEncrypted(mInitData, mInitDataType);
1284 : }
1285 0 : mDecoder = nullptr;
1286 0 : return NS_OK;
1287 : }
1288 : private:
1289 : RefPtr<AbstractMediaDecoder> mDecoder;
1290 : nsTArray<uint8_t> mInitData;
1291 : nsString mInitDataType;
1292 : };
1293 :
1294 : void
1295 0 : MediaFormatReader::SetCDMProxy(CDMProxy* aProxy)
1296 : {
1297 0 : RefPtr<CDMProxy> proxy = aProxy;
1298 0 : RefPtr<MediaFormatReader> self = this;
1299 : nsCOMPtr<nsIRunnable> r =
1300 0 : NS_NewRunnableFunction("MediaFormatReader::SetCDMProxy", [=]() {
1301 0 : MOZ_ASSERT(self->OnTaskQueue());
1302 0 : self->mCDMProxy = proxy;
1303 0 : });
1304 0 : OwnerThread()->Dispatch(r.forget());
1305 0 : }
1306 :
1307 : bool
1308 0 : MediaFormatReader::IsWaitingOnCDMResource()
1309 : {
1310 0 : MOZ_ASSERT(OnTaskQueue());
1311 0 : return IsEncrypted() && !mCDMProxy;
1312 : }
1313 :
1314 : RefPtr<MediaDecoderReader::MetadataPromise>
1315 0 : MediaFormatReader::AsyncReadMetadata()
1316 : {
1317 0 : MOZ_ASSERT(OnTaskQueue());
1318 :
1319 0 : MOZ_DIAGNOSTIC_ASSERT(mMetadataPromise.IsEmpty());
1320 :
1321 0 : if (mInitDone) {
1322 : // We are returning from dormant.
1323 0 : MetadataHolder metadata;
1324 0 : metadata.mInfo = MakeUnique<MediaInfo>(mInfo);
1325 0 : return MetadataPromise::CreateAndResolve(Move(metadata), __func__);
1326 : }
1327 :
1328 0 : RefPtr<MetadataPromise> p = mMetadataPromise.Ensure(__func__);
1329 :
1330 0 : mDemuxer->Init()
1331 0 : ->Then(OwnerThread(), __func__, this,
1332 : &MediaFormatReader::OnDemuxerInitDone,
1333 : &MediaFormatReader::OnDemuxerInitFailed)
1334 0 : ->Track(mDemuxerInitRequest);
1335 0 : return p;
1336 : }
1337 :
1338 : void
1339 0 : MediaFormatReader::OnDemuxerInitDone(const MediaResult& aResult)
1340 : {
1341 0 : MOZ_ASSERT(OnTaskQueue());
1342 0 : mDemuxerInitRequest.Complete();
1343 :
1344 0 : if (NS_FAILED(aResult) && MediaPrefs::MediaWarningsAsErrors()) {
1345 0 : mMetadataPromise.Reject(aResult, __func__);
1346 0 : return;
1347 : }
1348 :
1349 0 : mDemuxerInitDone = true;
1350 :
1351 0 : UniquePtr<MetadataTags> tags(MakeUnique<MetadataTags>());
1352 :
1353 0 : RefPtr<PDMFactory> platform;
1354 0 : if (!IsWaitingOnCDMResource()) {
1355 0 : platform = new PDMFactory();
1356 : }
1357 :
1358 : // To decode, we need valid video and a place to put it.
1359 : bool videoActive =
1360 0 : !!mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack) && GetImageContainer();
1361 :
1362 0 : if (videoActive) {
1363 : // We currently only handle the first video track.
1364 0 : mVideo.mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
1365 0 : if (!mVideo.mTrackDemuxer) {
1366 0 : mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
1367 0 : return;
1368 : }
1369 :
1370 0 : UniquePtr<TrackInfo> videoInfo = mVideo.mTrackDemuxer->GetInfo();
1371 0 : videoActive = videoInfo && videoInfo->IsValid();
1372 0 : if (videoActive) {
1373 0 : if (platform
1374 0 : && !platform->SupportsMimeType(videoInfo->mMimeType, nullptr)) {
1375 : // We have no decoder for this track. Error.
1376 0 : mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
1377 0 : return;
1378 : }
1379 0 : mInfo.mVideo = *videoInfo->GetAsVideoInfo();
1380 0 : for (const MetadataTag& tag : videoInfo->mTags) {
1381 0 : tags->Put(tag.mKey, tag.mValue);
1382 : }
1383 0 : mVideo.mOriginalInfo = Move(videoInfo);
1384 0 : mTrackDemuxersMayBlock |= mVideo.mTrackDemuxer->GetSamplesMayBlock();
1385 : } else {
1386 0 : mVideo.mTrackDemuxer->BreakCycles();
1387 0 : mVideo.mTrackDemuxer = nullptr;
1388 : }
1389 : }
1390 :
1391 0 : bool audioActive = !!mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
1392 0 : if (audioActive) {
1393 0 : mAudio.mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
1394 0 : if (!mAudio.mTrackDemuxer) {
1395 0 : mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
1396 0 : return;
1397 : }
1398 :
1399 0 : UniquePtr<TrackInfo> audioInfo = mAudio.mTrackDemuxer->GetInfo();
1400 : // We actively ignore audio tracks that we know we can't play.
1401 0 : audioActive =
1402 : audioInfo
1403 0 : && audioInfo->IsValid()
1404 0 : && (!platform || platform->SupportsMimeType(audioInfo->mMimeType,
1405 : nullptr));
1406 :
1407 0 : if (audioActive) {
1408 0 : mInfo.mAudio = *audioInfo->GetAsAudioInfo();
1409 0 : for (const MetadataTag& tag : audioInfo->mTags) {
1410 0 : tags->Put(tag.mKey, tag.mValue);
1411 : }
1412 0 : mAudio.mOriginalInfo = Move(audioInfo);
1413 0 : mTrackDemuxersMayBlock |= mAudio.mTrackDemuxer->GetSamplesMayBlock();
1414 : } else {
1415 0 : mAudio.mTrackDemuxer->BreakCycles();
1416 0 : mAudio.mTrackDemuxer = nullptr;
1417 : }
1418 : }
1419 :
1420 0 : UniquePtr<EncryptionInfo> crypto = mDemuxer->GetCrypto();
1421 0 : if (mDecoder && crypto && crypto->IsEncrypted()) {
1422 : // Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
1423 0 : for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
1424 : nsCOMPtr<nsIRunnable> r =
1425 0 : new DispatchKeyNeededEvent(mDecoder, crypto->mInitDatas[i].mInitData,
1426 0 : crypto->mInitDatas[i].mType);
1427 0 : mDecoder->AbstractMainThread()->Dispatch(r.forget());
1428 : }
1429 0 : mInfo.mCrypto = *crypto;
1430 : }
1431 :
1432 0 : auto videoDuration = HasVideo() ? mInfo.mVideo.mDuration : TimeUnit::Zero();
1433 0 : auto audioDuration = HasAudio() ? mInfo.mAudio.mDuration : TimeUnit::Zero();
1434 :
1435 0 : auto duration = std::max(videoDuration, audioDuration);
1436 0 : if (duration.IsPositive()) {
1437 0 : mInfo.mMetadataDuration = Some(duration);
1438 : }
1439 :
1440 0 : mInfo.mMediaSeekable = mDemuxer->IsSeekable();
1441 0 : mInfo.mMediaSeekableOnlyInBufferedRanges =
1442 0 : mDemuxer->IsSeekableOnlyInBufferedRanges();
1443 :
1444 0 : if (!videoActive && !audioActive) {
1445 0 : mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
1446 0 : return;
1447 : }
1448 :
1449 0 : mTags = Move(tags);
1450 0 : mInitDone = true;
1451 :
1452 : // Try to get the start time.
1453 : // For MSE case, the start time of each track is assumed to be 0.
1454 : // For others, we must demux the first sample to know the start time for each
1455 : // track.
1456 0 : if (!mDemuxer->ShouldComputeStartTime()) {
1457 0 : mAudio.mFirstDemuxedSampleTime.emplace(TimeUnit::Zero());
1458 0 : mVideo.mFirstDemuxedSampleTime.emplace(TimeUnit::Zero());
1459 : } else {
1460 0 : if (HasAudio()) {
1461 0 : RequestDemuxSamples(TrackInfo::kAudioTrack);
1462 : }
1463 :
1464 0 : if (HasVideo()) {
1465 0 : RequestDemuxSamples(TrackInfo::kVideoTrack);
1466 : }
1467 : }
1468 :
1469 0 : if (aResult != NS_OK && mDecoder) {
1470 0 : RefPtr<AbstractMediaDecoder> decoder = mDecoder;
1471 0 : mDecoder->AbstractMainThread()->Dispatch(NS_NewRunnableFunction(
1472 0 : "MediaFormatReader::OnDemuxerInitDone", [decoder, aResult]() {
1473 0 : if (decoder->GetOwner()) {
1474 0 : decoder->GetOwner()->DecodeWarning(aResult);
1475 : }
1476 0 : }));
1477 : }
1478 :
1479 0 : MaybeResolveMetadataPromise();
1480 : }
1481 :
1482 : void
1483 0 : MediaFormatReader::MaybeResolveMetadataPromise()
1484 : {
1485 0 : MOZ_ASSERT(OnTaskQueue());
1486 :
1487 0 : if ((HasAudio() && mAudio.mFirstDemuxedSampleTime.isNothing())
1488 0 : || (HasVideo() && mVideo.mFirstDemuxedSampleTime.isNothing())) {
1489 0 : return;
1490 : }
1491 :
1492 : TimeUnit startTime =
1493 0 : std::min(mAudio.mFirstDemuxedSampleTime.refOr(TimeUnit::FromInfinity()),
1494 0 : mVideo.mFirstDemuxedSampleTime.refOr(TimeUnit::FromInfinity()));
1495 :
1496 0 : if (!startTime.IsInfinite()) {
1497 0 : mInfo.mStartTime = startTime; // mInfo.mStartTime is initialized to 0.
1498 : }
1499 :
1500 0 : MetadataHolder metadata;
1501 0 : metadata.mInfo = MakeUnique<MediaInfo>(mInfo);
1502 0 : metadata.mTags = mTags->Count() ? Move(mTags) : nullptr;
1503 :
1504 : // We now have all the informations required to calculate the initial buffered
1505 : // range.
1506 0 : mHasStartTime = true;
1507 0 : UpdateBuffered();
1508 :
1509 0 : mMetadataPromise.Resolve(Move(metadata), __func__);
1510 : }
1511 :
1512 : bool
1513 0 : MediaFormatReader::IsEncrypted() const
1514 : {
1515 0 : return (HasAudio() && mInfo.mAudio.mCrypto.mValid)
1516 0 : || (HasVideo() && mInfo.mVideo.mCrypto.mValid);
1517 : }
1518 :
1519 : void
1520 0 : MediaFormatReader::OnDemuxerInitFailed(const MediaResult& aError)
1521 : {
1522 0 : mDemuxerInitRequest.Complete();
1523 0 : mMetadataPromise.Reject(aError, __func__);
1524 0 : }
1525 :
1526 : void
1527 0 : MediaFormatReader::ReadUpdatedMetadata(MediaInfo* aInfo)
1528 : {
1529 0 : *aInfo = mInfo;
1530 0 : }
1531 :
1532 : MediaFormatReader::DecoderData&
1533 0 : MediaFormatReader::GetDecoderData(TrackType aTrack)
1534 : {
1535 0 : MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack
1536 : || aTrack == TrackInfo::kVideoTrack);
1537 0 : if (aTrack == TrackInfo::kAudioTrack) {
1538 0 : return mAudio;
1539 : }
1540 0 : return mVideo;
1541 : }
1542 :
1543 : bool
1544 0 : MediaFormatReader::ShouldSkip(TimeUnit aTimeThreshold)
1545 : {
1546 0 : MOZ_ASSERT(HasVideo());
1547 :
1548 0 : if (!MediaPrefs::MFRSkipToNextKeyFrameEnabled()) {
1549 0 : return false;
1550 : }
1551 :
1552 0 : TimeUnit nextKeyframe;
1553 0 : nsresult rv = mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe);
1554 0 : if (NS_FAILED(rv)) {
1555 : // Only OggTrackDemuxer with video type gets into here.
1556 : // We don't support skip-to-next-frame for this case.
1557 0 : return false;
1558 : }
1559 0 : return (nextKeyframe <= aTimeThreshold
1560 0 : || (mVideo.mTimeThreshold
1561 0 : && mVideo.mTimeThreshold.ref().EndTime() < aTimeThreshold))
1562 0 : && nextKeyframe.ToMicroseconds() >= 0
1563 0 : && !nextKeyframe.IsInfinite();
1564 : }
1565 :
1566 : RefPtr<MediaDecoderReader::VideoDataPromise>
1567 0 : MediaFormatReader::RequestVideoData(const TimeUnit& aTimeThreshold)
1568 : {
1569 0 : MOZ_ASSERT(OnTaskQueue());
1570 0 : MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(),
1571 : "No sample requests allowed while seeking");
1572 0 : MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
1573 0 : MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists()
1574 : || mVideo.mTimeThreshold.isSome());
1575 0 : MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
1576 0 : LOGV("RequestVideoData(%" PRId64 ")", aTimeThreshold.ToMicroseconds());
1577 :
1578 0 : if (!HasVideo()) {
1579 0 : LOG("called with no video track");
1580 : return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
1581 0 : __func__);
1582 : }
1583 :
1584 0 : if (IsSeeking()) {
1585 0 : LOG("called mid-seek. Rejecting.");
1586 : return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
1587 0 : __func__);
1588 : }
1589 :
1590 0 : if (mShutdown) {
1591 0 : NS_WARNING("RequestVideoData on shutdown MediaFormatReader!");
1592 : return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
1593 0 : __func__);
1594 : }
1595 :
1596 : // Ensure we have no pending seek going as ShouldSkip could return out of date
1597 : // information.
1598 0 : if (!mVideo.HasInternalSeekPending() && ShouldSkip(aTimeThreshold)) {
1599 0 : RefPtr<VideoDataPromise> p = mVideo.EnsurePromise(__func__);
1600 0 : SkipVideoDemuxToNextKeyFrame(aTimeThreshold);
1601 0 : return p;
1602 : }
1603 :
1604 0 : RefPtr<VideoDataPromise> p = mVideo.EnsurePromise(__func__);
1605 0 : ScheduleUpdate(TrackInfo::kVideoTrack);
1606 :
1607 0 : return p;
1608 : }
1609 :
1610 : void
1611 0 : MediaFormatReader::OnDemuxFailed(TrackType aTrack, const MediaResult& aError)
1612 : {
1613 0 : MOZ_ASSERT(OnTaskQueue());
1614 0 : LOG("Failed to demux %s, failure:%" PRIu32,
1615 : aTrack == TrackType::kVideoTrack ? "video" : "audio",
1616 : static_cast<uint32_t>(aError.Code()));
1617 0 : auto& decoder = GetDecoderData(aTrack);
1618 0 : decoder.mDemuxRequest.Complete();
1619 0 : switch (aError.Code()) {
1620 : case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
1621 0 : if (!decoder.mWaitingForData) {
1622 0 : decoder.RequestDrain();
1623 : }
1624 0 : NotifyEndOfStream(aTrack);
1625 0 : break;
1626 : case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
1627 0 : if (!decoder.mWaitingForData) {
1628 0 : decoder.RequestDrain();
1629 : }
1630 0 : NotifyWaitingForData(aTrack);
1631 0 : break;
1632 : case NS_ERROR_DOM_MEDIA_CANCELED:
1633 0 : if (decoder.HasPromise()) {
1634 0 : decoder.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
1635 : }
1636 0 : break;
1637 : default:
1638 0 : NotifyError(aTrack, aError);
1639 0 : break;
1640 : }
1641 0 : }
1642 :
1643 : void
1644 0 : MediaFormatReader::DoDemuxVideo()
1645 : {
1646 : using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
1647 :
1648 0 : auto p = mVideo.mTrackDemuxer->GetSamples(1);
1649 :
1650 0 : if (mVideo.mFirstDemuxedSampleTime.isNothing()) {
1651 0 : RefPtr<MediaFormatReader> self = this;
1652 0 : p = p->Then(OwnerThread(), __func__,
1653 0 : [self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
1654 0 : self->OnFirstDemuxCompleted(TrackInfo::kVideoTrack, aSamples);
1655 0 : return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
1656 : },
1657 0 : [self] (const MediaResult& aError) {
1658 0 : self->OnFirstDemuxFailed(TrackInfo::kVideoTrack, aError);
1659 0 : return SamplesPromise::CreateAndReject(aError, __func__);
1660 0 : });
1661 : }
1662 :
1663 0 : p->Then(OwnerThread(), __func__, this,
1664 : &MediaFormatReader::OnVideoDemuxCompleted,
1665 : &MediaFormatReader::OnVideoDemuxFailed)
1666 0 : ->Track(mVideo.mDemuxRequest);
1667 0 : }
1668 :
1669 : void
1670 0 : MediaFormatReader::OnVideoDemuxCompleted(
1671 : RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
1672 : {
1673 0 : LOGV("%" PRIuSIZE " video samples demuxed (sid:%d)",
1674 : aSamples->mSamples.Length(),
1675 : aSamples->mSamples[0]->mTrackInfo
1676 : ? aSamples->mSamples[0]->mTrackInfo->GetID()
1677 : : 0);
1678 0 : mVideo.mDemuxRequest.Complete();
1679 0 : mVideo.mQueuedSamples.AppendElements(aSamples->mSamples);
1680 0 : ScheduleUpdate(TrackInfo::kVideoTrack);
1681 0 : }
1682 :
1683 : RefPtr<MediaDecoderReader::AudioDataPromise>
1684 0 : MediaFormatReader::RequestAudioData()
1685 : {
1686 0 : MOZ_ASSERT(OnTaskQueue());
1687 0 : MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise(), "No duplicate sample requests");
1688 0 : MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || mSeekPromise.IsEmpty(),
1689 : "No sample requests allowed while seeking");
1690 0 : MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking()
1691 : || !mAudio.mSeekRequest.Exists()
1692 : || mAudio.mTimeThreshold.isSome());
1693 0 : MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || !IsSeeking(), "called mid-seek");
1694 0 : LOGV("");
1695 :
1696 0 : if (!HasAudio()) {
1697 0 : LOG("called with no audio track");
1698 : return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
1699 0 : __func__);
1700 : }
1701 :
1702 0 : if (IsSeeking()) {
1703 0 : LOG("called mid-seek. Rejecting.");
1704 : return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
1705 0 : __func__);
1706 : }
1707 :
1708 0 : if (mShutdown) {
1709 0 : NS_WARNING("RequestAudioData on shutdown MediaFormatReader!");
1710 : return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
1711 0 : __func__);
1712 : }
1713 :
1714 0 : RefPtr<AudioDataPromise> p = mAudio.EnsurePromise(__func__);
1715 0 : ScheduleUpdate(TrackInfo::kAudioTrack);
1716 :
1717 0 : return p;
1718 : }
1719 :
1720 : void
1721 0 : MediaFormatReader::DoDemuxAudio()
1722 : {
1723 : using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
1724 :
1725 0 : auto p = mAudio.mTrackDemuxer->GetSamples(1);
1726 :
1727 0 : if (mAudio.mFirstDemuxedSampleTime.isNothing()) {
1728 0 : RefPtr<MediaFormatReader> self = this;
1729 0 : p = p->Then(OwnerThread(), __func__,
1730 0 : [self] (RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
1731 0 : self->OnFirstDemuxCompleted(TrackInfo::kAudioTrack, aSamples);
1732 0 : return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
1733 : },
1734 0 : [self] (const MediaResult& aError) {
1735 0 : self->OnFirstDemuxFailed(TrackInfo::kAudioTrack, aError);
1736 0 : return SamplesPromise::CreateAndReject(aError, __func__);
1737 0 : });
1738 : }
1739 :
1740 0 : p->Then(OwnerThread(), __func__, this,
1741 : &MediaFormatReader::OnAudioDemuxCompleted,
1742 : &MediaFormatReader::OnAudioDemuxFailed)
1743 0 : ->Track(mAudio.mDemuxRequest);
1744 0 : }
1745 :
1746 : void
1747 0 : MediaFormatReader::OnAudioDemuxCompleted(
1748 : RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
1749 : {
1750 0 : LOGV("%" PRIuSIZE " audio samples demuxed (sid:%d)",
1751 : aSamples->mSamples.Length(),
1752 : aSamples->mSamples[0]->mTrackInfo
1753 : ? aSamples->mSamples[0]->mTrackInfo->GetID()
1754 : : 0);
1755 0 : mAudio.mDemuxRequest.Complete();
1756 0 : mAudio.mQueuedSamples.AppendElements(aSamples->mSamples);
1757 0 : ScheduleUpdate(TrackInfo::kAudioTrack);
1758 0 : }
1759 :
1760 : void
1761 0 : MediaFormatReader::NotifyNewOutput(
1762 : TrackType aTrack, const MediaDataDecoder::DecodedData& aResults)
1763 : {
1764 0 : MOZ_ASSERT(OnTaskQueue());
1765 0 : auto& decoder = GetDecoderData(aTrack);
1766 0 : for (auto& sample : aResults) {
1767 0 : LOGV("Received new %s sample time:%" PRId64 " duration:%" PRId64,
1768 : TrackTypeToStr(aTrack), sample->mTime.ToMicroseconds(),
1769 : sample->mDuration.ToMicroseconds());
1770 0 : decoder.mOutput.AppendElement(sample);
1771 0 : decoder.mNumSamplesOutput++;
1772 0 : decoder.mNumOfConsecutiveError = 0;
1773 : }
1774 0 : LOG("Done processing new %s samples", TrackTypeToStr(aTrack));
1775 :
1776 0 : if (!aResults.IsEmpty()) {
1777 : // We have decoded our first frame, we can now starts to skip future errors.
1778 0 : decoder.mFirstFrameTime.reset();
1779 : }
1780 0 : ScheduleUpdate(aTrack);
1781 0 : }
1782 :
1783 : void
1784 0 : MediaFormatReader::NotifyError(TrackType aTrack, const MediaResult& aError)
1785 : {
1786 0 : MOZ_ASSERT(OnTaskQueue());
1787 0 : NS_WARNING(aError.Description().get());
1788 0 : LOGV("%s Decoding error", TrackTypeToStr(aTrack));
1789 0 : auto& decoder = GetDecoderData(aTrack);
1790 0 : decoder.mError = decoder.HasFatalError() ? decoder.mError : Some(aError);
1791 0 : ScheduleUpdate(aTrack);
1792 0 : }
1793 :
1794 : void
1795 0 : MediaFormatReader::NotifyWaitingForData(TrackType aTrack)
1796 : {
1797 0 : MOZ_ASSERT(OnTaskQueue());
1798 0 : auto& decoder = GetDecoderData(aTrack);
1799 0 : decoder.mWaitingForData = true;
1800 0 : if (decoder.mTimeThreshold) {
1801 0 : decoder.mTimeThreshold.ref().mWaiting = true;
1802 : }
1803 0 : ScheduleUpdate(aTrack);
1804 0 : }
1805 :
1806 : void
1807 0 : MediaFormatReader::NotifyWaitingForKey(TrackType aTrack)
1808 : {
1809 0 : MOZ_ASSERT(OnTaskQueue());
1810 0 : auto& decoder = GetDecoderData(aTrack);
1811 0 : if (mDecoder) {
1812 0 : mDecoder->NotifyWaitingForKey();
1813 : }
1814 0 : if (!decoder.mDecodeRequest.Exists()) {
1815 0 : LOGV("WaitingForKey received while no pending decode. Ignoring");
1816 0 : return;
1817 : }
1818 0 : decoder.mWaitingForKey = true;
1819 0 : ScheduleUpdate(aTrack);
1820 : }
1821 :
1822 : void
1823 0 : MediaFormatReader::NotifyEndOfStream(TrackType aTrack)
1824 : {
1825 0 : MOZ_ASSERT(OnTaskQueue());
1826 0 : auto& decoder = GetDecoderData(aTrack);
1827 0 : decoder.mDemuxEOS = true;
1828 0 : ScheduleUpdate(aTrack);
1829 0 : }
1830 :
1831 : bool
1832 0 : MediaFormatReader::NeedInput(DecoderData& aDecoder)
1833 : {
1834 : // The decoder will not be fed a new raw sample until the current decoding
1835 : // requests has completed.
1836 : return
1837 0 : (aDecoder.HasPromise() || aDecoder.mTimeThreshold.isSome())
1838 0 : && !aDecoder.HasPendingDrain()
1839 0 : && !aDecoder.HasFatalError()
1840 0 : && !aDecoder.mDemuxRequest.Exists()
1841 0 : && !aDecoder.mOutput.Length()
1842 0 : && !aDecoder.HasInternalSeekPending()
1843 0 : && !aDecoder.mDecodeRequest.Exists();
1844 : }
1845 :
1846 : void
1847 0 : MediaFormatReader::ScheduleUpdate(TrackType aTrack)
1848 : {
1849 0 : MOZ_ASSERT(OnTaskQueue());
1850 0 : if (mShutdown) {
1851 0 : return;
1852 : }
1853 0 : auto& decoder = GetDecoderData(aTrack);
1854 0 : if (decoder.mUpdateScheduled) {
1855 0 : return;
1856 : }
1857 0 : LOGV("SchedulingUpdate(%s)", TrackTypeToStr(aTrack));
1858 0 : decoder.mUpdateScheduled = true;
1859 0 : RefPtr<nsIRunnable> task(NewRunnableMethod<TrackType>(
1860 0 : "MediaFormatReader::Update", this, &MediaFormatReader::Update, aTrack));
1861 0 : OwnerThread()->Dispatch(task.forget());
1862 : }
1863 :
1864 : bool
1865 0 : MediaFormatReader::UpdateReceivedNewData(TrackType aTrack)
1866 : {
1867 0 : MOZ_ASSERT(OnTaskQueue());
1868 0 : auto& decoder = GetDecoderData(aTrack);
1869 :
1870 0 : if (!decoder.mReceivedNewData) {
1871 0 : return false;
1872 : }
1873 :
1874 : // We do not want to clear mWaitingForData while there are pending
1875 : // demuxing or seeking operations that could affect the value of this flag.
1876 : // This is in order to ensure that we will retry once they complete as we may
1877 : // now have new data that could potentially allow those operations to
1878 : // successfully complete if tried again.
1879 0 : if (decoder.mSeekRequest.Exists()) {
1880 : // Nothing more to do until this operation complete.
1881 0 : return true;
1882 : }
1883 :
1884 0 : if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) {
1885 0 : LOGV("Skipping in progress, nothing more to do");
1886 0 : return true;
1887 : }
1888 :
1889 0 : if (decoder.mDemuxRequest.Exists()) {
1890 : // We may have pending operations to process, so we want to continue
1891 : // after UpdateReceivedNewData returns.
1892 0 : return false;
1893 : }
1894 :
1895 0 : if (decoder.HasPendingDrain()) {
1896 : // We do not want to clear mWaitingForData or mDemuxEOS while
1897 : // a drain is in progress in order to properly complete the operation.
1898 0 : return false;
1899 : }
1900 :
1901 0 : decoder.mReceivedNewData = false;
1902 0 : if (decoder.mTimeThreshold) {
1903 0 : decoder.mTimeThreshold.ref().mWaiting = false;
1904 : }
1905 0 : decoder.mWaitingForData = false;
1906 :
1907 0 : if (decoder.HasFatalError()) {
1908 0 : return false;
1909 : }
1910 :
1911 0 : if (!mSeekPromise.IsEmpty()
1912 0 : && (!IsVideoSeeking() || aTrack == TrackInfo::kVideoTrack)) {
1913 0 : MOZ_ASSERT(!decoder.HasPromise());
1914 0 : MOZ_DIAGNOSTIC_ASSERT(
1915 : (IsVideoSeeking() || !mAudio.mTimeThreshold) && !mVideo.mTimeThreshold,
1916 : "InternalSeek must have been aborted when Seek was first called");
1917 0 : MOZ_DIAGNOSTIC_ASSERT(
1918 : (IsVideoSeeking() || !mAudio.HasWaitingPromise())
1919 : && !mVideo.HasWaitingPromise(),
1920 : "Waiting promises must have been rejected when Seek was first called");
1921 0 : if (mVideo.mSeekRequest.Exists()
1922 0 : || (!IsVideoSeeking() && mAudio.mSeekRequest.Exists())) {
1923 : // Already waiting for a seek to complete. Nothing more to do.
1924 0 : return true;
1925 : }
1926 0 : LOG("Attempting Seek");
1927 0 : ScheduleSeek();
1928 0 : return true;
1929 : }
1930 0 : if (decoder.HasInternalSeekPending() || decoder.HasWaitingPromise()) {
1931 0 : if (decoder.HasInternalSeekPending()) {
1932 0 : LOG("Attempting Internal Seek");
1933 0 : InternalSeek(aTrack, decoder.mTimeThreshold.ref());
1934 : }
1935 0 : if (decoder.HasWaitingPromise() && !decoder.IsWaiting()) {
1936 0 : MOZ_ASSERT(!decoder.HasPromise());
1937 0 : LOG("We have new data. Resolving WaitingPromise");
1938 0 : decoder.mWaitingPromise.Resolve(decoder.mType, __func__);
1939 : }
1940 0 : return true;
1941 : }
1942 0 : return false;
1943 : }
1944 :
1945 : void
1946 0 : MediaFormatReader::RequestDemuxSamples(TrackType aTrack)
1947 : {
1948 0 : MOZ_ASSERT(OnTaskQueue());
1949 0 : auto& decoder = GetDecoderData(aTrack);
1950 0 : MOZ_ASSERT(!decoder.mDemuxRequest.Exists());
1951 :
1952 0 : if (!decoder.mQueuedSamples.IsEmpty()) {
1953 : // No need to demux new samples.
1954 0 : return;
1955 : }
1956 :
1957 0 : if (decoder.mDemuxEOS) {
1958 : // Nothing left to demux.
1959 : // We do not want to attempt to demux while in waiting for data mode
1960 : // as it would retrigger an unecessary drain.
1961 0 : return;
1962 : }
1963 :
1964 0 : LOGV("Requesting extra demux %s", TrackTypeToStr(aTrack));
1965 0 : if (aTrack == TrackInfo::kVideoTrack) {
1966 0 : DoDemuxVideo();
1967 : } else {
1968 0 : DoDemuxAudio();
1969 : }
1970 : }
1971 :
1972 : void
1973 0 : MediaFormatReader::DecodeDemuxedSamples(TrackType aTrack,
1974 : MediaRawData* aSample)
1975 : {
1976 0 : MOZ_ASSERT(OnTaskQueue());
1977 0 : auto& decoder = GetDecoderData(aTrack);
1978 0 : RefPtr<MediaFormatReader> self = this;
1979 0 : decoder.mFlushed = false;
1980 0 : decoder.mDecoder->Decode(aSample)
1981 0 : ->Then(mTaskQueue, __func__,
1982 0 : [self, this, aTrack, &decoder]
1983 0 : (const MediaDataDecoder::DecodedData& aResults) {
1984 0 : decoder.mDecodeRequest.Complete();
1985 0 : NotifyNewOutput(aTrack, aResults);
1986 0 : },
1987 0 : [self, this, aTrack, &decoder](const MediaResult& aError) {
1988 0 : decoder.mDecodeRequest.Complete();
1989 0 : NotifyError(aTrack, aError);
1990 0 : })
1991 0 : ->Track(decoder.mDecodeRequest);
1992 0 : }
1993 :
1994 : void
1995 0 : MediaFormatReader::HandleDemuxedSamples(
1996 : TrackType aTrack, AbstractMediaDecoder::AutoNotifyDecoded& aA)
1997 : {
1998 0 : MOZ_ASSERT(OnTaskQueue());
1999 :
2000 0 : auto& decoder = GetDecoderData(aTrack);
2001 :
2002 0 : if (decoder.mFlushing) {
2003 0 : LOGV("Decoder operation in progress, let it complete.");
2004 0 : return;
2005 : }
2006 :
2007 0 : if (decoder.mQueuedSamples.IsEmpty()) {
2008 0 : return;
2009 : }
2010 :
2011 0 : if (!decoder.mDecoder) {
2012 0 : mDecoderFactory->CreateDecoder(aTrack);
2013 0 : return;
2014 : }
2015 :
2016 0 : LOGV("Giving %s input to decoder", TrackTypeToStr(aTrack));
2017 :
2018 : // Decode all our demuxed frames.
2019 0 : while (decoder.mQueuedSamples.Length()) {
2020 0 : RefPtr<MediaRawData> sample = decoder.mQueuedSamples[0];
2021 0 : RefPtr<TrackInfoSharedPtr> info = sample->mTrackInfo;
2022 :
2023 0 : if (info && decoder.mLastStreamSourceID != info->GetID()) {
2024 0 : bool recyclable = MediaPrefs::MediaDecoderCheckRecycling()
2025 0 : && decoder.mDecoder->SupportDecoderRecycling();
2026 0 : if (!recyclable
2027 0 : && decoder.mTimeThreshold.isNothing()
2028 0 : && (decoder.mNextStreamSourceID.isNothing()
2029 0 : || decoder.mNextStreamSourceID.ref() != info->GetID())) {
2030 0 : LOG("%s stream id has changed from:%d to:%d, draining decoder.",
2031 : TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
2032 : info->GetID());
2033 0 : decoder.RequestDrain();
2034 0 : decoder.mNextStreamSourceID = Some(info->GetID());
2035 0 : ScheduleUpdate(aTrack);
2036 0 : return;
2037 : }
2038 :
2039 0 : LOG("%s stream id has changed from:%d to:%d.",
2040 : TrackTypeToStr(aTrack), decoder.mLastStreamSourceID,
2041 : info->GetID());
2042 0 : decoder.mLastStreamSourceID = info->GetID();
2043 0 : decoder.mNextStreamSourceID.reset();
2044 :
2045 0 : if (!recyclable) {
2046 0 : LOG("Decoder does not support recycling, recreate decoder.");
2047 : // If flushing is required, it will clear our array of queued samples.
2048 : // So make a copy now.
2049 0 : nsTArray<RefPtr<MediaRawData>> samples{ Move(decoder.mQueuedSamples) };
2050 0 : ShutdownDecoder(aTrack);
2051 0 : if (sample->mKeyframe) {
2052 0 : decoder.mQueuedSamples.AppendElements(Move(samples));
2053 : }
2054 0 : } else if (decoder.HasWaitingPromise()) {
2055 0 : decoder.Flush();
2056 : }
2057 :
2058 0 : decoder.mInfo = info;
2059 :
2060 0 : if (sample->mKeyframe) {
2061 0 : ScheduleUpdate(aTrack);
2062 : } else {
2063 0 : auto time = TimeInterval(sample->mTime, sample->GetEndTime());
2064 : InternalSeekTarget seekTarget =
2065 0 : decoder.mTimeThreshold.refOr(InternalSeekTarget(time, false));
2066 0 : LOG("Stream change occurred on a non-keyframe. Seeking to:%" PRId64,
2067 : sample->mTime.ToMicroseconds());
2068 0 : InternalSeek(aTrack, seekTarget);
2069 : }
2070 0 : return;
2071 : }
2072 :
2073 0 : LOGV("Input:%" PRId64 " (dts:%" PRId64 " kf:%d)",
2074 : sample->mTime.ToMicroseconds(), sample->mTimecode.ToMicroseconds(),
2075 : sample->mKeyframe);
2076 0 : decoder.mNumSamplesInput++;
2077 0 : decoder.mSizeOfQueue++;
2078 0 : if (aTrack == TrackInfo::kVideoTrack) {
2079 0 : aA.mStats.mParsedFrames++;
2080 : }
2081 :
2082 0 : DecodeDemuxedSamples(aTrack, sample);
2083 :
2084 0 : decoder.mQueuedSamples.RemoveElementAt(0);
2085 0 : break;
2086 : }
2087 : }
2088 :
2089 : void
2090 0 : MediaFormatReader::InternalSeek(TrackType aTrack,
2091 : const InternalSeekTarget& aTarget)
2092 : {
2093 0 : MOZ_ASSERT(OnTaskQueue());
2094 0 : LOG("%s internal seek to %f",
2095 : TrackTypeToStr(aTrack), aTarget.Time().ToSeconds());
2096 :
2097 0 : auto& decoder = GetDecoderData(aTrack);
2098 0 : decoder.Flush();
2099 0 : decoder.ResetDemuxer();
2100 0 : decoder.mTimeThreshold = Some(aTarget);
2101 0 : RefPtr<MediaFormatReader> self = this;
2102 0 : decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().Time())
2103 0 : ->Then(OwnerThread(), __func__,
2104 0 : [self, aTrack] (TimeUnit aTime) {
2105 0 : auto& decoder = self->GetDecoderData(aTrack);
2106 0 : decoder.mSeekRequest.Complete();
2107 0 : MOZ_ASSERT(
2108 : decoder.mTimeThreshold,
2109 : "Seek promise must be disconnected when timethreshold is reset");
2110 0 : decoder.mTimeThreshold.ref().mHasSeeked = true;
2111 0 : self->SetVideoDecodeThreshold();
2112 0 : self->ScheduleUpdate(aTrack);
2113 0 : },
2114 0 : [self, aTrack] (const MediaResult& aError) {
2115 0 : auto& decoder = self->GetDecoderData(aTrack);
2116 0 : decoder.mSeekRequest.Complete();
2117 0 : switch (aError.Code()) {
2118 : case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
2119 0 : self->NotifyWaitingForData(aTrack);
2120 0 : break;
2121 : case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
2122 0 : decoder.mTimeThreshold.reset();
2123 0 : self->NotifyEndOfStream(aTrack);
2124 0 : break;
2125 : case NS_ERROR_DOM_MEDIA_CANCELED:
2126 0 : decoder.mTimeThreshold.reset();
2127 0 : break;
2128 : default:
2129 0 : decoder.mTimeThreshold.reset();
2130 0 : self->NotifyError(aTrack, aError);
2131 0 : break;
2132 : }
2133 0 : })
2134 0 : ->Track(decoder.mSeekRequest);
2135 0 : }
2136 :
2137 : void
2138 0 : MediaFormatReader::DrainDecoder(TrackType aTrack)
2139 : {
2140 0 : MOZ_ASSERT(OnTaskQueue());
2141 :
2142 0 : auto& decoder = GetDecoderData(aTrack);
2143 0 : if (decoder.mDrainState == DrainState::Draining) {
2144 0 : return;
2145 : }
2146 0 : if (!decoder.mDecoder
2147 0 : || (decoder.mDrainState != DrainState::PartialDrainPending
2148 0 : && decoder.mNumSamplesInput == decoder.mNumSamplesOutput)) {
2149 : // No frames to drain.
2150 0 : LOGV("Draining %s with nothing to drain", TrackTypeToStr(aTrack));
2151 0 : decoder.mDrainState = DrainState::DrainAborted;
2152 0 : ScheduleUpdate(aTrack);
2153 0 : return;
2154 : }
2155 :
2156 0 : decoder.mDrainState = DrainState::Draining;
2157 :
2158 0 : RefPtr<MediaFormatReader> self = this;
2159 0 : decoder.mDecoder->Drain()
2160 0 : ->Then(mTaskQueue, __func__,
2161 0 : [self, this, aTrack, &decoder]
2162 0 : (const MediaDataDecoder::DecodedData& aResults) {
2163 0 : decoder.mDrainRequest.Complete();
2164 0 : if (aResults.IsEmpty()) {
2165 0 : decoder.mDrainState = DrainState::DrainCompleted;
2166 : } else {
2167 0 : NotifyNewOutput(aTrack, aResults);
2168 : // Let's see if we have any more data available to drain.
2169 0 : decoder.mDrainState = DrainState::PartialDrainPending;
2170 : }
2171 0 : ScheduleUpdate(aTrack);
2172 0 : },
2173 0 : [self, this, aTrack, &decoder](const MediaResult& aError) {
2174 0 : decoder.mDrainRequest.Complete();
2175 0 : NotifyError(aTrack, aError);
2176 0 : })
2177 0 : ->Track(decoder.mDrainRequest);
2178 0 : LOG("Requesting %s decoder to drain", TrackTypeToStr(aTrack));
2179 : }
2180 :
2181 : void
2182 0 : MediaFormatReader::Update(TrackType aTrack)
2183 : {
2184 0 : MOZ_ASSERT(OnTaskQueue());
2185 :
2186 0 : if (mShutdown) {
2187 0 : return;
2188 : }
2189 :
2190 0 : LOGV("Processing update for %s", TrackTypeToStr(aTrack));
2191 :
2192 0 : bool needOutput = false;
2193 0 : auto& decoder = GetDecoderData(aTrack);
2194 0 : decoder.mUpdateScheduled = false;
2195 :
2196 0 : if (!mInitDone) {
2197 0 : return;
2198 : }
2199 :
2200 0 : if (aTrack == TrackType::kVideoTrack && mSkipRequest.Exists()) {
2201 0 : LOGV("Skipping in progress, nothing more to do");
2202 0 : return;
2203 : }
2204 :
2205 0 : if (UpdateReceivedNewData(aTrack)) {
2206 0 : LOGV("Nothing more to do");
2207 0 : return;
2208 : }
2209 :
2210 0 : if (decoder.mSeekRequest.Exists()) {
2211 0 : LOGV("Seeking hasn't completed, nothing more to do");
2212 0 : return;
2213 : }
2214 :
2215 0 : MOZ_DIAGNOSTIC_ASSERT(
2216 : !decoder.HasInternalSeekPending()
2217 : || (!decoder.mOutput.Length() && !decoder.mQueuedSamples.Length()),
2218 : "No frames can be demuxed or decoded while an internal seek is pending");
2219 :
2220 : // Record number of frames decoded and parsed. Automatically update the
2221 : // stats counters using the AutoNotifyDecoded stack-based class.
2222 0 : AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder);
2223 :
2224 : // Drop any frames found prior our internal seek target.
2225 0 : while (decoder.mTimeThreshold && decoder.mOutput.Length()) {
2226 0 : RefPtr<MediaData>& output = decoder.mOutput[0];
2227 0 : InternalSeekTarget target = decoder.mTimeThreshold.ref();
2228 0 : auto time = output->mTime;
2229 0 : if (time >= target.Time()) {
2230 : // We have reached our internal seek target.
2231 0 : decoder.mTimeThreshold.reset();
2232 : // We might have dropped some keyframes.
2233 0 : mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe;
2234 : }
2235 0 : if (time < target.Time() || (target.mDropTarget && target.Contains(time))) {
2236 0 : LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)",
2237 : TrackTypeToStr(aTrack),
2238 : output->mTime.ToSeconds(),
2239 : target.Time().ToSeconds(),
2240 : output->mKeyframe);
2241 0 : decoder.mOutput.RemoveElementAt(0);
2242 0 : decoder.mSizeOfQueue -= 1;
2243 : }
2244 : }
2245 :
2246 0 : while (decoder.mOutput.Length()
2247 0 : && decoder.mOutput[0]->mType == MediaData::NULL_DATA) {
2248 0 : LOGV("Dropping null data. Time: %" PRId64,
2249 : decoder.mOutput[0]->mTime.ToMicroseconds());
2250 0 : decoder.mOutput.RemoveElementAt(0);
2251 0 : decoder.mSizeOfQueue -= 1;
2252 : }
2253 :
2254 0 : if (decoder.HasPromise()) {
2255 0 : needOutput = true;
2256 0 : if (decoder.mOutput.Length()) {
2257 0 : RefPtr<MediaData> output = decoder.mOutput[0];
2258 0 : decoder.mOutput.RemoveElementAt(0);
2259 0 : decoder.mSizeOfQueue -= 1;
2260 : decoder.mLastDecodedSampleTime =
2261 0 : Some(TimeInterval(output->mTime, output->GetEndTime()));
2262 0 : decoder.mNumSamplesOutputTotal++;
2263 0 : ReturnOutput(output, aTrack);
2264 : // We have a decoded sample ready to be returned.
2265 0 : if (aTrack == TrackType::kVideoTrack) {
2266 : uint64_t delta =
2267 0 : decoder.mNumSamplesOutputTotal - mLastReportedNumDecodedFrames;
2268 0 : a.mStats.mDecodedFrames = static_cast<uint32_t>(delta);
2269 0 : mLastReportedNumDecodedFrames = decoder.mNumSamplesOutputTotal;
2270 0 : if (output->mKeyframe) {
2271 0 : if (mPreviousDecodedKeyframeTime_us < output->mTime.ToMicroseconds()) {
2272 : // There is a previous keyframe -> Record inter-keyframe stats.
2273 : uint64_t segment_us =
2274 0 : output->mTime.ToMicroseconds() - mPreviousDecodedKeyframeTime_us;
2275 0 : a.mStats.mInterKeyframeSum_us += segment_us;
2276 0 : a.mStats.mInterKeyframeCount += 1;
2277 0 : if (a.mStats.mInterKeyFrameMax_us < segment_us) {
2278 0 : a.mStats.mInterKeyFrameMax_us = segment_us;
2279 : }
2280 : }
2281 0 : mPreviousDecodedKeyframeTime_us = output->mTime.ToMicroseconds();
2282 : }
2283 0 : nsCString error;
2284 0 : mVideo.mIsHardwareAccelerated =
2285 0 : mVideo.mDecoder && mVideo.mDecoder->IsHardwareAccelerated(error);
2286 : #ifdef XP_WIN
2287 : // D3D11_YCBCR_IMAGE images are GPU based, we try to limit the amount
2288 : // of GPU RAM used.
2289 : VideoData* videoData = static_cast<VideoData*>(output.get());
2290 : mVideo.mIsHardwareAccelerated =
2291 : mVideo.mIsHardwareAccelerated ||
2292 : (videoData->mImage &&
2293 : videoData->mImage->GetFormat() == ImageFormat::D3D11_YCBCR_IMAGE);
2294 : #endif
2295 : }
2296 0 : } else if (decoder.HasFatalError()) {
2297 0 : LOG("Rejecting %s promise: DECODE_ERROR", TrackTypeToStr(aTrack));
2298 0 : decoder.RejectPromise(decoder.mError.ref(), __func__);
2299 0 : return;
2300 0 : } else if (decoder.HasCompletedDrain()) {
2301 0 : if (decoder.mDemuxEOS) {
2302 0 : LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
2303 0 : decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
2304 0 : } else if (decoder.mWaitingForData) {
2305 0 : if (decoder.mDrainState == DrainState::DrainCompleted
2306 0 : && decoder.mLastDecodedSampleTime
2307 0 : && !decoder.mNextStreamSourceID) {
2308 : // We have completed draining the decoder following WaitingForData.
2309 : // Set up the internal seek machinery to be able to resume from the
2310 : // last sample decoded.
2311 0 : LOG("Seeking to last sample time: %" PRId64,
2312 : decoder.mLastDecodedSampleTime.ref().mStart.ToMicroseconds());
2313 : InternalSeek(aTrack,
2314 0 : InternalSeekTarget(decoder.mLastDecodedSampleTime.ref(), true));
2315 : }
2316 0 : if (!decoder.mReceivedNewData) {
2317 0 : LOG("Rejecting %s promise: WAITING_FOR_DATA", TrackTypeToStr(aTrack));
2318 0 : decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
2319 : }
2320 : }
2321 :
2322 0 : decoder.mDrainState = DrainState::None;
2323 :
2324 : // Now that draining has completed, we check if we have received
2325 : // new data again as the result may now be different from the earlier
2326 : // run.
2327 0 : if (UpdateReceivedNewData(aTrack) || decoder.mSeekRequest.Exists()) {
2328 0 : LOGV("Nothing more to do");
2329 0 : return;
2330 : }
2331 0 : } else if (decoder.mDemuxEOS
2332 0 : && !decoder.HasPendingDrain()
2333 0 : && decoder.mQueuedSamples.IsEmpty()) {
2334 : // It is possible to transition from WAITING_FOR_DATA directly to EOS
2335 : // state during the internal seek; in which case no draining would occur.
2336 : // There is no more samples left to be decoded and we are already in
2337 : // EOS state. We can immediately reject the data promise.
2338 0 : LOG("Rejecting %s promise: EOS", TrackTypeToStr(aTrack));
2339 0 : decoder.RejectPromise(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__);
2340 0 : } else if (decoder.mWaitingForKey) {
2341 0 : LOG("Rejecting %s promise: WAITING_FOR_DATA due to waiting for key",
2342 : TrackTypeToStr(aTrack));
2343 0 : decoder.RejectPromise(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
2344 : }
2345 : }
2346 :
2347 0 : if (decoder.mDrainState == DrainState::DrainRequested
2348 0 : || decoder.mDrainState == DrainState::PartialDrainPending) {
2349 0 : if (decoder.mOutput.IsEmpty()) {
2350 0 : DrainDecoder(aTrack);
2351 : }
2352 0 : return;
2353 : }
2354 :
2355 0 : if (decoder.mError && !decoder.HasFatalError()) {
2356 0 : MOZ_RELEASE_ASSERT(!decoder.HasInternalSeekPending(),
2357 : "No error can occur while an internal seek is pending");
2358 : bool needsNewDecoder =
2359 0 : decoder.mError.ref() == NS_ERROR_DOM_MEDIA_NEED_NEW_DECODER;
2360 0 : if (!needsNewDecoder
2361 0 : && ++decoder.mNumOfConsecutiveError > decoder.mMaxConsecutiveError) {
2362 0 : NotifyError(aTrack, decoder.mError.ref());
2363 0 : return;
2364 : }
2365 0 : decoder.mError.reset();
2366 :
2367 0 : LOG("%s decoded error count %d", TrackTypeToStr(aTrack),
2368 : decoder.mNumOfConsecutiveError);
2369 :
2370 0 : if (needsNewDecoder) {
2371 0 : LOG("Error: Need new decoder");
2372 0 : ShutdownDecoder(aTrack);
2373 : }
2374 0 : if (decoder.mFirstFrameTime) {
2375 : TimeInterval seekInterval = TimeInterval(decoder.mFirstFrameTime.ref(),
2376 0 : decoder.mFirstFrameTime.ref());
2377 0 : InternalSeek(aTrack, InternalSeekTarget(seekInterval, false));
2378 0 : return;
2379 : }
2380 :
2381 0 : TimeUnit nextKeyframe;
2382 0 : if (aTrack == TrackType::kVideoTrack &&
2383 0 : NS_SUCCEEDED(
2384 0 : decoder.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe)) &&
2385 0 : !nextKeyframe.IsInfinite()) {
2386 0 : SkipVideoDemuxToNextKeyFrame(
2387 0 : decoder.mLastDecodedSampleTime.refOr(TimeInterval()).Length());
2388 0 : } else if (aTrack == TrackType::kAudioTrack) {
2389 0 : decoder.Flush();
2390 : } else {
2391 : // We can't recover from this error.
2392 0 : NotifyError(aTrack, NS_ERROR_DOM_MEDIA_FATAL_ERR);
2393 : }
2394 0 : return;
2395 : }
2396 :
2397 0 : bool needInput = NeedInput(decoder);
2398 :
2399 0 : LOGV("Update(%s) ni=%d no=%d in:%" PRIu64 " out:%" PRIu64
2400 : " qs=%u decoding:%d flushing:%d desc:%s pending:%u waiting:%d eos:%d "
2401 : "ds:%d sid:%u",
2402 : TrackTypeToStr(aTrack),
2403 : needInput,
2404 : needOutput,
2405 : decoder.mNumSamplesInput,
2406 : decoder.mNumSamplesOutput,
2407 : uint32_t(size_t(decoder.mSizeOfQueue)),
2408 : decoder.mDecodeRequest.Exists(),
2409 : decoder.mFlushing,
2410 : decoder.mDescription,
2411 : uint32_t(decoder.mOutput.Length()),
2412 : decoder.mWaitingForData,
2413 : decoder.mDemuxEOS,
2414 : int32_t(decoder.mDrainState),
2415 : decoder.mLastStreamSourceID);
2416 :
2417 0 : if ((decoder.mWaitingForData
2418 0 : && (!decoder.mTimeThreshold || decoder.mTimeThreshold.ref().mWaiting))
2419 0 : || (decoder.mWaitingForKey && decoder.mDecodeRequest.Exists())) {
2420 : // Nothing more we can do at present.
2421 0 : LOGV("Still waiting for data or key.");
2422 0 : return;
2423 : }
2424 :
2425 0 : if (decoder.CancelWaitingForKey()) {
2426 0 : LOGV("No longer waiting for key. Resolving waiting promise");
2427 0 : return;
2428 : }
2429 :
2430 0 : if (!needInput) {
2431 0 : LOGV("No need for additional input (pending:%u)",
2432 : uint32_t(decoder.mOutput.Length()));
2433 0 : return;
2434 : }
2435 :
2436 : // Demux samples if we don't have some.
2437 0 : RequestDemuxSamples(aTrack);
2438 :
2439 0 : HandleDemuxedSamples(aTrack, a);
2440 : }
2441 :
2442 : void
2443 0 : MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack)
2444 : {
2445 0 : MOZ_ASSERT(GetDecoderData(aTrack).HasPromise());
2446 0 : MOZ_DIAGNOSTIC_ASSERT(aData->mType != MediaData::NULL_DATA);
2447 0 : LOG("Resolved data promise for %s [%" PRId64 ", %" PRId64 "]", TrackTypeToStr(aTrack),
2448 : aData->mTime.ToMicroseconds(), aData->GetEndTime().ToMicroseconds());
2449 :
2450 0 : if (aTrack == TrackInfo::kAudioTrack) {
2451 0 : AudioData* audioData = static_cast<AudioData*>(aData);
2452 :
2453 0 : if (audioData->mChannels != mInfo.mAudio.mChannels
2454 0 : || audioData->mRate != mInfo.mAudio.mRate) {
2455 0 : LOG("change of audio format (rate:%d->%d). "
2456 : "This is an unsupported configuration",
2457 : mInfo.mAudio.mRate, audioData->mRate);
2458 0 : mInfo.mAudio.mRate = audioData->mRate;
2459 0 : mInfo.mAudio.mChannels = audioData->mChannels;
2460 : }
2461 0 : mAudio.ResolvePromise(audioData, __func__);
2462 0 : } else if (aTrack == TrackInfo::kVideoTrack) {
2463 0 : VideoData* videoData = static_cast<VideoData*>(aData);
2464 :
2465 0 : if (videoData->mDisplay != mInfo.mVideo.mDisplay) {
2466 0 : LOG("change of video display size (%dx%d->%dx%d)",
2467 : mInfo.mVideo.mDisplay.width, mInfo.mVideo.mDisplay.height,
2468 : videoData->mDisplay.width, videoData->mDisplay.height);
2469 0 : mInfo.mVideo.mDisplay = videoData->mDisplay;
2470 : }
2471 0 : mVideo.ResolvePromise(videoData, __func__);
2472 : }
2473 0 : }
2474 :
2475 : size_t
2476 0 : MediaFormatReader::SizeOfVideoQueueInFrames()
2477 : {
2478 0 : return SizeOfQueue(TrackInfo::kVideoTrack);
2479 : }
2480 :
2481 : size_t
2482 0 : MediaFormatReader::SizeOfAudioQueueInFrames()
2483 : {
2484 0 : return SizeOfQueue(TrackInfo::kAudioTrack);
2485 : }
2486 :
2487 : size_t
2488 0 : MediaFormatReader::SizeOfQueue(TrackType aTrack)
2489 : {
2490 0 : auto& decoder = GetDecoderData(aTrack);
2491 0 : return decoder.mSizeOfQueue;
2492 : }
2493 :
2494 : RefPtr<MediaDecoderReader::WaitForDataPromise>
2495 0 : MediaFormatReader::WaitForData(MediaData::Type aType)
2496 : {
2497 0 : MOZ_ASSERT(OnTaskQueue());
2498 0 : TrackType trackType = aType == MediaData::VIDEO_DATA ?
2499 0 : TrackType::kVideoTrack : TrackType::kAudioTrack;
2500 0 : auto& decoder = GetDecoderData(trackType);
2501 0 : if (!decoder.IsWaiting()) {
2502 : // We aren't waiting for anything.
2503 0 : return WaitForDataPromise::CreateAndResolve(decoder.mType, __func__);
2504 : }
2505 0 : RefPtr<WaitForDataPromise> p = decoder.mWaitingPromise.Ensure(__func__);
2506 0 : ScheduleUpdate(trackType);
2507 0 : return p;
2508 : }
2509 :
2510 : nsresult
2511 0 : MediaFormatReader::ResetDecode(TrackSet aTracks)
2512 : {
2513 0 : MOZ_ASSERT(OnTaskQueue());
2514 0 : LOGV("");
2515 :
2516 0 : mSeekPromise.RejectIfExists(NS_OK, __func__);
2517 0 : mSkipRequest.DisconnectIfExists();
2518 :
2519 : // Do the same for any data wait promises.
2520 0 : if (aTracks.contains(TrackInfo::kAudioTrack)) {
2521 0 : mAudio.mWaitingPromise.RejectIfExists(
2522 0 : WaitForDataRejectValue(MediaData::AUDIO_DATA,
2523 0 : WaitForDataRejectValue::CANCELED), __func__);
2524 : }
2525 :
2526 0 : if (aTracks.contains(TrackInfo::kVideoTrack)) {
2527 0 : mVideo.mWaitingPromise.RejectIfExists(
2528 0 : WaitForDataRejectValue(MediaData::VIDEO_DATA,
2529 0 : WaitForDataRejectValue::CANCELED), __func__);
2530 : }
2531 :
2532 : // Reset miscellaneous seeking state.
2533 0 : mPendingSeekTime.reset();
2534 :
2535 0 : if (HasVideo() && aTracks.contains(TrackInfo::kVideoTrack)) {
2536 0 : mVideo.ResetDemuxer();
2537 0 : mVideo.mFirstFrameTime = Some(media::TimeUnit::Zero());
2538 0 : Reset(TrackInfo::kVideoTrack);
2539 0 : if (mVideo.HasPromise()) {
2540 0 : mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
2541 : }
2542 : }
2543 :
2544 0 : if (HasAudio() && aTracks.contains(TrackInfo::kAudioTrack)) {
2545 0 : mAudio.ResetDemuxer();
2546 0 : mVideo.mFirstFrameTime = Some(media::TimeUnit::Zero());
2547 0 : Reset(TrackInfo::kAudioTrack);
2548 0 : if (mAudio.HasPromise()) {
2549 0 : mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
2550 : }
2551 : }
2552 :
2553 0 : return MediaDecoderReader::ResetDecode(aTracks);
2554 : }
2555 :
2556 : void
2557 0 : MediaFormatReader::Reset(TrackType aTrack)
2558 : {
2559 0 : MOZ_ASSERT(OnTaskQueue());
2560 0 : LOG("Reset(%s) BEGIN", TrackTypeToStr(aTrack));
2561 :
2562 0 : auto& decoder = GetDecoderData(aTrack);
2563 :
2564 0 : decoder.ResetState();
2565 0 : decoder.Flush();
2566 :
2567 0 : LOG("Reset(%s) END", TrackTypeToStr(aTrack));
2568 0 : }
2569 :
2570 : void
2571 0 : MediaFormatReader::DropDecodedSamples(TrackType aTrack)
2572 : {
2573 0 : MOZ_ASSERT(OnTaskQueue());
2574 0 : auto& decoder = GetDecoderData(aTrack);
2575 0 : size_t lengthDecodedQueue = decoder.mOutput.Length();
2576 0 : if (lengthDecodedQueue && decoder.mTimeThreshold.isSome()) {
2577 0 : auto time = decoder.mOutput.LastElement()->mTime;
2578 0 : if (time >= decoder.mTimeThreshold.ref().Time()) {
2579 : // We would have reached our internal seek target.
2580 0 : decoder.mTimeThreshold.reset();
2581 : }
2582 : }
2583 0 : decoder.mOutput.Clear();
2584 0 : decoder.mSizeOfQueue -= lengthDecodedQueue;
2585 0 : if (aTrack == TrackInfo::kVideoTrack && mDecoder) {
2586 0 : mDecoder->NotifyDecodedFrames({ 0, 0, lengthDecodedQueue });
2587 : }
2588 0 : }
2589 :
2590 : void
2591 0 : MediaFormatReader::SkipVideoDemuxToNextKeyFrame(TimeUnit aTimeThreshold)
2592 : {
2593 0 : MOZ_ASSERT(OnTaskQueue());
2594 0 : LOG("Skipping up to %" PRId64, aTimeThreshold.ToMicroseconds());
2595 :
2596 : // We've reached SkipVideoDemuxToNextKeyFrame when our decoding is late.
2597 : // As such we can drop all already decoded samples and discard all pending
2598 : // samples.
2599 0 : DropDecodedSamples(TrackInfo::kVideoTrack);
2600 :
2601 0 : mVideo.mTrackDemuxer->SkipToNextRandomAccessPoint(aTimeThreshold)
2602 0 : ->Then(OwnerThread(), __func__, this,
2603 : &MediaFormatReader::OnVideoSkipCompleted,
2604 : &MediaFormatReader::OnVideoSkipFailed)
2605 0 : ->Track(mSkipRequest);
2606 0 : return;
2607 : }
2608 :
2609 : void
2610 0 : MediaFormatReader::VideoSkipReset(uint32_t aSkipped)
2611 : {
2612 0 : MOZ_ASSERT(OnTaskQueue());
2613 :
2614 : // Some frames may have been output by the decoder since we initiated the
2615 : // videoskip process and we know they would be late.
2616 0 : DropDecodedSamples(TrackInfo::kVideoTrack);
2617 : // Report the pending frames as dropped.
2618 0 : if (mDecoder) {
2619 0 : mDecoder->NotifyDecodedFrames({ 0, 0, SizeOfVideoQueueInFrames() });
2620 : }
2621 :
2622 : // Cancel any pending demux request and pending demuxed samples.
2623 0 : mVideo.mDemuxRequest.DisconnectIfExists();
2624 0 : Reset(TrackType::kVideoTrack);
2625 :
2626 0 : if (mDecoder) {
2627 0 : mDecoder->NotifyDecodedFrames({ aSkipped, 0, aSkipped });
2628 : }
2629 :
2630 0 : mVideo.mNumSamplesSkippedTotal += aSkipped;
2631 0 : }
2632 :
2633 : void
2634 0 : MediaFormatReader::OnVideoSkipCompleted(uint32_t aSkipped)
2635 : {
2636 0 : MOZ_ASSERT(OnTaskQueue());
2637 0 : LOG("Skipping succeeded, skipped %u frames", aSkipped);
2638 0 : mSkipRequest.Complete();
2639 :
2640 0 : VideoSkipReset(aSkipped);
2641 :
2642 0 : ScheduleUpdate(TrackInfo::kVideoTrack);
2643 0 : }
2644 :
2645 : void
2646 0 : MediaFormatReader::OnVideoSkipFailed(
2647 : MediaTrackDemuxer::SkipFailureHolder aFailure)
2648 : {
2649 0 : MOZ_ASSERT(OnTaskQueue());
2650 0 : LOG("Skipping failed, skipped %u frames", aFailure.mSkipped);
2651 0 : mSkipRequest.Complete();
2652 :
2653 0 : switch (aFailure.mFailure.Code()) {
2654 : case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
2655 : case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
2656 : // Some frames may have been output by the decoder since we initiated the
2657 : // videoskip process and we know they would be late.
2658 0 : DropDecodedSamples(TrackInfo::kVideoTrack);
2659 : // We can't complete the skip operation, will just service a video frame
2660 : // normally.
2661 0 : ScheduleUpdate(TrackInfo::kVideoTrack);
2662 0 : break;
2663 : case NS_ERROR_DOM_MEDIA_CANCELED:
2664 0 : if (mVideo.HasPromise()) {
2665 0 : mVideo.RejectPromise(aFailure.mFailure, __func__);
2666 : }
2667 0 : break;
2668 : default:
2669 0 : NotifyError(TrackType::kVideoTrack, aFailure.mFailure);
2670 0 : break;
2671 : }
2672 0 : }
2673 :
2674 : RefPtr<MediaDecoderReader::SeekPromise>
2675 0 : MediaFormatReader::Seek(const SeekTarget& aTarget)
2676 : {
2677 0 : MOZ_ASSERT(OnTaskQueue());
2678 :
2679 0 : LOG("aTarget=(%" PRId64 ")", aTarget.GetTime().ToMicroseconds());
2680 :
2681 0 : MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty());
2682 0 : MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise());
2683 0 : MOZ_DIAGNOSTIC_ASSERT(aTarget.IsVideoOnly() || !mAudio.HasPromise());
2684 0 : MOZ_DIAGNOSTIC_ASSERT(mPendingSeekTime.isNothing());
2685 0 : MOZ_DIAGNOSTIC_ASSERT(mVideo.mTimeThreshold.isNothing());
2686 0 : MOZ_DIAGNOSTIC_ASSERT(aTarget.IsVideoOnly()
2687 : || mAudio.mTimeThreshold.isNothing());
2688 :
2689 0 : if (!mInfo.mMediaSeekable && !mInfo.mMediaSeekableOnlyInBufferedRanges) {
2690 0 : LOG("Seek() END (Unseekable)");
2691 0 : return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
2692 : }
2693 :
2694 0 : if (mShutdown) {
2695 0 : return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
2696 : }
2697 :
2698 0 : SetSeekTarget(aTarget);
2699 :
2700 0 : RefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__);
2701 :
2702 0 : ScheduleSeek();
2703 :
2704 0 : return p;
2705 : }
2706 :
2707 : void
2708 0 : MediaFormatReader::SetSeekTarget(const SeekTarget& aTarget)
2709 : {
2710 0 : MOZ_ASSERT(OnTaskQueue());
2711 :
2712 0 : mOriginalSeekTarget = aTarget;
2713 0 : mFallbackSeekTime = mPendingSeekTime = Some(aTarget.GetTime());
2714 0 : }
2715 :
2716 : void
2717 0 : MediaFormatReader::ScheduleSeek()
2718 : {
2719 0 : if (mSeekScheduled) {
2720 0 : return;
2721 : }
2722 0 : mSeekScheduled = true;
2723 0 : OwnerThread()->Dispatch(NewRunnableMethod(
2724 0 : "MediaFormatReader::AttemptSeek", this, &MediaFormatReader::AttemptSeek));
2725 : }
2726 :
2727 : void
2728 0 : MediaFormatReader::AttemptSeek()
2729 : {
2730 0 : MOZ_ASSERT(OnTaskQueue());
2731 :
2732 0 : mSeekScheduled = false;
2733 :
2734 0 : if (mPendingSeekTime.isNothing()) {
2735 0 : return;
2736 : }
2737 :
2738 0 : if (HasVideo()) {
2739 0 : mVideo.ResetDemuxer();
2740 0 : mVideo.ResetState();
2741 : }
2742 :
2743 : // Don't reset the audio demuxer not state when seeking video only
2744 : // as it will cause the audio to seek back to the beginning
2745 : // resulting in out-of-sync audio from video.
2746 0 : if (HasAudio() && !mOriginalSeekTarget.IsVideoOnly()) {
2747 0 : mAudio.ResetDemuxer();
2748 0 : mAudio.ResetState();
2749 : }
2750 :
2751 0 : if (HasVideo()) {
2752 0 : DoVideoSeek();
2753 0 : } else if (HasAudio()) {
2754 0 : DoAudioSeek();
2755 : } else {
2756 0 : MOZ_CRASH();
2757 : }
2758 : }
2759 :
2760 : void
2761 0 : MediaFormatReader::OnSeekFailed(TrackType aTrack, const MediaResult& aError)
2762 : {
2763 0 : MOZ_ASSERT(OnTaskQueue());
2764 0 : LOGV("%s failure:%" PRIu32, TrackTypeToStr(aTrack), static_cast<uint32_t>(aError.Code()));
2765 0 : if (aTrack == TrackType::kVideoTrack) {
2766 0 : mVideo.mSeekRequest.Complete();
2767 : } else {
2768 0 : mAudio.mSeekRequest.Complete();
2769 : }
2770 :
2771 0 : if (aError == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
2772 0 : if (HasVideo()
2773 0 : && aTrack == TrackType::kAudioTrack
2774 0 : && mFallbackSeekTime.isSome()
2775 0 : && mPendingSeekTime.ref() != mFallbackSeekTime.ref()) {
2776 : // We have failed to seek audio where video seeked to earlier.
2777 : // Attempt to seek instead to the closest point that we know we have in
2778 : // order to limit A/V sync discrepency.
2779 :
2780 : // Ensure we have the most up to date buffered ranges.
2781 0 : UpdateReceivedNewData(TrackType::kAudioTrack);
2782 0 : Maybe<TimeUnit> nextSeekTime;
2783 : // Find closest buffered time found after video seeked time.
2784 0 : for (const auto& timeRange : mAudio.mTimeRanges) {
2785 0 : if (timeRange.mStart >= mPendingSeekTime.ref()) {
2786 0 : nextSeekTime.emplace(timeRange.mStart);
2787 0 : break;
2788 : }
2789 : }
2790 0 : if (nextSeekTime.isNothing()
2791 0 : || nextSeekTime.ref() > mFallbackSeekTime.ref()) {
2792 0 : nextSeekTime = Some(mFallbackSeekTime.ref());
2793 0 : LOG("Unable to seek audio to video seek time. A/V sync may be broken");
2794 : } else {
2795 0 : mFallbackSeekTime.reset();
2796 : }
2797 0 : mPendingSeekTime = nextSeekTime;
2798 0 : DoAudioSeek();
2799 0 : return;
2800 : }
2801 0 : NotifyWaitingForData(aTrack);
2802 : }
2803 0 : MOZ_ASSERT(!mVideo.mSeekRequest.Exists() && !mAudio.mSeekRequest.Exists());
2804 0 : mPendingSeekTime.reset();
2805 :
2806 0 : auto type = aTrack == TrackType::kAudioTrack ? MediaData::AUDIO_DATA
2807 0 : : MediaData::VIDEO_DATA;
2808 0 : mSeekPromise.Reject(SeekRejectValue(type, aError), __func__);
2809 : }
2810 :
2811 : void
2812 0 : MediaFormatReader::DoVideoSeek()
2813 : {
2814 0 : MOZ_ASSERT(mPendingSeekTime.isSome());
2815 0 : LOGV("Seeking video to %" PRId64, mPendingSeekTime.ref().ToMicroseconds());
2816 0 : auto seekTime = mPendingSeekTime.ref();
2817 0 : mVideo.mTrackDemuxer->Seek(seekTime)
2818 0 : ->Then(OwnerThread(), __func__, this,
2819 : &MediaFormatReader::OnVideoSeekCompleted,
2820 : &MediaFormatReader::OnVideoSeekFailed)
2821 0 : ->Track(mVideo.mSeekRequest);
2822 0 : }
2823 :
2824 : void
2825 0 : MediaFormatReader::OnVideoSeekCompleted(TimeUnit aTime)
2826 : {
2827 0 : MOZ_ASSERT(OnTaskQueue());
2828 0 : LOGV("Video seeked to %" PRId64, aTime.ToMicroseconds());
2829 0 : mVideo.mSeekRequest.Complete();
2830 :
2831 0 : mVideo.mFirstFrameTime = Some(aTime);
2832 0 : mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe;
2833 :
2834 0 : SetVideoDecodeThreshold();
2835 :
2836 0 : if (HasAudio() && !mOriginalSeekTarget.IsVideoOnly()) {
2837 0 : MOZ_ASSERT(mPendingSeekTime.isSome());
2838 0 : if (mOriginalSeekTarget.IsFast()) {
2839 : // We are performing a fast seek. We need to seek audio to where the
2840 : // video seeked to, to ensure proper A/V sync once playback resume.
2841 0 : mPendingSeekTime = Some(aTime);
2842 : }
2843 0 : DoAudioSeek();
2844 : } else {
2845 0 : mPendingSeekTime.reset();
2846 0 : mSeekPromise.Resolve(aTime, __func__);
2847 : }
2848 0 : }
2849 :
2850 : void
2851 0 : MediaFormatReader::OnVideoSeekFailed(const MediaResult& aError)
2852 : {
2853 0 : mPreviousDecodedKeyframeTime_us = sNoPreviousDecodedKeyframe;
2854 0 : OnSeekFailed(TrackType::kVideoTrack, aError);
2855 0 : }
2856 :
2857 : void
2858 0 : MediaFormatReader::SetVideoDecodeThreshold()
2859 : {
2860 0 : MOZ_ASSERT(OnTaskQueue());
2861 :
2862 0 : if (!HasVideo() || !mVideo.mDecoder) {
2863 0 : return;
2864 : }
2865 :
2866 0 : if (!mVideo.mTimeThreshold && !IsSeeking()) {
2867 0 : return;
2868 : }
2869 :
2870 0 : TimeUnit threshold;
2871 0 : if (mVideo.mTimeThreshold) {
2872 : // For internalSeek.
2873 0 : threshold = mVideo.mTimeThreshold.ref().Time();
2874 0 : } else if (IsSeeking()) {
2875 : // If IsSeeking() is true, then video seek must have completed already.
2876 0 : TimeUnit keyframe;
2877 0 : if (NS_FAILED(mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&keyframe))) {
2878 0 : return;
2879 : }
2880 :
2881 : // If the key frame is invalid/infinite, it means the target position is
2882 : // closing to end of stream. We don't want to skip any frame at this point.
2883 0 : if (!keyframe.IsValid() || keyframe.IsInfinite()) {
2884 0 : return;
2885 : }
2886 0 : threshold = mOriginalSeekTarget.GetTime();
2887 : } else {
2888 0 : return;
2889 : }
2890 :
2891 0 : LOG("Set seek threshold to %" PRId64, threshold.ToMicroseconds());
2892 0 : mVideo.mDecoder->SetSeekThreshold(threshold);
2893 : }
2894 :
2895 : void
2896 0 : MediaFormatReader::DoAudioSeek()
2897 : {
2898 0 : MOZ_ASSERT(mPendingSeekTime.isSome());
2899 0 : LOGV("Seeking audio to %" PRId64, mPendingSeekTime.ref().ToMicroseconds());
2900 0 : auto seekTime = mPendingSeekTime.ref();
2901 0 : mAudio.mTrackDemuxer->Seek(seekTime)
2902 0 : ->Then(OwnerThread(), __func__, this,
2903 : &MediaFormatReader::OnAudioSeekCompleted,
2904 : &MediaFormatReader::OnAudioSeekFailed)
2905 0 : ->Track(mAudio.mSeekRequest);
2906 0 : }
2907 :
2908 : void
2909 0 : MediaFormatReader::OnAudioSeekCompleted(TimeUnit aTime)
2910 : {
2911 0 : MOZ_ASSERT(OnTaskQueue());
2912 0 : LOGV("Audio seeked to %" PRId64, aTime.ToMicroseconds());
2913 0 : mAudio.mSeekRequest.Complete();
2914 0 : mAudio.mFirstFrameTime = Some(aTime);
2915 0 : mPendingSeekTime.reset();
2916 0 : mSeekPromise.Resolve(aTime, __func__);
2917 0 : }
2918 :
2919 : void
2920 0 : MediaFormatReader::OnAudioSeekFailed(const MediaResult& aError)
2921 : {
2922 0 : OnSeekFailed(TrackType::kAudioTrack, aError);
2923 0 : }
2924 :
2925 0 : void MediaFormatReader::ReleaseResources()
2926 : {
2927 0 : LOGV("");
2928 0 : if (mShutdown) {
2929 0 : return;
2930 : }
2931 0 : ShutdownDecoder(TrackInfo::kAudioTrack);
2932 0 : ShutdownDecoder(TrackInfo::kVideoTrack);
2933 : }
2934 :
2935 : bool
2936 0 : MediaFormatReader::VideoIsHardwareAccelerated() const
2937 : {
2938 0 : return mVideo.mIsHardwareAccelerated;
2939 : }
2940 :
2941 : void
2942 0 : MediaFormatReader::NotifyTrackDemuxers()
2943 : {
2944 0 : MOZ_ASSERT(OnTaskQueue());
2945 :
2946 0 : LOGV("");
2947 :
2948 0 : if (!mInitDone) {
2949 0 : return;
2950 : }
2951 :
2952 0 : if (HasVideo()) {
2953 0 : mVideo.mReceivedNewData = true;
2954 0 : ScheduleUpdate(TrackType::kVideoTrack);
2955 : }
2956 0 : if (HasAudio()) {
2957 0 : mAudio.mReceivedNewData = true;
2958 0 : ScheduleUpdate(TrackType::kAudioTrack);
2959 : }
2960 : }
2961 :
2962 : void
2963 0 : MediaFormatReader::NotifyDataArrived()
2964 : {
2965 0 : MOZ_ASSERT(OnTaskQueue());
2966 :
2967 0 : if (mShutdown || !mDemuxer || !mDemuxerInitDone) {
2968 0 : return;
2969 : }
2970 :
2971 0 : if (mNotifyDataArrivedPromise.Exists()) {
2972 : // Already one in progress. Set the dirty flag so we can process it later.
2973 0 : mPendingNotifyDataArrived = true;
2974 0 : return;
2975 : }
2976 :
2977 0 : RefPtr<MediaFormatReader> self = this;
2978 0 : mDemuxer->NotifyDataArrived()
2979 0 : ->Then(OwnerThread(), __func__,
2980 0 : [self]() {
2981 0 : self->mNotifyDataArrivedPromise.Complete();
2982 0 : self->UpdateBuffered();
2983 0 : self->NotifyTrackDemuxers();
2984 0 : if (self->mPendingNotifyDataArrived) {
2985 0 : self->mPendingNotifyDataArrived = false;
2986 0 : self->NotifyDataArrived();
2987 : }
2988 0 : },
2989 0 : [self]() { self->mNotifyDataArrivedPromise.Complete(); })
2990 0 : ->Track(mNotifyDataArrivedPromise);
2991 : }
2992 :
2993 : void
2994 0 : MediaFormatReader::UpdateBuffered()
2995 : {
2996 0 : MOZ_ASSERT(OnTaskQueue());
2997 :
2998 0 : if (mShutdown) {
2999 0 : return;
3000 : }
3001 :
3002 0 : if (!mInitDone || !mHasStartTime) {
3003 0 : mBuffered = TimeIntervals();
3004 0 : return;
3005 : }
3006 :
3007 0 : if (HasVideo()) {
3008 0 : mVideo.mTimeRanges = mVideo.mTrackDemuxer->GetBuffered();
3009 : bool hasLastEnd;
3010 0 : auto lastEnd = mVideo.mTimeRanges.GetEnd(&hasLastEnd);
3011 0 : if (hasLastEnd) {
3012 0 : if (mVideo.mLastTimeRangesEnd
3013 0 : && mVideo.mLastTimeRangesEnd.ref() < lastEnd) {
3014 : // New data was added after our previous end, we can clear the EOS flag.
3015 0 : mVideo.mDemuxEOS = false;
3016 0 : ScheduleUpdate(TrackInfo::kVideoTrack);
3017 : }
3018 0 : mVideo.mLastTimeRangesEnd = Some(lastEnd);
3019 : }
3020 : }
3021 0 : if (HasAudio()) {
3022 0 : mAudio.mTimeRanges = mAudio.mTrackDemuxer->GetBuffered();
3023 : bool hasLastEnd;
3024 0 : auto lastEnd = mAudio.mTimeRanges.GetEnd(&hasLastEnd);
3025 0 : if (hasLastEnd) {
3026 0 : if (mAudio.mLastTimeRangesEnd
3027 0 : && mAudio.mLastTimeRangesEnd.ref() < lastEnd) {
3028 : // New data was added after our previous end, we can clear the EOS flag.
3029 0 : mAudio.mDemuxEOS = false;
3030 0 : ScheduleUpdate(TrackInfo::kAudioTrack);
3031 : }
3032 0 : mAudio.mLastTimeRangesEnd = Some(lastEnd);
3033 : }
3034 : }
3035 :
3036 0 : media::TimeIntervals intervals;
3037 0 : if (HasAudio() && HasVideo()) {
3038 0 : intervals = media::Intersection(mVideo.mTimeRanges, mAudio.mTimeRanges);
3039 0 : } else if (HasAudio()) {
3040 0 : intervals = mAudio.mTimeRanges;
3041 0 : } else if (HasVideo()) {
3042 0 : intervals = mVideo.mTimeRanges;
3043 : }
3044 :
3045 0 : if (!intervals.Length()
3046 0 : || intervals.GetStart() == TimeUnit::Zero()) {
3047 : // IntervalSet already starts at 0 or is empty, nothing to shift.
3048 0 : mBuffered = intervals;
3049 : } else {
3050 : mBuffered =
3051 0 : intervals.Shift(TimeUnit::Zero() - mInfo.mStartTime);
3052 : }
3053 : }
3054 :
3055 : layers::ImageContainer*
3056 0 : MediaFormatReader::GetImageContainer()
3057 : {
3058 0 : return mVideoFrameContainer ? mVideoFrameContainer->GetImageContainer()
3059 0 : : nullptr;
3060 : }
3061 :
3062 : void
3063 0 : MediaFormatReader::GetMozDebugReaderData(nsACString& aString)
3064 : {
3065 0 : nsAutoCString result;
3066 0 : const char* audioName = "unavailable";
3067 0 : const char* videoName = audioName;
3068 :
3069 0 : if (HasAudio()) {
3070 0 : MutexAutoLock lock(mAudio.mMutex);
3071 0 : audioName = mAudio.mDescription;
3072 : }
3073 0 : if (HasVideo()) {
3074 0 : MutexAutoLock mon(mVideo.mMutex);
3075 0 : videoName = mVideo.mDescription;
3076 : }
3077 :
3078 0 : result += nsPrintfCString("Audio Decoder: %s\n", audioName);
3079 0 : result += nsPrintfCString("Audio Frames Decoded: %" PRIu64 "\n",
3080 0 : mAudio.mNumSamplesOutputTotal);
3081 0 : if (HasAudio()) {
3082 0 : result += nsPrintfCString(
3083 : "Audio State: ni=%d no=%d wp=%d demuxr=%d demuxq=%u decoder=%d tt=%.1f "
3084 : "tths=%d in=%" PRIu64 " out=%" PRIu64
3085 : " qs=%u pending=%u wfd=%d eos=%d ds=%d wfk=%d sid=%u\n",
3086 0 : NeedInput(mAudio),
3087 0 : mAudio.HasPromise(),
3088 0 : !mAudio.mWaitingPromise.IsEmpty(),
3089 0 : mAudio.mDemuxRequest.Exists(),
3090 0 : uint32_t(mAudio.mQueuedSamples.Length()),
3091 0 : mAudio.mDecodeRequest.Exists(),
3092 0 : mAudio.mTimeThreshold ? mAudio.mTimeThreshold.ref().Time().ToSeconds()
3093 0 : : -1.0,
3094 0 : mAudio.mTimeThreshold ? mAudio.mTimeThreshold.ref().mHasSeeked : -1,
3095 : mAudio.mNumSamplesInput,
3096 : mAudio.mNumSamplesOutput,
3097 0 : unsigned(size_t(mAudio.mSizeOfQueue)),
3098 0 : unsigned(mAudio.mOutput.Length()),
3099 0 : mAudio.mWaitingForData,
3100 0 : mAudio.mDemuxEOS,
3101 0 : int32_t(mAudio.mDrainState),
3102 0 : mAudio.mWaitingForKey,
3103 0 : mAudio.mLastStreamSourceID);
3104 : }
3105 0 : result += nsPrintfCString("Video Decoder: %s\n", videoName);
3106 : result +=
3107 0 : nsPrintfCString("Hardware Video Decoding: %s\n",
3108 0 : VideoIsHardwareAccelerated() ? "enabled" : "disabled");
3109 : result +=
3110 0 : nsPrintfCString("Video Frames Decoded: %" PRIu64 " (skipped=%" PRIu64 ")\n",
3111 : mVideo.mNumSamplesOutputTotal,
3112 0 : mVideo.mNumSamplesSkippedTotal);
3113 0 : if (HasVideo()) {
3114 0 : result += nsPrintfCString(
3115 : "Video State: ni=%d no=%d wp=%d demuxr=%d demuxq=%u decoder=%d tt=%.1f "
3116 : "tths=%d in=%" PRIu64 " out=%" PRIu64
3117 : " qs=%u pending:%u wfd=%d eos=%d ds=%d wfk=%d sid=%u\n",
3118 0 : NeedInput(mVideo),
3119 0 : mVideo.HasPromise(),
3120 0 : !mVideo.mWaitingPromise.IsEmpty(),
3121 0 : mVideo.mDemuxRequest.Exists(),
3122 0 : uint32_t(mVideo.mQueuedSamples.Length()),
3123 0 : mVideo.mDecodeRequest.Exists(),
3124 0 : mVideo.mTimeThreshold ? mVideo.mTimeThreshold.ref().Time().ToSeconds()
3125 0 : : -1.0,
3126 0 : mVideo.mTimeThreshold ? mVideo.mTimeThreshold.ref().mHasSeeked : -1,
3127 : mVideo.mNumSamplesInput,
3128 : mVideo.mNumSamplesOutput,
3129 0 : unsigned(size_t(mVideo.mSizeOfQueue)),
3130 0 : unsigned(mVideo.mOutput.Length()),
3131 0 : mVideo.mWaitingForData,
3132 0 : mVideo.mDemuxEOS,
3133 0 : int32_t(mVideo.mDrainState),
3134 0 : mVideo.mWaitingForKey,
3135 0 : mVideo.mLastStreamSourceID);
3136 : }
3137 0 : aString += result;
3138 0 : }
3139 :
3140 : void
3141 0 : MediaFormatReader::SetVideoNullDecode(bool aIsNullDecode)
3142 : {
3143 0 : MOZ_ASSERT(OnTaskQueue());
3144 0 : return SetNullDecode(TrackType::kVideoTrack, aIsNullDecode);
3145 : }
3146 :
3147 : void
3148 0 : MediaFormatReader::SetNullDecode(TrackType aTrack, bool aIsNullDecode)
3149 : {
3150 0 : MOZ_ASSERT(OnTaskQueue());
3151 :
3152 0 : auto& decoder = GetDecoderData(aTrack);
3153 0 : if (decoder.mIsNullDecode == aIsNullDecode) {
3154 0 : return;
3155 : }
3156 :
3157 0 : LOG("%s, decoder.mIsNullDecode = %d => aIsNullDecode = %d",
3158 : TrackTypeToStr(aTrack), decoder.mIsNullDecode, aIsNullDecode);
3159 :
3160 0 : decoder.mIsNullDecode = aIsNullDecode;
3161 0 : ShutdownDecoder(aTrack);
3162 : }
3163 :
3164 : void
3165 0 : MediaFormatReader::OnFirstDemuxCompleted(
3166 : TrackInfo::TrackType aType, RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples)
3167 : {
3168 0 : MOZ_ASSERT(OnTaskQueue());
3169 :
3170 0 : if (mShutdown) {
3171 0 : return;
3172 : }
3173 :
3174 0 : auto& decoder = GetDecoderData(aType);
3175 0 : MOZ_ASSERT(decoder.mFirstDemuxedSampleTime.isNothing());
3176 0 : decoder.mFirstDemuxedSampleTime.emplace(aSamples->mSamples[0]->mTime);
3177 0 : MaybeResolveMetadataPromise();
3178 : }
3179 :
3180 : void
3181 0 : MediaFormatReader::OnFirstDemuxFailed(TrackInfo::TrackType aType,
3182 : const MediaResult& aError)
3183 : {
3184 0 : MOZ_ASSERT(OnTaskQueue());
3185 :
3186 0 : if (mShutdown) {
3187 0 : return;
3188 : }
3189 :
3190 0 : auto& decoder = GetDecoderData(aType);
3191 0 : MOZ_ASSERT(decoder.mFirstDemuxedSampleTime.isNothing());
3192 0 : decoder.mFirstDemuxedSampleTime.emplace(TimeUnit::FromInfinity());
3193 0 : MaybeResolveMetadataPromise();
3194 : }
3195 :
3196 : } // namespace mozilla
3197 :
3198 : #undef NS_DispatchToMainThread
|