1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "media/video/capture/fake_video_capture_device.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/strings/stringprintf.h"
12 #include "media/audio/fake_audio_input_stream.h"
13 #include "third_party/skia/include/core/SkBitmap.h"
14 #include "third_party/skia/include/core/SkCanvas.h"
15 #include "third_party/skia/include/core/SkPaint.h"
19 static const int kFakeCaptureTimeoutMs = 50;
20 static const int kFakeCaptureBeepCycle = 20; // Visual beep every 1s.
21 static const int kFakeCaptureCapabilityChangePeriod = 30;
22 enum { kNumberOfFakeDevices = 2 };
24 bool FakeVideoCaptureDevice::fail_next_create_ = false;
26 void FakeVideoCaptureDevice::GetDeviceNames(Names* const device_names) {
27 // Empty the name list.
28 device_names->erase(device_names->begin(), device_names->end());
30 for (int n = 0; n < kNumberOfFakeDevices; n++) {
31 Name name(base::StringPrintf("fake_device_%d", n),
32 base::StringPrintf("/dev/video%d", n));
33 device_names->push_back(name);
37 void FakeVideoCaptureDevice::GetDeviceSupportedFormats(
39 VideoCaptureCapabilities* formats) {
40 VideoCaptureCapability capture_format;
41 capture_format.color = media::PIXEL_FORMAT_I420;
42 capture_format.width = 640;
43 capture_format.height = 480;
44 capture_format.frame_rate = 1000 / kFakeCaptureTimeoutMs;
45 formats->push_back(capture_format);
48 VideoCaptureDevice* FakeVideoCaptureDevice::Create(const Name& device_name) {
49 if (fail_next_create_) {
50 fail_next_create_ = false;
53 for (int n = 0; n < kNumberOfFakeDevices; ++n) {
54 std::string possible_id = base::StringPrintf("/dev/video%d", n);
55 if (device_name.id().compare(possible_id) == 0) {
56 return new FakeVideoCaptureDevice();
62 void FakeVideoCaptureDevice::SetFailNextCreate() {
63 fail_next_create_ = true;
66 FakeVideoCaptureDevice::FakeVideoCaptureDevice()
68 capture_thread_("CaptureThread"),
70 capabilities_roster_index_(0) {
73 FakeVideoCaptureDevice::~FakeVideoCaptureDevice() {
74 // Check if the thread is running.
75 // This means that the device have not been DeAllocated properly.
76 DCHECK(!capture_thread_.IsRunning());
79 void FakeVideoCaptureDevice::AllocateAndStart(
80 const VideoCaptureCapability& capture_format,
81 scoped_ptr<VideoCaptureDevice::Client> client) {
82 capture_format_.frame_size_type = capture_format.frame_size_type;
83 if (capture_format.frame_size_type == VariableResolutionVideoCaptureDevice)
84 PopulateCapabilitiesRoster();
86 if (state_ != kIdle) {
87 return; // Wrong state.
90 client_ = client.Pass();
91 capture_format_.color = PIXEL_FORMAT_I420;
92 if (capture_format.width > 320) { // VGA
93 capture_format_.width = 640;
94 capture_format_.height = 480;
95 capture_format_.frame_rate = 30;
97 capture_format_.width = 320;
98 capture_format_.height = 240;
99 capture_format_.frame_rate = 30;
102 const size_t fake_frame_size = VideoFrame::AllocationSize(
104 gfx::Size(capture_format_.width, capture_format_.height));
105 fake_frame_.reset(new uint8[fake_frame_size]);
107 client_->OnFrameInfo(capture_format_);
110 capture_thread_.Start();
111 capture_thread_.message_loop()->PostTask(
113 base::Bind(&FakeVideoCaptureDevice::OnCaptureTask,
114 base::Unretained(this)));
117 void FakeVideoCaptureDevice::Reallocate() {
118 DCHECK_EQ(state_, kCapturing);
119 capture_format_ = capabilities_roster_.at(++capabilities_roster_index_ %
120 capabilities_roster_.size());
121 DCHECK_EQ(capture_format_.color, PIXEL_FORMAT_I420);
122 DVLOG(3) << "Reallocating FakeVideoCaptureDevice, new capture resolution ("
123 << capture_format_.width << "x" << capture_format_.height << ")";
125 const size_t fake_frame_size = VideoFrame::AllocationSize(
127 gfx::Size(capture_format_.width, capture_format_.height));
128 fake_frame_.reset(new uint8[fake_frame_size]);
130 client_->OnFrameInfoChanged(capture_format_);
133 void FakeVideoCaptureDevice::StopAndDeAllocate() {
134 if (state_ != kCapturing) {
135 return; // Wrong state.
137 capture_thread_.Stop();
141 void FakeVideoCaptureDevice::OnCaptureTask() {
142 if (state_ != kCapturing) {
146 const size_t frame_size = VideoFrame::AllocationSize(
148 gfx::Size(capture_format_.width, capture_format_.height));
149 memset(fake_frame_.get(), 0, frame_size);
152 bitmap.setConfig(SkBitmap::kA8_Config,
153 capture_format_.width,
154 capture_format_.height,
155 capture_format_.width);
156 bitmap.setPixels(fake_frame_.get());
158 SkCanvas canvas(bitmap);
160 // Draw a sweeping circle to show an animation.
161 int radius = std::min(capture_format_.width, capture_format_.height) / 4;
162 SkRect rect = SkRect::MakeXYWH(
163 capture_format_.width / 2 - radius, capture_format_.height / 2 - radius,
164 2 * radius, 2 * radius);
167 paint.setStyle(SkPaint::kFill_Style);
169 // Only Y plane is being drawn and this gives 50% grey on the Y
170 // plane. The result is a light green color in RGB space.
173 int end_angle = (frame_count_ % kFakeCaptureBeepCycle * 360) /
174 kFakeCaptureBeepCycle;
177 canvas.drawArc(rect, 0, end_angle, true, paint);
179 // Draw current time.
180 int elapsed_ms = kFakeCaptureTimeoutMs * frame_count_;
181 int milliseconds = elapsed_ms % 1000;
182 int seconds = (elapsed_ms / 1000) % 60;
183 int minutes = (elapsed_ms / 1000 / 60) % 60;
184 int hours = (elapsed_ms / 1000 / 60 / 60) % 60;
186 std::string time_string =
187 base::StringPrintf("%d:%02d:%02d:%03d %d", hours, minutes,
188 seconds, milliseconds, frame_count_);
190 canvas.drawText(time_string.data(), time_string.length(), 30, 20,
193 if (frame_count_ % kFakeCaptureBeepCycle == 0) {
194 // Generate a synchronized beep sound if there is one audio input
196 FakeAudioInputStream::BeepOnce();
201 // Give the captured frame to the client.
202 client_->OnIncomingCapturedFrame(
203 fake_frame_.get(), frame_size, base::Time::Now(), 0, false, false);
204 if (!(frame_count_ % kFakeCaptureCapabilityChangePeriod) &&
205 (capture_format_.frame_size_type ==
206 VariableResolutionVideoCaptureDevice)) {
209 // Reschedule next CaptureTask.
210 capture_thread_.message_loop()->PostDelayedTask(
212 base::Bind(&FakeVideoCaptureDevice::OnCaptureTask,
213 base::Unretained(this)),
214 base::TimeDelta::FromMilliseconds(kFakeCaptureTimeoutMs));
217 void FakeVideoCaptureDevice::PopulateCapabilitiesRoster() {
218 capabilities_roster_.push_back(
219 media::VideoCaptureCapability(320,
223 VariableResolutionVideoCaptureDevice));
224 capabilities_roster_.push_back(
225 media::VideoCaptureCapability(640,
229 VariableResolutionVideoCaptureDevice));
230 capabilities_roster_.push_back(
231 media::VideoCaptureCapability(800,
235 VariableResolutionVideoCaptureDevice));
237 capabilities_roster_index_ = 0;