content/media/ogg/OpusParser.cpp

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     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/. */
     7 #include <string.h>
     9 #include "mozilla/DebugOnly.h"
    10 #include "mozilla/Endian.h"
    11 #include <stdint.h>
    13 #include "OpusParser.h"
    15 #include "nsDebug.h"
    16 #include "MediaDecoderReader.h"
    17 #include "VideoUtils.h"
    18 #include <algorithm>
    20 #include "opus/opus.h"
    21 extern "C" {
    22 #include "opus/opus_multistream.h"
    23 }
    25 namespace mozilla {
    27 #ifdef PR_LOGGING
    28 extern PRLogModuleInfo* gMediaDecoderLog;
    29 #define OPUS_LOG(type, msg) PR_LOG(gMediaDecoderLog, type, msg)
    30 #else
    31 #define OPUS_LOG(type, msg)
    32 #endif
    34 OpusParser::OpusParser():
    35   mRate(0),
    36   mNominalRate(0),
    37   mChannels(0),
    38   mPreSkip(0),
    39 #ifdef MOZ_SAMPLE_TYPE_FLOAT32
    40   mGain(1.0f),
    41 #else
    42   mGain_Q16(65536),
    43 #endif
    44   mChannelMapping(0),
    45   mStreams(0),
    46   mCoupledStreams(0)
    47 { }
    49 bool OpusParser::DecodeHeader(unsigned char* aData, size_t aLength)
    50 {
    51     if (aLength < 19 || memcmp(aData, "OpusHead", 8)) {
    52       OPUS_LOG(PR_LOG_DEBUG, ("Invalid Opus file: unrecognized header"));
    53       return false;
    54     }
    56     mRate = 48000; // The Opus decoder runs at 48 kHz regardless.
    58     int version = aData[8];
    59     // Accept file format versions 0.x.
    60     if ((version & 0xf0) != 0) {
    61       OPUS_LOG(PR_LOG_DEBUG, ("Rejecting unknown Opus file version %d", version));
    62       return false;
    63     }
    65     mChannels = aData[9];
    66     if (mChannels<1) {
    67       OPUS_LOG(PR_LOG_DEBUG, ("Invalid Opus file: Number of channels %d", mChannels));
    68       return false;
    69     }
    71     mPreSkip = LittleEndian::readUint16(aData + 10);
    72     mNominalRate = LittleEndian::readUint32(aData + 12);
    73     double gain_dB = LittleEndian::readInt16(aData + 16) / 256.0;
    74 #ifdef MOZ_SAMPLE_TYPE_FLOAT32
    75     mGain = static_cast<float>(pow(10,0.05*gain_dB));
    76 #else
    77     mGain_Q16 = static_cast<int32_t>(std::min(65536*pow(10,0.05*gain_dB)+0.5,
    78                                             static_cast<double>(INT32_MAX)));
    79 #endif
    80     mChannelMapping = aData[18];
    82     if (mChannelMapping == 0) {
    83       // Mapping family 0 only allows two channels
    84       if (mChannels>2) {
    85         OPUS_LOG(PR_LOG_DEBUG, ("Invalid Opus file: too many channels (%d) for"
    86                            " mapping family 0.", mChannels));
    87         return false;
    88       }
    89       mStreams = 1;
    90       mCoupledStreams = mChannels - 1;
    91       mMappingTable[0] = 0;
    92       mMappingTable[1] = 1;
    93     } else if (mChannelMapping == 1) {
    94       // Currently only up to 8 channels are defined for mapping family 1
    95       if (mChannels>8) {
    96         OPUS_LOG(PR_LOG_DEBUG, ("Invalid Opus file: too many channels (%d) for"
    97                            " mapping family 1.", mChannels));
    98         return false;
    99       }
   100       if (aLength>static_cast<unsigned>(20+mChannels)) {
   101         mStreams = aData[19];
   102         mCoupledStreams = aData[20];
   103         int i;
   104         for (i=0; i<mChannels; i++)
   105           mMappingTable[i] = aData[21+i];
   106       } else {
   107         OPUS_LOG(PR_LOG_DEBUG, ("Invalid Opus file: channel mapping %d,"
   108                            " but no channel mapping table", mChannelMapping));
   109         return false;
   110       }
   111     } else {
   112       OPUS_LOG(PR_LOG_DEBUG, ("Invalid Opus file: unsupported channel mapping "
   113                          "family %d", mChannelMapping));
   114       return false;
   115     }
   116     if (mStreams < 1) {
   117       OPUS_LOG(PR_LOG_DEBUG, ("Invalid Opus file: no streams"));
   118       return false;
   119     }
   120     if (mCoupledStreams > mStreams) {
   121       OPUS_LOG(PR_LOG_DEBUG, ("Invalid Opus file: more coupled streams (%d) than "
   122                          "total streams (%d)", mCoupledStreams, mStreams));
   123       return false;
   124     }
   126 #ifdef DEBUG
   127     OPUS_LOG(PR_LOG_DEBUG, ("Opus stream header:"));
   128     OPUS_LOG(PR_LOG_DEBUG, (" channels: %d", mChannels));
   129     OPUS_LOG(PR_LOG_DEBUG, ("  preskip: %d", mPreSkip));
   130     OPUS_LOG(PR_LOG_DEBUG, (" original: %d Hz", mNominalRate));
   131     OPUS_LOG(PR_LOG_DEBUG, ("     gain: %.2f dB", gain_dB));
   132     OPUS_LOG(PR_LOG_DEBUG, ("Channel Mapping:"));
   133     OPUS_LOG(PR_LOG_DEBUG, ("   family: %d", mChannelMapping));
   134     OPUS_LOG(PR_LOG_DEBUG, ("  streams: %d", mStreams));
   135 #endif
   136   return true;
   137 }
   139 bool OpusParser::DecodeTags(unsigned char* aData, size_t aLength)
   140 {
   141   if (aLength < 16 || memcmp(aData, "OpusTags", 8))
   142     return false;
   144   // Copy out the raw comment lines, but only do basic validation
   145   // checks against the string packing: too little data, too many
   146   // comments, or comments that are too long. Rejecting these cases
   147   // helps reduce the propagation of broken files.
   148   // We do not ensure they are valid UTF-8 here, nor do we validate
   149   // the required ASCII_TAG=value format of the user comments.
   150   const unsigned char* buf = aData + 8;
   151   uint32_t bytes = aLength - 8;
   152   uint32_t len;
   153   // Read the vendor string.
   154   len = LittleEndian::readUint32(buf);
   155   buf += 4;
   156   bytes -= 4;
   157   if (len > bytes)
   158     return false;
   159   mVendorString = nsCString(reinterpret_cast<const char*>(buf), len);
   160   buf += len;
   161   bytes -= len;
   162   // Read the user comments.
   163   if (bytes < 4)
   164     return false;
   165   uint32_t ncomments = LittleEndian::readUint32(buf);
   166   buf += 4;
   167   bytes -= 4;
   168   // If there are so many comments even their length fields
   169   // won't fit in the packet, stop reading now.
   170   if (ncomments > (bytes>>2))
   171     return false;
   172   uint32_t i;
   173   for (i = 0; i < ncomments; i++) {
   174     if (bytes < 4)
   175       return false;
   176     len = LittleEndian::readUint32(buf);
   177     buf += 4;
   178     bytes -= 4;
   179     if (len > bytes)
   180       return false;
   181     mTags.AppendElement(nsCString(reinterpret_cast<const char*>(buf), len));
   182     buf += len;
   183     bytes -= len;
   184   }
   186 #ifdef DEBUG
   187   OPUS_LOG(PR_LOG_DEBUG, ("Opus metadata header:"));
   188   OPUS_LOG(PR_LOG_DEBUG, ("  vendor: %s", mVendorString.get()));
   189   for (uint32_t i = 0; i < mTags.Length(); i++) {
   190     OPUS_LOG(PR_LOG_DEBUG, (" %s", mTags[i].get()));
   191   }
   192 #endif
   193   return true;
   194 }
   196 } // namespace mozilla

mercurial