- add sources.
[platform/framework/web/crosswalk.git] / src / media / video / capture / fake_video_capture_device.cc
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.
4
5 #include "media/video/capture/fake_video_capture_device.h"
6
7 #include <string>
8
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"
16
17 namespace media {
18
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 };
23
24 bool FakeVideoCaptureDevice::fail_next_create_ = false;
25
26 void FakeVideoCaptureDevice::GetDeviceNames(Names* const device_names) {
27   // Empty the name list.
28   device_names->erase(device_names->begin(), device_names->end());
29
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);
34   }
35 }
36
37 void FakeVideoCaptureDevice::GetDeviceSupportedFormats(
38     const Name& device,
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);
46 }
47
48 VideoCaptureDevice* FakeVideoCaptureDevice::Create(const Name& device_name) {
49   if (fail_next_create_) {
50     fail_next_create_ = false;
51     return NULL;
52   }
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();
57     }
58   }
59   return NULL;
60 }
61
62 void FakeVideoCaptureDevice::SetFailNextCreate() {
63   fail_next_create_ = true;
64 }
65
66 FakeVideoCaptureDevice::FakeVideoCaptureDevice()
67     : state_(kIdle),
68       capture_thread_("CaptureThread"),
69       frame_count_(0),
70       capabilities_roster_index_(0) {
71 }
72
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());
77 }
78
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();
85
86   if (state_ != kIdle) {
87     return;  // Wrong state.
88   }
89
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;
96   } else {  // QVGA
97     capture_format_.width = 320;
98     capture_format_.height = 240;
99     capture_format_.frame_rate = 30;
100   }
101
102   const size_t fake_frame_size = VideoFrame::AllocationSize(
103       VideoFrame::I420,
104       gfx::Size(capture_format_.width, capture_format_.height));
105   fake_frame_.reset(new uint8[fake_frame_size]);
106
107   client_->OnFrameInfo(capture_format_);
108
109   state_ = kCapturing;
110   capture_thread_.Start();
111   capture_thread_.message_loop()->PostTask(
112       FROM_HERE,
113       base::Bind(&FakeVideoCaptureDevice::OnCaptureTask,
114                  base::Unretained(this)));
115 }
116
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 << ")";
124
125   const size_t fake_frame_size = VideoFrame::AllocationSize(
126       VideoFrame::I420,
127       gfx::Size(capture_format_.width, capture_format_.height));
128   fake_frame_.reset(new uint8[fake_frame_size]);
129
130   client_->OnFrameInfoChanged(capture_format_);
131 }
132
133 void FakeVideoCaptureDevice::StopAndDeAllocate() {
134   if (state_ != kCapturing) {
135     return;  // Wrong state.
136   }
137   capture_thread_.Stop();
138   state_ = kIdle;
139 }
140
141 void FakeVideoCaptureDevice::OnCaptureTask() {
142   if (state_ != kCapturing) {
143     return;
144   }
145
146   const size_t frame_size = VideoFrame::AllocationSize(
147       VideoFrame::I420,
148       gfx::Size(capture_format_.width, capture_format_.height));
149   memset(fake_frame_.get(), 0, frame_size);
150
151   SkBitmap bitmap;
152   bitmap.setConfig(SkBitmap::kA8_Config,
153                    capture_format_.width,
154                    capture_format_.height,
155                    capture_format_.width);
156   bitmap.setPixels(fake_frame_.get());
157
158   SkCanvas canvas(bitmap);
159
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);
165
166   SkPaint paint;
167   paint.setStyle(SkPaint::kFill_Style);
168
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.
171   paint.setAlpha(128);
172
173   int end_angle = (frame_count_ % kFakeCaptureBeepCycle * 360) /
174       kFakeCaptureBeepCycle;
175   if (!end_angle)
176     end_angle = 360;
177   canvas.drawArc(rect, 0, end_angle, true, paint);
178
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;
185
186   std::string time_string =
187       base::StringPrintf("%d:%02d:%02d:%03d %d", hours, minutes,
188                          seconds, milliseconds, frame_count_);
189   canvas.scale(3, 3);
190   canvas.drawText(time_string.data(), time_string.length(), 30, 20,
191                   paint);
192
193   if (frame_count_ % kFakeCaptureBeepCycle == 0) {
194     // Generate a synchronized beep sound if there is one audio input
195     // stream created.
196     FakeAudioInputStream::BeepOnce();
197   }
198
199   frame_count_++;
200
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)) {
207     Reallocate();
208   }
209   // Reschedule next CaptureTask.
210   capture_thread_.message_loop()->PostDelayedTask(
211       FROM_HERE,
212       base::Bind(&FakeVideoCaptureDevice::OnCaptureTask,
213                  base::Unretained(this)),
214       base::TimeDelta::FromMilliseconds(kFakeCaptureTimeoutMs));
215 }
216
217 void FakeVideoCaptureDevice::PopulateCapabilitiesRoster() {
218   capabilities_roster_.push_back(
219       media::VideoCaptureCapability(320,
220                                     240,
221                                     30,
222                                     PIXEL_FORMAT_I420,
223                                     VariableResolutionVideoCaptureDevice));
224   capabilities_roster_.push_back(
225       media::VideoCaptureCapability(640,
226                                     480,
227                                     30,
228                                     PIXEL_FORMAT_I420,
229                                     VariableResolutionVideoCaptureDevice));
230   capabilities_roster_.push_back(
231       media::VideoCaptureCapability(800,
232                                     600,
233                                     30,
234                                     PIXEL_FORMAT_I420,
235                                     VariableResolutionVideoCaptureDevice));
236
237   capabilities_roster_index_ = 0;
238 }
239
240 }  // namespace media