nsRefPtr<MediaDecoderReader::SeekPromise> MediaOmxReader::Seek(int64_t aTarget, int64_t aEndTime) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); EnsureActive(); VideoFrameContainer* container = mDecoder->GetVideoFrameContainer(); if (container && container->GetImageContainer()) { container->GetImageContainer()->ClearAllImagesExceptFront(); } if (mHasAudio && mHasVideo) { // The OMXDecoder seeks/demuxes audio and video streams separately. So if // we seek both audio and video to aTarget, the audio stream can typically // seek closer to the seek target, since typically every audio block is // a sync point, whereas for video there are only keyframes once every few // seconds. So if we have both audio and video, we must seek the video // stream to the preceeding keyframe first, get the stream time, and then // seek the audio stream to match the video stream's time. Otherwise, the // audio and video streams won't be in sync after the seek. mVideoSeekTimeUs = aTarget; const VideoData* v = DecodeToFirstVideoData(); mAudioSeekTimeUs = v ? v->mTime : aTarget; } else { mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget; } return SeekPromise::CreateAndResolve(mAudioSeekTimeUs, __func__); }
nsRefPtr<MediaDecoderReader::SeekPromise> MediaOmxReader::Seek(int64_t aTarget, int64_t aEndTime) { MOZ_ASSERT(OnTaskQueue()); EnsureActive(); nsRefPtr<SeekPromise> p = mSeekPromise.Ensure(__func__); if (mHasAudio && mHasVideo) { // The OMXDecoder seeks/demuxes audio and video streams separately. So if // we seek both audio and video to aTarget, the audio stream can typically // seek closer to the seek target, since typically every audio block is // a sync point, whereas for video there are only keyframes once every few // seconds. So if we have both audio and video, we must seek the video // stream to the preceeding keyframe first, get the stream time, and then // seek the audio stream to match the video stream's time. Otherwise, the // audio and video streams won't be in sync after the seek. mVideoSeekTimeUs = aTarget; nsRefPtr<MediaOmxReader> self = this; mSeekRequest.Begin(DecodeToFirstVideoData()->Then(OwnerThread(), __func__, [self] (VideoData* v) { self->mSeekRequest.Complete(); self->mAudioSeekTimeUs = v->mTime; self->mSeekPromise.Resolve(self->mAudioSeekTimeUs, __func__); }, [self, aTarget] () { self->mSeekRequest.Complete(); self->mAudioSeekTimeUs = aTarget; self->mSeekPromise.Resolve(aTarget, __func__); })); } else { mAudioSeekTimeUs = mVideoSeekTimeUs = aTarget; mSeekPromise.Resolve(aTarget, __func__); } return p; }
VideoData* MediaDecoderReader::FindStartTime(int64_t& aOutStartTime) { NS_ASSERTION(mDecoder->OnStateMachineThread() || mDecoder->OnDecodeThread(), "Should be on state machine or decode thread."); // Extract the start times of the bitstreams in order to calculate // the duration. int64_t videoStartTime = INT64_MAX; int64_t audioStartTime = INT64_MAX; VideoData* videoData = nullptr; if (HasVideo()) { videoData = DecodeToFirstVideoData(); if (videoData) { videoStartTime = videoData->mTime; DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoderReader::FindStartTime() video=%lld", videoStartTime)); } } if (HasAudio()) { AudioData* audioData = DecodeToFirstAudioData(); if (audioData) { audioStartTime = audioData->mTime; DECODER_LOG(PR_LOG_DEBUG, ("MediaDecoderReader::FindStartTime() audio=%lld", audioStartTime)); } } int64_t startTime = std::min(videoStartTime, audioStartTime); if (startTime != INT64_MAX) { aOutStartTime = startTime; } return videoData; }