Index: media/cast/sender/external_video_encoder.cc |
diff --git a/media/cast/sender/external_video_encoder.cc b/media/cast/sender/external_video_encoder.cc |
index 70a57772c2289b374c00a6e4519831da81f9c9ed..bff088cc1e91f4460c63bff985e2dd173ddc968f 100644 |
--- a/media/cast/sender/external_video_encoder.cc |
+++ b/media/cast/sender/external_video_encoder.cc |
@@ -8,6 +8,7 @@ |
#include <utility> |
#include "base/bind.h" |
+#include "base/command_line.h" |
#include "base/debug/crash_logging.h" |
#include "base/debug/dump_without_crashing.h" |
#include "base/format_macros.h" |
@@ -16,9 +17,11 @@ |
#include "base/memory/shared_memory.h" |
#include "base/message_loop/message_loop.h" |
#include "base/metrics/histogram.h" |
+#include "base/strings/string_number_conversions.h" |
#include "base/strings/stringprintf.h" |
#include "build/build_config.h" |
#include "media/base/bind_to_current_loop.h" |
+#include "media/base/media_switches.h" |
#include "media/base/video_frame.h" |
#include "media/base/video_types.h" |
#include "media/base/video_util.h" |
@@ -40,6 +43,40 @@ constexpr size_t kOutputBufferCount = 3; |
// used when copy is needed to match the required coded size. |
constexpr size_t kExtraInputBufferCount = 2; |
+// Parses the command-line flag and returns 0 (default) to use the old/flawed |
+// "deadline utilization" heuristic to measure encoder utilization. Otherwise, |
+// returns the "redline" value for the "backlog" heuristic (i.e., num_frames / |
+// redline = utilization). |
+// |
+// Example command line switches and results: |
+// |
+// --cast-encoder-util-heuristic=foobar ==> 0 (unrecognized, use deadline) |
+// --cast-encoder-util-heuristic=backlog ==> 6 (use backlog, default) |
+// --cast-encoder-util-heuristic=backlog7 ==> 7 (use backlog, redline=7) |
+// |
+// TODO(miu): This is temporary, for lab performance testing, until a |
+// good "works for all" solution is confirmed. |
+// https://code.google.com/p/chrome-os-partner/issues/detail?id=54806 |
+int GetConfiguredBacklogRedline() { |
+ constexpr char kBacklogSwitchValue[] = "backlog"; |
+ constexpr int kBacklogDefaultRedline = 6; |
+ |
+ const std::string& switch_value = |
+ base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
+ switches::kCastEncoderUtilHeuristic); |
+ if (switch_value.find(kBacklogSwitchValue) == 0) { |
+ int redline = kBacklogDefaultRedline; |
+ if (!base::StringToInt(switch_value.substr(sizeof(kBacklogSwitchValue) - 1), |
+ &redline)) { |
+ redline = kBacklogDefaultRedline; |
+ } |
+ VLOG(1) << "Using 'backlog' heuristic with a redline of " << redline |
+ << " to compute encoder utilization."; |
+ return redline; |
+ } |
+ return 0; |
+} |
+ |
} // namespace |
namespace media { |
@@ -96,6 +133,7 @@ class ExternalVideoEncoder::VEAClientImpl |
status_change_cb_(status_change_cb), |
create_video_encode_memory_cb_(create_video_encode_memory_cb), |
video_encode_accelerator_(std::move(vea)), |
+ backlog_redline_threshold_(GetConfiguredBacklogRedline()), |
encoder_active_(false), |
next_frame_id_(FrameId::first()), |
key_frame_encountered_(false), |
@@ -307,12 +345,30 @@ class ExternalVideoEncoder::VEAClientImpl |
if (request.video_frame->metadata()->GetTimeDelta( |
media::VideoFrameMetadata::FRAME_DURATION, &frame_duration) && |
frame_duration > base::TimeDelta()) { |
- // Compute encoder utilization as the real-world time elapsed divided |
- // by the frame duration. |
- const base::TimeDelta processing_time = |
- base::TimeTicks::Now() - request.start_time; |
- encoded_frame->encoder_utilization = |
- processing_time.InSecondsF() / frame_duration.InSecondsF(); |
+ if (backlog_redline_threshold_ == 0) { |
+ // Compute encoder utilization as the real-world time elapsed divided |
+ // by the frame duration. |
+ const base::TimeDelta processing_time = |
+ base::TimeTicks::Now() - request.start_time; |
+ encoded_frame->encoder_utilization = |
+ processing_time.InSecondsF() / frame_duration.InSecondsF(); |
+ } else { |
+ // Compute encoder utilization in terms of the number of frames in |
+ // backlog, including the current frame encode that is finishing |
+ // here. This "backlog" model works as follows: First, assume that all |
+ // frames utilize the encoder by the same amount. This is actually a |
+ // false assumption, but it still works well because any frame that |
+ // takes longer to encode will naturally cause the backlog to |
+ // increase, and this will result in a higher computed utilization for |
+ // the offending frame. If the backlog continues to increase, because |
+ // the following frames are also taking too long to encode, the |
+ // computed utilization for each successive frame will be higher. At |
+ // some point, upstream control logic will decide that the data volume |
+ // must be reduced. |
+ encoded_frame->encoder_utilization = |
+ static_cast<double>(in_progress_frame_encodes_.size()) / |
+ backlog_redline_threshold_; |
+ } |
const double actual_bit_rate = |
encoded_frame->data.size() * 8.0 / frame_duration.InSecondsF(); |
@@ -540,6 +596,7 @@ class ExternalVideoEncoder::VEAClientImpl |
const StatusChangeCallback status_change_cb_; // Must be run on MAIN thread. |
const CreateVideoEncodeMemoryCallback create_video_encode_memory_cb_; |
std::unique_ptr<media::VideoEncodeAccelerator> video_encode_accelerator_; |
+ const int backlog_redline_threshold_; |
bool encoder_active_; |
FrameId next_frame_id_; |
bool key_frame_encountered_; |