nsRefPtr<MP4TrackDemuxer::SamplesPromise> MP4TrackDemuxer::GetSamples(int32_t aNumSamples) { EnsureUpToDateIndex(); nsRefPtr<SamplesHolder> samples = new SamplesHolder; if (!aNumSamples) { return SamplesPromise::CreateAndReject(DemuxerFailureReason::DEMUXER_ERROR, __func__); } if (mQueuedSample) { samples->mSamples.AppendElement(mQueuedSample); mQueuedSample = nullptr; aNumSamples--; } MonitorAutoLock mon(mMonitor); nsRefPtr<MediaRawData> sample; while (aNumSamples && (sample = mIterator->GetNext())) { samples->mSamples.AppendElement(sample); aNumSamples--; } if (samples->mSamples.IsEmpty()) { return SamplesPromise::CreateAndReject(DemuxerFailureReason::END_OF_STREAM, __func__); } else { UpdateSamples(samples->mSamples); return SamplesPromise::CreateAndResolve(samples, __func__); } }
MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent, UniquePtr<TrackInfo>&& aInfo, const nsTArray<mp4_demuxer::Index::Indice>& indices) : mParent(aParent) , mStream(new mp4_demuxer::ResourceStream(mParent->mResource)) , mInfo(Move(aInfo)) , mIndex(new mp4_demuxer::Index(indices, mStream, mInfo->mTrackId, mInfo->IsAudio())) , mIterator(MakeUnique<mp4_demuxer::SampleIterator>(mIndex)) , mNeedReIndex(true) { EnsureUpToDateIndex(); // Force update of index // Collect telemetry from h264 AVCC SPS. if (mInfo->GetAsVideoInfo() && (mInfo->mMimeType.EqualsLiteral("video/mp4") || mInfo->mMimeType.EqualsLiteral("video/avc"))) { mNeedSPSForTelemetry = AccumulateSPSTelemetry(mInfo->GetAsVideoInfo()->mExtraData); } else { // No SPS to be found. mNeedSPSForTelemetry = false; } }
int64_t MP4TrackDemuxer::GetEvictionOffset(media::TimeUnit aTime) { EnsureUpToDateIndex(); MonitorAutoLock mon(mMonitor); uint64_t offset = mIndex->GetEvictionOffset(aTime.ToMicroseconds()); return int64_t(offset == std::numeric_limits<uint64_t>::max() ? 0 : offset); }
media::TimeIntervals MP4TrackDemuxer::GetBuffered() { EnsureUpToDateIndex(); AutoPinned<MediaResource> resource(mParent->mResource); MediaByteRangeSet byteRanges; nsresult rv = resource->GetCachedRanges(byteRanges); if (NS_FAILED(rv)) { return media::TimeIntervals(); } return mIndex->ConvertByteRangesToTimeRanges(byteRanges); }
MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent, UniquePtr<TrackInfo>&& aInfo, const nsTArray<mp4_demuxer::Index::Indice>& indices) : mParent(aParent) , mStream(new mp4_demuxer::ResourceStream(mParent->mResource)) , mInfo(Move(aInfo)) , mMonitor("MP4TrackDemuxer") , mIndex(new mp4_demuxer::Index(indices, mStream, mInfo->mTrackId, mInfo->IsAudio(), &mMonitor)) , mIterator(MakeUnique<mp4_demuxer::SampleIterator>(mIndex)) , mNeedReIndex(true) { EnsureUpToDateIndex(); // Force update of index }
RefPtr<MP4TrackDemuxer::SamplesPromise> MP4TrackDemuxer::GetSamples(int32_t aNumSamples) { EnsureUpToDateIndex(); RefPtr<SamplesHolder> samples = new SamplesHolder; if (!aNumSamples) { return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, __func__); } if (mQueuedSample) { MOZ_ASSERT(mQueuedSample->mKeyframe, "mQueuedSample must be a keyframe"); samples->mSamples.AppendElement(mQueuedSample); mQueuedSample = nullptr; aNumSamples--; } RefPtr<MediaRawData> sample; while (aNumSamples && (sample = GetNextSample())) { if (!sample->Size()) { continue; } samples->mSamples.AppendElement(sample); aNumSamples--; } if (samples->mSamples.IsEmpty()) { return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__); } for (const auto& sample : samples->mSamples) { // Collect telemetry from h264 Annex B SPS. if (mNeedSPSForTelemetry && mp4_demuxer::AnnexB::HasSPS(sample)) { RefPtr<MediaByteBuffer> extradata = mp4_demuxer::AnnexB::ExtractExtraData(sample); mNeedSPSForTelemetry = AccumulateSPSTelemetry(extradata); } } if (mNextKeyframeTime.isNothing() || samples->mSamples.LastElement()->mTime >= mNextKeyframeTime.value()) { SetNextKeyFrameTime(); } return SamplesPromise::CreateAndResolve(samples, __func__); }
MP4TrackDemuxer::MP4TrackDemuxer(MP4Demuxer* aParent, UniquePtr<TrackInfo>&& aInfo, const mp4_demuxer::IndiceWrapper& aIndices) : mParent(aParent) , mStream(new mp4_demuxer::ResourceStream(mParent->mResource)) , mInfo(Move(aInfo)) , mIndex(new mp4_demuxer::Index(aIndices, mStream, mInfo->mTrackId, mInfo->IsAudio())) , mIterator(MakeUnique<mp4_demuxer::SampleIterator>(mIndex)) , mNeedReIndex(true) { EnsureUpToDateIndex(); // Force update of index VideoInfo* videoInfo = mInfo->GetAsVideoInfo(); // Collect telemetry from h264 AVCC SPS. if (videoInfo && (mInfo->mMimeType.EqualsLiteral("video/mp4") || mInfo->mMimeType.EqualsLiteral("video/avc"))) { mIsH264 = true; RefPtr<MediaByteBuffer> extraData = videoInfo->mExtraData; mNeedSPSForTelemetry = AccumulateSPSTelemetry(extraData); mp4_demuxer::SPSData spsdata; if (mp4_demuxer::H264::DecodeSPSFromExtraData(extraData, spsdata) && spsdata.pic_width > 0 && spsdata.pic_height > 0 && mp4_demuxer::H264::EnsureSPSIsSane(spsdata)) { videoInfo->mImage.width = spsdata.pic_width; videoInfo->mImage.height = spsdata.pic_height; videoInfo->mDisplay.width = spsdata.display_width; videoInfo->mDisplay.height = spsdata.display_height; } } else { // No SPS to be found. mNeedSPSForTelemetry = false; } }
media::TimeIntervals MP4TrackDemuxer::GetBuffered() { EnsureUpToDateIndex(); AutoPinned<MediaResource> resource(mParent->mResource); nsTArray<MediaByteRange> byteRanges; nsresult rv = resource->GetCachedRanges(byteRanges); if (NS_FAILED(rv)) { return media::TimeIntervals(); } nsTArray<mp4_demuxer::Interval<int64_t>> timeRanges; MonitorAutoLock mon(mMonitor); mIndex->ConvertByteRangesToTimeRanges(byteRanges, &timeRanges); // convert timeRanges. media::TimeIntervals ranges = media::TimeIntervals(); for (size_t i = 0; i < timeRanges.Length(); i++) { ranges += media::TimeInterval(media::TimeUnit::FromMicroseconds(timeRanges[i].start), media::TimeUnit::FromMicroseconds(timeRanges[i].end)); } return ranges; }