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" | 8 #include "base/command_line.h" |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/sys_info.h" | 10 #include "base/sys_info.h" |
(...skipping 21 matching lines...) Expand all Loading... | |
32 const int kBytesPerRgbPixel = 4; | 32 const int kBytesPerRgbPixel = 4; |
33 | 33 |
34 // 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 |
35 // map for the encoder. | 35 // map for the encoder. |
36 const int kMacroBlockSize = 16; | 36 const int kMacroBlockSize = 16; |
37 | 37 |
38 // Magic encoder profile numbers for I420 and I444 input formats. | 38 // Magic encoder profile numbers for I420 and I444 input formats. |
39 const int kVp9I420ProfileNumber = 0; | 39 const int kVp9I420ProfileNumber = 0; |
40 const int kVp9I444ProfileNumber = 1; | 40 const int kVp9I444ProfileNumber = 1; |
41 | 41 |
42 // Magic encoder constants for adaptive quantization strategy | |
43 const int kVp9AqNone = 0; | |
44 const int kVp9AqCyclicRefresh = 3; | |
Wez
2015/04/18 00:17:54
nit: Suggest these start kVp9AqMode, for consisten
aconverse
2015/04/20 18:32:38
Done.
| |
45 | |
42 void SetCommonCodecParameters(vpx_codec_enc_cfg_t* config, | 46 void SetCommonCodecParameters(vpx_codec_enc_cfg_t* config, |
43 const webrtc::DesktopSize& size) { | 47 const webrtc::DesktopSize& size) { |
44 // Use millisecond granularity time base. | 48 // Use millisecond granularity time base. |
45 config->g_timebase.num = 1; | 49 config->g_timebase.num = 1; |
46 config->g_timebase.den = 1000; | 50 config->g_timebase.den = 1000; |
47 | 51 |
48 config->g_w = size.width(); | 52 config->g_w = size.width(); |
49 config->g_h = size.height(); | 53 config->g_h = size.height(); |
50 config->g_pass = VPX_RC_ONE_PASS; | 54 config->g_pass = VPX_RC_ONE_PASS; |
51 | 55 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
127 | 131 |
128 // Use the lowest level of noise sensitivity so as to spend less time | 132 // Use the lowest level of noise sensitivity so as to spend less time |
129 // on motion estimation and inter-prediction mode. | 133 // on motion estimation and inter-prediction mode. |
130 ret = vpx_codec_control(codec, VP9E_SET_NOISE_SENSITIVITY, 0); | 134 ret = vpx_codec_control(codec, VP9E_SET_NOISE_SENSITIVITY, 0); |
131 DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set noise sensitivity"; | 135 DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set noise sensitivity"; |
132 | 136 |
133 // Configure the codec to tune it for screen media. | 137 // Configure the codec to tune it for screen media. |
134 ret = vpx_codec_control( | 138 ret = vpx_codec_control( |
135 codec, VP9E_SET_TUNE_CONTENT, VP9E_CONTENT_SCREEN); | 139 codec, VP9E_SET_TUNE_CONTENT, VP9E_CONTENT_SCREEN); |
136 DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set screen content mode"; | 140 DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set screen content mode"; |
141 | |
142 // Set cyclic refresh for lossy encode | |
Wez
2015/04/18 00:17:54
nit: missing .
Suggest "Enable cyclic refresh (ak
aconverse
2015/04/20 18:32:38
Done.
| |
143 int aq_mode = lossless_encode ? kVp9AqNone : kVp9AqCyclicRefresh; | |
144 ret = vpx_codec_control(codec, VP9E_SET_AQ_MODE, aq_mode); | |
145 DCHECK_EQ(VPX_CODEC_OK, ret) << "Failed to set aq mode"; | |
137 } | 146 } |
138 | 147 |
139 void FreeImageIfMismatched(bool use_i444, | 148 void FreeImageIfMismatched(bool use_i444, |
140 const webrtc::DesktopSize& size, | 149 const webrtc::DesktopSize& size, |
141 scoped_ptr<vpx_image_t>* out_image, | 150 scoped_ptr<vpx_image_t>* out_image, |
142 scoped_ptr<uint8[]>* out_image_buffer) { | 151 scoped_ptr<uint8[]>* out_image_buffer) { |
143 if (*out_image) { | 152 if (*out_image) { |
144 const vpx_img_fmt_t desired_fmt = | 153 const vpx_img_fmt_t desired_fmt = |
145 use_i444 ? VPX_IMG_FMT_I444 : VPX_IMG_FMT_I420; | 154 use_i444 ? VPX_IMG_FMT_I444 : VPX_IMG_FMT_I420; |
146 if (!size.equals(webrtc::DesktopSize((*out_image)->w, (*out_image)->h)) || | 155 if (!size.equals(webrtc::DesktopSize((*out_image)->w, (*out_image)->h)) || |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
283 | 292 |
284 // Do the actual encoding. | 293 // Do the actual encoding. |
285 int timestamp = (encode_start_time - timestamp_base_).InMilliseconds(); | 294 int timestamp = (encode_start_time - timestamp_base_).InMilliseconds(); |
286 vpx_codec_err_t ret = vpx_codec_encode( | 295 vpx_codec_err_t ret = vpx_codec_encode( |
287 codec_.get(), image_.get(), timestamp, 1, 0, VPX_DL_REALTIME); | 296 codec_.get(), image_.get(), timestamp, 1, 0, VPX_DL_REALTIME); |
288 DCHECK_EQ(ret, VPX_CODEC_OK) | 297 DCHECK_EQ(ret, VPX_CODEC_OK) |
289 << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n" | 298 << "Encoding error: " << vpx_codec_err_to_string(ret) << "\n" |
290 << "Details: " << vpx_codec_error(codec_.get()) << "\n" | 299 << "Details: " << vpx_codec_error(codec_.get()) << "\n" |
291 << vpx_codec_error_detail(codec_.get()); | 300 << vpx_codec_error_detail(codec_.get()); |
292 | 301 |
302 if (use_vp9_) { | |
303 if (vpx_codec_control(codec_.get(), VP9E_GET_ACTIVEMAP, &act_map) == | |
304 VPX_CODEC_OK) { | |
Wez
2015/04/18 00:17:54
Is there any point calling this if we are already
aconverse
2015/04/20 18:32:39
Done.
| |
305 UpdateActiveMap(&updated_region); | |
306 } else { | |
307 LOG(ERROR) << "Failed to fetch active map"; | |
308 updated_region.Clear(); | |
309 updated_region.AddRect(webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | |
Wez
2015/04/18 00:17:54
Under what circumstances can the get call fail? Sh
aconverse
2015/04/20 18:32:39
I was following the example of SET_ACTIVEMAP. Neit
Wez
2015/04/21 01:29:18
Ah, OK; we should probably have SET_ACTIVEMAP erro
| |
310 } | |
311 } | |
312 | |
293 // Read the encoded data. | 313 // Read the encoded data. |
294 vpx_codec_iter_t iter = NULL; | 314 vpx_codec_iter_t iter = NULL; |
295 bool got_data = false; | 315 bool got_data = false; |
296 | 316 |
297 // TODO(hclam): Make sure we get exactly one frame from the packet. | 317 // TODO(hclam): Make sure we get exactly one frame from the packet. |
298 // TODO(hclam): We should provide the output buffer to avoid one copy. | 318 // TODO(hclam): We should provide the output buffer to avoid one copy. |
299 scoped_ptr<VideoPacket> packet( | 319 scoped_ptr<VideoPacket> packet( |
300 helper_.CreateVideoPacketWithUpdatedRegion(frame, updated_region)); | 320 helper_.CreateVideoPacketWithUpdatedRegion(frame, updated_region)); |
301 packet->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8); | 321 packet->mutable_format()->set_encoding(VideoPacketFormat::ENCODING_VP8); |
302 | 322 |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
500 | 520 |
501 uint8* map = active_map_.get() + top * active_map_width_; | 521 uint8* map = active_map_.get() + top * active_map_width_; |
502 for (int y = top; y <= bottom; ++y) { | 522 for (int y = top; y <= bottom; ++y) { |
503 for (int x = left; x <= right; ++x) | 523 for (int x = left; x <= right; ++x) |
504 map[x] = 1; | 524 map[x] = 1; |
505 map += active_map_width_; | 525 map += active_map_width_; |
506 } | 526 } |
507 } | 527 } |
508 } | 528 } |
509 | 529 |
530 void VideoEncoderVpx::UpdateActiveMap(webrtc::DesktopRegion *updated_region) { | |
531 uint8* map = active_map_.get(); | |
532 // Mark active areas updated. | |
Wez
2015/04/18 00:17:54
nit: This comment doesn't fit this function; we're
aconverse
2015/04/20 18:32:38
We've already fetched the areas. We are marking th
Wez
2015/04/21 01:29:18
OK; suggest "Add areas marked active to |updated_r
| |
533 for (int r = 0; r < active_map_height_; ++r) { | |
Wez
2015/04/18 00:17:54
Suggest r -> y
aconverse
2015/04/20 18:32:39
Done.
| |
534 int c1; | |
Wez
2015/04/18 00:17:54
Move this inside the c0 loop?
aconverse
2015/04/20 18:32:38
This is used in the iteration condition so that we
Wez
2015/04/21 01:29:18
Gotcha; I think it might be more readable to decla
aconverse
2015/04/28 17:03:56
Done. lmk if I misunderstood
| |
535 for (int c0 = 0; c0 < active_map_height_; c0 = c1 + 1) { | |
Wez
2015/04/18 00:17:54
Suggest c0 -> x0
Wez
2015/04/18 00:17:54
Looks like this should be |active_map_width_|?
aconverse
2015/04/20 18:32:39
Done.
aconverse
2015/04/20 18:32:39
Done.
| |
536 for (c1 = c0; c1 < active_map_height_; ++c1) { | |
Wez
2015/04/18 00:17:54
Ditto.
aconverse
2015/04/20 18:32:38
Done.
| |
537 if (map[c1] == 0) | |
aconverse
2015/04/20 18:32:39
Big oops on this line as well. [not taking row int
Wez
2015/04/21 01:29:18
Yes and no; no, we can't remove this, because we d
aconverse
2015/04/28 17:03:56
I should give this a try before we move forward.
| |
538 break; | |
539 } | |
540 if (c1 > c0) { | |
541 updated_region->AddRect(webrtc::DesktopRect::MakeLTRB( | |
542 kMacroBlockSize * c0, | |
543 kMacroBlockSize * r, | |
544 kMacroBlockSize * c1, | |
545 kMacroBlockSize * (r + 1))); | |
546 } | |
547 } | |
548 } | |
549 updated_region->IntersectWith( | |
550 webrtc::DesktopRect::MakeWH(image_->w, image_->h)); | |
551 } | |
552 | |
510 } // namespace remoting | 553 } // namespace remoting |
OLD | NEW |