1 /*
2 * Copyright (c) 2016 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/rtcp_packet/target_bitrate.h"
12
13 #include "modules/rtp_rtcp/source/byte_io.h"
14 #include "rtc_base/checks.h"
15 #include "rtc_base/numerics/safe_conversions.h"
16
17 namespace webrtc {
18 namespace rtcp {
19 constexpr size_t kTargetBitrateHeaderSizeBytes = 4;
20 constexpr uint8_t TargetBitrate::kBlockType;
21 const size_t TargetBitrate::kBitrateItemSizeBytes = 4;
22
BitrateItem()23 TargetBitrate::BitrateItem::BitrateItem()
24 : spatial_layer(0), temporal_layer(0), target_bitrate_kbps(0) {}
25
BitrateItem(uint8_t spatial_layer,uint8_t temporal_layer,uint32_t target_bitrate_kbps)26 TargetBitrate::BitrateItem::BitrateItem(uint8_t spatial_layer,
27 uint8_t temporal_layer,
28 uint32_t target_bitrate_kbps)
29 : spatial_layer(spatial_layer),
30 temporal_layer(temporal_layer),
31 target_bitrate_kbps(target_bitrate_kbps) {}
32
33 // RFC 4585: Feedback format.
34 //
35 // Common packet format:
36 //
37 // 0 1 2 3
38 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
39 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
40 // | BT=42 | reserved | block length |
41 // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
42 //
43 // Target bitrate item (repeat as many times as necessary).
44 //
45 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 // | S | T | Target Bitrate |
47 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
48 // : ... :
49 //
50 // Spatial Layer (S): 4 bits
51 // Indicates which temporal layer this bitrate concerns.
52 //
53 // Temporal Layer (T): 4 bits
54 // Indicates which temporal layer this bitrate concerns.
55 //
56 // Target Bitrate: 24 bits
57 // The encoder target bitrate for this layer, in kbps.
58 //
59 // As an example of how S and T are intended to be used, VP8 simulcast will
60 // use a separate TargetBitrate message per stream, since they are transmitted
61 // on separate SSRCs, with temporal layers grouped by stream.
62 // If VP9 SVC is used, there will be only one SSRC, so each spatial and
63 // temporal layer combo used shall be specified in the TargetBitrate packet.
64
65 TargetBitrate::TargetBitrate() = default;
66 TargetBitrate::TargetBitrate(const TargetBitrate&) = default;
67 TargetBitrate& TargetBitrate::operator=(const TargetBitrate&) = default;
68 TargetBitrate::~TargetBitrate() = default;
69
Parse(const uint8_t * block,uint16_t block_length)70 void TargetBitrate::Parse(const uint8_t* block, uint16_t block_length) {
71 // Validate block header (should already have been parsed and checked).
72 RTC_DCHECK_EQ(block[0], kBlockType);
73 RTC_DCHECK_EQ(block_length, ByteReader<uint16_t>::ReadBigEndian(&block[2]));
74
75 // Header specifies block length - 1, but since we ignore the header, which
76 // occupies exactly on block, we can just treat this as payload length.
77 const size_t payload_bytes = block_length * 4;
78 const size_t num_items = payload_bytes / kBitrateItemSizeBytes;
79 size_t index = kTargetBitrateHeaderSizeBytes;
80 bitrates_.clear();
81 for (size_t i = 0; i < num_items; ++i) {
82 uint8_t layers = block[index];
83 uint32_t bitrate_kbps =
84 ByteReader<uint32_t, 3>::ReadBigEndian(&block[index + 1]);
85 index += kBitrateItemSizeBytes;
86 AddTargetBitrate((layers >> 4) & 0x0F, layers & 0x0F, bitrate_kbps);
87 }
88 }
89
AddTargetBitrate(uint8_t spatial_layer,uint8_t temporal_layer,uint32_t target_bitrate_kbps)90 void TargetBitrate::AddTargetBitrate(uint8_t spatial_layer,
91 uint8_t temporal_layer,
92 uint32_t target_bitrate_kbps) {
93 RTC_DCHECK_LE(spatial_layer, 0x0F);
94 RTC_DCHECK_LE(temporal_layer, 0x0F);
95 RTC_DCHECK_LE(target_bitrate_kbps, 0x00FFFFFFU);
96 bitrates_.push_back(
97 BitrateItem(spatial_layer, temporal_layer, target_bitrate_kbps));
98 }
99
100 const std::vector<TargetBitrate::BitrateItem>&
GetTargetBitrates() const101 TargetBitrate::GetTargetBitrates() const {
102 return bitrates_;
103 }
104
BlockLength() const105 size_t TargetBitrate::BlockLength() const {
106 return kTargetBitrateHeaderSizeBytes +
107 bitrates_.size() * kBitrateItemSizeBytes;
108 }
109
Create(uint8_t * buffer) const110 void TargetBitrate::Create(uint8_t* buffer) const {
111 buffer[0] = kBlockType;
112 buffer[1] = 0; // Reserved.
113 uint16_t block_length_words =
114 rtc::dchecked_cast<uint16_t>((BlockLength() / 4) - 1);
115 ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], block_length_words);
116
117 size_t index = kTargetBitrateHeaderSizeBytes;
118 for (const BitrateItem& item : bitrates_) {
119 buffer[index] = (item.spatial_layer << 4) | item.temporal_layer;
120 ByteWriter<uint32_t, 3>::WriteBigEndian(&buffer[index + 1],
121 item.target_bitrate_kbps);
122 index += kBitrateItemSizeBytes;
123 }
124 }
125
126 } // namespace rtcp
127 } // namespace webrtc
128