OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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/logging.h" | 8 #include "base/logging.h" |
8 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
9 #include "remoting/base/decoder.h" | 10 #include "remoting/base/decoder.h" |
10 #include "remoting/base/decoder_row_based.h" | 11 #include "remoting/base/decoder_row_based.h" |
11 #include "remoting/base/decoder_vp8.h" | 12 #include "remoting/base/decoder_vp8.h" |
12 #include "remoting/base/util.h" | 13 #include "remoting/base/util.h" |
13 #include "remoting/client/frame_consumer.h" | 14 #include "remoting/client/frame_consumer.h" |
14 #include "remoting/protocol/session_config.h" | 15 #include "remoting/protocol/session_config.h" |
15 | 16 |
16 using remoting::protocol::ChannelConfig; | 17 using remoting::protocol::ChannelConfig; |
17 using remoting::protocol::SessionConfig; | 18 using remoting::protocol::SessionConfig; |
18 | 19 |
19 namespace remoting { | 20 namespace remoting { |
20 | 21 |
21 class PartialFrameCleanup : public Task { | 22 class PartialFrameCleanup |
23 : public base::RefCountedThreadSafe<PartialFrameCleanup> { | |
22 public: | 24 public: |
23 PartialFrameCleanup(media::VideoFrame* frame, RectVector* rects, | 25 PartialFrameCleanup(media::VideoFrame* frame, RectVector* rects, |
24 RectangleUpdateDecoder* decoder) | 26 RectangleUpdateDecoder* decoder) |
25 : frame_(frame), rects_(rects), decoder_(decoder) { | 27 : frame_(frame), rects_(rects), decoder_(decoder) { |
26 } | 28 } |
29 virtual ~PartialFrameCleanup() { | |
30 } | |
27 | 31 |
28 virtual void Run() { | 32 void Run() { |
awong
2011/11/09 21:52:44
I think this class can be replaced with just a sin
Sergey Ulanov
2011/11/09 22:09:22
Just removed this class and moved deletion of Rect
| |
29 delete rects_; | 33 delete rects_; |
30 frame_ = NULL; | 34 frame_ = NULL; |
31 | 35 |
32 // There maybe pending request to refresh rectangles. | 36 // There maybe pending request to refresh rectangles. |
33 decoder_->OnFrameConsumed(); | 37 decoder_->OnFrameConsumed(); |
34 decoder_ = NULL; | 38 decoder_ = NULL; |
35 } | 39 } |
36 | 40 |
37 private: | 41 private: |
38 scoped_refptr<media::VideoFrame> frame_; | 42 scoped_refptr<media::VideoFrame> frame_; |
(...skipping 23 matching lines...) Expand all Loading... | |
62 } else if (codec == ChannelConfig::CODEC_ZIP) { | 66 } else if (codec == ChannelConfig::CODEC_ZIP) { |
63 decoder_.reset(DecoderRowBased::CreateZlibDecoder()); | 67 decoder_.reset(DecoderRowBased::CreateZlibDecoder()); |
64 } else if (codec == ChannelConfig::CODEC_VP8) { | 68 } else if (codec == ChannelConfig::CODEC_VP8) { |
65 decoder_.reset(new DecoderVp8()); | 69 decoder_.reset(new DecoderVp8()); |
66 } else { | 70 } else { |
67 NOTREACHED() << "Invalid Encoding found: " << codec; | 71 NOTREACHED() << "Invalid Encoding found: " << codec; |
68 } | 72 } |
69 } | 73 } |
70 | 74 |
71 void RectangleUpdateDecoder::DecodePacket(const VideoPacket* packet, | 75 void RectangleUpdateDecoder::DecodePacket(const VideoPacket* packet, |
72 Task* done) { | 76 const base::Closure& done) { |
73 if (message_loop_ != MessageLoop::current()) { | 77 if (message_loop_ != MessageLoop::current()) { |
74 message_loop_->PostTask( | 78 message_loop_->PostTask( |
75 FROM_HERE, | 79 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DecodePacket, |
76 NewRunnableMethod(this, | 80 this, packet, done)); |
77 &RectangleUpdateDecoder::DecodePacket, packet, | |
78 done)); | |
79 return; | 81 return; |
80 } | 82 } |
81 base::ScopedTaskRunner done_runner(done); | 83 AllocateFrame(packet, done); |
82 | |
83 AllocateFrame(packet, done_runner.Release()); | |
84 } | 84 } |
85 | 85 |
86 void RectangleUpdateDecoder::AllocateFrame(const VideoPacket* packet, | 86 void RectangleUpdateDecoder::AllocateFrame(const VideoPacket* packet, |
87 Task* done) { | 87 const base::Closure& done) { |
88 if (message_loop_ != MessageLoop::current()) { | 88 if (message_loop_ != MessageLoop::current()) { |
89 message_loop_->PostTask( | 89 message_loop_->PostTask( |
90 FROM_HERE, | 90 FROM_HERE, base::Bind(&RectangleUpdateDecoder::AllocateFrame, |
91 NewRunnableMethod( | 91 this, packet, done)); |
92 this, | |
93 &RectangleUpdateDecoder::AllocateFrame, packet, done)); | |
94 return; | 92 return; |
95 } | 93 } |
96 base::ScopedTaskRunner done_runner(done); | 94 base::ScopedClosureRunner done_runner(done); |
97 | 95 |
98 // Find the required frame size. | 96 // Find the required frame size. |
99 bool has_screen_size = packet->format().has_screen_width() && | 97 bool has_screen_size = packet->format().has_screen_width() && |
100 packet->format().has_screen_height(); | 98 packet->format().has_screen_height(); |
101 SkISize screen_size(SkISize::Make(packet->format().screen_width(), | 99 SkISize screen_size(SkISize::Make(packet->format().screen_width(), |
102 packet->format().screen_height())); | 100 packet->format().screen_height())); |
103 if (!has_screen_size) | 101 if (!has_screen_size) |
104 screen_size = initial_screen_size_; | 102 screen_size = initial_screen_size_; |
105 | 103 |
106 // Find the current frame size. | 104 // Find the current frame size. |
107 int width = 0; | 105 int width = 0; |
108 int height = 0; | 106 int height = 0; |
109 if (frame_) { | 107 if (frame_) { |
110 width = static_cast<int>(frame_->width()); | 108 width = static_cast<int>(frame_->width()); |
111 height = static_cast<int>(frame_->height()); | 109 height = static_cast<int>(frame_->height()); |
112 } | 110 } |
113 | 111 |
114 SkISize frame_size(SkISize::Make(width, height)); | 112 SkISize frame_size(SkISize::Make(width, height)); |
115 | 113 |
116 // Allocate a new frame, if necessary. | 114 // Allocate a new frame, if necessary. |
117 if ((!frame_) || (has_screen_size && (screen_size != frame_size))) { | 115 if ((!frame_) || (has_screen_size && (screen_size != frame_size))) { |
118 if (frame_) { | 116 if (frame_) { |
119 consumer_->ReleaseFrame(frame_); | 117 consumer_->ReleaseFrame(frame_); |
120 frame_ = NULL; | 118 frame_ = NULL; |
121 } | 119 } |
122 | 120 |
123 consumer_->AllocateFrame(media::VideoFrame::RGB32, | 121 consumer_->AllocateFrame( |
124 screen_size.width(), screen_size.height(), | 122 media::VideoFrame::RGB32, screen_size, &frame_, |
125 base::TimeDelta(), base::TimeDelta(), | 123 base::Bind(&RectangleUpdateDecoder::ProcessPacketData, |
126 &frame_, | 124 this, packet, done_runner.Release())); |
127 NewRunnableMethod(this, | |
128 &RectangleUpdateDecoder::ProcessPacketData, | |
129 packet, done_runner.Release())); | |
130 frame_is_new_ = true; | 125 frame_is_new_ = true; |
131 return; | 126 return; |
132 } | 127 } |
133 ProcessPacketData(packet, done_runner.Release()); | 128 ProcessPacketData(packet, done_runner.Release()); |
134 } | 129 } |
135 | 130 |
136 void RectangleUpdateDecoder::ProcessPacketData( | 131 void RectangleUpdateDecoder::ProcessPacketData( |
137 const VideoPacket* packet, Task* done) { | 132 const VideoPacket* packet, const base::Closure& done) { |
138 if (message_loop_ != MessageLoop::current()) { | 133 if (message_loop_ != MessageLoop::current()) { |
139 message_loop_->PostTask( | 134 message_loop_->PostTask( |
140 FROM_HERE, | 135 FROM_HERE, base::Bind(&RectangleUpdateDecoder::ProcessPacketData, |
141 NewRunnableMethod(this, | 136 this, packet, done)); |
142 &RectangleUpdateDecoder::ProcessPacketData, packet, | |
143 done)); | |
144 return; | 137 return; |
145 } | 138 } |
146 base::ScopedTaskRunner done_runner(done); | 139 base::ScopedClosureRunner done_runner(done); |
147 | 140 |
148 if (frame_is_new_) { | 141 if (frame_is_new_) { |
149 decoder_->Reset(); | 142 decoder_->Reset(); |
150 decoder_->Initialize(frame_); | 143 decoder_->Initialize(frame_); |
151 frame_is_new_ = false; | 144 frame_is_new_ = false; |
152 } | 145 } |
153 | 146 |
154 if (!decoder_->IsReadyForData()) { | 147 if (!decoder_->IsReadyForData()) { |
155 // TODO(ajwong): This whole thing should move into an invalid state. | 148 // TODO(ajwong): This whole thing should move into an invalid state. |
156 LOG(ERROR) << "Decoder is unable to process data. Dropping packet."; | 149 LOG(ERROR) << "Decoder is unable to process data. Dropping packet."; |
157 return; | 150 return; |
158 } | 151 } |
159 | 152 |
160 if (decoder_->DecodePacket(packet) == Decoder::DECODE_DONE) | 153 if (decoder_->DecodePacket(packet) == Decoder::DECODE_DONE) |
161 SubmitToConsumer(); | 154 SubmitToConsumer(); |
162 } | 155 } |
163 | 156 |
164 void RectangleUpdateDecoder::SetScaleRatios(double horizontal_ratio, | 157 void RectangleUpdateDecoder::SetScaleRatios(double horizontal_ratio, |
165 double vertical_ratio) { | 158 double vertical_ratio) { |
166 if (message_loop_ != MessageLoop::current()) { | 159 if (message_loop_ != MessageLoop::current()) { |
167 message_loop_->PostTask( | 160 message_loop_->PostTask( |
168 FROM_HERE, | 161 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetScaleRatios, |
169 NewRunnableMethod(this, | 162 this, horizontal_ratio, vertical_ratio)); |
170 &RectangleUpdateDecoder::SetScaleRatios, | |
171 horizontal_ratio, | |
172 vertical_ratio)); | |
173 return; | 163 return; |
174 } | 164 } |
175 | 165 |
176 // TODO(hclam): If the scale ratio has changed we should reallocate a | 166 // TODO(hclam): If the scale ratio has changed we should reallocate a |
177 // VideoFrame of different size. However if the scale ratio is always | 167 // VideoFrame of different size. However if the scale ratio is always |
178 // smaller than 1.0 we can use the same video frame. | 168 // smaller than 1.0 we can use the same video frame. |
179 decoder_->SetScaleRatios(horizontal_ratio, vertical_ratio); | 169 decoder_->SetScaleRatios(horizontal_ratio, vertical_ratio); |
180 } | 170 } |
181 | 171 |
182 void RectangleUpdateDecoder::UpdateClipRect(const SkIRect& new_clip_rect) { | 172 void RectangleUpdateDecoder::UpdateClipRect(const SkIRect& new_clip_rect) { |
183 if (message_loop_ != MessageLoop::current()) { | 173 if (message_loop_ != MessageLoop::current()) { |
184 message_loop_->PostTask( | 174 message_loop_->PostTask( |
185 FROM_HERE, | 175 FROM_HERE, base::Bind(&RectangleUpdateDecoder::UpdateClipRect, |
186 NewRunnableMethod( | 176 this, new_clip_rect)); |
187 this, | |
188 &RectangleUpdateDecoder::UpdateClipRect, new_clip_rect)); | |
189 return; | 177 return; |
190 } | 178 } |
191 | 179 |
192 if (new_clip_rect == clip_rect_ || !decoder_.get()) | 180 if (new_clip_rect == clip_rect_ || !decoder_.get()) |
193 return; | 181 return; |
194 | 182 |
195 // Find out the rectangles to show because of clip rect is updated. | 183 // Find out the rectangles to show because of clip rect is updated. |
196 if (new_clip_rect.fTop < clip_rect_.fTop) { | 184 if (new_clip_rect.fTop < clip_rect_.fTop) { |
197 refresh_rects_.push_back( | 185 refresh_rects_.push_back( |
198 SkIRect::MakeXYWH(new_clip_rect.fLeft, | 186 SkIRect::MakeXYWH(new_clip_rect.fLeft, |
(...skipping 27 matching lines...) Expand all Loading... | |
226 } | 214 } |
227 | 215 |
228 clip_rect_ = new_clip_rect; | 216 clip_rect_ = new_clip_rect; |
229 decoder_->SetClipRect(new_clip_rect); | 217 decoder_->SetClipRect(new_clip_rect); |
230 DoRefresh(); | 218 DoRefresh(); |
231 } | 219 } |
232 | 220 |
233 void RectangleUpdateDecoder::RefreshFullFrame() { | 221 void RectangleUpdateDecoder::RefreshFullFrame() { |
234 if (message_loop_ != MessageLoop::current()) { | 222 if (message_loop_ != MessageLoop::current()) { |
235 message_loop_->PostTask( | 223 message_loop_->PostTask( |
236 FROM_HERE, | 224 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RefreshFullFrame, this)); |
237 NewRunnableMethod(this, &RectangleUpdateDecoder::RefreshFullFrame)); | |
238 return; | 225 return; |
239 } | 226 } |
240 | 227 |
241 // If a video frame or the decoder is not allocated yet then don't | 228 // If a video frame or the decoder is not allocated yet then don't |
242 // save the refresh rectangle to avoid wasted computation. | 229 // save the refresh rectangle to avoid wasted computation. |
243 if (!frame_ || !decoder_.get()) | 230 if (!frame_ || !decoder_.get()) |
244 return; | 231 return; |
245 | 232 |
246 refresh_rects_.push_back( | 233 refresh_rects_.push_back( |
247 SkIRect::MakeWH(static_cast<int>(frame_->width()), | 234 SkIRect::MakeWH(static_cast<int>(frame_->width()), |
248 static_cast<int>(frame_->height()))); | 235 static_cast<int>(frame_->height()))); |
249 DoRefresh(); | 236 DoRefresh(); |
250 } | 237 } |
251 | 238 |
252 void RectangleUpdateDecoder::SubmitToConsumer() { | 239 void RectangleUpdateDecoder::SubmitToConsumer() { |
253 // A frame is not allocated yet, we can reach here because of a refresh | 240 // A frame is not allocated yet, we can reach here because of a refresh |
254 // request. | 241 // request. |
255 if (!frame_) | 242 if (!frame_) |
256 return; | 243 return; |
257 | 244 |
258 RectVector* dirty_rects = new RectVector(); | 245 RectVector* dirty_rects = new RectVector(); |
259 decoder_->GetUpdatedRects(dirty_rects); | 246 decoder_->GetUpdatedRects(dirty_rects); |
260 | 247 |
261 frame_is_consuming_ = true; | 248 frame_is_consuming_ = true; |
262 consumer_->OnPartialFrameOutput( | 249 consumer_->OnPartialFrameOutput( |
263 frame_, dirty_rects, | 250 frame_, dirty_rects, |
264 new PartialFrameCleanup(frame_, dirty_rects, this)); | 251 base::Bind(&PartialFrameCleanup::Run, |
252 new PartialFrameCleanup(frame_, dirty_rects, this))); | |
265 } | 253 } |
266 | 254 |
267 void RectangleUpdateDecoder::DoRefresh() { | 255 void RectangleUpdateDecoder::DoRefresh() { |
268 DCHECK_EQ(message_loop_, MessageLoop::current()); | 256 DCHECK_EQ(message_loop_, MessageLoop::current()); |
269 | 257 |
270 if (refresh_rects_.empty()) | 258 if (refresh_rects_.empty()) |
271 return; | 259 return; |
272 | 260 |
273 decoder_->RefreshRects(refresh_rects_); | 261 decoder_->RefreshRects(refresh_rects_); |
274 refresh_rects_.clear(); | 262 refresh_rects_.clear(); |
275 SubmitToConsumer(); | 263 SubmitToConsumer(); |
276 } | 264 } |
277 | 265 |
278 void RectangleUpdateDecoder::OnFrameConsumed() { | 266 void RectangleUpdateDecoder::OnFrameConsumed() { |
279 if (message_loop_ != MessageLoop::current()) { | 267 if (message_loop_ != MessageLoop::current()) { |
280 message_loop_->PostTask( | 268 message_loop_->PostTask( |
281 FROM_HERE, | 269 FROM_HERE, base::Bind(&RectangleUpdateDecoder::OnFrameConsumed, this)); |
282 NewRunnableMethod(this, &RectangleUpdateDecoder::OnFrameConsumed)); | |
283 return; | 270 return; |
284 } | 271 } |
285 | 272 |
286 frame_is_consuming_ = false; | 273 frame_is_consuming_ = false; |
287 DoRefresh(); | 274 DoRefresh(); |
288 } | 275 } |
289 | 276 |
290 } // namespace remoting | 277 } // namespace remoting |
OLD | NEW |