void MediaSourceReader::OnNotDecoded(MediaData::Type aType, RequestSampleCallback::NotDecodedReason aReason) { MSE_DEBUG("MediaSourceReader(%p)::OnNotDecoded aType=%u aReason=%u IsEnded: %d", this, aType, aReason, IsEnded()); if (aReason == RequestSampleCallback::DECODE_ERROR) { GetCallback()->OnNotDecoded(aType, aReason); return; } // End of stream. Force switching past this stream to another reader by // switching to the end of the buffered range. MOZ_ASSERT(aReason == RequestSampleCallback::END_OF_STREAM); nsRefPtr<MediaDecoderReader> reader = aType == MediaData::AUDIO_DATA ? mAudioReader : mVideoReader; // Find the closest approximation to the end time for this stream. // mLast{Audio,Video}Time differs from the actual end time because of // Bug 1065207 - the duration of a WebM fragment is an estimate not the // actual duration. In the case of audio time an example of where they // differ would be the actual sample duration being small but the // previous sample being large. The buffered end time uses that last // sample duration as an estimate of the end time duration giving an end // time that is greater than mLastAudioTime, which is the actual sample // end time. // Reader switching is based on the buffered end time though so they can be // quite different. By using the EOS_FUZZ_US and the buffered end time we // attempt to account for this difference. int64_t* time = aType == MediaData::AUDIO_DATA ? &mLastAudioTime : &mLastVideoTime; if (reader) { nsRefPtr<dom::TimeRanges> ranges = new dom::TimeRanges(); reader->GetBuffered(ranges); if (ranges->Length() > 0) { // End time is a double so we convert to nearest by adding 0.5. int64_t end = ranges->GetEndTime() * USECS_PER_S + 0.5; *time = std::max(*time, end); } } // See if we can find a different reader that can pick up where we left off. We use the // EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug // 1065207 - the duration of a WebM frame is an estimate. if (aType == MediaData::AUDIO_DATA && SwitchAudioReader(*time + EOS_FUZZ_US)) { RequestAudioData(); return; } if (aType == MediaData::VIDEO_DATA && SwitchVideoReader(*time + EOS_FUZZ_US)) { RequestVideoData(false, 0); return; } // If the entire MediaSource is done, generate an EndOfStream. if (IsEnded()) { GetCallback()->OnNotDecoded(aType, RequestSampleCallback::END_OF_STREAM); return; } // We don't have the data the caller wants. Tell that we're waiting for JS to // give us more data. GetCallback()->OnNotDecoded(aType, RequestSampleCallback::WAITING_FOR_DATA); }
void MediaSourceReader::RequestAudioData() { MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData", this); if (!mAudioReader) { MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called with no audio reader", this); GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::DECODE_ERROR); return; } mAudioIsSeeking = false; SwitchAudioReader(mLastAudioTime); mAudioReader->RequestAudioData(); }
void MediaSourceReader::RequestAudioData() { MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData", this); if (!mAudioReader) { MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called with no audio reader", this); GetCallback()->OnDecodeError(); return; } mAudioIsSeeking = false; SwitchAudioReader(mLastAudioTime); mAudioReader->RequestAudioData(); }
void MediaSourceReader::AttemptSeek() { // Make sure we don't hold the monitor while calling into the reader // Seek methods since it can deadlock. { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); if (!mWaitingForSeekData || !TrackBuffersContainTime(mPendingSeekTime)) { return; } } ResetDecode(); for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) { mTrackBuffers[i]->ResetDecode(); } // Decoding discontinuity upon seek, reset last times to seek target. mLastAudioTime = mPendingSeekTime; mLastVideoTime = mPendingSeekTime; if (mAudioTrack) { mAudioIsSeeking = true; SwitchAudioReader(mPendingSeekTime); mAudioReader->Seek(mPendingSeekTime, mPendingStartTime, mPendingEndTime, mPendingCurrentTime) ->Then(GetTaskQueue(), __func__, this, &MediaSourceReader::OnSeekCompleted, &MediaSourceReader::OnSeekFailed); MSE_DEBUG("MediaSourceReader(%p)::Seek audio reader=%p", this, mAudioReader.get()); } if (mVideoTrack) { mVideoIsSeeking = true; SwitchVideoReader(mPendingSeekTime); mVideoReader->Seek(mPendingSeekTime, mPendingStartTime, mPendingEndTime, mPendingCurrentTime) ->Then(GetTaskQueue(), __func__, this, &MediaSourceReader::OnSeekCompleted, &MediaSourceReader::OnSeekFailed); MSE_DEBUG("MediaSourceReader(%p)::Seek video reader=%p", this, mVideoReader.get()); } { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mWaitingForSeekData = false; } }
void MediaSourceReader::OnAudioEOS() { MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p (decoders=%u)", this, mAudioReader.get(), mAudioTrack->Decoders().Length()); if (SwitchAudioReader(mLastAudioTime)) { // Success! Resume decoding with next audio decoder. RequestAudioData(); } else if (IsEnded()) { // End of stream. MSE_DEBUG("MediaSourceReader(%p)::OnAudioEOS reader=%p EOS (decoders=%u)", this, mAudioReader.get(), mAudioTrack->Decoders().Length()); GetCallback()->OnAudioEOS(); } }
nsRefPtr<MediaDecoderReader::AudioDataPromise> MediaSourceReader::RequestAudioData() { nsRefPtr<AudioDataPromise> p = mAudioPromise.Ensure(__func__); MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData", this); if (!mAudioReader) { MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called with no audio reader", this); mAudioPromise.Reject(DECODE_ERROR, __func__); return p; } mAudioIsSeeking = false; SwitchAudioReader(mLastAudioTime); mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this, &MediaSourceReader::OnAudioDecoded, &MediaSourceReader::OnAudioNotDecoded); return p; }
void MediaSourceReader::OnAudioNotDecoded(NotDecodedReason aReason) { MSE_DEBUG("MediaSourceReader(%p)::OnAudioNotDecoded aReason=%u IsEnded: %d", this, aReason, IsEnded()); if (aReason == DECODE_ERROR || aReason == CANCELED) { mAudioPromise.Reject(aReason, __func__); return; } // End of stream. Force switching past this stream to another reader by // switching to the end of the buffered range. MOZ_ASSERT(aReason == END_OF_STREAM); if (mAudioReader) { AdjustEndTime(&mLastAudioTime, mAudioReader); } // See if we can find a different reader that can pick up where we left off. We use the // EOS_FUZZ_US to allow for the fact that our end time can be inaccurate due to bug // 1065207. if (SwitchAudioReader(mLastAudioTime + EOS_FUZZ_US)) { mAudioReader->RequestAudioData()->Then(GetTaskQueue(), __func__, this, &MediaSourceReader::OnAudioDecoded, &MediaSourceReader::OnAudioNotDecoded); return; } // If the entire MediaSource is done, generate an EndOfStream. if (IsEnded()) { mAudioPromise.Reject(END_OF_STREAM, __func__); return; } // We don't have the data the caller wants. Tell that we're waiting for JS to // give us more data. mAudioPromise.Reject(WAITING_FOR_DATA, __func__); }