tor-browser

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

Adts.cpp (10305B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "Adts.h"
      6 
      7 #include "ADTSDemuxer.h"
      8 #include "BitWriter.h"
      9 #include "MediaData.h"
     10 #include "MediaDataDemuxer.h"
     11 #include "PlatformDecoderModule.h"
     12 #include "mozilla/Array.h"
     13 #include "mozilla/Logging.h"
     14 
     15 #define LOG(msg, ...) \
     16  MOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
     17 #define ADTSLOG(msg, ...) \
     18  DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Debug, msg, ##__VA_ARGS__)
     19 #define ADTSLOGV(msg, ...) \
     20  DDMOZ_LOG(gMediaDemuxerLog, LogLevel::Verbose, msg, ##__VA_ARGS__)
     21 
     22 namespace mozilla {
     23 namespace ADTS {
     24 
     25 static const int kADTSHeaderSize = 7;
     26 
     27 constexpr std::array FREQ_LOOKUP{96000, 88200, 64000, 48000, 44100,
     28                                 32000, 24000, 22050, 16000, 12000,
     29                                 11025, 8000,  7350,  0};
     30 
     31 Result<uint8_t, bool> GetFrequencyIndex(uint32_t aSamplesPerSecond) {
     32  auto found =
     33      std::find(FREQ_LOOKUP.begin(), FREQ_LOOKUP.end(), aSamplesPerSecond);
     34 
     35  if (found == FREQ_LOOKUP.end()) {
     36    return Err(false);
     37  }
     38 
     39  return std::distance(FREQ_LOOKUP.begin(), found);
     40 }
     41 
     42 bool ConvertSample(uint16_t aChannelCount, uint8_t aFrequencyIndex,
     43                   uint8_t aProfile, MediaRawData* aSample) {
     44  size_t newSize = aSample->Size() + kADTSHeaderSize;
     45 
     46  MOZ_LOG(sPDMLog, LogLevel::Debug,
     47          ("Converting sample to ADTS format: newSize: %zu, ch: %u, "
     48           "profile: %u, freq index: %d",
     49           newSize, aChannelCount, aProfile, aFrequencyIndex));
     50 
     51  // ADTS header uses 13 bits for packet size.
     52  if (newSize >= (1 << 13) || aChannelCount > 15 || aProfile < 1 ||
     53      aProfile > 4 || aFrequencyIndex >= FREQ_LOOKUP.size()) {
     54    MOZ_LOG(sPDMLog, LogLevel::Debug,
     55            ("Couldn't convert sample to ADTS format: newSize: %zu, ch: %u, "
     56             "profile: %u, freq index: %d",
     57             newSize, aChannelCount, aProfile, aFrequencyIndex));
     58    return false;
     59  }
     60 
     61  Array<uint8_t, kADTSHeaderSize> header;
     62  header[0] = 0xff;
     63  header[1] = 0xf1;
     64  header[2] =
     65      ((aProfile - 1) << 6) + (aFrequencyIndex << 2) + (aChannelCount >> 2);
     66  header[3] = ((aChannelCount & 0x3) << 6) + (newSize >> 11);
     67  header[4] = (newSize & 0x7ff) >> 3;
     68  header[5] = ((newSize & 7) << 5) + 0x1f;
     69  header[6] = 0xfc;
     70 
     71  UniquePtr<MediaRawDataWriter> writer(aSample->CreateWriter());
     72  if (!writer->Prepend(&header[0], std::size(header))) {
     73    return false;
     74  }
     75 
     76  if (aSample->mCrypto.IsEncrypted()) {
     77    if (aSample->mCrypto.mPlainSizes.Length() == 0) {
     78      writer->mCrypto.mPlainSizes.AppendElement(kADTSHeaderSize);
     79      writer->mCrypto.mEncryptedSizes.AppendElement(aSample->Size() -
     80                                                    kADTSHeaderSize);
     81    } else {
     82      writer->mCrypto.mPlainSizes[0] += kADTSHeaderSize;
     83    }
     84  }
     85 
     86  return true;
     87 }
     88 
     89 bool StripHeader(MediaRawData* aSample) {
     90  if (aSample->Size() < kADTSHeaderSize) {
     91    return false;
     92  }
     93 
     94  FrameHeader header;
     95  auto data = Span{aSample->Data(), aSample->Size()};
     96  MOZ_ASSERT(FrameHeader::MatchesSync(data),
     97             "Don't attempt to strip the ADTS header of a raw AAC packet.");
     98 
     99  bool crcPresent = header.mHaveCrc;
    100 
    101  LOG(("Stripping ADTS, crc %spresent", crcPresent ? "" : "not "));
    102 
    103  size_t toStrip = crcPresent ? kADTSHeaderSize + 2 : kADTSHeaderSize;
    104 
    105  UniquePtr<MediaRawDataWriter> writer(aSample->CreateWriter());
    106  writer->PopFront(toStrip);
    107 
    108  if (aSample->mCrypto.IsEncrypted()) {
    109    if (aSample->mCrypto.mPlainSizes.Length() > 0 &&
    110        writer->mCrypto.mPlainSizes[0] >= kADTSHeaderSize) {
    111      writer->mCrypto.mPlainSizes[0] -= kADTSHeaderSize;
    112    }
    113  }
    114 
    115  return true;
    116 }
    117 
    118 bool RevertSample(MediaRawData* aSample) {
    119  if (aSample->Size() < kADTSHeaderSize) {
    120    return false;
    121  }
    122 
    123  {
    124    const uint8_t* header = aSample->Data();
    125    if (header[0] != 0xff || header[1] != 0xf1 || header[6] != 0xfc) {
    126      // Not ADTS.
    127      return false;
    128    }
    129  }
    130 
    131  UniquePtr<MediaRawDataWriter> writer(aSample->CreateWriter());
    132  writer->PopFront(kADTSHeaderSize);
    133 
    134  if (aSample->mCrypto.IsEncrypted()) {
    135    if (aSample->mCrypto.mPlainSizes.Length() > 0 &&
    136        writer->mCrypto.mPlainSizes[0] >= kADTSHeaderSize) {
    137      writer->mCrypto.mPlainSizes[0] -= kADTSHeaderSize;
    138    }
    139  }
    140 
    141  return true;
    142 }
    143 
    144 bool FrameHeader::MatchesSync(const Span<const uint8_t>& aData) {
    145  return aData.Length() >= 2 && aData[0] == 0xFF && (aData[1] & 0xF6) == 0xF0;
    146 }
    147 
    148 FrameHeader::FrameHeader() { Reset(); }
    149 
    150 // Header size
    151 uint64_t FrameHeader::HeaderSize() const { return (mHaveCrc) ? 9 : 7; }
    152 
    153 bool FrameHeader::IsValid() const { return mFrameLength > 0; }
    154 
    155 // Resets the state to allow for a new parsing session.
    156 void FrameHeader::Reset() { PodZero(this); }
    157 
    158 // Returns whether the byte creates a valid sequence up to this point.
    159 bool FrameHeader::Parse(const Span<const uint8_t>& aData) {
    160  if (!MatchesSync(aData)) {
    161    return false;
    162  }
    163 
    164  // AAC has 1024 samples per frame per channel.
    165  mSamples = 1024;
    166 
    167  mHaveCrc = !(aData[1] & 0x01);
    168  mObjectType = ((aData[2] & 0xC0) >> 6) + 1;
    169  mSamplingIndex = (aData[2] & 0x3C) >> 2;
    170  mChannelConfig = (aData[2] & 0x01) << 2 | (aData[3] & 0xC0) >> 6;
    171  mFrameLength =
    172      static_cast<uint32_t>((aData[3] & 0x03) << 11 | (aData[4] & 0xFF) << 3 |
    173                            (aData[5] & 0xE0) >> 5);
    174  mNumAACFrames = (aData[6] & 0x03) + 1;
    175 
    176  static const uint32_t SAMPLE_RATES[] = {96000, 88200, 64000, 48000, 44100,
    177                                          32000, 24000, 22050, 16000, 12000,
    178                                          11025, 8000,  7350};
    179  if (mSamplingIndex >= std::size(SAMPLE_RATES)) {
    180    LOG(("ADTS: Init() failure: invalid sample-rate index value: %" PRIu32 ".",
    181         mSamplingIndex));
    182    // This marks the header as invalid.
    183    mFrameLength = 0;
    184    return false;
    185  }
    186  mSampleRate = SAMPLE_RATES[mSamplingIndex];
    187 
    188  MOZ_ASSERT(mChannelConfig < 8);
    189  mChannels = (mChannelConfig == 7) ? 8 : mChannelConfig;
    190 
    191  return true;
    192 }
    193 
    194 Frame::Frame() : mOffset(0), mHeader() {}
    195 uint64_t Frame::Offset() const { return mOffset; }
    196 size_t Frame::Length() const {
    197  // TODO: If fields are zero'd when invalid, this check wouldn't be
    198  // necessary.
    199  if (!mHeader.IsValid()) {
    200    return 0;
    201  }
    202 
    203  return mHeader.mFrameLength;
    204 }
    205 
    206 // Returns the offset to the start of frame's raw data.
    207 uint64_t Frame::PayloadOffset() const { return mOffset + mHeader.HeaderSize(); }
    208 
    209 // Returns the length of the frame's raw data (excluding the header) in bytes.
    210 size_t Frame::PayloadLength() const {
    211  // TODO: If fields are zero'd when invalid, this check wouldn't be
    212  // necessary.
    213  if (!mHeader.IsValid()) {
    214    return 0;
    215  }
    216 
    217  return mHeader.mFrameLength - mHeader.HeaderSize();
    218 }
    219 
    220 // Returns the parsed frame header.
    221 const FrameHeader& Frame::Header() const { return mHeader; }
    222 
    223 bool Frame::IsValid() const { return mHeader.IsValid(); }
    224 
    225 // Resets the frame header and data.
    226 void Frame::Reset() {
    227  mHeader.Reset();
    228  mOffset = 0;
    229 }
    230 
    231 // Returns whether the valid
    232 bool Frame::Parse(uint64_t aOffset, const uint8_t* aStart,
    233                  const uint8_t* aEnd) {
    234  MOZ_ASSERT(aStart && aEnd && aStart <= aEnd);
    235 
    236  bool found = false;
    237  const uint8_t* ptr = aStart;
    238  // Require at least 7 bytes of data at the end of the buffer for the minimum
    239  // ADTS frame header.
    240  while (ptr < aEnd - 7 && !found) {
    241    found = mHeader.Parse(Span(ptr, aEnd));
    242    ptr++;
    243  }
    244 
    245  mOffset = aOffset + (static_cast<size_t>(ptr - aStart)) - 1u;
    246 
    247  return found;
    248 }
    249 
    250 const Frame& FrameParser::CurrentFrame() { return mFrame; }
    251 
    252 const Frame& FrameParser::FirstFrame() const { return mFirstFrame; }
    253 
    254 void FrameParser::Reset() {
    255  EndFrameSession();
    256  mFirstFrame.Reset();
    257 }
    258 
    259 void FrameParser::EndFrameSession() { mFrame.Reset(); }
    260 
    261 bool FrameParser::Parse(uint64_t aOffset, const uint8_t* aStart,
    262                        const uint8_t* aEnd) {
    263  const bool found = mFrame.Parse(aOffset, aStart, aEnd);
    264 
    265  if (mFrame.Length() && !mFirstFrame.Length()) {
    266    mFirstFrame = mFrame;
    267  }
    268 
    269  return found;
    270 }
    271 
    272 // Initialize the AAC AudioSpecificConfig.
    273 // Only handles two-byte version for AAC-LC.
    274 void InitAudioSpecificConfig(const ADTS::Frame& frame,
    275                             MediaByteBuffer* aBuffer) {
    276  const ADTS::FrameHeader& header = frame.Header();
    277  MOZ_ASSERT(header.IsValid());
    278 
    279  int audioObjectType = header.mObjectType;
    280  int samplingFrequencyIndex = header.mSamplingIndex;
    281  int channelConfig = header.mChannelConfig;
    282 
    283  uint8_t asc[2];
    284  asc[0] = (audioObjectType & 0x1F) << 3 | (samplingFrequencyIndex & 0x0E) >> 1;
    285  asc[1] = (samplingFrequencyIndex & 0x01) << 7 | (channelConfig & 0x0F) << 3;
    286 
    287  aBuffer->AppendElements(asc, 2);
    288 }
    289 
    290 // https://wiki.multimedia.cx/index.php/MPEG-4_Audio#Audio_Specific_Config
    291 Result<already_AddRefed<MediaByteBuffer>, nsresult> MakeSpecificConfig(
    292    uint8_t aObjectType, uint32_t aFrequency, uint32_t aChannelCount) {
    293  if (aObjectType > 45 /* USAC */ || aObjectType == 0x1F /* Escape value */) {
    294    return Err(NS_ERROR_INVALID_ARG);
    295  }
    296 
    297  if (aFrequency > 0x00FFFFFF /* max value of 24 bits */) {
    298    return Err(NS_ERROR_INVALID_ARG);
    299  }
    300 
    301  if (aChannelCount > 8 || aChannelCount == 7) {
    302    return Err(NS_ERROR_INVALID_ARG);
    303  }
    304 
    305  uint8_t index = GetFrequencyIndex(aFrequency)
    306                      .unwrapOr(0x0F /* frequency is written explictly */);
    307  MOZ_ASSERT(index <= 0x0F /* index needs only 4 bits */);
    308 
    309  uint8_t channelConfig =
    310      aChannelCount == 8 ? aChannelCount - 1 : aChannelCount;
    311 
    312  RefPtr<MediaByteBuffer> buffer = new MediaByteBuffer();
    313  BitWriter bw(buffer);
    314 
    315  if (aObjectType < 0x1F /* Escape value */) {
    316    bw.WriteBits(aObjectType, 5);
    317  } else {  // If object type needs more than 5 bits
    318    MOZ_ASSERT(aObjectType >= 32);
    319    bw.WriteBits(0x1F, 5);
    320    // Since aObjectType < 0x3F + 32, it's safe to put it into 6 bits.
    321    bw.WriteBits(aObjectType - 32, 6);
    322  }
    323 
    324  bw.WriteBits(index, 4);
    325  if (index == 0x0F /* frequency is written explictly */) {
    326    bw.WriteBits(aFrequency, 24);
    327  }
    328 
    329  bw.WriteBits(channelConfig, 4);
    330 
    331  // Skip extension configuration for now.
    332 
    333  return buffer.forget();
    334 }
    335 
    336 };  // namespace ADTS
    337 };  // namespace mozilla
    338 
    339 #undef LOG
    340 #undef ADTSLOG
    341 #undef ADTSLOGV