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