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) { | |
Sergey Ulanov
2015/06/06 00:19:58
nit: might be more readable if you handle the retu
Sergey Ulanov
2015/06/09 05:32:43
not addressed in the last patch set.
Wez
2015/06/09 22:00:37
Done.
| |
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 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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) |
347 : use_vp9_(use_vp9), | 363 : 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 } | 364 } |
360 | 365 |
361 void VideoEncoderVpx::Configure(const webrtc::DesktopSize& size) { | 366 void VideoEncoderVpx::Configure(const webrtc::DesktopSize& size) { |
362 DCHECK(use_vp9_ || !lossless_color_); | 367 DCHECK(use_vp9_ || !lossless_color_); |
363 DCHECK(use_vp9_ || !lossless_encode_); | 368 DCHECK(use_vp9_ || !lossless_encode_); |
364 | 369 |
365 // Tear down |image_| if it no longer matches the size and color settings. | 370 // 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 | 371 // PrepareImage() will then create a new buffer of the required dimensions if |
367 // |image_| is not allocated. | 372 // |image_| is not allocated. |
368 FreeImageIfMismatched(lossless_color_, size, &image_, &image_buffer_); | 373 FreeImageIfMismatched(lossless_color_, size, &image_, &image_buffer_); |
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
543 kMacroBlockSize * (y + 1))); | 548 kMacroBlockSize * (y + 1))); |
544 } | 549 } |
545 x0 = x1 + 1; | 550 x0 = x1 + 1; |
546 } | 551 } |
547 } | 552 } |
548 updated_region->IntersectWith( | 553 updated_region->IntersectWith( |
549 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | 554 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); |
550 } | 555 } |
551 | 556 |
552 } // namespace remoting | 557 } // namespace remoting |
OLD | NEW |