tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

loss_notification_controller.cc (6587B)


      1 /*
      2 *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
      3 *
      4 *  Use of this source code is governed by a BSD-style license
      5 *  that can be found in the LICENSE file in the root of the source
      6 *  tree. An additional intellectual property rights grant can be found
      7 *  in the file PATENTS.  All contributing project authors may
      8 *  be found in the AUTHORS file in the root of the source tree.
      9 */
     10 
     11 #include "modules/video_coding/loss_notification_controller.h"
     12 
     13 #include <cstddef>
     14 #include <cstdint>
     15 
     16 #include "api/array_view.h"
     17 #include "api/sequence_checker.h"
     18 #include "modules/include/module_common_types.h"
     19 #include "rtc_base/checks.h"
     20 #include "rtc_base/logging.h"
     21 #include "rtc_base/numerics/sequence_number_util.h"
     22 
     23 namespace webrtc {
     24 namespace {
     25 // Keep a container's size no higher than `max_allowed_size`, by paring its size
     26 // down to `target_size` whenever it has more than `max_allowed_size` elements.
     27 template <typename Container>
     28 void PareDown(Container* container,
     29              size_t max_allowed_size,
     30              size_t target_size) {
     31  if (container->size() > max_allowed_size) {
     32    const size_t entries_to_delete = container->size() - target_size;
     33    auto erase_to = container->begin();
     34    std::advance(erase_to, entries_to_delete);
     35    container->erase(container->begin(), erase_to);
     36    RTC_DCHECK_EQ(container->size(), target_size);
     37  }
     38 }
     39 }  // namespace
     40 
     41 LossNotificationController::LossNotificationController(
     42    KeyFrameRequestSender* key_frame_request_sender,
     43    LossNotificationSender* loss_notification_sender)
     44    : key_frame_request_sender_(key_frame_request_sender),
     45      loss_notification_sender_(loss_notification_sender),
     46      current_frame_potentially_decodable_(true) {
     47  RTC_DCHECK(key_frame_request_sender_);
     48  RTC_DCHECK(loss_notification_sender_);
     49 }
     50 
     51 LossNotificationController::~LossNotificationController() = default;
     52 
     53 void LossNotificationController::OnReceivedPacket(
     54    uint16_t rtp_seq_num,
     55    const LossNotificationController::FrameDetails* frame) {
     56  RTC_DCHECK_RUN_ON(&sequence_checker_);
     57 
     58  // Ignore repeated or reordered packets.
     59  // TODO(bugs.webrtc.org/10336): Handle packet reordering.
     60  if (last_received_seq_num_ &&
     61      !AheadOf(rtp_seq_num, *last_received_seq_num_)) {
     62    return;
     63  }
     64 
     65  DiscardOldInformation();  // Prevent memory overconsumption.
     66 
     67  const bool seq_num_gap =
     68      last_received_seq_num_ &&
     69      rtp_seq_num != static_cast<uint16_t>(*last_received_seq_num_ + 1u);
     70 
     71  last_received_seq_num_ = rtp_seq_num;
     72 
     73  // `frame` is not nullptr iff the packet is the first packet in the frame.
     74  if (frame != nullptr) {
     75    // Ignore repeated or reordered frames.
     76    // TODO(bugs.webrtc.org/10336): Handle frame reordering.
     77    if (last_received_frame_id_.has_value() &&
     78        frame->frame_id <= last_received_frame_id_.value()) {
     79      RTC_LOG(LS_WARNING) << "Repeated or reordered frame ID ("
     80                          << frame->frame_id << ").";
     81      return;
     82    }
     83 
     84    last_received_frame_id_ = frame->frame_id;
     85 
     86    if (frame->is_keyframe) {
     87      // Subsequent frames may not rely on frames before the key frame.
     88      // Note that upon receiving a key frame, we do not issue a loss
     89      // notification on RTP sequence number gap, unless that gap spanned
     90      // the key frame itself. This is because any loss which occurred before
     91      // the key frame is no longer relevant.
     92      decodable_frame_ids_.clear();
     93      current_frame_potentially_decodable_ = true;
     94    } else {
     95      const bool all_dependencies_decodable =
     96          AllDependenciesDecodable(frame->frame_dependencies);
     97      current_frame_potentially_decodable_ = all_dependencies_decodable;
     98      if (seq_num_gap || !current_frame_potentially_decodable_) {
     99        HandleLoss(rtp_seq_num, current_frame_potentially_decodable_);
    100      }
    101    }
    102  } else if (seq_num_gap || !current_frame_potentially_decodable_) {
    103    current_frame_potentially_decodable_ = false;
    104    // We allow sending multiple loss notifications for a single frame
    105    // even if only one of its packets is lost. We do this because the bigger
    106    // the frame, the more likely it is to be non-discardable, and therefore
    107    // the more robust we wish to be to loss of the feedback messages.
    108    HandleLoss(rtp_seq_num, false);
    109  }
    110 }
    111 
    112 void LossNotificationController::OnAssembledFrame(
    113    uint16_t first_seq_num,
    114    int64_t frame_id,
    115    bool discardable,
    116    ArrayView<const int64_t> frame_dependencies) {
    117  RTC_DCHECK_RUN_ON(&sequence_checker_);
    118 
    119  DiscardOldInformation();  // Prevent memory overconsumption.
    120 
    121  if (discardable) {
    122    return;
    123  }
    124 
    125  if (!AllDependenciesDecodable(frame_dependencies)) {
    126    return;
    127  }
    128 
    129  last_decodable_non_discardable_.emplace(first_seq_num);
    130  const auto it = decodable_frame_ids_.insert(frame_id);
    131  RTC_DCHECK(it.second);
    132 }
    133 
    134 void LossNotificationController::DiscardOldInformation() {
    135  constexpr size_t kExpectedKeyFrameIntervalFrames = 3000;
    136  constexpr size_t kMaxSize = 2 * kExpectedKeyFrameIntervalFrames;
    137  constexpr size_t kTargetSize = kExpectedKeyFrameIntervalFrames;
    138  PareDown(&decodable_frame_ids_, kMaxSize, kTargetSize);
    139 }
    140 
    141 bool LossNotificationController::AllDependenciesDecodable(
    142    ArrayView<const int64_t> frame_dependencies) const {
    143  RTC_DCHECK_RUN_ON(&sequence_checker_);
    144 
    145  // Due to packet reordering, frame buffering and asynchronous decoders, it is
    146  // infeasible to make reliable conclusions on the decodability of a frame
    147  // immediately when it arrives. We use the following assumptions:
    148  // * Intra frames are decodable.
    149  // * Inter frames are decodable if all of their references were decodable.
    150  // One possibility that is ignored, is that the packet may be corrupt.
    151  for (int64_t ref_frame_id : frame_dependencies) {
    152    const auto ref_frame_it = decodable_frame_ids_.find(ref_frame_id);
    153    if (ref_frame_it == decodable_frame_ids_.end()) {
    154      // Reference frame not decodable.
    155      return false;
    156    }
    157  }
    158 
    159  return true;
    160 }
    161 
    162 void LossNotificationController::HandleLoss(uint16_t last_received_seq_num,
    163                                            bool decodability_flag) {
    164  RTC_DCHECK_RUN_ON(&sequence_checker_);
    165 
    166  if (last_decodable_non_discardable_) {
    167    RTC_DCHECK(AheadOf(last_received_seq_num,
    168                       last_decodable_non_discardable_->first_seq_num));
    169    loss_notification_sender_->SendLossNotification(
    170        last_decodable_non_discardable_->first_seq_num, last_received_seq_num,
    171        decodability_flag, /*buffering_allowed=*/true);
    172  } else {
    173    key_frame_request_sender_->RequestKeyFrame();
    174  }
    175 }
    176 }  //  namespace webrtc