diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/libwebrtc/modules/video_coding/receiver.cc | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/modules/video_coding/receiver.cc')
-rw-r--r-- | third_party/libwebrtc/modules/video_coding/receiver.cc | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/video_coding/receiver.cc b/third_party/libwebrtc/modules/video_coding/receiver.cc new file mode 100644 index 0000000000..3f954ec9bf --- /dev/null +++ b/third_party/libwebrtc/modules/video_coding/receiver.cc @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "modules/video_coding/receiver.h" + + +#include <cstdint> +#include <cstdlib> +#include <utility> +#include <vector> + +#include "absl/memory/memory.h" +#include "api/video/encoded_image.h" +#include "modules/video_coding/encoded_frame.h" +#include "modules/video_coding/internal_defines.h" +#include "modules/video_coding/jitter_buffer_common.h" +#include "rtc_base/logging.h" +#include "rtc_base/numerics/safe_conversions.h" +#include "rtc_base/trace_event.h" +#include "system_wrappers/include/clock.h" + +namespace webrtc { + +enum { kMaxReceiverDelayMs = 10000 }; + +VCMReceiver::VCMReceiver(VCMTiming* timing, + Clock* clock, + const FieldTrialsView& field_trials) + : VCMReceiver::VCMReceiver(timing, + clock, + absl::WrapUnique(EventWrapper::Create()), + absl::WrapUnique(EventWrapper::Create()), + field_trials) {} + +VCMReceiver::VCMReceiver(VCMTiming* timing, + Clock* clock, + std::unique_ptr<EventWrapper> receiver_event, + std::unique_ptr<EventWrapper> jitter_buffer_event, + const FieldTrialsView& field_trials) + : clock_(clock), + jitter_buffer_(clock_, std::move(jitter_buffer_event), field_trials), + timing_(timing), + render_wait_event_(std::move(receiver_event)), + max_video_delay_ms_(kMaxVideoDelayMs) { + jitter_buffer_.Start(); +} + +VCMReceiver::~VCMReceiver() { + render_wait_event_->Set(); +} + +int32_t VCMReceiver::InsertPacket(const VCMPacket& packet) { + // Insert the packet into the jitter buffer. The packet can either be empty or + // contain media at this point. + bool retransmitted = false; + const VCMFrameBufferEnum ret = + jitter_buffer_.InsertPacket(packet, &retransmitted); + if (ret == kOldPacket) { + return VCM_OK; + } else if (ret == kFlushIndicator) { + return VCM_FLUSH_INDICATOR; + } else if (ret < 0) { + return VCM_JITTER_BUFFER_ERROR; + } + if (ret == kCompleteSession && !retransmitted) { + // We don't want to include timestamps which have suffered from + // retransmission here, since we compensate with extra retransmission + // delay within the jitter estimate. + timing_->IncomingTimestamp(packet.timestamp, clock_->CurrentTime()); + } + return VCM_OK; +} + +VCMEncodedFrame* VCMReceiver::FrameForDecoding(uint16_t max_wait_time_ms, + bool prefer_late_decoding) { + const int64_t start_time_ms = clock_->TimeInMilliseconds(); + uint32_t frame_timestamp = 0; + int min_playout_delay_ms = -1; + int max_playout_delay_ms = -1; + int64_t render_time_ms = 0; + // Exhaust wait time to get a complete frame for decoding. + VCMEncodedFrame* found_frame = + jitter_buffer_.NextCompleteFrame(max_wait_time_ms); + + if (found_frame) { + frame_timestamp = found_frame->Timestamp(); + min_playout_delay_ms = found_frame->EncodedImage().playout_delay_.min_ms; + max_playout_delay_ms = found_frame->EncodedImage().playout_delay_.max_ms; + } else { + return nullptr; + } + + if (min_playout_delay_ms >= 0) + timing_->set_min_playout_delay(TimeDelta::Millis(min_playout_delay_ms)); + + if (max_playout_delay_ms >= 0) + timing_->set_max_playout_delay(TimeDelta::Millis(max_playout_delay_ms)); + + // We have a frame - Set timing and render timestamp. + timing_->SetJitterDelay( + TimeDelta::Millis(jitter_buffer_.EstimatedJitterMs())); + const Timestamp now = clock_->CurrentTime(); + const int64_t now_ms = now.ms(); + timing_->UpdateCurrentDelay(frame_timestamp); + render_time_ms = timing_->RenderTime(frame_timestamp, now).ms(); + // Check render timing. + bool timing_error = false; + // Assume that render timing errors are due to changes in the video stream. + if (render_time_ms < 0) { + timing_error = true; + } else if (std::abs(render_time_ms - now_ms) > max_video_delay_ms_) { + int frame_delay = static_cast<int>(std::abs(render_time_ms - now_ms)); + RTC_LOG(LS_WARNING) + << "A frame about to be decoded is out of the configured " + "delay bounds (" + << frame_delay << " > " << max_video_delay_ms_ + << "). Resetting the video jitter buffer."; + timing_error = true; + } else if (static_cast<int>(timing_->TargetVideoDelay().ms()) > + max_video_delay_ms_) { + RTC_LOG(LS_WARNING) << "The video target delay has grown larger than " + << max_video_delay_ms_ + << " ms. Resetting jitter buffer."; + timing_error = true; + } + + if (timing_error) { + // Timing error => reset timing and flush the jitter buffer. + jitter_buffer_.Flush(); + timing_->Reset(); + return NULL; + } + + if (prefer_late_decoding) { + // Decode frame as close as possible to the render timestamp. + const int32_t available_wait_time = + max_wait_time_ms - + static_cast<int32_t>(clock_->TimeInMilliseconds() - start_time_ms); + uint16_t new_max_wait_time = + static_cast<uint16_t>(VCM_MAX(available_wait_time, 0)); + uint32_t wait_time_ms = rtc::saturated_cast<uint32_t>( + timing_ + ->MaxWaitingTime(Timestamp::Millis(render_time_ms), + clock_->CurrentTime(), + /*too_many_frames_queued=*/false) + .ms()); + if (new_max_wait_time < wait_time_ms) { + // We're not allowed to wait until the frame is supposed to be rendered, + // waiting as long as we're allowed to avoid busy looping, and then return + // NULL. Next call to this function might return the frame. + render_wait_event_->Wait(new_max_wait_time); + return NULL; + } + // Wait until it's time to render. + render_wait_event_->Wait(wait_time_ms); + } + + // Extract the frame from the jitter buffer and set the render time. + VCMEncodedFrame* frame = jitter_buffer_.ExtractAndSetDecode(frame_timestamp); + if (frame == NULL) { + return NULL; + } + frame->SetRenderTime(render_time_ms); + TRACE_EVENT_ASYNC_STEP1("webrtc", "Video", frame->Timestamp(), "SetRenderTS", + "render_time", frame->RenderTimeMs()); + return frame; +} + +void VCMReceiver::ReleaseFrame(VCMEncodedFrame* frame) { + jitter_buffer_.ReleaseFrame(frame); +} + +void VCMReceiver::SetNackSettings(size_t max_nack_list_size, + int max_packet_age_to_nack, + int max_incomplete_time_ms) { + jitter_buffer_.SetNackSettings(max_nack_list_size, max_packet_age_to_nack, + max_incomplete_time_ms); +} + +std::vector<uint16_t> VCMReceiver::NackList(bool* request_key_frame) { + return jitter_buffer_.GetNackList(request_key_frame); +} + +} // namespace webrtc |