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 |