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