1 // Copyright 2021 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "cast/standalone_sender/streaming_video_encoder.h"
6
7 #include "util/chrono_helpers.h"
8
9 namespace openscreen {
10 namespace cast {
11
StreamingVideoEncoder(const Parameters & params,TaskRunner * task_runner,Sender * sender)12 StreamingVideoEncoder::StreamingVideoEncoder(const Parameters& params,
13 TaskRunner* task_runner,
14 Sender* sender)
15 : params_(params), main_task_runner_(task_runner), sender_(sender) {
16 OSP_DCHECK_LE(1, params_.num_encode_threads);
17 OSP_DCHECK_LE(kMinQuantizer, params_.min_quantizer);
18 OSP_DCHECK_LE(params_.min_quantizer, params_.max_cpu_saver_quantizer);
19 OSP_DCHECK_LE(params_.max_cpu_saver_quantizer, params_.max_quantizer);
20 OSP_DCHECK_LE(params_.max_quantizer, kMaxQuantizer);
21 OSP_DCHECK_LT(0.0, params_.max_time_utilization);
22 OSP_DCHECK_LE(params_.max_time_utilization, 1.0);
23 OSP_DCHECK(main_task_runner_);
24 OSP_DCHECK(sender_);
25 }
26
~StreamingVideoEncoder()27 StreamingVideoEncoder::~StreamingVideoEncoder() {}
28
UpdateSpeedSettingForNextFrame(const Stats & stats)29 void StreamingVideoEncoder::UpdateSpeedSettingForNextFrame(const Stats& stats) {
30 OSP_DCHECK_EQ(std::this_thread::get_id(), encode_thread_.get_id());
31
32 // Combine the speed setting that was used to encode the last frame, and the
33 // quantizer the encoder chose into a single speed metric.
34 const double speed = current_speed_setting_ +
35 kEquivalentEncodingSpeedStepPerQuantizerStep *
36 std::max(0, stats.quantizer - params_.min_quantizer);
37
38 // Like |Stats::perfect_quantizer|, this computes a "hindsight" speed setting
39 // for the last frame, one that may have potentially allowed for a
40 // better-quality quantizer choice by the encoder, while also keeping CPU
41 // utilization within budget.
42 const double perfect_speed =
43 speed * stats.time_utilization() / params_.max_time_utilization;
44
45 // Update the ideal speed setting, to be used for the next frame. An
46 // exponentially-decaying weighted average is used here to smooth-out noise.
47 // The weight is based on the duration of the frame that was encoded.
48 constexpr Clock::duration kDecayHalfLife = milliseconds(120);
49 const double ticks = stats.frame_duration.count();
50 const double weight = ticks / (ticks + kDecayHalfLife.count());
51 ideal_speed_setting_ =
52 weight * perfect_speed + (1.0 - weight) * ideal_speed_setting_;
53 OSP_DCHECK(std::isfinite(ideal_speed_setting_));
54 }
55
56 } // namespace cast
57 } // namespace openscreen
58