| /* |
| * 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 "video/encoder_rtcp_feedback.h" |
| |
| #include <algorithm> |
| #include <optional> |
| #include <utility> |
| |
| #include "api/environment/environment.h" |
| #include "api/video_codecs/video_encoder.h" |
| #include "rtc_base/checks.h" |
| #include "rtc_base/experiments/keyframe_interval_settings.h" |
| #include "system_wrappers/include/clock.h" |
| |
| namespace webrtc { |
| |
| namespace { |
| constexpr int kMinKeyframeSendIntervalMs = 300; |
| } // namespace |
| |
| EncoderRtcpFeedback::EncoderRtcpFeedback( |
| const Environment& env, |
| bool per_layer_keyframes, |
| const std::vector<uint32_t>& ssrcs, |
| VideoStreamEncoderInterface* encoder, |
| std::function<std::vector<RtpSequenceNumberMap::Info>( |
| uint32_t ssrc, |
| const std::vector<uint16_t>& seq_nums)> get_packet_infos) |
| : env_(env), |
| ssrcs_(ssrcs), |
| per_layer_keyframes_(per_layer_keyframes), |
| get_packet_infos_(std::move(get_packet_infos)), |
| video_stream_encoder_(encoder), |
| time_last_packet_delivery_queue_(per_layer_keyframes ? ssrcs.size() : 1, |
| Timestamp::Zero()), |
| min_keyframe_send_interval_( |
| TimeDelta::Millis(KeyframeIntervalSettings(env_.field_trials()) |
| .MinKeyframeSendIntervalMs() |
| .value_or(kMinKeyframeSendIntervalMs))) { |
| RTC_DCHECK(!ssrcs.empty()); |
| packet_delivery_queue_.Detach(); |
| } |
| |
| // Called via Call::DeliverRtcp. |
| void EncoderRtcpFeedback::OnReceivedIntraFrameRequest(uint32_t ssrc) { |
| RTC_DCHECK_RUN_ON(&packet_delivery_queue_); |
| RTC_DCHECK(std::find(ssrcs_.begin(), ssrcs_.end(), ssrc) != ssrcs_.end()); |
| |
| auto it = std::find(ssrcs_.begin(), ssrcs_.end(), ssrc); |
| if (it == ssrcs_.end()) { |
| RTC_LOG(LS_WARNING) << "SSRC " << ssrc << " not found."; |
| return; |
| } |
| size_t ssrc_index = |
| per_layer_keyframes_ ? std::distance(ssrcs_.begin(), it) : 0; |
| RTC_CHECK_LE(ssrc_index, time_last_packet_delivery_queue_.size()); |
| const Timestamp now = env_.clock().CurrentTime(); |
| if (time_last_packet_delivery_queue_[ssrc_index] + |
| min_keyframe_send_interval_ > |
| now) |
| return; |
| |
| time_last_packet_delivery_queue_[ssrc_index] = now; |
| |
| std::vector<VideoFrameType> layers(ssrcs_.size(), |
| VideoFrameType::kVideoFrameDelta); |
| if (!per_layer_keyframes_) { |
| // Always produce key frame for all streams. |
| video_stream_encoder_->SendKeyFrame(); |
| } else { |
| // Determine on which layer we ask for key frames. |
| layers[ssrc_index] = VideoFrameType::kVideoFrameKey; |
| video_stream_encoder_->SendKeyFrame(layers); |
| } |
| } |
| |
| void EncoderRtcpFeedback::OnReceivedLossNotification( |
| uint32_t ssrc, |
| uint16_t seq_num_of_last_decodable, |
| uint16_t seq_num_of_last_received, |
| bool decodability_flag) { |
| RTC_DCHECK(get_packet_infos_) << "Object initialization incomplete."; |
| |
| const std::vector<uint16_t> seq_nums = {seq_num_of_last_decodable, |
| seq_num_of_last_received}; |
| const std::vector<RtpSequenceNumberMap::Info> infos = |
| get_packet_infos_(ssrc, seq_nums); |
| if (infos.empty()) { |
| return; |
| } |
| RTC_DCHECK_EQ(infos.size(), 2u); |
| |
| const RtpSequenceNumberMap::Info& last_decodable = infos[0]; |
| const RtpSequenceNumberMap::Info& last_received = infos[1]; |
| |
| VideoEncoder::LossNotification loss_notification; |
| loss_notification.timestamp_of_last_decodable = last_decodable.timestamp; |
| loss_notification.timestamp_of_last_received = last_received.timestamp; |
| |
| // Deduce decodability of the last received frame and of its dependencies. |
| if (last_received.is_first && last_received.is_last) { |
| // The frame consists of a single packet, and that packet has evidently |
| // been received in full; the frame is therefore assemblable. |
| // In this case, the decodability of the dependencies is communicated by |
| // the decodability flag, and the frame itself is decodable if and only |
| // if they are decodable. |
| loss_notification.dependencies_of_last_received_decodable = |
| decodability_flag; |
| loss_notification.last_received_decodable = decodability_flag; |
| } else if (last_received.is_first && !last_received.is_last) { |
| // In this case, the decodability flag communicates the decodability of |
| // the dependencies. If any is undecodable, we also know that the frame |
| // itself will not be decodable; if all are decodable, the frame's own |
| // decodability will remain unknown, as not all of its packets have |
| // been received. |
| loss_notification.dependencies_of_last_received_decodable = |
| decodability_flag; |
| loss_notification.last_received_decodable = |
| !decodability_flag ? std::make_optional(false) : std::nullopt; |
| } else if (!last_received.is_first && last_received.is_last) { |
| if (decodability_flag) { |
| // The frame has been received in full, and found to be decodable. |
| // (Messages of this type are not sent by WebRTC at the moment, but are |
| // theoretically possible, for example for serving as acks.) |
| loss_notification.dependencies_of_last_received_decodable = true; |
| loss_notification.last_received_decodable = true; |
| } else { |
| // It is impossible to tell whether some dependencies were undecodable, |
| // or whether the frame was unassemblable, but in either case, the frame |
| // itself was undecodable. |
| loss_notification.dependencies_of_last_received_decodable = std::nullopt; |
| loss_notification.last_received_decodable = false; |
| } |
| } else { // !last_received.is_first && !last_received.is_last |
| if (decodability_flag) { |
| // The frame has not yet been received in full, but no gaps have |
| // been encountered so far, and the dependencies were all decodable. |
| // (Messages of this type are not sent by WebRTC at the moment, but are |
| // theoretically possible, for example for serving as acks.) |
| loss_notification.dependencies_of_last_received_decodable = true; |
| loss_notification.last_received_decodable = std::nullopt; |
| } else { |
| // It is impossible to tell whether some dependencies were undecodable, |
| // or whether the frame was unassemblable, but in either case, the frame |
| // itself was undecodable. |
| loss_notification.dependencies_of_last_received_decodable = std::nullopt; |
| loss_notification.last_received_decodable = false; |
| } |
| } |
| |
| video_stream_encoder_->OnLossNotification(loss_notification); |
| } |
| |
| } // namespace webrtc |