1 /*
2 * Copyright (c) 2019 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 #include "modules/rtp_rtcp/source/rtp_packetizer_av1.h"
11
12 #include <stddef.h>
13 #include <stdint.h>
14
15 #include <algorithm>
16
17 #include "api/array_view.h"
18 #include "api/video/video_frame_type.h"
19 #include "modules/rtp_rtcp/source/rtp_packet_to_send.h"
20 #include "rtc_base/byte_buffer.h"
21 #include "rtc_base/checks.h"
22 #include "rtc_base/logging.h"
23
24 namespace webrtc {
25 namespace {
26 // TODO(danilchap): Some of the helpers/constants are same as in
27 // rtp_depacketizer_av1. Move them to common av1 file.
28 constexpr int kAggregationHeaderSize = 1;
29 // when there are 3 or less OBU (fragments) in a packet, size of the last one
30 // can be omited.
31 constexpr int kMaxNumObusToOmitSize = 3;
32 constexpr uint8_t kObuSizePresentBit = 0b0'0000'010;
33 constexpr int kObuTypeSequenceHeader = 1;
34 constexpr int kObuTypeTemporalDelimiter = 2;
35 constexpr int kObuTypeTileList = 8;
36 constexpr int kObuTypePadding = 15;
37
ObuHasExtension(uint8_t obu_header)38 bool ObuHasExtension(uint8_t obu_header) {
39 return obu_header & 0b0'0000'100;
40 }
41
ObuHasSize(uint8_t obu_header)42 bool ObuHasSize(uint8_t obu_header) {
43 return obu_header & kObuSizePresentBit;
44 }
45
ObuType(uint8_t obu_header)46 int ObuType(uint8_t obu_header) {
47 return (obu_header & 0b0'1111'000) >> 3;
48 }
49
Leb128Size(int value)50 int Leb128Size(int value) {
51 RTC_DCHECK_GE(value, 0);
52 int size = 0;
53 while (value >= 0x80) {
54 ++size;
55 value >>= 7;
56 }
57 return size + 1;
58 }
59
60 // Returns number of bytes consumed.
WriteLeb128(uint32_t value,uint8_t * buffer)61 int WriteLeb128(uint32_t value, uint8_t* buffer) {
62 int size = 0;
63 while (value >= 0x80) {
64 buffer[size] = 0x80 | (value & 0x7F);
65 ++size;
66 value >>= 7;
67 }
68 buffer[size] = value;
69 ++size;
70 return size;
71 }
72
73 // Given |remaining_bytes| free bytes left in a packet, returns max size of an
74 // OBU fragment that can fit into the packet.
75 // i.e. MaxFragmentSize + Leb128Size(MaxFragmentSize) <= remaining_bytes.
MaxFragmentSize(int remaining_bytes)76 int MaxFragmentSize(int remaining_bytes) {
77 if (remaining_bytes <= 1) {
78 return 0;
79 }
80 for (int i = 1;; ++i) {
81 if (remaining_bytes < (1 << 7 * i) + i) {
82 return remaining_bytes - i;
83 }
84 }
85 }
86
87 } // namespace
88
RtpPacketizerAv1(rtc::ArrayView<const uint8_t> payload,RtpPacketizer::PayloadSizeLimits limits,VideoFrameType frame_type)89 RtpPacketizerAv1::RtpPacketizerAv1(rtc::ArrayView<const uint8_t> payload,
90 RtpPacketizer::PayloadSizeLimits limits,
91 VideoFrameType frame_type)
92 : frame_type_(frame_type),
93 obus_(ParseObus(payload)),
94 packets_(Packetize(obus_, limits)) {}
95
ParseObus(rtc::ArrayView<const uint8_t> payload)96 std::vector<RtpPacketizerAv1::Obu> RtpPacketizerAv1::ParseObus(
97 rtc::ArrayView<const uint8_t> payload) {
98 std::vector<Obu> result;
99 rtc::ByteBufferReader payload_reader(
100 reinterpret_cast<const char*>(payload.data()), payload.size());
101 while (payload_reader.Length() > 0) {
102 Obu obu;
103 payload_reader.ReadUInt8(&obu.header);
104 obu.size = 1;
105 if (ObuHasExtension(obu.header)) {
106 if (payload_reader.Length() == 0) {
107 RTC_DLOG(LS_ERROR) << "Malformed AV1 input: expected extension_header, "
108 "no more bytes in the buffer. Offset: "
109 << (payload.size() - payload_reader.Length());
110 return {};
111 }
112 payload_reader.ReadUInt8(&obu.extension_header);
113 ++obu.size;
114 }
115 if (!ObuHasSize(obu.header)) {
116 obu.payload = rtc::MakeArrayView(
117 reinterpret_cast<const uint8_t*>(payload_reader.Data()),
118 payload_reader.Length());
119 payload_reader.Consume(payload_reader.Length());
120 } else {
121 uint64_t size = 0;
122 if (!payload_reader.ReadUVarint(&size) ||
123 size > payload_reader.Length()) {
124 RTC_DLOG(LS_ERROR) << "Malformed AV1 input: declared size " << size
125 << " is larger than remaining buffer size "
126 << payload_reader.Length();
127 return {};
128 }
129 obu.payload = rtc::MakeArrayView(
130 reinterpret_cast<const uint8_t*>(payload_reader.Data()), size);
131 payload_reader.Consume(size);
132 }
133 obu.size += obu.payload.size();
134 // Skip obus that shouldn't be transfered over rtp.
135 int obu_type = ObuType(obu.header);
136 if (obu_type != kObuTypeTemporalDelimiter && //
137 obu_type != kObuTypeTileList && //
138 obu_type != kObuTypePadding) {
139 result.push_back(obu);
140 }
141 }
142 return result;
143 }
144
AdditionalBytesForPreviousObuElement(const Packet & packet)145 int RtpPacketizerAv1::AdditionalBytesForPreviousObuElement(
146 const Packet& packet) {
147 if (packet.packet_size == 0) {
148 // Packet is still empty => no last OBU element, no need to reserve space
149 // for it.
150 return 0;
151 }
152 if (packet.num_obu_elements > kMaxNumObusToOmitSize) {
153 // There is so many obu elements in the packet, all of them must be
154 // prepended with the length field. That imply space for the length of the
155 // last obu element is already reserved.
156 return 0;
157 }
158 // No space was reserved for length field of the last OBU element, but that
159 // element becoming non-last, so it now requires explicit length field.
160 // Calculate how many bytes are needed to store the length in leb128 format.
161 return Leb128Size(packet.last_obu_size);
162 }
163
Packetize(rtc::ArrayView<const Obu> obus,PayloadSizeLimits limits)164 std::vector<RtpPacketizerAv1::Packet> RtpPacketizerAv1::Packetize(
165 rtc::ArrayView<const Obu> obus,
166 PayloadSizeLimits limits) {
167 std::vector<Packet> packets;
168 if (obus.empty()) {
169 return packets;
170 }
171 // Ignore certian edge cases where packets should be very small. They are
172 // inpractical but adds complexity to handle.
173 if (limits.max_payload_len - limits.last_packet_reduction_len < 3 ||
174 limits.max_payload_len - limits.first_packet_reduction_len < 3) {
175 RTC_DLOG(LS_ERROR) << "Failed to packetize AV1 frame: requested packet "
176 "size is unreasonable small.";
177 return packets;
178 }
179 // Aggregation header is present in all packets.
180 limits.max_payload_len -= kAggregationHeaderSize;
181
182 // Assemble packets. Push to current packet as much as it can hold before
183 // considering next one. That would normally cause uneven distribution across
184 // packets, specifically last one would be generally smaller.
185 packets.emplace_back(/*first_obu_index=*/0);
186 int packet_remaining_bytes =
187 limits.max_payload_len - limits.first_packet_reduction_len;
188 for (size_t obu_index = 0; obu_index < obus.size(); ++obu_index) {
189 const bool is_last_obu = obu_index == obus.size() - 1;
190 const Obu& obu = obus[obu_index];
191
192 // Putting |obu| into the last packet would make last obu element stored in
193 // that packet not last. All not last OBU elements must be prepend with the
194 // element length. AdditionalBytesForPreviousObuElement calculates how many
195 // bytes are needed to store that length.
196 int previous_obu_extra_size =
197 AdditionalBytesForPreviousObuElement(packets.back());
198 int min_required_size =
199 packets.back().num_obu_elements >= kMaxNumObusToOmitSize ? 2 : 1;
200 if (packet_remaining_bytes < previous_obu_extra_size + min_required_size) {
201 // Start a new packet.
202 packets.emplace_back(/*first_obu_index=*/obu_index);
203 packet_remaining_bytes = limits.max_payload_len;
204 previous_obu_extra_size = 0;
205 }
206 Packet& packet = packets.back();
207 // Start inserting current obu into the packet.
208 packet.packet_size += previous_obu_extra_size;
209 packet_remaining_bytes -= previous_obu_extra_size;
210 packet.num_obu_elements++;
211
212 bool must_write_obu_element_size =
213 packet.num_obu_elements > kMaxNumObusToOmitSize;
214 // Can fit all of the obu into the packet?
215 int required_bytes = obu.size;
216 if (must_write_obu_element_size) {
217 required_bytes += Leb128Size(obu.size);
218 }
219 int available_bytes = packet_remaining_bytes;
220 if (is_last_obu) {
221 // If this packet would be the last packet, available size is smaller.
222 if (packets.size() == 1) {
223 available_bytes += limits.first_packet_reduction_len;
224 available_bytes -= limits.single_packet_reduction_len;
225 } else {
226 available_bytes -= limits.last_packet_reduction_len;
227 }
228 }
229 if (required_bytes <= available_bytes) {
230 // Insert the obu into the packet unfragmented.
231 packet.last_obu_size = obu.size;
232 packet.packet_size += required_bytes;
233 packet_remaining_bytes -= required_bytes;
234 continue;
235 }
236
237 // Fragment the obu.
238 int max_first_fragment_size = must_write_obu_element_size
239 ? MaxFragmentSize(packet_remaining_bytes)
240 : packet_remaining_bytes;
241 // Because available_bytes might be different than
242 // packet_remaining_bytes it might happen that max_first_fragment_size >=
243 // obu.size. Also, since checks above verified |obu| should not be put
244 // completely into the |packet|, leave at least 1 byte for later packet.
245 int first_fragment_size = std::min(obu.size - 1, max_first_fragment_size);
246 if (first_fragment_size == 0) {
247 // Rather than writing 0-size element at the tail of the packet,
248 // 'uninsert' the |obu| from the |packet|.
249 packet.num_obu_elements--;
250 packet.packet_size -= previous_obu_extra_size;
251 } else {
252 packet.packet_size += first_fragment_size;
253 if (must_write_obu_element_size) {
254 packet.packet_size += Leb128Size(first_fragment_size);
255 }
256 packet.last_obu_size = first_fragment_size;
257 }
258
259 // Add middle fragments that occupy all of the packet.
260 // These are easy because
261 // - one obu per packet imply no need to store the size of the obu.
262 // - this packets are nor the first nor the last packets of the frame, so
263 // packet capacity is always limits.max_payload_len.
264 int obu_offset;
265 for (obu_offset = first_fragment_size;
266 obu_offset + limits.max_payload_len < obu.size;
267 obu_offset += limits.max_payload_len) {
268 packets.emplace_back(/*first_obu_index=*/obu_index);
269 Packet& packet = packets.back();
270 packet.num_obu_elements = 1;
271 packet.first_obu_offset = obu_offset;
272 int middle_fragment_size = limits.max_payload_len;
273 packet.last_obu_size = middle_fragment_size;
274 packet.packet_size = middle_fragment_size;
275 }
276
277 // Add the last fragment of the obu.
278 int last_fragment_size = obu.size - obu_offset;
279 // Check for corner case where last fragment of the last obu is too large
280 // to fit into last packet, but may fully fit into semi-last packet.
281 if (is_last_obu &&
282 last_fragment_size >
283 limits.max_payload_len - limits.last_packet_reduction_len) {
284 // Split last fragments into two.
285 RTC_DCHECK_GE(last_fragment_size, 2);
286 // Try to even packet sizes rather than payload sizes across the last
287 // two packets.
288 int semi_last_fragment_size =
289 (last_fragment_size + limits.last_packet_reduction_len) / 2;
290 // But leave at least one payload byte for the last packet to avoid
291 // weird scenarios where size of the fragment is zero and rtp payload has
292 // nothing except for an aggregation header.
293 if (semi_last_fragment_size >= last_fragment_size) {
294 semi_last_fragment_size = last_fragment_size - 1;
295 }
296 last_fragment_size -= semi_last_fragment_size;
297
298 packets.emplace_back(/*first_obu_index=*/obu_index);
299 Packet& packet = packets.back();
300 packet.num_obu_elements = 1;
301 packet.first_obu_offset = obu_offset;
302 packet.last_obu_size = semi_last_fragment_size;
303 packet.packet_size = semi_last_fragment_size;
304 obu_offset += semi_last_fragment_size;
305 }
306 packets.emplace_back(/*first_obu_index=*/obu_index);
307 Packet& last_packet = packets.back();
308 last_packet.num_obu_elements = 1;
309 last_packet.first_obu_offset = obu_offset;
310 last_packet.last_obu_size = last_fragment_size;
311 last_packet.packet_size = last_fragment_size;
312 packet_remaining_bytes = limits.max_payload_len - last_fragment_size;
313 }
314 return packets;
315 }
316
AggregationHeader() const317 uint8_t RtpPacketizerAv1::AggregationHeader() const {
318 const Packet& packet = packets_[packet_index_];
319 uint8_t aggregation_header = 0;
320
321 // Set Z flag: first obu element is continuation of the previous OBU.
322 bool first_obu_element_is_fragment = packet.first_obu_offset > 0;
323 if (first_obu_element_is_fragment)
324 aggregation_header |= (1 << 7);
325
326 // Set Y flag: last obu element will be continuated in the next packet.
327 int last_obu_offset =
328 packet.num_obu_elements == 1 ? packet.first_obu_offset : 0;
329 bool last_obu_is_fragment =
330 last_obu_offset + packet.last_obu_size <
331 obus_[packet.first_obu + packet.num_obu_elements - 1].size;
332 if (last_obu_is_fragment)
333 aggregation_header |= (1 << 6);
334
335 // Set W field: number of obu elements in the packet (when not too large).
336 if (packet.num_obu_elements <= kMaxNumObusToOmitSize)
337 aggregation_header |= packet.num_obu_elements << 4;
338
339 // Set N flag: beginning of a new coded video sequence.
340 // Encoder may produce key frame without a sequence header, thus double check
341 // incoming frame includes the sequence header. Since Temporal delimiter is
342 // already filtered out, sequence header should be the first obu when present.
343 if (frame_type_ == VideoFrameType::kVideoFrameKey && packet_index_ == 0 &&
344 ObuType(obus_.front().header) == kObuTypeSequenceHeader) {
345 aggregation_header |= (1 << 3);
346 }
347 return aggregation_header;
348 }
349
NextPacket(RtpPacketToSend * packet)350 bool RtpPacketizerAv1::NextPacket(RtpPacketToSend* packet) {
351 if (packet_index_ >= packets_.size()) {
352 return false;
353 }
354 const Packet& next_packet = packets_[packet_index_];
355
356 RTC_DCHECK_GT(next_packet.num_obu_elements, 0);
357 RTC_DCHECK_LT(next_packet.first_obu_offset,
358 obus_[next_packet.first_obu].size);
359 RTC_DCHECK_LE(
360 next_packet.last_obu_size,
361 obus_[next_packet.first_obu + next_packet.num_obu_elements - 1].size);
362
363 uint8_t* const rtp_payload =
364 packet->AllocatePayload(kAggregationHeaderSize + next_packet.packet_size);
365 uint8_t* write_at = rtp_payload;
366
367 *write_at++ = AggregationHeader();
368
369 int obu_offset = next_packet.first_obu_offset;
370 // Store all OBU elements except the last one.
371 for (int i = 0; i < next_packet.num_obu_elements - 1; ++i) {
372 const Obu& obu = obus_[next_packet.first_obu + i];
373 size_t fragment_size = obu.size - obu_offset;
374 write_at += WriteLeb128(fragment_size, write_at);
375 if (obu_offset == 0) {
376 *write_at++ = obu.header & ~kObuSizePresentBit;
377 }
378 if (obu_offset <= 1 && ObuHasExtension(obu.header)) {
379 *write_at++ = obu.extension_header;
380 }
381 int payload_offset =
382 std::max(0, obu_offset - (ObuHasExtension(obu.header) ? 2 : 1));
383 size_t payload_size = obu.payload.size() - payload_offset;
384 memcpy(write_at, obu.payload.data() + payload_offset, payload_size);
385 write_at += payload_size;
386 // All obus are stored from the beginning, except, may be, the first one.
387 obu_offset = 0;
388 }
389 // Store the last OBU element.
390 const Obu& last_obu =
391 obus_[next_packet.first_obu + next_packet.num_obu_elements - 1];
392 int fragment_size = next_packet.last_obu_size;
393 RTC_DCHECK_GT(fragment_size, 0);
394 if (next_packet.num_obu_elements > kMaxNumObusToOmitSize) {
395 write_at += WriteLeb128(fragment_size, write_at);
396 }
397 if (obu_offset == 0 && fragment_size > 0) {
398 *write_at++ = last_obu.header & ~kObuSizePresentBit;
399 --fragment_size;
400 }
401 if (obu_offset <= 1 && ObuHasExtension(last_obu.header) &&
402 fragment_size > 0) {
403 *write_at++ = last_obu.extension_header;
404 --fragment_size;
405 }
406 RTC_DCHECK_EQ(write_at - rtp_payload + fragment_size,
407 kAggregationHeaderSize + next_packet.packet_size);
408 int payload_offset =
409 std::max(0, obu_offset - (ObuHasExtension(last_obu.header) ? 2 : 1));
410 memcpy(write_at, last_obu.payload.data() + payload_offset, fragment_size);
411 write_at += fragment_size;
412
413 RTC_DCHECK_EQ(write_at - rtp_payload,
414 kAggregationHeaderSize + next_packet.packet_size);
415
416 ++packet_index_;
417 if (packet_index_ == packets_.size()) {
418 // TODO(danilchap): To support spatial scalability pass and use information
419 // if this frame is the last in the temporal unit.
420 packet->SetMarker(true);
421 }
422 return true;
423 }
424
425 } // namespace webrtc
426