Tue, 06 Jan 2015 21:39:09 +0100
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