nsresult WaveReader::ReadMetadata(VideoInfo* aInfo, MetadataTags** aTags) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); bool loaded = LoadRIFFChunk(); if (!loaded) { return NS_ERROR_FAILURE; } nsAutoPtr<nsHTMLMediaElement::MetadataTags> tags; bool loadAllChunks = LoadAllChunks(tags); if (!loadAllChunks) { return NS_ERROR_FAILURE; } mInfo.mHasAudio = true; mInfo.mHasVideo = false; mInfo.mAudioRate = mSampleRate; mInfo.mAudioChannels = mChannels; *aInfo = mInfo; *aTags = tags.forget(); ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration( static_cast<int64_t>(BytesToTime(GetDataLength()) * USECS_PER_S)); return NS_OK; }
nsresult WaveReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { MOZ_ASSERT(OnTaskQueue()); bool loaded = LoadRIFFChunk(); if (!loaded) { return NS_ERROR_FAILURE; } nsAutoPtr<dom::HTMLMediaElement::MetadataTags> tags; bool loadAllChunks = LoadAllChunks(tags); if (!loadAllChunks) { return NS_ERROR_FAILURE; } mInfo.mAudio.mRate = mSampleRate; mInfo.mAudio.mChannels = mChannels; mInfo.mMetadataDuration.emplace(TimeUnit::FromSeconds(BytesToTime(GetDataLength()))); *aInfo = mInfo; *aTags = tags.forget(); return NS_OK; }
nsresult MediaOmxReader::GetBuffered(mozilla::dom::TimeRanges* aBuffered, int64_t aStartTime) { if (!mOmxDecoder.get()) return NS_OK; MediaResource* stream = mOmxDecoder->GetResource(); int64_t durationUs = 0; mOmxDecoder->GetDuration(&durationUs); // Nothing to cache if the media takes 0us to play. if (!durationUs) return NS_OK; // Special case completely cached files. This also handles local files. if (stream->IsDataCachedToEndOfResource(0)) { aBuffered->Add(0, durationUs); return NS_OK; } int64_t totalBytes = stream->GetLength(); // If we can't determine the total size, pretend that we have nothing // buffered. This will put us in a state of eternally-low-on-undecoded-data // which is not get, but about the best we can do. if (totalBytes == -1) return NS_OK; int64_t startOffset = stream->GetNextCachedData(0); while (startOffset >= 0) { int64_t endOffset = stream->GetCachedDataEnd(startOffset); // Bytes [startOffset..endOffset] are cached. NS_ASSERTION(startOffset >= 0, "Integer underflow in GetBuffered"); NS_ASSERTION(endOffset >= 0, "Integer underflow in GetBuffered"); uint64_t startUs = BytesToTime(startOffset, totalBytes, durationUs); uint64_t endUs = BytesToTime(endOffset, totalBytes, durationUs); if (startUs != endUs) { aBuffered->Add((double)startUs / USECS_PER_S, (double)endUs / USECS_PER_S); } startOffset = stream->GetNextCachedData(endOffset); } return NS_OK; }
media::TimeIntervals GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream, int64_t aDurationUsecs) { media::TimeIntervals buffered; // Nothing to cache if the media takes 0us to play. if (aDurationUsecs <= 0 || !aStream) return buffered; // Special case completely cached files. This also handles local files. if (aStream->IsDataCachedToEndOfResource(0)) { buffered += media::TimeInterval(media::TimeUnit::FromMicroseconds(0), media::TimeUnit::FromMicroseconds(aDurationUsecs)); return buffered; } int64_t totalBytes = aStream->GetLength(); // If we can't determine the total size, pretend that we have nothing // buffered. This will put us in a state of eternally-low-on-undecoded-data // which is not great, but about the best we can do. if (totalBytes <= 0) return buffered; int64_t startOffset = aStream->GetNextCachedData(0); while (startOffset >= 0) { int64_t endOffset = aStream->GetCachedDataEnd(startOffset); // Bytes [startOffset..endOffset] are cached. NS_ASSERTION(startOffset >= 0, "Integer underflow in GetBuffered"); NS_ASSERTION(endOffset >= 0, "Integer underflow in GetBuffered"); int64_t startUs = BytesToTime(startOffset, totalBytes, aDurationUsecs); int64_t endUs = BytesToTime(endOffset, totalBytes, aDurationUsecs); if (startUs != endUs) { buffered += media::TimeInterval(media::TimeUnit::FromMicroseconds(startUs), media::TimeUnit::FromMicroseconds(endUs)); } startOffset = aStream->GetNextCachedData(endOffset); } return buffered; }
nsresult WaveReader::GetBuffered(nsTimeRanges* aBuffered, int64_t aStartTime) { if (!mInfo.mHasAudio) { return NS_OK; } int64_t startOffset = mDecoder->GetResource()->GetNextCachedData(mWavePCMOffset); while (startOffset >= 0) { int64_t endOffset = mDecoder->GetResource()->GetCachedDataEnd(startOffset); // Bytes [startOffset..endOffset] are cached. NS_ASSERTION(startOffset >= mWavePCMOffset, "Integer underflow in GetBuffered"); NS_ASSERTION(endOffset >= mWavePCMOffset, "Integer underflow in GetBuffered"); // We need to round the buffered ranges' times to microseconds so that they // have the same precision as the currentTime and duration attribute on // the media element. aBuffered->Add(RoundToUsecs(BytesToTime(startOffset - mWavePCMOffset)), RoundToUsecs(BytesToTime(endOffset - mWavePCMOffset))); startOffset = mDecoder->GetResource()->GetNextCachedData(endOffset); } return NS_OK; }
media::TimeIntervals WaveReader::GetBuffered() { if (!mInfo.HasAudio()) { return media::TimeIntervals(); } media::TimeIntervals buffered; AutoPinned<MediaResource> resource(mDecoder->GetResource()); int64_t startOffset = resource->GetNextCachedData(mWavePCMOffset); while (startOffset >= 0) { int64_t endOffset = resource->GetCachedDataEnd(startOffset); // Bytes [startOffset..endOffset] are cached. NS_ASSERTION(startOffset >= mWavePCMOffset, "Integer underflow in GetBuffered"); NS_ASSERTION(endOffset >= mWavePCMOffset, "Integer underflow in GetBuffered"); // We need to round the buffered ranges' times to microseconds so that they // have the same precision as the currentTime and duration attribute on // the media element. buffered += media::TimeInterval( media::TimeUnit::FromSeconds(BytesToTime(startOffset - mWavePCMOffset)), media::TimeUnit::FromSeconds(BytesToTime(endOffset - mWavePCMOffset))); startOffset = resource->GetNextCachedData(endOffset); } return buffered; }
nsresult WaveReader::Seek(int64_t aTarget, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); LOG(PR_LOG_DEBUG, ("%p About to seek to %lld", mDecoder, aTarget)); if (NS_FAILED(ResetDecode())) { return NS_ERROR_FAILURE; } double d = BytesToTime(GetDataLength()); NS_ASSERTION(d < INT64_MAX / USECS_PER_S, "Duration overflow"); int64_t duration = static_cast<int64_t>(d * USECS_PER_S); double seekTime = NS_MIN(aTarget, duration) / static_cast<double>(USECS_PER_S); int64_t position = RoundDownToFrame(static_cast<int64_t>(TimeToBytes(seekTime))); NS_ASSERTION(INT64_MAX - mWavePCMOffset > position, "Integer overflow during wave seek"); position += mWavePCMOffset; return mDecoder->GetResource()->Seek(nsISeekableStream::NS_SEEK_SET, position); }
nsRefPtr<MediaDecoderReader::SeekPromise> WaveReader::Seek(int64_t aTarget, int64_t aEndTime) { MOZ_ASSERT(OnTaskQueue()); LOG(LogLevel::Debug, ("%p About to seek to %lld", mDecoder, aTarget)); if (NS_FAILED(ResetDecode())) { return SeekPromise::CreateAndReject(NS_ERROR_FAILURE, __func__); } double d = BytesToTime(GetDataLength()); NS_ASSERTION(d < INT64_MAX / USECS_PER_S, "Duration overflow"); int64_t duration = static_cast<int64_t>(d * USECS_PER_S); double seekTime = std::min(aTarget, duration) / static_cast<double>(USECS_PER_S); int64_t position = RoundDownToFrame(static_cast<int64_t>(TimeToBytes(seekTime))); NS_ASSERTION(INT64_MAX - mWavePCMOffset > position, "Integer overflow during wave seek"); position += mWavePCMOffset; nsresult res = mDecoder->GetResource()->Seek(nsISeekableStream::NS_SEEK_SET, position); if (NS_FAILED(res)) { return SeekPromise::CreateAndReject(res, __func__); } else { return SeekPromise::CreateAndResolve(aTarget, __func__); } }