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 13 matching lines...) Expand all Loading... |
24 // pause in the video stream. | 24 // pause in the video stream. |
25 const int kRestartFramePeriods = 3; | 25 const int kRestartFramePeriods = 3; |
26 | 26 |
27 // The following constants are used to automactically tune the encoder | 27 // The following constants are used to automactically tune the encoder |
28 // parameters: |cpu_used| and |min_quantizer|. | 28 // parameters: |cpu_used| and |min_quantizer|. |
29 | 29 |
30 // The |half-life| of the encoding speed accumulator. | 30 // The |half-life| of the encoding speed accumulator. |
31 // The smaller, the shorter of the time averaging window. | 31 // The smaller, the shorter of the time averaging window. |
32 const int kEncodingSpeedAccHalfLife = 120000; // 0.12 second. | 32 const int kEncodingSpeedAccHalfLife = 120000; // 0.12 second. |
33 | 33 |
34 // The target deadline utilization signal. This is a trade-off between quality | 34 // The target encoder utilization signal. This is a trade-off between quality |
35 // and less CPU usage. The range of this value is [0, 1]. Higher the value, | 35 // and less CPU usage. The range of this value is [0, 1]. Higher the value, |
36 // better the quality and higher the CPU usage. | 36 // better the quality and higher the CPU usage. |
37 // | 37 // |
38 // For machines with more than two encoding threads. | 38 // For machines with more than two encoding threads. |
39 const double kHiTargetDeadlineUtilization = 0.7; | 39 const double kHiTargetEncoderUtilization = 0.7; |
40 // For machines with two encoding threads. | 40 // For machines with two encoding threads. |
41 const double kMidTargetDeadlineUtilization = 0.6; | 41 const double kMidTargetEncoderUtilization = 0.6; |
42 // For machines with single encoding thread. | 42 // For machines with single encoding thread. |
43 const double kLoTargetDeadlineUtilization = 0.5; | 43 const double kLoTargetEncoderUtilization = 0.5; |
44 | 44 |
45 // This is the equivalent change on encoding speed for the change on each | 45 // This is the equivalent change on encoding speed for the change on each |
46 // quantizer step. | 46 // quantizer step. |
47 const double kEquivalentEncodingSpeedStepPerQpStep = 1 / 20.0; | 47 const double kEquivalentEncodingSpeedStepPerQpStep = 1 / 20.0; |
48 | 48 |
49 // Highest/lowest allowed encoding speed set to the encoder. The valid range | 49 // Highest/lowest allowed encoding speed set to the encoder. The valid range |
50 // is [4, 16]. Experiments show that with speed higher than 12, the saving of | 50 // is [4, 16]. Experiments show that with speed higher than 12, the saving of |
51 // the encoding time is not worth the dropping of the quality. And with speed | 51 // the encoding time is not worth the dropping of the quality. And with speed |
52 // lower than 6, the increasing of quality is not worth the increasing of | 52 // lower than 6, the increasing of quality is not worth the increasing of |
53 // encoding time. | 53 // encoding time. |
54 const int kHighestEncodingSpeed = 12; | 54 const int kHighestEncodingSpeed = 12; |
55 const int kLowestEncodingSpeed = 6; | 55 const int kLowestEncodingSpeed = 6; |
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 VideoSenderConfig& video_config) |
67 : cast_config_(video_config), | 67 : cast_config_(video_config), |
68 target_deadline_utilization_( | 68 target_encoder_utilization_( |
69 video_config.number_of_encode_threads > 2 | 69 video_config.number_of_encode_threads > 2 |
70 ? kHiTargetDeadlineUtilization | 70 ? kHiTargetEncoderUtilization |
71 : (video_config.number_of_encode_threads > 1 | 71 : (video_config.number_of_encode_threads > 1 |
72 ? kMidTargetDeadlineUtilization | 72 ? kMidTargetEncoderUtilization |
73 : kLoTargetDeadlineUtilization)), | 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_.min_qp, cast_config_.max_cpu_saver_qp); |
83 DCHECK_LE(cast_config_.max_cpu_saver_qp, cast_config_.max_qp); | 83 DCHECK_LE(cast_config_.max_cpu_saver_qp, cast_config_.max_qp); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -encoding_speed_), | 185 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_SET_CPUUSED, -encoding_speed_), |
186 VPX_CODEC_OK); | 186 VPX_CODEC_OK); |
187 } | 187 } |
188 | 188 |
189 void Vp8Encoder::Encode(const scoped_refptr<media::VideoFrame>& video_frame, | 189 void Vp8Encoder::Encode(const scoped_refptr<media::VideoFrame>& video_frame, |
190 const base::TimeTicks& reference_time, | 190 const base::TimeTicks& reference_time, |
191 SenderEncodedFrame* encoded_frame) { | 191 SenderEncodedFrame* encoded_frame) { |
192 DCHECK(thread_checker_.CalledOnValidThread()); | 192 DCHECK(thread_checker_.CalledOnValidThread()); |
193 DCHECK(encoded_frame); | 193 DCHECK(encoded_frame); |
194 | 194 |
195 // Note: This is used to compute the |deadline_utilization| and so it uses the | 195 // Note: This is used to compute the |encoder_utilization| and so it uses the |
196 // real-world clock instead of the CastEnvironment clock, the latter of which | 196 // real-world clock instead of the CastEnvironment clock, the latter of which |
197 // might be simulated. | 197 // might be simulated. |
198 const base::TimeTicks start_time = base::TimeTicks::Now(); | 198 const base::TimeTicks start_time = base::TimeTicks::Now(); |
199 | 199 |
200 // Initialize on-demand. Later, if the video frame size has changed, update | 200 // Initialize on-demand. Later, if the video frame size has changed, update |
201 // the encoder configuration. | 201 // the encoder configuration. |
202 const gfx::Size frame_size = video_frame->visible_rect().size(); | 202 const gfx::Size frame_size = video_frame->visible_rect().size(); |
203 if (!is_initialized() || gfx::Size(config_.g_w, config_.g_h) != frame_size) | 203 if (!is_initialized() || gfx::Size(config_.g_w, config_.g_h) != frame_size) |
204 ConfigureForNewFrameSize(frame_size); | 204 ConfigureForNewFrameSize(frame_size); |
205 | 205 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 encoded_frame->frame_id.lower_32_bits(), | 301 encoded_frame->frame_id.lower_32_bits(), |
302 encoded_frame->rtp_timestamp.lower_32_bits(), | 302 encoded_frame->rtp_timestamp.lower_32_bits(), |
303 static_cast<int>(config_.rc_target_bitrate), | 303 static_cast<int>(config_.rc_target_bitrate), |
304 key_frame_requested_ ? 'Y' : 'N'); | 304 key_frame_requested_ ? 'Y' : 'N'); |
305 base::debug::SetCrashKeyValue(kZeroEncodeDetails, details); | 305 base::debug::SetCrashKeyValue(kZeroEncodeDetails, details); |
306 // Please forward crash reports to http://crbug.com/519022: | 306 // Please forward crash reports to http://crbug.com/519022: |
307 base::debug::DumpWithoutCrashing(); | 307 base::debug::DumpWithoutCrashing(); |
308 base::debug::ClearCrashKey(kZeroEncodeDetails); | 308 base::debug::ClearCrashKey(kZeroEncodeDetails); |
309 } | 309 } |
310 | 310 |
311 // Compute deadline utilization as the real-world time elapsed divided by the | 311 // Compute encoder utilization as the real-world time elapsed divided by the |
312 // frame duration. | 312 // frame duration. |
313 const base::TimeDelta processing_time = base::TimeTicks::Now() - start_time; | 313 const base::TimeDelta processing_time = base::TimeTicks::Now() - start_time; |
314 encoded_frame->deadline_utilization = | 314 encoded_frame->encoder_utilization = |
315 processing_time.InSecondsF() / predicted_frame_duration.InSecondsF(); | 315 processing_time.InSecondsF() / predicted_frame_duration.InSecondsF(); |
316 | 316 |
317 // Compute lossy utilization. The VP8 encoder took an estimated guess at what | 317 // Compute lossy utilization. The VP8 encoder took an estimated guess at what |
318 // quantizer value would produce an encoded frame size as close to the target | 318 // quantizer value would produce an encoded frame size as close to the target |
319 // as possible. Now that the frame has been encoded and the number of bytes | 319 // as possible. Now that the frame has been encoded and the number of bytes |
320 // is known, the perfect quantizer value (i.e., the one that should have been | 320 // is known, the perfect quantizer value (i.e., the one that should have been |
321 // used) can be determined. This perfect quantizer is then normalized and | 321 // used) can be determined. This perfect quantizer is then normalized and |
322 // used as the lossy utilization. | 322 // used as the lossy utilization. |
323 const double actual_bitrate = | 323 const double actual_bitrate = |
324 encoded_frame->data.size() * 8.0 / predicted_frame_duration.InSecondsF(); | 324 encoded_frame->data.size() * 8.0 / predicted_frame_duration.InSecondsF(); |
325 const double target_bitrate = 1000.0 * config_.rc_target_bitrate; | 325 const double target_bitrate = 1000.0 * config_.rc_target_bitrate; |
326 DCHECK_GT(target_bitrate, 0.0); | 326 DCHECK_GT(target_bitrate, 0.0); |
327 const double bitrate_utilization = actual_bitrate / target_bitrate; | 327 const double bitrate_utilization = actual_bitrate / target_bitrate; |
328 int quantizer = -1; | 328 int quantizer = -1; |
329 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_GET_LAST_QUANTIZER_64, &quantizer), | 329 CHECK_EQ(vpx_codec_control(&encoder_, VP8E_GET_LAST_QUANTIZER_64, &quantizer), |
330 VPX_CODEC_OK); | 330 VPX_CODEC_OK); |
331 const double perfect_quantizer = bitrate_utilization * std::max(0, quantizer); | 331 const double perfect_quantizer = bitrate_utilization * std::max(0, quantizer); |
332 // Side note: If it was possible for the encoder to encode within the target | 332 // Side note: If it was possible for the encoder to encode within the target |
333 // number of bytes, the |perfect_quantizer| will be in the range [0.0,63.0]. | 333 // number of bytes, the |perfect_quantizer| will be in the range [0.0,63.0]. |
334 // If it was never possible, the value will be greater than 63.0. | 334 // If it was never possible, the value will be greater than 63.0. |
335 encoded_frame->lossy_utilization = perfect_quantizer / 63.0; | 335 encoded_frame->lossy_utilization = perfect_quantizer / 63.0; |
336 | 336 |
337 DVLOG(2) << "VP8 encoded frame_id " << encoded_frame->frame_id | 337 DVLOG(2) << "VP8 encoded frame_id " << encoded_frame->frame_id |
338 << ", sized: " << encoded_frame->data.size() | 338 << ", sized: " << encoded_frame->data.size() |
339 << ", deadline_utilization: " << encoded_frame->deadline_utilization | 339 << ", encoder_utilization: " << encoded_frame->encoder_utilization |
340 << ", lossy_utilization: " << encoded_frame->lossy_utilization | 340 << ", lossy_utilization: " << encoded_frame->lossy_utilization |
341 << " (quantizer chosen by the encoder was " << quantizer << ')'; | 341 << " (quantizer chosen by the encoder was " << quantizer << ')'; |
342 | 342 |
343 if (encoded_frame->dependency == EncodedFrame::KEY) { | 343 if (encoded_frame->dependency == EncodedFrame::KEY) { |
344 key_frame_requested_ = false; | 344 key_frame_requested_ = false; |
345 } | 345 } |
346 if (encoded_frame->dependency == EncodedFrame::KEY) { | 346 if (encoded_frame->dependency == EncodedFrame::KEY) { |
347 encoding_speed_acc_.Reset(kHighestEncodingSpeed, video_frame->timestamp()); | 347 encoding_speed_acc_.Reset(kHighestEncodingSpeed, video_frame->timestamp()); |
348 } else { | 348 } else { |
349 // Equivalent encoding speed considering both cpu_used setting and | 349 // Equivalent encoding speed considering both cpu_used setting and |
350 // quantizer. | 350 // quantizer. |
351 double actual_encoding_speed = | 351 double actual_encoding_speed = |
352 encoding_speed_ + | 352 encoding_speed_ + |
353 kEquivalentEncodingSpeedStepPerQpStep * | 353 kEquivalentEncodingSpeedStepPerQpStep * |
354 std::max(0, quantizer - cast_config_.min_qp); | 354 std::max(0, quantizer - cast_config_.min_qp); |
355 double adjusted_encoding_speed = actual_encoding_speed * | 355 double adjusted_encoding_speed = actual_encoding_speed * |
356 encoded_frame->deadline_utilization / | 356 encoded_frame->encoder_utilization / |
357 target_deadline_utilization_; | 357 target_encoder_utilization_; |
358 encoding_speed_acc_.Update(adjusted_encoding_speed, | 358 encoding_speed_acc_.Update(adjusted_encoding_speed, |
359 video_frame->timestamp()); | 359 video_frame->timestamp()); |
360 } | 360 } |
361 | 361 |
362 if (HasSufficientFeedback(encoding_speed_acc_)) { | 362 if (HasSufficientFeedback(encoding_speed_acc_)) { |
363 // Predict |encoding_speed_| and |min_quantizer| for next frame. | 363 // Predict |encoding_speed_| and |min_quantizer| for next frame. |
364 // When CPU is constrained, increase encoding speed and increase | 364 // When CPU is constrained, increase encoding speed and increase |
365 // |min_quantizer| if needed. | 365 // |min_quantizer| if needed. |
366 double next_encoding_speed = encoding_speed_acc_.current(); | 366 double next_encoding_speed = encoding_speed_acc_.current(); |
367 int next_min_qp; | 367 int next_min_qp; |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
409 VLOG(1) << "VP8 new rc_target_bitrate: " << new_bitrate_kbit << " kbps"; | 409 VLOG(1) << "VP8 new rc_target_bitrate: " << new_bitrate_kbit << " kbps"; |
410 } | 410 } |
411 | 411 |
412 void Vp8Encoder::GenerateKeyFrame() { | 412 void Vp8Encoder::GenerateKeyFrame() { |
413 DCHECK(thread_checker_.CalledOnValidThread()); | 413 DCHECK(thread_checker_.CalledOnValidThread()); |
414 key_frame_requested_ = true; | 414 key_frame_requested_ = true; |
415 } | 415 } |
416 | 416 |
417 } // namespace cast | 417 } // namespace cast |
418 } // namespace media | 418 } // namespace media |
OLD | NEW |