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 |