Upstream version 7.36.149.0
[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 "media/base/video_frame.h"
14 #include "third_party/skia/include/core/SkBitmap.h"
15 #include "third_party/skia/include/core/SkCanvas.h"
16 #include "third_party/skia/include/core/SkPaint.h"
17
18 namespace media {
19
20 static const int kFakeCaptureBeepCycle = 10;  // Visual beep every 0.5s.
21 static const int kFakeCaptureCapabilityChangePeriod = 30;
22
23 FakeVideoCaptureDevice::FakeVideoCaptureDevice()
24     : capture_thread_("CaptureThread"),
25       frame_count_(0),
26       format_roster_index_(0) {}
27
28 FakeVideoCaptureDevice::~FakeVideoCaptureDevice() {
29   DCHECK(thread_checker_.CalledOnValidThread());
30   DCHECK(!capture_thread_.IsRunning());
31 }
32
33 void FakeVideoCaptureDevice::AllocateAndStart(
34     const VideoCaptureParams& params,
35     scoped_ptr<VideoCaptureDevice::Client> client) {
36   DCHECK(thread_checker_.CalledOnValidThread());
37   DCHECK(!capture_thread_.IsRunning());
38
39   capture_thread_.Start();
40   capture_thread_.message_loop()->PostTask(
41       FROM_HERE,
42       base::Bind(&FakeVideoCaptureDevice::OnAllocateAndStart,
43                  base::Unretained(this),
44                  params,
45                  base::Passed(&client)));
46 }
47
48 void FakeVideoCaptureDevice::StopAndDeAllocate() {
49   DCHECK(thread_checker_.CalledOnValidThread());
50   DCHECK(capture_thread_.IsRunning());
51   capture_thread_.message_loop()->PostTask(
52       FROM_HERE,
53       base::Bind(&FakeVideoCaptureDevice::OnStopAndDeAllocate,
54                  base::Unretained(this)));
55   capture_thread_.Stop();
56 }
57
58 void FakeVideoCaptureDevice::PopulateVariableFormatsRoster(
59     const VideoCaptureFormats& formats) {
60   DCHECK(thread_checker_.CalledOnValidThread());
61   DCHECK(!capture_thread_.IsRunning());
62   format_roster_ = formats;
63   format_roster_index_ = 0;
64 }
65
66 void FakeVideoCaptureDevice::OnAllocateAndStart(
67     const VideoCaptureParams& params,
68     scoped_ptr<VideoCaptureDevice::Client> client) {
69   DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
70   client_ = client.Pass();
71
72   // Incoming |params| can be none of the supported formats, so we get the
73   // closest thing rounded up. TODO(mcasas): Use the |params|, if they belong to
74   // the supported ones, when http://crbug.com/309554 is verified.
75   DCHECK_EQ(params.requested_format.pixel_format, PIXEL_FORMAT_I420);
76   capture_format_.pixel_format = params.requested_format.pixel_format;
77   capture_format_.frame_rate = 30;
78   if (params.requested_format.frame_size.width() > 640)
79       capture_format_.frame_size.SetSize(1280, 720);
80   else if (params.requested_format.frame_size.width() > 320)
81     capture_format_.frame_size.SetSize(640, 480);
82   else
83     capture_format_.frame_size.SetSize(320, 240);
84   const size_t fake_frame_size =
85       VideoFrame::AllocationSize(VideoFrame::I420, capture_format_.frame_size);
86   fake_frame_.reset(new uint8[fake_frame_size]);
87
88   capture_thread_.message_loop()->PostTask(
89       FROM_HERE,
90       base::Bind(&FakeVideoCaptureDevice::OnCaptureTask,
91                  base::Unretained(this)));
92 }
93
94 void FakeVideoCaptureDevice::OnStopAndDeAllocate() {
95   DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
96   client_.reset();
97 }
98
99 void FakeVideoCaptureDevice::OnCaptureTask() {
100   if (!client_)
101     return;
102
103   const size_t frame_size =
104       VideoFrame::AllocationSize(VideoFrame::I420, capture_format_.frame_size);
105   memset(fake_frame_.get(), 0, frame_size);
106
107   SkBitmap bitmap;
108   bitmap.setConfig(SkBitmap::kA8_Config,
109                    capture_format_.frame_size.width(),
110                    capture_format_.frame_size.height(),
111                    capture_format_.frame_size.width()),
112       bitmap.setPixels(fake_frame_.get());
113   SkCanvas canvas(bitmap);
114
115   // Draw a sweeping circle to show an animation.
116   int radius = std::min(capture_format_.frame_size.width(),
117                         capture_format_.frame_size.height()) / 4;
118   SkRect rect =
119       SkRect::MakeXYWH(capture_format_.frame_size.width() / 2 - radius,
120                        capture_format_.frame_size.height() / 2 - radius,
121                        2 * radius,
122                        2 * radius);
123
124   SkPaint paint;
125   paint.setStyle(SkPaint::kFill_Style);
126
127   // Only Y plane is being drawn and this gives 50% grey on the Y
128   // plane. The result is a light green color in RGB space.
129   paint.setAlpha(128);
130
131   int end_angle = (frame_count_ % kFakeCaptureBeepCycle * 360) /
132       kFakeCaptureBeepCycle;
133   if (!end_angle)
134     end_angle = 360;
135   canvas.drawArc(rect, 0, end_angle, true, paint);
136
137   // Draw current time.
138   int elapsed_ms = kFakeCaptureTimeoutMs * frame_count_;
139   int milliseconds = elapsed_ms % 1000;
140   int seconds = (elapsed_ms / 1000) % 60;
141   int minutes = (elapsed_ms / 1000 / 60) % 60;
142   int hours = (elapsed_ms / 1000 / 60 / 60) % 60;
143
144   std::string time_string =
145       base::StringPrintf("%d:%02d:%02d:%03d %d", hours, minutes,
146                          seconds, milliseconds, frame_count_);
147   canvas.scale(3, 3);
148   canvas.drawText(time_string.data(), time_string.length(), 30, 20,
149                   paint);
150
151   if (frame_count_ % kFakeCaptureBeepCycle == 0) {
152     // Generate a synchronized beep sound if there is one audio input
153     // stream created.
154     FakeAudioInputStream::BeepOnce();
155   }
156
157   frame_count_++;
158
159   // Give the captured frame to the client.
160   client_->OnIncomingCapturedData(fake_frame_.get(),
161                                   frame_size,
162                                   capture_format_,
163                                   0,
164                                   base::TimeTicks::Now());
165   if (!(frame_count_ % kFakeCaptureCapabilityChangePeriod) &&
166       format_roster_.size() > 0U) {
167     Reallocate();
168   }
169   // Reschedule next CaptureTask.
170   capture_thread_.message_loop()->PostDelayedTask(
171       FROM_HERE,
172       base::Bind(&FakeVideoCaptureDevice::OnCaptureTask,
173                  base::Unretained(this)),
174       base::TimeDelta::FromMilliseconds(kFakeCaptureTimeoutMs));
175 }
176
177 void FakeVideoCaptureDevice::Reallocate() {
178   DCHECK_EQ(capture_thread_.message_loop(), base::MessageLoop::current());
179   capture_format_ =
180       format_roster_.at(++format_roster_index_ % format_roster_.size());
181   DCHECK_EQ(capture_format_.pixel_format, PIXEL_FORMAT_I420);
182   DVLOG(3) << "Reallocating FakeVideoCaptureDevice, new capture resolution "
183            << capture_format_.frame_size.ToString();
184
185   const size_t fake_frame_size =
186       VideoFrame::AllocationSize(VideoFrame::I420, capture_format_.frame_size);
187   fake_frame_.reset(new uint8[fake_frame_size]);
188 }
189
190 }  // namespace media