Line data Source code
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 "webrtc/modules/rtp_rtcp/source/rtcp_packet/target_bitrate.h"
12 :
13 : #include "webrtc/base/checks.h"
14 : #include "webrtc/base/logging.h"
15 : #include "webrtc/modules/rtp_rtcp/source/byte_io.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 :
23 0 : TargetBitrate::BitrateItem::BitrateItem()
24 0 : : spatial_layer(0), temporal_layer(0), target_bitrate_kbps(0) {}
25 :
26 0 : TargetBitrate::BitrateItem::BitrateItem(uint8_t spatial_layer,
27 : uint8_t temporal_layer,
28 0 : uint32_t target_bitrate_kbps)
29 : : spatial_layer(spatial_layer),
30 : temporal_layer(temporal_layer),
31 0 : 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 0 : TargetBitrate::TargetBitrate() {}
66 0 : TargetBitrate::~TargetBitrate() {}
67 :
68 0 : void TargetBitrate::Create(uint8_t* buffer) const {
69 0 : buffer[0] = kBlockType;
70 0 : buffer[1] = 0; // Reserved.
71 0 : const size_t block_length_words = (BlockLength() / 4) - 1;
72 0 : ByteWriter<uint16_t>::WriteBigEndian(&buffer[2], block_length_words);
73 :
74 0 : size_t index = kTargetBitrateHeaderSizeBytes;
75 0 : for (const BitrateItem& item : bitrates_) {
76 0 : buffer[index] = (item.spatial_layer << 4) | item.temporal_layer;
77 0 : ByteWriter<uint32_t, 3>::WriteBigEndian(&buffer[index + 1],
78 0 : item.target_bitrate_kbps);
79 0 : index += kBitrateItemSizeBytes;
80 : }
81 0 : }
82 :
83 0 : bool TargetBitrate::Parse(const uint8_t* block, uint16_t block_length) {
84 0 : if (block_length < 1) {
85 0 : LOG(LS_WARNING)
86 0 : << "Cannot parse TargetBitrate RTCP packet: Too little payload data ("
87 0 : << kTargetBitrateHeaderSizeBytes << " bytes needed, got "
88 0 : << block_length * 4 << ").";
89 0 : return false;
90 : }
91 :
92 : // Validate block header (should already have been parsed and checked).
93 0 : RTC_DCHECK_EQ(block[0], kBlockType);
94 0 : RTC_DCHECK_EQ(block_length, ByteReader<uint16_t>::ReadBigEndian(&block[2]));
95 :
96 : // Header specifies block length - 1, but since we ignore the header, which
97 : // occupies exactly on block, we can just treat this as payload length.
98 0 : const size_t payload_bytes = block_length * 4;
99 0 : const size_t num_items = payload_bytes / kBitrateItemSizeBytes;
100 0 : size_t index = kTargetBitrateHeaderSizeBytes;
101 0 : bitrates_.clear();
102 0 : for (size_t i = 0; i < num_items; ++i) {
103 0 : uint8_t layers = block[index];
104 : uint32_t bitrate_kbps =
105 0 : ByteReader<uint32_t, 3>::ReadBigEndian(&block[index + 1]);
106 0 : index += kBitrateItemSizeBytes;
107 0 : AddTargetBitrate((layers >> 4) & 0x0F, layers & 0x0F, bitrate_kbps);
108 : }
109 :
110 0 : return true;
111 : }
112 :
113 0 : void TargetBitrate::AddTargetBitrate(uint8_t spatial_layer,
114 : uint8_t temporal_layer,
115 : uint32_t target_bitrate_kbps) {
116 0 : RTC_DCHECK_LE(spatial_layer, 0x0F);
117 0 : RTC_DCHECK_LE(temporal_layer, 0x0F);
118 0 : RTC_DCHECK_LE(target_bitrate_kbps, 0x00FFFFFFU);
119 0 : bitrates_.push_back(
120 0 : BitrateItem(spatial_layer, temporal_layer, target_bitrate_kbps));
121 0 : }
122 :
123 : const std::vector<TargetBitrate::BitrateItem>&
124 0 : TargetBitrate::GetTargetBitrates() const {
125 0 : return bitrates_;
126 : }
127 :
128 0 : size_t TargetBitrate::BlockLength() const {
129 : return kTargetBitrateHeaderSizeBytes +
130 0 : bitrates_.size() * kBitrateItemSizeBytes;
131 : }
132 :
133 : } // namespace rtcp
134 : } // namespace webrtc
|