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(); } }
nsRefPtr<MediaDecoderReader::MetadataPromise> MediaDecoderReader::AsyncReadMetadata() { typedef ReadMetadataFailureReason Reason; MOZ_ASSERT(OnTaskQueue()); mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn(); DECODER_LOG("MediaDecoderReader::AsyncReadMetadata"); // PreReadMetadata causes us to try to allocate various hardware and OS // resources, which may not be available at the moment. PreReadMetadata(); if (IsWaitingMediaResources()) { return MetadataPromise::CreateAndReject(Reason::WAITING_FOR_RESOURCES, __func__); } // Attempt to read the metadata. nsRefPtr<MetadataHolder> metadata = new MetadataHolder(); nsresult rv = ReadMetadata(&metadata->mInfo, getter_Transfers(metadata->mTags)); // Reading metadata can cause us to discover that we need resources (a hardware // resource initialized but not yet ready for use). if (IsWaitingMediaResources()) { return MetadataPromise::CreateAndReject(Reason::WAITING_FOR_RESOURCES, __func__); } // We're not waiting for anything. If we didn't get the metadata, that's an error. if (NS_FAILED(rv) || !metadata->mInfo.HasValidMedia()) { DECODER_WARN("ReadMetadata failed, rv=%x HasValidMedia=%d", rv, metadata->mInfo.HasValidMedia()); return MetadataPromise::CreateAndReject(Reason::METADATA_ERROR, __func__); } // Success! return MetadataPromise::CreateAndResolve(metadata, __func__); }
RefPtr<MediaDecoderReader::MetadataPromise> MediaDecoderReader::AsyncReadMetadata() { MOZ_ASSERT(OnTaskQueue()); DECODER_LOG("MediaDecoderReader::AsyncReadMetadata"); // Attempt to read the metadata. MetadataHolder metadata; metadata.mInfo = MakeUnique<MediaInfo>(); MetadataTags* tags = nullptr; nsresult rv = ReadMetadata(metadata.mInfo.get(), &tags); metadata.mTags.reset(tags); metadata.mInfo->AssertValid(); // Update the buffer ranges before resolving the metadata promise. Bug 1320258. UpdateBuffered(); // We're not waiting for anything. If we didn't get the metadata, that's an // error. if (NS_FAILED(rv) || !metadata.mInfo->HasValidMedia()) { DECODER_WARN("ReadMetadata failed, rv=%" PRIx32 " HasValidMedia=%d", static_cast<uint32_t>(rv), metadata.mInfo->HasValidMedia()); return MetadataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__); } // Success! return MetadataPromise::CreateAndResolve(Move(metadata), __func__); }
RefPtr<MediaDecoderReader::MetadataPromise> MediaDecoderReader::AsyncReadMetadata() { MOZ_ASSERT(OnTaskQueue()); DECODER_LOG("MediaDecoderReader::AsyncReadMetadata"); // Attempt to read the metadata. RefPtr<MetadataHolder> metadata = new MetadataHolder(); nsresult rv = ReadMetadata(&metadata->mInfo, getter_Transfers(metadata->mTags)); metadata->mInfo.AssertValid(); // We're not waiting for anything. If we didn't get the metadata, that's an // error. if (NS_FAILED(rv) || !metadata->mInfo.HasValidMedia()) { DECODER_WARN("ReadMetadata failed, rv=%x HasValidMedia=%d", rv, metadata->mInfo.HasValidMedia()); return MetadataPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_METADATA_ERR, __func__); } // Success! return MetadataPromise::CreateAndResolve(metadata, __func__); }
nsRefPtr<MediaDecoderReader::MetadataPromise> MediaDecoderReader::AsyncReadMetadata() { typedef ReadMetadataFailureReason Reason; MOZ_ASSERT(OnTaskQueue()); mDecoder->GetReentrantMonitor().AssertNotCurrentThreadIn(); DECODER_LOG("MediaDecoderReader::AsyncReadMetadata"); // Attempt to read the metadata. nsRefPtr<MetadataHolder> metadata = new MetadataHolder(); nsresult rv = ReadMetadata(&metadata->mInfo, getter_Transfers(metadata->mTags)); // We're not waiting for anything. If we didn't get the metadata, that's an // error. if (NS_FAILED(rv) || !metadata->mInfo.HasValidMedia()) { DECODER_WARN("ReadMetadata failed, rv=%x HasValidMedia=%d", rv, metadata->mInfo.HasValidMedia()); return MetadataPromise::CreateAndReject(Reason::METADATA_ERROR, __func__); } // Success! return MetadataPromise::CreateAndResolve(metadata, __func__); }
nsresult SeekTask::DropAudioUpToSeekTarget(MediaData* aSample) { AssertOwnerThread(); RefPtr<AudioData> audio(aSample->As<AudioData>()); MOZ_ASSERT(audio && mSeekJob.Exists() && mSeekJob.mTarget.IsAccurate()); CheckedInt64 sampleDuration = FramesToUsecs(audio->mFrames, mAudioRate); if (!sampleDuration.isValid()) { return NS_ERROR_FAILURE; } if (audio->mTime + sampleDuration.value() <= mSeekJob.mTarget.GetTime().ToMicroseconds()) { // Our seek target lies after the frames in this AudioData. Don't // push it onto the audio queue, and keep decoding forwards. return NS_OK; } if (audio->mTime > mSeekJob.mTarget.GetTime().ToMicroseconds()) { // The seek target doesn't lie in the audio block just after the last // audio frames we've seen which were before the seek target. This // could have been the first audio data we've seen after seek, i.e. the // seek terminated after the seek target in the audio stream. Just // abort the audio decode-to-target, the state machine will play // silence to cover the gap. Typically this happens in poorly muxed // files. DECODER_WARN("Audio not synced after seek, maybe a poorly muxed file?"); mSeekedAudioData = audio; return NS_OK; } // The seek target lies somewhere in this AudioData's frames, strip off // any frames which lie before the seek target, so we'll begin playback // exactly at the seek target. NS_ASSERTION(mSeekJob.mTarget.GetTime().ToMicroseconds() >= audio->mTime, "Target must at or be after data start."); NS_ASSERTION(mSeekJob.mTarget.GetTime().ToMicroseconds() < audio->mTime + sampleDuration.value(), "Data must end after target."); CheckedInt64 framesToPrune = UsecsToFrames(mSeekJob.mTarget.GetTime().ToMicroseconds() - audio->mTime, mAudioRate); if (!framesToPrune.isValid()) { return NS_ERROR_FAILURE; } if (framesToPrune.value() > audio->mFrames) { // We've messed up somehow. Don't try to trim frames, the |frames| // variable below will overflow. DECODER_WARN("Can't prune more frames that we have!"); return NS_ERROR_FAILURE; } uint32_t frames = audio->mFrames - static_cast<uint32_t>(framesToPrune.value()); uint32_t channels = audio->mChannels; AlignedAudioBuffer audioData(frames * channels); if (!audioData) { return NS_ERROR_OUT_OF_MEMORY; } memcpy(audioData.get(), audio->mAudioData.get() + (framesToPrune.value() * channels), frames * channels * sizeof(AudioDataValue)); CheckedInt64 duration = FramesToUsecs(frames, mAudioRate); if (!duration.isValid()) { return NS_ERROR_FAILURE; } RefPtr<AudioData> data(new AudioData(audio->mOffset, mSeekJob.mTarget.GetTime().ToMicroseconds(), duration.value(), frames, Move(audioData), channels, audio->mRate)); MOZ_ASSERT(!mSeekedAudioData, "Should be the 1st sample after seeking"); mSeekedAudioData = data; return NS_OK; }