Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(268)

Side by Side Diff: media/capture/video/fake_video_capture_device_unittest.cc

Issue 2805863002: Remove VideoCaptureDeviceFactory::EnumerateDeviceDescriptors() (Closed)
Patch Set: Rebase Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | media/capture/video/video_capture_device_descriptor.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/capture/video/fake_video_capture_device.h" 5 #include "media/capture/video/fake_video_capture_device.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <memory> 10 #include <memory>
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
147 media::VideoPixelStorage storage, 147 media::VideoPixelStorage storage,
148 int frame_feedback_id) override { 148 int frame_feedback_id) override {
149 return Buffer(); 149 return Buffer();
150 } 150 }
151 double GetBufferPoolUtilization() const override { return 0.0; } 151 double GetBufferPoolUtilization() const override { return 0.0; }
152 152
153 private: 153 private:
154 base::Callback<void(const VideoCaptureFormat&)> frame_cb_; 154 base::Callback<void(const VideoCaptureFormat&)> frame_cb_;
155 }; 155 };
156 156
157 class DeviceEnumerationListener
158 : public base::RefCounted<DeviceEnumerationListener> {
159 public:
160 MOCK_METHOD1(OnEnumeratedDevicesCallbackPtr,
161 void(VideoCaptureDeviceDescriptors* descriptors));
162 // GMock doesn't support move-only arguments, so we use this forward method.
163 void OnEnumeratedDevicesCallback(
164 std::unique_ptr<VideoCaptureDeviceDescriptors> descriptors) {
165 OnEnumeratedDevicesCallbackPtr(descriptors.release());
166 }
167
168 private:
169 friend class base::RefCounted<DeviceEnumerationListener>;
170 virtual ~DeviceEnumerationListener() {}
171 };
172
173 class ImageCaptureClient : public base::RefCounted<ImageCaptureClient> { 157 class ImageCaptureClient : public base::RefCounted<ImageCaptureClient> {
174 public: 158 public:
175 // GMock doesn't support move-only arguments, so we use this forward method. 159 // GMock doesn't support move-only arguments, so we use this forward method.
176 void DoOnGetPhotoCapabilities(mojom::PhotoCapabilitiesPtr capabilities) { 160 void DoOnGetPhotoCapabilities(mojom::PhotoCapabilitiesPtr capabilities) {
177 capabilities_ = std::move(capabilities); 161 capabilities_ = std::move(capabilities);
178 OnCorrectGetPhotoCapabilities(); 162 OnCorrectGetPhotoCapabilities();
179 } 163 }
180 MOCK_METHOD0(OnCorrectGetPhotoCapabilities, void(void)); 164 MOCK_METHOD0(OnCorrectGetPhotoCapabilities, void(void));
181 MOCK_METHOD1(OnGetPhotoCapabilitiesFailure, 165 MOCK_METHOD1(OnGetPhotoCapabilitiesFailure,
182 void(const base::Callback<void(mojom::PhotoCapabilitiesPtr)>&)); 166 void(const base::Callback<void(mojom::PhotoCapabilitiesPtr)>&));
(...skipping 26 matching lines...) Expand all
209 193
210 mojom::PhotoCapabilitiesPtr capabilities_; 194 mojom::PhotoCapabilitiesPtr capabilities_;
211 }; 195 };
212 196
213 } // namespace 197 } // namespace
214 198
215 class FakeVideoCaptureDeviceBase : public ::testing::Test { 199 class FakeVideoCaptureDeviceBase : public ::testing::Test {
216 protected: 200 protected:
217 FakeVideoCaptureDeviceBase() 201 FakeVideoCaptureDeviceBase()
218 : loop_(new base::MessageLoop()), 202 : loop_(new base::MessageLoop()),
203 descriptors_(new VideoCaptureDeviceDescriptors()),
219 client_(CreateClient()), 204 client_(CreateClient()),
220 device_enumeration_listener_(new DeviceEnumerationListener()),
221 image_capture_client_(new ImageCaptureClient()), 205 image_capture_client_(new ImageCaptureClient()),
222 video_capture_device_factory_(new FakeVideoCaptureDeviceFactory()) {} 206 video_capture_device_factory_(new FakeVideoCaptureDeviceFactory()) {}
223 207
224 void SetUp() override { EXPECT_CALL(*client_, OnError(_, _)).Times(0); } 208 void SetUp() override { EXPECT_CALL(*client_, OnError(_, _)).Times(0); }
225 209
226 std::unique_ptr<MockClient> CreateClient() { 210 std::unique_ptr<MockClient> CreateClient() {
227 return std::unique_ptr<MockClient>(new MockClient(base::Bind( 211 return std::unique_ptr<MockClient>(new MockClient(base::Bind(
228 &FakeVideoCaptureDeviceBase::OnFrameCaptured, base::Unretained(this)))); 212 &FakeVideoCaptureDeviceBase::OnFrameCaptured, base::Unretained(this))));
229 } 213 }
230 214
231 void OnFrameCaptured(const VideoCaptureFormat& format) { 215 void OnFrameCaptured(const VideoCaptureFormat& format) {
232 last_format_ = format; 216 last_format_ = format;
233 run_loop_->QuitClosure().Run(); 217 run_loop_->QuitClosure().Run();
234 } 218 }
235 219
236 void WaitForCapturedFrame() { 220 void WaitForCapturedFrame() {
237 run_loop_.reset(new base::RunLoop()); 221 run_loop_.reset(new base::RunLoop());
238 run_loop_->Run(); 222 run_loop_->Run();
239 } 223 }
240 224
241 std::unique_ptr<VideoCaptureDeviceDescriptors> EnumerateDevices() {
242 VideoCaptureDeviceDescriptors* descriptors;
243 EXPECT_CALL(*device_enumeration_listener_.get(),
244 OnEnumeratedDevicesCallbackPtr(_))
245 .WillOnce(SaveArg<0>(&descriptors));
246
247 video_capture_device_factory_->EnumerateDeviceDescriptors(
248 base::Bind(&DeviceEnumerationListener::OnEnumeratedDevicesCallback,
249 device_enumeration_listener_));
250 base::RunLoop().RunUntilIdle();
251 return std::unique_ptr<VideoCaptureDeviceDescriptors>(descriptors);
252 }
253
254 const VideoCaptureFormat& last_format() const { return last_format_; } 225 const VideoCaptureFormat& last_format() const { return last_format_; }
255 226
256 VideoCaptureDeviceDescriptors descriptors_;
257 const std::unique_ptr<base::MessageLoop> loop_; 227 const std::unique_ptr<base::MessageLoop> loop_;
228 std::unique_ptr<VideoCaptureDeviceDescriptors> descriptors_;
258 std::unique_ptr<base::RunLoop> run_loop_; 229 std::unique_ptr<base::RunLoop> run_loop_;
259 std::unique_ptr<MockClient> client_; 230 std::unique_ptr<MockClient> client_;
260 const scoped_refptr<DeviceEnumerationListener> device_enumeration_listener_;
261 const scoped_refptr<ImageCaptureClient> image_capture_client_; 231 const scoped_refptr<ImageCaptureClient> image_capture_client_;
262 VideoCaptureFormat last_format_; 232 VideoCaptureFormat last_format_;
263 const std::unique_ptr<FakeVideoCaptureDeviceFactory> 233 const std::unique_ptr<FakeVideoCaptureDeviceFactory>
264 video_capture_device_factory_; 234 video_capture_device_factory_;
265 }; 235 };
266 236
267 class FakeVideoCaptureDeviceTest 237 class FakeVideoCaptureDeviceTest
268 : public FakeVideoCaptureDeviceBase, 238 : public FakeVideoCaptureDeviceBase,
269 public ::testing::WithParamInterface< 239 public ::testing::WithParamInterface<
270 ::testing::tuple<VideoPixelFormat, 240 ::testing::tuple<VideoPixelFormat,
271 FakeVideoCaptureDevice::DeliveryMode, 241 FakeVideoCaptureDevice::DeliveryMode,
272 float>> {}; 242 float>> {};
273 243
274 // Tests that a frame is delivered with the expected settings. 244 // Tests that a frame is delivered with the expected settings.
275 // Sweeps through a fixed set of requested/expected resolutions. 245 // Sweeps through a fixed set of requested/expected resolutions.
276 TEST_P(FakeVideoCaptureDeviceTest, CaptureUsing) { 246 TEST_P(FakeVideoCaptureDeviceTest, CaptureUsing) {
277 if (testing::get<1>(GetParam()) == 247 if (testing::get<1>(GetParam()) ==
278 FakeVideoCaptureDevice::DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS && 248 FakeVideoCaptureDevice::DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS &&
279 testing::get<0>(GetParam()) == media::PIXEL_FORMAT_MJPEG) { 249 testing::get<0>(GetParam()) == media::PIXEL_FORMAT_MJPEG) {
280 // Unsupported case 250 // Unsupported case
281 return; 251 return;
282 } 252 }
283 253
284 const std::unique_ptr<VideoCaptureDeviceDescriptors> descriptors( 254 video_capture_device_factory_->GetDeviceDescriptors(descriptors_.get());
285 EnumerateDevices()); 255 ASSERT_FALSE(descriptors_->empty());
286 ASSERT_FALSE(descriptors->empty());
287 256
288 std::unique_ptr<VideoCaptureDevice> device = 257 std::unique_ptr<VideoCaptureDevice> device =
289 FakeVideoCaptureDeviceFactory::CreateDeviceWithDefaultResolutions( 258 FakeVideoCaptureDeviceFactory::CreateDeviceWithDefaultResolutions(
290 testing::get<0>(GetParam()), testing::get<1>(GetParam()), 259 testing::get<0>(GetParam()), testing::get<1>(GetParam()),
291 testing::get<2>(GetParam())); 260 testing::get<2>(GetParam()));
292 ASSERT_TRUE(device); 261 ASSERT_TRUE(device);
293 262
294 // First: Requested, Second: Expected 263 // First: Requested, Second: Expected
295 std::vector<std::pair<gfx::Size, gfx::Size>> resolutions_to_test; 264 std::vector<std::pair<gfx::Size, gfx::Size>> resolutions_to_test;
296 resolutions_to_test.emplace_back(gfx::Size(640, 480), gfx::Size(640, 480)); 265 resolutions_to_test.emplace_back(gfx::Size(640, 480), gfx::Size(640, 480));
(...skipping 27 matching lines...) Expand all
324 FakeVideoCaptureDeviceTest, 293 FakeVideoCaptureDeviceTest,
325 Combine( 294 Combine(
326 Values(PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16, PIXEL_FORMAT_MJPEG), 295 Values(PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16, PIXEL_FORMAT_MJPEG),
327 Values( 296 Values(
328 FakeVideoCaptureDevice::DeliveryMode::USE_DEVICE_INTERNAL_BUFFERS, 297 FakeVideoCaptureDevice::DeliveryMode::USE_DEVICE_INTERNAL_BUFFERS,
329 FakeVideoCaptureDevice::DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS), 298 FakeVideoCaptureDevice::DeliveryMode::USE_CLIENT_PROVIDED_BUFFERS),
330 Values(20, 29.97, 30, 50, 60))); 299 Values(20, 29.97, 30, 50, 60)));
331 300
332 TEST_F(FakeVideoCaptureDeviceTest, GetDeviceSupportedFormats) { 301 TEST_F(FakeVideoCaptureDeviceTest, GetDeviceSupportedFormats) {
333 video_capture_device_factory_->SetToDefaultDevicesConfig(4); 302 video_capture_device_factory_->SetToDefaultDevicesConfig(4);
334 std::unique_ptr<VideoCaptureDeviceDescriptors> descriptors( 303 video_capture_device_factory_->GetDeviceDescriptors(descriptors_.get());
335 EnumerateDevices()); 304 ASSERT_EQ(4u, descriptors_->size());
336 ASSERT_EQ(4u, descriptors->size());
337 const VideoPixelFormat expected_format_by_device_index[] = { 305 const VideoPixelFormat expected_format_by_device_index[] = {
338 PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16, PIXEL_FORMAT_MJPEG, 306 PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16, PIXEL_FORMAT_MJPEG,
339 PIXEL_FORMAT_I420}; 307 PIXEL_FORMAT_I420};
340 308
341 int device_index = 0; 309 int device_index = 0;
342 for (const auto& descriptors_iterator : *descriptors) { 310 for (const auto& descriptors_iterator : *descriptors_) {
343 VideoCaptureFormats supported_formats; 311 VideoCaptureFormats supported_formats;
344 video_capture_device_factory_->GetSupportedFormats(descriptors_iterator, 312 video_capture_device_factory_->GetSupportedFormats(descriptors_iterator,
345 &supported_formats); 313 &supported_formats);
346 ASSERT_EQ(5u, supported_formats.size()); 314 ASSERT_EQ(5u, supported_formats.size());
347 VideoPixelFormat expected_format = 315 VideoPixelFormat expected_format =
348 expected_format_by_device_index[device_index]; 316 expected_format_by_device_index[device_index];
349 EXPECT_EQ(96, supported_formats[0].frame_size.width()); 317 EXPECT_EQ(96, supported_formats[0].frame_size.width());
350 EXPECT_EQ(96, supported_formats[0].frame_size.height()); 318 EXPECT_EQ(96, supported_formats[0].frame_size.height());
351 EXPECT_EQ(expected_format, supported_formats[0].pixel_format); 319 EXPECT_EQ(expected_format, supported_formats[0].pixel_format);
352 EXPECT_GE(supported_formats[0].frame_rate, 20.0); 320 EXPECT_GE(supported_formats[0].frame_rate, 20.0);
(...skipping 13 matching lines...) Expand all
366 EXPECT_EQ(1080, supported_formats[4].frame_size.height()); 334 EXPECT_EQ(1080, supported_formats[4].frame_size.height());
367 EXPECT_EQ(expected_format, supported_formats[4].pixel_format); 335 EXPECT_EQ(expected_format, supported_formats[4].pixel_format);
368 EXPECT_GE(supported_formats[4].frame_rate, 20.0); 336 EXPECT_GE(supported_formats[4].frame_rate, 20.0);
369 device_index++; 337 device_index++;
370 } 338 }
371 } 339 }
372 340
373 TEST_F(FakeVideoCaptureDeviceTest, GetCameraCalibration) { 341 TEST_F(FakeVideoCaptureDeviceTest, GetCameraCalibration) {
374 const size_t device_count = 2; 342 const size_t device_count = 2;
375 video_capture_device_factory_->SetToDefaultDevicesConfig(device_count); 343 video_capture_device_factory_->SetToDefaultDevicesConfig(device_count);
376 std::unique_ptr<VideoCaptureDeviceDescriptors> descriptors( 344 video_capture_device_factory_->GetDeviceDescriptors(descriptors_.get());
377 EnumerateDevices()); 345 ASSERT_EQ(device_count, descriptors_->size());
378 ASSERT_EQ(device_count, descriptors->size()); 346 ASSERT_FALSE(descriptors_->at(0).camera_calibration);
379 ASSERT_FALSE(descriptors->at(0).camera_calibration); 347 const VideoCaptureDeviceDescriptor& depth_device = descriptors_->at(1);
380 const VideoCaptureDeviceDescriptor& depth_device = descriptors->at(1);
381 EXPECT_EQ("/dev/video1", depth_device.device_id); 348 EXPECT_EQ("/dev/video1", depth_device.device_id);
382 ASSERT_TRUE(depth_device.camera_calibration); 349 ASSERT_TRUE(depth_device.camera_calibration);
383 EXPECT_EQ(135.0, depth_device.camera_calibration->focal_length_x); 350 EXPECT_EQ(135.0, depth_device.camera_calibration->focal_length_x);
384 EXPECT_EQ(135.6, depth_device.camera_calibration->focal_length_y); 351 EXPECT_EQ(135.6, depth_device.camera_calibration->focal_length_y);
385 EXPECT_EQ(0.0, depth_device.camera_calibration->depth_near); 352 EXPECT_EQ(0.0, depth_device.camera_calibration->depth_near);
386 EXPECT_EQ(65.535, depth_device.camera_calibration->depth_far); 353 EXPECT_EQ(65.535, depth_device.camera_calibration->depth_far);
387 } 354 }
388 355
389 TEST_F(FakeVideoCaptureDeviceTest, ErrorDeviceReportsError) { 356 TEST_F(FakeVideoCaptureDeviceTest, ErrorDeviceReportsError) {
390 auto device = FakeVideoCaptureDeviceFactory::CreateErrorDevice(); 357 auto device = FakeVideoCaptureDeviceFactory::CreateErrorDevice();
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
554 class FakeVideoCaptureDeviceFactoryTest 521 class FakeVideoCaptureDeviceFactoryTest
555 : public FakeVideoCaptureDeviceBase, 522 : public FakeVideoCaptureDeviceBase,
556 public ::testing::WithParamInterface<CommandLineTestData> {}; 523 public ::testing::WithParamInterface<CommandLineTestData> {};
557 524
558 TEST_F(FakeVideoCaptureDeviceFactoryTest, DeviceWithNoSupportedFormats) { 525 TEST_F(FakeVideoCaptureDeviceFactoryTest, DeviceWithNoSupportedFormats) {
559 std::vector<FakeVideoCaptureDeviceSettings> config; 526 std::vector<FakeVideoCaptureDeviceSettings> config;
560 FakeVideoCaptureDeviceSettings device_setting; 527 FakeVideoCaptureDeviceSettings device_setting;
561 device_setting.device_id = "Device with no supported formats"; 528 device_setting.device_id = "Device with no supported formats";
562 config.emplace_back(device_setting); 529 config.emplace_back(device_setting);
563 video_capture_device_factory_->SetToCustomDevicesConfig(config); 530 video_capture_device_factory_->SetToCustomDevicesConfig(config);
564 531 video_capture_device_factory_->GetDeviceDescriptors(descriptors_.get());
565 const std::unique_ptr<VideoCaptureDeviceDescriptors> descriptors( 532 EXPECT_EQ(1u, descriptors_->size());
566 EnumerateDevices());
567 EXPECT_EQ(1u, descriptors->size());
568 media::VideoCaptureFormats supported_formats; 533 media::VideoCaptureFormats supported_formats;
569 video_capture_device_factory_->GetSupportedFormats(descriptors->at(0), 534 video_capture_device_factory_->GetSupportedFormats(descriptors_->at(0),
570 &supported_formats); 535 &supported_formats);
571 EXPECT_EQ(0u, supported_formats.size()); 536 EXPECT_EQ(0u, supported_formats.size());
572 auto device = video_capture_device_factory_->CreateDevice(descriptors->at(0)); 537 auto device =
538 video_capture_device_factory_->CreateDevice(descriptors_->at(0));
573 EXPECT_TRUE(device.get()); 539 EXPECT_TRUE(device.get());
574 540
575 auto client = CreateClient(); 541 auto client = CreateClient();
576 EXPECT_CALL(*client, OnError(_, _)); 542 EXPECT_CALL(*client, OnError(_, _));
577 VideoCaptureParams capture_params; 543 VideoCaptureParams capture_params;
578 capture_params.requested_format.frame_size.SetSize(1280, 720); 544 capture_params.requested_format.frame_size.SetSize(1280, 720);
579 device->AllocateAndStart(capture_params, std::move(client)); 545 device->AllocateAndStart(capture_params, std::move(client));
580 } 546 }
581 547
582 // Tests that the FakeVideoCaptureDeviceFactory delivers the expected number 548 // Tests that the FakeVideoCaptureDeviceFactory delivers the expected number
583 // of devices and formats when being configured using command-line switches. 549 // of devices and formats when being configured using command-line switches.
584 TEST_P(FakeVideoCaptureDeviceFactoryTest, FrameRateAndDeviceCount) { 550 TEST_P(FakeVideoCaptureDeviceFactoryTest, FrameRateAndDeviceCount) {
585 std::vector<FakeVideoCaptureDeviceSettings> config; 551 std::vector<FakeVideoCaptureDeviceSettings> config;
586 FakeVideoCaptureDeviceFactory::ParseFakeDevicesConfigFromOptionsString( 552 FakeVideoCaptureDeviceFactory::ParseFakeDevicesConfigFromOptionsString(
587 GetParam().switch_value_string, &config); 553 GetParam().switch_value_string, &config);
588 video_capture_device_factory_->SetToCustomDevicesConfig(config); 554 video_capture_device_factory_->SetToCustomDevicesConfig(config);
589 555 video_capture_device_factory_->GetDeviceDescriptors(descriptors_.get());
590 const std::unique_ptr<VideoCaptureDeviceDescriptors> descriptors( 556 EXPECT_EQ(GetParam().expected_device_count, descriptors_->size());
591 EnumerateDevices());
592 EXPECT_EQ(GetParam().expected_device_count, descriptors->size());
593 557
594 int device_index = 0; 558 int device_index = 0;
595 for (const auto& descriptors_iterator : *descriptors) { 559 for (const auto& descriptors_iterator : *descriptors_) {
596 media::VideoCaptureFormats supported_formats; 560 media::VideoCaptureFormats supported_formats;
597 video_capture_device_factory_->GetSupportedFormats(descriptors_iterator, 561 video_capture_device_factory_->GetSupportedFormats(descriptors_iterator,
598 &supported_formats); 562 &supported_formats);
599 for (const auto& supported_formats_entry : supported_formats) { 563 for (const auto& supported_formats_entry : supported_formats) {
600 EXPECT_EQ(GetParam().expected_pixel_formats[device_index], 564 EXPECT_EQ(GetParam().expected_pixel_formats[device_index],
601 supported_formats_entry.pixel_format); 565 supported_formats_entry.pixel_format);
602 } 566 }
603 567
604 std::unique_ptr<VideoCaptureDevice> device = 568 std::unique_ptr<VideoCaptureDevice> device =
605 video_capture_device_factory_->CreateDevice(descriptors_iterator); 569 video_capture_device_factory_->CreateDevice(descriptors_iterator);
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
646 4u, 610 4u,
647 {PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16, 611 {PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16,
648 PIXEL_FORMAT_MJPEG, PIXEL_FORMAT_I420}}, 612 PIXEL_FORMAT_MJPEG, PIXEL_FORMAT_I420}},
649 CommandLineTestData{"device-count=4,ownership=client", 613 CommandLineTestData{"device-count=4,ownership=client",
650 20, 614 20,
651 4u, 615 4u,
652 {PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16, 616 {PIXEL_FORMAT_I420, PIXEL_FORMAT_Y16,
653 PIXEL_FORMAT_MJPEG, PIXEL_FORMAT_I420}}, 617 PIXEL_FORMAT_MJPEG, PIXEL_FORMAT_I420}},
654 CommandLineTestData{"device-count=0", 20, 0u, {PIXEL_FORMAT_I420}})); 618 CommandLineTestData{"device-count=0", 20, 0u, {PIXEL_FORMAT_I420}}));
655 }; // namespace media 619 }; // namespace media
OLDNEW
« no previous file with comments | « no previous file | media/capture/video/video_capture_device_descriptor.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698