OLD | NEW |
---|---|
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 |
OLD | NEW |