Bug 1171330: P13. Relax frame discontinuity detection. r=cajbir
authorJean-Yves Avenard <jyavenard@mozilla.com>
Thu, 11 Jun 2015 16:27:08 +1000
changeset 248277 d3f99ebe7c888182b6734ac82e94e3c341252dcf
parent 248276 d62627bbe3b24fa92aef8aa9b3fa86a39bbcfb32
child 248278 06f657ea41601a67abfdc7e5f7b15c22c904d977
push id28893
push userkwierso@gmail.com
push dateFri, 12 Jun 2015 00:02:58 +0000
treeherderautoland@8cf9d3e497f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscajbir
bugs1171330
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1171330: P13. Relax frame discontinuity detection. r=cajbir
dom/media/mediasource/TrackBuffersManager.cpp
dom/media/mediasource/TrackBuffersManager.h
--- a/dom/media/mediasource/TrackBuffersManager.cpp
+++ b/dom/media/mediasource/TrackBuffersManager.cpp
@@ -258,16 +258,17 @@ TrackBuffersManager::CompleteResetParser
     // 4. Unset the highest end timestamp on all track buffers.
     track->mHighestEndTimestamp.reset();
     // 5. Set the need random access point flag on all track buffers to true.
     track->mNeedRandomAccessPoint = true;
 
     // if we have been aborted, we may have pending frames that we are going
     // to discard now.
     track->mQueuedSamples.Clear();
+    track->mLongestFrameDuration.reset();
   }
   // 6. Remove all bytes from the input buffer.
   mIncomingBuffers.Clear();
   mInputBuffer->Clear();
   if (mCurrentInputBuffer) {
     mCurrentInputBuffer->EvictAll();
     mCurrentInputBuffer = new SourceBufferResource(mType);
   }
@@ -694,16 +695,19 @@ TrackBuffersManager::OnDemuxerInitDone(n
     // then the Track IDs match the ones in the first initialization segment.
     // TODO
     // 2. Add the appropriate track descriptions from this initialization
     // segment to each of the track buffers.
     // TODO
     // 3. Set the need random access point flag on all track buffers to true.
     mVideoTracks.mNeedRandomAccessPoint = true;
     mAudioTracks.mNeedRandomAccessPoint = true;
+
+    mVideoTracks.mLongestFrameDuration = mVideoTracks.mLastFrameDuration;
+    mAudioTracks.mLongestFrameDuration = mAudioTracks.mLastFrameDuration;
   }
 
   // 4. Let active track flag equal false.
   mActiveTrack = false;
 
   // 5. If the first initialization segment received flag is false, then run the following steps:
   if (!mFirstInitializationSegmentReceived) {
     mAudioTracks.mNumTracks = numAudios;
@@ -1049,20 +1053,25 @@ TrackBuffersManager::ProcessFrame(MediaR
   auto& trackBuffer = aTrackData;
 
   // 6. If last decode timestamp for track buffer is set and decode timestamp is less than last decode timestamp:
   // OR
   // If last decode timestamp for track buffer is set and the difference between decode timestamp and last decode timestamp is greater than 2 times last frame duration:
 
   // TODO: Maybe we should be using TimeStamp and TimeDuration instead?
 
+  // Some MP4 content may exhibit an extremely short frame duration.
+  // As such, we can't use the last frame duration as a way to detect
+  // discontinuities as required per step 6 above.
+  // Instead we use the biggest duration seen so far in this run (init + media
+  // segment).
   if ((trackBuffer.mLastDecodeTimestamp.isSome() &&
        decodeTimestamp < trackBuffer.mLastDecodeTimestamp.ref()) ||
       (trackBuffer.mLastDecodeTimestamp.isSome() &&
-       decodeTimestamp - trackBuffer.mLastDecodeTimestamp.ref() > 2*trackBuffer.mLastFrameDuration.ref())) {
+       decodeTimestamp - trackBuffer.mLastDecodeTimestamp.ref() > 2*trackBuffer.mLongestFrameDuration.ref())) {
 
     // 1a. If mode equals "segments":
     if (mParent->mAppendMode == SourceBufferAppendMode::Segments) {
       // Set group end timestamp to presentation timestamp.
       mGroupEndTimestamp = presentationTimestamp;
     }
     // 1b. If mode equals "sequence":
     if (mParent->mAppendMode == SourceBufferAppendMode::Sequence) {
@@ -1073,16 +1082,18 @@ TrackBuffersManager::ProcessFrame(MediaR
       // 2. Unset the last decode timestamp on all track buffers.
       track->mLastDecodeTimestamp.reset();
       // 3. Unset the last frame duration on all track buffers.
       track->mLastFrameDuration.reset();
       // 4. Unset the highest end timestamp on all track buffers.
       track->mHighestEndTimestamp.reset();
       // 5. Set the need random access point flag on all track buffers to true.
       track->mNeedRandomAccessPoint = true;
+
+      trackBuffer.mLongestFrameDuration.reset();
     }
     MSE_DEBUG("Detected discontinuity. Restarting process");
     // 6. Jump to the Loop Top step above to restart processing of the current coded frame.
     return true;
   }
 
   // 7. Let frame end timestamp equal the sum of presentation timestamp and frame duration.
   TimeUnit frameEndTimestamp = presentationTimestamp + frameDuration;
@@ -1203,17 +1214,27 @@ TrackBuffersManager::ProcessFrame(MediaR
       }
     }
   }
   trackBuffer.mSizeBuffer += sizeof(*aSample) + aSample->mSize;
 
   // 17. Set last decode timestamp for track buffer to decode timestamp.
   trackBuffer.mLastDecodeTimestamp = Some(decodeTimestamp);
   // 18. Set last frame duration for track buffer to frame duration.
-  trackBuffer.mLastFrameDuration = Some(TimeUnit::FromMicroseconds(aSample->mDuration));
+  trackBuffer.mLastFrameDuration =
+    Some(TimeUnit::FromMicroseconds(aSample->mDuration));
+
+  if (trackBuffer.mLongestFrameDuration.isNothing()) {
+    trackBuffer.mLongestFrameDuration = trackBuffer.mLastFrameDuration;
+  } else {
+    trackBuffer.mLongestFrameDuration =
+      Some(std::max(trackBuffer.mLongestFrameDuration.ref(),
+               trackBuffer.mLastFrameDuration.ref()));
+  }
+
   // 19. If highest end timestamp for track buffer is unset or frame end timestamp is greater than highest end timestamp, then set highest end timestamp for track buffer to frame end timestamp.
   if (trackBuffer.mHighestEndTimestamp.isNothing() ||
       frameEndTimestamp > trackBuffer.mHighestEndTimestamp.ref()) {
     trackBuffer.mHighestEndTimestamp = Some(frameEndTimestamp);
   }
   // 20. If frame end timestamp is greater than group end timestamp, then set group end timestamp equal to frame end timestamp.
   if (frameEndTimestamp > mGroupEndTimestamp) {
     mGroupEndTimestamp = frameEndTimestamp;
--- a/dom/media/mediasource/TrackBuffersManager.h
+++ b/dom/media/mediasource/TrackBuffersManager.h
@@ -166,16 +166,18 @@ private:
       : mNumTracks(0)
       , mNeedRandomAccessPoint(true)
       , mSizeBuffer(0)
     {}
     uint32_t mNumTracks;
     Maybe<TimeUnit> mLastDecodeTimestamp;
     Maybe<TimeUnit> mLastFrameDuration;
     Maybe<TimeUnit> mHighestEndTimestamp;
+    // Longest frame duration seen in a coded frame group.
+    Maybe<TimeUnit> mLongestFrameDuration;
     bool mNeedRandomAccessPoint;
     nsRefPtr<MediaTrackDemuxer> mDemuxer;
     TrackBuffer mQueuedSamples;
     MediaPromiseRequestHolder<MediaTrackDemuxer::SamplesPromise> mDemuxRequest;
     UniquePtr<TrackInfo> mInfo;
     // We only manage a single track of each type at this time.
     nsTArray<TrackBuffer> mBuffers;
     TimeIntervals mBufferedRanges;