Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/mediasource/MediaSourceDemuxer.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 "MediaSourceDemuxer.h"
8
9
#include "MediaSourceUtils.h"
10
#include "OpusDecoder.h"
11
#include "SourceBufferList.h"
12
#include "VorbisDecoder.h"
13
#include "VideoUtils.h"
14
#include "nsPrintfCString.h"
15
16
#include <algorithm>
17
#include <limits>
18
#include <stdint.h>
19
20
namespace mozilla {
21
22
typedef TrackInfo::TrackType TrackType;
23
using media::TimeUnit;
24
using media::TimeIntervals;
25
26
MediaSourceDemuxer::MediaSourceDemuxer(AbstractThread* aAbstractMainThread)
27
  : mTaskQueue(new TaskQueue(GetMediaThreadPool(MediaThreadType::PLAYBACK),
28
                             "MediaSourceDemuxer::mTaskQueue"))
29
  , mMonitor("MediaSourceDemuxer")
30
0
{
31
0
  MOZ_ASSERT(NS_IsMainThread());
32
0
}
33
34
constexpr TimeUnit MediaSourceDemuxer::EOS_FUZZ;
35
36
RefPtr<MediaSourceDemuxer::InitPromise>
37
MediaSourceDemuxer::Init()
38
0
{
39
0
  RefPtr<MediaSourceDemuxer> self = this;
40
0
  return InvokeAsync(GetTaskQueue(), __func__,
41
0
    [self](){
42
0
      if (self->ScanSourceBuffersForContent()) {
43
0
        return InitPromise::CreateAndResolve(NS_OK, __func__);
44
0
      }
45
0
46
0
      RefPtr<InitPromise> p = self->mInitPromise.Ensure(__func__);
47
0
48
0
      return p;
49
0
    });
50
0
}
51
52
void
53
MediaSourceDemuxer::AddSizeOfResources(
54
  MediaSourceDecoder::ResourceSizes* aSizes)
55
0
{
56
0
  MOZ_ASSERT(NS_IsMainThread());
57
0
58
0
  // NB: The track buffers must only be accessed on the TaskQueue.
59
0
  RefPtr<MediaSourceDemuxer> self = this;
60
0
  RefPtr<MediaSourceDecoder::ResourceSizes> sizes = aSizes;
61
0
  nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
62
0
    "MediaSourceDemuxer::AddSizeOfResources", [self, sizes]() {
63
0
      for (const RefPtr<TrackBuffersManager>& manager : self->mSourceBuffers) {
64
0
        manager->AddSizeOfResources(sizes);
65
0
      }
66
0
    });
67
0
68
0
  nsresult rv = GetTaskQueue()->Dispatch(task.forget());
69
0
  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
70
0
  Unused << rv;
71
0
}
72
73
void MediaSourceDemuxer::NotifyInitDataArrived()
74
0
{
75
0
  RefPtr<MediaSourceDemuxer> self = this;
76
0
  nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
77
0
    "MediaSourceDemuxer::NotifyInitDataArrived", [self]() {
78
0
      if (self->mInitPromise.IsEmpty()) {
79
0
        return;
80
0
      }
81
0
      if (self->ScanSourceBuffersForContent()) {
82
0
        self->mInitPromise.ResolveIfExists(NS_OK, __func__);
83
0
      }
84
0
    });
85
0
  nsresult rv = GetTaskQueue()->Dispatch(task.forget());
86
0
  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
87
0
  Unused << rv;
88
0
}
89
90
bool
91
MediaSourceDemuxer::ScanSourceBuffersForContent()
92
0
{
93
0
  MOZ_ASSERT(OnTaskQueue());
94
0
95
0
  if (mSourceBuffers.IsEmpty()) {
96
0
    return false;
97
0
  }
98
0
99
0
  MonitorAutoLock mon(mMonitor);
100
0
101
0
  bool haveEmptySourceBuffer = false;
102
0
  for (const auto& sourceBuffer : mSourceBuffers) {
103
0
    MediaInfo info = sourceBuffer->GetMetadata();
104
0
    if (!info.HasAudio() && !info.HasVideo()) {
105
0
      haveEmptySourceBuffer = true;
106
0
    }
107
0
    if (info.HasAudio() && !mAudioTrack) {
108
0
      mInfo.mAudio = info.mAudio;
109
0
      mAudioTrack = sourceBuffer;
110
0
    }
111
0
    if (info.HasVideo() && !mVideoTrack) {
112
0
      mInfo.mVideo = info.mVideo;
113
0
      mVideoTrack = sourceBuffer;
114
0
    }
115
0
    if (info.IsEncrypted() && !mInfo.IsEncrypted()) {
116
0
      mInfo.mCrypto = info.mCrypto;
117
0
    }
118
0
  }
119
0
  if (mInfo.HasAudio() && mInfo.HasVideo()) {
120
0
    // We have both audio and video. We can ignore non-ready source buffer.
121
0
    return true;
122
0
  }
123
0
  return !haveEmptySourceBuffer;
124
0
}
125
126
uint32_t
127
MediaSourceDemuxer::GetNumberTracks(TrackType aType) const
128
0
{
129
0
  MonitorAutoLock mon(mMonitor);
130
0
131
0
  switch (aType) {
132
0
    case TrackType::kAudioTrack:
133
0
      return mInfo.HasAudio() ? 1u : 0;
134
0
    case TrackType::kVideoTrack:
135
0
      return mInfo.HasVideo() ? 1u : 0;
136
0
    default:
137
0
      return 0;
138
0
  }
139
0
}
140
141
already_AddRefed<MediaTrackDemuxer>
142
MediaSourceDemuxer::GetTrackDemuxer(TrackType aType, uint32_t aTrackNumber)
143
0
{
144
0
  RefPtr<TrackBuffersManager> manager = GetManager(aType);
145
0
  if (!manager) {
146
0
    return nullptr;
147
0
  }
148
0
  RefPtr<MediaSourceTrackDemuxer> e =
149
0
    new MediaSourceTrackDemuxer(this, aType, manager);
150
0
  DDLINKCHILD("track demuxer", e.get());
151
0
  mDemuxers.AppendElement(e);
152
0
  return e.forget();
153
0
}
154
155
bool
156
MediaSourceDemuxer::IsSeekable() const
157
0
{
158
0
  return true;
159
0
}
160
161
UniquePtr<EncryptionInfo>
162
MediaSourceDemuxer::GetCrypto()
163
0
{
164
0
  MonitorAutoLock mon(mMonitor);
165
0
  auto crypto = MakeUnique<EncryptionInfo>();
166
0
  *crypto = mInfo.mCrypto;
167
0
  return crypto;
168
0
}
169
170
void
171
MediaSourceDemuxer::AttachSourceBuffer(
172
  RefPtr<TrackBuffersManager>& aSourceBuffer)
173
0
{
174
0
  nsCOMPtr<nsIRunnable> task = NewRunnableMethod<RefPtr<TrackBuffersManager>&&>(
175
0
    "MediaSourceDemuxer::DoAttachSourceBuffer",
176
0
    this,
177
0
    &MediaSourceDemuxer::DoAttachSourceBuffer,
178
0
    aSourceBuffer);
179
0
  nsresult rv = GetTaskQueue()->Dispatch(task.forget());
180
0
  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
181
0
  Unused << rv;
182
0
}
183
184
void
185
MediaSourceDemuxer::DoAttachSourceBuffer(
186
  RefPtr<mozilla::TrackBuffersManager>&& aSourceBuffer)
187
0
{
188
0
  MOZ_ASSERT(OnTaskQueue());
189
0
  mSourceBuffers.AppendElement(std::move(aSourceBuffer));
190
0
  ScanSourceBuffersForContent();
191
0
}
192
193
void
194
MediaSourceDemuxer::DetachSourceBuffer(
195
  RefPtr<TrackBuffersManager>& aSourceBuffer)
196
0
{
197
0
  nsCOMPtr<nsIRunnable> task = NewRunnableMethod<RefPtr<TrackBuffersManager>&&>(
198
0
    "MediaSourceDemuxer::DoDetachSourceBuffer",
199
0
    this,
200
0
    &MediaSourceDemuxer::DoDetachSourceBuffer,
201
0
    aSourceBuffer);
202
0
  nsresult rv = GetTaskQueue()->Dispatch(task.forget());
203
0
  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
204
0
  Unused << rv;
205
0
}
206
207
void
208
MediaSourceDemuxer::DoDetachSourceBuffer(
209
  RefPtr<TrackBuffersManager>&& aSourceBuffer)
210
0
{
211
0
  MOZ_ASSERT(OnTaskQueue());
212
0
  mSourceBuffers.RemoveElementsBy(
213
0
    [&aSourceBuffer](const RefPtr<TrackBuffersManager> aLinkedSourceBuffer) {
214
0
      return aLinkedSourceBuffer == aSourceBuffer;
215
0
    });
216
0
  {
217
0
    MonitorAutoLock mon(mMonitor);
218
0
    if (aSourceBuffer == mAudioTrack) {
219
0
      mAudioTrack = nullptr;
220
0
    }
221
0
    if (aSourceBuffer == mVideoTrack) {
222
0
      mVideoTrack = nullptr;
223
0
    }
224
0
  }
225
0
226
0
  for (auto& demuxer : mDemuxers) {
227
0
    if (demuxer->HasManager(aSourceBuffer)) {
228
0
      demuxer->DetachManager();
229
0
    }
230
0
  }
231
0
  ScanSourceBuffersForContent();
232
0
}
233
234
TrackInfo*
235
MediaSourceDemuxer::GetTrackInfo(TrackType aTrack)
236
{
237
  MonitorAutoLock mon(mMonitor);
238
  switch (aTrack) {
239
    case TrackType::kAudioTrack:
240
      return &mInfo.mAudio;
241
    case TrackType::kVideoTrack:
242
      return &mInfo.mVideo;
243
    default:
244
      return nullptr;
245
  }
246
}
247
248
RefPtr<TrackBuffersManager>
249
MediaSourceDemuxer::GetManager(TrackType aTrack)
250
{
251
  MonitorAutoLock mon(mMonitor);
252
  switch (aTrack) {
253
    case TrackType::kAudioTrack:
254
      return mAudioTrack;
255
    case TrackType::kVideoTrack:
256
      return mVideoTrack;
257
    default:
258
      return nullptr;
259
  }
260
}
261
262
MediaSourceDemuxer::~MediaSourceDemuxer()
263
0
{
264
0
  mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__);
265
0
}
266
267
void
268
MediaSourceDemuxer::GetMozDebugReaderData(nsACString& aString)
269
0
{
270
0
  MonitorAutoLock mon(mMonitor);
271
0
  nsAutoCString result;
272
0
  result += nsPrintfCString("Dumping Data for Demuxer: %p\n", this);
273
0
  if (mAudioTrack) {
274
0
    result += nsPrintfCString(
275
0
      "\tDumping Audio Track Buffer(%s): mLastAudioTime=%f\n"
276
0
      "\t\tAudio Track Buffer Details: NumSamples=%zu"
277
0
      " Size=%u Evictable=%u "
278
0
      "NextGetSampleIndex=%u NextInsertionIndex=%d\n",
279
0
      mAudioTrack->mType.Type().AsString().get(),
280
0
      mAudioTrack->mAudioTracks.mNextSampleTime.ToSeconds(),
281
0
      mAudioTrack->mAudioTracks.mBuffers[0].Length(),
282
0
      mAudioTrack->mAudioTracks.mSizeBuffer,
283
0
      mAudioTrack->Evictable(TrackInfo::kAudioTrack),
284
0
      mAudioTrack->mAudioTracks.mNextGetSampleIndex.valueOr(-1),
285
0
      mAudioTrack->mAudioTracks.mNextInsertionIndex.valueOr(-1));
286
0
287
0
    result += nsPrintfCString(
288
0
      "\t\tAudio Track Buffered: ranges=%s\n",
289
0
      DumpTimeRanges(mAudioTrack->SafeBuffered(TrackInfo::kAudioTrack)).get());
290
0
  }
291
0
  if (mVideoTrack) {
292
0
    result += nsPrintfCString(
293
0
      "\tDumping Video Track Buffer(%s): mLastVideoTime=%f\n"
294
0
      "\t\tVideo Track Buffer Details: NumSamples=%zu"
295
0
      " Size=%u Evictable=%u "
296
0
      "NextGetSampleIndex=%u NextInsertionIndex=%d\n",
297
0
      mVideoTrack->mType.Type().AsString().get(),
298
0
      mVideoTrack->mVideoTracks.mNextSampleTime.ToSeconds(),
299
0
      mVideoTrack->mVideoTracks.mBuffers[0].Length(),
300
0
      mVideoTrack->mVideoTracks.mSizeBuffer,
301
0
      mVideoTrack->Evictable(TrackInfo::kVideoTrack),
302
0
      mVideoTrack->mVideoTracks.mNextGetSampleIndex.valueOr(-1),
303
0
      mVideoTrack->mVideoTracks.mNextInsertionIndex.valueOr(-1));
304
0
305
0
    result += nsPrintfCString(
306
0
      "\t\tVideo Track Buffered: ranges=%s\n",
307
0
      DumpTimeRanges(mVideoTrack->SafeBuffered(TrackInfo::kVideoTrack)).get());
308
0
  }
309
0
  aString += result;
310
0
}
311
312
MediaSourceTrackDemuxer::MediaSourceTrackDemuxer(MediaSourceDemuxer* aParent,
313
                                                 TrackInfo::TrackType aType,
314
                                                 TrackBuffersManager* aManager)
315
  : mParent(aParent)
316
  , mType(aType)
317
  , mMonitor("MediaSourceTrackDemuxer")
318
  , mManager(aManager)
319
  , mReset(true)
320
  , mPreRoll(TimeUnit::FromMicroseconds(
321
      OpusDataDecoder::IsOpus(mParent->GetTrackInfo(mType)->mMimeType) ||
322
      VorbisDataDecoder::IsVorbis(mParent->GetTrackInfo(mType)->mMimeType)
323
      ? 80000
324
      : mParent->GetTrackInfo(mType)->mMimeType.EqualsLiteral("audio/mp4a-latm")
325
        // AAC encoder delay is by default 2112 audio frames.
326
        // See https://developer.apple.com/library/content/documentation/QuickTime/QTFF/QTFFAppenG/QTFFAppenG.html
327
        // So we always seek 2112 frames
328
        ? (2112 * 1000000ULL
329
           / mParent->GetTrackInfo(mType)->GetAsAudioInfo()->mRate)
330
        : 0))
331
0
{
332
0
}
333
334
UniquePtr<TrackInfo>
335
MediaSourceTrackDemuxer::GetInfo() const
336
0
{
337
0
  return mParent->GetTrackInfo(mType)->Clone();
338
0
}
339
340
RefPtr<MediaSourceTrackDemuxer::SeekPromise>
341
MediaSourceTrackDemuxer::Seek(const TimeUnit& aTime)
342
0
{
343
0
  MOZ_ASSERT(mParent, "Called after BreackCycle()");
344
0
  return InvokeAsync(
345
0
           mParent->GetTaskQueue(), this, __func__,
346
0
           &MediaSourceTrackDemuxer::DoSeek, aTime);
347
0
}
348
349
RefPtr<MediaSourceTrackDemuxer::SamplesPromise>
350
MediaSourceTrackDemuxer::GetSamples(int32_t aNumSamples)
351
0
{
352
0
  MOZ_ASSERT(mParent, "Called after BreackCycle()");
353
0
  return InvokeAsync(mParent->GetTaskQueue(), this, __func__,
354
0
                     &MediaSourceTrackDemuxer::DoGetSamples, aNumSamples);
355
0
}
356
357
void
358
MediaSourceTrackDemuxer::Reset()
359
0
{
360
0
  MOZ_ASSERT(mParent, "Called after BreackCycle()");
361
0
  RefPtr<MediaSourceTrackDemuxer> self = this;
362
0
  nsCOMPtr<nsIRunnable> task =
363
0
    NS_NewRunnableFunction("MediaSourceTrackDemuxer::Reset", [self]() {
364
0
      self->mNextSample.reset();
365
0
      self->mReset = true;
366
0
      if (!self->mManager) {
367
0
        return;
368
0
      }
369
0
      MOZ_ASSERT(self->OnTaskQueue());
370
0
      self->mManager->Seek(self->mType, TimeUnit::Zero(), TimeUnit::Zero());
371
0
      {
372
0
        MonitorAutoLock mon(self->mMonitor);
373
0
        self->mNextRandomAccessPoint = self->mManager->GetNextRandomAccessPoint(
374
0
          self->mType, MediaSourceDemuxer::EOS_FUZZ);
375
0
      }
376
0
    });
377
0
  nsresult rv = mParent->GetTaskQueue()->Dispatch(task.forget());
378
0
  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
379
0
  Unused << rv;
380
0
}
381
382
nsresult
383
MediaSourceTrackDemuxer::GetNextRandomAccessPoint(TimeUnit* aTime)
384
0
{
385
0
  MonitorAutoLock mon(mMonitor);
386
0
  *aTime = mNextRandomAccessPoint;
387
0
  return NS_OK;
388
0
}
389
390
RefPtr<MediaSourceTrackDemuxer::SkipAccessPointPromise>
391
MediaSourceTrackDemuxer::SkipToNextRandomAccessPoint(
392
  const TimeUnit& aTimeThreshold)
393
0
{
394
0
  return InvokeAsync(
395
0
           mParent->GetTaskQueue(), this, __func__,
396
0
           &MediaSourceTrackDemuxer::DoSkipToNextRandomAccessPoint,
397
0
           aTimeThreshold);
398
0
}
399
400
media::TimeIntervals
401
MediaSourceTrackDemuxer::GetBuffered()
402
0
{
403
0
  MonitorAutoLock mon(mMonitor);
404
0
  if (!mManager) {
405
0
    return media::TimeIntervals();
406
0
  }
407
0
  return mManager->Buffered();
408
0
}
409
410
void
411
MediaSourceTrackDemuxer::BreakCycles()
412
0
{
413
0
  RefPtr<MediaSourceTrackDemuxer> self = this;
414
0
  nsCOMPtr<nsIRunnable> task =
415
0
    NS_NewRunnableFunction("MediaSourceTrackDemuxer::BreakCycles", [self]() {
416
0
      self->DetachManager();
417
0
      self->mParent = nullptr;
418
0
    });
419
0
  nsresult rv = mParent->GetTaskQueue()->Dispatch(task.forget());
420
0
  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
421
0
  Unused << rv;
422
0
}
423
424
RefPtr<MediaSourceTrackDemuxer::SeekPromise>
425
MediaSourceTrackDemuxer::DoSeek(const TimeUnit& aTime)
426
0
{
427
0
  if (!mManager) {
428
0
    return SeekPromise::CreateAndReject(
429
0
      MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
430
0
                  RESULT_DETAIL("manager is detached.")), __func__);
431
0
  }
432
0
433
0
  MOZ_ASSERT(OnTaskQueue());
434
0
  TimeIntervals buffered = mManager->Buffered(mType);
435
0
  // Fuzz factor represents a +/- threshold. So when seeking it allows the gap
436
0
  // to be twice as big as the fuzz value. We only want to allow EOS_FUZZ gap.
437
0
  buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
438
0
  TimeUnit seekTime = std::max(aTime - mPreRoll, TimeUnit::Zero());
439
0
440
0
  if (mManager->IsEnded() && seekTime >= buffered.GetEnd()) {
441
0
    // We're attempting to seek past the end time. Cap seekTime so that we seek
442
0
    // to the last sample instead.
443
0
    seekTime =
444
0
      std::max(mManager->HighestStartTime(mType) - mPreRoll, TimeUnit::Zero());
445
0
  }
446
0
  if (!buffered.ContainsWithStrictEnd(seekTime)) {
447
0
    if (!buffered.ContainsWithStrictEnd(aTime)) {
448
0
      // We don't have the data to seek to.
449
0
      return SeekPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA,
450
0
                                          __func__);
451
0
    }
452
0
    // Theoretically we should reject the promise with WAITING_FOR_DATA,
453
0
    // however, to avoid unwanted regressions we assume that if at this time
454
0
    // we don't have the wanted data it won't come later.
455
0
    // Instead of using the pre-rolled time, use the earliest time available in
456
0
    // the interval.
457
0
    TimeIntervals::IndexType index = buffered.Find(aTime);
458
0
    MOZ_ASSERT(index != TimeIntervals::NoIndex);
459
0
    seekTime = buffered[index].mStart;
460
0
  }
461
0
  seekTime = mManager->Seek(mType, seekTime, MediaSourceDemuxer::EOS_FUZZ);
462
0
  MediaResult result = NS_OK;
463
0
  RefPtr<MediaRawData> sample =
464
0
    mManager->GetSample(mType,
465
0
                        TimeUnit::Zero(),
466
0
                        result);
467
0
  MOZ_ASSERT(NS_SUCCEEDED(result) && sample);
468
0
  mNextSample = Some(sample);
469
0
  mReset = false;
470
0
  {
471
0
    MonitorAutoLock mon(mMonitor);
472
0
    mNextRandomAccessPoint =
473
0
      mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ);
474
0
  }
475
0
  return SeekPromise::CreateAndResolve(seekTime, __func__);
476
0
}
477
478
RefPtr<MediaSourceTrackDemuxer::SamplesPromise>
479
MediaSourceTrackDemuxer::DoGetSamples(int32_t aNumSamples)
480
0
{
481
0
  if (!mManager) {
482
0
    return SamplesPromise::CreateAndReject(
483
0
      MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
484
0
                  RESULT_DETAIL("manager is detached.")), __func__);
485
0
  }
486
0
487
0
  MOZ_ASSERT(OnTaskQueue());
488
0
  if (mReset) {
489
0
    // If a seek (or reset) was recently performed, we ensure that the data
490
0
    // we are about to retrieve is still available.
491
0
    TimeIntervals buffered = mManager->Buffered(mType);
492
0
    buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
493
0
494
0
    if (!buffered.Length() && mManager->IsEnded()) {
495
0
      return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
496
0
                                             __func__);
497
0
    }
498
0
    if (!buffered.ContainsWithStrictEnd(TimeUnit::Zero())) {
499
0
      return SamplesPromise::CreateAndReject(
500
0
        NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
501
0
    }
502
0
    mReset = false;
503
0
  }
504
0
  RefPtr<MediaRawData> sample;
505
0
  if (mNextSample) {
506
0
    sample = mNextSample.ref();
507
0
    mNextSample.reset();
508
0
  } else {
509
0
    MediaResult result = NS_OK;
510
0
    sample = mManager->GetSample(mType, MediaSourceDemuxer::EOS_FUZZ, result);
511
0
    if (!sample) {
512
0
      if (result == NS_ERROR_DOM_MEDIA_END_OF_STREAM ||
513
0
          result == NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA) {
514
0
        return SamplesPromise::CreateAndReject(
515
0
          (result == NS_ERROR_DOM_MEDIA_END_OF_STREAM && mManager->IsEnded())
516
0
          ? NS_ERROR_DOM_MEDIA_END_OF_STREAM
517
0
          : NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, __func__);
518
0
      }
519
0
      return SamplesPromise::CreateAndReject(result, __func__);
520
0
    }
521
0
  }
522
0
  RefPtr<SamplesHolder> samples = new SamplesHolder;
523
0
  samples->mSamples.AppendElement(sample);
524
0
  if (mNextRandomAccessPoint <= sample->mTime) {
525
0
    MonitorAutoLock mon(mMonitor);
526
0
    mNextRandomAccessPoint =
527
0
      mManager->GetNextRandomAccessPoint(mType, MediaSourceDemuxer::EOS_FUZZ);
528
0
  }
529
0
  return SamplesPromise::CreateAndResolve(samples, __func__);
530
0
}
531
532
RefPtr<MediaSourceTrackDemuxer::SkipAccessPointPromise>
533
MediaSourceTrackDemuxer::DoSkipToNextRandomAccessPoint(
534
  const TimeUnit& aTimeThreadshold)
535
0
{
536
0
  if (!mManager) {
537
0
    return SkipAccessPointPromise::CreateAndReject(
538
0
      SkipFailureHolder(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR,
539
0
                        RESULT_DETAIL("manager is detached.")), 0), __func__);
540
0
  }
541
0
542
0
  MOZ_ASSERT(OnTaskQueue());
543
0
  uint32_t parsed = 0;
544
0
  // Ensure that the data we are about to skip to is still available.
545
0
  TimeIntervals buffered = mManager->Buffered(mType);
546
0
  buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ / 2);
547
0
  if (buffered.ContainsWithStrictEnd(aTimeThreadshold)) {
548
0
    bool found;
549
0
    parsed = mManager->SkipToNextRandomAccessPoint(mType,
550
0
                                                   aTimeThreadshold,
551
0
                                                   MediaSourceDemuxer::EOS_FUZZ,
552
0
                                                   found);
553
0
    if (found) {
554
0
      return SkipAccessPointPromise::CreateAndResolve(parsed, __func__);
555
0
    }
556
0
  }
557
0
  SkipFailureHolder holder(
558
0
    mManager->IsEnded() ? NS_ERROR_DOM_MEDIA_END_OF_STREAM :
559
0
                          NS_ERROR_DOM_MEDIA_WAITING_FOR_DATA, parsed);
560
0
  return SkipAccessPointPromise::CreateAndReject(holder, __func__);
561
0
}
562
563
bool
564
MediaSourceTrackDemuxer::HasManager(TrackBuffersManager* aManager) const
565
0
{
566
0
  MOZ_ASSERT(OnTaskQueue());
567
0
  return mManager == aManager;
568
0
}
569
570
void
571
MediaSourceTrackDemuxer::DetachManager()
572
0
{
573
0
  MOZ_ASSERT(OnTaskQueue());
574
0
  MonitorAutoLock mon(mMonitor);
575
0
  mManager = nullptr;
576
0
}
577
578
} // namespace mozilla