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 487148 5dcf18a41fc29d4f7f10080566397fedfaa0c90a
parent 487147 5e28f82f0ba81e79ff0f53ead920e49718cab399
child 487149 38cba148ab0768c5c137b602f51fdd2b7c1f9144
push id246
push userfmarier@mozilla.com
push dateSat, 13 Oct 2018 00:15:40 +0000
bugs1487797
milestone64.0a1
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..