| 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 |
| 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 screen_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 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; |
| 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); | 82 decoder_->Initialize(screen_size_); |
| 86 if (frame_) | 83 consumer_->SetScreenSize(screen_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(); |
| 111 consumer_->PaintBuffer(view_size_, clip_area_, buffer, output_region); |
| 112 } |
| 113 } |
| 114 |
| 115 void RectangleUpdateDecoder::DrainQueue(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::DrainQueue, this, done)); |
| 136 this, size)); | |
| 137 return; | 119 return; |
| 138 } | 120 } |
| 139 | 121 |
| 140 // TODO(wez): Refresh the frame only if the ratio has changed. | 122 while (!buffers_.empty()) { |
| 141 if (frame_) { | 123 consumer_->ReturnBuffer(buffers_.front()); |
| 142 SkIRect frame_rect = SkIRect::MakeWH(frame_->width(), frame_->height()); | 124 buffers_.pop(); |
| 143 refresh_region_.op(frame_rect, SkRegion::kUnion_Op); | |
| 144 } | 125 } |
| 145 | 126 |
| 146 // TODO(hclam): If the scale ratio has changed we should reallocate a | 127 if (!done.is_null()) |
| 147 // VideoFrame of different size. However if the scale ratio is always | 128 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 } | 129 } |
| 154 | 130 |
| 155 void RectangleUpdateDecoder::UpdateClipRect(const SkIRect& new_clip_rect) { | 131 void RectangleUpdateDecoder::EnqueueBuffer(pp::ImageData* buffer) { |
| 156 if (!message_loop_->BelongsToCurrentThread()) { | 132 if (!message_loop_->BelongsToCurrentThread()) { |
| 157 message_loop_->PostTask( | 133 message_loop_->PostTask( |
| 158 FROM_HERE, base::Bind(&RectangleUpdateDecoder::UpdateClipRect, | 134 FROM_HERE, base::Bind(&RectangleUpdateDecoder::EnqueueBuffer, |
| 159 this, new_clip_rect)); | 135 this, buffer)); |
| 160 return; | 136 return; |
| 161 } | 137 } |
| 162 | 138 |
| 163 if (new_clip_rect == clip_rect_ || !decoder_.get()) | 139 DCHECK(clip_area_.width() <= buffer->size().width() && |
| 164 return; | 140 clip_area_.height() <= buffer->size().height()); |
| 165 | 141 |
| 166 // TODO(wez): Only refresh newly-exposed portions of the frame. | 142 buffers_.push(buffer); |
| 167 if (frame_) { | 143 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 } | 144 } |
| 178 | 145 |
| 179 void RectangleUpdateDecoder::RefreshFullFrame() { | 146 void RectangleUpdateDecoder::Invalidate(const SkRegion& region) { |
| 180 if (!message_loop_->BelongsToCurrentThread()) { | 147 if (!message_loop_->BelongsToCurrentThread()) { |
| 181 message_loop_->PostTask( | 148 message_loop_->PostTask( |
| 182 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RefreshFullFrame, this)); | 149 FROM_HERE, base::Bind(&RectangleUpdateDecoder::Invalidate, |
| 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)); | 150 this, region)); |
| 226 return; | 151 return; |
| 227 } | 152 } |
| 228 | 153 |
| 229 delete region; | 154 if (decoder_.get()) { |
| 155 decoder_->Invalidate(view_size_, region); |
| 156 DoPaint(); |
| 157 } |
| 158 } |
| 230 | 159 |
| 231 DoRefresh(); | 160 void RectangleUpdateDecoder::SetView(const SkISize& view_size, |
| 161 const SkIRect& clip_area) { |
| 162 if (!message_loop_->BelongsToCurrentThread()) { |
| 163 message_loop_->PostTask( |
| 164 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetView, |
| 165 this, view_size, clip_area)); |
| 166 return; |
| 167 } |
| 168 |
| 169 // The whole frame needs to be repainted if the scaling factor has changed. |
| 170 // Otherwise the newly exposed parts of the frame will be automatically |
| 171 // updated because they haven't been validated by RenderFrame() yet. |
| 172 if (view_size_ != view_size && decoder_.get()) { |
| 173 SkRegion region; |
| 174 region.op(SkIRect::MakeSize(view_size), SkRegion::kUnion_Op); |
| 175 decoder_->Invalidate(view_size, region); |
| 176 } |
| 177 |
| 178 if (view_size_ != view_size || |
| 179 clip_area_ != clip_area) { |
| 180 view_size_ = view_size; |
| 181 clip_area_ = clip_area; |
| 182 |
| 183 // Return buffers to the consumer for reuse/reallocation. |
| 184 while (!buffers_.empty()) { |
| 185 consumer_->ReturnBuffer(buffers_.front()); |
| 186 buffers_.pop(); |
| 187 } |
| 188 } |
| 232 } | 189 } |
| 233 | 190 |
| 234 } // namespace remoting | 191 } // namespace remoting |
| OLD | NEW |