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

Side by Side Diff: remoting/client/rectangle_update_decoder.cc

Issue 9331003: Improving the decoder pipeline. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebased 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
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/rectangle_update_decoder.h" 5 #include "remoting/client/rectangle_update_decoder.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/callback.h" 9 #include "base/callback.h"
10 #include "base/location.h" 10 #include "base/location.h"
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "base/message_loop_proxy.h" 12 #include "base/message_loop_proxy.h"
13 #include "ppapi/cpp/image_data.h"
13 #include "remoting/base/decoder.h" 14 #include "remoting/base/decoder.h"
14 #include "remoting/base/decoder_row_based.h" 15 #include "remoting/base/decoder_row_based.h"
15 #include "remoting/base/decoder_vp8.h" 16 #include "remoting/base/decoder_vp8.h"
16 #include "remoting/base/util.h" 17 #include "remoting/base/util.h"
17 #include "remoting/client/frame_consumer.h" 18 #include "remoting/client/frame_consumer.h"
18 #include "remoting/protocol/session_config.h" 19 #include "remoting/protocol/session_config.h"
19 20
21 using base::Passed;
20 using remoting::protocol::ChannelConfig; 22 using remoting::protocol::ChannelConfig;
21 using remoting::protocol::SessionConfig; 23 using remoting::protocol::SessionConfig;
22 24
23 namespace remoting { 25 namespace remoting {
24 26
25 RectangleUpdateDecoder::RectangleUpdateDecoder( 27 RectangleUpdateDecoder::RectangleUpdateDecoder(
26 base::MessageLoopProxy* message_loop, FrameConsumer* consumer) 28 base::MessageLoopProxy* message_loop, FrameConsumer* consumer)
27 : message_loop_(message_loop), 29 : message_loop_(message_loop),
28 consumer_(consumer), 30 consumer_(consumer),
29 screen_size_(SkISize::Make(0, 0)), 31 screen_size_(SkISize::Make(0, 0)),
30 clip_rect_(SkIRect::MakeEmpty()), 32 view_size_(SkISize::Make(0, 0)),
31 decoder_needs_reset_(false) { 33 clip_area_(SkIRect::MakeEmpty()) {
32 } 34 }
33 35
34 RectangleUpdateDecoder::~RectangleUpdateDecoder() { 36 RectangleUpdateDecoder::~RectangleUpdateDecoder() {
35 } 37 }
36 38
37 void RectangleUpdateDecoder::Initialize(const SessionConfig& config) { 39 void RectangleUpdateDecoder::Initialize(const SessionConfig& config) {
38 // Initialize decoder based on the selected codec. 40 // Initialize decoder based on the selected codec.
39 ChannelConfig::Codec codec = config.video_config().codec; 41 ChannelConfig::Codec codec = config.video_config().codec;
40 if (codec == ChannelConfig::CODEC_VERBATIM) { 42 if (codec == ChannelConfig::CODEC_VERBATIM) {
41 decoder_.reset(DecoderRowBased::CreateVerbatimDecoder()); 43 decoder_.reset(DecoderRowBased::CreateVerbatimDecoder());
42 } else if (codec == ChannelConfig::CODEC_ZIP) { 44 } else if (codec == ChannelConfig::CODEC_ZIP) {
43 decoder_.reset(DecoderRowBased::CreateZlibDecoder()); 45 decoder_.reset(DecoderRowBased::CreateZlibDecoder());
44 } else if (codec == ChannelConfig::CODEC_VP8) { 46 } else if (codec == ChannelConfig::CODEC_VP8) {
45 decoder_.reset(new DecoderVp8()); 47 decoder_.reset(new DecoderVp8());
46 } else { 48 } else {
47 NOTREACHED() << "Invalid Encoding found: " << codec; 49 NOTREACHED() << "Invalid Encoding found: " << codec;
48 } 50 }
49 } 51 }
50 52
51 void RectangleUpdateDecoder::DecodePacket(const VideoPacket* packet, 53 void RectangleUpdateDecoder::DecodePacket(const VideoPacket* packet,
52 const base::Closure& done) { 54 const base::Closure& done) {
53 if (!message_loop_->BelongsToCurrentThread()) { 55 if (!message_loop_->BelongsToCurrentThread()) {
54 message_loop_->PostTask( 56 message_loop_->PostTask(
55 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DecodePacket, 57 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DecodePacket,
56 this, packet, done)); 58 this, packet, done));
57 return; 59 return;
58 } 60 }
59 AllocateFrame(packet, done);
60 }
61 61
62 void RectangleUpdateDecoder::AllocateFrame(const VideoPacket* packet,
63 const base::Closure& done) {
64 if (!message_loop_->BelongsToCurrentThread()) {
65 message_loop_->PostTask(
66 FROM_HERE, base::Bind(&RectangleUpdateDecoder::AllocateFrame,
67 this, packet, done));
68 return;
69 }
70 base::ScopedClosureRunner done_runner(done); 62 base::ScopedClosureRunner done_runner(done);
63 bool decoder_needs_reset = false;
71 64
72 // If the packet includes a screen size, store it. 65 // If the packet includes a screen size, store it.
73 if (packet->format().has_screen_width() && 66 if (packet->format().has_screen_width() &&
74 packet->format().has_screen_height()) { 67 packet->format().has_screen_height()) {
75 screen_size_.set(packet->format().screen_width(), 68 SkISize screen_size = SkISize::Make(packet->format().screen_width(),
76 packet->format().screen_height()); 69 packet->format().screen_height());
70 if (screen_size_ != screen_size) {
71 screen_size_ = screen_size;
72 decoder_needs_reset = true;
73 }
77 } 74 }
78 75
79 // If we've never seen a screen size, ignore the packet. 76 // If we've never seen a screen size, ignore the packet.
80 if (screen_size_.isZero()) { 77 if (screen_size_.isZero()) {
81 return; 78 return;
82 } 79 }
83 80
84 // Ensure the output frame is the right size. 81 if (decoder_needs_reset) {
85 SkISize frame_size = SkISize::Make(0, 0); 82 decoder_->Initialize(screen_size_);
86 if (frame_) 83 consumer_->SetScreenSize(screen_size_);
87 frame_size.set(frame_->width(), frame_->height());
88
89 // Allocate a new frame, if necessary.
90 if ((!frame_) || (screen_size_ != frame_size)) {
91 if (frame_) {
92 consumer_->ReleaseFrame(frame_);
93 frame_ = NULL;
94 }
95
96 consumer_->AllocateFrame(
97 media::VideoFrame::RGB32, screen_size_, &frame_,
98 base::Bind(&RectangleUpdateDecoder::ProcessPacketData,
99 this, packet, done_runner.Release()));
100 decoder_needs_reset_ = true;
101 return;
102 }
103 ProcessPacketData(packet, done_runner.Release());
104 }
105
106 void RectangleUpdateDecoder::ProcessPacketData(
107 const VideoPacket* packet, const base::Closure& done) {
108 if (!message_loop_->BelongsToCurrentThread()) {
109 message_loop_->PostTask(
110 FROM_HERE, base::Bind(&RectangleUpdateDecoder::ProcessPacketData,
111 this, packet, done));
112 return;
113 }
114 base::ScopedClosureRunner done_runner(done);
115
116 if (decoder_needs_reset_) {
117 decoder_->Reset();
118 decoder_->Initialize(frame_);
119 decoder_needs_reset_ = false;
120 } 84 }
121 85
122 if (!decoder_->IsReadyForData()) { 86 if (!decoder_->IsReadyForData()) {
123 // TODO(ajwong): This whole thing should move into an invalid state. 87 // TODO(ajwong): This whole thing should move into an invalid state.
124 LOG(ERROR) << "Decoder is unable to process data. Dropping packet."; 88 LOG(ERROR) << "Decoder is unable to process data. Dropping packet.";
125 return; 89 return;
126 } 90 }
127 91
128 if (decoder_->DecodePacket(packet) == Decoder::DECODE_DONE) 92 if (decoder_->DecodePacket(packet) == Decoder::DECODE_DONE)
129 SubmitToConsumer(); 93 DoPaint();
130 } 94 }
131 95
132 void RectangleUpdateDecoder::SetOutputSize(const SkISize& size) { 96 void RectangleUpdateDecoder::DoPaint() {
97 if (buffers_.empty())
98 return;
99
100 // Draw the invalidated region to the buffer.
101 pp::ImageData* buffer = buffers_.front();
102 SkRegion output_region;
103 decoder_->RenderFrame(view_size_, clip_area_,
104 reinterpret_cast<uint8*>(buffer->data()),
105 buffer->stride(),
106 &output_region);
107
108 // Notify the consumer that painting is done.
109 if (!output_region.isEmpty()) {
110 buffers_.pop();
111 consumer_->PaintBuffer(view_size_, clip_area_, buffer, output_region);
112 }
113 }
114
115 void RectangleUpdateDecoder::DrainQueue(const base::Closure& done) {
133 if (!message_loop_->BelongsToCurrentThread()) { 116 if (!message_loop_->BelongsToCurrentThread()) {
134 message_loop_->PostTask( 117 message_loop_->PostTask(
135 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSize, 118 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrainQueue, this, done));
136 this, size));
137 return; 119 return;
138 } 120 }
139 121
140 // TODO(wez): Refresh the frame only if the ratio has changed. 122 while (!buffers_.empty()) {
141 if (frame_) { 123 consumer_->ReturnBuffer(buffers_.front());
142 SkIRect frame_rect = SkIRect::MakeWH(frame_->width(), frame_->height()); 124 buffers_.pop();
143 refresh_region_.op(frame_rect, SkRegion::kUnion_Op);
144 } 125 }
145 126
146 // TODO(hclam): If the scale ratio has changed we should reallocate a 127 if (!done.is_null())
147 // VideoFrame of different size. However if the scale ratio is always 128 done.Run();
148 // smaller than 1.0 we can use the same video frame.
149 if (decoder_.get()) {
150 decoder_->SetOutputSize(size);
151 RefreshFullFrame();
152 }
153 } 129 }
154 130
155 void RectangleUpdateDecoder::UpdateClipRect(const SkIRect& new_clip_rect) { 131 void RectangleUpdateDecoder::EnqueueBuffer(pp::ImageData* buffer) {
156 if (!message_loop_->BelongsToCurrentThread()) { 132 if (!message_loop_->BelongsToCurrentThread()) {
157 message_loop_->PostTask( 133 message_loop_->PostTask(
158 FROM_HERE, base::Bind(&RectangleUpdateDecoder::UpdateClipRect, 134 FROM_HERE, base::Bind(&RectangleUpdateDecoder::EnqueueBuffer,
159 this, new_clip_rect)); 135 this, buffer));
160 return; 136 return;
161 } 137 }
162 138
163 if (new_clip_rect == clip_rect_ || !decoder_.get()) 139 DCHECK(clip_area_.width() <= buffer->size().width() &&
164 return; 140 clip_area_.height() <= buffer->size().height());
165 141
166 // TODO(wez): Only refresh newly-exposed portions of the frame. 142 buffers_.push(buffer);
167 if (frame_) { 143 DoPaint();
168 SkIRect frame_rect = SkIRect::MakeWH(frame_->width(), frame_->height());
169 refresh_region_.op(frame_rect, SkRegion::kUnion_Op);
170 }
171
172 clip_rect_ = new_clip_rect;
173 decoder_->SetClipRect(new_clip_rect);
174
175 // TODO(wez): Defer refresh so that multiple events can be batched.
176 DoRefresh();
177 } 144 }
178 145
179 void RectangleUpdateDecoder::RefreshFullFrame() { 146 void RectangleUpdateDecoder::Invalidate(const SkRegion& region) {
180 if (!message_loop_->BelongsToCurrentThread()) { 147 if (!message_loop_->BelongsToCurrentThread()) {
181 message_loop_->PostTask( 148 message_loop_->PostTask(
182 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RefreshFullFrame, this)); 149 FROM_HERE, base::Bind(&RectangleUpdateDecoder::Invalidate,
183 return;
184 }
185
186 // If a video frame or the decoder is not allocated yet then don't
187 // save the refresh rectangle to avoid wasted computation.
188 if (!frame_ || !decoder_.get())
189 return;
190
191 SkIRect frame_rect = SkIRect::MakeWH(frame_->width(), frame_->height());
192 refresh_region_.op(frame_rect, SkRegion::kUnion_Op);
193
194 DoRefresh();
195 }
196
197 void RectangleUpdateDecoder::SubmitToConsumer() {
198 // A frame is not allocated yet, we can reach here because of a refresh
199 // request.
200 if (!frame_)
201 return;
202
203 SkRegion* dirty_region = new SkRegion;
204 decoder_->GetUpdatedRegion(dirty_region);
205
206 consumer_->OnPartialFrameOutput(frame_, dirty_region, base::Bind(
207 &RectangleUpdateDecoder::OnFrameConsumed, this, dirty_region));
208 }
209
210 void RectangleUpdateDecoder::DoRefresh() {
211 DCHECK(message_loop_->BelongsToCurrentThread());
212
213 if (refresh_region_.isEmpty())
214 return;
215
216 decoder_->RefreshRegion(refresh_region_);
217 refresh_region_.setEmpty();
218 SubmitToConsumer();
219 }
220
221 void RectangleUpdateDecoder::OnFrameConsumed(SkRegion* region) {
222 if (!message_loop_->BelongsToCurrentThread()) {
223 message_loop_->PostTask(
224 FROM_HERE, base::Bind(&RectangleUpdateDecoder::OnFrameConsumed,
225 this, region)); 150 this, region));
226 return; 151 return;
227 } 152 }
228 153
229 delete region; 154 if (decoder_.get()) {
155 decoder_->Invalidate(view_size_, region);
156 DoPaint();
157 }
158 }
230 159
231 DoRefresh(); 160 void RectangleUpdateDecoder::SetView(const SkISize& view_size,
161 const SkIRect& clip_area) {
162 if (!message_loop_->BelongsToCurrentThread()) {
163 message_loop_->PostTask(
164 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetView,
165 this, view_size, clip_area));
166 return;
167 }
168
169 // The whole frame needs to be repainted if the scaling factor has changed.
170 // Otherwise the newly exposed parts of the frame will be automatically
171 // updated because they haven't been validated by RenderFrame() yet.
Wez 2012/02/17 23:42:17 This sentence sounds the wrong way around?
alexeypa (please no reviews) 2012/02/21 23:00:44 Yeah. I was trying to say that if the scaling is t
172 if (view_size_ != view_size && decoder_.get()) {
173 SkRegion region;
174 region.op(SkIRect::MakeSize(view_size), SkRegion::kUnion_Op);
175 decoder_->Invalidate(view_size, region);
176 }
177
178 if (view_size_ != view_size ||
179 clip_area_ != clip_area) {
180 view_size_ = view_size;
181 clip_area_ = clip_area;
182
183 // Return buffers to the consumer for reuse/reallocation.
184 while (!buffers_.empty()) {
185 consumer_->ReturnBuffer(buffers_.front());
186 buffers_.pop();
187 }
188 }
232 } 189 }
233 190
234 } // namespace remoting 191 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698