tor-browser

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

OpusParser.cpp (7232B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      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 "OpusParser.h"
      8 
      9 #include <opus/opus.h>
     10 
     11 #include <algorithm>
     12 
     13 #include "VideoUtils.h"
     14 #include "mozilla/EndianUtils.h"
     15 extern "C" {
     16 #include <opus/opus_multistream.h>
     17 }
     18 
     19 #include <cmath>
     20 
     21 namespace mozilla {
     22 
     23 extern LazyLogModule gMediaDecoderLog;
     24 #define OPUS_LOG(type, msg) MOZ_LOG(gMediaDecoderLog, type, msg)
     25 
     26 OpusParser::OpusParser()
     27    : mRate(0),
     28      mNominalRate(0),
     29      mChannels(0),
     30      mPreSkip(0),
     31 #ifdef MOZ_SAMPLE_TYPE_FLOAT32
     32      mGain(1.0f),
     33 #else
     34      mGain_Q16(65536),
     35 #endif
     36      mChannelMapping(0),
     37      mStreams(0),
     38      mCoupledStreams(0),
     39      mPrevPacketGranulepos(0) {
     40 }
     41 
     42 bool OpusParser::DecodeHeader(unsigned char* aData, size_t aLength) {
     43  if (aLength < 19 || memcmp(aData, "OpusHead", 8) != 0) {
     44    OPUS_LOG(LogLevel::Debug, ("Invalid Opus file: unrecognized header"));
     45    return false;
     46  }
     47 
     48  mRate = 48000;  // The Opus decoder runs at 48 kHz regardless.
     49 
     50  int version = aData[8];
     51  // Accept file format versions 0.x.
     52  if ((version & 0xf0) != 0) {
     53    OPUS_LOG(LogLevel::Debug,
     54             ("Rejecting unknown Opus file version %d", version));
     55    return false;
     56  }
     57 
     58  mChannels = aData[9];
     59  if (mChannels < 1) {
     60    OPUS_LOG(LogLevel::Debug,
     61             ("Invalid Opus file: Number of channels %d", mChannels));
     62    return false;
     63  }
     64 
     65  mPreSkip = LittleEndian::readUint16(aData + 10);
     66  mNominalRate = LittleEndian::readUint32(aData + 12);
     67  double gain_dB = LittleEndian::readInt16(aData + 16) / 256.0;
     68 #ifdef MOZ_SAMPLE_TYPE_FLOAT32
     69  mGain = static_cast<float>(pow(10, 0.05 * gain_dB));
     70 #else
     71  mGain_Q16 = static_cast<int32_t>(std::min(
     72      65536 * pow(10, 0.05 * gain_dB) + 0.5, static_cast<double>(INT32_MAX)));
     73 #endif
     74  mChannelMapping = aData[18];
     75 
     76  if (mChannelMapping == 0) {
     77    // Mapping family 0 only allows two channels
     78    if (mChannels > 2) {
     79      OPUS_LOG(LogLevel::Debug, ("Invalid Opus file: too many channels (%d) for"
     80                                 " mapping family 0.",
     81                                 mChannels));
     82      return false;
     83    }
     84    mStreams = 1;
     85    mCoupledStreams = mChannels - 1;
     86    mMappingTable[0] = 0;
     87    mMappingTable[1] = 1;
     88  } else if (mChannelMapping == 1 || mChannelMapping == 2 ||
     89             mChannelMapping == 255) {
     90    // Currently only up to 8 channels are defined for mapping family 1
     91    if (mChannelMapping == 1 && mChannels > 8) {
     92      OPUS_LOG(LogLevel::Debug, ("Invalid Opus file: too many channels (%d) for"
     93                                 " mapping family 1.",
     94                                 mChannels));
     95      return false;
     96    }
     97    if (mChannelMapping == 2) {
     98      if (!IsValidMapping2ChannelsCount(mChannels)) {
     99        return false;
    100      }
    101    }
    102    if (aLength > static_cast<unsigned>(20 + mChannels)) {
    103      mStreams = aData[19];
    104      mCoupledStreams = aData[20];
    105      int i;
    106      for (i = 0; i < mChannels; i++) {
    107        mMappingTable[i] = aData[21 + i];
    108      }
    109    } else {
    110      OPUS_LOG(LogLevel::Debug, ("Invalid Opus file: channel mapping %d,"
    111                                 " but no channel mapping table",
    112                                 mChannelMapping));
    113      return false;
    114    }
    115  } else {
    116    OPUS_LOG(LogLevel::Debug, ("Invalid Opus file: unsupported channel mapping "
    117                               "family %d",
    118                               mChannelMapping));
    119    return false;
    120  }
    121  if (mStreams < 1) {
    122    OPUS_LOG(LogLevel::Debug, ("Invalid Opus file: no streams"));
    123    return false;
    124  }
    125  if (mCoupledStreams > mStreams) {
    126    OPUS_LOG(LogLevel::Debug,
    127             ("Invalid Opus file: more coupled streams (%d) than "
    128              "total streams (%d)",
    129              mCoupledStreams, mStreams));
    130    return false;
    131  }
    132 
    133 #ifdef DEBUG
    134  OPUS_LOG(LogLevel::Debug, ("Opus stream header:"));
    135  OPUS_LOG(LogLevel::Debug, (" channels: %d", mChannels));
    136  OPUS_LOG(LogLevel::Debug, ("  preskip: %d", mPreSkip));
    137  OPUS_LOG(LogLevel::Debug, (" original: %d Hz", mNominalRate));
    138  OPUS_LOG(LogLevel::Debug, ("     gain: %.2f dB", gain_dB));
    139  OPUS_LOG(LogLevel::Debug, ("Channel Mapping:"));
    140  OPUS_LOG(LogLevel::Debug, ("   family: %d", mChannelMapping));
    141  OPUS_LOG(LogLevel::Debug, ("  streams: %d", mStreams));
    142 #endif
    143  return true;
    144 }
    145 
    146 bool OpusParser::DecodeTags(unsigned char* aData, size_t aLength) {
    147  if (aLength < 16 || memcmp(aData, "OpusTags", 8) != 0) {
    148    return false;
    149  }
    150 
    151  // Copy out the raw comment lines, but only do basic validation
    152  // checks against the string packing: too little data, too many
    153  // comments, or comments that are too long. Rejecting these cases
    154  // helps reduce the propagation of broken files.
    155  // We do not ensure they are valid UTF-8 here, nor do we validate
    156  // the required ASCII_TAG=value format of the user comments.
    157  const unsigned char* buf = aData + 8;
    158  uint32_t bytes = aLength - 8;
    159  uint32_t len;
    160  // Read the vendor string.
    161  len = LittleEndian::readUint32(buf);
    162  buf += 4;
    163  bytes -= 4;
    164  if (len > bytes) return false;
    165  mVendorString = nsCString(reinterpret_cast<const char*>(buf), len);
    166  buf += len;
    167  bytes -= len;
    168  // Read the user comments.
    169  if (bytes < 4) return false;
    170  uint32_t ncomments = LittleEndian::readUint32(buf);
    171  buf += 4;
    172  bytes -= 4;
    173  // If there are so many comments even their length fields
    174  // won't fit in the packet, stop reading now.
    175  if (ncomments > (bytes >> 2)) return false;
    176  for (uint32_t i = 0; i < ncomments; i++) {
    177    if (bytes < 4) return false;
    178    len = LittleEndian::readUint32(buf);
    179    buf += 4;
    180    bytes -= 4;
    181    if (len > bytes) return false;
    182    mTags.AppendElement(nsCString(reinterpret_cast<const char*>(buf), len));
    183    buf += len;
    184    bytes -= len;
    185  }
    186 
    187 #ifdef DEBUG
    188  OPUS_LOG(LogLevel::Debug, ("Opus metadata header:"));
    189  OPUS_LOG(LogLevel::Debug, ("  vendor: %s", mVendorString.get()));
    190  for (uint32_t i = 0; i < mTags.Length(); i++) {
    191    OPUS_LOG(LogLevel::Debug, (" %s", mTags[i].get()));
    192  }
    193 #endif
    194  return true;
    195 }
    196 
    197 /* static */
    198 bool OpusParser::IsValidMapping2ChannelsCount(uint8_t aChannels) {
    199  // https://tools.ietf.org/html/draft-ietf-codec-ambisonics-08#page-4
    200  // For both channel mapping family 2 and family 3, the allowed numbers
    201  // of channels: (1 + n)^2 + 2j for n = 0, 1, ..., 14 and j = 0 or 1,
    202  // where n denotes the (highest) ambisonic order and j denotes whether
    203  // or not there is a separate non-diegetic stereo stream Explicitly the
    204  // allowed number of channels are 1, 3, 4, 6, 9, 11, 16, 18, 25, 27, 36,
    205  // 38, 49, 51, 64, 66, 81, 83, 100, 102, 121, 123, 144, 146, 169, 171,
    206  // 196, 198, 225, and 227.
    207 
    208  // We use the property that int(sqrt(n)) == int(sqrt(n+2)) for n != 3
    209  // which is handled by the test n^2 + 2 != channel
    210  if (aChannels < 1 || aChannels > 227) {
    211    return false;
    212  }
    213  double val = sqrt(aChannels);
    214  int32_t valInt = int32_t(val);
    215  return val == valInt || valInt * valInt + 2 == aChannels;
    216 }
    217 
    218 #undef OPUS_LOG
    219 
    220 }  // namespace mozilla