| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "media/cast/sender/vp8_encoder.h" | 5 #include "media/cast/sender/vp8_encoder.h" |
| 6 | 6 |
| 7 #include "base/debug/crash_logging.h" | 7 #include "base/debug/crash_logging.h" |
| 8 #include "base/debug/dump_without_crashing.h" | 8 #include "base/debug/dump_without_crashing.h" |
| 9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 56 | 56 |
| 57 bool HasSufficientFeedback( | 57 bool HasSufficientFeedback( |
| 58 const FeedbackSignalAccumulator<base::TimeDelta>& accumulator) { | 58 const FeedbackSignalAccumulator<base::TimeDelta>& accumulator) { |
| 59 const base::TimeDelta amount_of_history = | 59 const base::TimeDelta amount_of_history = |
| 60 accumulator.update_time() - accumulator.reset_time(); | 60 accumulator.update_time() - accumulator.reset_time(); |
| 61 return amount_of_history.InMicroseconds() >= 250000; // 0.25 second. | 61 return amount_of_history.InMicroseconds() >= 250000; // 0.25 second. |
| 62 } | 62 } |
| 63 | 63 |
| 64 } // namespace | 64 } // namespace |
| 65 | 65 |
| 66 Vp8Encoder::Vp8Encoder(const FrameSenderConfig& video_config) | 66 Vp8Encoder::Vp8Encoder(const VideoSenderConfig& video_config) |
| 67 : cast_config_(video_config), | 67 : cast_config_(video_config), |
| 68 target_encoder_utilization_( | 68 target_encoder_utilization_( |
| 69 video_config.video_codec_params.number_of_encode_threads > 2 | 69 video_config.number_of_encode_threads > 2 |
| 70 ? kHiTargetEncoderUtilization | 70 ? kHiTargetEncoderUtilization |
| 71 : (video_config.video_codec_params.number_of_encode_threads > 1 | 71 : (video_config.number_of_encode_threads > 1 |
| 72 ? kMidTargetEncoderUtilization | 72 ? kMidTargetEncoderUtilization |
| 73 : kLoTargetEncoderUtilization)), | 73 : kLoTargetEncoderUtilization)), |
| 74 key_frame_requested_(true), | 74 key_frame_requested_(true), |
| 75 bitrate_kbit_(cast_config_.start_bitrate / 1000), | 75 bitrate_kbit_(cast_config_.start_bitrate / 1000), |
| 76 next_frame_id_(FrameId::first()), | 76 next_frame_id_(FrameId::first()), |
| 77 has_seen_zero_length_encoded_frame_(false), | 77 has_seen_zero_length_encoded_frame_(false), |
| 78 encoding_speed_acc_( | 78 encoding_speed_acc_( |
| 79 base::TimeDelta::FromMicroseconds(kEncodingSpeedAccHalfLife)), | 79 base::TimeDelta::FromMicroseconds(kEncodingSpeedAccHalfLife)), |
| 80 encoding_speed_(kHighestEncodingSpeed) { | 80 encoding_speed_(kHighestEncodingSpeed) { |
| 81 config_.g_timebase.den = 0; // Not initialized. | 81 config_.g_timebase.den = 0; // Not initialized. |
| 82 DCHECK_LE(cast_config_.video_codec_params.min_qp, | 82 DCHECK_LE(cast_config_.min_qp, cast_config_.max_cpu_saver_qp); |
| 83 cast_config_.video_codec_params.max_cpu_saver_qp); | 83 DCHECK_LE(cast_config_.max_cpu_saver_qp, cast_config_.max_qp); |
| 84 DCHECK_LE(cast_config_.video_codec_params.max_cpu_saver_qp, | |
| 85 cast_config_.video_codec_params.max_qp); | |
| 86 | 84 |
| 87 thread_checker_.DetachFromThread(); | 85 thread_checker_.DetachFromThread(); |
| 88 } | 86 } |
| 89 | 87 |
| 90 Vp8Encoder::~Vp8Encoder() { | 88 Vp8Encoder::~Vp8Encoder() { |
| 91 DCHECK(thread_checker_.CalledOnValidThread()); | 89 DCHECK(thread_checker_.CalledOnValidThread()); |
| 92 if (is_initialized()) | 90 if (is_initialized()) |
| 93 vpx_codec_destroy(&encoder_); | 91 vpx_codec_destroy(&encoder_); |
| 94 } | 92 } |
| 95 | 93 |
| 96 void Vp8Encoder::Initialize() { | 94 void Vp8Encoder::Initialize() { |
| 97 DCHECK(thread_checker_.CalledOnValidThread()); | 95 DCHECK(thread_checker_.CalledOnValidThread()); |
| 98 DCHECK(!is_initialized()); | 96 DCHECK(!is_initialized()); |
| 99 // The encoder will be created/configured when the first frame encode is | 97 // The encoder will be created/configured when the first frame encode is |
| 100 // requested. | 98 // requested. |
| 101 } | 99 } |
| 102 | 100 |
| 103 void Vp8Encoder::ConfigureForNewFrameSize(const gfx::Size& frame_size) { | 101 void Vp8Encoder::ConfigureForNewFrameSize(const gfx::Size& frame_size) { |
| 104 if (is_initialized()) { | 102 if (is_initialized()) { |
| 105 // Workaround for VP8 bug: If the new size is strictly less-than-or-equal to | 103 // Workaround for VP8 bug: If the new size is strictly less-than-or-equal to |
| 106 // the old size, in terms of area, the existing encoder instance can | 104 // the old size, in terms of area, the existing encoder instance can |
| 107 // continue. Otherwise, completely tear-down and re-create a new encoder to | 105 // continue. Otherwise, completely tear-down and re-create a new encoder to |
| 108 // avoid a shutdown crash. | 106 // avoid a shutdown crash. |
| 109 if (frame_size.GetArea() <= gfx::Size(config_.g_w, config_.g_h).GetArea()) { | 107 if (frame_size.GetArea() <= gfx::Size(config_.g_w, config_.g_h).GetArea()) { |
| 110 DVLOG(1) << "Continuing to use existing encoder at smaller frame size: " | 108 DVLOG(1) << "Continuing to use existing encoder at smaller frame size: " |
| 111 << gfx::Size(config_.g_w, config_.g_h).ToString() << " --> " | 109 << gfx::Size(config_.g_w, config_.g_h).ToString() << " --> " |
| 112 << frame_size.ToString(); | 110 << frame_size.ToString(); |
| 113 config_.g_w = frame_size.width(); | 111 config_.g_w = frame_size.width(); |
| 114 config_.g_h = frame_size.height(); | 112 config_.g_h = frame_size.height(); |
| 115 config_.rc_min_quantizer = cast_config_.video_codec_params.min_qp; | 113 config_.rc_min_quantizer = cast_config_.min_qp; |
| 116 if (vpx_codec_enc_config_set(&encoder_, &config_) == VPX_CODEC_OK) | 114 if (vpx_codec_enc_config_set(&encoder_, &config_) == VPX_CODEC_OK) |
| 117 return; | 115 return; |
| 118 DVLOG(1) << "libvpx rejected the attempt to use a smaller frame size in " | 116 DVLOG(1) << "libvpx rejected the attempt to use a smaller frame size in " |
| 119 "the current instance."; | 117 "the current instance."; |
| 120 } | 118 } |
| 121 | 119 |
| 122 DVLOG(1) << "Destroying/Re-Creating encoder for larger frame size: " | 120 DVLOG(1) << "Destroying/Re-Creating encoder for larger frame size: " |
| 123 << gfx::Size(config_.g_w, config_.g_h).ToString() << " --> " | 121 << gfx::Size(config_.g_w, config_.g_h).ToString() << " --> " |
| 124 << frame_size.ToString(); | 122 << frame_size.ToString(); |
| 125 vpx_codec_destroy(&encoder_); | 123 vpx_codec_destroy(&encoder_); |
| 126 } else { | 124 } else { |
| 127 DVLOG(1) << "Creating encoder for the first frame; size: " | 125 DVLOG(1) << "Creating encoder for the first frame; size: " |
| 128 << frame_size.ToString(); | 126 << frame_size.ToString(); |
| 129 } | 127 } |
| 130 | 128 |
| 131 // Populate encoder configuration with default values. | 129 // Populate encoder configuration with default values. |
| 132 CHECK_EQ(vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0), | 130 CHECK_EQ(vpx_codec_enc_config_default(vpx_codec_vp8_cx(), &config_, 0), |
| 133 VPX_CODEC_OK); | 131 VPX_CODEC_OK); |
| 134 | 132 |
| 135 config_.g_threads = cast_config_.video_codec_params.number_of_encode_threads; | 133 config_.g_threads = cast_config_.number_of_encode_threads; |
| 136 config_.g_w = frame_size.width(); | 134 config_.g_w = frame_size.width(); |
| 137 config_.g_h = frame_size.height(); | 135 config_.g_h = frame_size.height(); |
| 138 // Set the timebase to match that of base::TimeDelta. | 136 // Set the timebase to match that of base::TimeDelta. |
| 139 config_.g_timebase.num = 1; | 137 config_.g_timebase.num = 1; |
| 140 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; | 138 config_.g_timebase.den = base::Time::kMicrosecondsPerSecond; |
| 141 | 139 |
| 142 // |g_pass| and |g_lag_in_frames| must be "one pass" and zero, respectively, | 140 // |g_pass| and |g_lag_in_frames| must be "one pass" and zero, respectively, |
| 143 // in order for VP8 to support changing frame sizes during encoding: | 141 // in order for VP8 to support changing frame sizes during encoding: |
| 144 config_.g_pass = VPX_RC_ONE_PASS; | 142 config_.g_pass = VPX_RC_ONE_PASS; |
| 145 config_.g_lag_in_frames = 0; // Immediate data output for each frame. | 143 config_.g_lag_in_frames = 0; // Immediate data output for each frame. |
| 146 | 144 |
| 147 // Rate control settings. | 145 // Rate control settings. |
| 148 config_.rc_dropframe_thresh = 0; // The encoder may not drop any frames. | 146 config_.rc_dropframe_thresh = 0; // The encoder may not drop any frames. |
| 149 config_.rc_resize_allowed = 0; // TODO(miu): Why not? Investigate this. | 147 config_.rc_resize_allowed = 0; // TODO(miu): Why not? Investigate this. |
| 150 config_.rc_end_usage = VPX_CBR; | 148 config_.rc_end_usage = VPX_CBR; |
| 151 config_.rc_target_bitrate = bitrate_kbit_; | 149 config_.rc_target_bitrate = bitrate_kbit_; |
| 152 config_.rc_min_quantizer = cast_config_.video_codec_params.min_qp; | 150 config_.rc_min_quantizer = cast_config_.min_qp; |
| 153 config_.rc_max_quantizer = cast_config_.video_codec_params.max_qp; | 151 config_.rc_max_quantizer = cast_config_.max_qp; |
| 154 // TODO(miu): Revisit these now that the encoder is being successfully | 152 // TODO(miu): Revisit these now that the encoder is being successfully |
| 155 // micro-managed. | 153 // micro-managed. |
| 156 config_.rc_undershoot_pct = 100; | 154 config_.rc_undershoot_pct = 100; |
| 157 config_.rc_overshoot_pct = 15; | 155 config_.rc_overshoot_pct = 15; |
| 158 // TODO(miu): Document why these rc_buf_*_sz values were chosen and/or | 156 // TODO(miu): Document why these rc_buf_*_sz values were chosen and/or |
| 159 // research for better values. Should they be computed from the target | 157 // research for better values. Should they be computed from the target |
| 160 // playout delay? | 158 // playout delay? |
| 161 config_.rc_buf_initial_sz = 500; | 159 config_.rc_buf_initial_sz = 500; |
| 162 config_.rc_buf_optimal_sz = 600; | 160 config_.rc_buf_optimal_sz = 600; |
| 163 config_.rc_buf_sz = 1000; | 161 config_.rc_buf_sz = 1000; |
| (...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 key_frame_requested_ = false; | 344 key_frame_requested_ = false; |
| 347 } | 345 } |
| 348 if (encoded_frame->dependency == EncodedFrame::KEY) { | 346 if (encoded_frame->dependency == EncodedFrame::KEY) { |
| 349 encoding_speed_acc_.Reset(kHighestEncodingSpeed, video_frame->timestamp()); | 347 encoding_speed_acc_.Reset(kHighestEncodingSpeed, video_frame->timestamp()); |
| 350 } else { | 348 } else { |
| 351 // Equivalent encoding speed considering both cpu_used setting and | 349 // Equivalent encoding speed considering both cpu_used setting and |
| 352 // quantizer. | 350 // quantizer. |
| 353 double actual_encoding_speed = | 351 double actual_encoding_speed = |
| 354 encoding_speed_ + | 352 encoding_speed_ + |
| 355 kEquivalentEncodingSpeedStepPerQpStep * | 353 kEquivalentEncodingSpeedStepPerQpStep * |
| 356 std::max(0, quantizer - cast_config_.video_codec_params.min_qp); | 354 std::max(0, quantizer - cast_config_.min_qp); |
| 357 double adjusted_encoding_speed = actual_encoding_speed * | 355 double adjusted_encoding_speed = actual_encoding_speed * |
| 358 encoded_frame->encoder_utilization / | 356 encoded_frame->encoder_utilization / |
| 359 target_encoder_utilization_; | 357 target_encoder_utilization_; |
| 360 encoding_speed_acc_.Update(adjusted_encoding_speed, | 358 encoding_speed_acc_.Update(adjusted_encoding_speed, |
| 361 video_frame->timestamp()); | 359 video_frame->timestamp()); |
| 362 } | 360 } |
| 363 | 361 |
| 364 if (HasSufficientFeedback(encoding_speed_acc_)) { | 362 if (HasSufficientFeedback(encoding_speed_acc_)) { |
| 365 // Predict |encoding_speed_| and |min_quantizer| for next frame. | 363 // Predict |encoding_speed_| and |min_quantizer| for next frame. |
| 366 // When CPU is constrained, increase encoding speed and increase | 364 // When CPU is constrained, increase encoding speed and increase |
| 367 // |min_quantizer| if needed. | 365 // |min_quantizer| if needed. |
| 368 double next_encoding_speed = encoding_speed_acc_.current(); | 366 double next_encoding_speed = encoding_speed_acc_.current(); |
| 369 int next_min_qp; | 367 int next_min_qp; |
| 370 if (next_encoding_speed > kHighestEncodingSpeed) { | 368 if (next_encoding_speed > kHighestEncodingSpeed) { |
| 371 double remainder = next_encoding_speed - kHighestEncodingSpeed; | 369 double remainder = next_encoding_speed - kHighestEncodingSpeed; |
| 372 next_encoding_speed = kHighestEncodingSpeed; | 370 next_encoding_speed = kHighestEncodingSpeed; |
| 373 next_min_qp = | 371 next_min_qp = |
| 374 static_cast<int>(remainder / kEquivalentEncodingSpeedStepPerQpStep + | 372 static_cast<int>(remainder / kEquivalentEncodingSpeedStepPerQpStep + |
| 375 cast_config_.video_codec_params.min_qp + 0.5); | 373 cast_config_.min_qp + 0.5); |
| 376 next_min_qp = std::min(next_min_qp, | 374 next_min_qp = std::min(next_min_qp, cast_config_.max_cpu_saver_qp); |
| 377 cast_config_.video_codec_params.max_cpu_saver_qp); | |
| 378 } else { | 375 } else { |
| 379 next_encoding_speed = | 376 next_encoding_speed = |
| 380 std::max<double>(kLowestEncodingSpeed, next_encoding_speed) + 0.5; | 377 std::max<double>(kLowestEncodingSpeed, next_encoding_speed) + 0.5; |
| 381 next_min_qp = cast_config_.video_codec_params.min_qp; | 378 next_min_qp = cast_config_.min_qp; |
| 382 } | 379 } |
| 383 if (encoding_speed_ != static_cast<int>(next_encoding_speed)) { | 380 if (encoding_speed_ != static_cast<int>(next_encoding_speed)) { |
| 384 encoding_speed_ = static_cast<int>(next_encoding_speed); | 381 encoding_speed_ = static_cast<int>(next_encoding_speed); |
| 385 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -encoding_speed_), | 382 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -encoding_speed_), |
| 386 VPX_CODEC_OK); | 383 VPX_CODEC_OK); |
| 387 } | 384 } |
| 388 if (config_.rc_min_quantizer != static_cast<unsigned int>(next_min_qp)) { | 385 if (config_.rc_min_quantizer != static_cast<unsigned int>(next_min_qp)) { |
| 389 config_.rc_min_quantizer = static_cast<unsigned int>(next_min_qp); | 386 config_.rc_min_quantizer = static_cast<unsigned int>(next_min_qp); |
| 390 CHECK_EQ(vpx_codec_enc_config_set(&encoder_, &config_), VPX_CODEC_OK); | 387 CHECK_EQ(vpx_codec_enc_config_set(&encoder_, &config_), VPX_CODEC_OK); |
| 391 } | 388 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 412 VLOG(1) << "VP8 new rc_target_bitrate: " << new_bitrate_kbit << " kbps"; | 409 VLOG(1) << "VP8 new rc_target_bitrate: " << new_bitrate_kbit << " kbps"; |
| 413 } | 410 } |
| 414 | 411 |
| 415 void Vp8Encoder::GenerateKeyFrame() { | 412 void Vp8Encoder::GenerateKeyFrame() { |
| 416 DCHECK(thread_checker_.CalledOnValidThread()); | 413 DCHECK(thread_checker_.CalledOnValidThread()); |
| 417 key_frame_requested_ = true; | 414 key_frame_requested_ = true; |
| 418 } | 415 } |
| 419 | 416 |
| 420 } // namespace cast | 417 } // namespace cast |
| 421 } // namespace media | 418 } // namespace media |
| OLD | NEW |