xref: /aosp_15_r20/external/webrtc/modules/rtp_rtcp/source/rtp_generic_frame_descriptor_extension.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
2  *  Copyright (c) 2018 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/rtp_generic_frame_descriptor_extension.h"
12 
13 #include "rtc_base/checks.h"
14 
15 namespace webrtc {
16 namespace {
17 
18 constexpr uint8_t kFlagBeginOfSubframe = 0x80;
19 constexpr uint8_t kFlagEndOfSubframe = 0x40;
20 
21 // In version 00, the flags F and L in the first byte correspond to
22 // kFlagFirstSubframeV00 and kFlagLastSubframeV00. In practice, they were
23 // always set to `true`.
24 constexpr uint8_t kFlagFirstSubframeV00 = 0x20;
25 constexpr uint8_t kFlagLastSubframeV00 = 0x10;
26 
27 constexpr uint8_t kFlagDependencies = 0x08;
28 constexpr uint8_t kMaskTemporalLayer = 0x07;
29 
30 constexpr uint8_t kFlagMoreDependencies = 0x01;
31 constexpr uint8_t kFlageXtendedOffset = 0x02;
32 }  // namespace
33 //       0 1 2 3 4 5 6 7
34 //      +-+-+-+-+-+-+-+-+
35 //      |B|E|F|L|D|  T  |
36 //      +-+-+-+-+-+-+-+-+
37 // B:   |       S       |
38 //      +-+-+-+-+-+-+-+-+
39 //      |               |
40 // B:   +      FID      +
41 //      |               |
42 //      +-+-+-+-+-+-+-+-+
43 //      |               |
44 //      +     Width     +
45 // B=1  |               |
46 // and  +-+-+-+-+-+-+-+-+
47 // D=0  |               |
48 //      +     Height    +
49 //      |               |
50 //      +-+-+-+-+-+-+-+-+
51 // D:   |    FDIFF  |X|M|
52 //      +---------------+
53 // X:   |      ...      |
54 //      +-+-+-+-+-+-+-+-+
55 // M:   |    FDIFF  |X|M|
56 //      +---------------+
57 //      |      ...      |
58 //      +-+-+-+-+-+-+-+-+
59 constexpr RTPExtensionType RtpGenericFrameDescriptorExtension00::kId;
60 
Parse(rtc::ArrayView<const uint8_t> data,RtpGenericFrameDescriptor * descriptor)61 bool RtpGenericFrameDescriptorExtension00::Parse(
62     rtc::ArrayView<const uint8_t> data,
63     RtpGenericFrameDescriptor* descriptor) {
64   if (data.empty()) {
65     return false;
66   }
67 
68   bool begins_subframe = (data[0] & kFlagBeginOfSubframe) != 0;
69   descriptor->SetFirstPacketInSubFrame(begins_subframe);
70   descriptor->SetLastPacketInSubFrame((data[0] & kFlagEndOfSubframe) != 0);
71 
72   // Parse Subframe details provided in 1st packet of subframe.
73   if (!begins_subframe) {
74     return data.size() == 1;
75   }
76   if (data.size() < 4) {
77     return false;
78   }
79   descriptor->SetTemporalLayer(data[0] & kMaskTemporalLayer);
80   descriptor->SetSpatialLayersBitmask(data[1]);
81   descriptor->SetFrameId(data[2] | (data[3] << 8));
82 
83   // Parse dependencies.
84   descriptor->ClearFrameDependencies();
85   size_t offset = 4;
86   bool has_more_dependencies = (data[0] & kFlagDependencies) != 0;
87   if (!has_more_dependencies && data.size() >= offset + 4) {
88     uint16_t width = (data[offset] << 8) | data[offset + 1];
89     uint16_t height = (data[offset + 2] << 8) | data[offset + 3];
90     descriptor->SetResolution(width, height);
91     offset += 4;
92   }
93   while (has_more_dependencies) {
94     if (data.size() == offset)
95       return false;
96     has_more_dependencies = (data[offset] & kFlagMoreDependencies) != 0;
97     bool extended = (data[offset] & kFlageXtendedOffset) != 0;
98     uint16_t fdiff = data[offset] >> 2;
99     offset++;
100     if (extended) {
101       if (data.size() == offset)
102         return false;
103       fdiff |= (data[offset] << 6);
104       offset++;
105     }
106     if (!descriptor->AddFrameDependencyDiff(fdiff))
107       return false;
108   }
109   return true;
110 }
111 
ValueSize(const RtpGenericFrameDescriptor & descriptor)112 size_t RtpGenericFrameDescriptorExtension00::ValueSize(
113     const RtpGenericFrameDescriptor& descriptor) {
114   if (!descriptor.FirstPacketInSubFrame())
115     return 1;
116 
117   size_t size = 4;
118   for (uint16_t fdiff : descriptor.FrameDependenciesDiffs()) {
119     size += (fdiff >= (1 << 6)) ? 2 : 1;
120   }
121   if (descriptor.FirstPacketInSubFrame() &&
122       descriptor.FrameDependenciesDiffs().empty() && descriptor.Width() > 0 &&
123       descriptor.Height() > 0) {
124     size += 4;
125   }
126   return size;
127 }
128 
Write(rtc::ArrayView<uint8_t> data,const RtpGenericFrameDescriptor & descriptor)129 bool RtpGenericFrameDescriptorExtension00::Write(
130     rtc::ArrayView<uint8_t> data,
131     const RtpGenericFrameDescriptor& descriptor) {
132   RTC_CHECK_EQ(data.size(), ValueSize(descriptor));
133   uint8_t base_header =
134       (descriptor.FirstPacketInSubFrame() ? kFlagBeginOfSubframe : 0) |
135       (descriptor.LastPacketInSubFrame() ? kFlagEndOfSubframe : 0);
136   base_header |= kFlagFirstSubframeV00;
137   base_header |= kFlagLastSubframeV00;
138 
139   if (!descriptor.FirstPacketInSubFrame()) {
140     data[0] = base_header;
141     return true;
142   }
143   data[0] =
144       base_header |
145       (descriptor.FrameDependenciesDiffs().empty() ? 0 : kFlagDependencies) |
146       descriptor.TemporalLayer();
147   data[1] = descriptor.SpatialLayersBitmask();
148   uint16_t frame_id = descriptor.FrameId();
149   data[2] = frame_id & 0xff;
150   data[3] = frame_id >> 8;
151   rtc::ArrayView<const uint16_t> fdiffs = descriptor.FrameDependenciesDiffs();
152   size_t offset = 4;
153   if (descriptor.FirstPacketInSubFrame() && fdiffs.empty() &&
154       descriptor.Width() > 0 && descriptor.Height() > 0) {
155     data[offset++] = (descriptor.Width() >> 8);
156     data[offset++] = (descriptor.Width() & 0xFF);
157     data[offset++] = (descriptor.Height() >> 8);
158     data[offset++] = (descriptor.Height() & 0xFF);
159   }
160   for (size_t i = 0; i < fdiffs.size(); i++) {
161     bool extended = fdiffs[i] >= (1 << 6);
162     bool more = i < fdiffs.size() - 1;
163     data[offset++] = ((fdiffs[i] & 0x3f) << 2) |
164                      (extended ? kFlageXtendedOffset : 0) |
165                      (more ? kFlagMoreDependencies : 0);
166     if (extended) {
167       data[offset++] = fdiffs[i] >> 6;
168     }
169   }
170   return true;
171 }
172 
173 }  // namespace webrtc
174