tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

FlacDemuxer.cpp (35311B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "FlacDemuxer.h"
      8 
      9 #include "BitReader.h"
     10 #include "FlacFrameParser.h"
     11 #include "TimeUnits.h"
     12 #include "VideoUtils.h"
     13 #include "mozilla/Maybe.h"
     14 #include "prenv.h"
     15 
     16 #define LOG(msg, ...) \
     17  DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
     18 #define LOGV(msg, ...) \
     19  DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, msg, ##__VA_ARGS__)
     20 
     21 using namespace mozilla::media;
     22 
     23 namespace mozilla {
     24 namespace flac {
     25 
     26 // flac::FrameHeader - Holds the flac frame header and its parsing
     27 // state.
     28 
     29 class FrameHeader {
     30 public:
     31  const AudioInfo& Info() const { return mInfo; }
     32 
     33  uint32_t Size() const { return mSize; }
     34 
     35  bool IsValid() const { return mValid; }
     36 
     37  // Return the index (in samples) from the beginning of the track.
     38  int64_t Index() const { return mIndex; }
     39 
     40  // Parse the current packet and check that it made a valid flac frame header.
     41  // From https://xiph.org/flac/format.html#frame_header
     42  // A valid header is one that can be decoded without error and that has a
     43  // valid CRC.
     44  bool Parse(const uint8_t* aPacket, size_t aBytes) {
     45    BitReader br(aPacket, aBytes * 8);
     46 
     47    // Frame sync code.
     48    if ((br.ReadBits(15) & 0x7fff) != 0x7ffc) {
     49      return false;
     50    }
     51 
     52    // Variable block size stream code.
     53    mVariableBlockSize = br.ReadBit();
     54 
     55    // Block size and sample rate codes.
     56    int bs_code = AssertedCast<int>(br.ReadBits(4));
     57    int sr_code = AssertedCast<int>(br.ReadBits(4));
     58 
     59    // Channels and decorrelation.
     60    uint32_t ch_mode = br.ReadBits(4);
     61    if (ch_mode < FLAC_MAX_CHANNELS) {
     62      mInfo.mChannels = ch_mode + 1;
     63    } else if (ch_mode < FLAC_MAX_CHANNELS + FLAC_CHMODE_MID_SIDE) {
     64      // This is a special flac channels, we can't handle those yet. Treat it
     65      // as stereo.
     66      mInfo.mChannels = 2;
     67    } else {
     68      // invalid channel mode
     69      return false;
     70    }
     71 
     72    // Bits per sample.
     73    int bps_code = AssertedCast<int>(br.ReadBits(3));
     74    if (bps_code == 3 || bps_code == 7) {
     75      // Invalid sample size code.
     76      return false;
     77    }
     78    mInfo.mBitDepth = FlacSampleSizeTable[bps_code];
     79 
     80    // Reserved bit, must be 0.
     81    if (br.ReadBit()) {
     82      // Broken stream, invalid padding.
     83      return false;
     84    }
     85 
     86    // Sample or frame count.
     87    uint64_t frame_or_sample_num = br.ReadUTF8();
     88    if (frame_or_sample_num == UINT64_MAX) {
     89      // Sample/frame number invalid.
     90      return false;
     91    }
     92 
     93    // Blocksize
     94    if (bs_code == 0) {
     95      // reserved blocksize code
     96      return false;
     97    }
     98    if (bs_code == 6) {
     99      mBlocksize = br.ReadBits(8) + 1;
    100    } else if (bs_code == 7) {
    101      mBlocksize = br.ReadBits(16) + 1;
    102    } else {
    103      mBlocksize = FlacBlocksizeTable[bs_code];
    104    }
    105 
    106    // The sample index is either:
    107    // 1- coded sample number if blocksize is variable or
    108    // 2- coded frame number if blocksize is known.
    109    // A frame is made of Blocksize sample.
    110    mIndex = mVariableBlockSize
    111                 ? AssertedCast<int64_t>(frame_or_sample_num)
    112                 : AssertedCast<int64_t>(frame_or_sample_num * mBlocksize);
    113    mFrameOrSampleNum = static_cast<uint64_t>(frame_or_sample_num);
    114 
    115    // Sample rate.
    116    if (sr_code < 12) {
    117      mInfo.mRate = FlacSampleRateTable[sr_code];
    118    } else if (sr_code == 12) {
    119      mInfo.mRate = br.ReadBits(8) * 1000;
    120    } else if (sr_code == 13) {
    121      mInfo.mRate = br.ReadBits(16);
    122    } else if (sr_code == 14) {
    123      mInfo.mRate = br.ReadBits(16) * 10;
    124    } else {
    125      // Illegal sample rate code.
    126      return false;
    127    }
    128 
    129    // Header CRC-8 check.
    130    uint8_t crc = 0;
    131    for (uint32_t i = 0; i < br.BitCount() / 8; i++) {
    132      crc = CRC8Table[crc ^ aPacket[i]];
    133    }
    134    mValid =
    135 #ifdef FUZZING
    136        true;
    137 #else
    138        crc == br.ReadBits(8);
    139 #endif
    140    mSize = br.BitCount() / 8;
    141 
    142    if (mValid) {
    143      // Set the mimetype to make it a valid AudioInfo.
    144      mInfo.mMimeType = "audio/flac";
    145      // Set the codec specific data to flac, but leave it empty since we don't
    146      // have METADATA_BLOCK_STREAMINFO in the frame.
    147      mInfo.mCodecSpecificConfig =
    148          AudioCodecSpecificVariant{FlacCodecSpecificData{}};
    149    }
    150 
    151    return mValid;
    152  }
    153 
    154 private:
    155  friend class Frame;
    156  enum {
    157    FLAC_CHMODE_INDEPENDENT = 0,
    158    FLAC_CHMODE_LEFT_SIDE,
    159    FLAC_CHMODE_RIGHT_SIDE,
    160    FLAC_CHMODE_MID_SIDE,
    161  };
    162  AudioInfo mInfo;
    163  // mFrameOrSampleNum is either:
    164  // 1- coded sample number if blocksize is variable or
    165  // 2- coded frame number if blocksize is fixed.
    166  // A frame is made of Blocksize sample.
    167  uint64_t mFrameOrSampleNum = 0;
    168  // Index in samples from start;
    169  int64_t mIndex = 0;
    170  bool mVariableBlockSize = false;
    171  uint32_t mBlocksize = 0;
    172  uint32_t mSize = 0;
    173  bool mValid = false;
    174 
    175  static const uint32_t FlacSampleRateTable[16];
    176  static const uint32_t FlacBlocksizeTable[16];
    177  static const uint8_t FlacSampleSizeTable[8];
    178  static const uint8_t CRC8Table[256];
    179 };
    180 
    181 const uint32_t FrameHeader::FlacSampleRateTable[16] = {
    182    0,     88200, 176400, 192000, 8000, 16000, 22050, 24000,
    183    32000, 44100, 48000,  96000,  0,    0,     0,     0};
    184 
    185 const uint32_t FrameHeader::FlacBlocksizeTable[16] = {
    186    0,        192,      576 << 0, 576 << 1, 576 << 2, 576 << 3,
    187    0,        0,        256 << 0, 256 << 1, 256 << 2, 256 << 3,
    188    256 << 4, 256 << 5, 256 << 6, 256 << 7};
    189 
    190 const uint8_t FrameHeader::FlacSampleSizeTable[8] = {0,  8,  12, 0,
    191                                                     16, 20, 24, 0};
    192 
    193 const uint8_t FrameHeader::CRC8Table[256] = {
    194    0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31,
    195    0x24, 0x23, 0x2A, 0x2D, 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
    196    0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, 0xE0, 0xE7, 0xEE, 0xE9,
    197    0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
    198    0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1,
    199    0xB4, 0xB3, 0xBA, 0xBD, 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
    200    0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, 0xB7, 0xB0, 0xB9, 0xBE,
    201    0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
    202    0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16,
    203    0x03, 0x04, 0x0D, 0x0A, 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
    204    0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, 0x89, 0x8E, 0x87, 0x80,
    205    0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
    206    0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8,
    207    0xDD, 0xDA, 0xD3, 0xD4, 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
    208    0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, 0x19, 0x1E, 0x17, 0x10,
    209    0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
    210    0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F,
    211    0x6A, 0x6D, 0x64, 0x63, 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
    212    0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, 0xAE, 0xA9, 0xA0, 0xA7,
    213    0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
    214    0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF,
    215    0xFA, 0xFD, 0xF4, 0xF3};
    216 
    217 // flac::Frame - Frame meta container used to parse and hold a frame
    218 // header and side info.
    219 class Frame {
    220 public:
    221  // The FLAC signature is made of 14 bits set to 1; however the 15th bit is
    222  // mandatorily set to 0, so we need to find either of 0xfffc or 0xfffd 2-bytes
    223  // signature. We first use a bitmask to see if 0xfc or 0xfd is present. And if
    224  // so we check for the whole signature.
    225  int64_t FindNext(const uint8_t* aData, const uint32_t aLength) {
    226    // The non-variable size of a FLAC header is 32 bits followed by variable
    227    // size data and a 8 bits CRC.
    228    // There's no need to read the last 4 bytes, it can never make a complete
    229    // header.
    230    if (aLength < 4) {
    231      return -1;
    232    }
    233    uint32_t modOffset = aLength % 4;
    234    uint32_t i, j;
    235 
    236    for (i = 0; i < modOffset; i++) {
    237      if ((BigEndian::readUint16(aData + i) & 0xfffe) == 0xfff8) {
    238        if (mHeader.Parse(aData + i, aLength - i)) {
    239          return i;
    240        }
    241      }
    242    }
    243 
    244    for (; i < aLength - 4; i += 4) {
    245      uint32_t x = BigEndian::readUint32(aData + i);
    246      if (((x & ~(x + 0x01010101)) & 0x80808080)) {
    247        for (j = 0; j < 4; j++) {
    248          if ((BigEndian::readUint16(aData + i + j) & 0xfffe) == 0xfff8) {
    249            if (mHeader.Parse(aData + i + j, aLength - i - j)) {
    250              return i + j;
    251            }
    252          }
    253        }
    254      }
    255    }
    256    return -1;
    257  }
    258 
    259  // Find the next frame start in the current resource.
    260  // On exit return true, offset is set and resource points to the frame found.
    261  bool FindNext(MediaResourceIndex& aResource) {
    262    static const int BUFFER_SIZE = 4096;
    263 
    264    Reset();
    265 
    266    nsTArray<char> buffer;
    267    uint64_t originalOffset = static_cast<uint64_t>(aResource.Tell());
    268    uint64_t offset = originalOffset;
    269    uint32_t innerOffset = 0;
    270 
    271    do {
    272      uint32_t read = 0;
    273      buffer.SetLength(BUFFER_SIZE + innerOffset);
    274      nsresult rv =
    275          aResource.Read(buffer.Elements() + innerOffset, BUFFER_SIZE, &read);
    276      if (NS_FAILED(rv)) {
    277        return false;
    278      }
    279 
    280      const size_t bufSize = read + innerOffset;
    281      int64_t foundOffset =
    282          FindNext(reinterpret_cast<uint8_t*>(buffer.Elements()), bufSize);
    283 
    284      if (foundOffset >= 0) {
    285        SetOffset(aResource, static_cast<uint64_t>(foundOffset) + offset);
    286        return true;
    287      }
    288 
    289      if (read < BUFFER_SIZE) {
    290        // Nothing more to try on as we had reached EOS during the previous
    291        // read.
    292        mEOS = true;
    293        return false;
    294      }
    295 
    296      // Scan the next block;
    297      // We rewind a bit to re-try what could have been an incomplete packet.
    298      // The maximum size of a FLAC header being FLAC_MAX_FRAME_HEADER_SIZE so
    299      // we need to retry just after that amount.
    300      offset += bufSize - (FLAC_MAX_FRAME_HEADER_SIZE + 1);
    301      buffer.RemoveElementsAt(0, bufSize - (FLAC_MAX_FRAME_HEADER_SIZE + 1));
    302      innerOffset = buffer.Length();
    303    } while (offset - originalOffset < FLAC_MAX_FRAME_SIZE);
    304 
    305    return false;
    306  }
    307 
    308  uint64_t Offset() const { return mOffset; }
    309 
    310  const AudioInfo& Info() const { return Header().Info(); }
    311 
    312  void SetEndOffset(uint64_t aOffset) { mSize = aOffset - mOffset; }
    313 
    314  void SetEndTime(int64_t aIndex) {
    315    if (aIndex > Header().mIndex) {
    316      mDuration = aIndex - Header().mIndex;
    317    }
    318  }
    319 
    320  void ResetStartTimeIfNeeded(const Frame& aReferenceFrame) {
    321    if (Header().mVariableBlockSize ||
    322        aReferenceFrame.Header().mVariableBlockSize ||
    323        aReferenceFrame.Header().mBlocksize <= Header().mBlocksize) {
    324      // Not a fixed size frame, or nothing to adjust.
    325      return;
    326    }
    327    mHeader.mIndex = AssertedCast<int64_t>(Header().mFrameOrSampleNum *
    328                                           aReferenceFrame.Header().mBlocksize);
    329  }
    330 
    331  uint32_t Size() const { return mSize; }
    332 
    333  TimeUnit Time() const {
    334    if (!IsValid()) {
    335      return TimeUnit::Invalid();
    336    }
    337    MOZ_ASSERT(Header().Info().mRate, "Invalid Frame. Need Header");
    338    return media::TimeUnit(Header().mIndex, Header().Info().mRate);
    339  }
    340 
    341  TimeUnit Duration() const {
    342    if (!IsValid()) {
    343      return TimeUnit();
    344    }
    345    MOZ_ASSERT(Header().Info().mRate, "Invalid Frame. Need Header");
    346    return media::TimeUnit(mDuration, Header().Info().mRate);
    347  }
    348 
    349  // Returns the parsed frame header.
    350  const FrameHeader& Header() const { return mHeader; }
    351 
    352  bool IsValid() const { return mHeader.IsValid(); }
    353 
    354  bool EOS() const { return mEOS; }
    355 
    356  void SetRate(uint32_t aRate) { mHeader.mInfo.mRate = aRate; };
    357 
    358  void SetBitDepth(uint32_t aBitDepth) { mHeader.mInfo.mBitDepth = aBitDepth; }
    359 
    360  void SetInvalid() { mHeader.mValid = false; }
    361 
    362  // Resets the frame header and data.
    363  void Reset() { *this = Frame(); }
    364 
    365 private:
    366  void SetOffset(MediaResourceIndex& aResource, uint64_t aOffset) {
    367    mOffset = aOffset;
    368    aResource.Seek(SEEK_SET, AssertedCast<int64_t>(mOffset));
    369  }
    370 
    371  // The offset to the start of the header.
    372  uint64_t mOffset = 0;
    373  uint32_t mSize = 0;
    374  uint32_t mDuration = 0;
    375  bool mEOS = false;
    376 
    377  // The currently parsed frame header.
    378  FrameHeader mHeader;
    379 };
    380 
    381 class FrameParser {
    382 public:
    383  // Returns the currently parsed frame. Reset via EndFrameSession.
    384  const Frame& CurrentFrame() const { return mFrame; }
    385 
    386  // Returns the first parsed frame.
    387  const Frame& FirstFrame() const { return mFirstFrame; }
    388 
    389  // Clear the last parsed frame to allow for next frame parsing
    390  void EndFrameSession() {
    391    mNextFrame.Reset();
    392    mFrame.Reset();
    393  }
    394 
    395  // Attempt to find the next frame.
    396  bool FindNextFrame(MediaResourceIndex& aResource) {
    397    mFrame = mNextFrame;
    398    if (GetNextFrame(aResource)) {
    399      if (!mFrame.IsValid()) {
    400        mFrame = mNextFrame;
    401        // We need two frames to be able to start playing (or have reached EOS).
    402        GetNextFrame(aResource);
    403      }
    404    }
    405 
    406    if (mFrame.IsValid()) {
    407      if (mNextFrame.EOS()) {
    408        mFrame.SetEndOffset(static_cast<uint64_t>(aResource.Tell()));
    409        // If the blocksize is fixed, the frame's starting sample number will be
    410        // the frame number times the blocksize. However, the last block may
    411        // have been incorrectly set as shorter than the stream blocksize.
    412        // We recalculate the start time of this last sample using the first
    413        // frame blocksize.
    414        // TODO: should we use an overall counter of frames instead?
    415        mFrame.ResetStartTimeIfNeeded(mFirstFrame);
    416      } else if (mNextFrame.IsValid()) {
    417        mFrame.SetEndOffset(mNextFrame.Offset());
    418        mFrame.SetEndTime(mNextFrame.Header().Index());
    419      }
    420    }
    421 
    422    if (!mFirstFrame.IsValid()) {
    423      mFirstFrame = mFrame;
    424    }
    425    return mFrame.IsValid();
    426  }
    427 
    428  // Convenience methods to external FlacFrameParser ones.
    429  bool IsHeaderBlock(const uint8_t* aPacket, size_t aLength) const {
    430    auto res = mParser.IsHeaderBlock(aPacket, aLength);
    431    return res.isOk() ? res.unwrap() : false;
    432  }
    433 
    434  uint32_t HeaderBlockLength(const uint8_t* aPacket) const {
    435    return mParser.HeaderBlockLength(aPacket);
    436  }
    437 
    438  bool DecodeHeaderBlock(const uint8_t* aPacket, size_t aLength) {
    439    return mParser.DecodeHeaderBlock(aPacket, aLength).isOk();
    440  }
    441 
    442  bool HasFullMetadata() const { return mParser.HasFullMetadata(); }
    443 
    444  AudioInfo Info() const { return mParser.mInfo; }
    445 
    446  // Return a hash table with tag metadata.
    447  UniquePtr<MetadataTags> GetTags() const { return mParser.GetTags(); }
    448 
    449 private:
    450  bool GetNextFrame(MediaResourceIndex& aResource) {
    451    while (mNextFrame.FindNext(aResource)) {
    452      // Move our offset slightly, so that we don't find the same frame at the
    453      // next FindNext call.
    454      aResource.Seek(SEEK_CUR, mNextFrame.Header().Size());
    455      if (mFrame.IsValid() &&
    456          mNextFrame.Offset() - mFrame.Offset() < FLAC_MAX_FRAME_SIZE &&
    457          !CheckCRC16AtOffset(AssertedCast<int64_t>(mFrame.Offset()),
    458                              AssertedCast<int64_t>(mNextFrame.Offset()),
    459                              aResource)) {
    460        // The frame doesn't match its CRC or would be too far, skip it..
    461        continue;
    462      }
    463      CheckFrameData();
    464      break;
    465    }
    466    return mNextFrame.IsValid();
    467  }
    468 
    469  bool CheckFrameData() {
    470    if (mNextFrame.Header().Info().mRate == 0 ||
    471        mNextFrame.Header().Info().mBitDepth == 0) {
    472      if (!Info().IsValid()) {
    473        // We can only use the STREAMINFO data if we have one.
    474        mNextFrame.SetInvalid();
    475      } else {
    476        if (mNextFrame.Header().Info().mRate == 0) {
    477          mNextFrame.SetRate(Info().mRate);
    478        }
    479        if (mNextFrame.Header().Info().mBitDepth == 0) {
    480          mNextFrame.SetBitDepth(Info().mBitDepth);
    481        }
    482      }
    483    }
    484    return mNextFrame.IsValid();
    485  }
    486 
    487  bool CheckCRC16AtOffset(int64_t aStart, int64_t aEnd,
    488                          MediaResourceIndex& aResource) const {
    489    int64_t size = aEnd - aStart;
    490    if (size <= 0) {
    491      return false;
    492    }
    493    UniquePtr<char[]> buffer(new char[static_cast<size_t>(size)]);
    494    uint32_t read = 0;
    495    if (NS_FAILED(aResource.ReadAt(aStart, buffer.get(), size, &read)) ||
    496        read != size) {
    497      NS_WARNING("Couldn't read frame content");
    498      return false;
    499    }
    500 
    501    uint16_t crc = 0;
    502    uint8_t* buf = reinterpret_cast<uint8_t*>(buffer.get());
    503    const uint8_t* end = buf + size;
    504    while (buf < end) {
    505      crc = CRC16Table[((uint8_t)crc) ^ *buf++] ^ (crc >> 8);
    506    }
    507 #ifdef FUZZING
    508    return true;
    509 #else
    510    return !crc;
    511 #endif
    512  }
    513 
    514  const uint16_t CRC16Table[256] = {
    515      0x0000, 0x0580, 0x0F80, 0x0A00, 0x1B80, 0x1E00, 0x1400, 0x1180, 0x3380,
    516      0x3600, 0x3C00, 0x3980, 0x2800, 0x2D80, 0x2780, 0x2200, 0x6380, 0x6600,
    517      0x6C00, 0x6980, 0x7800, 0x7D80, 0x7780, 0x7200, 0x5000, 0x5580, 0x5F80,
    518      0x5A00, 0x4B80, 0x4E00, 0x4400, 0x4180, 0xC380, 0xC600, 0xCC00, 0xC980,
    519      0xD800, 0xDD80, 0xD780, 0xD200, 0xF000, 0xF580, 0xFF80, 0xFA00, 0xEB80,
    520      0xEE00, 0xE400, 0xE180, 0xA000, 0xA580, 0xAF80, 0xAA00, 0xBB80, 0xBE00,
    521      0xB400, 0xB180, 0x9380, 0x9600, 0x9C00, 0x9980, 0x8800, 0x8D80, 0x8780,
    522      0x8200, 0x8381, 0x8601, 0x8C01, 0x8981, 0x9801, 0x9D81, 0x9781, 0x9201,
    523      0xB001, 0xB581, 0xBF81, 0xBA01, 0xAB81, 0xAE01, 0xA401, 0xA181, 0xE001,
    524      0xE581, 0xEF81, 0xEA01, 0xFB81, 0xFE01, 0xF401, 0xF181, 0xD381, 0xD601,
    525      0xDC01, 0xD981, 0xC801, 0xCD81, 0xC781, 0xC201, 0x4001, 0x4581, 0x4F81,
    526      0x4A01, 0x5B81, 0x5E01, 0x5401, 0x5181, 0x7381, 0x7601, 0x7C01, 0x7981,
    527      0x6801, 0x6D81, 0x6781, 0x6201, 0x2381, 0x2601, 0x2C01, 0x2981, 0x3801,
    528      0x3D81, 0x3781, 0x3201, 0x1001, 0x1581, 0x1F81, 0x1A01, 0x0B81, 0x0E01,
    529      0x0401, 0x0181, 0x0383, 0x0603, 0x0C03, 0x0983, 0x1803, 0x1D83, 0x1783,
    530      0x1203, 0x3003, 0x3583, 0x3F83, 0x3A03, 0x2B83, 0x2E03, 0x2403, 0x2183,
    531      0x6003, 0x6583, 0x6F83, 0x6A03, 0x7B83, 0x7E03, 0x7403, 0x7183, 0x5383,
    532      0x5603, 0x5C03, 0x5983, 0x4803, 0x4D83, 0x4783, 0x4203, 0xC003, 0xC583,
    533      0xCF83, 0xCA03, 0xDB83, 0xDE03, 0xD403, 0xD183, 0xF383, 0xF603, 0xFC03,
    534      0xF983, 0xE803, 0xED83, 0xE783, 0xE203, 0xA383, 0xA603, 0xAC03, 0xA983,
    535      0xB803, 0xBD83, 0xB783, 0xB203, 0x9003, 0x9583, 0x9F83, 0x9A03, 0x8B83,
    536      0x8E03, 0x8403, 0x8183, 0x8002, 0x8582, 0x8F82, 0x8A02, 0x9B82, 0x9E02,
    537      0x9402, 0x9182, 0xB382, 0xB602, 0xBC02, 0xB982, 0xA802, 0xAD82, 0xA782,
    538      0xA202, 0xE382, 0xE602, 0xEC02, 0xE982, 0xF802, 0xFD82, 0xF782, 0xF202,
    539      0xD002, 0xD582, 0xDF82, 0xDA02, 0xCB82, 0xCE02, 0xC402, 0xC182, 0x4382,
    540      0x4602, 0x4C02, 0x4982, 0x5802, 0x5D82, 0x5782, 0x5202, 0x7002, 0x7582,
    541      0x7F82, 0x7A02, 0x6B82, 0x6E02, 0x6402, 0x6182, 0x2002, 0x2582, 0x2F82,
    542      0x2A02, 0x3B82, 0x3E02, 0x3402, 0x3182, 0x1382, 0x1602, 0x1C02, 0x1982,
    543      0x0802, 0x0D82, 0x0782, 0x0202,
    544  };
    545 
    546  FlacFrameParser mParser;
    547  // We keep the first parsed frame around for static info access
    548  // and the currently parsed frame.
    549  Frame mFirstFrame;
    550  Frame mNextFrame;
    551  Frame mFrame;
    552 };
    553 
    554 }  // namespace flac
    555 
    556 // FlacDemuxer
    557 
    558 FlacDemuxer::FlacDemuxer(MediaResource* aSource) : mSource(aSource) {
    559  DDLINKCHILD("source", aSource);
    560 }
    561 
    562 bool FlacDemuxer::InitInternal() {
    563  if (!mTrackDemuxer) {
    564    mTrackDemuxer = new FlacTrackDemuxer(mSource);
    565    DDLINKCHILD("track demuxer", mTrackDemuxer.get());
    566  }
    567  return mTrackDemuxer->Init();
    568 }
    569 
    570 RefPtr<FlacDemuxer::InitPromise> FlacDemuxer::Init() {
    571  if (!InitInternal()) {
    572    LOG("Init() failure: waiting for data");
    573 
    574    return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
    575                                        __func__);
    576  }
    577 
    578  LOG("Init() successful");
    579  return InitPromise::CreateAndResolve(NS_OK, __func__);
    580 }
    581 
    582 uint32_t FlacDemuxer::GetNumberTracks(TrackInfo::TrackType aType) const {
    583  return (aType == TrackInfo::kAudioTrack) ? 1 : 0;
    584 }
    585 
    586 already_AddRefed<MediaTrackDemuxer> FlacDemuxer::GetTrackDemuxer(
    587    TrackInfo::TrackType aType, uint32_t aTrackNumber) {
    588  if (!mTrackDemuxer) {
    589    return nullptr;
    590  }
    591 
    592  return RefPtr<FlacTrackDemuxer>(mTrackDemuxer).forget();
    593 }
    594 
    595 bool FlacDemuxer::IsSeekable() const {
    596  return mTrackDemuxer && mTrackDemuxer->IsSeekable();
    597 }
    598 
    599 // FlacTrackDemuxer
    600 FlacTrackDemuxer::FlacTrackDemuxer(MediaResource* aSource)
    601    : mSource(aSource), mParser(new flac::FrameParser()), mTotalFrameLen(0) {
    602  DDLINKCHILD("source", aSource);
    603  Reset();
    604 }
    605 
    606 FlacTrackDemuxer::~FlacTrackDemuxer() = default;
    607 
    608 bool FlacTrackDemuxer::Init() {
    609  static const int BUFFER_SIZE = 4096;
    610 
    611  // First check if we have a valid Flac start.
    612  char buffer[BUFFER_SIZE];
    613  const uint8_t* ubuffer =  // only needed due to type constraints of ReadAt.
    614      reinterpret_cast<uint8_t*>(buffer);
    615  int64_t offset = 0;
    616 
    617  do {
    618    uint32_t read = 0;
    619    nsresult ret = mSource.ReadAt(offset, buffer, BUFFER_SIZE, &read);
    620    if (NS_FAILED(ret)) {
    621      return false;
    622    }
    623    if (!mParser->IsHeaderBlock(ubuffer, read)) {
    624      // Not a header and we haven't reached the end of the metadata blocks.
    625      // Will fall back to using the frames header instead.
    626      break;
    627    }
    628    uint32_t sizeHeader = mParser->HeaderBlockLength(ubuffer);
    629    RefPtr<MediaByteBuffer> block = mSource.MediaReadAt(offset, sizeHeader);
    630    if (!block || block->Length() != sizeHeader) {
    631      break;
    632    }
    633    if (!mParser->DecodeHeaderBlock(block->Elements(), sizeHeader)) {
    634      break;
    635    }
    636    offset += sizeHeader;
    637  } while (!mParser->HasFullMetadata());
    638 
    639  // First flac frame is found after the metadata.
    640  // Can seek there immediately to avoid reparsing it all.
    641  mSource.Seek(SEEK_SET, offset);
    642 
    643  // Find the first frame to fully initialise our parser.
    644  if (mParser->FindNextFrame(mSource)) {
    645    // Ensure that the next frame returned will be the first.
    646    mSource.Seek(SEEK_SET,
    647                 AssertedCast<int64_t>(mParser->FirstFrame().Offset()));
    648    mParser->EndFrameSession();
    649  } else if (!mParser->Info().IsValid() || !mParser->FirstFrame().IsValid()) {
    650    // We must find at least a frame to determine the metadata.
    651    // We can't play this stream.
    652    return false;
    653  }
    654 
    655  if (!mParser->Info().IsValid() || !mParser->Info().mDuration.IsPositive()) {
    656    // Check if we can look at the last frame for the end time to determine the
    657    // duration when we don't have any.
    658    TimeAtEnd();
    659  }
    660 
    661  return true;
    662 }
    663 
    664 UniquePtr<TrackInfo> FlacTrackDemuxer::GetInfo() const {
    665  if (mParser->Info().IsValid()) {
    666    // We have a proper metadata header.
    667    UniquePtr<TrackInfo> info = mParser->Info().Clone();
    668    UniquePtr<MetadataTags> tags(mParser->GetTags());
    669    if (tags) {
    670      for (const auto& entry : *tags) {
    671        info->mTags.AppendElement(MetadataTag(entry.GetKey(), entry.GetData()));
    672      }
    673    }
    674    MOZ_ASSERT(info->IsAudio() &&
    675                   info->GetAsAudioInfo()
    676                       ->mCodecSpecificConfig.is<FlacCodecSpecificData>(),
    677               "Should get flac specific data from parser");
    678    return info;
    679  }
    680 
    681  if (mParser->FirstFrame().Info().IsValid()) {
    682    // Use the first frame header.
    683    UniquePtr<TrackInfo> info = mParser->FirstFrame().Info().Clone();
    684    info->mDuration = Duration();
    685    MOZ_ASSERT(info->IsAudio() &&
    686                   info->GetAsAudioInfo()
    687                       ->mCodecSpecificConfig.is<FlacCodecSpecificData>(),
    688               "Should get flac specific data from parser");
    689    return info;
    690  }
    691  return nullptr;
    692 }
    693 
    694 bool FlacTrackDemuxer::IsSeekable() const {
    695  // For now we only allow seeking if a STREAMINFO block was found and with
    696  // a known number of samples (duration is set).
    697  return mParser->Info().IsValid() && mParser->Info().mDuration.IsPositive();
    698 }
    699 
    700 RefPtr<FlacTrackDemuxer::SeekPromise> FlacTrackDemuxer::Seek(
    701    const TimeUnit& aTime) {
    702  // Efficiently seek to the position.
    703  FastSeek(aTime);
    704  // Correct seek position by scanning the next frames.
    705  const TimeUnit seekTime = ScanUntil(aTime);
    706 
    707  return SeekPromise::CreateAndResolve(seekTime, __func__);
    708 }
    709 
    710 TimeUnit FlacTrackDemuxer::FastSeek(const TimeUnit& aTime) {
    711  LOG("FastSeek(%f) avgFrameLen=%f mParsedFramesDuration=%f offset=%" PRId64,
    712      aTime.ToSeconds(), AverageFrameLength(),
    713      mParsedFramesDuration.ToSeconds(), GetResourceOffset());
    714 
    715  // Invalidate current frames in the parser.
    716  mParser->EndFrameSession();
    717 
    718  if (!mParser->FirstFrame().IsValid()) {
    719    // Something wrong, and there's nothing to seek to anyway, so we can
    720    // do whatever here.
    721    mSource.Seek(SEEK_SET, 0);
    722    return TimeUnit();
    723  }
    724 
    725  if (aTime <= mParser->FirstFrame().Time()) {
    726    // We're attempting to seek prior the first frame, return the first frame.
    727    mSource.Seek(SEEK_SET,
    728                 AssertedCast<int64_t>(mParser->FirstFrame().Offset()));
    729    return mParser->FirstFrame().Time();
    730  }
    731 
    732  // We look for the seek position using a bisection search, starting where the
    733  // estimated position might be using the average frame length.
    734  // Typically, with flac such approximation is typically useless.
    735 
    736  // Estimate where the position might be.
    737  int64_t pivot = AssertedCast<int64_t>(
    738      aTime.ToSeconds() * AverageFrameLength() +
    739      AssertedCast<double>(mParser->FirstFrame().Offset()));
    740 
    741  // Time in seconds where we can stop seeking and will continue using
    742  // ScanUntil.
    743  static const int GAP_THRESHOLD = 5;
    744  int64_t first = AssertedCast<int64_t>(mParser->FirstFrame().Offset());
    745  int64_t last = mSource.GetLength();
    746  Maybe<uint64_t> lastFoundOffset;
    747  uint32_t iterations = 0;
    748  TimeUnit timeSeekedTo;
    749 
    750  do {
    751    iterations++;
    752    mSource.Seek(SEEK_SET, pivot);
    753    flac::Frame frame;
    754    bool found = frame.FindNext(mSource);
    755    if (!found) {
    756      NS_WARNING("We should have found a point");
    757      break;
    758    }
    759    if (!frame.IsValid()) {
    760      NS_WARNING("Invalid frame after seeking and sync on a frame");
    761      break;
    762    }
    763    // When the rate is 0, the rate from STREAMINFO is to be used.
    764    if (frame.Header().Info().mRate == 0) {
    765      frame.SetRate(mParser->FirstFrame().Info().mRate);
    766    }
    767    timeSeekedTo = frame.Time();
    768 
    769    LOGV("FastSeek: interation:%u found:%f @ %" PRIu64, iterations,
    770         timeSeekedTo.ToSeconds(), frame.Offset());
    771 
    772    if (lastFoundOffset && lastFoundOffset.ref() == frame.Offset()) {
    773      // Same frame found twice. We're done.
    774      break;
    775    }
    776    lastFoundOffset = Some(frame.Offset());
    777 
    778    if (frame.Time() == aTime) {
    779      break;
    780    }
    781    if (aTime > frame.Time() &&
    782        aTime - frame.Time() <= TimeUnit::FromSeconds(GAP_THRESHOLD)) {
    783      // We're close enough to the target, experimentation shows that bisection
    784      // search doesn't help much after that.
    785      break;
    786    }
    787    if (frame.Time() > aTime) {
    788      last = pivot;
    789      pivot -= (pivot - first) / 2;
    790    } else {
    791      first = pivot;
    792      pivot += (last - pivot) / 2;
    793    }
    794  } while (true);
    795 
    796  if (lastFoundOffset) {
    797    mSource.Seek(SEEK_SET, AssertedCast<int64_t>(lastFoundOffset.ref()));
    798  }
    799 
    800  return timeSeekedTo;
    801 }
    802 
    803 TimeUnit FlacTrackDemuxer::ScanUntil(const TimeUnit& aTime) {
    804  LOG("ScanUntil(%f avgFrameLen=%f mParsedFramesDuration=%f offset=%" PRId64,
    805      aTime.ToSeconds(), AverageFrameLength(),
    806      mParsedFramesDuration.ToSeconds(), mParser->CurrentFrame().Offset());
    807 
    808  if (!mParser->FirstFrame().IsValid() ||
    809      aTime <= mParser->FirstFrame().Time()) {
    810    return FastSeek(aTime);
    811  }
    812 
    813  int64_t previousOffset = 0;
    814  TimeUnit previousTime;
    815  while (FindNextFrame().IsValid() && mParser->CurrentFrame().Time() < aTime) {
    816    previousOffset = AssertedCast<int64_t>(mParser->CurrentFrame().Offset());
    817    previousTime = mParser->CurrentFrame().Time();
    818  }
    819 
    820  if (!mParser->CurrentFrame().IsValid()) {
    821    // We reached EOS.
    822    return Duration();
    823  }
    824 
    825  // Seek back to the last frame found prior the target.
    826  mParser->EndFrameSession();
    827  mSource.Seek(SEEK_SET, previousOffset);
    828  return previousTime;
    829 }
    830 
    831 RefPtr<FlacTrackDemuxer::SamplesPromise> FlacTrackDemuxer::GetSamples(
    832    int32_t aNumSamples) {
    833  LOGV("GetSamples(%d) Begin offset=%" PRId64
    834       " mParsedFramesDuration=%f"
    835       " mTotalFrameLen=%" PRIu64,
    836       aNumSamples, GetResourceOffset(), mParsedFramesDuration.ToSeconds(),
    837       mTotalFrameLen);
    838 
    839  if (!aNumSamples) {
    840    return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
    841                                           __func__);
    842  }
    843 
    844  RefPtr<SamplesHolder> frames = new SamplesHolder();
    845 
    846  while (aNumSamples--) {
    847    RefPtr<MediaRawData> frame(GetNextFrame(FindNextFrame()));
    848    if (!frame) break;
    849    if (!frame->HasValidTime()) {
    850      return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_DEMUXER_ERR,
    851                                             __func__);
    852    }
    853    frames->AppendSample(std::move(frame));
    854  }
    855 
    856  LOGV("GetSamples() End mSamples.Length=%zu aNumSamples=%d offset=%" PRId64
    857       " mParsedFramesDuration=%f mTotalFrameLen=%" PRIu64,
    858       frames->GetSamples().Length(), aNumSamples, GetResourceOffset(),
    859       mParsedFramesDuration.ToSeconds(), mTotalFrameLen);
    860 
    861  if (frames->GetSamples().IsEmpty()) {
    862    return SamplesPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_END_OF_STREAM,
    863                                           __func__);
    864  }
    865 
    866  return SamplesPromise::CreateAndResolve(frames, __func__);
    867 }
    868 
    869 void FlacTrackDemuxer::Reset() {
    870  LOG("Reset()");
    871  MOZ_ASSERT(mParser);
    872  if (mParser->FirstFrame().IsValid()) {
    873    mSource.Seek(SEEK_SET,
    874                 AssertedCast<int64_t>(mParser->FirstFrame().Offset()));
    875  } else {
    876    mSource.Seek(SEEK_SET, 0);
    877  }
    878  mParser->EndFrameSession();
    879 }
    880 
    881 RefPtr<FlacTrackDemuxer::SkipAccessPointPromise>
    882 FlacTrackDemuxer::SkipToNextRandomAccessPoint(const TimeUnit& aTimeThreshold) {
    883  // Will not be called for audio-only resources.
    884  return SkipAccessPointPromise::CreateAndReject(
    885      SkipFailureHolder(NS_ERROR_DOM_MEDIA_DEMUXER_ERR, 0), __func__);
    886 }
    887 
    888 int64_t FlacTrackDemuxer::GetResourceOffset() const { return mSource.Tell(); }
    889 
    890 TimeIntervals FlacTrackDemuxer::GetBuffered() {
    891  TimeUnit duration = Duration();
    892 
    893  if (duration <= TimeUnit()) {
    894    return TimeIntervals();
    895  }
    896 
    897  // We could simply parse the cached data instead and read the timestamps.
    898  // However, for now this will do.
    899  AutoPinned<MediaResource> stream(mSource.GetResource());
    900  return GetEstimatedBufferedTimeRanges(stream, duration.ToMicroseconds());
    901 }
    902 
    903 const flac::Frame& FlacTrackDemuxer::FindNextFrame() {
    904  LOGV("FindNextFrame() Begin offset=%" PRId64
    905       " mParsedFramesDuration=%f"
    906       " mTotalFrameLen=%" PRIu64,
    907       GetResourceOffset(), mParsedFramesDuration.ToSeconds(), mTotalFrameLen);
    908 
    909  if (mParser->FindNextFrame(mSource)) {
    910    // Update our current progress stats.
    911    mParsedFramesDuration =
    912        std::max(mParsedFramesDuration, mParser->CurrentFrame().Time() -
    913                                            mParser->FirstFrame().Time() +
    914                                            mParser->CurrentFrame().Duration());
    915    mTotalFrameLen =
    916        std::max<uint64_t>(mTotalFrameLen, mParser->CurrentFrame().Offset() -
    917                                               mParser->FirstFrame().Offset() +
    918                                               mParser->CurrentFrame().Size());
    919 
    920    LOGV("FindNextFrame() End time=%f offset=%" PRId64
    921         " mParsedFramesDuration=%f"
    922         " mTotalFrameLen=%" PRIu64,
    923         mParser->CurrentFrame().Time().ToSeconds(), GetResourceOffset(),
    924         mParsedFramesDuration.ToSeconds(), mTotalFrameLen);
    925  }
    926 
    927  return mParser->CurrentFrame();
    928 }
    929 
    930 already_AddRefed<MediaRawData> FlacTrackDemuxer::GetNextFrame(
    931    const flac::Frame& aFrame) {
    932  if (!aFrame.IsValid()) {
    933    LOG("GetNextFrame() EOS");
    934    return nullptr;
    935  }
    936 
    937  LOG("GetNextFrame() Begin(time=%f offset=%" PRId64 " size=%u)",
    938      aFrame.Time().ToSeconds(), aFrame.Offset(), aFrame.Size());
    939 
    940  const uint64_t offset = aFrame.Offset();
    941  const uint32_t size = aFrame.Size();
    942 
    943  RefPtr<MediaRawData> frame = new MediaRawData();
    944  frame->mOffset = AssertedCast<int64_t>(offset);
    945 
    946  UniquePtr<MediaRawDataWriter> frameWriter(frame->CreateWriter());
    947  if (!frameWriter->SetSize(size)) {
    948    LOG("GetNext() Exit failed to allocated media buffer");
    949    return nullptr;
    950  }
    951 
    952  const uint32_t read = Read(frameWriter->Data(), AssertedCast<int64_t>(offset),
    953                             AssertedCast<int32_t>(size));
    954  if (read != size) {
    955    LOG("GetNextFrame() Exit read=%u frame->Size=%zu", read, frame->Size());
    956    return nullptr;
    957  }
    958 
    959  frame->mTime = aFrame.Time();
    960  frame->mDuration = aFrame.Duration();
    961  frame->mTimecode = frame->mTime;
    962  frame->mOffset = AssertedCast<int64_t>(aFrame.Offset());
    963  frame->mKeyframe = true;
    964 
    965  MOZ_ASSERT(!frame->mTime.IsNegative());
    966  MOZ_ASSERT(!frame->mDuration.IsNegative());
    967 
    968  return frame.forget();
    969 }
    970 
    971 uint32_t FlacTrackDemuxer::Read(uint8_t* aBuffer, int64_t aOffset,
    972                                int32_t aSize) {
    973  uint32_t read = 0;
    974  const nsresult rv = mSource.ReadAt(aOffset, reinterpret_cast<char*>(aBuffer),
    975                                     static_cast<uint32_t>(aSize), &read);
    976  NS_ENSURE_SUCCESS(rv, 0);
    977  return read;
    978 }
    979 
    980 double FlacTrackDemuxer::AverageFrameLength() const {
    981  if (mParsedFramesDuration.ToMicroseconds()) {
    982    return AssertedCast<double>(mTotalFrameLen) /
    983           mParsedFramesDuration.ToSeconds();
    984  }
    985 
    986  return 0.0;
    987 }
    988 
    989 TimeUnit FlacTrackDemuxer::Duration() const {
    990  return std::max(mParsedFramesDuration, mParser->Info().mDuration);
    991 }
    992 
    993 TimeUnit FlacTrackDemuxer::TimeAtEnd() {
    994  // Scan the last 128kB if available to determine the last frame.
    995  static const int OFFSET_FROM_END = 128 * 1024;
    996 
    997  // Seek to the end of the file and attempt to find the last frame.
    998  MediaResourceIndex source(mSource.GetResource());
    999  TimeUnit previousDuration;
   1000  TimeUnit previousTime;
   1001 
   1002  const int64_t streamLen = mSource.GetLength();
   1003  if (streamLen < 0) {
   1004    return TimeUnit::FromInfinity();
   1005  }
   1006 
   1007  flac::FrameParser parser;
   1008 
   1009  source.Seek(SEEK_SET, std::max<int64_t>(0LL, streamLen - OFFSET_FROM_END));
   1010  while (parser.FindNextFrame(source)) {
   1011    // FFmpeg flac muxer can generate a last frame with earlier than the others.
   1012    previousTime = std::max(previousTime, parser.CurrentFrame().Time());
   1013    if (parser.CurrentFrame().Duration() > TimeUnit()) {
   1014      // The last frame doesn't have a duration, so only update our duration
   1015      // if we do have one.
   1016      previousDuration = parser.CurrentFrame().Duration();
   1017    }
   1018    if (source.Tell() >= streamLen) {
   1019      // Limit the read, in case the length change half-way.
   1020      break;
   1021    }
   1022  }
   1023 
   1024  // Update our current progress stats.
   1025  mParsedFramesDuration =
   1026      previousTime + previousDuration - mParser->FirstFrame().Time();
   1027 
   1028  mTotalFrameLen =
   1029      static_cast<uint64_t>(streamLen) - mParser->FirstFrame().Offset();
   1030 
   1031  return mParsedFramesDuration;
   1032 }
   1033 
   1034 /* static */
   1035 bool FlacDemuxer::FlacSniffer(const uint8_t* aData, const uint32_t aLength) {
   1036  if (aLength < FLAC_MIN_FRAME_SIZE) {
   1037    return false;
   1038  }
   1039 
   1040  flac::Frame frame;
   1041  return frame.FindNext(aData, aLength) >= 0;
   1042 }
   1043 
   1044 }  // namespace mozilla