1 /*
2 * Packetization for RTP Payload Format For AV1 (v1.0)
3 * https://aomediacodec.github.io/av1-rtp-spec/
4 * Copyright (c) 2024 Axis Communications
5 *
6 * This file is part of FFmpeg.
7 *
8 * FFmpeg is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * FFmpeg is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with FFmpeg; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /**
24 * @file
25 * @brief AV1 / RTP packetization code (RTP Payload Format For AV1 (v1.0))
26 * @author Chris Hodges <chris.hodges@axis.com>
27 * @note This will remove TDs and OBU size fields
28 */
29
34
35 // enable tracing of packet data
36 //#define RTPENC_AV1_VERBOSE_TRACE
37
38 // enable searching for sequence header as workaround for AV1 encoders
39 // that do not set AV_PKT_FLAG_KEY correctly
40 #define RTPENC_AV1_SEARCH_SEQ_HEADER 1
41
43 uint8_t aggr_hdr = 0;
44 int last_packet_of_frame = 0;
46 const uint8_t *obu_ptr = frame_buf;
47 int start_new_packet = 0;
48 unsigned int num_obus = 0;
50 uint8_t *pkt_ptr =
NULL;
51
52 const uint8_t *curr_obu_ptr =
NULL;
53 uint32_t curr_elem_size = 0;
54 int curr_obu_hdr = -1;
55 int curr_obu_ext = -1;
56 const uint8_t *last_obu_ptr =
NULL;
57 uint32_t last_elem_size = 0;
58 int last_obu_hdr = -1;
59 int last_obu_ext = -1;
60
62
63 /* The payload structure is supposed to be straight-forward, but there are a
64 * couple of edge cases to be tackled and make things very complex.
65 * These are mainly due to:
66 * - the OBU element size being optional for the last element, but MANDATORY
67 * if there are more than 3 elements
68 * - the size field of the element is made up of a variable number of
69 * LEB bytes
70 * - the latter in combination with the desire to fill the max packet size
71 * could cause a catch22
72 * - if there's less than 2 bytes remaining (depending on the required LEB),
73 * one would not have space for the payload of an element and must instead
74 * start the next packet
75 * - if there's less than 3 bytes remaining, the header byte plus the
76 * optional extension byte will not fit in the fragment making the
77 * handling even more complicated
78 * - as some OBU types are supposed to be filtered out, it is hard to decide
79 * via the remaining length whether the outputted OBU element will
80 * actually be the last one
81 *
82 * There are two major ways to tackle that: Pre-parsing of all OBUs within a
83 * frame (adds memory complexity) or lazy copying of the prior element.
84 * Here, the latter is implemented.
85 */
86
88 #if RTPENC_AV1_SEARCH_SEQ_HEADER
89 /* search for OBU_SEQUENCE_HEADER to get a better indication that
90 * the frame was marked as keyframe is really a KEY_FRAME and not
91 * a INTRA_ONLY frame. This might be unnecessary if the AV1 parser/
92 * encoder always correctly specifies AV_PKT_FLAG_KEY.
93 *
94 * Note: Spec does NOT prohibit resending bit-identical
95 * OBU_SEQUENCE_HEADER for ANY kind of frame, though!
96 */
98 const uint8_t *
buf_ptr = frame_buf;
99 while (rem_size > 0) {
100 uint32_t obu_size;
103 int num_lebs;
104
108 break;
109 }
111 break;
112 }
113 rem_size--;
114 // read out explicit OBU size
116 if (!num_lebs) {
117 break;
118 }
119 buf_ptr += num_lebs + obu_size;
120 rem_size -= num_lebs + obu_size;
121 }
122 #else // RTPENC_AV1_SEARCH_SEQ_HEADER
125 #endif // RTPENC_AV1_SEARCH_SEQ_HEADER
126 }
128 pkt_ptr = rtp_ctx->
buf + 1;
129
130 #ifdef RTPENC_AV1_VERBOSE_TRACE
134 #endif
135
137 uint32_t obu_size;
138 int num_lebs = 0;
139 int ext_byte = -1;
140
141 uint8_t obu_hdr = *obu_ptr++;
144
147 return;
148 }
149
153 return;
154 }
155 ext_byte = *obu_ptr++;
157 }
158
161 // read out explicit OBU size
163 if (!num_lebs) {
164 return;
165 }
166 obu_ptr += num_lebs;
168 } else {
170 return;
171 }
172
175 return;
176 }
177
178 if (obu_size > 0xfffffffd) {
180 return;
181 }
182
184
188 // ignore and remove according to spec (note that OBU_PADDING is not
189 // mentioned in spec, but it does not make sense to transmit it).
190 obu_ptr += obu_size;
191 // additional handling if the ignored OBU was the last one
193 // we're done, flush the last packet, set RTP marker bit
194 last_packet_of_frame = 1;
195 goto flush_last_packet;
196 }
197 continue;
198 }
199
200 /* if the last OBU had a temporal or spatial ID, they need to match to
201 * current; otherwise start new packet */
202 if ((last_obu_ext >= 0) && (curr_obu_ext != last_obu_ext)) {
203 start_new_packet = 1;
204 }
205
206 flush_last_packet:
207 last_obu_ptr = curr_obu_ptr;
208 last_elem_size = curr_elem_size;
209 last_obu_hdr = curr_obu_hdr;
210 last_obu_ext = curr_obu_ext;
211
212 curr_obu_ptr = obu_ptr; // behind header
213 curr_elem_size = obu_size + 1 + ((ext_byte >= 0) ? 1 : 0);
214 curr_obu_hdr = obu_hdr;
215 curr_obu_ext = ext_byte;
216
217 obu_ptr += obu_size;
218
219 if (last_obu_ptr) {
220 unsigned int first_elem_with_size = last_elem_size +
calc_leb_size(last_elem_size);
221 // check if last packet fits completely and has reasonable space for
222 // at least a fragment of the next
223 if (!last_packet_of_frame && (first_elem_with_size + 10 < rem_pkt_size)) {
224 num_lebs =
write_leb(pkt_ptr, last_elem_size);
225 pkt_ptr += num_lebs;
226 rem_pkt_size -= num_lebs;
227 } else {
228 if ((num_obus >= 3) && (last_packet_of_frame || (first_elem_with_size <= rem_pkt_size))) {
229 // last fits with forced size, but nothing else
230 num_lebs =
write_leb(pkt_ptr, last_elem_size);
231 pkt_ptr += num_lebs;
232 rem_pkt_size -= num_lebs;
233 }
234 // force new packet
235 start_new_packet = 1;
236 }
237
238 // write header and optional extension byte (if not a continued fragment)
239 if (last_obu_hdr >= 0) {
240 *pkt_ptr++ = last_obu_hdr;
241 last_elem_size--;
242 rem_pkt_size--;
243 if (last_obu_ext >= 0) {
244 *pkt_ptr++ = last_obu_ext;
245 last_elem_size--;
246 rem_pkt_size--;
247 }
248 }
249 // copy payload
250 memcpy(pkt_ptr, last_obu_ptr, last_elem_size);
251 pkt_ptr += last_elem_size;
252 rem_pkt_size -= last_elem_size;
253 num_obus++;
254 }
255
256 if (start_new_packet || last_packet_of_frame) {
257 if (num_obus < 4) {
259 }
260 rtp_ctx->
buf[0] = aggr_hdr;
261
262 #ifdef RTPENC_AV1_VERBOSE_TRACE
269 #endif
270
272
274 pkt_ptr = rtp_ctx->
buf + 1;
275 aggr_hdr = 0;
276 num_obus = 0;
277 }
278
279 if (last_packet_of_frame) {
280 break;
281 }
282
283 // check if element needs to be fragmented, otherwise we will deal with
284 // it in the next iteration
285 if ((curr_elem_size > rem_pkt_size) ||
286 ((num_obus >= 3) && (curr_elem_size +
calc_leb_size(curr_elem_size)) > rem_pkt_size)) {
287 uint32_t frag_size = rem_pkt_size;
288
289 // if there are going more than 3 OBU elements, we are obliged to
290 // have the length field for the last
291 if (num_obus >= 3) {
292 // that's an upper limit of LEBs
294 frag_size -= num_lebs;
295
296 // write a fixed number of LEBs, in case the frag_size could
297 // now be specified with one less byte
299 pkt_ptr += num_lebs;
300 rem_pkt_size -= num_lebs;
301 }
302
303 // write header and optional extension byte
304 *pkt_ptr++ = curr_obu_hdr;
305 curr_elem_size--;
306 rem_pkt_size--;
307 if (curr_obu_ext >= 0) {
308 *pkt_ptr++ = curr_obu_ext;
309 curr_elem_size--;
310 rem_pkt_size--;
311 }
312
313 // disable header writing for final fragment
314 curr_obu_hdr = -1;
315 curr_obu_ext = -1;
316
317 // send more full packet sized fragments
318 do {
319 // copy payload
320 memcpy(pkt_ptr, curr_obu_ptr, rem_pkt_size);
321 pkt_ptr += rem_pkt_size;
322 curr_obu_ptr += rem_pkt_size;
323 curr_elem_size -= rem_pkt_size;
324 num_obus++;
325
327 if (num_obus < 4) {
329 }
330 rtp_ctx->
buf[0] = aggr_hdr;
331
332 #ifdef RTPENC_AV1_VERBOSE_TRACE
339 #endif
340
343 pkt_ptr = rtp_ctx->
buf + 1;
344
346 num_obus = 0;
347 } while (curr_elem_size > rem_pkt_size);
348 start_new_packet = 0;
349 }
350
352 // we're done, flush the last packet, set RTP marker bit
353 last_packet_of_frame = 1;
354 goto flush_last_packet;
355 }
356 }
357 }