Updating XTBs based on .GRDs from branch master
[chromium-blink-merge.git] / media / capture / video / fake_video_capture_device.cc
bloba44f4e3dfb6157bdb384243186209e4f19900609
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/capture/video/fake_video_capture_device.h"
7 #include <algorithm>
9 #include "base/bind.h"
10 #include "base/strings/stringprintf.h"
11 #include "media/audio/fake_audio_input_stream.h"
12 #include "media/base/video_frame.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 kFakeCaptureBeepCycle = 10; // Visual beep every 0.5s.
21 void DrawPacman(bool use_argb,
22 uint8_t* const data,
23 int frame_count,
24 int frame_interval,
25 const gfx::Size& frame_size) {
26 // |kN32_SkColorType| stands for the appropriiate RGBA/BGRA format.
27 const SkColorType colorspace =
28 use_argb ? kN32_SkColorType : kAlpha_8_SkColorType;
29 const SkImageInfo info = SkImageInfo::Make(
30 frame_size.width(), frame_size.height(), colorspace, kOpaque_SkAlphaType);
31 SkBitmap bitmap;
32 bitmap.setInfo(info);
33 bitmap.setPixels(data);
34 SkPaint paint;
35 paint.setStyle(SkPaint::kFill_Style);
36 SkCanvas canvas(bitmap);
38 // Equalize Alpha_8 that has light green background while RGBA has white.
39 if (use_argb) {
40 const SkRect full_frame =
41 SkRect::MakeWH(frame_size.width(), frame_size.height());
42 paint.setARGB(255, 0, 127, 0);
43 canvas.drawRect(full_frame, paint);
45 paint.setColor(SK_ColorGREEN);
47 // Draw a sweeping circle to show an animation.
48 const int end_angle = (3 * kFakeCaptureBeepCycle * frame_count % 361);
49 const int radius = std::min(frame_size.width(), frame_size.height()) / 4;
50 const SkRect rect = SkRect::MakeXYWH(frame_size.width() / 2 - radius,
51 frame_size.height() / 2 - radius,
52 2 * radius, 2 * radius);
53 canvas.drawArc(rect, 0, end_angle, true, paint);
55 // Draw current time.
56 const int elapsed_ms = frame_interval * frame_count;
57 const int milliseconds = elapsed_ms % 1000;
58 const int seconds = (elapsed_ms / 1000) % 60;
59 const int minutes = (elapsed_ms / 1000 / 60) % 60;
60 const int hours = (elapsed_ms / 1000 / 60 / 60) % 60;
62 const std::string time_string =
63 base::StringPrintf("%d:%02d:%02d:%03d %d", hours, minutes, seconds,
64 milliseconds, frame_count);
65 canvas.scale(3, 3);
66 canvas.drawText(time_string.data(), time_string.length(), 30, 20, paint);
69 FakeVideoCaptureDevice::FakeVideoCaptureDevice(
70 FakeVideoCaptureDeviceType device_type)
71 : device_type_(device_type), frame_count_(0), weak_factory_(this) {
74 FakeVideoCaptureDevice::~FakeVideoCaptureDevice() {
75 DCHECK(thread_checker_.CalledOnValidThread());
78 void FakeVideoCaptureDevice::AllocateAndStart(
79 const VideoCaptureParams& params,
80 scoped_ptr<VideoCaptureDevice::Client> client) {
81 DCHECK(thread_checker_.CalledOnValidThread());
83 client_ = client.Pass();
85 // Incoming |params| can be none of the supported formats, so we get the
86 // closest thing rounded up. TODO(mcasas): Use the |params|, if they belong to
87 // the supported ones, when http://crbug.com/309554 is verified.
88 DCHECK_EQ(params.requested_format.pixel_format,
89 VIDEO_CAPTURE_PIXEL_FORMAT_I420);
90 capture_format_.pixel_format = params.requested_format.pixel_format;
91 capture_format_.frame_rate = 30.0;
92 if (params.requested_format.frame_size.width() > 1280)
93 capture_format_.frame_size.SetSize(1920, 1080);
94 else if (params.requested_format.frame_size.width() > 640)
95 capture_format_.frame_size.SetSize(1280, 720);
96 else if (params.requested_format.frame_size.width() > 320)
97 capture_format_.frame_size.SetSize(640, 480);
98 else
99 capture_format_.frame_size.SetSize(320, 240);
101 if (device_type_ == USING_OWN_BUFFERS ||
102 device_type_ == USING_OWN_BUFFERS_TRIPLANAR) {
103 capture_format_.pixel_storage = PIXEL_STORAGE_CPU;
104 fake_frame_.reset(new uint8[VideoFrame::AllocationSize(
105 PIXEL_FORMAT_I420, capture_format_.frame_size)]);
106 BeepAndScheduleNextCapture(
107 base::TimeTicks::Now(),
108 base::Bind(&FakeVideoCaptureDevice::CaptureUsingOwnBuffers,
109 weak_factory_.GetWeakPtr()));
110 } else if (device_type_ == USING_CLIENT_BUFFERS) {
111 DVLOG(1) << "starting with "
112 << (params.use_gpu_memory_buffers ? "GMB" : "ShMem");
113 BeepAndScheduleNextCapture(
114 base::TimeTicks::Now(),
115 base::Bind(&FakeVideoCaptureDevice::CaptureUsingClientBuffers,
116 weak_factory_.GetWeakPtr(),
117 params.use_gpu_memory_buffers
118 ? VIDEO_CAPTURE_PIXEL_FORMAT_ARGB
119 : VIDEO_CAPTURE_PIXEL_FORMAT_I420,
120 params.use_gpu_memory_buffers ? PIXEL_STORAGE_GPUMEMORYBUFFER
121 : PIXEL_STORAGE_CPU));
122 } else {
123 client_->OnError("Unknown Fake Video Capture Device type.");
127 void FakeVideoCaptureDevice::StopAndDeAllocate() {
128 DCHECK(thread_checker_.CalledOnValidThread());
129 client_.reset();
132 void FakeVideoCaptureDevice::CaptureUsingOwnBuffers(
133 base::TimeTicks expected_execution_time) {
134 DCHECK(thread_checker_.CalledOnValidThread());
135 const size_t frame_size = capture_format_.ImageAllocationSize();
136 memset(fake_frame_.get(), 0, frame_size);
138 DrawPacman(false /* use_argb */, fake_frame_.get(), frame_count_,
139 kFakeCapturePeriodMs, capture_format_.frame_size);
141 // Give the captured frame to the client.
142 if (device_type_ == USING_OWN_BUFFERS) {
143 client_->OnIncomingCapturedData(fake_frame_.get(), frame_size,
144 capture_format_, 0 /* rotation */,
145 base::TimeTicks::Now());
146 } else if (device_type_ == USING_OWN_BUFFERS_TRIPLANAR) {
147 client_->OnIncomingCapturedYuvData(
148 fake_frame_.get(),
149 fake_frame_.get() + capture_format_.frame_size.GetArea(),
150 fake_frame_.get() + capture_format_.frame_size.GetArea() * 5 / 4,
151 capture_format_.frame_size.width(),
152 capture_format_.frame_size.width() / 2,
153 capture_format_.frame_size.width() / 2, capture_format_,
154 0 /* rotation */, base::TimeTicks::Now());
156 BeepAndScheduleNextCapture(
157 expected_execution_time,
158 base::Bind(&FakeVideoCaptureDevice::CaptureUsingOwnBuffers,
159 weak_factory_.GetWeakPtr()));
162 void FakeVideoCaptureDevice::CaptureUsingClientBuffers(
163 VideoCapturePixelFormat pixel_format,
164 VideoPixelStorage pixel_storage,
165 base::TimeTicks expected_execution_time) {
166 DCHECK(thread_checker_.CalledOnValidThread());
168 scoped_ptr<VideoCaptureDevice::Client::Buffer> capture_buffer(
169 client_->ReserveOutputBuffer(capture_format_.frame_size, pixel_format,
170 pixel_storage));
171 DLOG_IF(ERROR, !capture_buffer) << "Couldn't allocate Capture Buffer";
173 if (capture_buffer.get()) {
174 uint8_t* const data_ptr = static_cast<uint8_t*>(capture_buffer->data());
175 DCHECK(data_ptr) << "Buffer has NO backing memory";
176 memset(data_ptr, 0, capture_buffer->size());
178 DrawPacman(
179 (pixel_format == media::VIDEO_CAPTURE_PIXEL_FORMAT_ARGB), /* use_argb */
180 data_ptr, frame_count_, kFakeCapturePeriodMs,
181 capture_format_.frame_size);
183 // Give the captured frame to the client.
184 const VideoCaptureFormat format(capture_format_.frame_size,
185 capture_format_.frame_rate, pixel_format,
186 pixel_storage);
187 client_->OnIncomingCapturedBuffer(capture_buffer.Pass(), format,
188 base::TimeTicks::Now());
191 BeepAndScheduleNextCapture(
192 expected_execution_time,
193 base::Bind(&FakeVideoCaptureDevice::CaptureUsingClientBuffers,
194 weak_factory_.GetWeakPtr(), pixel_format, pixel_storage));
197 void FakeVideoCaptureDevice::BeepAndScheduleNextCapture(
198 base::TimeTicks expected_execution_time,
199 const base::Callback<void(base::TimeTicks)>& next_capture) {
200 // Generate a synchronized beep sound every so many frames.
201 if (frame_count_++ % kFakeCaptureBeepCycle == 0)
202 FakeAudioInputStream::BeepOnce();
204 // Reschedule next CaptureTask.
205 const base::TimeTicks current_time = base::TimeTicks::Now();
206 const base::TimeDelta frame_interval =
207 base::TimeDelta::FromMilliseconds(kFakeCapturePeriodMs);
208 // Don't accumulate any debt if we are lagging behind - just post the next
209 // frame immediately and continue as normal.
210 const base::TimeTicks next_execution_time =
211 std::max(current_time, expected_execution_time + frame_interval);
212 const base::TimeDelta delay = next_execution_time - current_time;
213 base::MessageLoop::current()->PostDelayedTask(
214 FROM_HERE, base::Bind(next_capture, next_execution_time), delay);
217 } // namespace media