Source code

Revision control

Other Tools

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 "AllocationPolicy.h"
10
#include "DecoderBenchmark.h"
11
#include "GeckoProfiler.h"
12
#include "MediaData.h"
13
#include "MediaInfo.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/NotNull.h"
20
#include "mozilla/Preferences.h"
21
#include "mozilla/SharedThreadPool.h"
22
#include "mozilla/StaticPrefs_media.h"
23
#include "mozilla/TaskQueue.h"
24
#include "mozilla/Unused.h"
25
#include "nsContentUtils.h"
26
#include "nsPrintfCString.h"
27
28
#include <algorithm>
29
#include <map>
30
#include <queue>
31
32
using namespace mozilla::media;
33
34
static mozilla::LazyLogModule sFormatDecoderLog("MediaFormatReader");
35
mozilla::LazyLogModule gMediaDemuxerLog("MediaDemuxer");
36
37
#define LOG(arg, ...) \
38
DDMOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Debug, "::%s: " arg, \
39
__func__, ##__VA_ARGS__)
40
#define LOGV(arg, ...) \
41
DDMOZ_LOG(sFormatDecoderLog, mozilla::LogLevel::Verbose, "::%s: " arg, \
42
__func__, ##__VA_ARGS__)
43
44
#define NS_DispatchToMainThread(...) CompileError_UseAbstractMainThreadInstead
45
46
namespace mozilla {
47
48
typedef void* MediaDataDecoderID;
49
50
/**
51
* This class tracks shutdown promises to ensure all decoders are shut down
52
* completely before MFR continues the rest of the shutdown procedure.
53
*/
54
class MediaFormatReader::ShutdownPromisePool {
55
public:
56
ShutdownPromisePool()
57
: mOnShutdownComplete(new ShutdownPromise::Private(__func__)) {}
58
59
// Return a promise which will be resolved when all the tracking promises
60
// are resolved. Note no more promises should be added for tracking once
61
// this function is called.
62
RefPtr<ShutdownPromise> Shutdown();
63
64
// Track a shutdown promise.
65
void Track(RefPtr<ShutdownPromise> aPromise);
66
67
// Shut down a decoder and track its shutdown promise.
68
void ShutdownDecoder(already_AddRefed<MediaDataDecoder> aDecoder) {
69
Track(RefPtr<MediaDataDecoder>(aDecoder)->Shutdown());
70
}
71
72
private:
73
bool mShutdown = false;
74
const RefPtr<ShutdownPromise::Private> mOnShutdownComplete;
75
nsTHashtable<nsRefPtrHashKey<ShutdownPromise>> mPromises;
76
};
77
78
RefPtr<ShutdownPromise> MediaFormatReader::ShutdownPromisePool::Shutdown() {
79
MOZ_DIAGNOSTIC_ASSERT(!mShutdown);
80
mShutdown = true;
81
if (mPromises.Count() == 0) {
82
mOnShutdownComplete->Resolve(true, __func__);
83
}
84
return mOnShutdownComplete;
85
}
86
87
void MediaFormatReader::ShutdownPromisePool::Track(
88
RefPtr<ShutdownPromise> aPromise) {
89
MOZ_DIAGNOSTIC_ASSERT(!mShutdown);
90
MOZ_DIAGNOSTIC_ASSERT(!mPromises.Contains(aPromise));
91
mPromises.PutEntry(aPromise);
92
aPromise->Then(AbstractThread::GetCurrent(), __func__, [aPromise, this]() {
93
MOZ_DIAGNOSTIC_ASSERT(mPromises.Contains(aPromise));
94
mPromises.RemoveEntry(aPromise);
95
if (mShutdown && mPromises.Count() == 0) {
96
mOnShutdownComplete->Resolve(true, __func__);
97
}
98
});
99
}
100
101
void MediaFormatReader::DecoderData::ShutdownDecoder() {
102
MutexAutoLock lock(mMutex);
103
104
if (!mDecoder) {
105
// No decoder to shut down.
106
return;
107
}
108
109
if (mFlushing) {
110
// Flush is is in action. Shutdown will be initiated after flush completes.
111
MOZ_DIAGNOSTIC_ASSERT(mShutdownPromise);
112
mOwner->mShutdownPromisePool->Track(mShutdownPromise->Ensure(__func__));
113
// The order of decoder creation and shutdown is handled by LocalAllocPolicy
114
// and ShutdownPromisePool. MFR can now reset these members to a fresh state
115
// and be ready to create new decoders again without explicitly waiting for
116
// flush/shutdown to complete.
117
mShutdownPromise = nullptr;
118
mFlushing = false;
119
} else {
120
// No flush is in action. We can shut down the decoder now.
121
mOwner->mShutdownPromisePool->Track(mDecoder->Shutdown());
122
}
123
124
// mShutdownPromisePool will handle the order of decoder shutdown so
125
// we can forget mDecoder and be ready to create a new one.
126
mDecoder = nullptr;
127
mDescription = NS_LITERAL_CSTRING("shutdown");
128
mOwner->ScheduleUpdate(mType == MediaData::Type::AUDIO_DATA
129
? TrackType::kAudioTrack
130
: TrackType::kVideoTrack);
131
}
132
133
void MediaFormatReader::DecoderData::Flush() {
134
if (mFlushing || mFlushed) {
135
// Flush still pending or already flushed, nothing more to do.
136
return;
137
}
138
mDecodeRequest.DisconnectIfExists();
139
mDrainRequest.DisconnectIfExists();
140
mDrainState = DrainState::None;
141
CancelWaitingForKey();
142
mOutput.Clear();
143
mNumSamplesInput = 0;
144
mNumSamplesOutput = 0;
145
mSizeOfQueue = 0;
146
if (mDecoder) {
147
TrackType type = mType == MediaData::Type::AUDIO_DATA
148
? TrackType::kAudioTrack
149
: TrackType::kVideoTrack;
150
mFlushing = true;
151
MOZ_DIAGNOSTIC_ASSERT(!mShutdownPromise);
152
mShutdownPromise = new SharedShutdownPromiseHolder();
153
RefPtr<SharedShutdownPromiseHolder> p = mShutdownPromise;
154
RefPtr<MediaDataDecoder> d = mDecoder;
155
DDLOGEX2("MediaFormatReader::DecoderData", this, DDLogCategory::Log,
156
"flushing", DDNoValue{});
157
mDecoder->Flush()->Then(
158
mOwner->OwnerThread(), __func__,
159
[type, this, p, d]() {
160
DDLOGEX2("MediaFormatReader::DecoderData", this, DDLogCategory::Log,
161
"flushed", DDNoValue{});
162
if (!p->IsEmpty()) {
163
// Shutdown happened before flush completes.
164
// Let's continue to shut down the decoder. Note
165
// we don't access |this| because this decoder
166
// is no longer managed by MFR::DecoderData.
167
d->Shutdown()->ChainTo(p->Steal(), __func__);
168
return;
169
}
170
mFlushing = false;
171
mShutdownPromise = nullptr;
172
mOwner->ScheduleUpdate(type);
173
},
174
[type, this, p, d](const MediaResult& aError) {
175
DDLOGEX2("MediaFormatReader::DecoderData", this, DDLogCategory::Log,
176
"flush_error", aError);
177
if (!p->IsEmpty()) {
178
d->Shutdown()->ChainTo(p->Steal(), __func__);
179
return;
180
}
181
mFlushing = false;
182
mShutdownPromise = nullptr;
183
mOwner->NotifyError(type, aError);
184
});
185
}
186
mFlushed = true;
187
}
188
189
class MediaFormatReader::DecoderFactory {
190
using InitPromise = MediaDataDecoder::InitPromise;
191
using TokenPromise = AllocPolicy::Promise;
192
using Token = AllocPolicy::Token;
193
194
public:
195
explicit DecoderFactory(MediaFormatReader* aOwner)
196
: mAudio(aOwner->mAudio, TrackInfo::kAudioTrack, aOwner->OwnerThread()),
197
mVideo(aOwner->mVideo, TrackInfo::kVideoTrack, aOwner->OwnerThread()),
198
mOwner(WrapNotNull(aOwner)) {
199
DecoderDoctorLogger::LogConstruction("MediaFormatReader::DecoderFactory",
200
this);
201
DecoderDoctorLogger::LinkParentAndChild(
202
aOwner, "decoder factory", "MediaFormatReader::DecoderFactory", this);
203
}
204
205
~DecoderFactory() {
206
DecoderDoctorLogger::LogDestruction("MediaFormatReader::DecoderFactory",
207
this);
208
}
209
210
void CreateDecoder(TrackType aTrack);
211
212
// Shutdown any decoder pending initialization and reset mAudio/mVideo to its
213
// pristine state so CreateDecoder() is ready to be called again immediately.
214
void ShutdownDecoder(TrackType aTrack) {
215
MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack ||
216
aTrack == TrackInfo::kVideoTrack);
217
auto& data = aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo;
218
data.mPolicy->Cancel();
219
data.mTokenRequest.DisconnectIfExists();
220
data.mInitRequest.DisconnectIfExists();
221
if (data.mDecoder) {
222
mOwner->mShutdownPromisePool->ShutdownDecoder(data.mDecoder.forget());
223
}
224
data.mStage = Stage::None;
225
MOZ_ASSERT(!data.mToken);
226
}
227
228
private:
229
enum class Stage : int8_t { None, WaitForToken, CreateDecoder, WaitForInit };
230
231
struct Data {
232
Data(DecoderData& aOwnerData, TrackType aTrack, TaskQueue* aThread)
233
: mOwnerData(aOwnerData),
234
mTrack(aTrack),
235
mPolicy(new SingleAllocPolicy(aTrack, aThread)) {}
236
DecoderData& mOwnerData;
237
const TrackType mTrack;
238
RefPtr<SingleAllocPolicy> mPolicy;
239
Stage mStage = Stage::None;
240
RefPtr<Token> mToken;
241
RefPtr<MediaDataDecoder> mDecoder;
242
MozPromiseRequestHolder<TokenPromise> mTokenRequest;
243
MozPromiseRequestHolder<InitPromise> mInitRequest;
244
} mAudio, mVideo;
245
246
void RunStage(Data& aData);
247
MediaResult DoCreateDecoder(Data& aData);
248
void DoInitDecoder(Data& aData);
249
250
// guaranteed to be valid by the owner.
251
const NotNull<MediaFormatReader*> mOwner;
252
};
253
254
void MediaFormatReader::DecoderFactory::CreateDecoder(TrackType aTrack) {
255
MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack ||
256
aTrack == TrackInfo::kVideoTrack);
257
RunStage(aTrack == TrackInfo::kAudioTrack ? mAudio : mVideo);
258
}
259
260
void MediaFormatReader::DecoderFactory::RunStage(Data& aData) {
261
switch (aData.mStage) {
262
case Stage::None: {
263
MOZ_ASSERT(!aData.mToken);
264
aData.mPolicy->Alloc()
265
->Then(
266
mOwner->OwnerThread(), __func__,
267
[this, &aData](RefPtr<Token> aToken) {
268
aData.mTokenRequest.Complete();
269
aData.mToken = aToken.forget();
270
aData.mStage = Stage::CreateDecoder;
271
RunStage(aData);
272
},
273
[&aData]() {
274
aData.mTokenRequest.Complete();
275
aData.mStage = Stage::None;
276
})
277
->Track(aData.mTokenRequest);
278
aData.mStage = Stage::WaitForToken;
279
break;
280
}
281
282
case Stage::WaitForToken: {
283
MOZ_ASSERT(!aData.mToken);
284
MOZ_ASSERT(aData.mTokenRequest.Exists());
285
break;
286
}
287
288
case Stage::CreateDecoder: {
289
MOZ_ASSERT(aData.mToken);
290
MOZ_ASSERT(!aData.mDecoder);
291
MOZ_ASSERT(!aData.mInitRequest.Exists());
292
293
MediaResult rv = DoCreateDecoder(aData);
294
if (NS_FAILED(rv)) {
295
NS_WARNING("Error constructing decoders");
296
aData.mToken = nullptr;
297
aData.mStage = Stage::None;
298
aData.mOwnerData.mDescription = rv.Description();
299
DDLOGEX2("MediaFormatReader::DecoderFactory", this, DDLogCategory::Log,
300
"create_decoder_error", rv);
301
mOwner->NotifyError(aData.mTrack, rv);
302
return;
303
}
304
305
aData.mDecoder =
306
new AllocationWrapper(aData.mDecoder.forget(), aData.mToken.forget());
307
DecoderDoctorLogger::LinkParentAndChild(
308
aData.mDecoder.get(), "decoder", "MediaFormatReader::DecoderFactory",
309
this);
310
311
DoInitDecoder(aData);
312
aData.mStage = Stage::WaitForInit;
313
break;
314
}
315
316
case Stage::WaitForInit: {
317
MOZ_ASSERT(aData.mDecoder);
318
MOZ_ASSERT(aData.mInitRequest.Exists());
319
break;
320
}
321
}
322
}
323
324
MediaResult MediaFormatReader::DecoderFactory::DoCreateDecoder(Data& aData) {
325
auto& ownerData = aData.mOwnerData;
326
auto& decoder = mOwner->GetDecoderData(aData.mTrack);
327
auto& platform =
328
decoder.IsEncrypted() ? mOwner->mEncryptedPlatform : mOwner->mPlatform;
329
330
if (!platform) {
331
platform = new PDMFactory();
332
if (decoder.IsEncrypted()) {
333
MOZ_ASSERT(mOwner->mCDMProxy);
334
platform->SetCDMProxy(mOwner->mCDMProxy);
335
}
336
}
337
338
// Media playback is not supported when recording or replaying. See bug
339
// 1304146.
340
if (recordreplay::IsRecordingOrReplaying()) {
341
return MediaResult(
342
NS_ERROR_DOM_MEDIA_FATAL_ERR,
343
nsPrintfCString("error creating %s decoder: "
344
"media playback is disabled while recording/replaying",
345
TrackTypeToStr(aData.mTrack)));
346
}
347
348
// result may not be updated by PDMFactory::CreateDecoder, as such it must be
349
// initialized to a fatal error by default.
350
MediaResult result =
351
MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
352
nsPrintfCString("error creating %s decoder",
353
TrackTypeToStr(aData.mTrack)));
354
355
switch (aData.mTrack) {
356
case TrackInfo::kAudioTrack: {
357
aData.mDecoder = platform->CreateDecoder(
358
{*ownerData.GetCurrentInfo()->GetAsAudioInfo(), ownerData.mTaskQueue,
359
mOwner->mCrashHelper,
360
CreateDecoderParams::UseNullDecoder(ownerData.mIsNullDecode),
361
&result, TrackInfo::kAudioTrack,
362
&mOwner->OnTrackWaitingForKeyProducer()});
363
break;
364
}
365
366
case TrackType::kVideoTrack: {
367
// Decoders use the layers backend to decide if they can use hardware
368
// decoding, so specify LAYERS_NONE if we want to forcibly disable it.
369
using Option = CreateDecoderParams::Option;
370
using OptionSet = CreateDecoderParams::OptionSet;
371
372
aData.mDecoder = platform->CreateDecoder(
373
{*ownerData.GetCurrentInfo()->GetAsVideoInfo(), ownerData.mTaskQueue,
374
mOwner->mKnowsCompositor, mOwner->GetImageContainer(),
375
mOwner->mCrashHelper,
376
CreateDecoderParams::UseNullDecoder(ownerData.mIsNullDecode),
377
&result, TrackType::kVideoTrack,
378
&mOwner->OnTrackWaitingForKeyProducer(),
379
CreateDecoderParams::VideoFrameRate(ownerData.mMeanRate.Mean()),
380
OptionSet(ownerData.mHardwareDecodingDisabled
381
? Option::HardwareDecoderNotAllowed
382
: Option::Default)});
383
break;
384
}
385
386
default:
387
break;
388
}
389
390
if (aData.mDecoder) {
391
return NS_OK;
392
}
393
394
MOZ_RELEASE_ASSERT(NS_FAILED(result), "PDM returned an invalid error code");
395
396
return result;
397
}
398
399
void MediaFormatReader::DecoderFactory::DoInitDecoder(Data& aData) {
400
auto& ownerData = aData.mOwnerData;
401
402
DDLOGEX2("MediaFormatReader::DecoderFactory", this, DDLogCategory::Log,
403
"initialize_decoder", DDNoValue{});
404
aData.mDecoder->Init()
405
->Then(
406
mOwner->OwnerThread(), __func__,
407
[this, &aData, &ownerData](TrackType aTrack) {
408
aData.mInitRequest.Complete();
409
aData.mStage = Stage::None;
410
MutexAutoLock lock(ownerData.mMutex);
411
ownerData.mDecoder = aData.mDecoder.forget();
412
ownerData.mDescription = ownerData.mDecoder->GetDescriptionName();
413
DDLOGEX2("MediaFormatReader::DecoderFactory", this,
414
DDLogCategory::Log, "decoder_initialized", DDNoValue{});
415
DecoderDoctorLogger::LinkParentAndChild(
416
"MediaFormatReader::DecoderData", &ownerData, "decoder",
417
ownerData.mDecoder.get());
418
mOwner->SetVideoDecodeThreshold();
419
mOwner->ScheduleUpdate(aTrack);
420
if (aTrack == TrackInfo::kVideoTrack) {
421
DecoderBenchmark::CheckVersion(
422
ownerData.GetCurrentInfo()->mMimeType);
423
}
424
},
425
[this, &aData, &ownerData](const MediaResult& aError) {
426
aData.mInitRequest.Complete();
427
MOZ_RELEASE_ASSERT(!ownerData.mDecoder,
428
"Can't have a decoder already set");
429
aData.mStage = Stage::None;
430
mOwner->mShutdownPromisePool->ShutdownDecoder(
431
aData.mDecoder.forget());
432
DDLOGEX2("MediaFormatReader::DecoderFactory", this,
433
DDLogCategory::Log, "initialize_decoder_error", aError);
434
mOwner->NotifyError(aData.mTrack, aError);
435
})
436
->Track(aData.mInitRequest);
437
}
438
439
// DemuxerProxy ensures that the original main demuxer is only ever accessed
440
// via its own dedicated task queue.
441
// This ensure that the reader's taskqueue will never blocked while a demuxer
442
// is itself blocked attempting to access the MediaCache or the MediaResource.
443
class MediaFormatReader::DemuxerProxy {
444
using TrackType = TrackInfo::TrackType;
445
class Wrapper;
446
447
public:
448
explicit DemuxerProxy(MediaDataDemuxer* aDemuxer)
449
: mTaskQueue(
450
new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
451
"DemuxerProxy::mTaskQueue")),
452
mData(new Data(aDemuxer)) {
453
MOZ_COUNT_CTOR(DemuxerProxy);
454
}
455
456
~DemuxerProxy() { MOZ_COUNT_DTOR(DemuxerProxy); }
457
458
RefPtr<ShutdownPromise> Shutdown() {
459
RefPtr<Data> data = mData.forget();
460
return InvokeAsync(mTaskQueue, __func__, [data]() {
461
// We need to clear our reference to the demuxer now. So that in the event
462
// the init promise wasn't resolved, such as what can happen with the
463
// mediasource demuxer that is waiting on more data, it will force the
464
// init promise to be rejected.
465
data->mDemuxer = nullptr;
466
data->mAudioDemuxer = nullptr;
467
data->mVideoDemuxer = nullptr;
468
return ShutdownPromise::CreateAndResolve(true, __func__);
469
});
470
}
471
472
RefPtr<MediaDataDemuxer::InitPromise> Init();
473
474
Wrapper* GetTrackDemuxer(TrackType aTrack, uint32_t aTrackNumber) {
475
MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
476
477
switch (aTrack) {
478
case TrackInfo::kAudioTrack:
479
return mData->mAudioDemuxer;
480
case TrackInfo::kVideoTrack:
481
return mData->mVideoDemuxer;
482
default:
483
return nullptr;
484
}
485
}
486
487
uint32_t GetNumberTracks(TrackType aTrack) const {
488
MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
489
490
switch (aTrack) {
491
case TrackInfo::kAudioTrack:
492
return mData->mNumAudioTrack;
493
case TrackInfo::kVideoTrack:
494
return mData->mNumVideoTrack;
495
default:
496
return 0;
497
}
498
}
499
500
bool IsSeekable() const {
501
MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
502
503
return mData->mSeekable;
504
}
505
506
bool IsSeekableOnlyInBufferedRanges() const {
507
MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
508
509
return mData->mSeekableOnlyInBufferedRange;
510
}
511
512
UniquePtr<EncryptionInfo> GetCrypto() const {
513
MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
514
515
if (!mData->mCrypto) {
516
return nullptr;
517
}
518
auto crypto = MakeUnique<EncryptionInfo>();
519
*crypto = *mData->mCrypto;
520
return crypto;
521
}
522
523
RefPtr<NotifyDataArrivedPromise> NotifyDataArrived();
524
525
bool ShouldComputeStartTime() const {
526
MOZ_RELEASE_ASSERT(mData && mData->mInitDone);
527
528
return mData->mShouldComputeStartTime;
529
}
530
531
private:
532
const RefPtr<TaskQueue> mTaskQueue;
533
struct Data {
534
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Data)
535
536
explicit Data(MediaDataDemuxer* aDemuxer)
537
: mInitDone(false), mDemuxer(aDemuxer) {}
538
539
Atomic<bool> mInitDone;
540
// Only ever accessed over mTaskQueue once.
541
RefPtr<MediaDataDemuxer> mDemuxer;
542
// Only accessed once InitPromise has been resolved and immutable after.
543
// So we can safely access them without the use of the mutex.
544
uint32_t mNumAudioTrack = 0;
545
RefPtr<Wrapper> mAudioDemuxer;
546
uint32_t mNumVideoTrack = 0;
547
RefPtr<Wrapper> mVideoDemuxer;
548
bool mSeekable = false;
549
bool mSeekableOnlyInBufferedRange = false;
550
bool mShouldComputeStartTime = true;
551
UniquePtr<EncryptionInfo> mCrypto;
552
553
private:
554
~Data() {}
555
};
556
RefPtr<Data> mData;
557
};
558
559
class MediaFormatReader::DemuxerProxy::Wrapper : public MediaTrackDemuxer {
560
public:
561
Wrapper(MediaTrackDemuxer* aTrackDemuxer, TaskQueue* aTaskQueue)
562
: mMutex("TrackDemuxer Mutex"),
563
mTaskQueue(aTaskQueue),
564
mGetSamplesMayBlock(aTrackDemuxer->GetSamplesMayBlock()),
565
mInfo(aTrackDemuxer->GetInfo()),
566
mTrackDemuxer(aTrackDemuxer) {
567
DecoderDoctorLogger::LogConstructionAndBase(
568
"MediaFormatReader::DemuxerProxy::Wrapper", this,
569
static_cast<const MediaTrackDemuxer*>(this));
570
DecoderDoctorLogger::LinkParentAndChild(
571
"MediaFormatReader::DemuxerProxy::Wrapper", this, "track demuxer",
572
aTrackDemuxer);
573
}
574
575
UniquePtr<TrackInfo> GetInfo() const override {
576
if (!mInfo) {
577
return nullptr;
578
}
579
return mInfo->Clone();
580
}
581
582
RefPtr<SeekPromise> Seek(const TimeUnit& aTime) override {
583
RefPtr<Wrapper> self = this;
584
return InvokeAsync(
585
mTaskQueue, __func__,
586
[self, aTime]() { return self->mTrackDemuxer->Seek(aTime); })
587
->Then(
588
mTaskQueue, __func__,
589
[self](const TimeUnit& aTime) {
590
self->UpdateRandomAccessPoint();
591
return SeekPromise::CreateAndResolve(aTime, __func__);
592
},
593
[self](const MediaResult& aError) {
594
self->UpdateRandomAccessPoint();
595
return SeekPromise::CreateAndReject(aError, __func__);
596
});
597
}
598
599
RefPtr<SamplesPromise> GetSamples(int32_t aNumSamples) override {
600
RefPtr<Wrapper> self = this;
601
return InvokeAsync(mTaskQueue, __func__,
602
[self, aNumSamples]() {
603
return self->mTrackDemuxer->GetSamples(aNumSamples);
604
})
605
->Then(
606
mTaskQueue, __func__,
607
[self](RefPtr<SamplesHolder> aSamples) {
608
self->UpdateRandomAccessPoint();
609
return SamplesPromise::CreateAndResolve(aSamples.forget(),
610
__func__);
611
},
612
[self](const MediaResult& aError) {
613
self->UpdateRandomAccessPoint();
614
return SamplesPromise::CreateAndReject(aError, __func__);
615
});
616
}
617
618
bool GetSamplesMayBlock() const override { return mGetSamplesMayBlock; }
619
620
void Reset() override {
621
RefPtr<Wrapper> self = this;
622
nsresult rv = mTaskQueue->Dispatch(NS_NewRunnableFunction(
623
"MediaFormatReader::DemuxerProxy::Wrapper::Reset",
624
[self]() { self->mTrackDemuxer->Reset(); }));
625
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
626
Unused << rv;
627
}
628
629
nsresult GetNextRandomAccessPoint(TimeUnit* aTime) override {
630
MutexAutoLock lock(mMutex);
631
if (NS_SUCCEEDED(mNextRandomAccessPointResult)) {
632
*aTime = mNextRandomAccessPoint;
633
}
634
return mNextRandomAccessPointResult;
635
}
636
637
RefPtr<SkipAccessPointPromise> SkipToNextRandomAccessPoint(
638
const TimeUnit& aTimeThreshold) override {
639
RefPtr<Wrapper> self = this;
640
return InvokeAsync(
641
mTaskQueue, __func__,
642
[self, aTimeThreshold]() {
643
return self->mTrackDemuxer->SkipToNextRandomAccessPoint(
644
aTimeThreshold);
645
})
646
->Then(
647
mTaskQueue, __func__,
648
[self](uint32_t aVal) {
649
self->UpdateRandomAccessPoint();
650
return SkipAccessPointPromise::CreateAndResolve(aVal, __func__);
651
},
652
[self](const SkipFailureHolder& aError) {
653
self->UpdateRandomAccessPoint();
654
return SkipAccessPointPromise::CreateAndReject(aError, __func__);
655
});
656
}
657
658
TimeIntervals GetBuffered() override {
659
MutexAutoLock lock(mMutex);
660
return mBuffered;
661
}
662
663
void BreakCycles() override {}
664
665
private:
666
Mutex mMutex;
667
const RefPtr<TaskQueue> mTaskQueue;
668
const bool mGetSamplesMayBlock;
669
const UniquePtr<TrackInfo> mInfo;
670
// mTrackDemuxer is only ever accessed on demuxer's task queue.
671
RefPtr<MediaTrackDemuxer> mTrackDemuxer;
672
// All following members are protected by mMutex
673
nsresult mNextRandomAccessPointResult = NS_OK;
674
TimeUnit mNextRandomAccessPoint;
675
TimeIntervals mBuffered;
676
friend class DemuxerProxy;
677
678
~Wrapper() {
679
RefPtr<MediaTrackDemuxer> trackDemuxer = mTrackDemuxer.forget();
680
nsresult rv = mTaskQueue->Dispatch(NS_NewRunnableFunction(
681
"MediaFormatReader::DemuxerProxy::Wrapper::~Wrapper",
682
[trackDemuxer]() { trackDemuxer->BreakCycles(); }));
683
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
684
Unused << rv;
685
DecoderDoctorLogger::LogDestruction(
686
"MediaFormatReader::DemuxerProxy::Wrapper", this);
687
}
688
689
void UpdateRandomAccessPoint() {
690
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
691
if (!mTrackDemuxer) {
692
// Detached.
693
return;
694
}
695
MutexAutoLock lock(mMutex);
696
mNextRandomAccessPointResult =
697
mTrackDemuxer->GetNextRandomAccessPoint(&mNextRandomAccessPoint);
698
}
699
700
void UpdateBuffered() {
701
MOZ_ASSERT(mTaskQueue->IsCurrentThreadIn());
702
if (!mTrackDemuxer) {
703
// Detached.
704
return;
705
}
706
MutexAutoLock lock(mMutex);
707
mBuffered = mTrackDemuxer->GetBuffered();
708
}
709
};
710
711
RefPtr<MediaDataDemuxer::InitPromise> MediaFormatReader::DemuxerProxy::Init() {
712
using InitPromise = MediaDataDemuxer::InitPromise;
713
714
RefPtr<Data> data = mData;
715
RefPtr<TaskQueue> taskQueue = mTaskQueue;
716
return InvokeAsync(mTaskQueue, __func__,
717
[data, taskQueue]() {
718
if (!data->mDemuxer) {
719
return InitPromise::CreateAndReject(
720
NS_ERROR_DOM_MEDIA_CANCELED, __func__);
721
}
722
return data->mDemuxer->Init();
723
})
724
->Then(
725
taskQueue, __func__,
726
[data, taskQueue]() {
727
if (!data->mDemuxer) { // Was shutdown.
728
return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
729
__func__);
730
}
731
data->mNumAudioTrack =
732
data->mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
733
if (data->mNumAudioTrack) {
734
RefPtr<MediaTrackDemuxer> d =
735
data->mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
736
if (d) {
737
RefPtr<Wrapper> wrapper =
738
new DemuxerProxy::Wrapper(d, taskQueue);
739
wrapper->UpdateBuffered();
740
data->mAudioDemuxer = wrapper;
741
DecoderDoctorLogger::LinkParentAndChild(
742
data->mDemuxer.get(), "decoder factory wrapper",
743
"MediaFormatReader::DecoderFactory::Wrapper",
744
wrapper.get());
745
}
746
}
747
data->mNumVideoTrack =
748
data->mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack);
749
if (data->mNumVideoTrack) {
750
RefPtr<MediaTrackDemuxer> d =
751
data->mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
752
if (d) {
753
RefPtr<Wrapper> wrapper =
754
new DemuxerProxy::Wrapper(d, taskQueue);
755
wrapper->UpdateBuffered();
756
data->mVideoDemuxer = wrapper;
757
DecoderDoctorLogger::LinkParentAndChild(
758
data->mDemuxer.get(), "decoder factory wrapper",
759
"MediaFormatReader::DecoderFactory::Wrapper",
760
wrapper.get());
761
}
762
}
763
data->mCrypto = data->mDemuxer->GetCrypto();
764
data->mSeekable = data->mDemuxer->IsSeekable();
765
data->mSeekableOnlyInBufferedRange =
766
data->mDemuxer->IsSeekableOnlyInBufferedRanges();
767
data->mShouldComputeStartTime =
768
data->mDemuxer->ShouldComputeStartTime();
769
data->mInitDone = true;
770
return InitPromise::CreateAndResolve(NS_OK, __func__);
771
},
772
[](const MediaResult& aError) {
773
return InitPromise::CreateAndReject(aError, __func__);
774
});
775
}
776
777
RefPtr<MediaFormatReader::NotifyDataArrivedPromise>
778
MediaFormatReader::DemuxerProxy::NotifyDataArrived() {
779
RefPtr<Data> data = mData;
780
return InvokeAsync(mTaskQueue, __func__, [data]() {
781
if (!data->mDemuxer) {
782
// Was shutdown.
783
return NotifyDataArrivedPromise::CreateAndReject(
784
NS_ERROR_DOM_MEDIA_CANCELED, __func__);
785
}
786
data->mDemuxer->NotifyDataArrived();
787
if (data->mAudioDemuxer) {
788
data->mAudioDemuxer->UpdateBuffered();
789
}
790
if (data->mVideoDemuxer) {
791
data->mVideoDemuxer->UpdateBuffered();
792
}
793
return NotifyDataArrivedPromise::CreateAndResolve(true, __func__);
794
});
795
}
796
797
MediaFormatReader::MediaFormatReader(MediaFormatReaderInit& aInit,
798
MediaDataDemuxer* aDemuxer)
799
: mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
800
"MediaFormatReader::mTaskQueue",
801
/* aSupportsTailDispatch = */ true)),
802
mAudio(this, MediaData::Type::AUDIO_DATA,
803
StaticPrefs::media_audio_max_decode_error()),
804
mVideo(this, MediaData::Type::VIDEO_DATA,
805
StaticPrefs::media_video_max_decode_error()),
806
mDemuxer(new DemuxerProxy(aDemuxer)),
807
mDemuxerInitDone(false),
808
mPendingNotifyDataArrived(false),
809
mLastReportedNumDecodedFrames(0),
810
mPreviousDecodedKeyframeTime_us(sNoPreviousDecodedKeyframe),
811
mKnowsCompositor(aInit.mKnowsCompositor),
812
mInitDone(false),
813
mTrackDemuxersMayBlock(false),
814
mSeekScheduled(false),
815
mVideoFrameContainer(aInit.mVideoFrameContainer),
816
mCrashHelper(aInit.mCrashHelper),
817
mDecoderFactory(new DecoderFactory(this)),
818
mShutdownPromisePool(new ShutdownPromisePool()),
819
mBuffered(mTaskQueue, TimeIntervals(),
820
"MediaFormatReader::mBuffered (Canonical)"),
821
mFrameStats(aInit.mFrameStats),
822
mMediaDecoderOwnerID(aInit.mMediaDecoderOwnerID) {
823
MOZ_ASSERT(aDemuxer);
824
MOZ_COUNT_CTOR(MediaFormatReader);
825
DDLINKCHILD("audio decoder data", "MediaFormatReader::DecoderDataWithPromise",
826
&mAudio);
827
DDLINKCHILD("video decoder data", "MediaFormatReader::DecoderDataWithPromise",
828
&mVideo);
829
DDLINKCHILD("demuxer", aDemuxer);
830
mOnTrackWaitingForKeyListener = OnTrackWaitingForKey().Connect(
831
mTaskQueue, this, &MediaFormatReader::NotifyWaitingForKey);
832
}
833
834
MediaFormatReader::~MediaFormatReader() {
835
MOZ_COUNT_DTOR(MediaFormatReader);
836
MOZ_ASSERT(mShutdown);
837
}
838
839
RefPtr<ShutdownPromise> MediaFormatReader::Shutdown() {
840
MOZ_ASSERT(OnTaskQueue());
841
LOG("");
842
843
mDemuxerInitRequest.DisconnectIfExists();
844
mNotifyDataArrivedPromise.DisconnectIfExists();
845
mMetadataPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
846
mSeekPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
847
mSkipRequest.DisconnectIfExists();
848
mSetCDMPromise.RejectIfExists(
849
MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
850
"MediaFormatReader is shutting down"),
851
__func__);
852
853
if (mAudio.HasPromise()) {
854
mAudio.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
855
}
856
if (mVideo.HasPromise()) {
857
mVideo.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
858
}
859
860
if (HasAudio()) {
861
mAudio.ResetDemuxer();
862
mAudio.mTrackDemuxer->BreakCycles();
863
{
864
MutexAutoLock lock(mAudio.mMutex);
865
mAudio.mTrackDemuxer = nullptr;
866
}
867
mAudio.ResetState();
868
ShutdownDecoder(TrackInfo::kAudioTrack);
869
}
870
871
if (HasVideo()) {
872
mVideo.ResetDemuxer();
873
mVideo.mTrackDemuxer->BreakCycles();
874
{
875
MutexAutoLock lock(mVideo.mMutex);
876
mVideo.mTrackDemuxer = nullptr;
877
}
878
mVideo.ResetState();
879
ShutdownDecoder(TrackInfo::kVideoTrack);
880
}
881
882
mShutdownPromisePool->Track(mDemuxer->Shutdown());
883
mDemuxer = nullptr;
884
885
mOnTrackWaitingForKeyListener.Disconnect();
886
887
mShutdown = true;
888
return mShutdownPromisePool->Shutdown()->Then(
889
OwnerThread(), __func__, this, &MediaFormatReader::TearDownDecoders,
890
&MediaFormatReader::TearDownDecoders);
891
}
892
893
void MediaFormatReader::ShutdownDecoder(TrackType aTrack) {
894
LOGV("%s", TrackTypeToStr(aTrack));
895
896
// Shut down the pending decoder if any.
897
mDecoderFactory->ShutdownDecoder(aTrack);
898
899
auto& decoder = GetDecoderData(aTrack);
900
// Flush the decoder if necessary.
901
decoder.Flush();
902
903
// Shut down the decoder if any.
904
decoder.ShutdownDecoder();
905
}
906
907
void MediaFormatReader::NotifyDecoderBenchmarkStore() {
908
MOZ_ASSERT(OnTaskQueue());
909
if (!StaticPrefs::media_mediacapabilities_from_database()) {
910
return;
911
}
912
auto& decoder = GetDecoderData(TrackInfo::kVideoTrack);
913
if (decoder.GetCurrentInfo() && decoder.GetCurrentInfo()->GetAsVideoInfo()) {
914
VideoInfo info = *(decoder.GetCurrentInfo()->GetAsVideoInfo());
915
info.SetFrameRate(static_cast<int32_t>(ceil(decoder.mMeanRate.Mean())));
916
mOnStoreDecoderBenchmark.Notify(std::move(info));
917
}
918
}
919
920
RefPtr<ShutdownPromise> MediaFormatReader::TearDownDecoders() {
921
if (mAudio.mTaskQueue) {
922
mAudio.mTaskQueue->BeginShutdown();
923
mAudio.mTaskQueue->AwaitShutdownAndIdle();
924
mAudio.mTaskQueue = nullptr;
925
}
926
if (mVideo.mTaskQueue) {
927
mVideo.mTaskQueue->BeginShutdown();
928
mVideo.mTaskQueue->AwaitShutdownAndIdle();
929
mVideo.mTaskQueue = nullptr;
930
}
931
932
mDecoderFactory = nullptr;
933
mPlatform = nullptr;
934
mEncryptedPlatform = nullptr;
935
mVideoFrameContainer = nullptr;
936
937
ReleaseResources();
938
mBuffered.DisconnectAll();
939
return mTaskQueue->BeginShutdown();
940
}
941
942
nsresult MediaFormatReader::Init() {
943
MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread.");
944
945
mAudio.mTaskQueue =
946
new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
947
"MFR::mAudio::mTaskQueue");
948
949
mVideo.mTaskQueue =
950
new TaskQueue(GetMediaThreadPool(MediaThreadType::PLATFORM_DECODER),
951
"MFR::mVideo::mTaskQueue");
952
953
return NS_OK;
954
}
955
956
bool MediaFormatReader::ResolveSetCDMPromiseIfDone(TrackType aTrack) {
957
// When a CDM proxy is set, MFR would shutdown the existing MediaDataDecoder
958
// and would create new one for specific track in the next Update.
959
MOZ_ASSERT(OnTaskQueue());
960
961
if (mSetCDMPromise.IsEmpty()) {
962
return true;
963
}
964
965
MOZ_ASSERT(mCDMProxy);
966
if (mSetCDMForTracks.contains(aTrack)) {
967
mSetCDMForTracks -= aTrack;
968
}
969
970
if (mSetCDMForTracks.isEmpty()) {
971
LOGV("%s : Done ", __func__);
972
mSetCDMPromise.Resolve(/* aIgnored = */ true, __func__);
973
if (HasAudio()) {
974
ScheduleUpdate(TrackInfo::kAudioTrack);
975
}
976
if (HasVideo()) {
977
ScheduleUpdate(TrackInfo::kVideoTrack);
978
}
979
return true;
980
}
981
LOGV("%s : %s track is ready.", __func__, TrackTypeToStr(aTrack));
982
return false;
983
}
984
985
void MediaFormatReader::PrepareToSetCDMForTrack(TrackType aTrack) {
986
MOZ_ASSERT(OnTaskQueue());
987
LOGV("%s : %s", __func__, TrackTypeToStr(aTrack));
988
989
mSetCDMForTracks += aTrack;
990
if (mCDMProxy) {
991
// An old cdm proxy exists, so detaching old cdm proxy by shutting down
992
// MediaDataDecoder.
993
ShutdownDecoder(aTrack);
994
}
995
ScheduleUpdate(aTrack);
996
}
997
998
bool MediaFormatReader::IsDecoderWaitingForCDM(TrackType aTrack) {
999
MOZ_ASSERT(OnTaskQueue());
1000
return GetDecoderData(aTrack).IsEncrypted() &&
1001
mSetCDMForTracks.contains(aTrack) && !mCDMProxy;
1002
}
1003
1004
RefPtr<SetCDMPromise> MediaFormatReader::SetCDMProxy(CDMProxy* aProxy) {
1005
MOZ_ASSERT(OnTaskQueue());
1006
LOGV("SetCDMProxy (%p)", aProxy);
1007
1008
if (mShutdown) {
1009
return SetCDMPromise::CreateAndReject(
1010
MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
1011
"MediaFormatReader is shutting down"),
1012
__func__);
1013
}
1014
1015
mSetCDMPromise.RejectIfExists(
1016
MediaResult(NS_ERROR_DOM_INVALID_STATE_ERR,
1017
"Another new CDM proxy is being set."),
1018
__func__);
1019
1020
// Shutdown all decoders as switching CDM proxy indicates that it's
1021
// inappropriate for the existing decoders to continue decoding via the old
1022
// CDM proxy.
1023
if (HasAudio()) {
1024
PrepareToSetCDMForTrack(TrackInfo::kAudioTrack);
1025
}
1026
if (HasVideo()) {
1027
PrepareToSetCDMForTrack(TrackInfo::kVideoTrack);
1028
}
1029
1030
mCDMProxy = aProxy;
1031
1032
// Release old PDMFactory which contains an EMEDecoderModule.
1033
mEncryptedPlatform = nullptr;
1034
1035
if (!mInitDone || mSetCDMForTracks.isEmpty() || !mCDMProxy) {
1036
// 1) MFR is not initialized yet or
1037
// 2) Demuxer is initialized without active audio and video or
1038
// 3) A null cdm proxy is set
1039
// the promise can be resolved directly.
1040
mSetCDMForTracks.clear();
1041
return SetCDMPromise::CreateAndResolve(/* aIgnored = */ true, __func__);
1042
}
1043
1044
RefPtr<SetCDMPromise> p = mSetCDMPromise.Ensure(__func__);
1045
return p;
1046
}
1047
1048
bool MediaFormatReader::IsWaitingOnCDMResource() {
1049
MOZ_ASSERT(OnTaskQueue());
1050
return IsEncrypted() && !mCDMProxy;
1051
}
1052
1053
RefPtr<MediaFormatReader::MetadataPromise>
1054
MediaFormatReader::AsyncReadMetadata() {
1055
MOZ_ASSERT(OnTaskQueue());
1056
1057
MOZ_DIAGNOSTIC_ASSERT(mMetadataPromise.IsEmpty());
1058
1059
if (mInitDone) {
1060
// We are returning from dormant.
1061
MetadataHolder metadata;
1062
metadata.mInfo = MakeUnique<MediaInfo>(mInfo);
1063
return MetadataPromise::CreateAndResolve(std::move(metadata), __func__);
1064
}
1065
1066
RefPtr<MetadataPromise> p = mMetadataPromise.Ensure(__func__);
1067
1068
mDemuxer->Init()
1069
->Then(OwnerThread(), __func__, this,
1070
&MediaFormatReader::OnDemuxerInitDone,
1071
&MediaFormatReader::OnDemuxerInitFailed)
1072
->Track(mDemuxerInitRequest);
1073
return p;
1074
}
1075
1076
void MediaFormatReader::OnDemuxerInitDone(const MediaResult& aResult) {
1077
MOZ_ASSERT(OnTaskQueue());
1078
mDemuxerInitRequest.Complete();
1079
1080
if (NS_FAILED(aResult) && StaticPrefs::media_playback_warnings_as_errors()) {
1081
mMetadataPromise.Reject(aResult, __func__);
1082
return;
1083
}
1084
1085
mDemuxerInitDone = true;
1086
1087
UniquePtr<MetadataTags> tags(MakeUnique<MetadataTags>());
1088
1089
RefPtr<PDMFactory> platform;
1090
if (!IsWaitingOnCDMResource()) {
1091
platform = new PDMFactory();
1092
}
1093
1094
// To decode, we need valid video and a place to put it.
1095
bool videoActive = !!mDemuxer->GetNumberTracks(TrackInfo::kVideoTrack) &&
1096
GetImageContainer();
1097
1098
if (videoActive) {
1099
// We currently only handle the first video track.
1100
MutexAutoLock lock(mVideo.mMutex);
1101
mVideo.mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kVideoTrack, 0);
1102
if (!mVideo.mTrackDemuxer) {
1103
mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
1104
return;
1105
}
1106
1107
UniquePtr<TrackInfo> videoInfo = mVideo.mTrackDemuxer->GetInfo();
1108
videoActive = videoInfo && videoInfo->IsValid();
1109
if (videoActive) {
1110
if (platform &&
1111
!platform->SupportsMimeType(videoInfo->mMimeType, nullptr)) {
1112
// We have no decoder for this track. Error.
1113
mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
1114
return;
1115
}
1116
mInfo.mVideo = *videoInfo->GetAsVideoInfo();
1117
mVideo.mWorkingInfo = MakeUnique<VideoInfo>(mInfo.mVideo);
1118
for (const MetadataTag& tag : videoInfo->mTags) {
1119
tags->Put(tag.mKey, tag.mValue);
1120
}
1121
mVideo.mOriginalInfo = std::move(videoInfo);
1122
mTrackDemuxersMayBlock |= mVideo.mTrackDemuxer->GetSamplesMayBlock();
1123
} else {
1124
mVideo.mTrackDemuxer->BreakCycles();
1125
mVideo.mTrackDemuxer = nullptr;
1126
}
1127
}
1128
1129
bool audioActive = !!mDemuxer->GetNumberTracks(TrackInfo::kAudioTrack);
1130
if (audioActive) {
1131
MutexAutoLock lock(mAudio.mMutex);
1132
mAudio.mTrackDemuxer = mDemuxer->GetTrackDemuxer(TrackInfo::kAudioTrack, 0);
1133
if (!mAudio.mTrackDemuxer) {
1134
mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
1135
return;
1136
}
1137
1138
UniquePtr<TrackInfo> audioInfo = mAudio.mTrackDemuxer->GetInfo();
1139
// We actively ignore audio tracks that we know we can't play.
1140
audioActive = audioInfo && audioInfo->IsValid() &&
1141
(!platform ||
1142
platform->SupportsMimeType(audioInfo->mMimeType, nullptr));
1143
1144
if (audioActive) {
1145
mInfo.mAudio = *audioInfo->GetAsAudioInfo();
1146
mAudio.mWorkingInfo = MakeUnique<AudioInfo>(mInfo.mAudio);
1147
for (const MetadataTag& tag : audioInfo->mTags) {
1148
tags->Put(tag.mKey, tag.mValue);
1149
}
1150
mAudio.mOriginalInfo = std::move(audioInfo);
1151
mTrackDemuxersMayBlock |= mAudio.mTrackDemuxer->GetSamplesMayBlock();
1152
} else {
1153
mAudio.mTrackDemuxer->BreakCycles();
1154
mAudio.mTrackDemuxer = nullptr;
1155
}
1156
}
1157
1158
UniquePtr<EncryptionInfo> crypto = mDemuxer->GetCrypto();
1159
if (crypto && crypto->IsEncrypted()) {
1160
// Try and dispatch 'encrypted'. Won't go if ready state still HAVE_NOTHING.
1161
for (uint32_t i = 0; i < crypto->mInitDatas.Length(); i++) {
1162
mOnEncrypted.Notify(crypto->mInitDatas[i].mInitData,
1163
crypto->mInitDatas[i].mType);
1164
}
1165
mInfo.mCrypto = *crypto;
1166
}
1167
1168
auto videoDuration = HasVideo() ? mInfo.mVideo.mDuration : TimeUnit::Zero();
1169
auto audioDuration = HasAudio() ? mInfo.mAudio.mDuration : TimeUnit::Zero();
1170
1171
auto duration = std::max(videoDuration, audioDuration);
1172
if (duration.IsPositive()) {
1173
mInfo.mMetadataDuration = Some(duration);
1174
}
1175
1176
mInfo.mMediaSeekable = mDemuxer->IsSeekable();
1177
mInfo.mMediaSeekableOnlyInBufferedRanges =
1178
mDemuxer->IsSeekableOnlyInBufferedRanges();
1179
1180
if (!videoActive && !audioActive) {
1181
mMetadataPromise.Reject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__);
1182
return;
1183
}
1184
1185
mTags = std::move(tags);
1186
mInitDone = true;
1187
1188
// Try to get the start time.
1189
// For MSE case, the start time of each track is assumed to be 0.
1190
// For others, we must demux the first sample to know the start time for each
1191
// track.
1192
if (!mDemuxer->ShouldComputeStartTime()) {
1193
mAudio.mFirstDemuxedSampleTime.emplace(TimeUnit::Zero());
1194
mVideo.mFirstDemuxedSampleTime.emplace(TimeUnit::Zero());
1195
} else {
1196
if (HasAudio()) {
1197
RequestDemuxSamples(TrackInfo::kAudioTrack);
1198
}
1199
1200
if (HasVideo()) {
1201
RequestDemuxSamples(TrackInfo::kVideoTrack);
1202
}
1203
}
1204
1205
if (aResult != NS_OK) {
1206
mOnDecodeWarning.Notify(aResult);
1207
}
1208
1209
MaybeResolveMetadataPromise();
1210
}
1211
1212
void MediaFormatReader::MaybeResolveMetadataPromise() {
1213
MOZ_ASSERT(OnTaskQueue());
1214
1215
if ((HasAudio() && mAudio.mFirstDemuxedSampleTime.isNothing()) ||
1216
(HasVideo() && mVideo.mFirstDemuxedSampleTime.isNothing())) {
1217
return;
1218
}
1219
1220
TimeUnit startTime =
1221
std::min(mAudio.mFirstDemuxedSampleTime.refOr(TimeUnit::FromInfinity()),
1222
mVideo.mFirstDemuxedSampleTime.refOr(TimeUnit::FromInfinity()));
1223
1224
if (!startTime.IsInfinite()) {
1225
mInfo.mStartTime = startTime; // mInfo.mStartTime is initialized to 0.
1226
}
1227
1228
MetadataHolder metadata;
1229
metadata.mInfo = MakeUnique<MediaInfo>(mInfo);
1230
metadata.mTags = mTags->Count() ? std::move(mTags) : nullptr;
1231
1232
// We now have all the informations required to calculate the initial buffered
1233
// range.
1234
mHasStartTime = true;
1235
UpdateBuffered();
1236
1237
mMetadataPromise.Resolve(std::move(metadata), __func__);
1238
}
1239
1240
bool MediaFormatReader::IsEncrypted() const {
1241
return (HasAudio() && mAudio.GetCurrentInfo()->mCrypto.IsEncrypted()) ||
1242
(HasVideo() && mVideo.GetCurrentInfo()->mCrypto.IsEncrypted());
1243
}
1244
1245
void MediaFormatReader::OnDemuxerInitFailed(const MediaResult& aError) {
1246
mDemuxerInitRequest.Complete();
1247
mMetadataPromise.Reject(aError, __func__);
1248
}
1249
1250
void MediaFormatReader::ReadUpdatedMetadata(MediaInfo* aInfo) {
1251
// Called on the MDSM's TaskQueue.
1252
{
1253
MutexAutoLock lock(mVideo.mMutex);
1254
if (HasVideo()) {
1255
aInfo->mVideo = *mVideo.GetWorkingInfo()->GetAsVideoInfo();
1256
}
1257
}
1258
{
1259
MutexAutoLock lock(mAudio.mMutex);
1260
if (HasAudio()) {
1261
aInfo->mAudio = *mAudio.GetWorkingInfo()->GetAsAudioInfo();
1262
}
1263
}
1264
}
1265
1266
MediaFormatReader::DecoderData& MediaFormatReader::GetDecoderData(
1267
TrackType aTrack) {
1268
MOZ_ASSERT(aTrack == TrackInfo::kAudioTrack ||
1269
aTrack == TrackInfo::kVideoTrack);
1270
if (aTrack == TrackInfo::kAudioTrack) {
1271
return mAudio;
1272
}
1273
return mVideo;
1274
}
1275
1276
bool MediaFormatReader::ShouldSkip(TimeUnit aTimeThreshold) {
1277
MOZ_ASSERT(HasVideo());
1278
1279
if (!StaticPrefs::media_decoder_skip_to_next_key_frame_enabled()) {
1280
return false;
1281
}
1282
1283
TimeUnit nextKeyframe;
1284
nsresult rv = mVideo.mTrackDemuxer->GetNextRandomAccessPoint(&nextKeyframe);
1285
if (NS_FAILED(rv)) {
1286
// Only OggTrackDemuxer with video type gets into here.
1287
// We don't support skip-to-next-frame for this case.
1288
return false;
1289
}
1290
return (nextKeyframe <= aTimeThreshold ||
1291
(mVideo.mTimeThreshold &&
1292
mVideo.mTimeThreshold.ref().EndTime() < aTimeThreshold)) &&
1293
nextKeyframe.ToMicroseconds() >= 0 && !nextKeyframe.IsInfinite();
1294
}
1295
1296
RefPtr<MediaFormatReader::VideoDataPromise> MediaFormatReader::RequestVideoData(
1297
const TimeUnit& aTimeThreshold) {
1298
MOZ_ASSERT(OnTaskQueue());
1299
MOZ_DIAGNOSTIC_ASSERT(mSeekPromise.IsEmpty(),
1300
"No sample requests allowed while seeking");
1301
MOZ_DIAGNOSTIC_ASSERT(!mVideo.HasPromise(), "No duplicate sample requests");
1302
MOZ_DIAGNOSTIC_ASSERT(!mVideo.mSeekRequest.Exists() ||
1303
mVideo.mTimeThreshold.isSome());
1304
MOZ_DIAGNOSTIC_ASSERT(!IsSeeking(), "called mid-seek");
1305
LOGV("RequestVideoData(%" PRId64 ")", aTimeThreshold.ToMicroseconds());
1306
1307
if (!HasVideo()) {
1308
LOG("called with no video track");
1309
return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
1310
__func__);
1311
}
1312
1313
if (IsSeeking()) {
1314
LOG("called mid-seek. Rejecting.");
1315
return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
1316
__func__);
1317
}
1318
1319
if (mShutdown) {
1320
NS_WARNING("RequestVideoData on shutdown MediaFormatReader!");
1321
return VideoDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
1322
__func__);
1323
}
1324
1325
// Ensure we have no pending seek going as ShouldSkip could return out of date
1326
// information.
1327
if (!mVideo.HasInternalSeekPending() && ShouldSkip(aTimeThreshold)) {
1328
RefPtr<VideoDataPromise> p = mVideo.EnsurePromise(__func__);
1329
SkipVideoDemuxToNextKeyFrame(aTimeThreshold);
1330
return p;
1331
}
1332
1333
RefPtr<VideoDataPromise> p = mVideo.EnsurePromise(__func__);
1334
ScheduleUpdate(TrackInfo::kVideoTrack);
1335
1336
return p;
1337
}
1338
1339
void MediaFormatReader::OnDemuxFailed(TrackType aTrack,
1340
const MediaResult& aError) {
1341
MOZ_ASSERT(OnTaskQueue());
1342
LOG("Failed to demux %s, failure:%s",
1343
aTrack == TrackType::kVideoTrack ? "video" : "audio",
1344
aError.ErrorName().get());
1345
auto& decoder = GetDecoderData(aTrack);
1346
decoder.mDemuxRequest.Complete();
1347
switch (aError.Code()) {
1348
case NS_ERROR_DOM_MEDIA_END_OF_STREAM:
1349
DDLOG(DDLogCategory::Log,
1350
aTrack == TrackType::kVideoTrack ? "video_demux_interruption"
1351
: "audio_demux_interruption",
1352
aError);
1353
if (!decoder.mWaitingForData) {
1354
decoder.RequestDrain();
1355
}
1356
NotifyEndOfStream(aTrack);
1357
break;
1358
case NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA:
1359
DDLOG(DDLogCategory::Log,
1360
aTrack == TrackType::kVideoTrack ? "video_demux_interruption"
1361
: "audio_demux_interruption",
1362
aError);
1363
if (!decoder.mWaitingForData) {
1364
decoder.RequestDrain();
1365
}
1366
NotifyWaitingForData(aTrack);
1367
break;
1368
case NS_ERROR_DOM_MEDIA_CANCELED:
1369
DDLOG(DDLogCategory::Log,
1370
aTrack == TrackType::kVideoTrack ? "video_demux_interruption"
1371
: "audio_demux_interruption",
1372
aError);
1373
if (decoder.HasPromise()) {
1374
decoder.RejectPromise(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
1375
}
1376
break;
1377
default:
1378
DDLOG(DDLogCategory::Log,
1379
aTrack == TrackType::kVideoTrack ? "video_demux_error"
1380
: "audio_demux_error",
1381
aError);
1382
NotifyError(aTrack, aError);
1383
break;
1384
}
1385
}
1386
1387
void MediaFormatReader::DoDemuxVideo() {
1388
using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
1389
1390
DDLOG(DDLogCategory::Log, "video_demuxing", DDNoValue{});
1391
auto p = mVideo.mTrackDemuxer->GetSamples(1);
1392
1393
if (mVideo.mFirstDemuxedSampleTime.isNothing()) {
1394
RefPtr<MediaFormatReader> self = this;
1395
p = p->Then(
1396
OwnerThread(), __func__,
1397
[self](RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
1398
DDLOGEX(self.get(), DDLogCategory::Log, "video_first_demuxed",
1399
DDNoValue{});
1400
self->OnFirstDemuxCompleted(TrackInfo::kVideoTrack, aSamples);
1401
return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
1402
},
1403
[self](const MediaResult& aError) {
1404
DDLOGEX(self.get(), DDLogCategory::Log, "video_first_demuxing_error",
1405
aError);
1406
self->OnFirstDemuxFailed(TrackInfo::kVideoTrack, aError);
1407
return SamplesPromise::CreateAndReject(aError, __func__);
1408
});
1409
}
1410
1411
p->Then(OwnerThread(), __func__, this,
1412
&MediaFormatReader::OnVideoDemuxCompleted,
1413
&MediaFormatReader::OnVideoDemuxFailed)
1414
->Track(mVideo.mDemuxRequest);
1415
}
1416
1417
void MediaFormatReader::OnVideoDemuxCompleted(
1418
RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
1419
LOGV("%zu video samples demuxed (sid:%d)", aSamples->GetSamples().Length(),
1420
aSamples->GetSamples()[0]->mTrackInfo
1421
? aSamples->GetSamples()[0]->mTrackInfo->GetID()
1422
: 0);
1423
DDLOG(DDLogCategory::Log, "video_demuxed_samples",
1424
uint64_t(aSamples->GetSamples().Length()));
1425
mVideo.mDemuxRequest.Complete();
1426
mVideo.mQueuedSamples.AppendElements(aSamples->GetSamples());
1427
ScheduleUpdate(TrackInfo::kVideoTrack);
1428
}
1429
1430
RefPtr<MediaFormatReader::AudioDataPromise>
1431
MediaFormatReader::RequestAudioData() {
1432
MOZ_ASSERT(OnTaskQueue());
1433
MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasPromise(), "No duplicate sample requests");
1434
MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || mSeekPromise.IsEmpty(),
1435
"No sample requests allowed while seeking");
1436
MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || !mAudio.mSeekRequest.Exists() ||
1437
mAudio.mTimeThreshold.isSome());
1438
MOZ_DIAGNOSTIC_ASSERT(IsVideoSeeking() || !IsSeeking(), "called mid-seek");
1439
LOGV("");
1440
1441
if (!HasAudio()) {
1442
LOG("called with no audio track");
1443
return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR,
1444
__func__);
1445
}
1446
1447
if (IsSeeking()) {
1448
LOG("called mid-seek. Rejecting.");
1449
return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
1450
__func__);
1451
}
1452
1453
if (mShutdown) {
1454
NS_WARNING("RequestAudioData on shutdown MediaFormatReader!");
1455
return AudioDataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_CANCELED,
1456
__func__);
1457
}
1458
1459
RefPtr<AudioDataPromise> p = mAudio.EnsurePromise(__func__);
1460
ScheduleUpdate(TrackInfo::kAudioTrack);
1461
1462
return p;
1463
}
1464
1465
void MediaFormatReader::DoDemuxAudio() {
1466
using SamplesPromise = MediaTrackDemuxer::SamplesPromise;
1467
1468
DDLOG(DDLogCategory::Log, "audio_demuxing", DDNoValue{});
1469
auto p = mAudio.mTrackDemuxer->GetSamples(1);
1470
1471
if (mAudio.mFirstDemuxedSampleTime.isNothing()) {
1472
RefPtr<MediaFormatReader> self = this;
1473
p = p->Then(
1474
OwnerThread(), __func__,
1475
[self](RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
1476
DDLOGEX(self.get(), DDLogCategory::Log, "audio_first_demuxed",
1477
DDNoValue{});
1478
self->OnFirstDemuxCompleted(TrackInfo::kAudioTrack, aSamples);
1479
return SamplesPromise::CreateAndResolve(aSamples.forget(), __func__);
1480
},
1481
[self](const MediaResult& aError) {
1482
DDLOGEX(self.get(), DDLogCategory::Log, "audio_first_demuxing_error",
1483
aError);
1484
self->OnFirstDemuxFailed(TrackInfo::kAudioTrack, aError);
1485
return SamplesPromise::CreateAndReject(aError, __func__);
1486
});
1487
}
1488
1489
p->Then(OwnerThread(), __func__, this,
1490
&MediaFormatReader::OnAudioDemuxCompleted,
1491
&MediaFormatReader::OnAudioDemuxFailed)
1492
->Track(mAudio.mDemuxRequest);
1493
}
1494
1495
void MediaFormatReader::OnAudioDemuxCompleted(
1496
RefPtr<MediaTrackDemuxer::SamplesHolder> aSamples) {
1497
LOGV("%zu audio samples demuxed (sid:%d)", aSamples->GetSamples().Length(),
1498
aSamples->GetSamples()[0]->mTrackInfo
1499
? aSamples->GetSamples()[0]->mTrackInfo->GetID()
1500
: 0);
1501
DDLOG(DDLogCategory::Log, "audio_demuxed_samples",
1502
uint64_t(aSamples->GetSamples().Length()));
1503
mAudio.mDemuxRequest.Complete();
1504
mAudio.mQueuedSamples.AppendElements(aSamples->GetSamples());
1505
ScheduleUpdate(TrackInfo::kAudioTrack);
1506
}
1507
1508
void MediaFormatReader::NotifyNewOutput(
1509
TrackType aTrack, MediaDataDecoder::DecodedData&& aResults) {
1510
MOZ_ASSERT(OnTaskQueue());
1511
auto& decoder = GetDecoderData(aTrack);
1512
if (aResults.IsEmpty()) {
1513
DDLOG(DDLogCategory::Log,
1514
aTrack == TrackInfo::kAudioTrack ? "decoded_audio" : "decoded_video",
1515
"no output samples");
1516
} else
1517
for (auto&& sample : aResults) {
1518
if (DecoderDoctorLogger::IsDDLoggingEnabled()) {
1519
switch (sample->mType) {
1520
case MediaData::Type::AUDIO_DATA:
1521
DDLOGPR(DDLogCategory::Log,
1522
aTrack == TrackInfo::kAudioTrack ? "decoded_audio"
1523
: "decoded_got_audio!?",
1524
"{\"type\":\"AudioData\", \"offset\":%" PRIi64
1525
", \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
1526
", \"duration_us\":%" PRIi64 ", \"frames\":%" PRIu32
1527
", \"channels\":%" PRIu32 ", \"rate\":%" PRIu32
1528
", \"bytes\":%zu}",
1529
sample->mOffset, sample->mTime.ToMicroseconds(),
1530
sample->mTimecode.ToMicroseconds(),
1531
sample->mDuration.ToMicroseconds(),
1532
sample->As<AudioData>()->Frames(),
1533
sample->As<AudioData>()->mChannels,
1534
sample->As<AudioData>()->mRate,
1535
sample->As<AudioData>()->Data().Length());
1536
break;
1537
case MediaData::Type::VIDEO_DATA:
1538
DDLOGPR(DDLogCategory::Log,
1539
aTrack == TrackInfo::kVideoTrack ? "decoded_video"
1540
: "decoded_got_video!?",
1541
"{\"type\":\"VideoData\", \"offset\":%" PRIi64
1542
", \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
1543
", \"duration_us\":%" PRIi64
1544
", \"kf\":%s, \"size\":[%" PRIi32 ",%" PRIi32 "]}",
1545
sample->mOffset, sample->mTime.ToMicroseconds(),
1546
sample->mTimecode.ToMicroseconds(),
1547
sample->mDuration.ToMicroseconds(),
1548
sample->mKeyframe ? "true" : "false",
1549
sample->As<VideoData>()->mDisplay.width,
1550
sample->As<VideoData>()->mDisplay.height);
1551
break;
1552
case MediaData::Type::RAW_DATA:
1553
DDLOGPR(DDLogCategory::Log,
1554
aTrack == TrackInfo::kAudioTrack
1555
? "decoded_audio"
1556
: aTrack == TrackInfo::kVideoTrack ? "decoded_video"
1557
: "decoded_?",
1558
"{\"type\":\"RawData\", \"offset\":%" PRIi64
1559
" \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
1560
", \"duration_us\":%" PRIi64 ", \"kf\":%s}",
1561
sample->mOffset, sample->mTime.ToMicroseconds(),
1562
sample->mTimecode.ToMicroseconds(),
1563
sample->mDuration.ToMicroseconds(),
1564
sample->mKeyframe ? "true" : "false");
1565
break;
1566
case MediaData::Type::NULL_DATA:
1567
DDLOGPR(DDLogCategory::Log,
1568
aTrack == TrackInfo::kAudioTrack
1569
? "decoded_audio"
1570
: aTrack == TrackInfo::kVideoTrack ? "decoded_video"
1571
: "decoded_?",
1572
"{\"type\":\"NullData\", \"offset\":%" PRIi64
1573
" \"time_us\":%" PRIi64 ", \"timecode_us\":%" PRIi64
1574
", \"duration_us\":%" PRIi64 ", \"kf\":%s}",
1575
sample->mOffset, sample->mTime.ToMicroseconds(),
1576
sample->mTimecode.ToMicroseconds(),
1577
sample->mDuration.ToMicroseconds(),
1578
sample->mKeyframe ? "true" : "false");
1579
break;
1580
}
1581
}
1582
LOGV("Received new %s sample time:%" PRId64 " duration:%" PRId64,
1583
TrackTypeToStr(aTrack), sample->mTime.ToMicroseconds(),
1584
sample->mDuration.ToMicroseconds());
1585
decoder.mOutput.AppendElement(sample);
1586
decoder.mNumSamplesOutput++;
1587
decoder.mNumOfConsecutiveError = 0;
1588
}
1589
LOG("Done processing new %s samples", TrackTypeToStr(aTrack));
1590
1591
if (!aResults.IsEmpty()) {
1592
// We have decoded our first frame, we can now starts to skip future errors.
1593
decoder.mFirstFrameTime.reset();
1594
}
1595
ScheduleUpdate(aTrack);
1596
}
1597
1598
void MediaFormatReader::NotifyError(TrackType aTrack,
1599
const MediaResult& aError) {
1600
MOZ_ASSERT(OnTaskQueue());
1601
NS_WARNING(aError.Description().get());
1602
LOGV("%s Decoding error", TrackTypeToStr(aTrack));
1603
auto& decoder = GetDecoderData(aTrack);
1604
decoder.mError = decoder.HasFatalError() ? decoder.mError : Some(aError);
1605
1606
ScheduleUpdate(aTrack);
1607
}
1608
1609
void MediaFormatReader::NotifyWaitingForData(TrackType aTrack) {
1610
MOZ_ASSERT(OnTaskQueue());
1611
auto& decoder = GetDecoderData(aTrack);
1612
decoder.mWaitingForData = true;
1613
if (decoder.mTimeThreshold) {
1614
decoder.mTimeThreshold.ref().mWaiting = true;
1615
}
1616
ScheduleUpdate(aTrack);
1617
}
1618
1619
void MediaFormatReader::NotifyWaitingForKey(TrackType aTrack) {
1620
MOZ_ASSERT(OnTaskQueue());
1621
auto& decoder = GetDecoderData(aTrack);
1622
mOnWaitingForKey.Notify();
1623
if (!decoder.mDecodeRequest.Exists()) {
1624
LOGV("WaitingForKey received while no pending decode. Ignoring");
1625
return;
1626
}
1627
decoder.mWaitingForKey = true;
1628
ScheduleUpdate(aTrack);
1629
}
1630
1631
void MediaFormatReader::NotifyEndOfStream(TrackType aTrack) {
1632
MOZ_ASSERT(OnTaskQueue());
1633
auto& decoder = GetDecoderData(aTrack);
1634
decoder.mDemuxEOS = true;
1635
ScheduleUpdate(aTrack);
1636
}
1637
1638
bool MediaFormatReader::NeedInput(DecoderData& aDecoder) {
1639
// The decoder will not be fed a new raw sample until the current decoding
1640
// requests has completed.
1641
return (aDecoder.HasPromise() || aDecoder.mTimeThreshold.isSome()) &&
1642
!aDecoder.HasPendingDrain() && !aDecoder.HasFatalError() &&
1643
!aDecoder.mDemuxRequest.Exists() && !aDecoder.mOutput.Length() &&
1644
!aDecoder.HasInternalSeekPending() &&
1645
!aDecoder.mDecodeRequest.Exists();
1646
}
1647
1648
void MediaFormatReader::ScheduleUpdate(TrackType aTrack) {
1649
MOZ_ASSERT(OnTaskQueue());
1650
if (mShutdown) {
1651
return;
1652
}
1653
auto& decoder = GetDecoderData(aTrack);
1654
MOZ_RELEASE_ASSERT(decoder.GetCurrentInfo(),
1655
"Can only schedule update when track exists");
1656
1657
if (decoder.mUpdateScheduled) {
1658
return;
1659
}
1660
LOGV("SchedulingUpdate(%s)", TrackTypeToStr(aTrack));
1661
decoder.mUpdateScheduled = true;
1662
RefPtr<nsIRunnable> task(NewRunnableMethod<TrackType>(
1663
"MediaFormatReader::Update", this, &MediaFormatReader::Update, aTrack));
1664
nsresult rv = OwnerThread()->Dispatch(task.forget());
1665
MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
1666
Unused << rv;
1667
}
1668
1669
bool MediaFormatReader::UpdateReceivedNewData(TrackType aTrack) {
1670
MOZ_ASSERT(OnTaskQueue());
1671
auto& decoder = GetDecoderData(aTrack);
1672
1673
if (!decoder.mReceivedNewData) {
1674
return false;
1675
}
1676
1677
// We do not want to clear mWaitingForData while there are pending
1678
// demuxing or seeking operations that could affect the value of this flag.
1679
// This is in order to ensure that we will retry once they complete as we may
1680
// now have new data that could potentially allow those operations to
1681
// successfully complete if tried again.
1682
if (decoder.mSeekRequest.Exists()) {
1683
// Nothing more to do until this operation complete.
1684
return true;
1685
}
1686