| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/codec/video_encoder_vpx.h" | 5 #include "remoting/codec/video_encoder_vpx.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | |
| 9 #include "base/logging.h" | 8 #include "base/logging.h" |
| 10 #include "base/sys_info.h" | 9 #include "base/sys_info.h" |
| 11 #include "remoting/base/util.h" | 10 #include "remoting/base/util.h" |
| 12 #include "remoting/proto/video.pb.h" | 11 #include "remoting/proto/video.pb.h" |
| 13 #include "third_party/libyuv/include/libyuv/convert_from_argb.h" | 12 #include "third_party/libyuv/include/libyuv/convert_from_argb.h" |
| 14 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 13 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| 15 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" | 14 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" |
| 16 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" | 15 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" |
| 17 | 16 |
| 18 extern "C" { | 17 extern "C" { |
| 19 #define VPX_CODEC_DISABLE_COMPAT 1 | 18 #define VPX_CODEC_DISABLE_COMPAT 1 |
| 20 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h" | 19 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h" |
| 21 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" | 20 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" |
| 22 } | 21 } |
| 23 | 22 |
| 24 namespace remoting { | 23 namespace remoting { |
| 25 | 24 |
| 26 namespace { | 25 namespace { |
| 27 | 26 |
| 28 // Name of command-line flag to enable VP9 to use I444 by default. | |
| 29 const char kEnableI444SwitchName[] = "enable-i444"; | |
| 30 | |
| 31 // Number of bytes in an RGBx pixel. | 27 // Number of bytes in an RGBx pixel. |
| 32 const int kBytesPerRgbPixel = 4; | 28 const int kBytesPerRgbPixel = 4; |
| 33 | 29 |
| 34 // Defines the dimension of a macro block. This is used to compute the active | 30 // Defines the dimension of a macro block. This is used to compute the active |
| 35 // map for the encoder. | 31 // map for the encoder. |
| 36 const int kMacroBlockSize = 16; | 32 const int kMacroBlockSize = 16; |
| 37 | 33 |
| 38 // Magic encoder profile numbers for I420 and I444 input formats. | 34 // Magic encoder profile numbers for I420 and I444 input formats. |
| 39 const int kVp9I420ProfileNumber = 0; | 35 const int kVp9I420ProfileNumber = 0; |
| 40 const int kVp9I444ProfileNumber = 1; | 36 const int kVp9I444ProfileNumber = 1; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 // Configure VP9 for I420 or I444 source frames. | 92 // Configure VP9 for I420 or I444 source frames. |
| 97 config->g_profile = | 93 config->g_profile = |
| 98 lossless_color ? kVp9I444ProfileNumber : kVp9I420ProfileNumber; | 94 lossless_color ? kVp9I444ProfileNumber : kVp9I420ProfileNumber; |
| 99 | 95 |
| 100 if (lossless_encode) { | 96 if (lossless_encode) { |
| 101 // Disable quantization entirely, putting the encoder in "lossless" mode. | 97 // Disable quantization entirely, putting the encoder in "lossless" mode. |
| 102 config->rc_min_quantizer = 0; | 98 config->rc_min_quantizer = 0; |
| 103 config->rc_max_quantizer = 0; | 99 config->rc_max_quantizer = 0; |
| 104 config->rc_end_usage = VPX_VBR; | 100 config->rc_end_usage = VPX_VBR; |
| 105 } else { | 101 } else { |
| 106 config->rc_min_quantizer = 4; | 102 // TODO(wez): Set quantization range to 4-40, once the libvpx encoder is |
| 103 // updated not to output any bits if nothing needs topping-off. |
| 104 config->rc_min_quantizer = 20; |
| 107 config->rc_max_quantizer = 30; | 105 config->rc_max_quantizer = 30; |
| 108 config->rc_end_usage = VPX_CBR; | 106 config->rc_end_usage = VPX_CBR; |
| 109 // In the absence of a good bandwidth estimator set the target bitrate to a | 107 // In the absence of a good bandwidth estimator set the target bitrate to a |
| 110 // conservative default. | 108 // conservative default. |
| 111 config->rc_target_bitrate = 500; | 109 config->rc_target_bitrate = 500; |
| 112 } | 110 } |
| 113 } | 111 } |
| 114 | 112 |
| 115 void SetVp8CodecOptions(vpx_codec_ctx_t* codec) { | 113 void SetVp8CodecOptions(vpx_codec_ctx_t* codec) { |
| 116 // CPUUSED of 16 will have the smallest CPU load. This turns off sub-pixel | 114 // CPUUSED of 16 will have the smallest CPU load. This turns off sub-pixel |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 // codec_->config.enc->g_h)); | 259 // codec_->config.enc->g_h)); |
| 262 codec_.reset(); | 260 codec_.reset(); |
| 263 } | 261 } |
| 264 } | 262 } |
| 265 | 263 |
| 266 scoped_ptr<VideoPacket> VideoEncoderVpx::Encode( | 264 scoped_ptr<VideoPacket> VideoEncoderVpx::Encode( |
| 267 const webrtc::DesktopFrame& frame) { | 265 const webrtc::DesktopFrame& frame) { |
| 268 DCHECK_LE(32, frame.size().width()); | 266 DCHECK_LE(32, frame.size().width()); |
| 269 DCHECK_LE(32, frame.size().height()); | 267 DCHECK_LE(32, frame.size().height()); |
| 270 | 268 |
| 269 if (!use_vp9_ || lossless_encode_) { |
| 270 // Neither VP8 nor VP9-lossless support top-off, so ignore unchanged frames. |
| 271 if (frame.updated_region().is_empty()) |
| 272 return nullptr; |
| 273 } else { |
| 274 // Let VP9-lossy mode top-off, by continuing to pass it unchanged frames |
| 275 // for a short while. |
| 276 if (frame.updated_region().is_empty()) { |
| 277 if (topoff_frame_count_ > 0) { |
| 278 topoff_frame_count_--; |
| 279 } else { |
| 280 return nullptr; |
| 281 } |
| 282 } else { |
| 283 topoff_frame_count_ = 2; |
| 284 } |
| 285 } |
| 286 |
| 271 base::TimeTicks encode_start_time = base::TimeTicks::Now(); | 287 base::TimeTicks encode_start_time = base::TimeTicks::Now(); |
| 272 | 288 |
| 273 // Create or reconfigure the codec to match the size of |frame|. | 289 // Create or reconfigure the codec to match the size of |frame|. |
| 274 if (!codec_ || | 290 if (!codec_ || |
| 275 (image_ && | 291 (image_ && |
| 276 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) { | 292 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) { |
| 277 Configure(frame.size()); | 293 Configure(frame.size()); |
| 278 } | 294 } |
| 279 | 295 |
| 280 // Convert the updated capture data ready for encode. | 296 // Convert the updated capture data ready for encode. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 } | 352 } |
| 337 } | 353 } |
| 338 | 354 |
| 339 // Note the time taken to encode the pixel data. | 355 // Note the time taken to encode the pixel data. |
| 340 packet->set_encode_time_ms( | 356 packet->set_encode_time_ms( |
| 341 (base::TimeTicks::Now() - encode_start_time).InMillisecondsRoundedUp()); | 357 (base::TimeTicks::Now() - encode_start_time).InMillisecondsRoundedUp()); |
| 342 | 358 |
| 343 return packet.Pass(); | 359 return packet.Pass(); |
| 344 } | 360 } |
| 345 | 361 |
| 346 VideoEncoderVpx::VideoEncoderVpx(bool use_vp9) | 362 VideoEncoderVpx::VideoEncoderVpx(bool use_vp9) : use_vp9_(use_vp9) { |
| 347 : use_vp9_(use_vp9), | |
| 348 lossless_encode_(false), | |
| 349 lossless_color_(false), | |
| 350 active_map_width_(0), | |
| 351 active_map_height_(0) { | |
| 352 if (use_vp9_) { | |
| 353 // Use I444 colour space, by default, if specified on the command-line. | |
| 354 if (base::CommandLine::ForCurrentProcess()->HasSwitch( | |
| 355 kEnableI444SwitchName)) { | |
| 356 SetLosslessColor(true); | |
| 357 } | |
| 358 } | |
| 359 } | 363 } |
| 360 | 364 |
| 361 void VideoEncoderVpx::Configure(const webrtc::DesktopSize& size) { | 365 void VideoEncoderVpx::Configure(const webrtc::DesktopSize& size) { |
| 362 DCHECK(use_vp9_ || !lossless_color_); | 366 DCHECK(use_vp9_ || !lossless_color_); |
| 363 DCHECK(use_vp9_ || !lossless_encode_); | 367 DCHECK(use_vp9_ || !lossless_encode_); |
| 364 | 368 |
| 365 // Tear down |image_| if it no longer matches the size and color settings. | 369 // Tear down |image_| if it no longer matches the size and color settings. |
| 366 // PrepareImage() will then create a new buffer of the required dimensions if | 370 // PrepareImage() will then create a new buffer of the required dimensions if |
| 367 // |image_| is not allocated. | 371 // |image_| is not allocated. |
| 368 FreeImageIfMismatched(lossless_color_, size, &image_, &image_buffer_); | 372 FreeImageIfMismatched(lossless_color_, size, &image_, &image_buffer_); |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 543 kMacroBlockSize * (y + 1))); | 547 kMacroBlockSize * (y + 1))); |
| 544 } | 548 } |
| 545 x0 = x1 + 1; | 549 x0 = x1 + 1; |
| 546 } | 550 } |
| 547 } | 551 } |
| 548 updated_region->IntersectWith( | 552 updated_region->IntersectWith( |
| 549 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | 553 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); |
| 550 } | 554 } |
| 551 | 555 |
| 552 } // namespace remoting | 556 } // namespace remoting |
| OLD | NEW |