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

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: 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/rectangle_update_decoder.h ('k') | remoting/remoting.gyp » ('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/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 source_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 source_size = SkISize::Make(packet->format().screen_width(),
76 packet->format().screen_height()); 69 packet->format().screen_height());
70 if (source_size_ != source_size) {
71 source_size_ = source_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 (source_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(source_size_);
86 if (frame_) 83 consumer_->SetSourceSize(source_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_front();
111 consumer_->ApplyBuffer(view_size_, clip_area_, buffer, output_region);
112 }
113 }
114
115 void RectangleUpdateDecoder::RequestReturnBuffers(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::RequestReturnBuffers,
136 this, size)); 119 this, done));
137 return; 120 return;
138 } 121 }
139 122
140 // TODO(wez): Refresh the frame only if the ratio has changed. 123 while (!buffers_.empty()) {
141 if (frame_) { 124 consumer_->ReturnBuffer(buffers_.front());
142 SkIRect frame_rect = SkIRect::MakeWH(frame_->width(), frame_->height()); 125 buffers_.pop_front();
143 refresh_region_.op(frame_rect, SkRegion::kUnion_Op);
144 } 126 }
145 127
146 // TODO(hclam): If the scale ratio has changed we should reallocate a 128 if (!done.is_null())
147 // VideoFrame of different size. However if the scale ratio is always 129 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 } 130 }
154 131
155 void RectangleUpdateDecoder::UpdateClipRect(const SkIRect& new_clip_rect) { 132 void RectangleUpdateDecoder::DrawBuffer(pp::ImageData* buffer) {
156 if (!message_loop_->BelongsToCurrentThread()) { 133 if (!message_loop_->BelongsToCurrentThread()) {
157 message_loop_->PostTask( 134 message_loop_->PostTask(
158 FROM_HERE, base::Bind(&RectangleUpdateDecoder::UpdateClipRect, 135 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrawBuffer,
159 this, new_clip_rect)); 136 this, buffer));
160 return; 137 return;
161 } 138 }
162 139
163 if (new_clip_rect == clip_rect_ || !decoder_.get()) 140 DCHECK(clip_area_.width() <= buffer->size().width() &&
164 return; 141 clip_area_.height() <= buffer->size().height());
165 142
166 // TODO(wez): Only refresh newly-exposed portions of the frame. 143 buffers_.push_back(buffer);
167 if (frame_) { 144 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 } 145 }
178 146
179 void RectangleUpdateDecoder::RefreshFullFrame() { 147 void RectangleUpdateDecoder::InvalidateRegion(const SkRegion& region) {
180 if (!message_loop_->BelongsToCurrentThread()) { 148 if (!message_loop_->BelongsToCurrentThread()) {
181 message_loop_->PostTask( 149 message_loop_->PostTask(
182 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RefreshFullFrame, this)); 150 FROM_HERE, base::Bind(&RectangleUpdateDecoder::InvalidateRegion,
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)); 151 this, region));
226 return; 152 return;
227 } 153 }
228 154
229 delete region; 155 if (decoder_.get()) {
156 decoder_->Invalidate(view_size_, region);
157 DoPaint();
158 }
159 }
230 160
231 DoRefresh(); 161 void RectangleUpdateDecoder::SetOutputSizeAndClip(const SkISize& view_size,
162 const SkIRect& clip_area) {
163 if (!message_loop_->BelongsToCurrentThread()) {
164 message_loop_->PostTask(
165 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSizeAndClip,
166 this, view_size, clip_area));
167 return;
168 }
169
170 // The whole frame needs to be repainted if the scaling factor has changed.
171 if (view_size_ != view_size && decoder_.get()) {
172 SkRegion region;
173 region.op(SkIRect::MakeSize(view_size), SkRegion::kUnion_Op);
174 decoder_->Invalidate(view_size, region);
175 }
176
177 if (view_size_ != view_size ||
178 clip_area_ != clip_area) {
179 view_size_ = view_size;
180 clip_area_ = clip_area;
181
182 // Return buffers that are smaller than needed to the consumer for
183 // reuse/reallocation.
184 std::list<pp::ImageData*>::iterator i = buffers_.begin();
185 while (i != buffers_.end()) {
186 pp::Size buffer_size = (*i)->size();
187 if (buffer_size.width() < clip_area_.width() ||
188 buffer_size.height() < clip_area_.height()) {
189 consumer_->ReturnBuffer(*i);
190 i = buffers_.erase(i);
191 } else {
192 ++i;
193 }
194 }
195 }
232 } 196 }
233 197
234 } // namespace remoting 198 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/client/rectangle_update_decoder.h ('k') | remoting/remoting.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698