LCOV - code coverage report
Current view: top level - dom/media/ogg - OpusParser.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 94 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 3 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13