Reland "FrameCadenceAdapter: align video encoding to metronome"

This is a reland of commit b39c2a8464

Original change's description:
> FrameCadenceAdapter: align video encoding to metronome
>
> This CL aligns the video encoding tasks to metronome tick which
> similar with the metronome decoding.
>
> Design doc: https://docs.google.com/document/d/18PvEgS-DehClK6twCSCATOlX-j9acmXd-3vjb0tR9-Y
>
> Bug: b/304158952
> Change-Id: I262bd4a5097fdaeed559b9d7391a059ae86e2d63
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/327460
> Reviewed-by: Markus Handell <handellm@webrtc.org>
> Reviewed-by: Harald Alvestrand <hta@webrtc.org>
> Reviewed-by: Henrik Boström <hbos@webrtc.org>
> Commit-Queue: Zhaoliang Ma <zhaoliang.ma@intel.com>
> Cr-Commit-Position: refs/heads/main@{#41469}

Bug: b/304158952
Change-Id: Icf4e1ad91f5c98f3c32a88ffe4d6277e907353e6
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/333464
Reviewed-by: Harald Alvestrand <hta@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Markus Handell <handellm@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41479}
This commit is contained in:
Zhaoliang Ma 2024-01-08 10:44:15 +08:00 committed by WebRTC LUCI CQ
parent 55a61898a8
commit f089d7ea54
14 changed files with 310 additions and 23 deletions

View file

@ -49,6 +49,10 @@ void ForcedTickMetronome::Tick() {
FakeMetronome::FakeMetronome(TimeDelta tick_period)
: tick_period_(tick_period) {}
void FakeMetronome::SetTickPeriod(TimeDelta tick_period) {
tick_period_ = tick_period;
}
void FakeMetronome::RequestCallOnNextTick(
absl::AnyInvocable<void() &&> callback) {
TaskQueueBase* current = TaskQueueBase::Current();

View file

@ -55,12 +55,14 @@ class FakeMetronome : public Metronome {
public:
explicit FakeMetronome(TimeDelta tick_period);
void SetTickPeriod(TimeDelta tick_period);
// Metronome implementation.
void RequestCallOnNextTick(absl::AnyInvocable<void() &&> callback) override;
TimeDelta TickPeriod() const override;
private:
const TimeDelta tick_period_;
TimeDelta tick_period_;
std::vector<absl::AnyInvocable<void() &&>> callbacks_;
};

View file

@ -1442,6 +1442,10 @@ struct RTC_EXPORT PeerConnectionFactoryDependencies final {
transport_controller_send_factory;
// Metronome used for decoding, must be called on the worker thread.
std::unique_ptr<Metronome> decode_metronome;
// Metronome used for encoding, must be called on the worker thread.
// TODO(b/304158952): Consider merging into a single metronome for all codec
// usage.
std::unique_ptr<Metronome> encode_metronome;
// Media specific dependencies. Unused when `media_factory == nullptr`.
rtc::scoped_refptr<AudioDeviceModule> adm;

View file

@ -889,10 +889,11 @@ webrtc::VideoSendStream* Call::CreateVideoSendStream(
VideoSendStream* send_stream = new VideoSendStream(
&env_.clock(), num_cpu_cores_, &env_.task_queue_factory(),
network_thread_, call_stats_->AsRtcpRttStats(), transport_send_.get(),
bitrate_allocator_.get(), video_send_delay_stats_.get(),
&env_.event_log(), std::move(config), std::move(encoder_config),
suspended_video_send_ssrcs_, suspended_video_payload_states_,
std::move(fec_controller), env_.field_trials());
config_.encode_metronome, bitrate_allocator_.get(),
video_send_delay_stats_.get(), &env_.event_log(), std::move(config),
std::move(encoder_config), suspended_video_send_ssrcs_,
suspended_video_payload_states_, std::move(fec_controller),
env_.field_trials());
for (uint32_t ssrc : ssrcs) {
RTC_DCHECK(video_send_ssrcs_.find(ssrc) == video_send_ssrcs_.end());

View file

@ -69,6 +69,7 @@ struct CallConfig {
rtp_transport_controller_send_factory = nullptr;
Metronome* decode_metronome = nullptr;
Metronome* encode_metronome = nullptr;
// The burst interval of the pacer, see TaskQueuePacedSender constructor.
absl::optional<TimeDelta> pacer_burst_interval;

View file

@ -103,7 +103,8 @@ PeerConnectionFactory::PeerConnectionFactory(
(dependencies->transport_controller_send_factory)
? std::move(dependencies->transport_controller_send_factory)
: std::make_unique<RtpTransportControllerSendFactory>()),
decode_metronome_(std::move(dependencies->decode_metronome)) {}
decode_metronome_(std::move(dependencies->decode_metronome)),
encode_metronome_(std::move(dependencies->encode_metronome)) {}
PeerConnectionFactory::PeerConnectionFactory(
PeerConnectionFactoryDependencies dependencies)
@ -119,6 +120,7 @@ PeerConnectionFactory::~PeerConnectionFactory() {
worker_thread()->BlockingCall([this] {
RTC_DCHECK_RUN_ON(worker_thread());
decode_metronome_ = nullptr;
encode_metronome_ = nullptr;
});
}
@ -344,6 +346,7 @@ std::unique_ptr<Call> PeerConnectionFactory::CreateCall_w(
call_config.rtp_transport_controller_send_factory =
transport_controller_send_factory_.get();
call_config.decode_metronome = decode_metronome_.get();
call_config.encode_metronome = encode_metronome_.get();
call_config.pacer_burst_interval = configuration.pacer_burst_interval;
return context_->call_factory()->CreateCall(call_config);
}

View file

@ -148,6 +148,7 @@ class PeerConnectionFactory : public PeerConnectionFactoryInterface {
const std::unique_ptr<RtpTransportControllerSendFactoryInterface>
transport_controller_send_factory_;
std::unique_ptr<Metronome> decode_metronome_ RTC_GUARDED_BY(worker_thread());
std::unique_ptr<Metronome> encode_metronome_ RTC_GUARDED_BY(worker_thread());
};
} // namespace webrtc

View file

@ -92,6 +92,7 @@ rtc_library("video") {
"../api/crypto:frame_decryptor_interface",
"../api/crypto:options",
"../api/environment",
"../api/metronome",
"../api/task_queue",
"../api/task_queue:pending_task_safety_flag",
"../api/units:data_rate",
@ -230,6 +231,7 @@ rtc_library("frame_cadence_adapter") {
deps = [
"../api:field_trials_view",
"../api:sequence_checker",
"../api/metronome",
"../api/task_queue",
"../api/task_queue:pending_task_safety_flag",
"../api/units:time_delta",
@ -253,6 +255,7 @@ rtc_library("frame_cadence_adapter") {
absl_deps = [
"//third_party/abseil-cpp/absl/algorithm:container",
"//third_party/abseil-cpp/absl/base:core_headers",
"//third_party/abseil-cpp/absl/cleanup:cleanup",
]
}

View file

@ -19,6 +19,7 @@
#include "absl/algorithm/container.h"
#include "absl/base/attributes.h"
#include "absl/cleanup/cleanup.h"
#include "api/sequence_checker.h"
#include "api/task_queue/pending_task_safety_flag.h"
#include "api/task_queue/task_queue_base.h"
@ -234,10 +235,81 @@ class ZeroHertzAdapterMode : public AdapterMode {
ScopedTaskSafety safety_;
};
// Implements a frame cadence adapter supporting VSync aligned encoding.
class VSyncEncodeAdapterMode : public AdapterMode {
public:
VSyncEncodeAdapterMode(
Clock* clock,
TaskQueueBase* queue,
rtc::scoped_refptr<PendingTaskSafetyFlag> queue_safety_flag,
Metronome* metronome,
TaskQueueBase* worker_queue,
FrameCadenceAdapterInterface::Callback* callback)
: clock_(clock),
queue_(queue),
queue_safety_flag_(queue_safety_flag),
callback_(callback),
metronome_(metronome),
worker_queue_(worker_queue) {
queue_sequence_checker_.Detach();
worker_sequence_checker_.Detach();
}
// Adapter overrides.
void OnFrame(Timestamp post_time,
bool queue_overload,
const VideoFrame& frame) override;
absl::optional<uint32_t> GetInputFrameRateFps() override {
RTC_DCHECK_RUN_ON(&queue_sequence_checker_);
return input_framerate_.Rate(clock_->TimeInMilliseconds());
}
void UpdateFrameRate() override {
RTC_DCHECK_RUN_ON(&queue_sequence_checker_);
input_framerate_.Update(1, clock_->TimeInMilliseconds());
}
void EncodeAllEnqueuedFrames();
private:
// Holds input frames coming from the client ready to be encoded.
struct InputFrameRef {
InputFrameRef(const VideoFrame& video_frame, Timestamp time_when_posted_us)
: time_when_posted_us(time_when_posted_us),
video_frame(std::move(video_frame)) {}
Timestamp time_when_posted_us;
const VideoFrame video_frame;
};
Clock* const clock_;
TaskQueueBase* queue_;
RTC_NO_UNIQUE_ADDRESS SequenceChecker queue_sequence_checker_;
rtc::scoped_refptr<PendingTaskSafetyFlag> queue_safety_flag_;
// Input frame rate statistics for use when not in zero-hertz mode.
RateStatistics input_framerate_ RTC_GUARDED_BY(queue_sequence_checker_){
FrameCadenceAdapterInterface::kFrameRateAveragingWindowSizeMs, 1000};
FrameCadenceAdapterInterface::Callback* const callback_;
Metronome* metronome_;
TaskQueueBase* const worker_queue_;
RTC_NO_UNIQUE_ADDRESS SequenceChecker worker_sequence_checker_;
// `worker_safety_` protects tasks on the worker queue related to `metronome_`
// since metronome usage must happen on worker thread.
ScopedTaskSafetyDetached worker_safety_;
Timestamp expected_next_tick_ RTC_GUARDED_BY(worker_sequence_checker_) =
Timestamp::PlusInfinity();
// Vector of input frames to be encoded.
std::vector<InputFrameRef> input_queue_
RTC_GUARDED_BY(worker_sequence_checker_);
};
class FrameCadenceAdapterImpl : public FrameCadenceAdapterInterface {
public:
FrameCadenceAdapterImpl(Clock* clock,
TaskQueueBase* queue,
Metronome* metronome,
TaskQueueBase* worker_queue,
const FieldTrialsView& field_trials);
~FrameCadenceAdapterImpl();
@ -273,6 +345,10 @@ class FrameCadenceAdapterImpl : public FrameCadenceAdapterInterface {
// - zero-hertz mode enabled
bool IsZeroHertzScreenshareEnabled() const RTC_RUN_ON(queue_);
// Configures current adapter on non-ZeroHertz mode, called when Initialize or
// MaybeReconfigureAdapters.
void ConfigureCurrentAdapterWithoutZeroHertz();
// Handles adapter creation on configuration changes.
void MaybeReconfigureAdapters(bool was_zero_hertz_enabled) RTC_RUN_ON(queue_);
@ -283,14 +359,21 @@ class FrameCadenceAdapterImpl : public FrameCadenceAdapterInterface {
// 0 Hz.
const bool zero_hertz_screenshare_enabled_;
// The two possible modes we're under.
// The three possible modes we're under.
absl::optional<PassthroughAdapterMode> passthrough_adapter_;
absl::optional<ZeroHertzAdapterMode> zero_hertz_adapter_;
// The `vsync_encode_adapter_` must be destroyed on the worker queue since
// VSync metronome needs to happen on worker thread.
std::unique_ptr<VSyncEncodeAdapterMode> vsync_encode_adapter_;
// If set, zero-hertz mode has been enabled.
absl::optional<ZeroHertzModeParams> zero_hertz_params_;
// Cache for the current adapter mode.
AdapterMode* current_adapter_mode_ = nullptr;
// VSync encoding is used when this valid.
Metronome* const metronome_;
TaskQueueBase* const worker_queue_;
// Timestamp for statistics reporting.
absl::optional<Timestamp> zero_hertz_adapter_created_timestamp_
RTC_GUARDED_BY(queue_);
@ -620,23 +703,98 @@ void ZeroHertzAdapterMode::MaybeStartRefreshFrameRequester() {
}
}
void VSyncEncodeAdapterMode::OnFrame(Timestamp post_time,
bool queue_overload,
const VideoFrame& frame) {
// We expect `metronome_` and `EncodeAllEnqueuedFrames()` runs on
// `worker_queue_`.
if (!worker_queue_->IsCurrent()) {
worker_queue_->PostTask(SafeTask(
worker_safety_.flag(), [this, post_time, queue_overload, frame] {
OnFrame(post_time, queue_overload, frame);
}));
return;
}
RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
TRACE_EVENT0("webrtc", "VSyncEncodeAdapterMode::OnFrame");
input_queue_.emplace_back(std::move(frame), post_time);
// The `metronome_` tick period maybe throttled in some case, so here we only
// align encode task to VSync event when `metronome_` tick period is less
// than 34ms (30Hz).
static constexpr TimeDelta kMaxAllowedDelay = TimeDelta::Millis(34);
if (metronome_->TickPeriod() <= kMaxAllowedDelay) {
// The metronome is ticking frequently enough that it is worth the extra
// delay.
metronome_->RequestCallOnNextTick(
SafeTask(worker_safety_.flag(), [this] { EncodeAllEnqueuedFrames(); }));
} else {
// The metronome is ticking too infrequently, encode immediately.
EncodeAllEnqueuedFrames();
}
}
void VSyncEncodeAdapterMode::EncodeAllEnqueuedFrames() {
RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
TRACE_EVENT0("webrtc", "VSyncEncodeAdapterMode::EncodeAllEnqueuedFrames");
// Local time in webrtc time base.
Timestamp post_time = clock_->CurrentTime();
for (auto& input : input_queue_) {
TRACE_EVENT1("webrtc", "FrameCadenceAdapterImpl::EncodeAllEnqueuedFrames",
"VSyncEncodeDelay",
(post_time - input.time_when_posted_us).ms());
const VideoFrame frame = std::move(input.video_frame);
queue_->PostTask(SafeTask(queue_safety_flag_, [this, post_time, frame] {
RTC_DCHECK_RUN_ON(queue_);
// TODO(b/304158952): Support more refined queue overload control.
callback_->OnFrame(post_time, /*queue_overload=*/false, frame);
}));
}
input_queue_.clear();
}
FrameCadenceAdapterImpl::FrameCadenceAdapterImpl(
Clock* clock,
TaskQueueBase* queue,
Metronome* metronome,
TaskQueueBase* worker_queue,
const FieldTrialsView& field_trials)
: clock_(clock),
queue_(queue),
zero_hertz_screenshare_enabled_(
!field_trials.IsDisabled("WebRTC-ZeroHertzScreenshare")) {}
!field_trials.IsDisabled("WebRTC-ZeroHertzScreenshare")),
metronome_(metronome),
worker_queue_(worker_queue) {}
FrameCadenceAdapterImpl::~FrameCadenceAdapterImpl() {
RTC_DLOG(LS_VERBOSE) << __func__ << " this " << this;
// VSync adapter needs to be destroyed on worker queue when metronome is
// valid.
if (metronome_) {
absl::Cleanup cleanup = [adapter = std::move(vsync_encode_adapter_)] {};
worker_queue_->PostTask([cleanup = std::move(cleanup)] {});
}
}
void FrameCadenceAdapterImpl::Initialize(Callback* callback) {
callback_ = callback;
passthrough_adapter_.emplace(clock_, callback);
current_adapter_mode_ = &passthrough_adapter_.value();
// Use VSync encode mode if metronome is valid, otherwise passthrough mode
// would be used.
if (metronome_) {
vsync_encode_adapter_ = std::make_unique<VSyncEncodeAdapterMode>(
clock_, queue_, safety_.flag(), metronome_, worker_queue_, callback_);
} else {
passthrough_adapter_.emplace(clock_, callback);
}
ConfigureCurrentAdapterWithoutZeroHertz();
}
void FrameCadenceAdapterImpl::SetZeroHertzModeEnabled(
@ -655,9 +813,16 @@ absl::optional<uint32_t> FrameCadenceAdapterImpl::GetInputFrameRateFps() {
void FrameCadenceAdapterImpl::UpdateFrameRate() {
RTC_DCHECK_RUN_ON(queue_);
// The frame rate need not be updated for the zero-hertz adapter. The
// passthrough adapter however uses it. Always pass frames into the
// passthrough to keep the estimation alive should there be an adapter switch.
passthrough_adapter_->UpdateFrameRate();
// vsync encode and passthrough adapter however uses it. Always pass frames
// into the vsync encode or passthrough to keep the estimation alive should
// there be an adapter switch.
if (metronome_) {
RTC_CHECK(vsync_encode_adapter_);
vsync_encode_adapter_->UpdateFrameRate();
} else {
RTC_CHECK(passthrough_adapter_);
passthrough_adapter_->UpdateFrameRate();
}
}
void FrameCadenceAdapterImpl::UpdateLayerQualityConvergence(
@ -757,6 +922,17 @@ bool FrameCadenceAdapterImpl::IsZeroHertzScreenshareEnabled() const {
zero_hertz_params_.has_value();
}
void FrameCadenceAdapterImpl::ConfigureCurrentAdapterWithoutZeroHertz() {
// Enable VSyncEncodeAdapterMode if metronome is valid.
if (metronome_) {
RTC_CHECK(vsync_encode_adapter_);
current_adapter_mode_ = vsync_encode_adapter_.get();
} else {
RTC_CHECK(passthrough_adapter_);
current_adapter_mode_ = &passthrough_adapter_.value();
}
}
void FrameCadenceAdapterImpl::MaybeReconfigureAdapters(
bool was_zero_hertz_enabled) {
RTC_DCHECK_RUN_ON(queue_);
@ -780,7 +956,7 @@ void FrameCadenceAdapterImpl::MaybeReconfigureAdapters(
zero_hertz_adapter_ = absl::nullopt;
RTC_LOG(LS_INFO) << "Zero hertz mode disabled.";
}
current_adapter_mode_ = &passthrough_adapter_.value();
ConfigureCurrentAdapterWithoutZeroHertz();
}
}
@ -789,8 +965,11 @@ void FrameCadenceAdapterImpl::MaybeReconfigureAdapters(
std::unique_ptr<FrameCadenceAdapterInterface>
FrameCadenceAdapterInterface::Create(Clock* clock,
TaskQueueBase* queue,
Metronome* metronome,
TaskQueueBase* worker_queue,
const FieldTrialsView& field_trials) {
return std::make_unique<FrameCadenceAdapterImpl>(clock, queue, field_trials);
return std::make_unique<FrameCadenceAdapterImpl>(clock, queue, metronome,
worker_queue, field_trials);
}
} // namespace webrtc

View file

@ -15,6 +15,7 @@
#include "absl/base/attributes.h"
#include "api/field_trials_view.h"
#include "api/metronome/metronome.h"
#include "api/task_queue/task_queue_base.h"
#include "api/units/time_delta.h"
#include "api/video/video_frame.h"
@ -81,6 +82,8 @@ class FrameCadenceAdapterInterface
static std::unique_ptr<FrameCadenceAdapterInterface> Create(
Clock* clock,
TaskQueueBase* queue,
Metronome* metronome,
TaskQueueBase* worker_queue,
const FieldTrialsView& field_trials);
// Call before using the rest of the API.

View file

@ -14,6 +14,7 @@
#include <vector>
#include "absl/functional/any_invocable.h"
#include "api/metronome/test/fake_metronome.h"
#include "api/task_queue/default_task_queue_factory.h"
#include "api/task_queue/task_queue_base.h"
#include "api/task_queue/task_queue_factory.h"
@ -64,8 +65,9 @@ VideoFrame CreateFrameWithTimestamps(
std::unique_ptr<FrameCadenceAdapterInterface> CreateAdapter(
const FieldTrialsView& field_trials,
Clock* clock) {
return FrameCadenceAdapterInterface::Create(clock, TaskQueueBase::Current(),
field_trials);
return FrameCadenceAdapterInterface::Create(
clock, TaskQueueBase::Current(), /*metronome=*/nullptr,
/*worker_queue=*/nullptr, field_trials);
}
class MockCallback : public FrameCadenceAdapterInterface::Callback {
@ -593,7 +595,8 @@ TEST(FrameCadenceAdapterTest, IgnoresDropInducedCallbacksPostDestruction) {
auto queue = time_controller.GetTaskQueueFactory()->CreateTaskQueue(
"queue", TaskQueueFactory::Priority::NORMAL);
auto adapter = FrameCadenceAdapterInterface::Create(
time_controller.GetClock(), queue.get(), enabler);
time_controller.GetClock(), queue.get(), /*metronome=*/nullptr,
/*worker_queue=*/nullptr, enabler);
queue->PostTask([&adapter, &callback] {
adapter->Initialize(callback.get());
adapter->SetZeroHertzModeEnabled(
@ -609,6 +612,82 @@ TEST(FrameCadenceAdapterTest, IgnoresDropInducedCallbacksPostDestruction) {
time_controller.AdvanceTime(3 * TimeDelta::Seconds(1) / kMaxFps);
}
TEST(FrameCadenceAdapterTest, EncodeFramesAreAlignedWithMetronomeTick) {
ZeroHertzFieldTrialEnabler enabler;
GlobalSimulatedTimeController time_controller(Timestamp::Zero());
// Here the metronome interval is 33ms, because the metronome is not
// infrequent then the encode tasks are aligned with the tick period.
static constexpr TimeDelta kTickPeriod = TimeDelta::Millis(33);
auto queue = time_controller.GetTaskQueueFactory()->CreateTaskQueue(
"queue", TaskQueueFactory::Priority::NORMAL);
auto worker_queue = time_controller.GetTaskQueueFactory()->CreateTaskQueue(
"work_queue", TaskQueueFactory::Priority::NORMAL);
static test::FakeMetronome metronome(kTickPeriod);
auto adapter = FrameCadenceAdapterInterface::Create(
time_controller.GetClock(), queue.get(), &metronome, worker_queue.get(),
enabler);
MockCallback callback;
adapter->Initialize(&callback);
auto frame = CreateFrame();
// `callback->OnFrame()` would not be called if only 32ms went by after
// `adapter->OnFrame()`.
EXPECT_CALL(callback, OnFrame(_, false, _)).Times(0);
adapter->OnFrame(frame);
time_controller.AdvanceTime(TimeDelta::Millis(32));
Mock::VerifyAndClearExpectations(&callback);
// `callback->OnFrame()` should be called if 33ms went by after
// `adapter->OnFrame()`.
EXPECT_CALL(callback, OnFrame(_, false, _)).Times(1);
time_controller.AdvanceTime(TimeDelta::Millis(1));
Mock::VerifyAndClearExpectations(&callback);
// `callback->OnFrame()` would not be called if only 32ms went by after
// `adapter->OnFrame()`.
EXPECT_CALL(callback, OnFrame(_, false, _)).Times(0);
// Send two frame before next tick.
adapter->OnFrame(frame);
adapter->OnFrame(frame);
time_controller.AdvanceTime(TimeDelta::Millis(32));
Mock::VerifyAndClearExpectations(&callback);
// `callback->OnFrame()` should be called if 33ms went by after
// `adapter->OnFrame()`.
EXPECT_CALL(callback, OnFrame(_, false, _)).Times(2);
time_controller.AdvanceTime(TimeDelta::Millis(1));
Mock::VerifyAndClearExpectations(&callback);
// Change the metronome tick period to 67ms (15Hz).
metronome.SetTickPeriod(TimeDelta::Millis(67));
// Expect the encode would happen immediately.
EXPECT_CALL(callback, OnFrame(_, false, _)).Times(1);
adapter->OnFrame(frame);
time_controller.AdvanceTime(TimeDelta::Zero());
Mock::VerifyAndClearExpectations(&callback);
// Change the metronome tick period to 16ms (60Hz).
metronome.SetTickPeriod(TimeDelta::Millis(16));
// Expect the encode would not happen if only 15ms went by after
// `adapter->OnFrame()`.
EXPECT_CALL(callback, OnFrame(_, false, _)).Times(0);
adapter->OnFrame(frame);
time_controller.AdvanceTime(TimeDelta::Millis(15));
Mock::VerifyAndClearExpectations(&callback);
// `callback->OnFrame()` should be called if 16ms went by after
// `adapter->OnFrame()`.
EXPECT_CALL(callback, OnFrame(_, false, _)).Times(1);
time_controller.AdvanceTime(TimeDelta::Millis(1));
Mock::VerifyAndClearExpectations(&callback);
rtc::Event finalized;
queue->PostTask([&] {
adapter = nullptr;
finalized.Set();
});
finalized.Wait(rtc::Event::kForever);
}
class FrameCadenceAdapterSimulcastLayersParamTest
: public ::testing::TestWithParam<int> {
public:

View file

@ -114,6 +114,7 @@ std::unique_ptr<VideoStreamEncoder> CreateVideoStreamEncoder(
VideoStreamEncoder::BitrateAllocationCallbackType
bitrate_allocation_callback_type,
const FieldTrialsView& field_trials,
Metronome* metronome,
webrtc::VideoEncoderFactory::EncoderSelectorInterface* encoder_selector) {
std::unique_ptr<TaskQueueBase, TaskQueueDeleter> encoder_queue =
task_queue_factory->CreateTaskQueue("EncoderQueue",
@ -122,8 +123,9 @@ std::unique_ptr<VideoStreamEncoder> CreateVideoStreamEncoder(
return std::make_unique<VideoStreamEncoder>(
clock, num_cpu_cores, stats_proxy, encoder_settings,
std::make_unique<OveruseFrameDetector>(stats_proxy),
FrameCadenceAdapterInterface::Create(clock, encoder_queue_ptr,
field_trials),
FrameCadenceAdapterInterface::Create(
clock, encoder_queue_ptr, metronome,
/*worker_queue=*/TaskQueueBase::Current(), field_trials),
std::move(encoder_queue), bitrate_allocation_callback_type, field_trials,
encoder_selector);
}
@ -139,6 +141,7 @@ VideoSendStream::VideoSendStream(
TaskQueueBase* network_queue,
RtcpRttStats* call_stats,
RtpTransportControllerSendInterface* transport,
Metronome* metronome,
BitrateAllocatorInterface* bitrate_allocator,
SendDelayStats* send_delay_stats,
RtcEventLog* event_log,
@ -161,6 +164,7 @@ VideoSendStream::VideoSendStream(
config_.encoder_settings,
GetBitrateAllocationCallbackType(config_, field_trials),
field_trials,
metronome,
config_.encoder_selector)),
encoder_feedback_(
clock,

View file

@ -18,6 +18,7 @@
#include "api/fec_controller.h"
#include "api/field_trials_view.h"
#include "api/metronome/metronome.h"
#include "api/sequence_checker.h"
#include "api/task_queue/pending_task_safety_flag.h"
#include "call/bitrate_allocator.h"
@ -62,6 +63,7 @@ class VideoSendStream : public webrtc::VideoSendStream {
TaskQueueBase* network_queue,
RtcpRttStats* call_stats,
RtpTransportControllerSendInterface* transport,
Metronome* metronome,
BitrateAllocatorInterface* bitrate_allocator,
SendDelayStats* send_delay_stats,
RtcEventLog* event_log,

View file

@ -875,8 +875,9 @@ class VideoStreamEncoderTest : public ::testing::Test {
"EncoderQueue", TaskQueueFactory::Priority::NORMAL);
TaskQueueBase* encoder_queue_ptr = encoder_queue.get();
std::unique_ptr<FrameCadenceAdapterInterface> cadence_adapter =
FrameCadenceAdapterInterface::Create(time_controller_.GetClock(),
encoder_queue_ptr, field_trials_);
FrameCadenceAdapterInterface::Create(
time_controller_.GetClock(), encoder_queue_ptr,
/*metronome=*/nullptr, /*worker_queue=*/nullptr, field_trials_);
video_stream_encoder_ = std::make_unique<VideoStreamEncoderUnderTest>(
&time_controller_, std::move(cadence_adapter), std::move(encoder_queue),
stats_proxy_.get(), video_send_config_.encoder_settings,
@ -9556,7 +9557,7 @@ TEST(VideoStreamEncoderFrameCadenceTest,
"WebRTC-ZeroHertzScreenshare/Enabled/");
auto adapter = FrameCadenceAdapterInterface::Create(
factory.GetTimeController()->GetClock(), encoder_queue.get(),
field_trials);
/*metronome=*/nullptr, /*worker_queue=*/nullptr, field_trials);
FrameCadenceAdapterInterface* adapter_ptr = adapter.get();
MockVideoSourceInterface mock_source;