| /* |
| * 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 "absl/types/optional.h" |
| #include "api/video_codecs/video_encoder.h" |
| #include "rtc_base/checks.h" |
| #include "rtc_base/experiments/keyframe_interval_settings.h" |
| |
| namespace webrtc { |
| |
| namespace { |
| constexpr int kMinKeyframeSendIntervalMs = 300; |
| } // namespace |
| |
| EncoderRtcpFeedback::EncoderRtcpFeedback(Clock* clock, |
| const std::vector<uint32_t>& ssrcs, |
| VideoStreamEncoderInterface* encoder) |
| : clock_(clock), |
| ssrcs_(ssrcs), |
| rtp_video_sender_(nullptr), |
| video_stream_encoder_(encoder), |
| time_last_intra_request_ms_(-1), |
| min_keyframe_send_interval_ms_( |
| KeyframeIntervalSettings::ParseFromFieldTrials() |
| .MinKeyframeSendIntervalMs() |
| .value_or(kMinKeyframeSendIntervalMs)) { |
| RTC_DCHECK(!ssrcs.empty()); |
| } |
| |
| void EncoderRtcpFeedback::SetRtpVideoSender( |
| const RtpVideoSenderInterface* rtp_video_sender) { |
| RTC_DCHECK(rtp_video_sender); |
| RTC_DCHECK(!rtp_video_sender_); |
| rtp_video_sender_ = rtp_video_sender; |
| } |
| |
| bool EncoderRtcpFeedback::HasSsrc(uint32_t ssrc) { |
| for (uint32_t registered_ssrc : ssrcs_) { |
| if (registered_ssrc == ssrc) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void EncoderRtcpFeedback::OnReceivedIntraFrameRequest(uint32_t ssrc) { |
| RTC_DCHECK(HasSsrc(ssrc)); |
| { |
| int64_t now_ms = clock_->TimeInMilliseconds(); |
| rtc::CritScope lock(&crit_); |
| if (time_last_intra_request_ms_ + min_keyframe_send_interval_ms_ > now_ms) { |
| return; |
| } |
| time_last_intra_request_ms_ = now_ms; |
| } |
| |
| // Always produce key frame for all streams. |
| video_stream_encoder_->SendKeyFrame(); |
| } |
| |
| void EncoderRtcpFeedback::OnKeyFrameRequested(uint64_t channel_id) { |
| if (channel_id != ssrcs_[0]) { |
| RTC_LOG(LS_INFO) << "Key frame request on unknown channel id " << channel_id |
| << " expected " << ssrcs_[0]; |
| return; |
| } |
| |
| video_stream_encoder_->SendKeyFrame(); |
| } |
| |
| 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(rtp_video_sender_) << "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 = |
| rtp_video_sender_->GetSentRtpPacketInfos(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 ? absl::make_optional(false) : absl::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 = absl::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 = absl::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 = absl::nullopt; |
| loss_notification.last_received_decodable = false; |
| } |
| } |
| |
| video_stream_encoder_->OnLossNotification(loss_notification); |
| } |
| |
| } // namespace webrtc |