Bug 1487797 - "The seekbar is incorrectly displaying FLAC's audio progress after loop" []
☠☠ backed out by 4db3213f9303 ☠ ☠
authorChun-Min Chang <cchang>
Thu, 13 Sep 2018 14:30:00 +0300
changeset 494575 5dcf18a41fc29d4f7f10080566397fedfaa0c90a
parent 494574 5e28f82f0ba81e79ff0f53ead920e49718cab399
child 494576 38cba148ab0768c5c137b602f51fdd2b7c1f9144
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1487797
milestone64.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 1487797 - "The seekbar is incorrectly displaying FLAC's audio progress after loop" []
dom/media/flac/FlacDemuxer.cpp
--- a/dom/media/flac/FlacDemuxer.cpp
+++ b/dom/media/flac/FlacDemuxer.cpp
@@ -38,17 +38,17 @@ public:
 
   // Return the index (in samples) from the beginning of the track.
   int64_t Index() const { return mIndex; }
 
   // Parse the current packet and check that it made a valid flac frame header.
   // From https://xiph.org/flac/format.html#frame_header
   // A valid header is one that can be decoded without error and that has a
   // valid CRC.
-  bool Parse(const uint8_t* aPacket, size_t aBytes)
+  bool Parse(const uint8_t* aPacket, size_t aBytes, int64_t aPrevIndex)
   {
     BitReader br(aPacket, aBytes * 8);
 
     // Frame sync code.
     if ((br.ReadBits(15) & 0x7fff) != 0x7ffc) {
       return false;
     }
 
@@ -107,16 +107,30 @@ public:
 
     // The sample index is either:
     // 1- coded sample number if blocksize is variable or
     // 2- coded frame number if blocksize is known.
     // A frame is made of Blocksize sample.
     mIndex = mVariableBlockSize ? frame_or_sample_num
                                 : frame_or_sample_num * mBlocksize;
 
+    // The blocksize of the last frame in a fixed-blocksize stream may be
+    // smaller than its previous constant one(even it's fixed size). Hence,
+    // n * blocksize(n) may be smaller than (n-1) * blocksize(n-1),
+    // where n is the number of frames in the stream and
+    // blocksize(n) < blocksize(n-1). To make sure the index of frame is
+    // increasing (larger than its previous index), the minimal index is
+    // calculated as a index guard.
+    // `aPrevIndex` is 0 when this is called when seeking.
+    if (aPrevIndex && frame_or_sample_num > 0) {
+      int64_t minIndex = mVariableBlockSize ? aPrevIndex + 1
+                                            : aPrevIndex + mBlocksize;
+      mIndex = std::max(minIndex, mIndex);
+    }
+
     // Sample rate.
     if (sr_code < 12) {
       mInfo.mRate = FlacSampleRateTable[sr_code];
     } else if (sr_code == 12) {
       mInfo.mRate = br.ReadBits(8) * 1000;
     } else if (sr_code == 13) {
       mInfo.mRate = br.ReadBits(16);
     } else if (sr_code == 14) {
@@ -222,54 +236,54 @@ const uint8_t FrameHeader::CRC8Table[256
 class Frame
 {
 public:
 
   // The FLAC signature is made of 14 bits set to 1; however the 15th bit is
   // mandatorily set to 0, so we need to find either of 0xfffc or 0xfffd 2-bytes
   // signature. We first use a bitmask to see if 0xfc or 0xfd is present. And if
   // so we check for the whole signature.
-  int64_t FindNext(const uint8_t* aData, const uint32_t aLength)
+  int64_t FindNext(const uint8_t* aData, const uint32_t aLength, int64_t aCurrentIndex = 0)
   {
     // The non-variable size of a FLAC header is 32 bits followed by variable
     // size data and a 8 bits CRC.
     // There's no need to read the last 4 bytes, it can never make a complete
     // header.
     if (aLength < 4) {
       return -1;
     }
     uint32_t modOffset = aLength % 4;
     uint32_t i, j;
 
     for (i = 0; i < modOffset; i++) {
       if ((BigEndian::readUint16(aData + i) & 0xfffe) == 0xfff8) {
-        if (mHeader.Parse(aData + i, aLength - i)) {
+        if (mHeader.Parse(aData + i, aLength - i, aCurrentIndex)) {
           return i;
         }
       }
     }
 
     for (; i < aLength - 4; i += 4) {
       uint32_t x = BigEndian::readUint32(aData + i);
       if (((x & ~(x + 0x01010101)) & 0x80808080)) {
         for (j = 0; j < 4; j++) {
           if ((BigEndian::readUint16(aData + i + j) & 0xfffe) == 0xfff8) {
-            if (mHeader.Parse(aData + i + j, aLength - i - j)) {
+            if (mHeader.Parse(aData + i + j, aLength - i - j, aCurrentIndex)) {
               return i + j;
             }
           }
         }
       }
     }
     return -1;
   }
 
   // Find the next frame start in the current resource.
   // On exit return true, offset is set and resource points to the frame found.
-  bool FindNext(MediaResourceIndex& aResource)
+  bool FindNext(MediaResourceIndex& aResource, int64_t aCurrentIndex = 0)
   {
     static const int BUFFER_SIZE = 4096;
 
     Reset();
 
     nsTArray<char> buffer;
     int64_t originalOffset = aResource.Tell();
     int64_t offset = originalOffset;
@@ -281,17 +295,17 @@ public:
       nsresult rv =
         aResource.Read(buffer.Elements() + innerOffset, BUFFER_SIZE, &read);
       if (NS_FAILED(rv)) {
         return false;
       }
 
       const size_t bufSize = read + innerOffset;
       int64_t foundOffset =
-        FindNext(reinterpret_cast<uint8_t*>(buffer.Elements()), bufSize);
+        FindNext(reinterpret_cast<uint8_t*>(buffer.Elements()), bufSize, aCurrentIndex);
 
       if (foundOffset >= 0) {
         SetOffset(aResource, foundOffset + offset);
         return true;
       }
 
       if (read < BUFFER_SIZE) {
         // Nothing more to try on as we had reached EOS during the previous
@@ -445,17 +459,17 @@ public:
   AudioInfo Info() const { return mParser.mInfo; }
 
   // Return a hash table with tag metadata.
   MetadataTags* GetTags() const { return mParser.GetTags(); }
 
 private:
   bool GetNextFrame(MediaResourceIndex& aResource)
   {
-    while (mNextFrame.FindNext(aResource)) {
+    while (mNextFrame.FindNext(aResource, mFrame.Header().Index())) {
       // Move our offset slightly, so that we don't find the same frame at the
       // next FindNext call.
       aResource.Seek(SEEK_CUR, mNextFrame.Header().Size());
       if (mFrame.IsValid() &&
           mNextFrame.Offset() - mFrame.Offset() < FLAC_MAX_FRAME_SIZE &&
           !CheckCRC16AtOffset(
             mFrame.Offset(), mNextFrame.Offset(), aResource)) {
         // The frame doesn't match its CRC or would be too far, skip it..