void MP4TrackDemuxer::UpdateSamples(nsTArray<RefPtr<MediaRawData>>& aSamples) { for (size_t i = 0; i < aSamples.Length(); i++) { MediaRawData* sample = aSamples[i]; // 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 (sample->mCrypto.mValid) { nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter()); writer->mCrypto.mMode = mInfo->mCrypto.mMode; writer->mCrypto.mIVSize = mInfo->mCrypto.mIVSize; writer->mCrypto.mKeyId.AppendElements(mInfo->mCrypto.mKeyId); } if (mInfo->GetAsVideoInfo()) { sample->mExtraData = mInfo->GetAsVideoInfo()->mExtraData; } } if (mNextKeyframeTime.isNothing() || aSamples.LastElement()->mTime >= mNextKeyframeTime.value().ToMicroseconds()) { SetNextKeyFrameTime(); } }
RefPtr<MP4TrackDemuxer::SeekPromise> MP4TrackDemuxer::Seek(const media::TimeUnit& aTime) { auto seekTime = aTime; mQueuedSample = nullptr; mIterator->Seek(seekTime.ToMicroseconds()); // Check what time we actually seeked to. RefPtr<MediaRawData> sample; do { sample = GetNextSample(); if (!sample) { return SeekPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM, __func__); } if (!sample->Size()) { // This sample can't be decoded, continue searching. continue; } if (sample->mKeyframe) { mQueuedSample = sample; seekTime = mQueuedSample->mTime; } } while (!mQueuedSample); SetNextKeyFrameTime(); return SeekPromise::CreateAndResolve(seekTime, __func__); }
void MP4TrackDemuxer::Reset() { mQueuedSample = nullptr; // TODO, Seek to first frame available, which isn't always 0. mIterator->Seek(0); SetNextKeyFrameTime(); }
RefPtr<MP4TrackDemuxer::SeekPromise> MP4TrackDemuxer::Seek(media::TimeUnit aTime) { int64_t seekTime = aTime.ToMicroseconds(); mQueuedSample = nullptr; mIterator->Seek(seekTime); // Check what time we actually seeked to. mQueuedSample = mIterator->GetNext(); if (mQueuedSample) { seekTime = mQueuedSample->mTime; } SetNextKeyFrameTime(); return SeekPromise::CreateAndResolve(media::TimeUnit::FromMicroseconds(seekTime), __func__); }
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__); }
void MP4TrackDemuxer::UpdateSamples(nsTArray<nsRefPtr<MediaRawData>>& aSamples) { for (size_t i = 0; i < aSamples.Length(); i++) { MediaRawData* sample = aSamples[i]; if (sample->mCrypto.mValid) { nsAutoPtr<MediaRawDataWriter> writer(sample->CreateWriter()); writer->mCrypto.mMode = mInfo->mCrypto.mMode; writer->mCrypto.mIVSize = mInfo->mCrypto.mIVSize; writer->mCrypto.mKeyId.AppendElements(mInfo->mCrypto.mKeyId); } if (mInfo->GetAsVideoInfo()) { sample->mExtraData = mInfo->GetAsVideoInfo()->mExtraData; } } if (mNextKeyframeTime.isNothing() || aSamples.LastElement()->mTime >= mNextKeyframeTime.value().ToMicroseconds()) { SetNextKeyFrameTime(); } }
RefPtr<MP4TrackDemuxer::SkipAccessPointPromise> MP4TrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold) { mQueuedSample = nullptr; // Loop until we reach the next keyframe after the threshold. uint32_t parsed = 0; bool found = false; RefPtr<MediaRawData> sample; while (!found && (sample = mIterator->GetNext())) { parsed++; if (sample->mKeyframe && sample->mTime >= aTimeThreshold.ToMicroseconds()) { found = true; mQueuedSample = sample; } } SetNextKeyFrameTime(); if (found) { return SkipAccessPointPromise::CreateAndResolve(parsed, __func__); } else { SkipFailureHolder failure(DemuxerFailureReason::END_OF_STREAM, parsed); return SkipAccessPointPromise::CreateAndReject(Move(failure), __func__); } }