tor-browser

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

frame_buffer.cc (11258B)


      1 /*
      2 *  Copyright (c) 2021 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 "api/video/frame_buffer.h"
     12 
     13 #include <algorithm>
     14 #include <cstddef>
     15 #include <cstdint>
     16 #include <iterator>
     17 #include <memory>
     18 #include <optional>
     19 #include <utility>
     20 
     21 #include "absl/algorithm/container.h"
     22 #include "absl/container/inlined_vector.h"
     23 #include "api/array_view.h"
     24 #include "api/field_trials_view.h"
     25 #include "api/video/encoded_frame.h"
     26 #include "rtc_base/logging.h"
     27 #include "rtc_base/numerics/sequence_number_util.h"
     28 #include "rtc_base/trace_event.h"
     29 
     30 namespace webrtc {
     31 namespace {
     32 bool ValidReferences(const EncodedFrame& frame) {
     33  // All references must point backwards, and duplicates are not allowed.
     34  for (size_t i = 0; i < frame.num_references; ++i) {
     35    if (frame.references[i] >= frame.Id())
     36      return false;
     37 
     38    for (size_t j = i + 1; j < frame.num_references; ++j) {
     39      if (frame.references[i] == frame.references[j])
     40        return false;
     41    }
     42  }
     43 
     44  return true;
     45 }
     46 
     47 // Since FrameBuffer::FrameInfo is private it can't be used in the function
     48 // signature, hence the FrameIteratorT type.
     49 template <typename FrameIteratorT>
     50 ArrayView<const int64_t> GetReferences(const FrameIteratorT& it) {
     51  return {it->second.encoded_frame->references,
     52          std::min<size_t>(it->second.encoded_frame->num_references,
     53                           EncodedFrame::kMaxFrameReferences)};
     54 }
     55 
     56 template <typename FrameIteratorT>
     57 int64_t GetFrameId(const FrameIteratorT& it) {
     58  return it->first;
     59 }
     60 
     61 template <typename FrameIteratorT>
     62 uint32_t GetTimestamp(const FrameIteratorT& it) {
     63  return it->second.encoded_frame->RtpTimestamp();
     64 }
     65 
     66 template <typename FrameIteratorT>
     67 bool IsLastFrameInTemporalUnit(const FrameIteratorT& it) {
     68  return it->second.encoded_frame->is_last_spatial_layer;
     69 }
     70 }  // namespace
     71 
     72 FrameBuffer::FrameBuffer(int max_size,
     73                         int max_decode_history,
     74                         const FieldTrialsView& field_trials)
     75    : legacy_frame_id_jump_behavior_(
     76          !field_trials.IsDisabled("WebRTC-LegacyFrameIdJumpBehavior")),
     77      max_size_(max_size),
     78      decoded_frame_history_(max_decode_history) {}
     79 
     80 bool FrameBuffer::InsertFrame(std::unique_ptr<EncodedFrame> frame) {
     81  const uint32_t ssrc =
     82      frame->PacketInfos().empty() ? 0 : frame->PacketInfos()[0].ssrc();
     83  if (!ValidReferences(*frame)) {
     84    TRACE_EVENT2("webrtc",
     85                 "FrameBuffer::InsertFrame Frame dropped (Invalid references)",
     86                 "remote_ssrc", ssrc, "frame_id", frame->Id());
     87    RTC_DLOG(LS_WARNING) << "Frame " << frame->Id()
     88                         << " has invalid references, dropping frame.";
     89    return false;
     90  }
     91 
     92  if (frame->Id() <= decoded_frame_history_.GetLastDecodedFrameId()) {
     93    if (legacy_frame_id_jump_behavior_ && frame->is_keyframe() &&
     94        AheadOf(frame->RtpTimestamp(),
     95                *decoded_frame_history_.GetLastDecodedFrameTimestamp())) {
     96      TRACE_EVENT2("webrtc",
     97                   "FrameBuffer::InsertFrame Frames dropped (OOO + PicId jump)",
     98                   "remote_ssrc", ssrc, "frame_id", frame->Id());
     99      RTC_DLOG(LS_WARNING)
    100          << "Keyframe " << frame->Id()
    101          << " has newer timestamp but older picture id, clearing buffer.";
    102      Clear();
    103    } else {
    104      // Already decoded past this frame.
    105      TRACE_EVENT2("webrtc",
    106                   "FrameBuffer::InsertFrame Frame dropped (Out of order)",
    107                   "remote_ssrc", ssrc, "frame_id", frame->Id());
    108      return false;
    109    }
    110  }
    111 
    112  if (frames_.size() == max_size_) {
    113    if (frame->is_keyframe()) {
    114      TRACE_EVENT2("webrtc",
    115                   "FrameBuffer::InsertFrame Frames dropped (KF + Full buffer)",
    116                   "remote_ssrc", ssrc, "frame_id", frame->Id());
    117      RTC_DLOG(LS_WARNING) << "Keyframe " << frame->Id()
    118                           << " inserted into full buffer, clearing buffer.";
    119      Clear();
    120    } else {
    121      // No space for this frame.
    122      TRACE_EVENT2("webrtc",
    123                   "FrameBuffer::InsertFrame Frame dropped (Full buffer)",
    124                   "remote_ssrc", ssrc, "frame_id", frame->Id());
    125      return false;
    126    }
    127  }
    128 
    129  const int64_t frame_id = frame->Id();
    130  auto insert_res =
    131      frames_.emplace(frame_id, FrameInfo{.encoded_frame = std::move(frame)});
    132  if (!insert_res.second) {
    133    // Frame has already been inserted.
    134    return false;
    135  }
    136 
    137  if (frames_.size() == max_size_) {
    138    RTC_DLOG(LS_WARNING) << "Frame " << frame_id
    139                         << " inserted, buffer is now full.";
    140  }
    141 
    142  PropagateContinuity(insert_res.first);
    143  FindNextAndLastDecodableTemporalUnit();
    144  return true;
    145 }
    146 
    147 absl::InlinedVector<std::unique_ptr<EncodedFrame>, 4>
    148 FrameBuffer::ExtractNextDecodableTemporalUnit() {
    149  absl::InlinedVector<std::unique_ptr<EncodedFrame>, 4> res;
    150  if (!next_decodable_temporal_unit_) {
    151    return res;
    152  }
    153 
    154  auto end_it = std::next(next_decodable_temporal_unit_->last_frame);
    155  for (auto it = next_decodable_temporal_unit_->first_frame; it != end_it;
    156       ++it) {
    157    decoded_frame_history_.InsertDecoded(GetFrameId(it), GetTimestamp(it));
    158    res.push_back(std::move(it->second.encoded_frame));
    159  }
    160 
    161  DropNextDecodableTemporalUnit();
    162  return res;
    163 }
    164 
    165 void FrameBuffer::DropNextDecodableTemporalUnit() {
    166  if (!next_decodable_temporal_unit_) {
    167    return;
    168  }
    169 
    170  auto end_it = std::next(next_decodable_temporal_unit_->last_frame);
    171 
    172  UpdateDroppedFramesAndDiscardedPackets(frames_.begin(), end_it);
    173 
    174  frames_.erase(frames_.begin(), end_it);
    175  FindNextAndLastDecodableTemporalUnit();
    176 }
    177 
    178 void FrameBuffer::UpdateDroppedFramesAndDiscardedPackets(FrameIterator begin_it,
    179                                                         FrameIterator end_it) {
    180  uint32_t dropped_ssrc = 0;
    181  int64_t dropped_frame_id = 0;
    182  unsigned int num_discarded_packets = 0;
    183  unsigned int num_dropped_frames =
    184      std::count_if(begin_it, end_it, [&](const auto& f) {
    185        if (f.second.encoded_frame) {
    186          const auto& packetInfos = f.second.encoded_frame->PacketInfos();
    187          dropped_frame_id = f.first;
    188          if (!packetInfos.empty()) {
    189            dropped_ssrc = packetInfos[0].ssrc();
    190          }
    191          num_discarded_packets += packetInfos.size();
    192        }
    193        return f.second.encoded_frame != nullptr;
    194      });
    195 
    196  if (num_dropped_frames > 0) {
    197    TRACE_EVENT2("webrtc", "FrameBuffer Dropping Old Frames", "remote_ssrc",
    198                 dropped_ssrc, "frame_id", dropped_frame_id);
    199  }
    200  if (num_discarded_packets > 0) {
    201    TRACE_EVENT2("webrtc", "FrameBuffer Discarding Old Packets", "remote_ssrc",
    202                 dropped_ssrc, "frame_id", dropped_frame_id);
    203  }
    204 
    205  num_dropped_frames_ += num_dropped_frames;
    206  num_discarded_packets_ += num_discarded_packets;
    207 }
    208 
    209 std::optional<int64_t> FrameBuffer::LastContinuousFrameId() const {
    210  return last_continuous_frame_id_;
    211 }
    212 
    213 std::optional<int64_t> FrameBuffer::LastContinuousTemporalUnitFrameId() const {
    214  return last_continuous_temporal_unit_frame_id_;
    215 }
    216 
    217 std::optional<FrameBuffer::DecodabilityInfo>
    218 FrameBuffer::DecodableTemporalUnitsInfo() const {
    219  return decodable_temporal_units_info_;
    220 }
    221 
    222 int FrameBuffer::GetTotalNumberOfContinuousTemporalUnits() const {
    223  return num_continuous_temporal_units_;
    224 }
    225 int FrameBuffer::GetTotalNumberOfDroppedFrames() const {
    226  return num_dropped_frames_;
    227 }
    228 int FrameBuffer::GetTotalNumberOfDiscardedPackets() const {
    229  return num_discarded_packets_;
    230 }
    231 
    232 size_t FrameBuffer::CurrentSize() const {
    233  return frames_.size();
    234 }
    235 
    236 bool FrameBuffer::IsContinuous(const FrameIterator& it) const {
    237  for (int64_t reference : GetReferences(it)) {
    238    if (decoded_frame_history_.WasDecoded(reference)) {
    239      continue;
    240    }
    241 
    242    auto reference_frame_it = frames_.find(reference);
    243    if (reference_frame_it != frames_.end() &&
    244        reference_frame_it->second.continuous) {
    245      continue;
    246    }
    247 
    248    return false;
    249  }
    250 
    251  return true;
    252 }
    253 
    254 void FrameBuffer::PropagateContinuity(const FrameIterator& frame_it) {
    255  for (auto it = frame_it; it != frames_.end(); ++it) {
    256    if (!it->second.continuous) {
    257      if (IsContinuous(it)) {
    258        it->second.continuous = true;
    259        if (last_continuous_frame_id_ < GetFrameId(it)) {
    260          last_continuous_frame_id_ = GetFrameId(it);
    261        }
    262        if (IsLastFrameInTemporalUnit(it)) {
    263          num_continuous_temporal_units_++;
    264          if (last_continuous_temporal_unit_frame_id_ < GetFrameId(it)) {
    265            last_continuous_temporal_unit_frame_id_ = GetFrameId(it);
    266          }
    267        }
    268      }
    269    }
    270  }
    271 }
    272 
    273 void FrameBuffer::FindNextAndLastDecodableTemporalUnit() {
    274  next_decodable_temporal_unit_.reset();
    275  decodable_temporal_units_info_.reset();
    276 
    277  if (!last_continuous_temporal_unit_frame_id_) {
    278    return;
    279  }
    280 
    281  FrameIterator first_frame_it = frames_.begin();
    282  FrameIterator last_frame_it = frames_.begin();
    283  absl::InlinedVector<int64_t, 4> frames_in_temporal_unit;
    284  uint32_t last_decodable_temporal_unit_timestamp;
    285  for (auto frame_it = frames_.begin(); frame_it != frames_.end();) {
    286    if (GetFrameId(frame_it) > *last_continuous_temporal_unit_frame_id_) {
    287      break;
    288    }
    289 
    290    if (GetTimestamp(frame_it) != GetTimestamp(first_frame_it)) {
    291      frames_in_temporal_unit.clear();
    292      first_frame_it = frame_it;
    293    }
    294 
    295    frames_in_temporal_unit.push_back(GetFrameId(frame_it));
    296 
    297    last_frame_it = frame_it++;
    298 
    299    if (IsLastFrameInTemporalUnit(last_frame_it)) {
    300      bool temporal_unit_decodable = true;
    301      for (auto it = first_frame_it; it != frame_it && temporal_unit_decodable;
    302           ++it) {
    303        for (int64_t reference : GetReferences(it)) {
    304          if (!decoded_frame_history_.WasDecoded(reference) &&
    305              !absl::c_linear_search(frames_in_temporal_unit, reference)) {
    306            // A frame in the temporal unit has a non-decoded reference outside
    307            // the temporal unit, so it's not yet ready to be decoded.
    308            temporal_unit_decodable = false;
    309            break;
    310          }
    311        }
    312      }
    313 
    314      if (temporal_unit_decodable) {
    315        if (!next_decodable_temporal_unit_) {
    316          next_decodable_temporal_unit_ = {.first_frame = first_frame_it,
    317                                           .last_frame = last_frame_it};
    318        }
    319 
    320        last_decodable_temporal_unit_timestamp = GetTimestamp(first_frame_it);
    321      }
    322    }
    323  }
    324 
    325  if (next_decodable_temporal_unit_) {
    326    decodable_temporal_units_info_ = {
    327        .next_rtp_timestamp =
    328            GetTimestamp(next_decodable_temporal_unit_->first_frame),
    329        .last_rtp_timestamp = last_decodable_temporal_unit_timestamp};
    330  }
    331 }
    332 
    333 void FrameBuffer::Clear() {
    334  UpdateDroppedFramesAndDiscardedPackets(frames_.begin(), frames_.end());
    335  frames_.clear();
    336  next_decodable_temporal_unit_.reset();
    337  decodable_temporal_units_info_.reset();
    338  last_continuous_frame_id_.reset();
    339  last_continuous_temporal_unit_frame_id_.reset();
    340  decoded_frame_history_.Clear();
    341 }
    342 
    343 }  // namespace webrtc