Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1349)

Side by Side Diff: content/browser/renderer_host/media/screen_capturer.cc

Issue 11680002: Implement screen capturer for MediaStream API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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 "content/browser/renderer_host/media/screen_capturer.h"
6
7 #include "remoting/capturer/capture_data.h"
8 #include "remoting/capturer/mouse_cursor_shape.h"
9 #include "third_party/skia/include/core/SkCanvas.h"
10 #include "third_party/skia/include/core/SkDevice.h"
11
12 namespace content {
13
14 namespace {
15 const int kBytesPerPixel = 4;
16 } // namespace
17
18 ScreenCapturer::ScreenCapturer()
19 : capture_thread_("Screen Capture Thread"),
20 event_handler_(NULL),
21 capture_pending_(false),
22 waiting_frame_size_(false),
23 started_(false) {
24 name_.device_name = "Screen";
25 }
26
27 ScreenCapturer::~ScreenCapturer() {
Wez 2013/01/10 00:58:14 If the caller hasn't called DeAllocate then we sti
Sergey Ulanov 2013/01/11 23:46:20 Added DeAllocate.
28 }
29
30 void ScreenCapturer::Allocate(int width, int height,
31 int frame_rate,
32 EventHandler* event_handler) {
Wez 2013/01/10 00:58:14 nit: Consider [D]CHECKing the parameters. e.g. fra
Sergey Ulanov 2013/01/11 23:46:20 Done.
33 capture_thread_.Start();
Wez 2013/01/10 00:58:14 Is there no other thread or thread pool we can all
Sergey Ulanov 2013/01/11 23:46:20 Changed this code to use blocking IO pool.
34
35 // base::Unretained is safe because we control lifetime of the thread.
36 capture_thread_.message_loop()->PostTask(
37 FROM_HERE, base::Bind(&ScreenCapturer::DoAllocate, base::Unretained(this),
38 frame_rate, event_handler));
39 }
40
41 void ScreenCapturer::Start() {
wjia(left Chromium) 2013/01/07 22:15:26 check capture_thread_.IsRunning() here too?
Sergey Ulanov 2013/01/09 20:35:30 Done.
42 capture_thread_.message_loop()->PostTask(
43 FROM_HERE, base::Bind(&ScreenCapturer::DoStart, base::Unretained(this)));
44 }
45
46 void ScreenCapturer::Stop() {
47 capture_thread_.message_loop()->PostTask(
48 FROM_HERE, base::Bind(&ScreenCapturer::DoStop, base::Unretained(this)));
49 }
50
51 void ScreenCapturer::DeAllocate() {
52 if (capture_thread_.IsRunning()) {
53 capture_thread_.message_loop()->PostTask(
54 FROM_HERE, base::Bind(&ScreenCapturer::DoDeAllocate,
55 base::Unretained(this)));
56 capture_thread_.Stop();
Wez 2013/01/10 00:58:14 Does it matter that this might block e.g. for half
Sergey Ulanov 2013/01/11 23:46:20 Removed capture_thread_. thread pool is used inste
57 }
58 }
59
60 const media::VideoCaptureDevice::Name& ScreenCapturer::device_name() {
61 return name_;
62 }
63
64 void ScreenCapturer::OnCaptureCompleted(
65 scoped_refptr<remoting::CaptureData> capture_data) {
66 DCHECK(capture_thread_.message_loop_proxy()->BelongsToCurrentThread());
67 DCHECK(capture_pending_);
68 capture_pending_ = false;
69
70 if (waiting_frame_size_) {
71 frame_size_ = capture_data->size();
72 waiting_frame_size_ = false;
73
74 // Invoke OnFrameInfo().
Wez 2013/01/10 00:58:14 nit: Please make this more descriptive, e.g. "Info
Sergey Ulanov 2013/01/11 23:46:20 Done.
75 media::VideoCaptureCapability caps;
76 caps.width = frame_size_.width();
77 caps.height = frame_size_.height();
78 caps.frame_rate = frame_rate_;
79 caps.color = media::VideoCaptureCapability::kARGB;
80 caps.expected_capture_delay =
81 base::Time::kMillisecondsPerSecond / frame_rate_;
Wez 2013/01/10 00:58:14 Does it matter that the host platform might not be
Sergey Ulanov 2013/01/11 23:46:20 I don't think so. In either case we have no way to
82 caps.interlaced = false;
83 event_handler_->OnFrameInfo(caps);
Wez 2013/01/10 00:58:14 This calls the EventHandler on the capture thread
Sergey Ulanov 2013/01/11 23:46:20 That's the same behavior that we have in device vi
84 }
85
86 if (!started_)
Wez 2013/01/10 00:58:14 This is happening on the same thread that DoStop()
Sergey Ulanov 2013/01/11 23:46:20 OnFrameInfo() needs to be called in response to Al
87 return;
Wez 2013/01/10 00:58:14 Check this before the |waiting_frame_size_| check
Sergey Ulanov 2013/01/11 23:46:20 See my previous comment. OnFrameInfo() doesn't dep
88 size_t buffer_size =
89 frame_size_.width() * frame_size_.height() *
90 remoting::CaptureData::kBytesPerPixel;
91
92 if (capture_data->size() == frame_size_) {
93 // Invalidate resized frame buffer if we previously allocated it.
Wez 2013/01/10 00:58:14 Reword this comment and place it before the if, e.
Sergey Ulanov 2013/01/11 23:46:20 Done.
94 resized_bitmap_.reset();
95 event_handler_->OnIncomingCapturedFrame(
96 capture_data->data(), buffer_size, base::Time::Now());
97 return;
98 }
99
100 // In case screen size has changed we need to resize the image. Resized image
Wez 2013/01/10 00:58:14 Do we really have no way to inform the caller of t
Sergey Ulanov 2013/01/11 23:46:20 No. The interface was designed for webcams and the
101 // is stored to |resized_bitmap_|. Only regions of the screen that are
102 // changing are copied.
103
104 bool redraw_all = false;
Wez 2013/01/10 00:58:14 Why not re-set the CaptureData's rects to contain
Sergey Ulanov 2013/01/11 23:46:20 Done.
105
106 if (resized_bitmap_.width() != frame_size_.width() ||
107 resized_bitmap_.height() != frame_size_.height()) {
108 resized_bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
109 frame_size_.width(), frame_size_.height());
110 resized_bitmap_.setIsOpaque(true);
111 resized_bitmap_.allocPixels();
112 redraw_all = true;
113 }
114
115 float scale_x = static_cast<float>(frame_size_.width()) /
116 capture_data->size().width();
Wez 2013/01/10 00:58:14 Our capturers won't produce 0x0 frames, but if the
Sergey Ulanov 2013/01/11 23:46:20 Added DCHECK on top of this method.
117 float scale_y = static_cast<float>(frame_size_.height()) /
118 capture_data->size().height();
119 float scale;
120 float x, y;
121 // Center the image in case aspect ratio is different.
122 if (scale_x > scale_y) {
123 scale = scale_y;
124 x = (scale_x - scale_y) / scale * frame_size_.width() / 2.0;
125 y = 0;
Wez 2013/01/10 00:58:14 nit: 0.0f
Sergey Ulanov 2013/01/11 23:46:20 Done.
126 } else {
127 scale = scale_x;
128 x = 0;
129 y = (scale_y - scale_x) / scale * frame_size_.height() / 2.0;
130 }
131
132 SkDevice device(resized_bitmap_);
133 SkCanvas canvas(&device);
134 canvas.scale(scale, scale);
Wez 2013/01/10 00:58:14 Add a comment before this block to summarize the p
Sergey Ulanov 2013/01/11 23:46:20 Done.
135
136 if (redraw_all) {
137 SkBitmap source_bitmap;
138 source_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
139 capture_data->size().width(),
140 capture_data->size().height());
141 source_bitmap.setIsOpaque(true);
142 source_bitmap.setPixels(capture_data->data());
143 canvas.drawBitmap(source_bitmap, x / scale, y / scale, NULL);
144 } else {
145 int source_stride = capture_data->stride();
146 for (SkRegion::Iterator i(capture_data->dirty_region());
147 !i.done(); i.next()) {
148 SkBitmap source_bitmap;
149 source_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
150 i.rect().width(), i.rect().height(),
151 source_stride);
152 source_bitmap.setIsOpaque(true);
153 source_bitmap.setPixels(
154 capture_data->data() + i.rect().top() * source_stride +
155 i.rect().left() * remoting::CaptureData::kBytesPerPixel);
156 canvas.drawBitmap(source_bitmap, i.rect().left() + x / scale,
157 i.rect().top() + y / scale, NULL);
Wez 2013/01/10 00:58:14 Does this do the right thing wrt sub-pixel destina
Sergey Ulanov 2013/01/11 23:46:20 Yes, as far as I know, but it uses simple nearest
158 }
159 }
160
161 event_handler_->OnIncomingCapturedFrame(
162 reinterpret_cast<uint8*>(resized_bitmap_.getPixels()), buffer_size,
163 base::Time::Now());
164 }
165
166 void ScreenCapturer::OnCursorShapeChanged(
167 scoped_ptr<remoting::MouseCursorShape> cursor_shape) {
168 DCHECK(capture_thread_.message_loop_proxy()->BelongsToCurrentThread());
169 }
170
171 void ScreenCapturer::DoAllocate(int frame_rate,
172 EventHandler* event_handler) {
173 DCHECK(capture_thread_.message_loop_proxy()->BelongsToCurrentThread());
174 frame_rate_ = frame_rate;
175 event_handler_ = event_handler;
176 if (!video_frame_capturer_)
177 video_frame_capturer_ = remoting::VideoFrameCapturer::Create();
178 if (video_frame_capturer_)
179 video_frame_capturer_->Start(this);
180 waiting_frame_size_ = true;
Wez 2013/01/10 00:58:14 nit: If you need this, set it before Start()ing th
Wez 2013/01/10 00:58:14 nit: Add blank lines around frame_rate and event_h
Sergey Ulanov 2013/01/11 23:46:20 Start() doesn't really start anything. DoCapture()
Sergey Ulanov 2013/01/11 23:46:20 Done.
181 DoCapture();
182 }
183
184 void ScreenCapturer::DoStart() {
185 DCHECK(capture_thread_.message_loop_proxy()->BelongsToCurrentThread());
186 started_ = true;
187 if (video_frame_capturer_) {
188 timer_.reset(new base::RepeatingTimer<ScreenCapturer>());
189 timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(1) / frame_rate_,
190 base::Bind(&ScreenCapturer::DoCapture,
191 base::Unretained(this)));
192 }
193 }
194
195 void ScreenCapturer::DoStop() {
196 DCHECK(capture_thread_.message_loop_proxy()->BelongsToCurrentThread());
197 started_ = false;
198 if (video_frame_capturer_) {
199 timer_.reset();
200 video_frame_capturer_->Stop();
wjia(left Chromium) 2013/01/07 22:15:26 Is this an synchronous API? ScreenCapturer wouldn'
Sergey Ulanov 2013/01/09 20:35:30 Yes.
201 }
202 }
203
204 void ScreenCapturer::DoDeAllocate() {
Wez 2013/01/10 00:58:14 ALso deallocate the resize buffer here.
Sergey Ulanov 2013/01/11 23:46:20 Added it in DoStop.
205 DCHECK(capture_thread_.message_loop_proxy()->BelongsToCurrentThread());
206 video_frame_capturer_.reset();
207 event_handler_ = NULL;
208 waiting_frame_size_ = false;
209 started_ = false;
Wez 2013/01/10 00:58:14 We should already be stopped via Stop?
Sergey Ulanov 2013/01/11 23:46:20 DeAllocate can be called without calling Stop().
210 capture_pending_ = true;
Wez 2013/01/10 00:58:14 Why should capture_pending be true when deallocate
Sergey Ulanov 2013/01/11 23:46:20 Fixed now.
211 }
212
213 void ScreenCapturer::DoCapture() {
214 if (capture_pending_)
215 return;
216 capture_pending_ = true;
217 video_frame_capturer_->CaptureFrame();
218 }
219
220 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698