Chromium Code Reviews| 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/software_video_renderer.h" |
| 6 | |
| 7 #include <list> | |
| 6 | 8 |
| 7 #include "base/bind.h" | 9 #include "base/bind.h" |
| 8 #include "base/callback.h" | 10 #include "base/callback.h" |
| 9 #include "base/callback_helpers.h" | 11 #include "base/callback_helpers.h" |
| 10 #include "base/location.h" | 12 #include "base/location.h" |
| 11 #include "base/logging.h" | 13 #include "base/logging.h" |
| 12 #include "base/single_thread_task_runner.h" | 14 #include "base/single_thread_task_runner.h" |
| 13 #include "remoting/base/util.h" | 15 #include "remoting/base/util.h" |
| 14 #include "remoting/client/frame_consumer.h" | 16 #include "remoting/client/frame_consumer.h" |
| 15 #include "remoting/codec/video_decoder.h" | 17 #include "remoting/codec/video_decoder.h" |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 67 } | 69 } |
| 68 | 70 |
| 69 virtual const webrtc::DesktopRegion* GetImageShape() OVERRIDE { | 71 virtual const webrtc::DesktopRegion* GetImageShape() OVERRIDE { |
| 70 return parent_->GetImageShape(); | 72 return parent_->GetImageShape(); |
| 71 } | 73 } |
| 72 | 74 |
| 73 private: | 75 private: |
| 74 scoped_ptr<VideoDecoder> parent_; | 76 scoped_ptr<VideoDecoder> parent_; |
| 75 }; | 77 }; |
| 76 | 78 |
| 77 RectangleUpdateDecoder::RectangleUpdateDecoder( | 79 class SoftwareVideoRenderer::Core { |
| 80 public: | |
| 81 Core(scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | |
| 82 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner, | |
| 83 scoped_refptr<FrameConsumerProxy> consumer); | |
| 84 ~Core(); | |
| 85 | |
| 86 void Initialize(const protocol::SessionConfig& config); | |
| 87 | |
| 88 void DrawBuffer(webrtc::DesktopFrame* buffer); | |
|
Wez
2014/01/22 20:17:31
nit: Do you really need the blank line above this?
Sergey Ulanov
2014/01/23 01:02:43
Done.
| |
| 89 void InvalidateRegion(const webrtc::DesktopRegion& region); | |
| 90 void RequestReturnBuffers(const base::Closure& done); | |
| 91 void SetOutputSizeAndClip( | |
| 92 const webrtc::DesktopSize& view_size, | |
| 93 const webrtc::DesktopRect& clip_area); | |
| 94 | |
| 95 // Decodes the contents of |packet|. DecodePacket may keep a reference to | |
| 96 // |packet| so the |packet| must remain alive and valid until |done| is | |
| 97 // executed. | |
| 98 void DecodePacket(scoped_ptr<VideoPacket> packet, const base::Closure& done); | |
| 99 | |
| 100 private: | |
| 101 // Paints the invalidated region to the next available buffer and returns it | |
| 102 // to the consumer. | |
| 103 void SchedulePaint(); | |
| 104 void DoPaint(); | |
| 105 | |
| 106 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_; | |
| 107 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner_; | |
| 108 scoped_refptr<FrameConsumerProxy> consumer_; | |
| 109 scoped_ptr<VideoDecoder> decoder_; | |
| 110 | |
| 111 // Remote screen size in pixels. | |
| 112 webrtc::DesktopSize source_size_; | |
| 113 | |
| 114 // Vertical and horizontal DPI of the remote screen. | |
| 115 webrtc::DesktopVector source_dpi_; | |
| 116 | |
| 117 // The current dimensions of the frame consumer view. | |
| 118 webrtc::DesktopSize view_size_; | |
| 119 webrtc::DesktopRect clip_area_; | |
| 120 | |
| 121 // The drawing buffers supplied by the frame consumer. | |
| 122 std::list<webrtc::DesktopFrame*> buffers_; | |
| 123 | |
| 124 // Flag used to coalesce runs of SchedulePaint()s into a single DoPaint(). | |
| 125 bool paint_scheduled_; | |
| 126 | |
| 127 base::WeakPtrFactory<Core> weak_factory_; | |
| 128 }; | |
| 129 | |
| 130 SoftwareVideoRenderer::Core::Core( | |
| 78 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, | 131 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, |
| 79 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner, | 132 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner, |
| 80 scoped_refptr<FrameConsumerProxy> consumer) | 133 scoped_refptr<FrameConsumerProxy> consumer) |
| 81 : main_task_runner_(main_task_runner), | 134 : main_task_runner_(main_task_runner), |
| 82 decode_task_runner_(decode_task_runner), | 135 decode_task_runner_(decode_task_runner), |
| 83 consumer_(consumer), | 136 consumer_(consumer), |
| 84 paint_scheduled_(false), | 137 paint_scheduled_(false), |
| 85 latest_sequence_number_(0) { | 138 weak_factory_(this) { |
| 86 } | 139 } |
| 87 | 140 |
| 88 RectangleUpdateDecoder::~RectangleUpdateDecoder() { | 141 SoftwareVideoRenderer::Core::~Core() { |
| 89 } | 142 } |
| 90 | 143 |
| 91 void RectangleUpdateDecoder::Initialize(const SessionConfig& config) { | 144 void SoftwareVideoRenderer::Core::Initialize(const SessionConfig& config) { |
| 92 if (!decode_task_runner_->BelongsToCurrentThread()) { | 145 DCHECK(decode_task_runner_->BelongsToCurrentThread()); |
| 93 decode_task_runner_->PostTask( | |
| 94 FROM_HERE, base::Bind(&RectangleUpdateDecoder::Initialize, this, | |
| 95 config)); | |
| 96 return; | |
| 97 } | |
| 98 | 146 |
| 99 // Initialize decoder based on the selected codec. | 147 // Initialize decoder based on the selected codec. |
| 100 ChannelConfig::Codec codec = config.video_config().codec; | 148 ChannelConfig::Codec codec = config.video_config().codec; |
| 101 if (codec == ChannelConfig::CODEC_VERBATIM) { | 149 if (codec == ChannelConfig::CODEC_VERBATIM) { |
| 102 decoder_.reset(new VideoDecoderVerbatim()); | 150 decoder_.reset(new VideoDecoderVerbatim()); |
| 103 } else if (codec == ChannelConfig::CODEC_VP8) { | 151 } else if (codec == ChannelConfig::CODEC_VP8) { |
| 104 decoder_ = VideoDecoderVpx::CreateForVP8(); | 152 decoder_ = VideoDecoderVpx::CreateForVP8(); |
| 105 } else if (codec == ChannelConfig::CODEC_VP9) { | 153 } else if (codec == ChannelConfig::CODEC_VP9) { |
| 106 decoder_ = VideoDecoderVpx::CreateForVP9(); | 154 decoder_ = VideoDecoderVpx::CreateForVP9(); |
| 107 } else { | 155 } else { |
| 108 NOTREACHED() << "Invalid Encoding found: " << codec; | 156 NOTREACHED() << "Invalid Encoding found: " << codec; |
| 109 } | 157 } |
| 110 | 158 |
| 111 if (consumer_->GetPixelFormat() == FrameConsumer::FORMAT_RGBA) { | 159 if (consumer_->GetPixelFormat() == FrameConsumer::FORMAT_RGBA) { |
| 112 scoped_ptr<VideoDecoder> wrapper( | 160 scoped_ptr<VideoDecoder> wrapper( |
| 113 new RgbToBgrVideoDecoderFilter(decoder_.Pass())); | 161 new RgbToBgrVideoDecoderFilter(decoder_.Pass())); |
| 114 decoder_ = wrapper.Pass(); | 162 decoder_ = wrapper.Pass(); |
| 115 } | 163 } |
| 116 } | 164 } |
| 117 | 165 |
| 118 void RectangleUpdateDecoder::DecodePacket(scoped_ptr<VideoPacket> packet, | 166 void SoftwareVideoRenderer::Core::DecodePacket(scoped_ptr<VideoPacket> packet, |
| 119 const base::Closure& done) { | 167 const base::Closure& done) { |
| 120 DCHECK(decode_task_runner_->BelongsToCurrentThread()); | 168 DCHECK(decode_task_runner_->BelongsToCurrentThread()); |
| 121 | 169 |
| 122 base::ScopedClosureRunner done_runner(done); | |
| 123 | |
| 124 bool decoder_needs_reset = false; | 170 bool decoder_needs_reset = false; |
| 125 bool notify_size_or_dpi_change = false; | 171 bool notify_size_or_dpi_change = false; |
| 126 | 172 |
| 127 // If the packet includes screen size or DPI information, store them. | 173 // If the packet includes screen size or DPI information, store them. |
| 128 if (packet->format().has_screen_width() && | 174 if (packet->format().has_screen_width() && |
| 129 packet->format().has_screen_height()) { | 175 packet->format().has_screen_height()) { |
| 130 webrtc::DesktopSize source_size(packet->format().screen_width(), | 176 webrtc::DesktopSize source_size(packet->format().screen_width(), |
| 131 packet->format().screen_height()); | 177 packet->format().screen_height()); |
| 132 if (!source_size_.equals(source_size)) { | 178 if (!source_size_.equals(source_size)) { |
| 133 source_size_ = source_size; | 179 source_size_ = source_size; |
| 134 decoder_needs_reset = true; | 180 decoder_needs_reset = true; |
| 135 notify_size_or_dpi_change = true; | 181 notify_size_or_dpi_change = true; |
| 136 } | 182 } |
| 137 } | 183 } |
| 138 if (packet->format().has_x_dpi() && packet->format().has_y_dpi()) { | 184 if (packet->format().has_x_dpi() && packet->format().has_y_dpi()) { |
| 139 webrtc::DesktopVector source_dpi(packet->format().x_dpi(), | 185 webrtc::DesktopVector source_dpi(packet->format().x_dpi(), |
| 140 packet->format().y_dpi()); | 186 packet->format().y_dpi()); |
| 141 if (!source_dpi.equals(source_dpi_)) { | 187 if (!source_dpi.equals(source_dpi_)) { |
| 142 source_dpi_ = source_dpi; | 188 source_dpi_ = source_dpi; |
| 143 notify_size_or_dpi_change = true; | 189 notify_size_or_dpi_change = true; |
| 144 } | 190 } |
| 145 } | 191 } |
| 146 | 192 |
| 147 // If we've never seen a screen size, ignore the packet. | 193 // If we've never seen a screen size, ignore the packet. |
| 148 if (source_size_.is_empty()) | 194 if (source_size_.is_empty()) { |
| 195 main_task_runner_->PostTask(FROM_HERE, base::Bind(done)); | |
| 149 return; | 196 return; |
| 197 } | |
| 150 | 198 |
| 151 if (decoder_needs_reset) | 199 if (decoder_needs_reset) |
| 152 decoder_->Initialize(source_size_); | 200 decoder_->Initialize(source_size_); |
| 153 if (notify_size_or_dpi_change) | 201 if (notify_size_or_dpi_change) |
| 154 consumer_->SetSourceSize(source_size_, source_dpi_); | 202 consumer_->SetSourceSize(source_size_, source_dpi_); |
| 155 | 203 |
| 156 if (decoder_->DecodePacket(*packet.get())) { | 204 if (decoder_->DecodePacket(*packet.get())) { |
| 157 SchedulePaint(); | 205 SchedulePaint(); |
| 158 } else { | 206 } else { |
| 159 LOG(ERROR) << "DecodePacket() failed."; | 207 LOG(ERROR) << "DecodePacket() failed."; |
| 160 } | 208 } |
| 209 | |
| 210 main_task_runner_->PostTask(FROM_HERE, base::Bind(done)); | |
| 161 } | 211 } |
| 162 | 212 |
| 163 void RectangleUpdateDecoder::SchedulePaint() { | 213 void SoftwareVideoRenderer::Core::SchedulePaint() { |
| 214 DCHECK(decode_task_runner_->BelongsToCurrentThread()); | |
| 164 if (paint_scheduled_) | 215 if (paint_scheduled_) |
| 165 return; | 216 return; |
| 166 paint_scheduled_ = true; | 217 paint_scheduled_ = true; |
| 167 decode_task_runner_->PostTask( | 218 decode_task_runner_->PostTask( |
| 168 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DoPaint, this)); | 219 FROM_HERE, base::Bind(&SoftwareVideoRenderer::Core::DoPaint, |
| 220 weak_factory_.GetWeakPtr())); | |
| 169 } | 221 } |
| 170 | 222 |
| 171 void RectangleUpdateDecoder::DoPaint() { | 223 void SoftwareVideoRenderer::Core::DoPaint() { |
| 224 DCHECK(decode_task_runner_->BelongsToCurrentThread()); | |
| 172 DCHECK(paint_scheduled_); | 225 DCHECK(paint_scheduled_); |
| 173 paint_scheduled_ = false; | 226 paint_scheduled_ = false; |
| 174 | 227 |
| 175 // If the view size is empty or we have no output buffers ready, return. | 228 // If the view size is empty or we have no output buffers ready, return. |
| 176 if (buffers_.empty() || view_size_.is_empty()) | 229 if (buffers_.empty() || view_size_.is_empty()) |
| 177 return; | 230 return; |
| 178 | 231 |
| 179 // If no Decoder is initialized, or the host dimensions are empty, return. | 232 // If no Decoder is initialized, or the host dimensions are empty, return. |
| 180 if (!decoder_.get() || source_size_.is_empty()) | 233 if (!decoder_.get() || source_size_.is_empty()) |
| 181 return; | 234 return; |
| 182 | 235 |
| 183 // Draw the invalidated region to the buffer. | 236 // Draw the invalidated region to the buffer. |
| 184 webrtc::DesktopFrame* buffer = buffers_.front(); | 237 webrtc::DesktopFrame* buffer = buffers_.front(); |
| 185 webrtc::DesktopRegion output_region; | 238 webrtc::DesktopRegion output_region; |
| 186 decoder_->RenderFrame(view_size_, clip_area_, | 239 decoder_->RenderFrame(view_size_, clip_area_, |
| 187 buffer->data(), | 240 buffer->data(), buffer->stride(), &output_region); |
| 188 buffer->stride(), | |
| 189 &output_region); | |
| 190 | 241 |
| 191 // Notify the consumer that painting is done. | 242 // Notify the consumer that painting is done. |
| 192 if (!output_region.is_empty()) { | 243 if (!output_region.is_empty()) { |
| 193 buffers_.pop_front(); | 244 buffers_.pop_front(); |
| 194 consumer_->ApplyBuffer(view_size_, clip_area_, buffer, output_region); | 245 consumer_->ApplyBuffer(view_size_, clip_area_, buffer, output_region, |
| 246 *decoder_->GetImageShape()); | |
| 195 } | 247 } |
| 196 } | 248 } |
| 197 | 249 |
| 198 void RectangleUpdateDecoder::RequestReturnBuffers(const base::Closure& done) { | 250 void SoftwareVideoRenderer::Core::RequestReturnBuffers( |
| 199 if (!decode_task_runner_->BelongsToCurrentThread()) { | 251 const base::Closure& done) { |
| 200 decode_task_runner_->PostTask( | 252 DCHECK(decode_task_runner_->BelongsToCurrentThread()); |
| 201 FROM_HERE, base::Bind(&RectangleUpdateDecoder::RequestReturnBuffers, | |
| 202 this, done)); | |
| 203 return; | |
| 204 } | |
| 205 | 253 |
| 206 while (!buffers_.empty()) { | 254 while (!buffers_.empty()) { |
| 207 consumer_->ReturnBuffer(buffers_.front()); | 255 consumer_->ReturnBuffer(buffers_.front()); |
| 208 buffers_.pop_front(); | 256 buffers_.pop_front(); |
| 209 } | 257 } |
| 210 | 258 |
| 211 if (!done.is_null()) | 259 if (!done.is_null()) |
| 212 done.Run(); | 260 done.Run(); |
| 213 } | 261 } |
| 214 | 262 |
| 215 void RectangleUpdateDecoder::DrawBuffer(webrtc::DesktopFrame* buffer) { | 263 void SoftwareVideoRenderer::Core::DrawBuffer(webrtc::DesktopFrame* buffer) { |
| 216 if (!decode_task_runner_->BelongsToCurrentThread()) { | 264 DCHECK(decode_task_runner_->BelongsToCurrentThread()); |
| 217 decode_task_runner_->PostTask( | |
| 218 FROM_HERE, base::Bind(&RectangleUpdateDecoder::DrawBuffer, | |
| 219 this, buffer)); | |
| 220 return; | |
| 221 } | |
| 222 | |
| 223 DCHECK(clip_area_.width() <= buffer->size().width() && | 265 DCHECK(clip_area_.width() <= buffer->size().width() && |
| 224 clip_area_.height() <= buffer->size().height()); | 266 clip_area_.height() <= buffer->size().height()); |
| 225 | 267 |
| 226 buffers_.push_back(buffer); | 268 buffers_.push_back(buffer); |
| 227 SchedulePaint(); | 269 SchedulePaint(); |
| 228 } | 270 } |
| 229 | 271 |
| 230 void RectangleUpdateDecoder::InvalidateRegion( | 272 void SoftwareVideoRenderer::Core::InvalidateRegion( |
| 231 const webrtc::DesktopRegion& region) { | 273 const webrtc::DesktopRegion& region) { |
| 232 if (!decode_task_runner_->BelongsToCurrentThread()) { | 274 DCHECK(decode_task_runner_->BelongsToCurrentThread()); |
| 233 decode_task_runner_->PostTask( | |
| 234 FROM_HERE, base::Bind(&RectangleUpdateDecoder::InvalidateRegion, | |
| 235 this, region)); | |
| 236 return; | |
| 237 } | |
| 238 | 275 |
| 239 if (decoder_.get()) { | 276 if (decoder_.get()) { |
| 240 decoder_->Invalidate(view_size_, region); | 277 decoder_->Invalidate(view_size_, region); |
| 241 SchedulePaint(); | 278 SchedulePaint(); |
| 242 } | 279 } |
| 243 } | 280 } |
| 244 | 281 |
| 245 void RectangleUpdateDecoder::SetOutputSizeAndClip( | 282 void SoftwareVideoRenderer::Core::SetOutputSizeAndClip( |
| 246 const webrtc::DesktopSize& view_size, | 283 const webrtc::DesktopSize& view_size, |
| 247 const webrtc::DesktopRect& clip_area) { | 284 const webrtc::DesktopRect& clip_area) { |
| 248 if (!decode_task_runner_->BelongsToCurrentThread()) { | 285 DCHECK(decode_task_runner_->BelongsToCurrentThread()); |
| 249 decode_task_runner_->PostTask( | |
| 250 FROM_HERE, base::Bind(&RectangleUpdateDecoder::SetOutputSizeAndClip, | |
| 251 this, view_size, clip_area)); | |
| 252 return; | |
| 253 } | |
| 254 | 286 |
| 255 // The whole frame needs to be repainted if the scaling factor has changed. | 287 // The whole frame needs to be repainted if the scaling factor has changed. |
| 256 if (!view_size_.equals(view_size) && decoder_.get()) { | 288 if (!view_size_.equals(view_size) && decoder_.get()) { |
| 257 webrtc::DesktopRegion region; | 289 webrtc::DesktopRegion region; |
| 258 region.AddRect(webrtc::DesktopRect::MakeSize(view_size)); | 290 region.AddRect(webrtc::DesktopRect::MakeSize(view_size)); |
| 259 decoder_->Invalidate(view_size, region); | 291 decoder_->Invalidate(view_size, region); |
| 260 } | 292 } |
| 261 | 293 |
| 262 if (!view_size_.equals(view_size) || | 294 if (!view_size_.equals(view_size) || |
| 263 !clip_area_.equals(clip_area)) { | 295 !clip_area_.equals(clip_area)) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 274 i = buffers_.erase(i); | 306 i = buffers_.erase(i); |
| 275 } else { | 307 } else { |
| 276 ++i; | 308 ++i; |
| 277 } | 309 } |
| 278 } | 310 } |
| 279 | 311 |
| 280 SchedulePaint(); | 312 SchedulePaint(); |
| 281 } | 313 } |
| 282 } | 314 } |
| 283 | 315 |
| 284 const webrtc::DesktopRegion* RectangleUpdateDecoder::GetBufferShape() { | 316 SoftwareVideoRenderer::SoftwareVideoRenderer( |
| 285 return decoder_->GetImageShape(); | 317 scoped_refptr<base::SingleThreadTaskRunner> main_task_runner, |
| 318 scoped_refptr<base::SingleThreadTaskRunner> decode_task_runner, | |
| 319 scoped_refptr<FrameConsumerProxy> consumer) | |
| 320 : decode_task_runner_(decode_task_runner), | |
| 321 core_(new Core(main_task_runner, decode_task_runner, consumer)), | |
| 322 latest_sequence_number_(0), | |
| 323 weak_factory_(this) { | |
| 324 DCHECK(CalledOnValidThread()); | |
| 286 } | 325 } |
| 287 | 326 |
| 288 void RectangleUpdateDecoder::ProcessVideoPacket(scoped_ptr<VideoPacket> packet, | 327 SoftwareVideoRenderer::~SoftwareVideoRenderer() { |
| 328 DCHECK(CalledOnValidThread()); | |
| 329 decode_task_runner_->DeleteSoon(FROM_HERE, core_.release()); | |
| 330 } | |
| 331 | |
| 332 void SoftwareVideoRenderer::Initialize( | |
| 333 const protocol::SessionConfig& config) { | |
| 334 DCHECK(CalledOnValidThread()); | |
| 335 decode_task_runner_->PostTask( | |
| 336 FROM_HERE, base::Bind(&SoftwareVideoRenderer::Core::Initialize, | |
| 337 base::Unretained(core_.get()), config)); | |
| 338 } | |
| 339 | |
| 340 ChromotingStats* SoftwareVideoRenderer::GetStats() { | |
| 341 DCHECK(CalledOnValidThread()); | |
| 342 return &stats_; | |
| 343 } | |
| 344 | |
| 345 void SoftwareVideoRenderer::ProcessVideoPacket(scoped_ptr<VideoPacket> packet, | |
| 289 const base::Closure& done) { | 346 const base::Closure& done) { |
| 290 DCHECK(main_task_runner_->BelongsToCurrentThread()); | 347 DCHECK(CalledOnValidThread()); |
| 291 | 348 |
| 292 // If the video packet is empty then drop it. Empty packets are used to | 349 // If the video packet is empty then drop it. Empty packets are used to |
| 293 // maintain activity on the network. | 350 // maintain activity on the network. |
| 294 if (!packet->has_data() || packet->data().size() == 0) { | 351 if (!packet->has_data() || packet->data().size() == 0) { |
| 295 done.Run(); | 352 done.Run(); |
| 296 return; | 353 return; |
| 297 } | 354 } |
| 298 | 355 |
| 299 // Add one frame to the counter. | 356 // Add one frame to the counter. |
| 300 stats_.video_frame_rate()->Record(1); | 357 stats_.video_frame_rate()->Record(1); |
| 301 | 358 |
| 302 // Record other statistics received from host. | 359 // Record other statistics received from host. |
| 303 stats_.video_bandwidth()->Record(packet->data().size()); | 360 stats_.video_bandwidth()->Record(packet->data().size()); |
| 304 if (packet->has_capture_time_ms()) | 361 if (packet->has_capture_time_ms()) |
| 305 stats_.video_capture_ms()->Record(packet->capture_time_ms()); | 362 stats_.video_capture_ms()->Record(packet->capture_time_ms()); |
| 306 if (packet->has_encode_time_ms()) | 363 if (packet->has_encode_time_ms()) |
| 307 stats_.video_encode_ms()->Record(packet->encode_time_ms()); | 364 stats_.video_encode_ms()->Record(packet->encode_time_ms()); |
| 308 if (packet->has_client_sequence_number() && | 365 if (packet->has_client_sequence_number() && |
| 309 packet->client_sequence_number() > latest_sequence_number_) { | 366 packet->client_sequence_number() > latest_sequence_number_) { |
| 310 latest_sequence_number_ = packet->client_sequence_number(); | 367 latest_sequence_number_ = packet->client_sequence_number(); |
| 311 base::TimeDelta round_trip_latency = | 368 base::TimeDelta round_trip_latency = |
| 312 base::Time::Now() - | 369 base::Time::Now() - |
| 313 base::Time::FromInternalValue(packet->client_sequence_number()); | 370 base::Time::FromInternalValue(packet->client_sequence_number()); |
| 314 stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds()); | 371 stats_.round_trip_ms()->Record(round_trip_latency.InMilliseconds()); |
| 315 } | 372 } |
| 316 | 373 |
| 317 // Measure the latency between the last packet being received and presented. | 374 // Measure the latency between the last packet being received and presented. |
| 318 base::Time decode_start = base::Time::Now(); | 375 base::Time decode_start = base::Time::Now(); |
| 319 | 376 |
| 320 base::Closure decode_done = base::Bind( | 377 base::Closure decode_done = base::Bind(&SoftwareVideoRenderer::OnPacketDone, |
| 321 &RectangleUpdateDecoder::OnPacketDone, this, decode_start, done); | 378 weak_factory_.GetWeakPtr(), |
| 379 decode_start, done); | |
| 322 | 380 |
| 323 decode_task_runner_->PostTask(FROM_HERE, base::Bind( | 381 decode_task_runner_->PostTask(FROM_HERE, base::Bind( |
| 324 &RectangleUpdateDecoder::DecodePacket, this, | 382 &SoftwareVideoRenderer::Core::DecodePacket, |
| 325 base::Passed(&packet), decode_done)); | 383 base::Unretained(core_.get()), base::Passed(&packet), decode_done)); |
| 326 } | 384 } |
| 327 | 385 |
| 328 void RectangleUpdateDecoder::OnPacketDone(base::Time decode_start, | 386 void SoftwareVideoRenderer::DrawBuffer(webrtc::DesktopFrame* buffer) { |
| 387 decode_task_runner_->PostTask( | |
| 388 FROM_HERE, base::Bind(&SoftwareVideoRenderer::Core::DrawBuffer, | |
| 389 base::Unretained(core_.get()), buffer)); | |
| 390 } | |
| 391 | |
| 392 void SoftwareVideoRenderer::InvalidateRegion( | |
| 393 const webrtc::DesktopRegion& region) { | |
| 394 decode_task_runner_->PostTask( | |
| 395 FROM_HERE, base::Bind(&SoftwareVideoRenderer::Core::InvalidateRegion, | |
| 396 base::Unretained(core_.get()), region)); | |
| 397 } | |
| 398 | |
| 399 void SoftwareVideoRenderer::RequestReturnBuffers(const base::Closure& done) { | |
| 400 decode_task_runner_->PostTask( | |
| 401 FROM_HERE, | |
| 402 base::Bind(&SoftwareVideoRenderer::Core::RequestReturnBuffers, | |
| 403 base::Unretained(core_.get()), done)); | |
| 404 } | |
| 405 | |
| 406 void SoftwareVideoRenderer::SetOutputSizeAndClip( | |
| 407 const webrtc::DesktopSize& view_size, | |
| 408 const webrtc::DesktopRect& clip_area) { | |
| 409 decode_task_runner_->PostTask( | |
| 410 FROM_HERE, | |
| 411 base::Bind(&SoftwareVideoRenderer::Core::SetOutputSizeAndClip, | |
| 412 base::Unretained(core_.get()), view_size, clip_area)); | |
| 413 } | |
| 414 | |
| 415 void SoftwareVideoRenderer::OnPacketDone(base::Time decode_start, | |
| 329 const base::Closure& done) { | 416 const base::Closure& done) { |
| 330 if (!main_task_runner_->BelongsToCurrentThread()) { | 417 DCHECK(CalledOnValidThread()); |
| 331 main_task_runner_->PostTask(FROM_HERE, base::Bind( | |
| 332 &RectangleUpdateDecoder::OnPacketDone, this, | |
| 333 decode_start, done)); | |
| 334 return; | |
| 335 } | |
| 336 | 418 |
| 337 // Record the latency between the packet being received and presented. | 419 // Record the latency between the packet being received and presented. |
| 338 stats_.video_decode_ms()->Record( | 420 stats_.video_decode_ms()->Record( |
| 339 (base::Time::Now() - decode_start).InMilliseconds()); | 421 (base::Time::Now() - decode_start).InMilliseconds()); |
| 340 | 422 |
| 341 done.Run(); | 423 done.Run(); |
| 342 } | 424 } |
| 343 | 425 |
| 344 ChromotingStats* RectangleUpdateDecoder::GetStats() { | |
| 345 DCHECK(main_task_runner_->BelongsToCurrentThread()); | |
| 346 return &stats_; | |
| 347 } | |
| 348 | |
| 349 } // namespace remoting | 426 } // namespace remoting |
| OLD | NEW |