| /* | |
| * 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 <cstddef> | |
| #include <cstdint> | |
| #include <functional> | |
| #include <iterator> | |
| #include <optional> | |
| #include <utility> | |
| #include <vector> | |
| #include "api/environment/environment.h" | |
| #include "api/sequence_checker.h" | |
| #include "api/units/time_delta.h" | |
| #include "api/units/timestamp.h" | |
| #include "api/video/video_frame_type.h" | |
| #include "api/video_codecs/video_encoder.h" | |
| #include "modules/rtp_rtcp/source/rtp_sequence_number_map.h" | |
| #include "rtc_base/checks.h" | |
| #include "rtc_base/experiments/keyframe_interval_settings.h" | |
| #include "rtc_base/logging.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 |