Bug 1207946 - [MSE] P2. Fix seek when target isn't found exactly in a buffered range. r=gerald, a=sylvestre
--- a/dom/media/mediasource/MediaSourceDemuxer.cpp
+++ b/dom/media/mediasource/MediaSourceDemuxer.cpp
@@ -286,17 +286,17 @@ MediaSourceTrackDemuxer::GetSamples(int3
void
MediaSourceTrackDemuxer::Reset()
{
MOZ_ASSERT(mParent, "Called after BreackCycle()");
nsRefPtr<MediaSourceTrackDemuxer> self = this;
nsCOMPtr<nsIRunnable> task =
NS_NewRunnableFunction([self] () {
- self->mManager->Seek(self->mType, TimeUnit());
+ self->mManager->Seek(self->mType, TimeUnit(), TimeUnit());
{
MonitorAutoLock mon(self->mMonitor);
self->mNextRandomAccessPoint =
self->mManager->GetNextRandomAccessPoint(self->mType);
}
});
mParent->GetTaskQueue()->Dispatch(task.forget());
}
@@ -348,17 +348,18 @@ MediaSourceTrackDemuxer::DoSeek(media::T
TimeIntervals buffered = mManager->Buffered(mType);
buffered.SetFuzz(TimeUnit::FromMicroseconds(EOS_FUZZ_US));
if (!buffered.Contains(aTime)) {
// We don't have the data to seek to.
return SeekPromise::CreateAndReject(DemuxerFailureReason::WAITING_FOR_DATA,
__func__);
}
- TimeUnit seekTime = mManager->Seek(mType, aTime);
+ TimeUnit seekTime =
+ mManager->Seek(mType, aTime, TimeUnit::FromMicroseconds(EOS_FUZZ_US));
{
MonitorAutoLock mon(mMonitor);
mNextRandomAccessPoint = mManager->GetNextRandomAccessPoint(mType);
}
return SeekPromise::CreateAndResolve(seekTime, __func__);
}
nsRefPtr<MediaSourceTrackDemuxer::SamplesPromise>
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -1885,27 +1885,68 @@ TrackBuffersManager::SafeBuffered(TrackI
const TrackBuffersManager::TrackBuffer&
TrackBuffersManager::GetTrackBuffer(TrackInfo::TrackType aTrack)
{
MOZ_ASSERT(OnTaskQueue());
return GetTracksData(aTrack).mBuffers.LastElement();
}
+uint32_t TrackBuffersManager::FindSampleIndex(const TrackBuffer& aTrackBuffer,
+ const TimeInterval& aInterval)
+{
+ TimeUnit target = aInterval.mStart - aInterval.mFuzz;
+
+ for (uint32_t i = 0; i < aTrackBuffer.Length(); i++) {
+ const nsRefPtr<MediaRawData>& sample = aTrackBuffer[i];
+ if (sample->mTime >= target.ToMicroseconds() ||
+ sample->GetEndTime() > target.ToMicroseconds()) {
+ return i;
+ }
+ }
+ NS_ASSERTION(false, "FindSampleIndex called with invalid arguments");
+
+ return 0;
+}
+
TimeUnit
TrackBuffersManager::Seek(TrackInfo::TrackType aTrack,
- const TimeUnit& aTime)
+ const TimeUnit& aTime,
+ const TimeUnit& aFuzz)
{
MOZ_ASSERT(OnTaskQueue());
auto& trackBuffer = GetTracksData(aTrack);
const TrackBuffersManager::TrackBuffer& track = GetTrackBuffer(aTrack);
+
+ if (!track.Length()) {
+ // This a reset. It will be followed by another valid seek.
+ trackBuffer.mNextGetSampleIndex = Some(uint32_t(0));
+ trackBuffer.mNextSampleTimecode = TimeUnit();
+ trackBuffer.mNextSampleTime = TimeUnit();
+ return TimeUnit();
+ }
+
+ uint32_t i = 0;
+
+ if (aTime != TimeUnit()) {
+ // Determine the interval of samples we're attempting to seek to.
+ TimeIntervals buffered = trackBuffer.mBufferedRanges;
+ TimeIntervals::IndexType index = buffered.Find(aTime);
+ buffered.SetFuzz(aFuzz);
+ index = buffered.Find(aTime);
+ MOZ_ASSERT(index != TimeIntervals::NoIndex);
+
+ TimeInterval target = buffered[index];
+ i = FindSampleIndex(track, target);
+ }
+
Maybe<TimeUnit> lastKeyFrameTime;
TimeUnit lastKeyFrameTimecode;
uint32_t lastKeyFrameIndex = 0;
- for (uint32_t i = 0; i < track.Length(); i++) {
+ for (; i < track.Length(); i++) {
const nsRefPtr<MediaRawData>& sample = track[i];
TimeUnit sampleTime = TimeUnit::FromMicroseconds(sample->mTime);
if (sampleTime > aTime && lastKeyFrameTime.isSome()) {
break;
}
if (sample->mKeyframe) {
lastKeyFrameTimecode = TimeUnit::FromMicroseconds(sample->mTimecode);
lastKeyFrameTime = Some(sampleTime);
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -83,17 +83,18 @@ public:
const TrackBuffer& GetTrackBuffer(TrackInfo::TrackType aTrack);
const media::TimeIntervals& Buffered(TrackInfo::TrackType);
media::TimeIntervals SafeBuffered(TrackInfo::TrackType) const;
bool IsEnded() const
{
return mEnded;
}
media::TimeUnit Seek(TrackInfo::TrackType aTrack,
- const media::TimeUnit& aTime);
+ const media::TimeUnit& aTime,
+ const media::TimeUnit& aFuzz);
uint32_t SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack,
const media::TimeUnit& aTimeThreadshold,
bool& aFound);
already_AddRefed<MediaRawData> GetSample(TrackInfo::TrackType aTrack,
const media::TimeUnit& aFuzz,
bool& aError);
media::TimeUnit GetNextRandomAccessPoint(TrackInfo::TrackType aTrack);
@@ -285,16 +286,19 @@ private:
bool CheckNextInsertionIndex(TrackData& aTrackData,
const media::TimeUnit& aSampleTime);
void InsertFrames(TrackBuffer& aSamples,
const media::TimeIntervals& aIntervals,
TrackData& aTrackData);
void RemoveFrames(const media::TimeIntervals& aIntervals,
TrackData& aTrackData,
uint32_t aStartIndex);
+ // Find index of sample. Return a negative value if not found.
+ uint32_t FindSampleIndex(const TrackBuffer& aTrackBuffer,
+ const media::TimeInterval& aInterval);
void UpdateBufferedRanges();
void RejectProcessing(nsresult aRejectValue, const char* aName);
void ResolveProcessing(bool aResolveValue, const char* aName);
MozPromiseRequestHolder<CodedFrameProcessingPromise> mProcessingRequest;
MozPromiseHolder<CodedFrameProcessingPromise> mProcessingPromise;
MozPromiseHolder<AppendPromise> mAppendPromise;
// Set to true while SegmentParserLoop is running. This is used for diagnostic