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