Fri, 16 Jan 2015 04:50:19 +0100
Replace accessor implementation with direct member state manipulation, by
request https://trac.torproject.org/projects/tor/ticket/9701#comment:32
michael@0 | 1 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 4 | |
michael@0 | 5 | #include "VideoUtils.h" |
michael@0 | 6 | #include "MediaResource.h" |
michael@0 | 7 | #include "mozilla/dom/TimeRanges.h" |
michael@0 | 8 | #include "nsMathUtils.h" |
michael@0 | 9 | #include "nsSize.h" |
michael@0 | 10 | #include "VorbisUtils.h" |
michael@0 | 11 | #include "ImageContainer.h" |
michael@0 | 12 | |
michael@0 | 13 | #include <stdint.h> |
michael@0 | 14 | |
michael@0 | 15 | namespace mozilla { |
michael@0 | 16 | |
michael@0 | 17 | using layers::PlanarYCbCrImage; |
michael@0 | 18 | |
michael@0 | 19 | // Converts from number of audio frames to microseconds, given the specified |
michael@0 | 20 | // audio rate. |
michael@0 | 21 | CheckedInt64 FramesToUsecs(int64_t aFrames, uint32_t aRate) { |
michael@0 | 22 | return (CheckedInt64(aFrames) * USECS_PER_S) / aRate; |
michael@0 | 23 | } |
michael@0 | 24 | |
michael@0 | 25 | // Converts from microseconds to number of audio frames, given the specified |
michael@0 | 26 | // audio rate. |
michael@0 | 27 | CheckedInt64 UsecsToFrames(int64_t aUsecs, uint32_t aRate) { |
michael@0 | 28 | return (CheckedInt64(aUsecs) * aRate) / USECS_PER_S; |
michael@0 | 29 | } |
michael@0 | 30 | |
michael@0 | 31 | nsresult SecondsToUsecs(double aSeconds, int64_t& aOutUsecs) { |
michael@0 | 32 | if (aSeconds * double(USECS_PER_S) > INT64_MAX) { |
michael@0 | 33 | return NS_ERROR_FAILURE; |
michael@0 | 34 | } |
michael@0 | 35 | aOutUsecs = int64_t(aSeconds * double(USECS_PER_S)); |
michael@0 | 36 | return NS_OK; |
michael@0 | 37 | } |
michael@0 | 38 | |
michael@0 | 39 | static int32_t ConditionDimension(float aValue) |
michael@0 | 40 | { |
michael@0 | 41 | // This will exclude NaNs and too-big values. |
michael@0 | 42 | if (aValue > 1.0 && aValue <= INT32_MAX) |
michael@0 | 43 | return int32_t(NS_round(aValue)); |
michael@0 | 44 | return 0; |
michael@0 | 45 | } |
michael@0 | 46 | |
michael@0 | 47 | void ScaleDisplayByAspectRatio(nsIntSize& aDisplay, float aAspectRatio) |
michael@0 | 48 | { |
michael@0 | 49 | if (aAspectRatio > 1.0) { |
michael@0 | 50 | // Increase the intrinsic width |
michael@0 | 51 | aDisplay.width = ConditionDimension(aAspectRatio * aDisplay.width); |
michael@0 | 52 | } else { |
michael@0 | 53 | // Increase the intrinsic height |
michael@0 | 54 | aDisplay.height = ConditionDimension(aDisplay.height / aAspectRatio); |
michael@0 | 55 | } |
michael@0 | 56 | } |
michael@0 | 57 | |
michael@0 | 58 | static int64_t BytesToTime(int64_t offset, int64_t length, int64_t durationUs) { |
michael@0 | 59 | NS_ASSERTION(length > 0, "Must have positive length"); |
michael@0 | 60 | double r = double(offset) / double(length); |
michael@0 | 61 | if (r > 1.0) |
michael@0 | 62 | r = 1.0; |
michael@0 | 63 | return int64_t(double(durationUs) * r); |
michael@0 | 64 | } |
michael@0 | 65 | |
michael@0 | 66 | void GetEstimatedBufferedTimeRanges(mozilla::MediaResource* aStream, |
michael@0 | 67 | int64_t aDurationUsecs, |
michael@0 | 68 | mozilla::dom::TimeRanges* aOutBuffered) |
michael@0 | 69 | { |
michael@0 | 70 | // Nothing to cache if the media takes 0us to play. |
michael@0 | 71 | if (aDurationUsecs <= 0 || !aStream || !aOutBuffered) |
michael@0 | 72 | return; |
michael@0 | 73 | |
michael@0 | 74 | // Special case completely cached files. This also handles local files. |
michael@0 | 75 | if (aStream->IsDataCachedToEndOfResource(0)) { |
michael@0 | 76 | aOutBuffered->Add(0, double(aDurationUsecs) / USECS_PER_S); |
michael@0 | 77 | return; |
michael@0 | 78 | } |
michael@0 | 79 | |
michael@0 | 80 | int64_t totalBytes = aStream->GetLength(); |
michael@0 | 81 | |
michael@0 | 82 | // If we can't determine the total size, pretend that we have nothing |
michael@0 | 83 | // buffered. This will put us in a state of eternally-low-on-undecoded-data |
michael@0 | 84 | // which is not great, but about the best we can do. |
michael@0 | 85 | if (totalBytes <= 0) |
michael@0 | 86 | return; |
michael@0 | 87 | |
michael@0 | 88 | int64_t startOffset = aStream->GetNextCachedData(0); |
michael@0 | 89 | while (startOffset >= 0) { |
michael@0 | 90 | int64_t endOffset = aStream->GetCachedDataEnd(startOffset); |
michael@0 | 91 | // Bytes [startOffset..endOffset] are cached. |
michael@0 | 92 | NS_ASSERTION(startOffset >= 0, "Integer underflow in GetBuffered"); |
michael@0 | 93 | NS_ASSERTION(endOffset >= 0, "Integer underflow in GetBuffered"); |
michael@0 | 94 | |
michael@0 | 95 | int64_t startUs = BytesToTime(startOffset, totalBytes, aDurationUsecs); |
michael@0 | 96 | int64_t endUs = BytesToTime(endOffset, totalBytes, aDurationUsecs); |
michael@0 | 97 | if (startUs != endUs) { |
michael@0 | 98 | aOutBuffered->Add(double(startUs) / USECS_PER_S, |
michael@0 | 99 | double(endUs) / USECS_PER_S); |
michael@0 | 100 | } |
michael@0 | 101 | startOffset = aStream->GetNextCachedData(endOffset); |
michael@0 | 102 | } |
michael@0 | 103 | return; |
michael@0 | 104 | } |
michael@0 | 105 | |
michael@0 | 106 | int DownmixAudioToStereo(mozilla::AudioDataValue* buffer, |
michael@0 | 107 | int channels, uint32_t frames) |
michael@0 | 108 | { |
michael@0 | 109 | int outChannels; |
michael@0 | 110 | outChannels = 2; |
michael@0 | 111 | #ifdef MOZ_SAMPLE_TYPE_FLOAT32 |
michael@0 | 112 | // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8. |
michael@0 | 113 | static const float dmatrix[6][8][2]= { |
michael@0 | 114 | /*3*/{{0.5858f,0},{0.4142f,0.4142f},{0, 0.5858f}}, |
michael@0 | 115 | /*4*/{{0.4226f,0},{0, 0.4226f},{0.366f,0.2114f},{0.2114f,0.366f}}, |
michael@0 | 116 | /*5*/{{0.6510f,0},{0.4600f,0.4600f},{0, 0.6510f},{0.5636f,0.3254f},{0.3254f,0.5636f}}, |
michael@0 | 117 | /*6*/{{0.5290f,0},{0.3741f,0.3741f},{0, 0.5290f},{0.4582f,0.2645f},{0.2645f,0.4582f},{0.3741f,0.3741f}}, |
michael@0 | 118 | /*7*/{{0.4553f,0},{0.3220f,0.3220f},{0, 0.4553f},{0.3943f,0.2277f},{0.2277f,0.3943f},{0.2788f,0.2788f},{0.3220f,0.3220f}}, |
michael@0 | 119 | /*8*/{{0.3886f,0},{0.2748f,0.2748f},{0, 0.3886f},{0.3366f,0.1943f},{0.1943f,0.3366f},{0.3366f,0.1943f},{0.1943f,0.3366f},{0.2748f,0.2748f}}, |
michael@0 | 120 | }; |
michael@0 | 121 | // Re-write the buffer with downmixed data |
michael@0 | 122 | for (uint32_t i = 0; i < frames; i++) { |
michael@0 | 123 | float sampL = 0.0; |
michael@0 | 124 | float sampR = 0.0; |
michael@0 | 125 | for (int j = 0; j < channels; j++) { |
michael@0 | 126 | sampL+=buffer[i*channels+j]*dmatrix[channels-3][j][0]; |
michael@0 | 127 | sampR+=buffer[i*channels+j]*dmatrix[channels-3][j][1]; |
michael@0 | 128 | } |
michael@0 | 129 | buffer[i*outChannels]=sampL; |
michael@0 | 130 | buffer[i*outChannels+1]=sampR; |
michael@0 | 131 | } |
michael@0 | 132 | #else |
michael@0 | 133 | // Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8. |
michael@0 | 134 | // Coefficients in Q14. |
michael@0 | 135 | static const int16_t dmatrix[6][8][2]= { |
michael@0 | 136 | /*3*/{{9598, 0},{6786,6786},{0, 9598}}, |
michael@0 | 137 | /*4*/{{6925, 0},{0, 6925},{5997,3462},{3462,5997}}, |
michael@0 | 138 | /*5*/{{10663,0},{7540,7540},{0, 10663},{9234,5331},{5331,9234}}, |
michael@0 | 139 | /*6*/{{8668, 0},{6129,6129},{0, 8668},{7507,4335},{4335,7507},{6129,6129}}, |
michael@0 | 140 | /*7*/{{7459, 0},{5275,5275},{0, 7459},{6460,3731},{3731,6460},{4568,4568},{5275,5275}}, |
michael@0 | 141 | /*8*/{{6368, 0},{4502,4502},{0, 6368},{5514,3184},{3184,5514},{5514,3184},{3184,5514},{4502,4502}} |
michael@0 | 142 | }; |
michael@0 | 143 | // Re-write the buffer with downmixed data |
michael@0 | 144 | for (uint32_t i = 0; i < frames; i++) { |
michael@0 | 145 | int32_t sampL = 0; |
michael@0 | 146 | int32_t sampR = 0; |
michael@0 | 147 | for (int j = 0; j < channels; j++) { |
michael@0 | 148 | sampL+=buffer[i*channels+j]*dmatrix[channels-3][j][0]; |
michael@0 | 149 | sampR+=buffer[i*channels+j]*dmatrix[channels-3][j][1]; |
michael@0 | 150 | } |
michael@0 | 151 | sampL = (sampL + 8192)>>14; |
michael@0 | 152 | buffer[i*outChannels] = static_cast<mozilla::AudioDataValue>(MOZ_CLIP_TO_15(sampL)); |
michael@0 | 153 | sampR = (sampR + 8192)>>14; |
michael@0 | 154 | buffer[i*outChannels+1] = static_cast<mozilla::AudioDataValue>(MOZ_CLIP_TO_15(sampR)); |
michael@0 | 155 | } |
michael@0 | 156 | #endif |
michael@0 | 157 | return outChannels; |
michael@0 | 158 | } |
michael@0 | 159 | |
michael@0 | 160 | bool |
michael@0 | 161 | IsVideoContentType(const nsCString& aContentType) |
michael@0 | 162 | { |
michael@0 | 163 | NS_NAMED_LITERAL_CSTRING(video, "video"); |
michael@0 | 164 | if (FindInReadable(video, aContentType)) { |
michael@0 | 165 | return true; |
michael@0 | 166 | } |
michael@0 | 167 | return false; |
michael@0 | 168 | } |
michael@0 | 169 | |
michael@0 | 170 | bool |
michael@0 | 171 | IsValidVideoRegion(const nsIntSize& aFrame, const nsIntRect& aPicture, |
michael@0 | 172 | const nsIntSize& aDisplay) |
michael@0 | 173 | { |
michael@0 | 174 | return |
michael@0 | 175 | aFrame.width <= PlanarYCbCrImage::MAX_DIMENSION && |
michael@0 | 176 | aFrame.height <= PlanarYCbCrImage::MAX_DIMENSION && |
michael@0 | 177 | aFrame.width * aFrame.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT && |
michael@0 | 178 | aFrame.width * aFrame.height != 0 && |
michael@0 | 179 | aPicture.width <= PlanarYCbCrImage::MAX_DIMENSION && |
michael@0 | 180 | aPicture.x < PlanarYCbCrImage::MAX_DIMENSION && |
michael@0 | 181 | aPicture.x + aPicture.width < PlanarYCbCrImage::MAX_DIMENSION && |
michael@0 | 182 | aPicture.height <= PlanarYCbCrImage::MAX_DIMENSION && |
michael@0 | 183 | aPicture.y < PlanarYCbCrImage::MAX_DIMENSION && |
michael@0 | 184 | aPicture.y + aPicture.height < PlanarYCbCrImage::MAX_DIMENSION && |
michael@0 | 185 | aPicture.width * aPicture.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT && |
michael@0 | 186 | aPicture.width * aPicture.height != 0 && |
michael@0 | 187 | aDisplay.width <= PlanarYCbCrImage::MAX_DIMENSION && |
michael@0 | 188 | aDisplay.height <= PlanarYCbCrImage::MAX_DIMENSION && |
michael@0 | 189 | aDisplay.width * aDisplay.height <= MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT && |
michael@0 | 190 | aDisplay.width * aDisplay.height != 0; |
michael@0 | 191 | } |
michael@0 | 192 | |
michael@0 | 193 | } // end namespace mozilla |