cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / media / video / capture / fake_video_capture_device.cc
blobae7c07bc042558e63207efad091e35aaedfb656b
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"
7 #include <string>
9 #include "base/bind.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"
17 namespace media {
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 VideoCaptureDevice* FakeVideoCaptureDevice::Create(const Name& device_name) {
38 if (fail_next_create_) {
39 fail_next_create_ = false;
40 return NULL;
42 for (int n = 0; n < kNumberOfFakeDevices; ++n) {
43 std::string possible_id = base::StringPrintf("/dev/video%d", n);
44 if (device_name.id().compare(possible_id) == 0) {
45 return new FakeVideoCaptureDevice(device_name);
48 return NULL;
51 void FakeVideoCaptureDevice::SetFailNextCreate() {
52 fail_next_create_ = true;
55 FakeVideoCaptureDevice::FakeVideoCaptureDevice(const Name& device_name)
56 : device_name_(device_name),
57 observer_(NULL),
58 state_(kIdle),
59 capture_thread_("CaptureThread"),
60 frame_count_(0),
61 capabilities_roster_index_(0) {
64 FakeVideoCaptureDevice::~FakeVideoCaptureDevice() {
65 // Check if the thread is running.
66 // This means that the device have not been DeAllocated properly.
67 DCHECK(!capture_thread_.IsRunning());
70 void FakeVideoCaptureDevice::Allocate(
71 const VideoCaptureCapability& capture_format,
72 EventHandler* observer) {
73 capture_format_.frame_size_type = capture_format.frame_size_type;
74 if (capture_format.frame_size_type == VariableResolutionVideoCaptureDevice)
75 PopulateCapabilitiesRoster();
77 if (state_ != kIdle) {
78 return; // Wrong state.
81 observer_ = observer;
82 capture_format_.color = VideoCaptureCapability::kI420;
83 capture_format_.expected_capture_delay = 0;
84 capture_format_.interlaced = false;
85 if (capture_format.width > 320) { // VGA
86 capture_format_.width = 640;
87 capture_format_.height = 480;
88 capture_format_.frame_rate = 30;
89 } else { // QVGA
90 capture_format_.width = 320;
91 capture_format_.height = 240;
92 capture_format_.frame_rate = 30;
95 const size_t fake_frame_size = VideoFrame::AllocationSize(
96 VideoFrame::I420,
97 gfx::Size(capture_format_.width, capture_format_.height));
98 fake_frame_.reset(new uint8[fake_frame_size]);
100 state_ = kAllocated;
101 observer_->OnFrameInfo(capture_format_);
104 void FakeVideoCaptureDevice::Reallocate() {
105 DCHECK_EQ(state_, kCapturing);
106 capture_format_ = capabilities_roster_.at(++capabilities_roster_index_ %
107 capabilities_roster_.size());
108 DCHECK_EQ(capture_format_.color, VideoCaptureCapability::kI420);
109 DVLOG(3) << "Reallocating FakeVideoCaptureDevice, new capture resolution ("
110 << capture_format_.width << "x" << capture_format_.height << ")";
112 const size_t fake_frame_size = VideoFrame::AllocationSize(
113 VideoFrame::I420,
114 gfx::Size(capture_format_.width, capture_format_.height));
115 fake_frame_.reset(new uint8[fake_frame_size]);
117 observer_->OnFrameInfoChanged(capture_format_);
120 void FakeVideoCaptureDevice::Start() {
121 if (state_ != kAllocated) {
122 return; // Wrong state.
124 state_ = kCapturing;
125 capture_thread_.Start();
126 capture_thread_.message_loop()->PostTask(
127 FROM_HERE,
128 base::Bind(&FakeVideoCaptureDevice::OnCaptureTask,
129 base::Unretained(this)));
132 void FakeVideoCaptureDevice::Stop() {
133 if (state_ != kCapturing) {
134 return; // Wrong state.
136 capture_thread_.Stop();
137 state_ = kAllocated;
140 void FakeVideoCaptureDevice::DeAllocate() {
141 if (state_ != kAllocated && state_ != kCapturing) {
142 return; // Wrong state.
144 capture_thread_.Stop();
145 state_ = kIdle;
148 const VideoCaptureDevice::Name& FakeVideoCaptureDevice::device_name() {
149 return device_name_;
152 void FakeVideoCaptureDevice::OnCaptureTask() {
153 if (state_ != kCapturing) {
154 return;
157 const size_t frame_size = VideoFrame::AllocationSize(
158 VideoFrame::I420,
159 gfx::Size(capture_format_.width, capture_format_.height));
160 memset(fake_frame_.get(), 0, frame_size);
162 SkBitmap bitmap;
163 bitmap.setConfig(SkBitmap::kA8_Config,
164 capture_format_.width,
165 capture_format_.height,
166 capture_format_.width);
167 bitmap.setPixels(fake_frame_.get());
169 SkCanvas canvas(bitmap);
171 // Draw a sweeping circle to show an animation.
172 int radius = std::min(capture_format_.width, capture_format_.height) / 4;
173 SkRect rect = SkRect::MakeXYWH(
174 capture_format_.width / 2 - radius, capture_format_.height / 2 - radius,
175 2 * radius, 2 * radius);
177 SkPaint paint;
178 paint.setStyle(SkPaint::kFill_Style);
180 // Only Y plane is being drawn and this gives 50% grey on the Y
181 // plane. The result is a light green color in RGB space.
182 paint.setAlpha(128);
184 int end_angle = (frame_count_ % kFakeCaptureBeepCycle * 360) /
185 kFakeCaptureBeepCycle;
186 if (!end_angle)
187 end_angle = 360;
188 canvas.drawArc(rect, 0, end_angle, true, paint);
190 // Draw current time.
191 int elapsed_ms = kFakeCaptureTimeoutMs * frame_count_;
192 int milliseconds = elapsed_ms % 1000;
193 int seconds = (elapsed_ms / 1000) % 60;
194 int minutes = (elapsed_ms / 1000 / 60) % 60;
195 int hours = (elapsed_ms / 1000 / 60 / 60) % 60;
197 std::string time_string =
198 base::StringPrintf("%d:%02d:%02d:%03d %d", hours, minutes,
199 seconds, milliseconds, frame_count_);
200 canvas.scale(3, 3);
201 canvas.drawText(time_string.data(), time_string.length(), 30, 20,
202 paint);
204 if (frame_count_ % kFakeCaptureBeepCycle == 0) {
205 // Generate a synchronized beep sound if there is one audio input
206 // stream created.
207 FakeAudioInputStream::BeepOnce();
210 frame_count_++;
212 // Give the captured frame to the observer.
213 observer_->OnIncomingCapturedFrame(
214 fake_frame_.get(), frame_size, base::Time::Now(), 0, false, false);
215 if (!(frame_count_ % kFakeCaptureCapabilityChangePeriod) &&
216 (capture_format_.frame_size_type ==
217 VariableResolutionVideoCaptureDevice)) {
218 Reallocate();
220 // Reschedule next CaptureTask.
221 capture_thread_.message_loop()->PostDelayedTask(
222 FROM_HERE,
223 base::Bind(&FakeVideoCaptureDevice::OnCaptureTask,
224 base::Unretained(this)),
225 base::TimeDelta::FromMilliseconds(kFakeCaptureTimeoutMs));
228 void FakeVideoCaptureDevice::PopulateCapabilitiesRoster() {
229 capabilities_roster_.push_back(
230 media::VideoCaptureCapability(320,
231 240,
233 VideoCaptureCapability::kI420,
235 false,
236 VariableResolutionVideoCaptureDevice));
237 capabilities_roster_.push_back(
238 media::VideoCaptureCapability(640,
239 480,
241 VideoCaptureCapability::kI420,
243 false,
244 VariableResolutionVideoCaptureDevice));
245 capabilities_roster_.push_back(
246 media::VideoCaptureCapability(800,
247 600,
249 VideoCaptureCapability::kI420,
251 false,
252 VariableResolutionVideoCaptureDevice));
254 capabilities_roster_index_ = 0;
257 } // namespace media