Chromium Code Reviews| 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/external_video_encoder.h" | 5 #include "media/cast/sender/external_video_encoder.h" |
| 6 | 6 |
| 7 #include <cmath> | 7 #include <cmath> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/bind.h" | 10 #include "base/bind.h" |
| 11 #include "base/command_line.h" | |
| 11 #include "base/debug/crash_logging.h" | 12 #include "base/debug/crash_logging.h" |
| 12 #include "base/debug/dump_without_crashing.h" | 13 #include "base/debug/dump_without_crashing.h" |
| 13 #include "base/format_macros.h" | 14 #include "base/format_macros.h" |
| 14 #include "base/logging.h" | 15 #include "base/logging.h" |
| 15 #include "base/macros.h" | 16 #include "base/macros.h" |
| 16 #include "base/memory/shared_memory.h" | 17 #include "base/memory/shared_memory.h" |
| 17 #include "base/message_loop/message_loop.h" | 18 #include "base/message_loop/message_loop.h" |
| 18 #include "base/metrics/histogram.h" | 19 #include "base/metrics/histogram.h" |
| 20 #include "base/strings/string_number_conversions.h" | |
| 19 #include "base/strings/stringprintf.h" | 21 #include "base/strings/stringprintf.h" |
| 20 #include "build/build_config.h" | 22 #include "build/build_config.h" |
| 21 #include "media/base/bind_to_current_loop.h" | 23 #include "media/base/bind_to_current_loop.h" |
| 24 #include "media/base/media_switches.h" | |
| 22 #include "media/base/video_frame.h" | 25 #include "media/base/video_frame.h" |
| 23 #include "media/base/video_types.h" | 26 #include "media/base/video_types.h" |
| 24 #include "media/base/video_util.h" | 27 #include "media/base/video_util.h" |
| 25 #include "media/cast/cast_config.h" | 28 #include "media/cast/cast_config.h" |
| 26 #include "media/cast/common/rtp_time.h" | 29 #include "media/cast/common/rtp_time.h" |
| 27 #include "media/cast/logging/logging_defines.h" | 30 #include "media/cast/logging/logging_defines.h" |
| 28 #include "media/cast/net/cast_transport_config.h" | 31 #include "media/cast/net/cast_transport_config.h" |
| 29 #include "media/cast/sender/vp8_quantizer_parser.h" | 32 #include "media/cast/sender/vp8_quantizer_parser.h" |
| 30 #include "media/filters/h264_parser.h" | 33 #include "media/filters/h264_parser.h" |
| 31 | 34 |
| 32 namespace { | 35 namespace { |
| 33 | 36 |
| 34 enum { MAX_H264_QUANTIZER = 51 }; | 37 enum { MAX_H264_QUANTIZER = 51 }; |
| 35 | 38 |
| 36 // Number of buffers for encoded bit stream. | 39 // Number of buffers for encoded bit stream. |
| 37 constexpr size_t kOutputBufferCount = 3; | 40 constexpr size_t kOutputBufferCount = 3; |
| 38 | 41 |
| 39 // Maximum number of extra input buffers for encoder. The input buffers are only | 42 // Maximum number of extra input buffers for encoder. The input buffers are only |
| 40 // used when copy is needed to match the required coded size. | 43 // used when copy is needed to match the required coded size. |
| 41 constexpr size_t kExtraInputBufferCount = 2; | 44 constexpr size_t kExtraInputBufferCount = 2; |
| 42 | 45 |
| 46 // Parses the command-line flag and returns 0 (default) to use the old/flawed | |
| 47 // "deadline utilization" heuristic to measure encoder utilization. Otherwise, | |
|
xjz
2016/06/29 23:46:52
s/deadline/encoder
miu
2016/06/30 20:38:45
No, it's correct the way it is. Here, I am saying
| |
| 48 // returns the "redline" value for the "backlog" heuristic (i.e., num_frames / | |
| 49 // redline = utilization). | |
| 50 // | |
| 51 // Example command line switches and results: | |
| 52 // | |
| 53 // --cast-encoder-util-heuristic=foobar ==> 0 (unrecognized, use deadline) | |
|
xjz
2016/06/29 23:46:52
s/deadline/encoding time?
miu
2016/06/30 20:38:45
Same here. 0 means use the deadline computation.
| |
| 54 // --cast-encoder-util-heuristic=backlog ==> 4 (use backlog, default) | |
| 55 // --cast-encoder-util-heuristic=backlog7 ==> 7 (use backlog, redline=7) | |
| 56 // | |
| 57 // TODO(miu): This is temporary, for lab performance testing, until a | |
| 58 // good "works for all" solution is confirmed. | |
| 59 // https://code.google.com/p/chrome-os-partner/issues/detail?id=54806 | |
| 60 int GetConfiguredBacklogRedline() { | |
| 61 constexpr char kBacklogSwitchValue[] = "backlog"; | |
| 62 constexpr int kBacklogDefaultRedline = 4; | |
| 63 | |
| 64 const std::string& switch_value = | |
| 65 base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( | |
| 66 switches::kCastEncoderUtilHeuristic); | |
| 67 if (switch_value.find(kBacklogSwitchValue) == 0) { | |
| 68 int redline = kBacklogDefaultRedline; | |
| 69 if (!base::StringToInt(switch_value.substr(sizeof(kBacklogSwitchValue) - 1), | |
| 70 &redline)) { | |
| 71 redline = kBacklogDefaultRedline; | |
| 72 } | |
| 73 VLOG(1) << "Using 'backlog' heuristic with a redline of " << redline | |
| 74 << " to compute encoder utilization."; | |
| 75 return redline; | |
| 76 } | |
| 77 return 0; | |
| 78 } | |
| 79 | |
| 43 } // namespace | 80 } // namespace |
| 44 | 81 |
| 45 namespace media { | 82 namespace media { |
| 46 namespace cast { | 83 namespace cast { |
| 47 | 84 |
| 48 // Container for the associated data of a video frame being processed. | 85 // Container for the associated data of a video frame being processed. |
| 49 struct InProgressFrameEncode { | 86 struct InProgressFrameEncode { |
| 50 // The source content to encode. | 87 // The source content to encode. |
| 51 const scoped_refptr<VideoFrame> video_frame; | 88 const scoped_refptr<VideoFrame> video_frame; |
| 52 | 89 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 89 std::unique_ptr<media::VideoEncodeAccelerator> vea, | 126 std::unique_ptr<media::VideoEncodeAccelerator> vea, |
| 90 int max_frame_rate, | 127 int max_frame_rate, |
| 91 const StatusChangeCallback& status_change_cb, | 128 const StatusChangeCallback& status_change_cb, |
| 92 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) | 129 const CreateVideoEncodeMemoryCallback& create_video_encode_memory_cb) |
| 93 : cast_environment_(cast_environment), | 130 : cast_environment_(cast_environment), |
| 94 task_runner_(encoder_task_runner), | 131 task_runner_(encoder_task_runner), |
| 95 max_frame_rate_(max_frame_rate), | 132 max_frame_rate_(max_frame_rate), |
| 96 status_change_cb_(status_change_cb), | 133 status_change_cb_(status_change_cb), |
| 97 create_video_encode_memory_cb_(create_video_encode_memory_cb), | 134 create_video_encode_memory_cb_(create_video_encode_memory_cb), |
| 98 video_encode_accelerator_(std::move(vea)), | 135 video_encode_accelerator_(std::move(vea)), |
| 136 backlog_redline_threshold_(GetConfiguredBacklogRedline()), | |
| 99 encoder_active_(false), | 137 encoder_active_(false), |
| 100 next_frame_id_(FrameId::first()), | 138 next_frame_id_(FrameId::first()), |
| 101 key_frame_encountered_(false), | 139 key_frame_encountered_(false), |
| 102 codec_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), | 140 codec_profile_(media::VIDEO_CODEC_PROFILE_UNKNOWN), |
| 103 key_frame_quantizer_parsable_(false), | 141 key_frame_quantizer_parsable_(false), |
| 104 requested_bit_rate_(-1), | 142 requested_bit_rate_(-1), |
| 105 has_seen_zero_length_encoded_frame_(false), | 143 has_seen_zero_length_encoded_frame_(false), |
| 106 max_allowed_input_buffers_(0), | 144 max_allowed_input_buffers_(0), |
| 107 allocate_input_buffer_in_progress_(false) {} | 145 allocate_input_buffer_in_progress_(false) {} |
| 108 | 146 |
| (...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 300 } | 338 } |
| 301 encoded_frame->data.append( | 339 encoded_frame->data.append( |
| 302 static_cast<const char*>(output_buffer->memory()), payload_size); | 340 static_cast<const char*>(output_buffer->memory()), payload_size); |
| 303 | 341 |
| 304 // If FRAME_DURATION metadata was provided in the source VideoFrame, | 342 // If FRAME_DURATION metadata was provided in the source VideoFrame, |
| 305 // compute the utilization metrics. | 343 // compute the utilization metrics. |
| 306 base::TimeDelta frame_duration; | 344 base::TimeDelta frame_duration; |
| 307 if (request.video_frame->metadata()->GetTimeDelta( | 345 if (request.video_frame->metadata()->GetTimeDelta( |
| 308 media::VideoFrameMetadata::FRAME_DURATION, &frame_duration) && | 346 media::VideoFrameMetadata::FRAME_DURATION, &frame_duration) && |
| 309 frame_duration > base::TimeDelta()) { | 347 frame_duration > base::TimeDelta()) { |
| 310 // Compute deadline utilization as the real-world time elapsed divided | 348 if (backlog_redline_threshold_ == 0) { |
| 311 // by the frame duration. | 349 // Compute encoder utilization as the real-world time elapsed divided |
| 312 const base::TimeDelta processing_time = | 350 // by the frame duration. |
| 313 base::TimeTicks::Now() - request.start_time; | 351 const base::TimeDelta processing_time = |
| 314 encoded_frame->deadline_utilization = | 352 base::TimeTicks::Now() - request.start_time; |
| 315 processing_time.InSecondsF() / frame_duration.InSecondsF(); | 353 encoded_frame->encoder_utilization = |
| 354 processing_time.InSecondsF() / frame_duration.InSecondsF(); | |
| 355 } else { | |
| 356 // Compute encoder utilization in terms of the backlog. | |
| 357 encoded_frame->encoder_utilization = | |
| 358 static_cast<double>(in_progress_frame_encodes_.size()) / | |
| 359 backlog_redline_threshold_; | |
|
xjz
2016/06/29 23:46:52
Shall we use |in_progress_frame_encodes_.size()-1|
miu
2016/06/30 20:38:45
By encoding the frame, we utilized the encoder in
| |
| 360 } | |
| 316 | 361 |
| 317 const double actual_bit_rate = | 362 const double actual_bit_rate = |
| 318 encoded_frame->data.size() * 8.0 / frame_duration.InSecondsF(); | 363 encoded_frame->data.size() * 8.0 / frame_duration.InSecondsF(); |
| 319 DCHECK_GT(request.target_bit_rate, 0); | 364 DCHECK_GT(request.target_bit_rate, 0); |
| 320 const double bitrate_utilization = | 365 const double bitrate_utilization = |
| 321 actual_bit_rate / request.target_bit_rate; | 366 actual_bit_rate / request.target_bit_rate; |
| 322 double quantizer = QuantizerEstimator::NO_RESULT; | 367 double quantizer = QuantizerEstimator::NO_RESULT; |
| 323 // If the quantizer can be parsed from the key frame, try to parse | 368 // If the quantizer can be parsed from the key frame, try to parse |
| 324 // the following delta frames as well. | 369 // the following delta frames as well. |
| 325 // Otherwise, switch back to entropy estimation for the key frame | 370 // Otherwise, switch back to entropy estimation for the key frame |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 533 } | 578 } |
| 534 return (num_slices == 0) ? -1 : (total_quantizer / num_slices); | 579 return (num_slices == 0) ? -1 : (total_quantizer / num_slices); |
| 535 } | 580 } |
| 536 | 581 |
| 537 const scoped_refptr<CastEnvironment> cast_environment_; | 582 const scoped_refptr<CastEnvironment> cast_environment_; |
| 538 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; | 583 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; |
| 539 const int max_frame_rate_; | 584 const int max_frame_rate_; |
| 540 const StatusChangeCallback status_change_cb_; // Must be run on MAIN thread. | 585 const StatusChangeCallback status_change_cb_; // Must be run on MAIN thread. |
| 541 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; | 586 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; |
| 542 std::unique_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; | 587 std::unique_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; |
| 588 const int backlog_redline_threshold_; | |
| 543 bool encoder_active_; | 589 bool encoder_active_; |
| 544 FrameId next_frame_id_; | 590 FrameId next_frame_id_; |
| 545 bool key_frame_encountered_; | 591 bool key_frame_encountered_; |
| 546 std::string stream_header_; | 592 std::string stream_header_; |
| 547 VideoCodecProfile codec_profile_; | 593 VideoCodecProfile codec_profile_; |
| 548 bool key_frame_quantizer_parsable_; | 594 bool key_frame_quantizer_parsable_; |
| 549 H264Parser h264_parser_; | 595 H264Parser h264_parser_; |
| 550 | 596 |
| 551 // Shared memory buffers for output with the VideoAccelerator. | 597 // Shared memory buffers for output with the VideoAccelerator. |
| 552 std::vector<std::unique_ptr<base::SharedMemory>> output_buffers_; | 598 std::vector<std::unique_ptr<base::SharedMemory>> output_buffers_; |
| (...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 894 const double kEntropyAtMaxQuantizer = 7.5; | 940 const double kEntropyAtMaxQuantizer = 7.5; |
| 895 const double slope = | 941 const double slope = |
| 896 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer; | 942 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer; |
| 897 const double quantizer = std::min<double>( | 943 const double quantizer = std::min<double>( |
| 898 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy); | 944 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy); |
| 899 return quantizer; | 945 return quantizer; |
| 900 } | 946 } |
| 901 | 947 |
| 902 } // namespace cast | 948 } // namespace cast |
| 903 } // namespace media | 949 } // namespace media |
| OLD | NEW |