diff options
Diffstat (limited to 'cast/standalone_sender/streaming_vpx_encoder.cc')
-rw-r--r-- | cast/standalone_sender/streaming_vpx_encoder.cc | 99 |
1 files changed, 19 insertions, 80 deletions
diff --git a/cast/standalone_sender/streaming_vpx_encoder.cc b/cast/standalone_sender/streaming_vpx_encoder.cc index 1c9de314..1b10f92b 100644 --- a/cast/standalone_sender/streaming_vpx_encoder.cc +++ b/cast/standalone_sender/streaming_vpx_encoder.cc @@ -4,14 +4,13 @@ #include "cast/standalone_sender/streaming_vpx_encoder.h" -#include <stdint.h> -#include <string.h> #include <vpx/vp8cx.h> #include <chrono> #include <cmath> #include <utility> +#include "cast/standalone_sender/streaming_encoder_util.h" #include "cast/streaming/encoded_frame.h" #include "cast/streaming/environment.h" #include "cast/streaming/sender.h" @@ -22,8 +21,8 @@ namespace openscreen { namespace cast { -// TODO(https://crbug.com/openscreen/123): Fix the declarations and then remove -// this: +// TODO(issuetracker.google.com/issues/155336511): Fix the declarations and then +// remove this: using openscreen::operator<<; // For std::chrono::duration pretty-printing. namespace { @@ -44,28 +43,14 @@ constexpr Clock::duration kMaxFrameDuration = milliseconds(125); constexpr int kHighestEncodingSpeed = 12; constexpr int kLowestEncodingSpeed = 6; -// This is the equivalent change in encoding speed per one quantizer step. -constexpr double kEquivalentEncodingSpeedStepPerQuantizerStep = 1 / 20.0; - } // namespace StreamingVpxEncoder::StreamingVpxEncoder(const Parameters& params, TaskRunner* task_runner, Sender* sender) - : params_(params), - main_task_runner_(task_runner), - sender_(sender), - ideal_speed_setting_(kHighestEncodingSpeed), - encode_thread_([this] { ProcessWorkUnitsUntilTimeToQuit(); }) { - OSP_DCHECK_LE(1, params_.num_encode_threads); - OSP_DCHECK_LE(kMinQuantizer, params_.min_quantizer); - OSP_DCHECK_LE(params_.min_quantizer, params_.max_cpu_saver_quantizer); - OSP_DCHECK_LE(params_.max_cpu_saver_quantizer, params_.max_quantizer); - OSP_DCHECK_LE(params_.max_quantizer, kMaxQuantizer); - OSP_DCHECK_LT(0.0, params_.max_time_utilization); - OSP_DCHECK_LE(params_.max_time_utilization, 1.0); - OSP_DCHECK(main_task_runner_); - OSP_DCHECK(sender_); + : StreamingVideoEncoder(params, task_runner, sender) { + ideal_speed_setting_ = kHighestEncodingSpeed; + encode_thread_ = std::thread([this] { ProcessWorkUnitsUntilTimeToQuit(); }); vpx_codec_iface_t* ctx; if (params_.codec == VideoCodec::kVp9) { @@ -242,9 +227,9 @@ void StreamingVpxEncoder::ProcessWorkUnitsUntilTimeToQuit() { // measured. const Clock::time_point encode_start_time = Clock::now(); PrepareEncoder(work_unit.image->d_w, work_unit.image->d_h, target_bitrate); - EncodeFrame(force_key_frame, &work_unit); + EncodeFrame(force_key_frame, work_unit); ComputeFrameEncodeStats(Clock::now() - encode_start_time, target_bitrate, - &work_unit); + work_unit); UpdateSpeedSettingForNextFrame(work_unit.stats); main_task_runner_->PostTask( @@ -337,7 +322,7 @@ void StreamingVpxEncoder::PrepareEncoder(int width, } void StreamingVpxEncoder::EncodeFrame(bool force_key_frame, - WorkUnitWithResults* work_unit) { + WorkUnitWithResults& work_unit) { OSP_DCHECK_EQ(std::this_thread::get_id(), encode_thread_.get_id()); // The presentation timestamp argument here is fixed to zero to force the @@ -346,8 +331,8 @@ void StreamingVpxEncoder::EncodeFrame(bool force_key_frame, const vpx_codec_pts_t pts = 0; const vpx_enc_frame_flags_t flags = force_key_frame ? VPX_EFLAG_FORCE_KF : 0; const auto encode_result = - vpx_codec_encode(&encoder_, work_unit->image.get(), pts, - work_unit->duration.count(), flags, VPX_DL_REALTIME); + vpx_codec_encode(&encoder_, work_unit.image.get(), pts, + work_unit.duration.count(), flags, VPX_DL_REALTIME); OSP_CHECK_EQ(encode_result, VPX_CODEC_OK); const vpx_codec_cx_pkt_t* pkt; @@ -366,30 +351,30 @@ void StreamingVpxEncoder::EncodeFrame(bool force_key_frame, // be copied at some point anyway, to be passed back to the main thread. auto* const begin = static_cast<const uint8_t*>(pkt->data.frame.buf); auto* const end = begin + pkt->data.frame.sz; - work_unit->payload.assign(begin, end); - work_unit->is_key_frame = !!(pkt->data.frame.flags & VPX_FRAME_IS_KEY); + work_unit.payload.assign(begin, end); + work_unit.is_key_frame = !!(pkt->data.frame.flags & VPX_FRAME_IS_KEY); } void StreamingVpxEncoder::ComputeFrameEncodeStats( Clock::duration encode_wall_time, int target_bitrate, - WorkUnitWithResults* work_unit) { + WorkUnitWithResults& work_unit) { OSP_DCHECK_EQ(std::this_thread::get_id(), encode_thread_.get_id()); - Stats& stats = work_unit->stats; + Stats& stats = work_unit.stats; // Note: stats.frame_id is set later, in SendEncodedFrame(). - stats.rtp_timestamp = work_unit->rtp_timestamp; + stats.rtp_timestamp = work_unit.rtp_timestamp; stats.encode_wall_time = encode_wall_time; - stats.frame_duration = work_unit->duration; - stats.encoded_size = work_unit->payload.size(); + stats.frame_duration = work_unit.duration; + stats.encoded_size = work_unit.payload.size(); constexpr double kBytesPerBit = 1.0 / CHAR_BIT; constexpr double kSecondsPerClockTick = 1.0 / Clock::to_duration(seconds(1)).count(); const double target_bytes_per_clock_tick = target_bitrate * (kBytesPerBit * kSecondsPerClockTick); - stats.target_size = target_bytes_per_clock_tick * work_unit->duration.count(); + stats.target_size = target_bytes_per_clock_tick * work_unit.duration.count(); // The quantizer the encoder used. This is the result of the VP8/9 encoder // taking a guess at what quantizer value would produce an encoded frame size @@ -404,33 +389,6 @@ void StreamingVpxEncoder::ComputeFrameEncodeStats( stats.perfect_quantizer = stats.quantizer * stats.space_utilization(); } -void StreamingVpxEncoder::UpdateSpeedSettingForNextFrame(const Stats& stats) { - OSP_DCHECK_EQ(std::this_thread::get_id(), encode_thread_.get_id()); - - // Combine the speed setting that was used to encode the last frame, and the - // quantizer the encoder chose into a single speed metric. - const double speed = current_speed_setting_ + - kEquivalentEncodingSpeedStepPerQuantizerStep * - std::max(0, stats.quantizer - params_.min_quantizer); - - // Like |Stats::perfect_quantizer|, this computes a "hindsight" speed setting - // for the last frame, one that may have potentially allowed for a - // better-quality quantizer choice by the encoder, while also keeping CPU - // utilization within budget. - const double perfect_speed = - speed * stats.time_utilization() / params_.max_time_utilization; - - // Update the ideal speed setting, to be used for the next frame. An - // exponentially-decaying weighted average is used here to smooth-out noise. - // The weight is based on the duration of the frame that was encoded. - constexpr Clock::duration kDecayHalfLife = milliseconds(120); - const double ticks = stats.frame_duration.count(); - const double weight = ticks / (ticks + kDecayHalfLife.count()); - ideal_speed_setting_ = - weight * perfect_speed + (1.0 - weight) * ideal_speed_setting_; - OSP_DCHECK(std::isfinite(ideal_speed_setting_)); -} - void StreamingVpxEncoder::SendEncodedFrame(WorkUnitWithResults results) { OSP_DCHECK(main_task_runner_->IsRunningOnTaskRunner()); @@ -460,25 +418,6 @@ void StreamingVpxEncoder::SendEncodedFrame(WorkUnitWithResults results) { } } -namespace { -void CopyPlane(const uint8_t* src, - int src_stride, - int num_rows, - uint8_t* dst, - int dst_stride) { - if (src_stride == dst_stride) { - memcpy(dst, src, src_stride * num_rows); - return; - } - const int bytes_per_row = std::min(src_stride, dst_stride); - while (--num_rows >= 0) { - memcpy(dst, src, bytes_per_row); - dst += dst_stride; - src += src_stride; - } -} -} // namespace - // static StreamingVpxEncoder::VpxImageUniquePtr StreamingVpxEncoder::CloneAsVpxImage( const VideoFrame& frame) { |