Exemplo n.º 1
0
void
SeekTask::CheckIfSeekComplete()
{
  AssertOwnerThread();

  const bool videoSeekComplete = IsVideoSeekComplete();
  if (HasVideo() && !videoSeekComplete) {
    // We haven't reached the target. Ensure we have requested another sample.
    if (NS_FAILED(EnsureVideoDecodeTaskQueued())) {
      DECODER_WARN("Failed to request video during seek");
      RejectIfExist(__func__);
    }
  }

  const bool audioSeekComplete = IsAudioSeekComplete();
  if (HasAudio() && !audioSeekComplete) {
    // We haven't reached the target. Ensure we have requested another sample.
    if (NS_FAILED(EnsureAudioDecodeTaskQueued())) {
      DECODER_WARN("Failed to request audio during seek");
      RejectIfExist(__func__);
    }
  }

  SAMPLE_LOG("CheckIfSeekComplete() audioSeekComplete=%d videoSeekComplete=%d",
             audioSeekComplete, videoSeekComplete);

  if (audioSeekComplete && videoSeekComplete) {
    Resolve(__func__); // Call to MDSM::SeekCompleted();
  }
}
Exemplo n.º 2
0
void
SeekTask::OnSeekRejected(nsresult aResult)
{
  AssertOwnerThread();
  mSeekRequest.Complete();
  MOZ_ASSERT(NS_FAILED(aResult), "Cancels should also disconnect mSeekRequest");
  RejectIfExist(__func__);
}
Exemplo n.º 3
0
void
SeekTask::OnVideoDecoded(MediaData* aVideoSample)
{
  AssertOwnerThread();
  RefPtr<MediaData> video(aVideoSample);
  MOZ_ASSERT(video);

  // The MDSM::mDecodedVideoEndTime will be updated once the whole SeekTask is
  // resolved.

  SAMPLE_LOG("OnVideoDecoded [%lld,%lld] disc=%d",
             (video ? video->mTime : -1),
             (video ? video->GetEndTime() : -1),
             (video ? video->mDiscontinuity : 0));

  if (!Exists()) {
    // We've received a sample from a previous decode. Discard it.
    return;
  }

  if (mDropVideoUntilNextDiscontinuity) {
    if (video->mDiscontinuity) {
      mDropVideoUntilNextDiscontinuity = false;
    }
  }

  if (!mDropVideoUntilNextDiscontinuity) {
    // We must be after the discontinuity; we're receiving samples
    // at or after the seek target.
    if (mSeekJob.mTarget.IsFast() &&
        mSeekJob.mTarget.GetTime().ToMicroseconds() > mCurrentTimeBeforeSeek &&
        video->mTime < mCurrentTimeBeforeSeek) {
      // We are doing a fastSeek, but we ended up *before* the previous
      // playback position. This is surprising UX, so switch to an accurate
      // seek and decode to the seek target. This is not conformant to the
      // spec, fastSeek should always be fast, but until we get the time to
      // change all Readers to seek to the keyframe after the currentTime
      // in this case, we'll just decode forward. Bug 1026330.
      mSeekJob.mTarget.SetType(SeekTarget::Accurate);
    }
    if (mSeekJob.mTarget.IsFast()) {
      // Non-precise seek. We can stop the seek at the first sample.
      mSeekedVideoData = video;
    } else {
      // We're doing an accurate seek. We still need to discard
      // MediaData up to the one containing exact seek target.
      if (NS_FAILED(DropVideoUpToSeekTarget(video.get()))) {
        RejectIfExist(__func__);
        return;
      }
    }
  }
  CheckIfSeekComplete();
}
Exemplo n.º 4
0
void
AccurateSeekTask::OnNotDecoded(MediaData::Type aType,
                               MediaDecoderReader::NotDecodedReason aReason)
{
  AssertOwnerThread();
  MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");

  SAMPLE_LOG("OnNotDecoded type=%d reason=%u", aType, aReason);

  // Ignore pending requests from video-only seek.
  if (aType == MediaData::AUDIO_DATA && mTarget.IsVideoOnly()) {
    return;
  }

  if (aReason == MediaDecoderReader::DECODE_ERROR) {
    // If this is a decode error, delegate to the generic error path.
    CancelCallbacks();
    RejectIfExist(__func__);
    return;
  }

  // If the decoder is waiting for data, we tell it to call us back when the
  // data arrives.
  if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
    mReader->WaitForData(aType);
    return;
  }

  if (aReason == MediaDecoderReader::CANCELED) {
    if (aType == MediaData::AUDIO_DATA) {
      RequestAudioData();
    } else {
      RequestVideoData();
    }
    return;
  }

  if (aReason == MediaDecoderReader::END_OF_STREAM) {
    if (aType == MediaData::AUDIO_DATA) {
      mIsAudioQueueFinished = true;
      mDoneAudioSeeking = true;
    } else {
      mIsVideoQueueFinished = true;
      mDoneVideoSeeking = true;
      if (mFirstVideoFrameAfterSeek) {
        // Hit the end of stream. Move mFirstVideoFrameAfterSeek into
        // mSeekedVideoData so we have something to display after seeking.
        mSeekedVideoData = mFirstVideoFrameAfterSeek.forget();
      }
    }
    MaybeFinishSeek();
  }
}
Exemplo n.º 5
0
void
AccurateSeekTask::Discard()
{
  AssertOwnerThread();

  // Disconnect MDSM.
  RejectIfExist(__func__);

  // Disconnect MediaDecoderReaderWrapper.
  mSeekRequest.DisconnectIfExists();
  CancelCallbacks();

  mIsDiscarded = true;
}
Exemplo n.º 6
0
void
SeekTask::Discard()
{
  // Disconnect MediaDecoder.
  mSeekJob.RejectIfExists(__func__);

  // Disconnect MDSM.
  RejectIfExist(__func__);

  // Disconnect MediaDecoderReaderWrapper.
  mSeekRequest.DisconnectIfExists();
  CancelMediaDecoderReaderWrapperCallback();

  mIsDiscarded = true;
}
Exemplo n.º 7
0
void
SeekTask::OnVideoNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
{
  AssertOwnerThread();
  SAMPLE_LOG("OnVideoNotDecoded (aReason=%u)", aReason);

  if (aReason == MediaDecoderReader::DECODE_ERROR) {
    // If this is a decode error, delegate to the generic error path.
    RejectIfExist(__func__);
    return;
  }

  // If the decoder is waiting for data, we tell it to call us back when the
  // data arrives.
  if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
    MOZ_ASSERT(mReader->IsWaitForDataSupported(),
               "Readers that send WAITING_FOR_DATA need to implement WaitForData");
    mReader->WaitForData(MediaData::VIDEO_DATA);

    // We are out of data to decode and will enter buffering mode soon.
    // We want to play the frames we have already decoded, so we stop pre-rolling
    // and ensure that loadeddata is fired as required.
    mNeedToStopPrerollingVideo = true;
    return;
  }

  if (aReason == MediaDecoderReader::CANCELED) {
    EnsureVideoDecodeTaskQueued();
    return;
  }

  if (aReason == MediaDecoderReader::END_OF_STREAM) {

    if (Exists() && mFirstVideoFrameAfterSeek) {
      // Null sample. Hit end of stream. If we have decoded a frame,
      // insert it into the queue so that we have something to display.
      // We make sure to do this before invoking VideoQueue().Finish()
      // below.
      mSeekedVideoData = mFirstVideoFrameAfterSeek;
      mFirstVideoFrameAfterSeek = nullptr;
    }

    mIsVideoQueueFinished = true;
    mDropVideoUntilNextDiscontinuity = false; // To make IsVideoSeekComplete() return TRUE.
    CheckIfSeekComplete();
  }
}
Exemplo n.º 8
0
void
AccurateSeekTask::OnAudioDecoded(MediaData* aAudioSample)
{
  AssertOwnerThread();
  MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");

  RefPtr<MediaData> audio(aAudioSample);
  MOZ_ASSERT(audio);

  // The MDSM::mDecodedAudioEndTime will be updated once the whole SeekTask is
  // resolved.

  SAMPLE_LOG("OnAudioDecoded [%lld,%lld] disc=%d",
    audio->mTime, audio->GetEndTime(), audio->mDiscontinuity);

  // Video-only seek doesn't reset audio decoder. There might be pending audio
  // requests when AccurateSeekTask::Seek() begins. We will just store the data
  // without checking |mDiscontinuity| or calling DropAudioUpToSeekTarget().
  if (mTarget.IsVideoOnly()) {
    mSeekedAudioData = audio.forget();
    return;
  }

  if (mFirstAudioSample) {
    mFirstAudioSample = false;
    MOZ_ASSERT(audio->mDiscontinuity);
  }

  AdjustFastSeekIfNeeded(audio);

  if (mTarget.IsFast()) {
    // Non-precise seek; we can stop the seek at the first sample.
    mSeekedAudioData = audio;
    mDoneAudioSeeking = true;
  } else if (NS_FAILED(DropAudioUpToSeekTarget(audio))) {
    CancelCallbacks();
    RejectIfExist(__func__);
    return;
  }

  if (!mDoneAudioSeeking) {
    RequestAudioData();
    return;
  }
  MaybeFinishSeek();
}
Exemplo n.º 9
0
void
AccurateSeekTask::OnVideoDecoded(MediaData* aVideoSample)
{
  AssertOwnerThread();
  MOZ_ASSERT(!mSeekTaskPromise.IsEmpty(), "Seek shouldn't be finished");

  RefPtr<MediaData> video(aVideoSample);
  MOZ_ASSERT(video);

  // The MDSM::mDecodedVideoEndTime will be updated once the whole SeekTask is
  // resolved.

  SAMPLE_LOG("OnVideoDecoded [%lld,%lld] disc=%d",
    video->mTime, video->GetEndTime(), video->mDiscontinuity);

  if (mFirstVideoSample) {
    mFirstVideoSample = false;
    MOZ_ASSERT(video->mDiscontinuity);
  }

  AdjustFastSeekIfNeeded(video);

  if (mTarget.IsFast()) {
    // Non-precise seek. We can stop the seek at the first sample.
    mSeekedVideoData = video;
    mDoneVideoSeeking = true;
  } else if (NS_FAILED(DropVideoUpToSeekTarget(video.get()))) {
    CancelCallbacks();
    RejectIfExist(__func__);
    return;
  }

  if (!mDoneVideoSeeking) {
    RequestVideoData();
    return;
  }
  MaybeFinishSeek();
}
Exemplo n.º 10
0
void
SeekTask::OnAudioNotDecoded(MediaDecoderReader::NotDecodedReason aReason)
{
  AssertOwnerThread();
  SAMPLE_LOG("OnAduioNotDecoded (aReason=%u)", aReason);

  if (aReason == MediaDecoderReader::DECODE_ERROR) {
    // If this is a decode error, delegate to the generic error path.
    RejectIfExist(__func__);
    return;
  }

  // If the decoder is waiting for data, we tell it to call us back when the
  // data arrives.
  if (aReason == MediaDecoderReader::WAITING_FOR_DATA) {
    MOZ_ASSERT(mReader->IsWaitForDataSupported(),
               "Readers that send WAITING_FOR_DATA need to implement WaitForData");
    mReader->WaitForData(MediaData::AUDIO_DATA);

    // We are out of data to decode and will enter buffering mode soon.
    // We want to play the frames we have already decoded, so we stop pre-rolling
    // and ensure that loadeddata is fired as required.
    mNeedToStopPrerollingAudio = true;
    return;
  }

  if (aReason == MediaDecoderReader::CANCELED) {
    EnsureAudioDecodeTaskQueued();
    return;
  }

  if (aReason == MediaDecoderReader::END_OF_STREAM) {
    mIsAudioQueueFinished = true;
    mDropAudioUntilNextDiscontinuity = false; // To make IsAudioSeekComplete() return TRUE.
    CheckIfSeekComplete();
  }
}