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"
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"
20 static const int kFakeCaptureBeepCycle
= 10; // Visual beep every 0.5s.
21 static const int kFakeCaptureCapabilityChangePeriod
= 30;
23 FakeVideoCaptureDevice::FakeVideoCaptureDevice()
24 : capture_thread_("CaptureThread"),
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 DCHECK(!capture_thread_
.IsRunning());
39 capture_thread_
.Start();
40 capture_thread_
.message_loop()->PostTask(
42 base::Bind(&FakeVideoCaptureDevice::OnAllocateAndStart
,
43 base::Unretained(this),
45 base::Passed(&client
)));
48 void FakeVideoCaptureDevice::StopAndDeAllocate() {
49 DCHECK(thread_checker_
.CalledOnValidThread());
50 DCHECK(capture_thread_
.IsRunning());
51 capture_thread_
.message_loop()->PostTask(
53 base::Bind(&FakeVideoCaptureDevice::OnStopAndDeAllocate
,
54 base::Unretained(this)));
55 capture_thread_
.Stop();
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;
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();
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);
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
]);
88 capture_thread_
.message_loop()->PostTask(
90 base::Bind(&FakeVideoCaptureDevice::OnCaptureTask
,
91 base::Unretained(this)));
94 void FakeVideoCaptureDevice::OnStopAndDeAllocate() {
95 DCHECK_EQ(capture_thread_
.message_loop(), base::MessageLoop::current());
99 void FakeVideoCaptureDevice::OnCaptureTask() {
103 const size_t frame_size
=
104 VideoFrame::AllocationSize(VideoFrame::I420
, capture_format_
.frame_size
);
105 memset(fake_frame_
.get(), 0, frame_size
);
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
);
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;
119 SkRect::MakeXYWH(capture_format_
.frame_size
.width() / 2 - radius
,
120 capture_format_
.frame_size
.height() / 2 - radius
,
125 paint
.setStyle(SkPaint::kFill_Style
);
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.
131 int end_angle
= (frame_count_
% kFakeCaptureBeepCycle
* 360) /
132 kFakeCaptureBeepCycle
;
135 canvas
.drawArc(rect
, 0, end_angle
, true, paint
);
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;
144 std::string time_string
=
145 base::StringPrintf("%d:%02d:%02d:%03d %d", hours
, minutes
,
146 seconds
, milliseconds
, frame_count_
);
148 canvas
.drawText(time_string
.data(), time_string
.length(), 30, 20,
151 if (frame_count_
% kFakeCaptureBeepCycle
== 0) {
152 // Generate a synchronized beep sound if there is one audio input
154 FakeAudioInputStream::BeepOnce();
159 // Give the captured frame to the client.
160 client_
->OnIncomingCapturedData(fake_frame_
.get(),
164 base::TimeTicks::Now());
165 if (!(frame_count_
% kFakeCaptureCapabilityChangePeriod
) &&
166 format_roster_
.size() > 0U) {
169 // Reschedule next CaptureTask.
170 capture_thread_
.message_loop()->PostDelayedTask(
172 base::Bind(&FakeVideoCaptureDevice::OnCaptureTask
,
173 base::Unretained(this)),
174 base::TimeDelta::FromMilliseconds(kFakeCaptureTimeoutMs
));
177 void FakeVideoCaptureDevice::Reallocate() {
178 DCHECK_EQ(capture_thread_
.message_loop(), base::MessageLoop::current());
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();
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
]);