Chromium Code Reviews| 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 nothing has changed, then only encode data to top-off from lossy to | |
| 270 // lossless quantization. | |
| 271 if (frame.updated_region().is_empty()) { | |
| 272 // VP8 doesn't support top-off, and VP9's lossless mode doesn't need it. | |
| 273 if (!use_vp9_ || lossless_encode_) | |
| 274 return nullptr; | |
| 275 if (!--topoff_frame_count_) { | |
|
Sergey Ulanov
2015/05/26 21:57:22
nit: --topoff_frame_count > 0 (or != 0) would be m
Wez
2015/06/09 01:46:20
Plus, in cleaning it up, I fixed a bug in my imple
| |
| 276 return nullptr; | |
| 277 } | |
| 278 } else { | |
| 279 // Just allow a couple of fully empty frames' worth of top-off. | |
| 280 topoff_frame_count_ = 2; | |
|
Sergey Ulanov
2015/05/26 21:57:22
topoff_frame_count_ is set even when using VP8, bu
Wez
2015/06/09 01:46:20
Done.
| |
| 281 } | |
| 282 | |
| 271 base::TimeTicks encode_start_time = base::TimeTicks::Now(); | 283 base::TimeTicks encode_start_time = base::TimeTicks::Now(); |
| 272 | 284 |
| 273 // Create or reconfigure the codec to match the size of |frame|. | 285 // Create or reconfigure the codec to match the size of |frame|. |
| 274 if (!codec_ || | 286 if (!codec_ || |
| 275 (image_ && | 287 (image_ && |
| 276 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) { | 288 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h)))) { |
| 277 Configure(frame.size()); | 289 Configure(frame.size()); |
| 278 } | 290 } |
| 279 | 291 |
| 280 // Convert the updated capture data ready for encode. | 292 // Convert the updated capture data ready for encode. |
| 281 webrtc::DesktopRegion updated_region; | 293 webrtc::DesktopRegion updated_region; |
| 282 PrepareImage(frame, &updated_region); | 294 PrepareImage(frame, &updated_region); |
| 283 | 295 |
| 284 // Update active map based on updated region. | 296 // Update active map based on updated region. |
| 285 SetActiveMapFromRegion(updated_region); | 297 SetActiveMapFromRegion(updated_region); |
|
Sergey Ulanov
2015/05/26 21:57:22
Do we need to supply active map for top-off, or do
Wez
2015/06/09 01:46:20
Cyclic Refresh will top-off even during "active" f
| |
| 286 | 298 |
| 287 // Apply active map to the encoder. | 299 // Apply active map to the encoder. |
| 288 vpx_active_map_t act_map; | 300 vpx_active_map_t act_map; |
| 289 act_map.rows = active_map_height_; | 301 act_map.rows = active_map_height_; |
| 290 act_map.cols = active_map_width_; | 302 act_map.cols = active_map_width_; |
| 291 act_map.active_map = active_map_.get(); | 303 act_map.active_map = active_map_.get(); |
| 292 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { | 304 if (vpx_codec_control(codec_.get(), VP8E_SET_ACTIVEMAP, &act_map)) { |
| 293 LOG(ERROR) << "Unable to apply active map"; | 305 LOG(ERROR) << "Unable to apply active map"; |
| 294 } | 306 } |
| 295 | 307 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 341 (base::TimeTicks::Now() - encode_start_time).InMillisecondsRoundedUp()); | 353 (base::TimeTicks::Now() - encode_start_time).InMillisecondsRoundedUp()); |
| 342 | 354 |
| 343 return packet.Pass(); | 355 return packet.Pass(); |
| 344 } | 356 } |
| 345 | 357 |
| 346 VideoEncoderVpx::VideoEncoderVpx(bool use_vp9) | 358 VideoEncoderVpx::VideoEncoderVpx(bool use_vp9) |
| 347 : use_vp9_(use_vp9), | 359 : use_vp9_(use_vp9), |
| 348 lossless_encode_(false), | 360 lossless_encode_(false), |
| 349 lossless_color_(false), | 361 lossless_color_(false), |
| 350 active_map_width_(0), | 362 active_map_width_(0), |
| 351 active_map_height_(0) { | 363 active_map_height_(0), |
| 352 if (use_vp9_) { | 364 topoff_frame_count_(0) { |
| 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 } | 365 } |
| 360 | 366 |
| 361 void VideoEncoderVpx::Configure(const webrtc::DesktopSize& size) { | 367 void VideoEncoderVpx::Configure(const webrtc::DesktopSize& size) { |
| 362 DCHECK(use_vp9_ || !lossless_color_); | 368 DCHECK(use_vp9_ || !lossless_color_); |
| 363 DCHECK(use_vp9_ || !lossless_encode_); | 369 DCHECK(use_vp9_ || !lossless_encode_); |
| 364 | 370 |
| 365 // Tear down |image_| if it no longer matches the size and color settings. | 371 // 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 | 372 // PrepareImage() will then create a new buffer of the required dimensions if |
| 367 // |image_| is not allocated. | 373 // |image_| is not allocated. |
| 368 FreeImageIfMismatched(lossless_color_, size, &image_, &image_buffer_); | 374 FreeImageIfMismatched(lossless_color_, size, &image_, &image_buffer_); |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 543 kMacroBlockSize * (y + 1))); | 549 kMacroBlockSize * (y + 1))); |
| 544 } | 550 } |
| 545 x0 = x1 + 1; | 551 x0 = x1 + 1; |
| 546 } | 552 } |
| 547 } | 553 } |
| 548 updated_region->IntersectWith( | 554 updated_region->IntersectWith( |
| 549 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | 555 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); |
| 550 } | 556 } |
| 551 | 557 |
| 552 } // namespace remoting | 558 } // namespace remoting |
| OLD | NEW |