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

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: 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
20 using remoting::protocol::ChannelConfig; 21 using remoting::protocol::ChannelConfig;
21 using remoting::protocol::SessionConfig; 22 using remoting::protocol::SessionConfig;
22 23
23 namespace remoting { 24 namespace remoting {
24 25
25 RectangleUpdateDecoder::RectangleUpdateDecoder( 26 RectangleUpdateDecoder::RectangleUpdateDecoder(
26 base::MessageLoopProxy* message_loop, FrameConsumer* consumer) 27 base::MessageLoopProxy* message_loop, FrameConsumer* consumer)
27 : message_loop_(message_loop), 28 : message_loop_(message_loop),
28 consumer_(consumer), 29 consumer_(consumer),
29 screen_size_(SkISize::Make(0, 0)), 30 screen_size_(SkISize::Make(0, 0)),
30 clip_rect_(SkIRect::MakeEmpty()), 31 update_pending_(false),
31 decoder_needs_reset_(false) { 32 view_size_(SkISize::Make(0, 0)),
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;
Wez 2012/02/07 01:56:31 So we really need to reset the decoder on host res
alexeypa (please no reviews) 2012/02/15 23:06:22 I don't know but I'd like to avoid adding more cha
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);
86 if (frame_)
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(); 82 decoder_->Reset();
118 decoder_->Initialize(frame_); 83 decoder_->Initialize(screen_size_);
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 SubmitToConsumer();
130 } 94 }
131 95
132 void RectangleUpdateDecoder::SetOutputSize(const SkISize& size) {
133 if (!message_loop_->BelongsToCurrentThread()) {
134 message_loop_->PostTask(
135 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSize,
136 this, size));
137 return;
138 }
139
140 // TODO(wez): Refresh the frame only if the ratio has changed.
141 if (frame_) {
142 SkIRect frame_rect = SkIRect::MakeWH(frame_->width(), frame_->height());
143 refresh_region_.op(frame_rect, SkRegion::kUnion_Op);
144 }
145
146 // TODO(hclam): If the scale ratio has changed we should reallocate a
147 // VideoFrame of different size. However if the scale ratio is always
148 // smaller than 1.0 we can use the same video frame.
149 if (decoder_.get()) {
150 decoder_->SetOutputSize(size);
151 RefreshFullFrame();
152 }
153 }
154
155 void RectangleUpdateDecoder::UpdateClipRect(const SkIRect& new_clip_rect) {
156 if (!message_loop_->BelongsToCurrentThread()) {
157 message_loop_->PostTask(
158 FROM_HERE, base::Bind(&RectangleUpdateDecoder::UpdateClipRect,
159 this, new_clip_rect));
160 return;
161 }
162
163 if (new_clip_rect == clip_rect_ || !decoder_.get())
164 return;
165
166 // TODO(wez): Only refresh newly-exposed portions of the frame.
167 if (frame_) {
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 }
178
179 void RectangleUpdateDecoder::RefreshFullFrame() { 96 void RectangleUpdateDecoder::RefreshFullFrame() {
180 if (!message_loop_->BelongsToCurrentThread()) { 97 if (!message_loop_->BelongsToCurrentThread()) {
181 message_loop_->PostTask( 98 message_loop_->PostTask(
182 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RefreshFullFrame, this)); 99 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RefreshFullFrame, this));
183 return; 100 return;
184 } 101 }
185 102
186 // If a video frame or the decoder is not allocated yet then don't 103 if (decoder_.get()) {
187 // save the refresh rectangle to avoid wasted computation. 104 SkRegion region;
188 if (!frame_ || !decoder_.get()) 105 region.op(SkIRect::MakeSize(screen_size_), SkRegion::kUnion_Op);
189 return; 106 decoder_->UpdateRegion(region);
190 107 SubmitToConsumer();
191 SkIRect frame_rect = SkIRect::MakeWH(frame_->width(), frame_->height()); 108 }
192 refresh_region_.op(frame_rect, SkRegion::kUnion_Op);
193
194 DoRefresh();
195 } 109 }
196 110
197 void RectangleUpdateDecoder::SubmitToConsumer() { 111 void RectangleUpdateDecoder::SubmitToConsumer() {
198 // A frame is not allocated yet, we can reach here because of a refresh 112 DCHECK(message_loop_->BelongsToCurrentThread());
199 // request.
200 if (!frame_)
201 return;
202 113
203 SkRegion* dirty_region = new SkRegion; 114 if (!update_pending_) {
204 decoder_->GetUpdatedRegion(dirty_region); 115 // Make sure OnFrameReady() will not be called again until OnPaintFrame()
205 116 // is invoked.
206 consumer_->OnPartialFrameOutput(frame_, dirty_region, base::Bind( 117 update_pending_ = true;
207 &RectangleUpdateDecoder::OnFrameConsumed, this, dirty_region)); 118 consumer_->OnFrameReady(
119 screen_size_,
120 &view_size_, &clip_area_, &backing_store_,
121 base::Bind(&RectangleUpdateDecoder::OnPaintFrame, this));
122 }
208 } 123 }
209 124
210 void RectangleUpdateDecoder::DoRefresh() { 125 void RectangleUpdateDecoder::OnPaintFrame() {
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()) { 126 if (!message_loop_->BelongsToCurrentThread()) {
223 message_loop_->PostTask( 127 message_loop_->PostTask(
224 FROM_HERE, base::Bind(&RectangleUpdateDecoder::OnFrameConsumed, 128 FROM_HERE, base::Bind(&RectangleUpdateDecoder::OnPaintFrame,
225 this, region)); 129 this));
226 return; 130 return;
227 } 131 }
228 132
229 delete region; 133 update_pending_ = false;
230 134
231 DoRefresh(); 135 // Skip painting if the backing store is not ready yet.
136 if (backing_store_.get() && !backing_store_->is_null()) {
137 // Draw the updated region to the backing store.
138 scoped_ptr<SkRegion> output_region(new SkRegion());
139 decoder_->Draw(view_size_, clip_area_,
140 reinterpret_cast<uint8*>(backing_store_->data()),
141 backing_store_->stride(),
142 output_region.get());
143
144 // Notify the consumer that painting is done.
145 consumer_->OnPaintDone(backing_store_.Pass(), output_region.Pass());
146 } else {
147 LOG(ERROR) << "Backing store is not available.";
148 }
232 } 149 }
233 150
234 } // namespace remoting 151 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698