Bug 1291543 - [1.1] Accept partial information from VBR headers. r=jya a=sylvestre
authorEugen Sawin <esawin@mozilla.com>
Wed, 03 Aug 2016 15:34:30 +0200
changeset 349701 0c747cd335a77578aff1a1af0e1d363a7fd12e23
parent 349700 4d51664244aad86fbd00bed49ca41da1227bcdef
child 349702 bef207d78f05f9b39923c40c69ecbde6b70dd80c
push id1230
push userjlund@mozilla.com
push dateMon, 31 Oct 2016 18:13:35 +0000
treeherdermozilla-release@5e06e3766db2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya, sylvestre
bugs1291543
milestone50.0a2
Bug 1291543 - [1.1] Accept partial information from VBR headers. r=jya a=sylvestre
dom/media/MP3Demuxer.cpp
dom/media/MP3Demuxer.h
--- a/dom/media/MP3Demuxer.cpp
+++ b/dom/media/MP3Demuxer.cpp
@@ -364,17 +364,17 @@ MP3TrackDemuxer::StreamLength() const {
 TimeUnit
 MP3TrackDemuxer::Duration() const {
   if (!mNumParsedFrames) {
     return TimeUnit::FromMicroseconds(-1);
   }
 
   int64_t numFrames = 0;
   const auto numAudioFrames = mParser.VBRInfo().NumAudioFrames();
-  if (mParser.VBRInfo().IsValid()) {
+  if (mParser.VBRInfo().IsValid() && numAudioFrames.valueOr(0) + 1 > 1) {
     // VBR headers don't include the VBR header frame.
     numFrames = numAudioFrames.value() + 1;
   } else {
     const int64_t streamLen = StreamLength();
     if (streamLen < 0) {
       // Unknown length, we can't estimate duration.
       return TimeUnit::FromMicroseconds(-1);
     }
@@ -577,17 +577,16 @@ MP3TrackDemuxer::GetNextFrame(const Medi
   frame->mTimecode = frame->mTime;
   frame->mKeyframe = true;
 
   MOZ_ASSERT(frame->mTime >= 0);
   MOZ_ASSERT(frame->mDuration > 0);
 
   if (mNumParsedFrames == 1) {
     // First frame parsed, let's read VBR info if available.
-    // TODO: read info that helps with seeking (bug 1163667).
     ByteReader reader(frame->Data(), frame->Size());
     mParser.ParseVBRHeader(&reader);
     reader.DiscardRemaining();
     mFirstFrameOffset = frame->mOffset;
   }
 
   MP3LOGV("GetNext() End mOffset=%" PRIu64 " mNumParsedFrames=%" PRIu64
           " mFrameIndex=%" PRId64 " mTotalFrameLen=%" PRIu64
@@ -598,33 +597,33 @@ MP3TrackDemuxer::GetNextFrame(const Medi
   return frame.forget();
 }
 
 int64_t
 MP3TrackDemuxer::OffsetFromFrameIndex(int64_t aFrameIndex) const {
   int64_t offset = 0;
   const auto& vbr = mParser.VBRInfo();
 
-  if (vbr.IsValid()) {
+  if (vbr.IsComplete()) {
     offset = mFirstFrameOffset + aFrameIndex * vbr.NumBytes().value() /
              vbr.NumAudioFrames().value();
   } else if (AverageFrameLength() > 0) {
     offset = mFirstFrameOffset + aFrameIndex * AverageFrameLength();
   }
 
   MP3LOGV("OffsetFromFrameIndex(%" PRId64 ") -> %" PRId64, aFrameIndex, offset);
   return std::max<int64_t>(mFirstFrameOffset, offset);
 }
 
 int64_t
 MP3TrackDemuxer::FrameIndexFromOffset(int64_t aOffset) const {
   int64_t frameIndex = 0;
   const auto& vbr = mParser.VBRInfo();
 
-  if (vbr.IsValid()) {
+  if (vbr.IsComplete()) {
     frameIndex = static_cast<float>(aOffset - mFirstFrameOffset) /
                  vbr.NumBytes().value() * vbr.NumAudioFrames().value();
     frameIndex = std::min<int64_t>(vbr.NumAudioFrames().value(), frameIndex);
   } else if (AverageFrameLength() > 0) {
     frameIndex = (aOffset - mFirstFrameOffset) / AverageFrameLength();
   }
 
   MP3LOGV("FrameIndexFromOffset(%" PRId64 ") -> %" PRId64, aOffset, frameIndex);
@@ -690,17 +689,17 @@ MP3TrackDemuxer::Read(uint8_t* aBuffer, 
 }
 
 double
 MP3TrackDemuxer::AverageFrameLength() const {
   if (mNumParsedFrames) {
     return static_cast<double>(mTotalFrameLen) / mNumParsedFrames;
   }
   const auto& vbr = mParser.VBRInfo();
-  if (vbr.IsValid() && vbr.NumAudioFrames().value() + 1) {
+  if (vbr.IsComplete() && vbr.NumAudioFrames().value() + 1) {
     return static_cast<double>(vbr.NumBytes().value()) /
            (vbr.NumAudioFrames().value() + 1);
   }
   return 0.0;
 }
 
 // FrameParser
 
@@ -1031,17 +1030,22 @@ FrameParser::VBRHeader::Scale() const {
 
 bool
 FrameParser::VBRHeader::IsTOCPresent() const {
   return mTOC.size() == vbr_header::TOC_SIZE;
 }
 
 bool
 FrameParser::VBRHeader::IsValid() const {
-  return mType != NONE &&
+  return mType != NONE;
+}
+
+bool
+FrameParser::VBRHeader::IsComplete() const {
+  return IsValid() &&
          mNumAudioFrames.valueOr(0) > 0 &&
          mNumBytes.valueOr(0) > 0 &&
          // We don't care about the scale for any computations here.
          // mScale < 101 &&
          true;
 }
 
 int64_t
--- a/dom/media/MP3Demuxer.h
+++ b/dom/media/MP3Demuxer.h
@@ -223,19 +223,22 @@ public:
     const Maybe<uint32_t>& NumBytes() const;
 
     // Returns the VBR scale factor (0: best quality, 100: lowest quality).
     const Maybe<uint32_t>& Scale() const;
 
     // Returns true iff Xing/Info TOC (table of contents) is present.
     bool IsTOCPresent() const;
 
-    // Returns whether the header is valid (containing reasonable field values).
+    // Returns whether the header is valid (type XING or VBRI).
     bool IsValid() const;
 
+    // Returns whether the header is valid and contains reasonable non-zero field values.
+    bool IsComplete() const;
+
     // Returns the byte offset for the given duration percentage as a factor
     // (0: begin, 1.0: end).
     int64_t Offset(float aDurationFac) const;
 
     // Parses contents of given ByteReader for a valid VBR header.
     // The offset of the passed ByteReader needs to point to an MPEG frame begin,
     // as a VBRI-style header is searched at a fixed offset relative to frame begin.
     // Returns whether a valid VBR header was found in the range.