aboutsummaryrefslogtreecommitdiff
path: root/cast/standalone_sender/streaming_vpx_encoder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'cast/standalone_sender/streaming_vpx_encoder.cc')
-rw-r--r--cast/standalone_sender/streaming_vpx_encoder.cc99
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) {