• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2020 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/rtp_rtcp/source/active_decode_targets_helper.h"
12 
13 #include <stdint.h>
14 
15 #include "api/array_view.h"
16 #include "rtc_base/checks.h"
17 #include "rtc_base/logging.h"
18 
19 namespace webrtc {
20 namespace {
21 
22 // Returns mask of ids of chains previous frame is part of.
23 // Assumes for each chain frames are seen in order and no frame on any chain is
24 // missing. That assumptions allows a simple detection when previous frame is
25 // part of a chain.
LastSendOnChain(int frame_diff,rtc::ArrayView<const int> chain_diffs)26 std::bitset<32> LastSendOnChain(int frame_diff,
27                                 rtc::ArrayView<const int> chain_diffs) {
28   std::bitset<32> bitmask = 0;
29   for (size_t i = 0; i < chain_diffs.size(); ++i) {
30     if (frame_diff == chain_diffs[i]) {
31       bitmask.set(i);
32     }
33   }
34   return bitmask;
35 }
36 
37 // Returns bitmask with first `num` bits set to 1.
AllActive(size_t num)38 std::bitset<32> AllActive(size_t num) {
39   RTC_DCHECK_LE(num, 32);
40   return (~uint32_t{0}) >> (32 - num);
41 }
42 
43 // Returns bitmask of chains that protect at least one active decode target.
ActiveChains(rtc::ArrayView<const int> decode_target_protected_by_chain,int num_chains,std::bitset<32> active_decode_targets)44 std::bitset<32> ActiveChains(
45     rtc::ArrayView<const int> decode_target_protected_by_chain,
46     int num_chains,
47     std::bitset<32> active_decode_targets) {
48   std::bitset<32> active_chains = 0;
49   for (size_t dt = 0; dt < decode_target_protected_by_chain.size(); ++dt) {
50     if (dt < active_decode_targets.size() && !active_decode_targets[dt]) {
51       continue;
52     }
53     int chain_idx = decode_target_protected_by_chain[dt];
54     RTC_DCHECK_LT(chain_idx, num_chains);
55     active_chains.set(chain_idx);
56   }
57   return active_chains;
58 }
59 
60 }  // namespace
61 
OnFrame(rtc::ArrayView<const int> decode_target_protected_by_chain,std::bitset<32> active_decode_targets,bool is_keyframe,int64_t frame_id,rtc::ArrayView<const int> chain_diffs)62 void ActiveDecodeTargetsHelper::OnFrame(
63     rtc::ArrayView<const int> decode_target_protected_by_chain,
64     std::bitset<32> active_decode_targets,
65     bool is_keyframe,
66     int64_t frame_id,
67     rtc::ArrayView<const int> chain_diffs) {
68   const int num_chains = chain_diffs.size();
69   if (num_chains == 0) {
70     // Avoid printing the warning
71     // when already printed the warning for the same active decode targets, or
72     // when active_decode_targets are not changed from it's default value of
73     // all are active, including non-existent decode targets.
74     if (last_active_decode_targets_ != active_decode_targets &&
75         !active_decode_targets.all()) {
76       RTC_LOG(LS_WARNING) << "No chains are configured, but some decode "
77                              "targets might be inactive. Unsupported.";
78     }
79     last_active_decode_targets_ = active_decode_targets;
80     return;
81   }
82   const size_t num_decode_targets = decode_target_protected_by_chain.size();
83   RTC_DCHECK_GT(num_decode_targets, 0);
84   std::bitset<32> all_decode_targets = AllActive(num_decode_targets);
85   // Default value for active_decode_targets is 'all are active', i.e. all bits
86   // are set. Default value is set before number of decode targets is known.
87   // It is up to this helper to make the value cleaner and unset unused bits.
88   active_decode_targets &= all_decode_targets;
89 
90   if (is_keyframe) {
91     // Key frame resets the state.
92     last_active_decode_targets_ = all_decode_targets;
93     last_active_chains_ = AllActive(num_chains);
94     unsent_on_chain_.reset();
95   } else {
96     // Update state assuming previous frame was sent.
97     unsent_on_chain_ &=
98         ~LastSendOnChain(frame_id - last_frame_id_, chain_diffs);
99   }
100   // Save for the next call to OnFrame.
101   // Though usually `frame_id == last_frame_id_ + 1`, it might not be so when
102   // frame id space is shared by several simulcast rtp streams.
103   last_frame_id_ = frame_id;
104 
105   if (active_decode_targets == last_active_decode_targets_) {
106     return;
107   }
108   last_active_decode_targets_ = active_decode_targets;
109 
110   if (active_decode_targets.none()) {
111     RTC_LOG(LS_ERROR) << "It is invalid to produce a frame (" << frame_id
112                       << ") while there are no active decode targets";
113     return;
114   }
115   last_active_chains_ = ActiveChains(decode_target_protected_by_chain,
116                                      num_chains, active_decode_targets);
117   // Frames that are part of inactive chains might not be produced by the
118   // encoder. Thus stop sending `active_decode_target` bitmask when it is sent
119   // on all active chains rather than on all chains.
120   unsent_on_chain_ = last_active_chains_;
121   RTC_DCHECK(!unsent_on_chain_.none());
122 }
123 
124 }  // namespace webrtc
125