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 /* 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 "gtest/gtest.h"
6 #include <algorithm>
8 #include "mozilla/ArrayUtils.h"
9 #include "VP8TrackEncoder.h"
10 #include "ImageContainer.h"
11 #include "MediaStreamGraph.h"
12 #include "WebMWriter.h" // TODO: it's weird to include muxer header to get the class definition of VP8 METADATA
14 using ::testing::TestWithParam;
15 using ::testing::Values;
17 using namespace mozilla::layers;
18 using namespace mozilla;
20 // A helper object to generate of different YUV planes.
21 class YUVBufferGenerator {
22 public:
23 YUVBufferGenerator() {}
25 void Init(const mozilla::gfx::IntSize &aSize)
26 {
27 mImageSize = aSize;
29 int yPlaneLen = aSize.width * aSize.height;
30 int cbcrPlaneLen = (yPlaneLen + 1) / 2;
31 int frameLen = yPlaneLen + cbcrPlaneLen;
33 // Generate source buffer.
34 mSourceBuffer.SetLength(frameLen);
36 // Fill Y plane.
37 memset(mSourceBuffer.Elements(), 0x10, yPlaneLen);
39 // Fill Cb/Cr planes.
40 memset(mSourceBuffer.Elements() + yPlaneLen, 0x80, cbcrPlaneLen);
41 }
43 mozilla::gfx::IntSize GetSize() const
44 {
45 return mImageSize;
46 }
48 void Generate(nsTArray<nsRefPtr<Image> > &aImages)
49 {
50 aImages.AppendElement(CreateI420Image());
51 aImages.AppendElement(CreateNV12Image());
52 aImages.AppendElement(CreateNV21Image());
53 }
55 private:
56 Image *CreateI420Image()
57 {
58 PlanarYCbCrImage *image = new PlanarYCbCrImage(new BufferRecycleBin());
59 PlanarYCbCrData data;
61 const uint32_t yPlaneSize = mImageSize.width * mImageSize.height;
62 const uint32_t halfWidth = (mImageSize.width + 1) / 2;
63 const uint32_t halfHeight = (mImageSize.height + 1) / 2;
64 const uint32_t uvPlaneSize = halfWidth * halfHeight;
66 // Y plane.
67 uint8_t *y = mSourceBuffer.Elements();
68 data.mYChannel = y;
69 data.mYSize.width = mImageSize.width;
70 data.mYSize.height = mImageSize.height;
71 data.mYStride = mImageSize.width;
72 data.mYSkip = 0;
74 // Cr plane.
75 uint8_t *cr = y + yPlaneSize + uvPlaneSize;
76 data.mCrChannel = cr;
77 data.mCrSkip = 0;
79 // Cb plane
80 uint8_t *cb = y + yPlaneSize;
81 data.mCbChannel = cb;
82 data.mCbSkip = 0;
84 // CrCb plane vectors.
85 data.mCbCrStride = halfWidth;
86 data.mCbCrSize.width = halfWidth;
87 data.mCbCrSize.height = halfHeight;
89 image->SetData(data);
90 return image;
91 }
93 Image *CreateNV12Image()
94 {
95 PlanarYCbCrImage *image = new PlanarYCbCrImage(new BufferRecycleBin());
96 PlanarYCbCrData data;
98 const uint32_t yPlaneSize = mImageSize.width * mImageSize.height;
99 const uint32_t halfWidth = (mImageSize.width + 1) / 2;
100 const uint32_t halfHeight = (mImageSize.height + 1) / 2;
102 // Y plane.
103 uint8_t *y = mSourceBuffer.Elements();
104 data.mYChannel = y;
105 data.mYSize.width = mImageSize.width;
106 data.mYSize.height = mImageSize.height;
107 data.mYStride = mImageSize.width;
108 data.mYSkip = 0;
110 // Cr plane.
111 uint8_t *cr = y + yPlaneSize;
112 data.mCrChannel = cr;
113 data.mCrSkip = 1;
115 // Cb plane
116 uint8_t *cb = y + yPlaneSize + 1;
117 data.mCbChannel = cb;
118 data.mCbSkip = 1;
120 // 4:2:0.
121 data.mCbCrStride = mImageSize.width;
122 data.mCbCrSize.width = halfWidth;
123 data.mCbCrSize.height = halfHeight;
125 image->SetData(data);
126 return image;
127 }
129 Image *CreateNV21Image()
130 {
131 PlanarYCbCrImage *image = new PlanarYCbCrImage(new BufferRecycleBin());
132 PlanarYCbCrData data;
134 const uint32_t yPlaneSize = mImageSize.width * mImageSize.height;
135 const uint32_t halfWidth = (mImageSize.width + 1) / 2;
136 const uint32_t halfHeight = (mImageSize.height + 1) / 2;
138 // Y plane.
139 uint8_t *y = mSourceBuffer.Elements();
140 data.mYChannel = y;
141 data.mYSize.width = mImageSize.width;
142 data.mYSize.height = mImageSize.height;
143 data.mYStride = mImageSize.width;
144 data.mYSkip = 0;
146 // Cr plane.
147 uint8_t *cr = y + yPlaneSize + 1;
148 data.mCrChannel = cr;
149 data.mCrSkip = 1;
151 // Cb plane
152 uint8_t *cb = y + yPlaneSize;
153 data.mCbChannel = cb;
154 data.mCbSkip = 1;
156 // 4:2:0.
157 data.mCbCrStride = mImageSize.width;
158 data.mCbCrSize.width = halfWidth;
159 data.mCbCrSize.height = halfHeight;
161 image->SetData(data);
162 return image;
163 }
165 private:
166 mozilla::gfx::IntSize mImageSize;
167 nsTArray<uint8_t> mSourceBuffer;
168 };
170 struct InitParam {
171 bool mShouldSucceed; // This parameter should cause success or fail result
172 int mWidth; // frame width
173 int mHeight; // frame height
174 mozilla::TrackRate mTrackRate; // track rate. 90K is the most commond track rate.
175 };
177 class TestVP8TrackEncoder: public VP8TrackEncoder
178 {
179 public:
180 ::testing::AssertionResult TestInit(const InitParam &aParam)
181 {
182 nsresult result = Init(aParam.mWidth, aParam.mHeight, aParam.mWidth, aParam.mHeight, aParam.mTrackRate);
184 if (((NS_FAILED(result) && aParam.mShouldSucceed)) || (NS_SUCCEEDED(result) && !aParam.mShouldSucceed))
185 {
186 return ::testing::AssertionFailure()
187 << " width = " << aParam.mWidth
188 << " height = " << aParam.mHeight
189 << " TrackRate = " << aParam.mTrackRate << ".";
190 }
191 else
192 {
193 return ::testing::AssertionSuccess();
194 }
195 }
196 };
198 // Init test
199 TEST(VP8VideoTrackEncoder, Initialization)
200 {
201 InitParam params[] = {
202 // Failure cases.
203 { false, 640, 480, 0 }, // Trackrate should be larger than 1.
204 { false, 640, 480, -1 }, // Trackrate should be larger than 1.
205 { false, 0, 0, 90000 }, // Height/ width should be larger than 1.
206 { false, 0, 1, 90000 }, // Height/ width should be larger than 1.
207 { false, 1, 0, 90000}, // Height/ width should be larger than 1.
209 // Success cases
210 { true, 640, 480, 90000}, // Standard VGA
211 { true, 800, 480, 90000}, // Standard WVGA
212 { true, 960, 540, 90000}, // Standard qHD
213 { true, 1280, 720, 90000} // Standard HD
214 };
216 for (size_t i = 0; i < ArrayLength(params); i++)
217 {
218 TestVP8TrackEncoder encoder;
219 EXPECT_TRUE(encoder.TestInit(params[i]));
220 }
221 }
223 // Get MetaData test
224 TEST(VP8VideoTrackEncoder, FetchMetaData)
225 {
226 InitParam params[] = {
227 // Success cases
228 { true, 640, 480, 90000}, // Standard VGA
229 { true, 800, 480, 90000}, // Standard WVGA
230 { true, 960, 540, 90000}, // Standard qHD
231 { true, 1280, 720, 90000} // Standard HD
232 };
234 for (size_t i = 0; i < ArrayLength(params); i++)
235 {
236 TestVP8TrackEncoder encoder;
237 EXPECT_TRUE(encoder.TestInit(params[i]));
239 nsRefPtr<TrackMetadataBase> meta = encoder.GetMetadata();
240 nsRefPtr<VP8Metadata> vp8Meta(static_cast<VP8Metadata*>(meta.get()));
242 // METADATA should be depend on how to initiate encoder.
243 EXPECT_TRUE(vp8Meta->mWidth == params[i].mWidth);
244 EXPECT_TRUE(vp8Meta->mHeight == params[i].mHeight);
245 }
246 }
248 // Encode test
249 // XXX(bug 1018402): Disable this test when compiled with VS2013 because it
250 // crashes.
251 #if !defined(_MSC_VER) || _MSC_VER < 1800
252 TEST(VP8VideoTrackEncoder, FrameEncode)
253 {
254 // Initiate VP8 encoder
255 TestVP8TrackEncoder encoder;
256 InitParam param = {true, 640, 480, 90000};
257 encoder.TestInit(param);
259 // Create YUV images as source.
260 nsTArray<nsRefPtr<Image>> images;
261 YUVBufferGenerator generator;
262 generator.Init(mozilla::gfx::IntSize(640, 480));
263 generator.Generate(images);
265 // Put generated YUV frame into video segment.
266 // Duration of each frame is 1 second.
267 VideoSegment segment;
268 for (nsTArray<nsRefPtr<Image>>::size_type i = 0; i < images.Length(); i++)
269 {
270 nsRefPtr<Image> image = images[i];
271 segment.AppendFrame(image.forget(), mozilla::TrackTicks(90000), generator.GetSize());
272 }
274 // track change notification.
275 encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, 0, 0, segment);
277 // Pull Encoded Data back from encoder.
278 EncodedFrameContainer container;
279 EXPECT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
280 }
281 #endif // _MSC_VER
283 // EOS test
284 TEST(VP8VideoTrackEncoder, EncodeComplete)
285 {
286 // Initiate VP8 encoder
287 TestVP8TrackEncoder encoder;
288 InitParam param = {true, 640, 480, 90000};
289 encoder.TestInit(param);
291 // track end notification.
292 VideoSegment segment;
293 encoder.NotifyQueuedTrackChanges(nullptr, 0, 0, 0, MediaStreamListener::TRACK_EVENT_ENDED, segment);
295 // Pull Encoded Data back from encoder. Since we have sent
296 // EOS to encoder, encoder.GetEncodedTrack should return
297 // NS_OK immidiately.
298 EncodedFrameContainer container;
299 EXPECT_TRUE(NS_SUCCEEDED(encoder.GetEncodedTrack(container)));
300 }