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

Side by Side Diff: remoting/client/plugin/pepper_view.cc

Issue 9331003: Improving the decoder pipeline. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Integer ScaleRect Created 8 years, 10 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
« no previous file with comments | « remoting/client/plugin/pepper_view.h ('k') | remoting/client/rectangle_update_decoder.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/client/plugin/pepper_view.h" 5 #include "remoting/client/plugin/pepper_view.h"
6 6
7 #include <functional>
8
7 #include "base/message_loop.h" 9 #include "base/message_loop.h"
8 #include "base/string_util.h" 10 #include "base/string_util.h"
11 #include "base/synchronization/waitable_event.h"
9 #include "ppapi/cpp/completion_callback.h" 12 #include "ppapi/cpp/completion_callback.h"
10 #include "ppapi/cpp/graphics_2d.h" 13 #include "ppapi/cpp/graphics_2d.h"
11 #include "ppapi/cpp/image_data.h" 14 #include "ppapi/cpp/image_data.h"
12 #include "ppapi/cpp/point.h" 15 #include "ppapi/cpp/point.h"
13 #include "ppapi/cpp/rect.h" 16 #include "ppapi/cpp/rect.h"
14 #include "ppapi/cpp/size.h" 17 #include "ppapi/cpp/size.h"
15 #include "remoting/base/util.h" 18 #include "remoting/base/util.h"
16 #include "remoting/client/chromoting_stats.h" 19 #include "remoting/client/chromoting_stats.h"
17 #include "remoting/client/client_context.h" 20 #include "remoting/client/client_context.h"
21 #include "remoting/client/frame_producer.h"
18 #include "remoting/client/plugin/chromoting_instance.h" 22 #include "remoting/client/plugin/chromoting_instance.h"
19 #include "remoting/client/plugin/pepper_util.h" 23 #include "remoting/client/plugin/pepper_util.h"
20 24
25 using base::Passed;
26
21 namespace remoting { 27 namespace remoting {
22 28
23 namespace { 29 namespace {
24 30
31 // The maximum number of image buffers to be allocated at any point of time.
32 const size_t kMaxPendingBuffersCount = 2;
33
25 ChromotingInstance::ConnectionError ConvertConnectionError( 34 ChromotingInstance::ConnectionError ConvertConnectionError(
26 protocol::ConnectionToHost::Error error) { 35 protocol::ConnectionToHost::Error error) {
27 switch (error) { 36 switch (error) {
28 case protocol::ConnectionToHost::OK: 37 case protocol::ConnectionToHost::OK:
29 return ChromotingInstance::ERROR_NONE; 38 return ChromotingInstance::ERROR_NONE;
30 case protocol::ConnectionToHost::HOST_IS_OFFLINE: 39 case protocol::ConnectionToHost::HOST_IS_OFFLINE:
31 return ChromotingInstance::ERROR_HOST_IS_OFFLINE; 40 return ChromotingInstance::ERROR_HOST_IS_OFFLINE;
32 case protocol::ConnectionToHost::SESSION_REJECTED: 41 case protocol::ConnectionToHost::SESSION_REJECTED:
33 return ChromotingInstance::ERROR_SESSION_REJECTED; 42 return ChromotingInstance::ERROR_SESSION_REJECTED;
34 case protocol::ConnectionToHost::INCOMPATIBLE_PROTOCOL: 43 case protocol::ConnectionToHost::INCOMPATIBLE_PROTOCOL:
35 return ChromotingInstance::ERROR_INCOMPATIBLE_PROTOCOL; 44 return ChromotingInstance::ERROR_INCOMPATIBLE_PROTOCOL;
36 case protocol::ConnectionToHost::NETWORK_FAILURE: 45 case protocol::ConnectionToHost::NETWORK_FAILURE:
37 return ChromotingInstance::ERROR_NETWORK_FAILURE; 46 return ChromotingInstance::ERROR_NETWORK_FAILURE;
38 } 47 }
39 DLOG(FATAL) << "Unknown error code" << error; 48 DLOG(FATAL) << "Unknown error code" << error;
40 return ChromotingInstance::ERROR_NONE; 49 return ChromotingInstance::ERROR_NONE;
41 } 50 }
42 51
43 } // namespace 52 } // namespace
44 53
45 PepperView::PepperView(ChromotingInstance* instance, ClientContext* context) 54 PepperView::PepperView(ChromotingInstance* instance,
55 ClientContext* context,
56 FrameProducer* producer)
46 : instance_(instance), 57 : instance_(instance),
47 context_(context), 58 context_(context),
48 flush_blocked_(false), 59 producer_(producer),
49 is_static_fill_(false), 60 merge_buffer_(NULL),
50 static_fill_color_(0), 61 merge_clip_area_(SkIRect::MakeEmpty()),
62 view_size_(SkISize::Make(0, 0)),
63 clip_area_(SkIRect::MakeEmpty()),
64 source_size_(SkISize::Make(0, 0)),
65 flush_pending_(false),
66 in_teardown_(false),
51 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { 67 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
52 } 68 }
53 69
54 PepperView::~PepperView() { 70 PepperView::~PepperView() {
71 DCHECK(merge_buffer_ == NULL);
72 DCHECK(buffers_.empty());
55 } 73 }
56 74
57 bool PepperView::Initialize() { 75 bool PepperView::Initialize() {
58 return true; 76 return true;
59 } 77 }
60 78
61 void PepperView::TearDown() { 79 void PepperView::TearDown() {
62 DCHECK(context_->main_message_loop()->BelongsToCurrentThread()); 80 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
63 81
82 // The producer should now return any pending buffers. At this point, however,
83 // ReturnBuffer() tasks scheduled by the producer will not be delivered,
84 // so we free all the buffers once the producer's queue is empty.
85 in_teardown_ = true;
86 base::WaitableEvent done_event(true, false);
87 producer_->RequestReturnBuffers(
88 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done_event)));
89 done_event.Wait();
90
91 merge_buffer_ = NULL;
92 while (!buffers_.empty()) {
93 FreeBuffer(buffers_.front());
94 }
95
64 weak_factory_.InvalidateWeakPtrs(); 96 weak_factory_.InvalidateWeakPtrs();
65 } 97 }
66 98
67 void PepperView::Paint() { 99 void PepperView::SetConnectionState(protocol::ConnectionToHost::State state,
68 DCHECK(context_->main_message_loop()->BelongsToCurrentThread()); 100 protocol::ConnectionToHost::Error error) {
69 101 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
70 if (is_static_fill_) { 102
71 VLOG(1) << "Static filling " << static_fill_color_; 103 switch (state) {
72 pp::ImageData image(instance_, pp::ImageData::GetNativeImageDataFormat(), 104 case protocol::ConnectionToHost::CONNECTING:
73 pp::Size(graphics2d_.size().width(), 105 instance_->SetConnectionState(
74 graphics2d_.size().height()), 106 ChromotingInstance::STATE_CONNECTING,
75 false); 107 ConvertConnectionError(error));
76 if (image.is_null()) { 108 break;
77 LOG(ERROR) << "Unable to allocate image of size: " 109
78 << graphics2d_.size().width() << " x " 110 case protocol::ConnectionToHost::CONNECTED:
79 << graphics2d_.size().height(); 111 instance_->SetConnectionState(
80 return; 112 ChromotingInstance::STATE_CONNECTED,
113 ConvertConnectionError(error));
114 break;
115
116 case protocol::ConnectionToHost::CLOSED:
117 instance_->SetConnectionState(
118 ChromotingInstance::STATE_CLOSED,
119 ConvertConnectionError(error));
120 break;
121
122 case protocol::ConnectionToHost::FAILED:
123 instance_->SetConnectionState(
124 ChromotingInstance::STATE_FAILED,
125 ConvertConnectionError(error));
126 break;
127 }
128 }
129
130 void PepperView::SetView(const SkISize& view_size,
131 const SkIRect& clip_area) {
132 bool view_changed = false;
133
134 // TODO(alexeypa): Prevent upscaling because the YUV-to-RGB conversion code
135 // currently does not support upscaling. Once it does, this code be removed.
136 SkISize size = SkISize::Make(
137 std::min(view_size.width(), source_size_.width()),
138 std::min(view_size.height(), source_size_.height()));
139
140 if (view_size_ != size) {
141 view_changed = true;
142 view_size_ = size;
143
144 pp::Size pp_size = pp::Size(view_size_.width(), view_size_.height());
145 graphics2d_ = pp::Graphics2D(instance_, pp_size, true);
146 bool result = instance_->BindGraphics(graphics2d_);
147
148 // There is no good way to handle this error currently.
149 DCHECK(result) << "Couldn't bind the device context.";
150 }
151
152 if (clip_area_ != clip_area) {
153 view_changed = true;
154
155 // YUV to RGB conversion may require even X and Y coordinates for
156 // the top left corner of the clipping area.
157 clip_area_ = AlignRect(clip_area);
158 clip_area_.intersect(SkIRect::MakeSize(view_size_));
159 }
160
161 if (view_changed) {
162 producer_->SetOutputSizeAndClip(view_size_, clip_area_);
163 InitiateDrawing();
164 }
165 }
166
167 void PepperView::ApplyBuffer(const SkISize& view_size,
168 const SkIRect& clip_area,
169 pp::ImageData* buffer,
170 const SkRegion& region) {
171 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
172
173 // Currently we cannot use the data in the buffer is scale factor has changed
174 // already.
175 // TODO(alexeypa): We could rescale and draw it (or even draw it without
176 // rescaling) to reduce the perceived lag while we are waiting for
177 // the properly scaled data.
178 if (view_size_ != view_size) {
179 FreeBuffer(buffer);
180 InitiateDrawing();
181 } else {
182 FlushBuffer(clip_area, buffer, region);
183 }
184 }
185
186 void PepperView::ReturnBuffer(pp::ImageData* buffer) {
187 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
188
189 // Free the buffer if there is nothing to paint.
190 if (in_teardown_) {
191 FreeBuffer(buffer);
192 return;
193 }
194
195 // Reuse the buffer if it is large enough, otherwise drop it on the floor
196 // and allocate a new one.
197 if (buffer->size().width() >= clip_area_.width() &&
198 buffer->size().height() >= clip_area_.height()) {
199 producer_->DrawBuffer(buffer);
200 } else {
201 FreeBuffer(buffer);
202 InitiateDrawing();
203 }
204 }
205
206 void PepperView::SetSourceSize(const SkISize& source_size) {
207 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
208
209 if (source_size_ == source_size)
210 return;
211
212 source_size_ = source_size;
213
214 // Notify JavaScript of the change in source size.
215 instance_->SetDesktopSize(source_size.width(), source_size.height());
216 }
217
218 pp::ImageData* PepperView::AllocateBuffer() {
219 pp::ImageData* buffer = NULL;
220 if (buffers_.size() < kMaxPendingBuffersCount) {
221 pp::Size pp_size = pp::Size(clip_area_.width(), clip_area_.height());
222 buffer = new pp::ImageData(instance_,
223 PP_IMAGEDATAFORMAT_BGRA_PREMUL,
224 pp_size,
225 false);
226 if (buffer->is_null()) {
227 LOG(WARNING) << "Not enough memory for frame buffers.";
228 delete buffer;
229 buffer = NULL;
230 } else {
231 buffers_.push_back(buffer);
81 } 232 }
82 233 }
83 for (int y = 0; y < image.size().height(); y++) { 234
84 for (int x = 0; x < image.size().width(); x++) { 235 return buffer;
85 *image.GetAddr32(pp::Point(x, y)) = static_fill_color_; 236 }
86 } 237
238 void PepperView::FreeBuffer(pp::ImageData* buffer) {
239 DCHECK(std::find(buffers_.begin(), buffers_.end(), buffer) != buffers_.end());
240
241 buffers_.remove(buffer);
242 delete buffer;
243 }
244
245 void PepperView::InitiateDrawing() {
246 // Do not schedule drawing if there is nothing to paint.
247 if (in_teardown_)
248 return;
249
250 pp::ImageData* buffer = AllocateBuffer();
251 while (buffer) {
252 producer_->DrawBuffer(buffer);
253 buffer = AllocateBuffer();
254 }
255 }
256
257 void PepperView::FlushBuffer(const SkIRect& clip_area,
258 pp::ImageData* buffer,
259 const SkRegion& region) {
260
261 // Defer drawing if the flush is already in progress.
262 if (flush_pending_) {
263 // |merge_buffer_| is guaranteed to be free here because we allocate only
264 // two buffers simultaneously. If more buffers are allowed this code should
265 // apply all pending changes to the screen.
266 DCHECK(merge_buffer_ == NULL);
267
268 merge_clip_area_ = clip_area;
269 merge_buffer_ = buffer;
270 merge_region_ = region;
271 return;
272 }
273
274 // Notify Pepper API about the updated areas and flush pixels to the screen.
275 base::Time start_time = base::Time::Now();
276
277 for (SkRegion::Iterator i(region); !i.done(); i.next()) {
278 SkIRect rect = i.rect();
279
280 // Re-clip |region| with the current clipping area |clip_area_| because
281 // the latter could change from the time the buffer was drawn.
282 if (!rect.intersect(clip_area_))
283 continue;
284
285 // Specify the rectangle coordinates relative to the clipping area.
286 rect.offset(-clip_area.left(), -clip_area.top());
287
288 // Pepper Graphics 2D has a strange and badly documented API that the
289 // point here is the offset from the source rect. Why?
290 graphics2d_.PaintImageData(
291 *buffer,
292 pp::Point(clip_area.left(), clip_area.top()),
293 pp::Rect(rect.left(), rect.top(), rect.width(), rect.height()));
294 }
295
296 // Notify the producer that some parts of the region weren't painted because
297 // the clipping area has changed already.
298 if (clip_area != clip_area_) {
299 SkRegion not_painted = region;
300 not_painted.op(clip_area_, SkRegion::kDifference_Op);
301 if (!not_painted.isEmpty()) {
302 producer_->InvalidateRegion(not_painted);
87 } 303 }
88 304 }
89 // For ReplaceContents, make sure the image size matches the device context 305
90 // size! Otherwise, this will just silently do nothing. 306 // Flush the updated areas to the screen.
91 graphics2d_.ReplaceContents(&image);
92 FlushGraphics(base::Time::Now());
93 } else {
94 // TODO(ajwong): We need to keep a backing store image of the host screen
95 // that has the data here which can be redrawn.
96 return;
97 }
98 }
99
100 void PepperView::SetHostSize(const SkISize& host_size) {
101 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
102
103 if (host_size_ == host_size)
104 return;
105
106 host_size_ = host_size;
107
108 // Submit an update of desktop size to Javascript.
109 instance_->SetDesktopSize(host_size.width(), host_size.height());
110 }
111
112 void PepperView::PaintFrame(media::VideoFrame* frame, const SkRegion& region) {
113 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
114
115 SetHostSize(SkISize::Make(frame->width(), frame->height()));
116
117 if (!backing_store_.get() || backing_store_->is_null()) {
118 LOG(ERROR) << "Backing store is not available.";
119 return;
120 }
121
122 base::Time start_time = base::Time::Now();
123
124 // Copy updated regions to the backing store and then paint the regions.
125 bool changes_made = false;
126 for (SkRegion::Iterator i(region); !i.done(); i.next())
127 changes_made |= PaintRect(frame, i.rect());
128
129 if (changes_made)
130 FlushGraphics(start_time);
131 }
132
133 bool PepperView::PaintRect(media::VideoFrame* frame, const SkIRect& r) {
134 const uint8* frame_data = frame->data(media::VideoFrame::kRGBPlane);
135 const int kFrameStride = frame->stride(media::VideoFrame::kRGBPlane);
136 const int kBytesPerPixel = GetBytesPerPixel(media::VideoFrame::RGB32);
137
138 pp::Size backing_store_size = backing_store_->size();
139 SkIRect rect(r);
140 if (!rect.intersect(SkIRect::MakeWH(backing_store_size.width(),
141 backing_store_size.height()))) {
142 return false;
143 }
144
145 const uint8* in =
146 frame_data +
147 kFrameStride * rect.fTop + // Y offset.
148 kBytesPerPixel * rect.fLeft; // X offset.
149 uint8* out =
150 reinterpret_cast<uint8*>(backing_store_->data()) +
151 backing_store_->stride() * rect.fTop + // Y offset.
152 kBytesPerPixel * rect.fLeft; // X offset.
153
154 // TODO(hclam): We really should eliminate this memory copy.
155 for (int j = 0; j < rect.height(); ++j) {
156 memcpy(out, in, rect.width() * kBytesPerPixel);
157 in += kFrameStride;
158 out += backing_store_->stride();
159 }
160
161 // Pepper Graphics 2D has a strange and badly documented API that the
162 // point here is the offset from the source rect. Why?
163 graphics2d_.PaintImageData(
164 *backing_store_.get(),
165 pp::Point(0, 0),
166 pp::Rect(rect.fLeft, rect.fTop, rect.width(), rect.height()));
167 return true;
168 }
169
170 void PepperView::BlankRect(pp::ImageData& image_data, const pp::Rect& rect) {
171 const int kBytesPerPixel = GetBytesPerPixel(media::VideoFrame::RGB32);
172 for (int y = rect.y(); y < rect.bottom(); y++) {
173 uint8* to = reinterpret_cast<uint8*>(image_data.data()) +
174 (y * image_data.stride()) + (rect.x() * kBytesPerPixel);
175 memset(to, 0xff, rect.width() * kBytesPerPixel);
176 }
177 }
178
179 void PepperView::FlushGraphics(base::Time paint_start) {
180 scoped_ptr<base::Closure> task( 307 scoped_ptr<base::Closure> task(
181 new base::Closure( 308 new base::Closure(
182 base::Bind(&PepperView::OnPaintDone, weak_factory_.GetWeakPtr(), 309 base::Bind(&PepperView::OnFlushDone, weak_factory_.GetWeakPtr(),
183 paint_start))); 310 start_time, buffer)));
184 311
185 // Flag needs to be set here in order to get a proper error code for Flush(). 312 // Flag needs to be set here in order to get a proper error code for Flush().
186 // Otherwise Flush() will always return PP_OK_COMPLETIONPENDING and the error 313 // Otherwise Flush() will always return PP_OK_COMPLETIONPENDING and the error
187 // would be hidden. 314 // would be hidden.
188 // 315 //
189 // Note that we can also handle this by providing an actual callback which 316 // Note that we can also handle this by providing an actual callback which
190 // takes the result code. Right now everything goes to the task that doesn't 317 // takes the result code. Right now everything goes to the task that doesn't
191 // result value. 318 // result value.
192 pp::CompletionCallback pp_callback(&CompletionCallbackClosureAdapter, 319 pp::CompletionCallback pp_callback(&CompletionCallbackClosureAdapter,
193 task.get(), 320 task.get(),
194 PP_COMPLETIONCALLBACK_FLAG_OPTIONAL); 321 PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
195 int error = graphics2d_.Flush(pp_callback); 322 int error = graphics2d_.Flush(pp_callback);
196 323
197 // There is already a flush in progress so set this flag to true so that we
198 // can flush again later.
199 // |paint_start| is then discarded but this is fine because we're not aiming
200 // for precise measurement of timing, otherwise we need to keep a list of
201 // queued start time(s).
202 if (error == PP_ERROR_INPROGRESS)
203 flush_blocked_ = true;
204 else
205 flush_blocked_ = false;
206
207 // If Flush() returns asynchronously then release the task. 324 // If Flush() returns asynchronously then release the task.
208 if (error == PP_OK_COMPLETIONPENDING) 325 flush_pending_ = (error == PP_OK_COMPLETIONPENDING);
326 if (flush_pending_) {
209 ignore_result(task.release()); 327 ignore_result(task.release());
210 } 328 } else {
211 329 instance_->GetStats()->video_paint_ms()->Record(
212 void PepperView::SetSolidFill(uint32 color) { 330 (base::Time::Now() - start_time).InMilliseconds());
213 DCHECK(context_->main_message_loop()->BelongsToCurrentThread()); 331
214 332 ReturnBuffer(buffer);
215 is_static_fill_ = true; 333
216 static_fill_color_ = color; 334 // Resume painting for the buffer that was previoulsy postponed because of
217 335 // pending flush.
218 Paint(); 336 if (merge_buffer_ != NULL) {
219 } 337 buffer = merge_buffer_;
220 338 merge_buffer_ = NULL;
221 void PepperView::UnsetSolidFill() { 339 FlushBuffer(merge_clip_area_, buffer, merge_region_);
222 DCHECK(context_->main_message_loop()->BelongsToCurrentThread()); 340 }
223 341 }
224 is_static_fill_ = false; 342 }
225 } 343
226 344 void PepperView::OnFlushDone(base::Time paint_start,
227 void PepperView::SetConnectionState(protocol::ConnectionToHost::State state, 345 pp::ImageData* buffer) {
228 protocol::ConnectionToHost::Error error) { 346 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
229 DCHECK(context_->main_message_loop()->BelongsToCurrentThread()); 347 DCHECK(flush_pending_);
230 348
231 switch (state) {
232 case protocol::ConnectionToHost::CONNECTING:
233 SetSolidFill(kCreatedColor);
234 instance_->SetConnectionState(
235 ChromotingInstance::STATE_CONNECTING,
236 ConvertConnectionError(error));
237 break;
238
239 case protocol::ConnectionToHost::CONNECTED:
240 UnsetSolidFill();
241 instance_->SetConnectionState(
242 ChromotingInstance::STATE_CONNECTED,
243 ConvertConnectionError(error));
244 break;
245
246 case protocol::ConnectionToHost::CLOSED:
247 SetSolidFill(kDisconnectedColor);
248 instance_->SetConnectionState(
249 ChromotingInstance::STATE_CLOSED,
250 ConvertConnectionError(error));
251 break;
252
253 case protocol::ConnectionToHost::FAILED:
254 SetSolidFill(kFailedColor);
255 instance_->SetConnectionState(
256 ChromotingInstance::STATE_FAILED,
257 ConvertConnectionError(error));
258 break;
259 }
260 }
261
262 bool PepperView::SetViewSize(const SkISize& view_size) {
263 if (view_size_ == view_size)
264 return false;
265 view_size_ = view_size;
266
267 pp::Size pp_size = pp::Size(view_size.width(), view_size.height());
268
269 graphics2d_ = pp::Graphics2D(instance_, pp_size, true);
270 if (!instance_->BindGraphics(graphics2d_)) {
271 LOG(ERROR) << "Couldn't bind the device context.";
272 return false;
273 }
274
275 if (view_size.isEmpty())
276 return false;
277
278 // Allocate the backing store to save the desktop image.
279 if ((backing_store_.get() == NULL) ||
280 (backing_store_->size() != pp_size)) {
281 VLOG(1) << "Allocate backing store: "
282 << view_size.width() << " x " << view_size.height();
283 backing_store_.reset(
284 new pp::ImageData(instance_, pp::ImageData::GetNativeImageDataFormat(),
285 pp_size, false));
286 DCHECK(backing_store_.get() && !backing_store_->is_null())
287 << "Not enough memory for backing store.";
288 }
289 return true;
290 }
291
292 void PepperView::AllocateFrame(media::VideoFrame::Format format,
293 const SkISize& size,
294 scoped_refptr<media::VideoFrame>* frame_out,
295 const base::Closure& done) {
296 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
297
298 *frame_out = media::VideoFrame::CreateFrame(
299 media::VideoFrame::RGB32, size.width(), size.height(),
300 base::TimeDelta(), base::TimeDelta());
301 (*frame_out)->AddRef();
302 done.Run();
303 }
304
305 void PepperView::ReleaseFrame(media::VideoFrame* frame) {
306 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
307
308 if (frame)
309 frame->Release();
310 }
311
312 void PepperView::OnPartialFrameOutput(media::VideoFrame* frame,
313 SkRegion* region,
314 const base::Closure& done) {
315 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
316
317 // TODO(ajwong): Clean up this API to be async so we don't need to use a
318 // member variable as a hack.
319 PaintFrame(frame, *region);
320 done.Run();
321 }
322
323 void PepperView::OnPaintDone(base::Time paint_start) {
324 DCHECK(context_->main_message_loop()->BelongsToCurrentThread());
325 instance_->GetStats()->video_paint_ms()->Record( 349 instance_->GetStats()->video_paint_ms()->Record(
326 (base::Time::Now() - paint_start).InMilliseconds()); 350 (base::Time::Now() - paint_start).InMilliseconds());
327 351
328 // If the last flush failed because there was already another one in progress 352 flush_pending_ = false;
329 // then we perform the flush now. 353 ReturnBuffer(buffer);
330 if (flush_blocked_) 354
331 FlushGraphics(base::Time::Now()); 355 // Resume painting for the buffer that was previoulsy postponed because of
332 return; 356 // pending flush.
357 if (merge_buffer_ != NULL) {
358 buffer = merge_buffer_;
359 merge_buffer_ = NULL;
360 FlushBuffer(merge_clip_area_, buffer, merge_region_);
361 }
333 } 362 }
334 363
335 } // namespace remoting 364 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/client/plugin/pepper_view.h ('k') | remoting/client/rectangle_update_decoder.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698