already_AddRefed<SourceBufferDecoder>
MediaSourceReader::FirstDecoder(MediaData::Type aType)
{
  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
  TrackBuffer* trackBuffer =
    aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
  MOZ_ASSERT(trackBuffer);
  const nsTArray<nsRefPtr<SourceBufferDecoder>>& decoders = trackBuffer->Decoders();
  if (decoders.IsEmpty()) {
    return nullptr;
  }

  nsRefPtr<SourceBufferDecoder> firstDecoder;
  media::TimeUnit lowestStartTime{media::TimeUnit::FromInfinity()};


  for (uint32_t i = 0; i < decoders.Length(); ++i) {
    media::TimeIntervals r = decoders[i]->GetBuffered();
    if (!r.Length()) {
      continue;
    }
    media::TimeUnit start = r.GetStart();
    if (start < lowestStartTime) {
      firstDecoder = decoders[i];
      lowestStartTime = start;
    }
  }
  return firstDecoder.forget();
}
bool
MediaSourceReader::HaveData(int64_t aTarget, MediaData::Type aType)
{
  TrackBuffer* trackBuffer = aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
  MOZ_ASSERT(trackBuffer);
  nsRefPtr<SourceBufferDecoder> decoder = SelectDecoder(aTarget, EOS_FUZZ_US, trackBuffer->Decoders());
  return !!decoder;
}
int64_t
MediaSourceReader::LastSampleTime(MediaData::Type aType)
{
  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());

  TrackBuffer* trackBuffer =
    aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
  media::TimeIntervals buffered = trackBuffer->Buffered();
  return buffered.GetEnd().ToMicroseconds() - 1;
}
int64_t
MediaSourceReader::LastSampleTime(MediaData::Type aType)
{
  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());

  TrackBuffer* trackBuffer =
  aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
  nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
  trackBuffer->Buffered(buffered);
  return buffered->GetEndTime() * USECS_PER_S - 1;
}
bool
MediaSourceReader::IsNearEnd(MediaData::Type aType, int64_t aTime)
{
  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
  if (!mEnded) {
    return false;
  }
  TrackBuffer* trackBuffer =
    aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
  media::TimeIntervals buffered = trackBuffer->Buffered();
  return aTime >= buffered.GetEnd().ToMicroseconds() - EOS_FUZZ_US;
}
bool
MediaSourceReader::IsNearEnd(MediaData::Type aType, int64_t aTime)
{
  ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
  if (!mEnded) {
    return false;
  }
  TrackBuffer* trackBuffer =
    aType == MediaData::AUDIO_DATA ? mAudioTrack : mVideoTrack;
  nsRefPtr<dom::TimeRanges> buffered = new dom::TimeRanges();
  trackBuffer->Buffered(buffered);
  return aTime >= (buffered->GetEndTime() * USECS_PER_S - EOS_FUZZ_US);
}