Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1004)

Side by Side Diff: media/cast/sender/external_video_encoder.cc

Issue 2108373002: Add experimental 'backlog' heuristic for measuring encoder utilization. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: REBASE Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/base/media_switches.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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,
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)
54 // --cast-encoder-util-heuristic=backlog ==> 6 (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 = 6;
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
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
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 encoder 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->encoder_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 number of frames in
357 // backlog, including the current frame encode that is finishing
358 // here. This "backlog" model works as follows: First, assume that all
359 // frames utilize the encoder by the same amount. This is actually a
360 // false assumption, but it still works well because any frame that
361 // takes longer to encode will naturally cause the backlog to
362 // increase, and this will result in a higher computed utilization for
363 // the offending frame. If the backlog continues to increase, because
364 // the following frames are also taking too long to encode, the
365 // computed utilization for each successive frame will be higher. At
366 // some point, upstream control logic will decide that the data volume
367 // must be reduced.
368 encoded_frame->encoder_utilization =
369 static_cast<double>(in_progress_frame_encodes_.size()) /
370 backlog_redline_threshold_;
371 }
316 372
317 const double actual_bit_rate = 373 const double actual_bit_rate =
318 encoded_frame->data.size() * 8.0 / frame_duration.InSecondsF(); 374 encoded_frame->data.size() * 8.0 / frame_duration.InSecondsF();
319 DCHECK_GT(request.target_bit_rate, 0); 375 DCHECK_GT(request.target_bit_rate, 0);
320 const double bitrate_utilization = 376 const double bitrate_utilization =
321 actual_bit_rate / request.target_bit_rate; 377 actual_bit_rate / request.target_bit_rate;
322 double quantizer = QuantizerEstimator::NO_RESULT; 378 double quantizer = QuantizerEstimator::NO_RESULT;
323 // If the quantizer can be parsed from the key frame, try to parse 379 // If the quantizer can be parsed from the key frame, try to parse
324 // the following delta frames as well. 380 // the following delta frames as well.
325 // Otherwise, switch back to entropy estimation for the key frame 381 // Otherwise, switch back to entropy estimation for the key frame
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
533 } 589 }
534 return (num_slices == 0) ? -1 : (total_quantizer / num_slices); 590 return (num_slices == 0) ? -1 : (total_quantizer / num_slices);
535 } 591 }
536 592
537 const scoped_refptr<CastEnvironment> cast_environment_; 593 const scoped_refptr<CastEnvironment> cast_environment_;
538 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 594 const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
539 const int max_frame_rate_; 595 const int max_frame_rate_;
540 const StatusChangeCallback status_change_cb_; // Must be run on MAIN thread. 596 const StatusChangeCallback status_change_cb_; // Must be run on MAIN thread.
541 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; 597 const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_;
542 std::unique_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; 598 std::unique_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_;
599 const int backlog_redline_threshold_;
543 bool encoder_active_; 600 bool encoder_active_;
544 FrameId next_frame_id_; 601 FrameId next_frame_id_;
545 bool key_frame_encountered_; 602 bool key_frame_encountered_;
546 std::string stream_header_; 603 std::string stream_header_;
547 VideoCodecProfile codec_profile_; 604 VideoCodecProfile codec_profile_;
548 bool key_frame_quantizer_parsable_; 605 bool key_frame_quantizer_parsable_;
549 H264Parser h264_parser_; 606 H264Parser h264_parser_;
550 607
551 // Shared memory buffers for output with the VideoAccelerator. 608 // Shared memory buffers for output with the VideoAccelerator.
552 std::vector<std::unique_ptr<base::SharedMemory>> output_buffers_; 609 std::vector<std::unique_ptr<base::SharedMemory>> output_buffers_;
(...skipping 341 matching lines...) Expand 10 before | Expand all | Expand 10 after
894 const double kEntropyAtMaxQuantizer = 7.5; 951 const double kEntropyAtMaxQuantizer = 7.5;
895 const double slope = 952 const double slope =
896 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer; 953 (MAX_VP8_QUANTIZER - MIN_VP8_QUANTIZER) / kEntropyAtMaxQuantizer;
897 const double quantizer = std::min<double>( 954 const double quantizer = std::min<double>(
898 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy); 955 MAX_VP8_QUANTIZER, MIN_VP8_QUANTIZER + slope * shannon_entropy);
899 return quantizer; 956 return quantizer;
900 } 957 }
901 958
902 } // namespace cast 959 } // namespace cast
903 } // namespace media 960 } // namespace media
OLDNEW
« no previous file with comments | « media/base/media_switches.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698