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.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
michael@0 | 4 | * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "AudioChannelFormat.h" |
michael@0 | 7 | #include "nsTArray.h" |
michael@0 | 8 | |
michael@0 | 9 | #include <algorithm> |
michael@0 | 10 | |
michael@0 | 11 | namespace mozilla { |
michael@0 | 12 | |
michael@0 | 13 | enum { |
michael@0 | 14 | SURROUND_L, |
michael@0 | 15 | SURROUND_R, |
michael@0 | 16 | SURROUND_C, |
michael@0 | 17 | SURROUND_LFE, |
michael@0 | 18 | SURROUND_SL, |
michael@0 | 19 | SURROUND_SR |
michael@0 | 20 | }; |
michael@0 | 21 | |
michael@0 | 22 | static const uint32_t CUSTOM_CHANNEL_LAYOUTS = 6; |
michael@0 | 23 | |
michael@0 | 24 | static const int IGNORE = CUSTOM_CHANNEL_LAYOUTS; |
michael@0 | 25 | static const float IGNORE_F = 0.0f; |
michael@0 | 26 | |
michael@0 | 27 | uint32_t |
michael@0 | 28 | GetAudioChannelsSuperset(uint32_t aChannels1, uint32_t aChannels2) |
michael@0 | 29 | { |
michael@0 | 30 | return std::max(aChannels1, aChannels2); |
michael@0 | 31 | } |
michael@0 | 32 | |
michael@0 | 33 | /** |
michael@0 | 34 | * UpMixMatrix represents a conversion matrix by exploiting the fact that |
michael@0 | 35 | * each output channel comes from at most one input channel. |
michael@0 | 36 | */ |
michael@0 | 37 | struct UpMixMatrix { |
michael@0 | 38 | uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS]; |
michael@0 | 39 | }; |
michael@0 | 40 | |
michael@0 | 41 | static const UpMixMatrix |
michael@0 | 42 | gUpMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] = |
michael@0 | 43 | { |
michael@0 | 44 | // Upmixes from mono |
michael@0 | 45 | { { 0, 0 } }, |
michael@0 | 46 | { { 0, IGNORE, IGNORE } }, |
michael@0 | 47 | { { 0, 0, IGNORE, IGNORE } }, |
michael@0 | 48 | { { 0, IGNORE, IGNORE, IGNORE, IGNORE } }, |
michael@0 | 49 | { { IGNORE, IGNORE, 0, IGNORE, IGNORE, IGNORE } }, |
michael@0 | 50 | // Upmixes from stereo |
michael@0 | 51 | { { 0, 1, IGNORE } }, |
michael@0 | 52 | { { 0, 1, IGNORE, IGNORE } }, |
michael@0 | 53 | { { 0, 1, IGNORE, IGNORE, IGNORE } }, |
michael@0 | 54 | { { 0, 1, IGNORE, IGNORE, IGNORE, IGNORE } }, |
michael@0 | 55 | // Upmixes from 3-channel |
michael@0 | 56 | { { 0, 1, 2, IGNORE } }, |
michael@0 | 57 | { { 0, 1, 2, IGNORE, IGNORE } }, |
michael@0 | 58 | { { 0, 1, 2, IGNORE, IGNORE, IGNORE } }, |
michael@0 | 59 | // Upmixes from quad |
michael@0 | 60 | { { 0, 1, 2, 3, IGNORE } }, |
michael@0 | 61 | { { 0, 1, IGNORE, IGNORE, 2, 3 } }, |
michael@0 | 62 | // Upmixes from 5-channel |
michael@0 | 63 | { { 0, 1, 2, 3, 4, IGNORE } } |
michael@0 | 64 | }; |
michael@0 | 65 | |
michael@0 | 66 | static const int gMixingMatrixIndexByChannels[CUSTOM_CHANNEL_LAYOUTS - 1] = |
michael@0 | 67 | { 0, 5, 9, 12, 14 }; |
michael@0 | 68 | |
michael@0 | 69 | void |
michael@0 | 70 | AudioChannelsUpMix(nsTArray<const void*>* aChannelArray, |
michael@0 | 71 | uint32_t aOutputChannelCount, |
michael@0 | 72 | const void* aZeroChannel) |
michael@0 | 73 | { |
michael@0 | 74 | uint32_t inputChannelCount = aChannelArray->Length(); |
michael@0 | 75 | uint32_t outputChannelCount = |
michael@0 | 76 | GetAudioChannelsSuperset(aOutputChannelCount, inputChannelCount); |
michael@0 | 77 | NS_ASSERTION(outputChannelCount > inputChannelCount, |
michael@0 | 78 | "No up-mix needed"); |
michael@0 | 79 | NS_ASSERTION(inputChannelCount > 0, "Bad number of channels"); |
michael@0 | 80 | NS_ASSERTION(outputChannelCount > 0, "Bad number of channels"); |
michael@0 | 81 | |
michael@0 | 82 | aChannelArray->SetLength(outputChannelCount); |
michael@0 | 83 | |
michael@0 | 84 | if (inputChannelCount < CUSTOM_CHANNEL_LAYOUTS && |
michael@0 | 85 | outputChannelCount <= CUSTOM_CHANNEL_LAYOUTS) { |
michael@0 | 86 | const UpMixMatrix& m = gUpMixMatrices[ |
michael@0 | 87 | gMixingMatrixIndexByChannels[inputChannelCount - 1] + |
michael@0 | 88 | outputChannelCount - inputChannelCount - 1]; |
michael@0 | 89 | |
michael@0 | 90 | const void* outputChannels[CUSTOM_CHANNEL_LAYOUTS]; |
michael@0 | 91 | |
michael@0 | 92 | for (uint32_t i = 0; i < outputChannelCount; ++i) { |
michael@0 | 93 | uint8_t channelIndex = m.mInputDestination[i]; |
michael@0 | 94 | if (channelIndex == IGNORE) { |
michael@0 | 95 | outputChannels[i] = aZeroChannel; |
michael@0 | 96 | } else { |
michael@0 | 97 | outputChannels[i] = aChannelArray->ElementAt(channelIndex); |
michael@0 | 98 | } |
michael@0 | 99 | } |
michael@0 | 100 | for (uint32_t i = 0; i < outputChannelCount; ++i) { |
michael@0 | 101 | aChannelArray->ElementAt(i) = outputChannels[i]; |
michael@0 | 102 | } |
michael@0 | 103 | return; |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | for (uint32_t i = inputChannelCount; i < outputChannelCount; ++i) { |
michael@0 | 107 | aChannelArray->ElementAt(i) = aZeroChannel; |
michael@0 | 108 | } |
michael@0 | 109 | } |
michael@0 | 110 | |
michael@0 | 111 | /** |
michael@0 | 112 | * DownMixMatrix represents a conversion matrix efficiently by exploiting the |
michael@0 | 113 | * fact that each input channel contributes to at most one output channel, |
michael@0 | 114 | * except possibly for the C input channel in layouts that have one. Also, |
michael@0 | 115 | * every input channel is multiplied by the same coefficient for every output |
michael@0 | 116 | * channel it contributes to. |
michael@0 | 117 | */ |
michael@0 | 118 | struct DownMixMatrix { |
michael@0 | 119 | // Every input channel c is copied to output channel mInputDestination[c] |
michael@0 | 120 | // after multiplying by mInputCoefficient[c]. |
michael@0 | 121 | uint8_t mInputDestination[CUSTOM_CHANNEL_LAYOUTS]; |
michael@0 | 122 | // If not IGNORE, then the C channel is copied to this output channel after |
michael@0 | 123 | // multiplying by its coefficient. |
michael@0 | 124 | uint8_t mCExtraDestination; |
michael@0 | 125 | float mInputCoefficient[CUSTOM_CHANNEL_LAYOUTS]; |
michael@0 | 126 | }; |
michael@0 | 127 | |
michael@0 | 128 | static const DownMixMatrix |
michael@0 | 129 | gDownMixMatrices[CUSTOM_CHANNEL_LAYOUTS*(CUSTOM_CHANNEL_LAYOUTS - 1)/2] = |
michael@0 | 130 | { |
michael@0 | 131 | // Downmixes to mono |
michael@0 | 132 | { { 0, 0 }, IGNORE, { 0.5f, 0.5f } }, |
michael@0 | 133 | { { 0, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F } }, |
michael@0 | 134 | { { 0, 0, 0, 0 }, IGNORE, { 0.25f, 0.25f, 0.25f, 0.25f } }, |
michael@0 | 135 | { { 0, IGNORE, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, IGNORE_F, IGNORE_F, IGNORE_F, IGNORE_F } }, |
michael@0 | 136 | { { 0, 0, 0, IGNORE, 0, 0 }, IGNORE, { 0.7071f, 0.7071f, 1.0f, IGNORE_F, 0.5f, 0.5f } }, |
michael@0 | 137 | // Downmixes to stereo |
michael@0 | 138 | { { 0, 1, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F } }, |
michael@0 | 139 | { { 0, 1, 0, 1 }, IGNORE, { 0.5f, 0.5f, 0.5f, 0.5f } }, |
michael@0 | 140 | { { 0, 1, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } }, |
michael@0 | 141 | { { 0, 1, 0, IGNORE, 0, 1 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 0.7071f, 0.7071f } }, |
michael@0 | 142 | // Downmixes to 3-channel |
michael@0 | 143 | { { 0, 1, 2, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F } }, |
michael@0 | 144 | { { 0, 1, 2, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F } }, |
michael@0 | 145 | { { 0, 1, 2, IGNORE, IGNORE, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, IGNORE_F, IGNORE_F, IGNORE_F } }, |
michael@0 | 146 | // Downmixes to quad |
michael@0 | 147 | { { 0, 1, 2, 3, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } }, |
michael@0 | 148 | { { 0, 1, 0, IGNORE, 2, 3 }, 1, { 1.0f, 1.0f, 0.7071f, IGNORE_F, 1.0f, 1.0f } }, |
michael@0 | 149 | // Downmixes to 5-channel |
michael@0 | 150 | { { 0, 1, 2, 3, 4, IGNORE }, IGNORE, { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, IGNORE_F } } |
michael@0 | 151 | }; |
michael@0 | 152 | |
michael@0 | 153 | void |
michael@0 | 154 | AudioChannelsDownMix(const nsTArray<const void*>& aChannelArray, |
michael@0 | 155 | float** aOutputChannels, |
michael@0 | 156 | uint32_t aOutputChannelCount, |
michael@0 | 157 | uint32_t aDuration) |
michael@0 | 158 | { |
michael@0 | 159 | uint32_t inputChannelCount = aChannelArray.Length(); |
michael@0 | 160 | const void* const* inputChannels = aChannelArray.Elements(); |
michael@0 | 161 | NS_ASSERTION(inputChannelCount > aOutputChannelCount, "Nothing to do"); |
michael@0 | 162 | |
michael@0 | 163 | if (inputChannelCount > 6) { |
michael@0 | 164 | // Just drop the unknown channels. |
michael@0 | 165 | for (uint32_t o = 0; o < aOutputChannelCount; ++o) { |
michael@0 | 166 | memcpy(aOutputChannels[o], inputChannels[o], aDuration*sizeof(float)); |
michael@0 | 167 | } |
michael@0 | 168 | return; |
michael@0 | 169 | } |
michael@0 | 170 | |
michael@0 | 171 | // Ignore unknown channels, they're just dropped. |
michael@0 | 172 | inputChannelCount = std::min<uint32_t>(6, inputChannelCount); |
michael@0 | 173 | |
michael@0 | 174 | const DownMixMatrix& m = gDownMixMatrices[ |
michael@0 | 175 | gMixingMatrixIndexByChannels[aOutputChannelCount - 1] + |
michael@0 | 176 | inputChannelCount - aOutputChannelCount - 1]; |
michael@0 | 177 | |
michael@0 | 178 | // This is slow, but general. We can define custom code for special |
michael@0 | 179 | // cases later. |
michael@0 | 180 | for (uint32_t s = 0; s < aDuration; ++s) { |
michael@0 | 181 | // Reserve an extra junk channel at the end for the cases where we |
michael@0 | 182 | // want an input channel to contribute to nothing |
michael@0 | 183 | float outputChannels[CUSTOM_CHANNEL_LAYOUTS + 1]; |
michael@0 | 184 | memset(outputChannels, 0, sizeof(float)*(CUSTOM_CHANNEL_LAYOUTS)); |
michael@0 | 185 | for (uint32_t c = 0; c < inputChannelCount; ++c) { |
michael@0 | 186 | outputChannels[m.mInputDestination[c]] += |
michael@0 | 187 | m.mInputCoefficient[c]*(static_cast<const float*>(inputChannels[c]))[s]; |
michael@0 | 188 | } |
michael@0 | 189 | // Utilize the fact that in every layout, C is the third channel. |
michael@0 | 190 | if (m.mCExtraDestination != IGNORE) { |
michael@0 | 191 | outputChannels[m.mCExtraDestination] += |
michael@0 | 192 | m.mInputCoefficient[SURROUND_C]*(static_cast<const float*>(inputChannels[SURROUND_C]))[s]; |
michael@0 | 193 | } |
michael@0 | 194 | |
michael@0 | 195 | for (uint32_t c = 0; c < aOutputChannelCount; ++c) { |
michael@0 | 196 | aOutputChannels[c][s] = outputChannels[c]; |
michael@0 | 197 | } |
michael@0 | 198 | } |
michael@0 | 199 | } |
michael@0 | 200 | |
michael@0 | 201 | } |