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