Switch VideoReceiveStream2 internals to Time units
Change-Id: Ifcee6372120e968499acbdf3bf2c0d002d1c4724 Bug: webrtc:13756 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/259777 Reviewed-by: Erik Språng <sprang@webrtc.org> Commit-Queue: Evan Shrubsole <eshr@webrtc.org> Reviewed-by: Tomas Gunnarsson <tommi@webrtc.org> Reviewed-by: Johannes Kron <kron@google.com> Cr-Commit-Position: refs/heads/main@{#36685}
This commit is contained in:
parent
72efd91d1f
commit
d425f506ad
@ -32,6 +32,11 @@ namespace webrtc {
|
||||
// microseconds (us).
|
||||
class TimeDelta final : public rtc_units_impl::RelativeUnit<TimeDelta> {
|
||||
public:
|
||||
template <typename T>
|
||||
static constexpr TimeDelta Minutes(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
return Seconds(value * 60);
|
||||
}
|
||||
template <typename T>
|
||||
static constexpr TimeDelta Seconds(T value) {
|
||||
static_assert(std::is_arithmetic<T>::value, "");
|
||||
|
||||
@ -28,10 +28,12 @@ TEST(TimeDeltaTest, ConstExpr) {
|
||||
|
||||
static_assert(kTimeDeltaPlusInf > kTimeDeltaZero, "");
|
||||
|
||||
constexpr TimeDelta kTimeDeltaMinutes = TimeDelta::Minutes(kValue);
|
||||
constexpr TimeDelta kTimeDeltaSeconds = TimeDelta::Seconds(kValue);
|
||||
constexpr TimeDelta kTimeDeltaMs = TimeDelta::Millis(kValue);
|
||||
constexpr TimeDelta kTimeDeltaUs = TimeDelta::Micros(kValue);
|
||||
|
||||
static_assert(kTimeDeltaMinutes.seconds_or(0) == kValue * 60, "");
|
||||
static_assert(kTimeDeltaSeconds.seconds_or(0) == kValue, "");
|
||||
static_assert(kTimeDeltaMs.ms_or(0) == kValue, "");
|
||||
static_assert(kTimeDeltaUs.us_or(0) == kValue, "");
|
||||
@ -54,10 +56,12 @@ TEST(TimeDeltaTest, GetDifferentPrefix) {
|
||||
EXPECT_EQ(TimeDelta::Micros(kValue).seconds(), kValue / 1000000);
|
||||
EXPECT_EQ(TimeDelta::Millis(kValue).seconds(), kValue / 1000);
|
||||
EXPECT_EQ(TimeDelta::Micros(kValue).ms(), kValue / 1000);
|
||||
EXPECT_EQ(TimeDelta::Minutes(kValue / 60).seconds(), kValue);
|
||||
|
||||
EXPECT_EQ(TimeDelta::Millis(kValue).us(), kValue * 1000);
|
||||
EXPECT_EQ(TimeDelta::Seconds(kValue).ms(), kValue * 1000);
|
||||
EXPECT_EQ(TimeDelta::Seconds(kValue).us(), kValue * 1000000);
|
||||
EXPECT_EQ(TimeDelta::Minutes(kValue / 60).seconds(), kValue);
|
||||
}
|
||||
|
||||
TEST(TimeDeltaTest, IdentityChecks) {
|
||||
|
||||
@ -72,6 +72,7 @@ rtc_library("video") {
|
||||
"../api/crypto:options",
|
||||
"../api/rtc_event_log",
|
||||
"../api/task_queue",
|
||||
"../api/units:frequency",
|
||||
"../api/units:time_delta",
|
||||
"../api/units:timestamp",
|
||||
"../api/video:encoded_image",
|
||||
|
||||
@ -28,7 +28,9 @@
|
||||
#include "api/scoped_refptr.h"
|
||||
#include "api/sequence_checker.h"
|
||||
#include "api/task_queue/task_queue_base.h"
|
||||
#include "api/units/frequency.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "api/video/encoded_image.h"
|
||||
#include "api/video_codecs/h264_profile_level_id.h"
|
||||
#include "api/video_codecs/sdp_video_format.h"
|
||||
@ -70,14 +72,14 @@
|
||||
namespace webrtc {
|
||||
|
||||
namespace internal {
|
||||
constexpr int VideoReceiveStream2::kMaxWaitForKeyFrameMs;
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr int kMinBaseMinimumDelayMs = 0;
|
||||
constexpr int kMaxBaseMinimumDelayMs = 10000;
|
||||
|
||||
constexpr int kMaxWaitForFrameMs = 3000;
|
||||
// The default delay before re-requesting a key frame to be sent.
|
||||
constexpr TimeDelta kMaxWaitForKeyFrame = TimeDelta::Millis(200);
|
||||
constexpr TimeDelta kMinBaseMinimumDelay = TimeDelta::Zero();
|
||||
constexpr TimeDelta kMaxBaseMinimumDelay = TimeDelta::Seconds(10);
|
||||
constexpr TimeDelta kMaxWaitForFrame = TimeDelta::Seconds(3);
|
||||
|
||||
// Create a decoder for the preferred codec before the stream starts and any
|
||||
// other decoder lazily on demand.
|
||||
@ -178,25 +180,25 @@ bool IsKeyFrameAndUnspecifiedResolution(const EncodedFrame& frame) {
|
||||
// TODO(https://bugs.webrtc.org/9974): Consider removing this workaround.
|
||||
// Maximum time between frames before resetting the FrameBuffer to avoid RTP
|
||||
// timestamps wraparound to affect FrameBuffer.
|
||||
constexpr int kInactiveStreamThresholdMs = 600000; // 10 minutes.
|
||||
constexpr TimeDelta kInactiveStreamThreshold = TimeDelta::Minutes(10);
|
||||
|
||||
} // namespace
|
||||
|
||||
int DetermineMaxWaitForFrame(const VideoReceiveStream::Config& config,
|
||||
bool is_keyframe) {
|
||||
TimeDelta DetermineMaxWaitForFrame(const VideoReceiveStream::Config& config,
|
||||
bool is_keyframe) {
|
||||
// A (arbitrary) conversion factor between the remotely signalled NACK buffer
|
||||
// time (if not present defaults to 1000ms) and the maximum time we wait for a
|
||||
// remote frame. Chosen to not change existing defaults when using not
|
||||
// rtx-time.
|
||||
const int conversion_factor = 3;
|
||||
const TimeDelta rtp_history =
|
||||
TimeDelta::Millis(config.rtp.nack.rtp_history_ms);
|
||||
|
||||
if (config.rtp.nack.rtp_history_ms > 0 &&
|
||||
conversion_factor * config.rtp.nack.rtp_history_ms < kMaxWaitForFrameMs) {
|
||||
return is_keyframe ? config.rtp.nack.rtp_history_ms
|
||||
: conversion_factor * config.rtp.nack.rtp_history_ms;
|
||||
if (rtp_history > TimeDelta::Zero() &&
|
||||
conversion_factor * rtp_history < kMaxWaitForFrame) {
|
||||
return is_keyframe ? rtp_history : conversion_factor * rtp_history;
|
||||
}
|
||||
return is_keyframe ? VideoReceiveStream2::kMaxWaitForKeyFrameMs
|
||||
: kMaxWaitForFrameMs;
|
||||
return is_keyframe ? kMaxWaitForKeyFrame : kMaxWaitForFrame;
|
||||
}
|
||||
|
||||
VideoReceiveStream2::VideoReceiveStream2(
|
||||
@ -242,8 +244,8 @@ VideoReceiveStream2::VideoReceiveStream2(
|
||||
std::move(config_.frame_transformer),
|
||||
call->trials()),
|
||||
rtp_stream_sync_(call->worker_thread(), this),
|
||||
max_wait_for_keyframe_ms_(DetermineMaxWaitForFrame(config_, true)),
|
||||
max_wait_for_frame_ms_(DetermineMaxWaitForFrame(config_, false)),
|
||||
max_wait_for_keyframe_(DetermineMaxWaitForFrame(config_, true)),
|
||||
max_wait_for_frame_(DetermineMaxWaitForFrame(config_, false)),
|
||||
maximum_pre_stream_decoders_("max", kDefaultMaximumPreStreamDecoders),
|
||||
decode_sync_(decode_sync),
|
||||
decode_queue_(task_queue_factory_->CreateTaskQueue(
|
||||
@ -271,8 +273,8 @@ VideoReceiveStream2::VideoReceiveStream2(
|
||||
|
||||
frame_buffer_ = FrameBufferProxy::CreateFromFieldTrial(
|
||||
clock_, call_->worker_thread(), timing_.get(), &stats_proxy_,
|
||||
&decode_queue_, this, TimeDelta::Millis(max_wait_for_keyframe_ms_),
|
||||
TimeDelta::Millis(max_wait_for_frame_ms_), decode_sync_, call_->trials());
|
||||
&decode_queue_, this, max_wait_for_keyframe_, max_wait_for_frame_,
|
||||
decode_sync_, call_->trials());
|
||||
|
||||
if (config_.rtp.rtx_ssrc) {
|
||||
rtx_receive_stream_ = std::make_unique<RtxReceiveStream>(
|
||||
@ -566,18 +568,22 @@ void VideoReceiveStream2::UpdateHistograms() {
|
||||
|
||||
bool VideoReceiveStream2::SetBaseMinimumPlayoutDelayMs(int delay_ms) {
|
||||
RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
|
||||
if (delay_ms < kMinBaseMinimumDelayMs || delay_ms > kMaxBaseMinimumDelayMs) {
|
||||
TimeDelta delay = TimeDelta::Millis(delay_ms);
|
||||
if (delay < kMinBaseMinimumDelay || delay > kMaxBaseMinimumDelay) {
|
||||
return false;
|
||||
}
|
||||
|
||||
base_minimum_playout_delay_ms_ = delay_ms;
|
||||
base_minimum_playout_delay_ = delay;
|
||||
UpdatePlayoutDelays();
|
||||
return true;
|
||||
}
|
||||
|
||||
int VideoReceiveStream2::GetBaseMinimumPlayoutDelayMs() const {
|
||||
RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
|
||||
return base_minimum_playout_delay_ms_;
|
||||
constexpr TimeDelta kDefaultBaseMinPlayoutDelay = TimeDelta::Millis(-1);
|
||||
// Unset must be -1.
|
||||
static_assert(-1 == kDefaultBaseMinPlayoutDelay.ms(), "");
|
||||
return base_minimum_playout_delay_.value_or(kDefaultBaseMinPlayoutDelay).ms();
|
||||
}
|
||||
|
||||
void VideoReceiveStream2::OnFrame(const VideoFrame& video_frame) {
|
||||
@ -640,14 +646,14 @@ void VideoReceiveStream2::SendNack(
|
||||
rtp_video_stream_receiver_.RequestPacketRetransmit(sequence_numbers);
|
||||
}
|
||||
|
||||
void VideoReceiveStream2::RequestKeyFrame(int64_t timestamp_ms) {
|
||||
void VideoReceiveStream2::RequestKeyFrame(Timestamp now) {
|
||||
// Running on worker_sequence_checker_.
|
||||
// Called from RtpVideoStreamReceiver (rtp_video_stream_receiver_ is
|
||||
// ultimately responsible).
|
||||
rtp_video_stream_receiver_.RequestKeyFrame();
|
||||
decode_queue_.PostTask([this, timestamp_ms]() {
|
||||
decode_queue_.PostTask([this, now]() {
|
||||
RTC_DCHECK_RUN_ON(&decode_queue_);
|
||||
last_keyframe_request_ms_ = timestamp_ms;
|
||||
last_keyframe_request_ = now;
|
||||
});
|
||||
}
|
||||
|
||||
@ -658,21 +664,20 @@ void VideoReceiveStream2::OnCompleteFrame(std::unique_ptr<EncodedFrame> frame) {
|
||||
// TODO(https://bugs.webrtc.org/13343): Remove this check when FrameBuffer3 is
|
||||
// deployed. With FrameBuffer3, this case is properly handled and tested in
|
||||
// the FrameBufferProxyTest.PausedStream unit test.
|
||||
int64_t time_now_ms = clock_->TimeInMilliseconds();
|
||||
if (last_complete_frame_time_ms_ > 0 &&
|
||||
time_now_ms - last_complete_frame_time_ms_ > kInactiveStreamThresholdMs) {
|
||||
Timestamp time_now = clock_->CurrentTime();
|
||||
if (last_complete_frame_time_ &&
|
||||
time_now - *last_complete_frame_time_ > kInactiveStreamThreshold) {
|
||||
frame_buffer_->Clear();
|
||||
}
|
||||
last_complete_frame_time_ms_ = time_now_ms;
|
||||
last_complete_frame_time_ = time_now;
|
||||
|
||||
const VideoPlayoutDelay& playout_delay = frame->EncodedImage().playout_delay_;
|
||||
if (playout_delay.min_ms >= 0) {
|
||||
frame_minimum_playout_delay_ms_ = playout_delay.min_ms;
|
||||
frame_minimum_playout_delay_ = TimeDelta::Millis(playout_delay.min_ms);
|
||||
UpdatePlayoutDelays();
|
||||
}
|
||||
|
||||
if (playout_delay.max_ms >= 0) {
|
||||
frame_maximum_playout_delay_ms_ = playout_delay.max_ms;
|
||||
frame_maximum_playout_delay_ = TimeDelta::Millis(playout_delay.max_ms);
|
||||
UpdatePlayoutDelays();
|
||||
}
|
||||
|
||||
@ -725,14 +730,13 @@ void VideoReceiveStream2::SetEstimatedPlayoutNtpTimestampMs(
|
||||
|
||||
bool VideoReceiveStream2::SetMinimumPlayoutDelay(int delay_ms) {
|
||||
RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
|
||||
syncable_minimum_playout_delay_ms_ = delay_ms;
|
||||
syncable_minimum_playout_delay_ = TimeDelta::Millis(delay_ms);
|
||||
UpdatePlayoutDelays();
|
||||
return true;
|
||||
}
|
||||
|
||||
int64_t VideoReceiveStream2::GetMaxWaitMs() const {
|
||||
return keyframe_required_ ? max_wait_for_keyframe_ms_
|
||||
: max_wait_for_frame_ms_;
|
||||
TimeDelta VideoReceiveStream2::GetMaxWait() const {
|
||||
return keyframe_required_ ? max_wait_for_keyframe_ : max_wait_for_frame_;
|
||||
}
|
||||
|
||||
void VideoReceiveStream2::OnEncodedFrame(std::unique_ptr<EncodedFrame> frame) {
|
||||
@ -759,8 +763,7 @@ void VideoReceiveStream2::OnDecodableFrameTimeout(TimeDelta wait_time) {
|
||||
|
||||
// TODO(bugs.webrtc.org/11993): PostTask to the network thread.
|
||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||
HandleFrameBufferTimeout(now_ms, wait_time.ms());
|
||||
HandleFrameBufferTimeout(clock_->CurrentTime(), wait_time);
|
||||
|
||||
decode_queue_.PostTask([this] {
|
||||
RTC_DCHECK_RUN_ON(&decode_queue_);
|
||||
@ -771,7 +774,7 @@ void VideoReceiveStream2::OnDecodableFrameTimeout(TimeDelta wait_time) {
|
||||
void VideoReceiveStream2::HandleEncodedFrame(
|
||||
std::unique_ptr<EncodedFrame> frame) {
|
||||
// Running on `decode_queue_`.
|
||||
int64_t now_ms = clock_->TimeInMilliseconds();
|
||||
Timestamp now = clock_->CurrentTime();
|
||||
|
||||
// Current OnPreDecode only cares about QP for VP8.
|
||||
int qp = -1;
|
||||
@ -786,7 +789,8 @@ void VideoReceiveStream2::HandleEncodedFrame(
|
||||
int64_t decoded_frame_picture_id = -1;
|
||||
|
||||
const bool keyframe_request_is_due =
|
||||
now_ms >= (last_keyframe_request_ms_ + max_wait_for_keyframe_ms_);
|
||||
!last_keyframe_request_ ||
|
||||
now >= (*last_keyframe_request_ + max_wait_for_keyframe_);
|
||||
|
||||
if (!video_receiver_.IsExternalDecoderRegistered(frame->PayloadType())) {
|
||||
// Look for the decoder with this payload type.
|
||||
@ -823,14 +827,14 @@ void VideoReceiveStream2::HandleEncodedFrame(
|
||||
// TODO(bugs.webrtc.org/11993): Make this PostTask to the network thread.
|
||||
call_->worker_thread()->PostTask(ToQueuedTask(
|
||||
task_safety_,
|
||||
[this, now_ms, received_frame_is_keyframe, force_request_key_frame,
|
||||
[this, now, received_frame_is_keyframe, force_request_key_frame,
|
||||
decoded_frame_picture_id, keyframe_request_is_due]() {
|
||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||
|
||||
if (decoded_frame_picture_id != -1)
|
||||
rtp_video_stream_receiver_.FrameDecoded(decoded_frame_picture_id);
|
||||
|
||||
HandleKeyFrameGeneration(received_frame_is_keyframe, now_ms,
|
||||
HandleKeyFrameGeneration(received_frame_is_keyframe, now,
|
||||
force_request_key_frame,
|
||||
keyframe_request_is_due);
|
||||
}));
|
||||
@ -900,7 +904,7 @@ int VideoReceiveStream2::DecodeAndMaybeDispatchEncodedFrame(
|
||||
// RTC_RUN_ON(packet_sequence_checker_)
|
||||
void VideoReceiveStream2::HandleKeyFrameGeneration(
|
||||
bool received_frame_is_keyframe,
|
||||
int64_t now_ms,
|
||||
Timestamp now,
|
||||
bool always_request_key_frame,
|
||||
bool keyframe_request_is_due) {
|
||||
bool request_key_frame = always_request_key_frame;
|
||||
@ -910,7 +914,7 @@ void VideoReceiveStream2::HandleKeyFrameGeneration(
|
||||
if (received_frame_is_keyframe) {
|
||||
keyframe_generation_requested_ = false;
|
||||
} else if (keyframe_request_is_due) {
|
||||
if (!IsReceivingKeyFrame(now_ms)) {
|
||||
if (!IsReceivingKeyFrame(now)) {
|
||||
request_key_frame = true;
|
||||
}
|
||||
} else {
|
||||
@ -919,74 +923,75 @@ void VideoReceiveStream2::HandleKeyFrameGeneration(
|
||||
}
|
||||
|
||||
if (request_key_frame) {
|
||||
// HandleKeyFrameGeneration is initated from the decode thread -
|
||||
// HandleKeyFrameGeneration is initiated from the decode thread -
|
||||
// RequestKeyFrame() triggers a call back to the decode thread.
|
||||
// Perhaps there's a way to avoid that.
|
||||
RequestKeyFrame(now_ms);
|
||||
RequestKeyFrame(now);
|
||||
}
|
||||
}
|
||||
|
||||
// RTC_RUN_ON(packet_sequence_checker_)
|
||||
void VideoReceiveStream2::HandleFrameBufferTimeout(int64_t now_ms,
|
||||
int64_t wait_ms) {
|
||||
void VideoReceiveStream2::HandleFrameBufferTimeout(Timestamp now,
|
||||
TimeDelta wait) {
|
||||
absl::optional<int64_t> last_packet_ms =
|
||||
rtp_video_stream_receiver_.LastReceivedPacketMs();
|
||||
|
||||
// To avoid spamming keyframe requests for a stream that is not active we
|
||||
// check if we have received a packet within the last 5 seconds.
|
||||
constexpr TimeDelta kInactiveDuraction = TimeDelta::Seconds(5);
|
||||
const bool stream_is_active =
|
||||
last_packet_ms && now_ms - *last_packet_ms < 5000;
|
||||
last_packet_ms &&
|
||||
now - Timestamp::Millis(*last_packet_ms) < kInactiveDuraction;
|
||||
if (!stream_is_active)
|
||||
stats_proxy_.OnStreamInactive();
|
||||
|
||||
if (stream_is_active && !IsReceivingKeyFrame(now_ms) &&
|
||||
if (stream_is_active && !IsReceivingKeyFrame(now) &&
|
||||
(!config_.crypto_options.sframe.require_frame_encryption ||
|
||||
rtp_video_stream_receiver_.IsDecryptable())) {
|
||||
RTC_LOG(LS_WARNING) << "No decodable frame in " << wait_ms
|
||||
<< " ms, requesting keyframe.";
|
||||
RequestKeyFrame(now_ms);
|
||||
RTC_LOG(LS_WARNING) << "No decodable frame in " << wait
|
||||
<< ", requesting keyframe.";
|
||||
RequestKeyFrame(now);
|
||||
}
|
||||
}
|
||||
|
||||
// RTC_RUN_ON(packet_sequence_checker_)
|
||||
bool VideoReceiveStream2::IsReceivingKeyFrame(int64_t timestamp_ms) const {
|
||||
bool VideoReceiveStream2::IsReceivingKeyFrame(Timestamp now) const {
|
||||
absl::optional<int64_t> last_keyframe_packet_ms =
|
||||
rtp_video_stream_receiver_.LastReceivedKeyframePacketMs();
|
||||
|
||||
// If we recently have been receiving packets belonging to a keyframe then
|
||||
// we assume a keyframe is currently being received.
|
||||
bool receiving_keyframe =
|
||||
last_keyframe_packet_ms &&
|
||||
timestamp_ms - *last_keyframe_packet_ms < max_wait_for_keyframe_ms_;
|
||||
bool receiving_keyframe = last_keyframe_packet_ms &&
|
||||
now - Timestamp::Millis(*last_keyframe_packet_ms) <
|
||||
max_wait_for_keyframe_;
|
||||
return receiving_keyframe;
|
||||
}
|
||||
|
||||
void VideoReceiveStream2::UpdatePlayoutDelays() const {
|
||||
// Running on worker_sequence_checker_.
|
||||
const int minimum_delay_ms =
|
||||
std::max({frame_minimum_playout_delay_ms_, base_minimum_playout_delay_ms_,
|
||||
syncable_minimum_playout_delay_ms_});
|
||||
if (minimum_delay_ms >= 0) {
|
||||
timing_->set_min_playout_delay(TimeDelta::Millis(minimum_delay_ms));
|
||||
if (frame_minimum_playout_delay_ms_ == 0 &&
|
||||
frame_maximum_playout_delay_ms_ > 0) {
|
||||
// Since nullopt < anything, this will return the largest of the minumum
|
||||
// delays, or nullopt if all are nullopt.
|
||||
absl::optional<TimeDelta> minimum_delay =
|
||||
std::max({frame_minimum_playout_delay_, base_minimum_playout_delay_,
|
||||
syncable_minimum_playout_delay_});
|
||||
if (minimum_delay) {
|
||||
timing_->set_min_playout_delay(*minimum_delay);
|
||||
if (frame_minimum_playout_delay_ == TimeDelta::Zero() &&
|
||||
frame_maximum_playout_delay_ > TimeDelta::Zero()) {
|
||||
// TODO(kron): Estimate frame rate from video stream.
|
||||
constexpr double kFrameRate = 60.0;
|
||||
constexpr Frequency kFrameRate = Frequency::Hertz(60);
|
||||
// Convert playout delay in ms to number of frames.
|
||||
int max_composition_delay_in_frames = std::lrint(
|
||||
static_cast<double>(frame_maximum_playout_delay_ms_ * kFrameRate) /
|
||||
rtc::kNumMillisecsPerSec);
|
||||
int max_composition_delay_in_frames =
|
||||
std::lrint(*frame_maximum_playout_delay_ * kFrameRate);
|
||||
// Subtract frames in buffer.
|
||||
max_composition_delay_in_frames = std::max<int16_t>(
|
||||
max_composition_delay_in_frames - frame_buffer_->Size(), 0);
|
||||
timing_->SetMaxCompositionDelayInFrames(
|
||||
absl::make_optional(max_composition_delay_in_frames));
|
||||
max_composition_delay_in_frames =
|
||||
std::max(max_composition_delay_in_frames - frame_buffer_->Size(), 0);
|
||||
timing_->SetMaxCompositionDelayInFrames(max_composition_delay_in_frames);
|
||||
}
|
||||
}
|
||||
|
||||
const int maximum_delay_ms = frame_maximum_playout_delay_ms_;
|
||||
if (maximum_delay_ms >= 0) {
|
||||
timing_->set_max_playout_delay(TimeDelta::Millis(maximum_delay_ms));
|
||||
if (frame_maximum_playout_delay_) {
|
||||
timing_->set_max_playout_delay(*frame_maximum_playout_delay_);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1006,15 +1011,16 @@ VideoReceiveStream2::SetAndGetRecordingState(RecordingState state,
|
||||
decode_queue_.PostTask(
|
||||
[this, &event, &old_state, callback = std::move(state.callback),
|
||||
generate_key_frame,
|
||||
last_keyframe_request = state.last_keyframe_request_ms.value_or(0)] {
|
||||
last_keyframe_request =
|
||||
Timestamp::Millis(state.last_keyframe_request_ms.value_or(0))] {
|
||||
RTC_DCHECK_RUN_ON(&decode_queue_);
|
||||
old_state.callback = std::move(encoded_frame_buffer_function_);
|
||||
encoded_frame_buffer_function_ = std::move(callback);
|
||||
|
||||
old_state.last_keyframe_request_ms = last_keyframe_request_ms_;
|
||||
last_keyframe_request_ms_ = generate_key_frame
|
||||
? clock_->TimeInMilliseconds()
|
||||
: last_keyframe_request;
|
||||
old_state.last_keyframe_request_ms =
|
||||
last_keyframe_request_.value_or(Timestamp::Zero()).ms();
|
||||
last_keyframe_request_ =
|
||||
generate_key_frame ? clock_->CurrentTime() : last_keyframe_request;
|
||||
|
||||
event.Set();
|
||||
});
|
||||
@ -1034,7 +1040,7 @@ VideoReceiveStream2::SetAndGetRecordingState(RecordingState state,
|
||||
|
||||
void VideoReceiveStream2::GenerateKeyFrame() {
|
||||
RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
|
||||
RequestKeyFrame(clock_->TimeInMilliseconds());
|
||||
RequestKeyFrame(clock_->CurrentTime());
|
||||
keyframe_generation_requested_ = true;
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
|
||||
#include "api/sequence_checker.h"
|
||||
#include "api/task_queue/task_queue_factory.h"
|
||||
#include "api/units/time_delta.h"
|
||||
#include "api/units/timestamp.h"
|
||||
#include "api/video/recordable_encoded_frame.h"
|
||||
#include "call/call.h"
|
||||
@ -53,7 +54,7 @@ class CallStats;
|
||||
// Utility struct for grabbing metadata from a VideoFrame and processing it
|
||||
// asynchronously without needing the actual frame data.
|
||||
// Additionally the caller can bundle information from the current clock
|
||||
// when the metadata is captured, for accurate reporting and not needeing
|
||||
// when the metadata is captured, for accurate reporting and not needing
|
||||
// multiple calls to clock->Now().
|
||||
struct VideoFrameMetaData {
|
||||
VideoFrameMetaData(const webrtc::VideoFrame& frame, Timestamp now)
|
||||
@ -86,9 +87,6 @@ class VideoReceiveStream2
|
||||
public CallStatsObserver,
|
||||
public FrameSchedulingReceiver {
|
||||
public:
|
||||
// The default number of milliseconds to pass before re-requesting a key frame
|
||||
// to be sent.
|
||||
static constexpr int kMaxWaitForKeyFrameMs = 200;
|
||||
// The maximum number of buffered encoded frames when encoded output is
|
||||
// configured.
|
||||
static constexpr size_t kBufferedEncodedFramesMaxSize = 60;
|
||||
@ -189,21 +187,20 @@ class VideoReceiveStream2
|
||||
void OnEncodedFrame(std::unique_ptr<EncodedFrame> frame) override;
|
||||
void OnDecodableFrameTimeout(TimeDelta wait_time) override;
|
||||
void CreateAndRegisterExternalDecoder(const Decoder& decoder);
|
||||
int64_t GetMaxWaitMs() const RTC_RUN_ON(decode_queue_);
|
||||
TimeDelta GetMaxWait() const RTC_RUN_ON(decode_queue_);
|
||||
void HandleEncodedFrame(std::unique_ptr<EncodedFrame> frame)
|
||||
RTC_RUN_ON(decode_queue_);
|
||||
void HandleFrameBufferTimeout(int64_t now_ms, int64_t wait_ms)
|
||||
void HandleFrameBufferTimeout(Timestamp now, TimeDelta wait)
|
||||
RTC_RUN_ON(packet_sequence_checker_);
|
||||
void UpdatePlayoutDelays() const
|
||||
RTC_EXCLUSIVE_LOCKS_REQUIRED(worker_sequence_checker_);
|
||||
void RequestKeyFrame(int64_t timestamp_ms)
|
||||
RTC_RUN_ON(packet_sequence_checker_);
|
||||
void RequestKeyFrame(Timestamp now) RTC_RUN_ON(packet_sequence_checker_);
|
||||
void HandleKeyFrameGeneration(bool received_frame_is_keyframe,
|
||||
int64_t now_ms,
|
||||
Timestamp now,
|
||||
bool always_request_key_frame,
|
||||
bool keyframe_request_is_due)
|
||||
RTC_RUN_ON(packet_sequence_checker_);
|
||||
bool IsReceivingKeyFrame(int64_t timestamp_ms) const
|
||||
bool IsReceivingKeyFrame(Timestamp timestamp) const
|
||||
RTC_RUN_ON(packet_sequence_checker_);
|
||||
int DecodeAndMaybeDispatchEncodedFrame(std::unique_ptr<EncodedFrame> frame)
|
||||
RTC_RUN_ON(decode_queue_);
|
||||
@ -266,31 +263,32 @@ class VideoReceiveStream2
|
||||
// If we have successfully decoded any frame.
|
||||
bool frame_decoded_ RTC_GUARDED_BY(decode_queue_) = false;
|
||||
|
||||
int64_t last_keyframe_request_ms_ RTC_GUARDED_BY(decode_queue_) = 0;
|
||||
int64_t last_complete_frame_time_ms_
|
||||
RTC_GUARDED_BY(worker_sequence_checker_) = 0;
|
||||
absl::optional<Timestamp> last_keyframe_request_
|
||||
RTC_GUARDED_BY(decode_queue_);
|
||||
absl::optional<Timestamp> last_complete_frame_time_
|
||||
RTC_GUARDED_BY(worker_sequence_checker_);
|
||||
|
||||
// Keyframe request intervals are configurable through field trials.
|
||||
const int max_wait_for_keyframe_ms_;
|
||||
const int max_wait_for_frame_ms_;
|
||||
const TimeDelta max_wait_for_keyframe_;
|
||||
const TimeDelta max_wait_for_frame_;
|
||||
|
||||
// All of them tries to change current min_playout_delay on `timing_` but
|
||||
// source of the change request is different in each case. Among them the
|
||||
// biggest delay is used. -1 means use default value from the `timing_`.
|
||||
//
|
||||
// Minimum delay as decided by the RTP playout delay extension.
|
||||
int frame_minimum_playout_delay_ms_ RTC_GUARDED_BY(worker_sequence_checker_) =
|
||||
-1;
|
||||
absl::optional<TimeDelta> frame_minimum_playout_delay_
|
||||
RTC_GUARDED_BY(worker_sequence_checker_);
|
||||
// Minimum delay as decided by the setLatency function in "webrtc/api".
|
||||
int base_minimum_playout_delay_ms_ RTC_GUARDED_BY(worker_sequence_checker_) =
|
||||
-1;
|
||||
absl::optional<TimeDelta> base_minimum_playout_delay_
|
||||
RTC_GUARDED_BY(worker_sequence_checker_);
|
||||
// Minimum delay as decided by the A/V synchronization feature.
|
||||
int syncable_minimum_playout_delay_ms_
|
||||
RTC_GUARDED_BY(worker_sequence_checker_) = -1;
|
||||
absl::optional<TimeDelta> syncable_minimum_playout_delay_
|
||||
RTC_GUARDED_BY(worker_sequence_checker_);
|
||||
|
||||
// Maximum delay as decided by the RTP playout delay extension.
|
||||
int frame_maximum_playout_delay_ms_ RTC_GUARDED_BY(worker_sequence_checker_) =
|
||||
-1;
|
||||
absl::optional<TimeDelta> frame_maximum_playout_delay_
|
||||
RTC_GUARDED_BY(worker_sequence_checker_);
|
||||
|
||||
// Function that is triggered with encoded frames, if not empty.
|
||||
std::function<void(const RecordableEncodedFrame&)>
|
||||
|
||||
@ -483,7 +483,7 @@ TEST_F(VideoReceiveStream2TestWithFakeDecoder,
|
||||
}
|
||||
|
||||
class VideoReceiveStream2TestWithSimulatedClock
|
||||
: public ::testing::TestWithParam<std::tuple<int, bool>> {
|
||||
: public ::testing::TestWithParam<std::tuple<TimeDelta, bool>> {
|
||||
public:
|
||||
class FakeRenderer : public rtc::VideoSinkInterface<webrtc::VideoFrame> {
|
||||
public:
|
||||
@ -531,7 +531,7 @@ class VideoReceiveStream2TestWithSimulatedClock
|
||||
VideoReceiveStream::Config config(transport, decoder_factory);
|
||||
config.rtp.remote_ssrc = 1111;
|
||||
config.rtp.local_ssrc = 2222;
|
||||
config.rtp.nack.rtp_history_ms = std::get<0>(GetParam()); // rtx-time.
|
||||
config.rtp.nack.rtp_history_ms = std::get<0>(GetParam()).ms(); // rtx-time.
|
||||
config.renderer = renderer;
|
||||
VideoReceiveStream::Decoder fake_decoder;
|
||||
fake_decoder.payload_type = 99;
|
||||
@ -606,7 +606,7 @@ class VideoReceiveStream2TestWithSimulatedClock
|
||||
|
||||
TEST_P(VideoReceiveStream2TestWithSimulatedClock,
|
||||
RequestsKeyFramesUntilKeyFrameReceived) {
|
||||
auto tick = TimeDelta::Millis(std::get<0>(GetParam()) / 2);
|
||||
auto tick = std::get<0>(GetParam()) / 2;
|
||||
bool sent_rtcp = false;
|
||||
EXPECT_CALL(mock_transport_, SendRtcp)
|
||||
.Times(1)
|
||||
@ -711,10 +711,9 @@ TEST_P(VideoReceiveStream2TestWithSimulatedClock,
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
RtxTime,
|
||||
VideoReceiveStream2TestWithSimulatedClock,
|
||||
::testing::Combine(
|
||||
::testing::Values(internal::VideoReceiveStream2::kMaxWaitForKeyFrameMs,
|
||||
50 /*ms*/),
|
||||
::testing::Bool()));
|
||||
::testing::Combine(::testing::Values(TimeDelta::Millis(200),
|
||||
TimeDelta::Millis(50)),
|
||||
::testing::Bool()));
|
||||
|
||||
class VideoReceiveStream2TestWithLazyDecoderCreation : public ::testing::Test {
|
||||
public:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user