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