Linux: Depend on liberation-fonts package for RPMs.
[chromium-blink-merge.git] / remoting / client / plugin / pepper_video_renderer_2d.cc
blobafb2e76b3cc19f79bf2ee4e22cff774c2a82d6a2
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 "remoting/client/plugin/pepper_video_renderer_2d.h"
7 #include "base/bind.h"
8 #include "base/callback_helpers.h"
9 #include "base/strings/string_util.h"
10 #include "base/task_runner_util.h"
11 #include "ppapi/cpp/completion_callback.h"
12 #include "ppapi/cpp/image_data.h"
13 #include "ppapi/cpp/instance.h"
14 #include "ppapi/cpp/point.h"
15 #include "ppapi/cpp/rect.h"
16 #include "ppapi/cpp/size.h"
17 #include "remoting/base/util.h"
18 #include "remoting/client/client_context.h"
19 #include "remoting/client/software_video_renderer.h"
20 #include "remoting/proto/video.pb.h"
21 #include "remoting/protocol/performance_tracker.h"
22 #include "third_party/libyuv/include/libyuv/scale_argb.h"
23 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
25 namespace remoting {
27 namespace {
29 // DesktopFrame that wraps a supplied pp::ImageData
30 class PepperDesktopFrame : public webrtc::DesktopFrame {
31 public:
32 // Wraps the supplied ImageData.
33 explicit PepperDesktopFrame(const pp::ImageData& buffer)
34 : DesktopFrame(
35 webrtc::DesktopSize(buffer.size().width(), buffer.size().height()),
36 buffer.stride(),
37 reinterpret_cast<uint8_t*>(buffer.data()),
38 nullptr),
39 buffer_(buffer) {}
41 // Access to underlying pepper representation.
42 const pp::ImageData& buffer() const {
43 return buffer_;
46 private:
47 pp::ImageData buffer_;
50 } // namespace
52 PepperVideoRenderer2D::PepperVideoRenderer2D()
53 : callback_factory_(this),
54 weak_factory_(this) {}
56 PepperVideoRenderer2D::~PepperVideoRenderer2D() {}
58 bool PepperVideoRenderer2D::Initialize(
59 pp::Instance* instance,
60 const ClientContext& context,
61 EventHandler* event_handler,
62 protocol::PerformanceTracker* perf_tracker) {
63 DCHECK(thread_checker_.CalledOnValidThread());
64 DCHECK(!instance_);
65 DCHECK(!event_handler_);
66 DCHECK(instance);
67 DCHECK(event_handler);
69 instance_ = instance;
70 event_handler_ = event_handler;
71 software_video_renderer_.reset(new SoftwareVideoRenderer(
72 context.decode_task_runner(), this, perf_tracker));
74 return true;
77 void PepperVideoRenderer2D::OnViewChanged(const pp::View& view) {
78 DCHECK(thread_checker_.CalledOnValidThread());
80 pp::Rect pp_size = view.GetRect();
81 view_size_ = webrtc::DesktopSize(pp_size.width(), pp_size.height());
83 // Update scale if graphics2d has been initialized.
84 if (!graphics2d_.is_null() && source_size_.width() > 0) {
85 graphics2d_.SetScale(static_cast<float>(view_size_.width()) /
86 source_size_.width());
88 // Bind graphics2d_ again after changing the scale to work around
89 // crbug.com/521745 .
90 instance_->BindGraphics(graphics2d_);
91 bool result = instance_->BindGraphics(graphics2d_);
92 DCHECK(result) << "Couldn't bind the device context.";
96 void PepperVideoRenderer2D::EnableDebugDirtyRegion(bool enable) {
97 debug_dirty_region_ = enable;
100 void PepperVideoRenderer2D::OnSessionConfig(
101 const protocol::SessionConfig& config) {
102 DCHECK(thread_checker_.CalledOnValidThread());
104 software_video_renderer_->OnSessionConfig(config);
107 protocol::VideoStub* PepperVideoRenderer2D::GetVideoStub() {
108 DCHECK(thread_checker_.CalledOnValidThread());
110 return software_video_renderer_->GetVideoStub();
113 scoped_ptr<webrtc::DesktopFrame> PepperVideoRenderer2D::AllocateFrame(
114 const webrtc::DesktopSize& size) {
115 DCHECK(thread_checker_.CalledOnValidThread());
117 pp::ImageData buffer_data(instance_, PP_IMAGEDATAFORMAT_BGRA_PREMUL,
118 pp::Size(size.width(), size.height()), false);
119 return make_scoped_ptr(new PepperDesktopFrame(buffer_data));
122 void PepperVideoRenderer2D::DrawFrame(scoped_ptr<webrtc::DesktopFrame> frame,
123 const base::Closure& done) {
124 DCHECK(thread_checker_.CalledOnValidThread());
126 if (!frame_received_) {
127 event_handler_->OnVideoFirstFrameReceived();
128 frame_received_ = true;
131 bool size_changed = !source_size_.equals(frame->size());
132 if (size_changed) {
133 source_size_ = frame->size();
135 // Create a 2D rendering context with the new dimensions.
136 graphics2d_ = pp::Graphics2D(
137 instance_, pp::Size(source_size_.width(), source_size_.height()), true);
138 graphics2d_.SetScale(static_cast<float>(view_size_.width()) /
139 source_size_.width());
140 bool result = instance_->BindGraphics(graphics2d_);
141 DCHECK(result) << "Couldn't bind the device context.";
145 if (size_changed || !source_dpi_.equals(frame->dpi())) {
146 source_dpi_ = frame->dpi();
148 // Notify JavaScript of the change in source size.
149 event_handler_->OnVideoSize(source_size_, source_dpi_);
152 const webrtc::DesktopRegion* shape = frame->shape();
153 if (shape) {
154 if (!source_shape_ || !source_shape_->Equals(*shape)) {
155 source_shape_ = make_scoped_ptr(new webrtc::DesktopRegion(*shape));
156 event_handler_->OnVideoShape(source_shape_.get());
158 } else if (source_shape_) {
159 source_shape_ = nullptr;
160 event_handler_->OnVideoShape(nullptr);
163 // If Debug dirty region is enabled then emit it.
164 if (debug_dirty_region_)
165 event_handler_->OnVideoFrameDirtyRegion(frame->updated_region());
167 const pp::ImageData& image_data =
168 static_cast<PepperDesktopFrame*>(frame.get())->buffer();
169 for (webrtc::DesktopRegion::Iterator i(frame->updated_region()); !i.IsAtEnd();
170 i.Advance()) {
171 graphics2d_.PaintImageData(image_data, pp::Point(0, 0),
172 pp::Rect(i.rect().left(), i.rect().top(),
173 i.rect().width(), i.rect().height()));
176 if (!done.is_null()) {
177 pending_frames_done_callbacks_.push_back(
178 new base::ScopedClosureRunner(done));
181 need_flush_ = true;
183 Flush();
186 FrameConsumer::PixelFormat PepperVideoRenderer2D::GetPixelFormat() {
187 return FORMAT_BGRA;
190 void PepperVideoRenderer2D::Flush() {
191 DCHECK(thread_checker_.CalledOnValidThread());
193 if (flush_pending_ || !need_flush_)
194 return;
196 need_flush_ = false;
198 // Move callbacks from |pending_frames_done_callbacks_| to
199 // |flushing_frames_done_callbacks_| so the callbacks are called when flush is
200 // finished.
201 DCHECK(flushing_frames_done_callbacks_.empty());
202 flushing_frames_done_callbacks_ = pending_frames_done_callbacks_.Pass();
204 // Flush the updated areas to the screen.
205 int error = graphics2d_.Flush(
206 callback_factory_.NewCallback(&PepperVideoRenderer2D::OnFlushDone));
207 CHECK(error == PP_OK_COMPLETIONPENDING);
208 flush_pending_ = true;
211 void PepperVideoRenderer2D::OnFlushDone(int result) {
212 DCHECK(thread_checker_.CalledOnValidThread());
214 DCHECK(flush_pending_);
215 flush_pending_ = false;
217 // Call all callbacks for the frames we've just flushed.
218 flushing_frames_done_callbacks_.clear();
220 // Flush again if necessary.
221 Flush();
224 } // namespace remoting