Bug 1272964: [MSE] P3. Do not skip over gaps when searching for the next keyframe. r?gerald
MozReview-Commit-ID: 1wPbp6JOaa8
--- a/dom/media/mediasource/MediaSourceDemuxer.cpp
+++ b/dom/media/mediasource/MediaSourceDemuxer.cpp
@@ -463,18 +463,20 @@ RefPtr<MediaSourceTrackDemuxer::SkipAcce
MediaSourceTrackDemuxer::DoSkipToNextRandomAccessPoint(media::TimeUnit aTimeThreadshold)
{
uint32_t parsed = 0;
// Ensure that the data we are about to skip to is still available.
TimeIntervals buffered = mManager->Buffered(mType);
buffered.SetFuzz(MediaSourceDemuxer::EOS_FUZZ);
if (buffered.Contains(aTimeThreadshold)) {
bool found;
- parsed =
- mManager->SkipToNextRandomAccessPoint(mType, aTimeThreadshold, found);
+ parsed = mManager->SkipToNextRandomAccessPoint(mType,
+ aTimeThreadshold,
+ MediaSourceDemuxer::EOS_FUZZ,
+ found);
if (found) {
return SkipAccessPointPromise::CreateAndResolve(parsed, __func__);
}
}
SkipFailureHolder holder(
mManager->IsEnded() ? DemuxerFailureReason::END_OF_STREAM :
DemuxerFailureReason::WAITING_FOR_DATA, parsed);
return SkipAccessPointPromise::CreateAndReject(holder, __func__);
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -1891,50 +1891,85 @@ TrackBuffersManager::Seek(TrackInfo::Tra
trackBuffer.mNextSampleTime = lastKeyFrameTime.refOr(TimeUnit());
return lastKeyFrameTime.refOr(TimeUnit());
}
uint32_t
TrackBuffersManager::SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack,
const TimeUnit& aTimeThreadshold,
+ const media::TimeUnit& aFuzz,
bool& aFound)
{
MOZ_ASSERT(OnTaskQueue());
uint32_t parsed = 0;
auto& trackData = GetTracksData(aTrack);
const TrackBuffer& track = GetTrackBuffer(aTrack);
aFound = false;
- uint32_t nextSampleIndex = trackData.mNextGetSampleIndex.valueOr(0);
- for (uint32_t i = nextSampleIndex; i < track.Length(); i++) {
- const RefPtr<MediaRawData>& sample = track[i];
+ // SkipToNextRandomAccessPoint can only be called if aTimeThreadshold is known
+ // to be buffered.
+
+ // So first determine the current position in the track buffer if necessary.
+ if (trackData.mNextGetSampleIndex.isNothing()) {
+ if (trackData.mNextSampleTimecode == TimeUnit()) {
+ // First demux, get first sample.
+ trackData.mNextGetSampleIndex = Some(0u);
+ } else {
+ int32_t pos = FindCurrentPosition(aTrack, aFuzz);
+ if (pos < 0) {
+ return 0;
+ }
+ trackData.mNextGetSampleIndex = Some(uint32_t(pos));
+ }
+ }
+
+ TimeUnit nextSampleTimecode = trackData.mNextSampleTimecode;
+ TimeUnit nextSampleTime = trackData.mNextSampleTime;
+ uint32_t i = trackData.mNextGetSampleIndex.ref();
+
+ for (; i < track.Length(); i++) {
+ const MediaRawData* sample =
+ GetSample(aTrack,
+ i,
+ nextSampleTimecode,
+ nextSampleTime,
+ aFuzz);
+ if (!sample) {
+ break;
+ }
if (sample->mKeyframe &&
sample->mTime >= aTimeThreadshold.ToMicroseconds()) {
- trackData.mNextSampleTimecode =
- TimeUnit::FromMicroseconds(sample->mTimecode);
- trackData.mNextSampleTime =
- TimeUnit::FromMicroseconds(sample->mTime);
- trackData.mNextGetSampleIndex = Some(i);
aFound = true;
break;
}
+ nextSampleTimecode =
+ TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration);
+ nextSampleTime = TimeUnit::FromMicroseconds(sample->GetEndTime());
parsed++;
}
+ // Adjust the next demux time and index so that the next call to
+ // SkipToNextRandomAccessPoint will not count again the parsed sample as
+ // skipped.
+ trackData.mNextSampleTimecode = nextSampleTimecode;
+ trackData.mNextSampleTime = nextSampleTime;
+ trackData.mNextGetSampleIndex = Some(i);
+
return parsed;
}
const MediaRawData*
TrackBuffersManager::GetSample(TrackInfo::TrackType aTrack,
size_t aIndex,
const TimeUnit& aExpectedDts,
const TimeUnit& aExpectedPts,
const TimeUnit& aFuzz)
{
+ MOZ_ASSERT(OnTaskQueue());
const TrackBuffer& track = GetTrackBuffer(aTrack);
if (aIndex >= track.Length()) {
// reached the end.
return nullptr;
}
const RefPtr<MediaRawData>& sample = track[aIndex];
@@ -1990,73 +2025,82 @@ TrackBuffersManager::GetSample(TrackInfo
trackData.mNextSampleTimecode =
TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration);
trackData.mNextSampleTime =
TimeUnit::FromMicroseconds(sample->GetEndTime());
return p.forget();
}
// Our previous index has been overwritten, attempt to find the new one.
+ int32_t pos = FindCurrentPosition(aTrack, aFuzz);
+ if (pos < 0) {
+ MSE_DEBUG("Couldn't find sample (pts:%lld dts:%lld)",
+ trackData.mNextSampleTime.ToMicroseconds(),
+ trackData.mNextSampleTimecode.ToMicroseconds());
+ return nullptr;
+ }
+
+ const RefPtr<MediaRawData>& sample = track[pos];
+ RefPtr<MediaRawData> p = sample->Clone();
+ if (!p) {
+ // OOM
+ aError = true;
+ return nullptr;
+ }
+ trackData.mNextGetSampleIndex = Some(uint32_t(pos)+1);
+ trackData.mNextSampleTimecode =
+ TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration);
+ trackData.mNextSampleTime =
+ TimeUnit::FromMicroseconds(sample->GetEndTime());
+ return p.forget();
+}
+
+int32_t
+TrackBuffersManager::FindCurrentPosition(TrackInfo::TrackType aTrack,
+ const TimeUnit& aFuzz)
+{
+ MOZ_ASSERT(OnTaskQueue());
+ auto& trackData = GetTracksData(aTrack);
+ const TrackBuffer& track = GetTrackBuffer(aTrack);
+
for (uint32_t i = 0; i < track.Length(); i++) {
const RefPtr<MediaRawData>& sample = track[i];
TimeInterval sampleInterval{
TimeUnit::FromMicroseconds(sample->mTimecode),
TimeUnit::FromMicroseconds(sample->mTimecode + sample->mDuration),
aFuzz};
if (sampleInterval.ContainsWithStrictEnd(trackData.mNextSampleTimecode)) {
- RefPtr<MediaRawData> p = sample->Clone();
- if (!p) {
- // OOM
- aError = true;
- return nullptr;
- }
- trackData.mNextGetSampleIndex = Some(i+1);
- trackData.mNextSampleTimecode = sampleInterval.mEnd;
- trackData.mNextSampleTime =
- TimeUnit::FromMicroseconds(sample->GetEndTime());
- return p.forget();
+ return i;
}
}
// We couldn't find our sample by decode timestamp. Attempt to find it using
// presentation timestamp. There will likely be small jerkiness.
- for (uint32_t i = 0; i < track.Length(); i++) {
+ for (uint32_t i = 0; i < track.Length(); i++) {
const RefPtr<MediaRawData>& sample = track[i];
TimeInterval sampleInterval{
TimeUnit::FromMicroseconds(sample->mTime),
TimeUnit::FromMicroseconds(sample->GetEndTime()),
aFuzz};
if (sampleInterval.ContainsWithStrictEnd(trackData.mNextSampleTimecode)) {
- RefPtr<MediaRawData> p = sample->Clone();
- if (!p) {
- // OOM
- aError = true;
- return nullptr;
- }
- trackData.mNextGetSampleIndex = Some(i+1);
- // Estimate decode timestamp of the next sample.
- trackData.mNextSampleTimecode = sampleInterval.mEnd;
- trackData.mNextSampleTime =
- TimeUnit::FromMicroseconds(sample->GetEndTime());
- return p.forget();
+ return i;
}
}
- MSE_DEBUG("Couldn't find sample (pts:%lld dts:%lld)",
- trackData.mNextSampleTime.ToMicroseconds(),
- trackData.mNextSampleTimecode.ToMicroseconds());
- return nullptr;
+ // Still not found.
+ return -1;
}
TimeUnit
TrackBuffersManager::GetNextRandomAccessPoint(TrackInfo::TrackType aTrack,
const TimeUnit& aFuzz)
{
+ MOZ_ASSERT(OnTaskQueue());
auto& trackData = GetTracksData(aTrack);
MOZ_ASSERT(trackData.mNextGetSampleIndex.isSome());
const TrackBuffersManager::TrackBuffer& track = GetTrackBuffer(aTrack);
uint32_t i = trackData.mNextGetSampleIndex.ref();
TimeUnit nextSampleTimecode = trackData.mNextSampleTimecode;
TimeUnit nextSampleTime = trackData.mNextSampleTime;
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -140,20 +140,23 @@ public:
{
return mEnded;
}
media::TimeUnit Seek(TrackInfo::TrackType aTrack,
const media::TimeUnit& aTime,
const media::TimeUnit& aFuzz);
uint32_t SkipToNextRandomAccessPoint(TrackInfo::TrackType aTrack,
const media::TimeUnit& aTimeThreadshold,
+ const media::TimeUnit& aFuzz,
bool& aFound);
already_AddRefed<MediaRawData> GetSample(TrackInfo::TrackType aTrack,
const media::TimeUnit& aFuzz,
bool& aError);
+ int32_t FindCurrentPosition(TrackInfo::TrackType aTrack,
+ const media::TimeUnit& aFuzz);
media::TimeUnit GetNextRandomAccessPoint(TrackInfo::TrackType aTrack,
const media::TimeUnit& aFuzz);
void AddSizeOfResources(MediaSourceDecoder::ResourceSizes* aSizes);
private:
typedef MozPromise<bool, nsresult, /* IsExclusive = */ true> CodedFrameProcessingPromise;