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