Coverage Report

Created: 2018-09-25 14:53

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