mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-16 07:10:38 +01:00

Bug: webrtc:10342 Change-Id: I5e8a204881b94fe5786b14e27cefce2fe056e91b Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/178140 Reviewed-by: Björn Terelius <terelius@webrtc.org> Reviewed-by: Philip Eliasson <philipel@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/master@{#31579}
128 lines
4.8 KiB
C++
128 lines
4.8 KiB
C++
/*
|
|
* Copyright (c) 2020 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 "modules/rtp_rtcp/source/active_decode_targets_helper.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "api/array_view.h"
|
|
#include "rtc_base/checks.h"
|
|
#include "rtc_base/logging.h"
|
|
|
|
namespace webrtc {
|
|
namespace {
|
|
|
|
// Returns mask of ids of chains previous frame is part of.
|
|
// Assumes for each chain frames are seen in order and no frame on any chain is
|
|
// missing. That assumptions allows a simple detection when previous frame is
|
|
// part of a chain.
|
|
std::bitset<32> LastSendOnChain(int frame_diff,
|
|
rtc::ArrayView<const int> chain_diffs) {
|
|
std::bitset<32> bitmask = 0;
|
|
for (size_t i = 0; i < chain_diffs.size(); ++i) {
|
|
if (frame_diff == chain_diffs[i]) {
|
|
bitmask.set(i);
|
|
}
|
|
}
|
|
return bitmask;
|
|
}
|
|
|
|
// Returns bitmask with first `num` bits set to 1.
|
|
std::bitset<32> AllActive(size_t num) {
|
|
RTC_DCHECK_LE(num, 32);
|
|
return (~uint32_t{0}) >> (32 - num);
|
|
}
|
|
|
|
// Returns bitmask of chains that protect at least one active decode target.
|
|
std::bitset<32> ActiveChains(
|
|
rtc::ArrayView<const int> decode_target_protected_by_chain,
|
|
int num_chains,
|
|
std::bitset<32> active_decode_targets) {
|
|
std::bitset<32> active_chains = 0;
|
|
for (size_t dt = 0; dt < decode_target_protected_by_chain.size(); ++dt) {
|
|
if (dt < active_decode_targets.size() && !active_decode_targets[dt]) {
|
|
continue;
|
|
}
|
|
// chain_idx == num_chains is valid and means the decode target is
|
|
// not protected by any chain.
|
|
int chain_idx = decode_target_protected_by_chain[dt];
|
|
if (chain_idx < num_chains) {
|
|
active_chains.set(chain_idx);
|
|
}
|
|
}
|
|
return active_chains;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void ActiveDecodeTargetsHelper::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) {
|
|
const int num_chains = chain_diffs.size();
|
|
if (num_chains == 0) {
|
|
// Avoid printing the warning
|
|
// when already printed the warning for the same active decode targets, or
|
|
// when active_decode_targets are not changed from it's default value of
|
|
// all are active, including non-existent decode targets.
|
|
if (last_active_decode_targets_ != active_decode_targets &&
|
|
!active_decode_targets.all()) {
|
|
RTC_LOG(LS_WARNING) << "No chains are configured, but some decode "
|
|
"targets might be inactive. Unsupported.";
|
|
}
|
|
last_active_decode_targets_ = active_decode_targets;
|
|
return;
|
|
}
|
|
const size_t num_decode_targets = decode_target_protected_by_chain.size();
|
|
RTC_DCHECK_GT(num_decode_targets, 0);
|
|
std::bitset<32> all_decode_targets = AllActive(num_decode_targets);
|
|
// Default value for active_decode_targets is 'all are active', i.e. all bits
|
|
// are set. Default value is set before number of decode targets is known.
|
|
// It is up to this helper to make the value cleaner and unset unused bits.
|
|
active_decode_targets &= all_decode_targets;
|
|
|
|
if (is_keyframe) {
|
|
// Key frame resets the state.
|
|
last_active_decode_targets_ = all_decode_targets;
|
|
last_active_chains_ = AllActive(num_chains);
|
|
unsent_on_chain_.reset();
|
|
} else {
|
|
// Update state assuming previous frame was sent.
|
|
unsent_on_chain_ &=
|
|
~LastSendOnChain(frame_id - last_frame_id_, chain_diffs);
|
|
}
|
|
// Save for the next call to OnFrame.
|
|
// Though usually `frame_id == last_frame_id_ + 1`, it might not be so when
|
|
// frame id space is shared by several simulcast rtp streams.
|
|
last_frame_id_ = frame_id;
|
|
|
|
if (active_decode_targets == last_active_decode_targets_) {
|
|
return;
|
|
}
|
|
last_active_decode_targets_ = active_decode_targets;
|
|
last_active_chains_ = ActiveChains(decode_target_protected_by_chain,
|
|
num_chains, active_decode_targets);
|
|
// Frames that are part of inactive chains might not be produced by the
|
|
// encoder. Thus stop sending `active_decode_target` bitmask when it is sent
|
|
// on all active chains rather than on all chains.
|
|
unsent_on_chain_ = last_active_chains_;
|
|
if (unsent_on_chain_.none()) {
|
|
// Active decode targets are not protected by any chains. To be on the
|
|
// safe side always send the active_decode_targets_bitmask from now on.
|
|
RTC_LOG(LS_WARNING)
|
|
<< "Active decode targets protected by no chains. (In)active decode "
|
|
"targets information will be send overreliably.";
|
|
unsent_on_chain_.set(1);
|
|
}
|
|
}
|
|
|
|
} // namespace webrtc
|