Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(863)

Side by Side Diff: remoting/codec/video_encoder_vpx.cc

Issue 304653002: Extend VideoControl to allow clients to request lossless modes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Add tests Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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"
8 #include "base/logging.h" 9 #include "base/logging.h"
9 #include "base/sys_info.h" 10 #include "base/sys_info.h"
10 #include "remoting/base/util.h" 11 #include "remoting/base/util.h"
11 #include "remoting/proto/video.pb.h" 12 #include "remoting/proto/video.pb.h"
12 #include "third_party/libyuv/include/libyuv/convert_from_argb.h" 13 #include "third_party/libyuv/include/libyuv/convert_from_argb.h"
13 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 14 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
14 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h" 15 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
15 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" 16 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
16 17
17 extern "C" { 18 extern "C" {
18 #define VPX_CODEC_DISABLE_COMPAT 1 19 #define VPX_CODEC_DISABLE_COMPAT 1
19 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h" 20 #include "third_party/libvpx/source/libvpx/vpx/vpx_encoder.h"
20 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h" 21 #include "third_party/libvpx/source/libvpx/vpx/vp8cx.h"
21 } 22 }
22 23
23 namespace remoting { 24 namespace remoting {
24 25
25 namespace { 26 namespace {
26 27
28 // Name of command-line flag to enable VP9 to use I444 by default.
29 const char kEnableI444SwitchName[] = "enable-i444";
30
27 // Number of bytes in an RGBx pixel. 31 // Number of bytes in an RGBx pixel.
28 const int kBytesPerRgbPixel = 4; 32 const int kBytesPerRgbPixel = 4;
29 33
30 // Defines the dimension of a macro block. This is used to compute the active 34 // Defines the dimension of a macro block. This is used to compute the active
31 // map for the encoder. 35 // map for the encoder.
32 const int kMacroBlockSize = 16; 36 const int kMacroBlockSize = 16;
33 37
34 // Magic encoder profile numbers for I420 and I444 input formats. 38 // Magic encoder profile numbers for I420 and I444 input formats.
35 const int kVp9I420ProfileNumber = 0; 39 const int kVp9I420ProfileNumber = 0;
36 const int kVp9I444ProfileNumber = 1; 40 const int kVp9I444ProfileNumber = 1;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 return ScopedVpxCodec(); 94 return ScopedVpxCodec();
91 95
92 // Use the lowest level of noise sensitivity so as to spend less time 96 // Use the lowest level of noise sensitivity so as to spend less time
93 // on motion estimation and inter-prediction mode. 97 // on motion estimation and inter-prediction mode.
94 if (vpx_codec_control(codec.get(), VP8E_SET_NOISE_SENSITIVITY, 0)) 98 if (vpx_codec_control(codec.get(), VP8E_SET_NOISE_SENSITIVITY, 0))
95 return ScopedVpxCodec(); 99 return ScopedVpxCodec();
96 100
97 return codec.Pass(); 101 return codec.Pass();
98 } 102 }
99 103
100 ScopedVpxCodec CreateVP9Codec(bool use_i444, const webrtc::DesktopSize& size) { 104 ScopedVpxCodec CreateVP9Codec(const webrtc::DesktopSize& size,
105 bool use_i444,
Jamie 2014/05/29 22:19:41 Is i444 the same as lossless colour? Since that's
Wez 2014/05/29 22:39:26 Done.
106 bool lossless_encode) {
101 ScopedVpxCodec codec(new vpx_codec_ctx_t); 107 ScopedVpxCodec codec(new vpx_codec_ctx_t);
102 108
103 // Configure the encoder. 109 // Configure the encoder.
104 vpx_codec_enc_cfg_t config; 110 vpx_codec_enc_cfg_t config;
105 const vpx_codec_iface_t* algo = vpx_codec_vp9_cx(); 111 const vpx_codec_iface_t* algo = vpx_codec_vp9_cx();
106 CHECK(algo); 112 CHECK(algo);
107 vpx_codec_err_t ret = vpx_codec_enc_config_default(algo, &config, 0); 113 vpx_codec_err_t ret = vpx_codec_enc_config_default(algo, &config, 0);
108 if (ret != VPX_CODEC_OK) 114 if (ret != VPX_CODEC_OK)
109 return ScopedVpxCodec(); 115 return ScopedVpxCodec();
110 116
111 SetCommonCodecParameters(size, &config); 117 SetCommonCodecParameters(size, &config);
112 118
113 // Configure VP9 for I420 or I444 source frames. 119 // Configure VP9 for I420 or I444 source frames.
114 config.g_profile = use_i444 ? kVp9I444ProfileNumber : kVp9I420ProfileNumber; 120 config.g_profile = use_i444 ? kVp9I444ProfileNumber : kVp9I420ProfileNumber;
115 121
116 // Disable quantization entirely, putting the encoder in "lossless" mode. 122 if (lossless_encode) {
117 config.rc_min_quantizer = 0; 123 // Disable quantization entirely, putting the encoder in "lossless" mode.
118 config.rc_max_quantizer = 0; 124 config.rc_min_quantizer = 0;
125 config.rc_max_quantizer = 0;
126 } else {
127 // Lossy encode using the same settings as for VP8.
128 config.rc_min_quantizer = 20;
129 config.rc_max_quantizer = 30;
130 }
119 131
120 if (vpx_codec_enc_init(codec.get(), algo, &config, 0)) 132 if (vpx_codec_enc_init(codec.get(), algo, &config, 0))
121 return ScopedVpxCodec(); 133 return ScopedVpxCodec();
122 134
123 // VP9 encode doesn't yet support Realtime, so falls back to Good quality, 135 // VP9 encode doesn't yet support Realtime, so falls back to Good quality,
124 // for which 4 is the lowest CPU usage. 136 // for which 4 is the lowest CPU usage.
125 // Note that this is configured via the same parameter as for VP8. 137 // Note that this is configured via the same parameter as for VP8.
126 if (vpx_codec_control(codec.get(), VP8E_SET_CPUUSED, 4)) 138 if (vpx_codec_control(codec.get(), VP8E_SET_CPUUSED, 4))
127 return ScopedVpxCodec(); 139 return ScopedVpxCodec();
128 140
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 image->stride[2] = uv_stride; 207 image->stride[2] = uv_stride;
196 208
197 *out_image = image.Pass(); 209 *out_image = image.Pass();
198 *out_image_buffer = image_buffer.Pass(); 210 *out_image_buffer = image_buffer.Pass();
199 } 211 }
200 212
201 } // namespace 213 } // namespace
202 214
203 // static 215 // static
204 scoped_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP8() { 216 scoped_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP8() {
205 return scoped_ptr<VideoEncoderVpx>( 217 return scoped_ptr<VideoEncoderVpx>(new VideoEncoderVpx(false));
206 new VideoEncoderVpx(base::Bind(&CreateVP8Codec),
207 base::Bind(&CreateImage, false)));
208 } 218 }
209 219
210 // static 220 // static
211 scoped_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP9I420() { 221 scoped_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP9() {
212 return scoped_ptr<VideoEncoderVpx>( 222 return scoped_ptr<VideoEncoderVpx>(new VideoEncoderVpx(true));
213 new VideoEncoderVpx(base::Bind(&CreateVP9Codec, false),
214 base::Bind(&CreateImage, false)));
215 }
216
217 // static
218 scoped_ptr<VideoEncoderVpx> VideoEncoderVpx::CreateForVP9I444() {
219 return scoped_ptr<VideoEncoderVpx>(
220 new VideoEncoderVpx(base::Bind(&CreateVP9Codec, true),
221 base::Bind(&CreateImage, true)));
222 } 223 }
223 224
224 VideoEncoderVpx::~VideoEncoderVpx() {} 225 VideoEncoderVpx::~VideoEncoderVpx() {}
225 226
227 void VideoEncoderVpx::SetLosslessEncode(bool want_lossless) {
228 if (use_vp9_ && (want_lossless != lossless_encode_)) {
229 lossless_encode_ = want_lossless;
230 codec_.reset(); // Force encoder re-initialization.
231 }
232 }
233
234 void VideoEncoderVpx::SetLosslessColor(bool want_lossless) {
235 if (use_vp9_ && (want_lossless != lossless_color_)) {
236 lossless_color_ = want_lossless;
237 codec_.reset(); // Force encoder re-initialization.
238 }
239 }
240
226 scoped_ptr<VideoPacket> VideoEncoderVpx::Encode( 241 scoped_ptr<VideoPacket> VideoEncoderVpx::Encode(
227 const webrtc::DesktopFrame& frame) { 242 const webrtc::DesktopFrame& frame) {
228 DCHECK_LE(32, frame.size().width()); 243 DCHECK_LE(32, frame.size().width());
229 DCHECK_LE(32, frame.size().height()); 244 DCHECK_LE(32, frame.size().height());
230 245
231 base::TimeTicks encode_start_time = base::TimeTicks::Now(); 246 base::TimeTicks encode_start_time = base::TimeTicks::Now();
232 247
233 if (!codec_ || 248 if (!codec_ ||
234 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h))) { 249 !frame.size().equals(webrtc::DesktopSize(image_->w, image_->h))) {
235 bool ret = Initialize(frame.size()); 250 bool ret = Initialize(frame.size());
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
305 Rect* rect = packet->add_dirty_rects(); 320 Rect* rect = packet->add_dirty_rects();
306 rect->set_x(r.rect().left()); 321 rect->set_x(r.rect().left());
307 rect->set_y(r.rect().top()); 322 rect->set_y(r.rect().top());
308 rect->set_width(r.rect().width()); 323 rect->set_width(r.rect().width());
309 rect->set_height(r.rect().height()); 324 rect->set_height(r.rect().height());
310 } 325 }
311 326
312 return packet.Pass(); 327 return packet.Pass();
313 } 328 }
314 329
315 VideoEncoderVpx::VideoEncoderVpx(const CreateCodecCallback& create_codec, 330 VideoEncoderVpx::VideoEncoderVpx(bool use_vp9)
316 const CreateImageCallback& create_image) 331 : use_vp9_(use_vp9),
317 : create_codec_(create_codec), 332 lossless_encode_(false),
318 create_image_(create_image), 333 lossless_color_(false),
319 active_map_width_(0), 334 active_map_width_(0),
320 active_map_height_(0) { 335 active_map_height_(0) {
336 if (use_vp9_) {
337 // Use lossless encoding mode by default.
338 SetLosslessEncode(true);
339
340 // Use I444 colour space, by default, if specified on the command-line.
341 if (CommandLine::ForCurrentProcess()->HasSwitch(kEnableI444SwitchName)) {
342 SetLosslessColor(true);
343 }
344 }
321 } 345 }
322 346
323 bool VideoEncoderVpx::Initialize(const webrtc::DesktopSize& size) { 347 bool VideoEncoderVpx::Initialize(const webrtc::DesktopSize& size) {
348 DCHECK(use_vp9_ || !lossless_color_);
349 DCHECK(use_vp9_ || !lossless_encode_);
350
324 codec_.reset(); 351 codec_.reset();
325 352
326 // (Re)Create the VPX image structure and pixel buffer. 353 // (Re)Create the VPX image structure and pixel buffer.
327 create_image_.Run(size, &image_, &image_buffer_); 354 CreateImage(lossless_color_, size, &image_, &image_buffer_);
328 355
329 // Initialize active map. 356 // Initialize active map.
330 active_map_width_ = (image_->w + kMacroBlockSize - 1) / kMacroBlockSize; 357 active_map_width_ = (image_->w + kMacroBlockSize - 1) / kMacroBlockSize;
331 active_map_height_ = (image_->h + kMacroBlockSize - 1) / kMacroBlockSize; 358 active_map_height_ = (image_->h + kMacroBlockSize - 1) / kMacroBlockSize;
332 active_map_.reset(new uint8[active_map_width_ * active_map_height_]); 359 active_map_.reset(new uint8[active_map_width_ * active_map_height_]);
333 360
334 // (Re)Initialize the codec. 361 // (Re)Initialize the codec.
335 codec_ = create_codec_.Run(size); 362 if (use_vp9_) {
363 codec_ = CreateVP9Codec(size, lossless_color_, lossless_encode_);
364 } else {
365 codec_ = CreateVP8Codec(size);
366 }
336 367
337 return codec_; 368 return codec_;
338 } 369 }
339 370
340 void VideoEncoderVpx::PrepareImage(const webrtc::DesktopFrame& frame, 371 void VideoEncoderVpx::PrepareImage(const webrtc::DesktopFrame& frame,
341 webrtc::DesktopRegion* updated_region) { 372 webrtc::DesktopRegion* updated_region) {
342 if (frame.updated_region().is_empty()) { 373 if (frame.updated_region().is_empty()) {
343 updated_region->Clear(); 374 updated_region->Clear();
344 return; 375 return;
345 } 376 }
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
429 uint8* map = active_map_.get() + top * active_map_width_; 460 uint8* map = active_map_.get() + top * active_map_width_;
430 for (int y = top; y <= bottom; ++y) { 461 for (int y = top; y <= bottom; ++y) {
431 for (int x = left; x <= right; ++x) 462 for (int x = left; x <= right; ++x)
432 map[x] = 1; 463 map[x] = 1;
433 map += active_map_width_; 464 map += active_map_width_;
434 } 465 }
435 } 466 }
436 } 467 }
437 468
438 } // namespace remoting 469 } // namespace remoting
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698