blob: 4455ec0504e2136f0b430a7d20c71ced1b565de1 [file] [log] [blame]
James Almer9888a192018-07-07 19:35:321/*
2 * AV1 helper functions for muxers
3 * Copyright (c) 2018 James Almer <[email protected]>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
Andreas Rheinhardtd4bbc0d2020-01-23 16:08:3222#include "libavutil/avassert.h"
James Almer9888a192018-07-07 19:35:3223#include "libavutil/mem.h"
24#include "libavcodec/av1.h"
25#include "libavcodec/av1_parse.h"
Andreas Rheinhardt8238bc02023-09-02 12:57:4126#include "libavcodec/defs.h"
James Almer8d5604a2018-08-16 21:01:4427#include "libavcodec/put_bits.h"
James Almer9888a192018-07-07 19:35:3228#include "av1.h"
29#include "avio.h"
Andreas Rheinhardt27c6c922019-11-21 06:17:1930#include "avio_internal.h"
James Almer9888a192018-07-07 19:35:3231
Andreas Rheinhardta3e43e02020-01-24 22:48:3332static int av1_filter_obus(AVIOContext *pb, const uint8_t *buf,
33 int size, int *offset)
James Almer9888a192018-07-07 19:35:3234{
Andreas Rheinhardta3e43e02020-01-24 22:48:3335 const uint8_t *start = buf, *end = buf + size;
James Almer7a4840a2022-02-26 23:43:5936 int off;
Andreas Rheinhardta3e43e02020-01-24 22:48:3337 enum {
38 START_NOT_FOUND,
39 START_FOUND,
40 END_FOUND,
41 OFFSET_IMPOSSIBLE,
42 } state = START_NOT_FOUND;
James Almer9888a192018-07-07 19:35:3243
Andreas Rheinhardta3e43e02020-01-24 22:48:3344 off = size = 0;
James Almer9888a192018-07-07 19:35:3245 while (buf < end) {
James Almer7a4840a2022-02-26 23:43:5946 int64_t obu_size;
47 int start_pos, type, temporal_id, spatial_id;
James Almer692e3232018-07-30 18:14:2448 int len = parse_obu_header(buf, end - buf, &obu_size, &start_pos,
James Almer9888a192018-07-07 19:35:3249 &type, &temporal_id, &spatial_id);
James Almer692e3232018-07-30 18:14:2450 if (len < 0)
51 return len;
James Almer9888a192018-07-07 19:35:3252
53 switch (type) {
54 case AV1_OBU_TEMPORAL_DELIMITER:
55 case AV1_OBU_REDUNDANT_FRAME_HEADER:
James Almerf00964e2018-08-17 18:26:0556 case AV1_OBU_TILE_LIST:
James Almer9888a192018-07-07 19:35:3257 case AV1_OBU_PADDING:
Andreas Rheinhardta3e43e02020-01-24 22:48:3358 if (state == START_FOUND)
59 state = END_FOUND;
James Almer9888a192018-07-07 19:35:3260 break;
61 default:
Andreas Rheinhardta3e43e02020-01-24 22:48:3362 if (state == START_NOT_FOUND) {
63 off = buf - start;
64 state = START_FOUND;
65 } else if (state == END_FOUND) {
66 state = OFFSET_IMPOSSIBLE;
67 }
Andreas Rheinhardtd4bbc0d2020-01-23 16:08:3268 if (pb)
69 avio_write(pb, buf, len);
James Almer692e3232018-07-30 18:14:2470 size += len;
James Almer9888a192018-07-07 19:35:3271 break;
72 }
James Almer692e3232018-07-30 18:14:2473 buf += len;
James Almer9888a192018-07-07 19:35:3274 }
75
Andreas Rheinhardta3e43e02020-01-24 22:48:3376 if (offset)
77 *offset = state != OFFSET_IMPOSSIBLE ? off : -1;
78
James Almer9888a192018-07-07 19:35:3279 return size;
80}
81
Andreas Rheinhardta3e43e02020-01-24 22:48:3382int ff_av1_filter_obus(AVIOContext *pb, const uint8_t *buf, int size)
83{
84 return av1_filter_obus(pb, buf, size, NULL);
85}
86
87int ff_av1_filter_obus_buf(const uint8_t *in, uint8_t **out,
88 int *size, int *offset)
James Almer9888a192018-07-07 19:35:3289{
Andreas Rheinhardt45bfe8b2021-08-04 14:52:0790 FFIOContext pb;
Andreas Rheinhardtd4bbc0d2020-01-23 16:08:3291 uint8_t *buf;
Andreas Rheinhardta3e43e02020-01-24 22:48:3392 int len, off, ret;
James Almer9888a192018-07-07 19:35:3293
Andreas Rheinhardta3e43e02020-01-24 22:48:3394 len = ret = av1_filter_obus(NULL, in, *size, &off);
Andreas Rheinhardt27c6c922019-11-21 06:17:1995 if (ret < 0) {
James Almer9888a192018-07-07 19:35:3296 return ret;
Andreas Rheinhardt27c6c922019-11-21 06:17:1997 }
Andreas Rheinhardta3e43e02020-01-24 22:48:3398 if (off >= 0) {
99 *out = (uint8_t *)in;
100 *size = len;
101 *offset = off;
102
103 return 0;
104 }
James Almer9888a192018-07-07 19:35:32105
Andreas Rheinhardtd4bbc0d2020-01-23 16:08:32106 buf = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE);
107 if (!buf)
108 return AVERROR(ENOMEM);
109
110 ffio_init_context(&pb, buf, len, 1, NULL, NULL, NULL, NULL);
111
Andreas Rheinhardt45bfe8b2021-08-04 14:52:07112 ret = av1_filter_obus(&pb.pub, in, *size, NULL);
Andreas Rheinhardtd4bbc0d2020-01-23 16:08:32113 av_assert1(ret == len);
114
115 memset(buf + len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
116
Andreas Rheinhardtd4bbc0d2020-01-23 16:08:32117 *out = buf;
118 *size = len;
Andreas Rheinhardta3e43e02020-01-24 22:48:33119 *offset = 0;
James Almer9888a192018-07-07 19:35:32120
Andreas Rheinhardt22ec35a2020-01-23 16:08:30121 return 0;
James Almer9888a192018-07-07 19:35:32122}
123
James Almer8d5604a2018-08-16 21:01:44124static inline void uvlc(GetBitContext *gb)
125{
126 int leading_zeros = 0;
127
128 while (get_bits_left(gb)) {
129 if (get_bits1(gb))
130 break;
131 leading_zeros++;
132 }
133
134 if (leading_zeros >= 32)
135 return;
136
137 skip_bits_long(gb, leading_zeros);
138}
139
140static int parse_color_config(AV1SequenceParameters *seq_params, GetBitContext *gb)
141{
James Almer9a44ec92019-07-30 14:55:26142 int twelve_bit = 0;
143 int high_bitdepth = get_bits1(gb);
Andreas Rheinhardt8238bc02023-09-02 12:57:41144 if (seq_params->profile == AV_PROFILE_AV1_PROFESSIONAL && high_bitdepth)
James Almer9a44ec92019-07-30 14:55:26145 twelve_bit = get_bits1(gb);
146
147 seq_params->bitdepth = 8 + (high_bitdepth * 2) + (twelve_bit * 2);
James Almer8d5604a2018-08-16 21:01:44148
Andreas Rheinhardt8238bc02023-09-02 12:57:41149 if (seq_params->profile == AV_PROFILE_AV1_HIGH)
James Almer8d5604a2018-08-16 21:01:44150 seq_params->monochrome = 0;
151 else
152 seq_params->monochrome = get_bits1(gb);
153
James Almer0c7cfd22019-07-30 14:43:02154 seq_params->color_description_present_flag = get_bits1(gb);
155 if (seq_params->color_description_present_flag) {
156 seq_params->color_primaries = get_bits(gb, 8);
157 seq_params->transfer_characteristics = get_bits(gb, 8);
158 seq_params->matrix_coefficients = get_bits(gb, 8);
James Almer8d5604a2018-08-16 21:01:44159 } else {
James Almer0c7cfd22019-07-30 14:43:02160 seq_params->color_primaries = AVCOL_PRI_UNSPECIFIED;
161 seq_params->transfer_characteristics = AVCOL_TRC_UNSPECIFIED;
162 seq_params->matrix_coefficients = AVCOL_SPC_UNSPECIFIED;
James Almer8d5604a2018-08-16 21:01:44163 }
164
165 if (seq_params->monochrome) {
James Almer0c7cfd22019-07-30 14:43:02166 seq_params->color_range = get_bits1(gb);
James Almer8d5604a2018-08-16 21:01:44167 seq_params->chroma_subsampling_x = 1;
168 seq_params->chroma_subsampling_y = 1;
169 seq_params->chroma_sample_position = 0;
170 return 0;
James Almer0c7cfd22019-07-30 14:43:02171 } else if (seq_params->color_primaries == AVCOL_PRI_BT709 &&
172 seq_params->transfer_characteristics == AVCOL_TRC_IEC61966_2_1 &&
173 seq_params->matrix_coefficients == AVCOL_SPC_RGB) {
James Almer8d5604a2018-08-16 21:01:44174 seq_params->chroma_subsampling_x = 0;
175 seq_params->chroma_subsampling_y = 0;
176 } else {
James Almer0c7cfd22019-07-30 14:43:02177 seq_params->color_range = get_bits1(gb);
James Almer8d5604a2018-08-16 21:01:44178
Andreas Rheinhardt8238bc02023-09-02 12:57:41179 if (seq_params->profile == AV_PROFILE_AV1_MAIN) {
James Almer8d5604a2018-08-16 21:01:44180 seq_params->chroma_subsampling_x = 1;
181 seq_params->chroma_subsampling_y = 1;
Andreas Rheinhardt8238bc02023-09-02 12:57:41182 } else if (seq_params->profile == AV_PROFILE_AV1_HIGH) {
James Almer8d5604a2018-08-16 21:01:44183 seq_params->chroma_subsampling_x = 0;
184 seq_params->chroma_subsampling_y = 0;
185 } else {
James Almer9a44ec92019-07-30 14:55:26186 if (twelve_bit) {
James Almer8d5604a2018-08-16 21:01:44187 seq_params->chroma_subsampling_x = get_bits1(gb);
188 if (seq_params->chroma_subsampling_x)
189 seq_params->chroma_subsampling_y = get_bits1(gb);
190 else
191 seq_params->chroma_subsampling_y = 0;
192 } else {
193 seq_params->chroma_subsampling_x = 1;
194 seq_params->chroma_subsampling_y = 0;
195 }
196 }
197 if (seq_params->chroma_subsampling_x && seq_params->chroma_subsampling_y)
198 seq_params->chroma_sample_position = get_bits(gb, 2);
199 }
200
201 skip_bits1(gb); // separate_uv_delta_q
202
203 return 0;
204}
205
206static int parse_sequence_header(AV1SequenceParameters *seq_params, const uint8_t *buf, int size)
207{
208 GetBitContext gb;
209 int reduced_still_picture_header;
210 int frame_width_bits_minus_1, frame_height_bits_minus_1;
211 int size_bits, ret;
212
213 size_bits = get_obu_bit_length(buf, size, AV1_OBU_SEQUENCE_HEADER);
214 if (size_bits < 0)
215 return size_bits;
216
217 ret = init_get_bits(&gb, buf, size_bits);
218 if (ret < 0)
219 return ret;
220
James Almer11cec342018-09-03 02:27:51221 memset(seq_params, 0, sizeof(*seq_params));
222
James Almer0d597a62019-07-30 14:48:38223 seq_params->profile = get_bits(&gb, 3);
James Almer8d5604a2018-08-16 21:01:44224
225 skip_bits1(&gb); // still_picture
226 reduced_still_picture_header = get_bits1(&gb);
227
228 if (reduced_still_picture_header) {
James Almer0d597a62019-07-30 14:48:38229 seq_params->level = get_bits(&gb, 5);
230 seq_params->tier = 0;
James Almer8d5604a2018-08-16 21:01:44231 } else {
232 int initial_display_delay_present_flag, operating_points_cnt_minus_1;
233 int decoder_model_info_present_flag, buffer_delay_length_minus_1;
234
235 if (get_bits1(&gb)) { // timing_info_present_flag
236 skip_bits_long(&gb, 32); // num_units_in_display_tick
237 skip_bits_long(&gb, 32); // time_scale
238
239 if (get_bits1(&gb)) // equal_picture_interval
240 uvlc(&gb); // num_ticks_per_picture_minus_1
241
242 decoder_model_info_present_flag = get_bits1(&gb);
243 if (decoder_model_info_present_flag) {
244 buffer_delay_length_minus_1 = get_bits(&gb, 5);
245 skip_bits_long(&gb, 32); // num_units_in_decoding_tick
246 skip_bits(&gb, 10); // buffer_removal_time_length_minus_1 (5)
247 // frame_presentation_time_length_minus_1 (5)
248 }
249 } else
250 decoder_model_info_present_flag = 0;
251
252 initial_display_delay_present_flag = get_bits1(&gb);
253
254 operating_points_cnt_minus_1 = get_bits(&gb, 5);
255 for (int i = 0; i <= operating_points_cnt_minus_1; i++) {
256 int seq_level_idx, seq_tier;
257
258 skip_bits(&gb, 12); // operating_point_idc
259 seq_level_idx = get_bits(&gb, 5);
260
261 if (seq_level_idx > 7)
262 seq_tier = get_bits1(&gb);
263 else
264 seq_tier = 0;
265
266 if (decoder_model_info_present_flag) {
267 if (get_bits1(&gb)) { // decoder_model_present_for_this_op
268 skip_bits_long(&gb, buffer_delay_length_minus_1 + 1); // decoder_buffer_delay
269 skip_bits_long(&gb, buffer_delay_length_minus_1 + 1); // encoder_buffer_delay
270 skip_bits1(&gb); // low_delay_mode_flag
271 }
272 }
273
274 if (initial_display_delay_present_flag) {
275 if (get_bits1(&gb)) // initial_display_delay_present_for_this_op
276 skip_bits(&gb, 4); // initial_display_delay_minus_1
277 }
278
279 if (i == 0) {
James Almer0d597a62019-07-30 14:48:38280 seq_params->level = seq_level_idx;
281 seq_params->tier = seq_tier;
James Almer8d5604a2018-08-16 21:01:44282 }
283 }
284 }
285
286 frame_width_bits_minus_1 = get_bits(&gb, 4);
287 frame_height_bits_minus_1 = get_bits(&gb, 4);
288
289 skip_bits(&gb, frame_width_bits_minus_1 + 1); // max_frame_width_minus_1
290 skip_bits(&gb, frame_height_bits_minus_1 + 1); // max_frame_height_minus_1
291
292 if (!reduced_still_picture_header) {
293 if (get_bits1(&gb)) // frame_id_numbers_present_flag
294 skip_bits(&gb, 7); // delta_frame_id_length_minus_2 (4), additional_frame_id_length_minus_1 (3)
295 }
296
297 skip_bits(&gb, 3); // use_128x128_superblock (1), enable_filter_intra (1), enable_intra_edge_filter (1)
298
299 if (!reduced_still_picture_header) {
300 int enable_order_hint, seq_force_screen_content_tools;
301
Fei Wang5fc30992019-12-11 01:54:54302 skip_bits(&gb, 4); // enable_interintra_compound (1), enable_masked_compound (1)
James Almer8d5604a2018-08-16 21:01:44303 // enable_warped_motion (1), enable_dual_filter (1)
304
305 enable_order_hint = get_bits1(&gb);
306 if (enable_order_hint)
307 skip_bits(&gb, 2); // enable_jnt_comp (1), enable_ref_frame_mvs (1)
308
309 if (get_bits1(&gb)) // seq_choose_screen_content_tools
310 seq_force_screen_content_tools = 2;
311 else
312 seq_force_screen_content_tools = get_bits1(&gb);
313
314 if (seq_force_screen_content_tools) {
315 if (!get_bits1(&gb)) // seq_choose_integer_mv
316 skip_bits1(&gb); // seq_force_integer_mv
317 }
318
319 if (enable_order_hint)
320 skip_bits(&gb, 3); // order_hint_bits_minus_1
321 }
322
323 skip_bits(&gb, 3); // enable_superres (1), enable_cdef (1), enable_restoration (1)
324
325 parse_color_config(seq_params, &gb);
326
327 skip_bits1(&gb); // film_grain_params_present
328
329 if (get_bits_left(&gb))
330 return AVERROR_INVALIDDATA;
331
332 return 0;
333}
334
James Almer68e48e52019-07-30 15:08:44335int ff_av1_parse_seq_header(AV1SequenceParameters *seq, const uint8_t *buf, int size)
336{
James Almer76e10322022-02-26 23:30:45337 int is_av1c;
James Almer68e48e52019-07-30 15:08:44338
339 if (size <= 0)
340 return AVERROR_INVALIDDATA;
341
James Almer76e10322022-02-26 23:30:45342 is_av1c = !!(buf[0] & 0x80);
343 if (is_av1c) {
344 GetBitContext gb;
345 int ret, version = buf[0] & 0x7F;
346
347 if (version != 1 || size < 4)
348 return AVERROR_INVALIDDATA;
349
350 ret = init_get_bits8(&gb, buf, 4);
351 if (ret < 0)
352 return ret;
353
354 memset(seq, 0, sizeof(*seq));
355
356 skip_bits(&gb, 8);
357 seq->profile = get_bits(&gb, 3);
358 seq->level = get_bits(&gb, 5);
359 seq->tier = get_bits(&gb, 1);
360 seq->bitdepth = get_bits(&gb, 1) * 2 + 8;
361 seq->bitdepth += get_bits(&gb, 1) * 2;
362 seq->monochrome = get_bits(&gb, 1);
363 seq->chroma_subsampling_x = get_bits(&gb, 1);
364 seq->chroma_subsampling_y = get_bits(&gb, 1);
365 seq->chroma_sample_position = get_bits(&gb, 2);
366 seq->color_primaries = AVCOL_PRI_UNSPECIFIED;
367 seq->transfer_characteristics = AVCOL_TRC_UNSPECIFIED;
368 seq->matrix_coefficients = AVCOL_SPC_UNSPECIFIED;
369
370 size -= 4;
371 buf += 4;
372 }
373
James Almer68e48e52019-07-30 15:08:44374 while (size > 0) {
James Almer7a4840a2022-02-26 23:43:59375 int64_t obu_size;
376 int start_pos, type, temporal_id, spatial_id;
James Almer68e48e52019-07-30 15:08:44377 int len = parse_obu_header(buf, size, &obu_size, &start_pos,
378 &type, &temporal_id, &spatial_id);
379 if (len < 0)
380 return len;
381
382 switch (type) {
383 case AV1_OBU_SEQUENCE_HEADER:
384 if (!obu_size)
385 return AVERROR_INVALIDDATA;
386
387 return parse_sequence_header(seq, buf + start_pos, obu_size);
388 default:
389 break;
390 }
391 size -= len;
392 buf += len;
393 }
394
James Almer76e10322022-02-26 23:30:45395 return is_av1c ? 0 : AVERROR_INVALIDDATA;
James Almer68e48e52019-07-30 15:08:44396}
397
Vignesh Venkatasubramanian98ec4262022-05-02 21:36:28398int ff_isom_write_av1c(AVIOContext *pb, const uint8_t *buf, int size,
399 int write_seq_header)
James Almer9888a192018-07-07 19:35:32400{
Andreas Rheinhardt36fa84e2020-06-21 10:58:21401 AVIOContext *meta_pb;
James Almer8d5604a2018-08-16 21:01:44402 AV1SequenceParameters seq_params;
403 PutBitContext pbc;
Andreas Rheinhardt36fa84e2020-06-21 10:58:21404 uint8_t header[4], *meta;
405 const uint8_t *seq;
James Almerded339f2018-07-30 18:15:43406 int ret, nb_seq = 0, seq_size, meta_size;
James Almer9888a192018-07-07 19:35:32407
James Almer1e126562018-07-23 16:15:06408 if (size <= 0)
409 return AVERROR_INVALIDDATA;
410
Jan Ekström46880172020-11-23 16:00:44411 if (buf[0] & 0x80) {
412 // first bit is nonzero, the passed data does not consist purely of
413 // OBUs. Expect that the data is already in AV1CodecConfigurationRecord
414 // format.
415 int config_record_version = buf[0] & 0x7f;
416 if (config_record_version != 1 || size < 4) {
417 return AVERROR_INVALIDDATA;
418 }
419
420 avio_write(pb, buf, size);
421
422 return 0;
423 }
424
James Almerded339f2018-07-30 18:15:43425 ret = avio_open_dyn_buf(&meta_pb);
426 if (ret < 0)
Andreas Rheinhardt36fa84e2020-06-21 10:58:21427 return ret;
James Almerded339f2018-07-30 18:15:43428
James Almer9888a192018-07-07 19:35:32429 while (size > 0) {
James Almer7a4840a2022-02-26 23:43:59430 int64_t obu_size;
431 int start_pos, type, temporal_id, spatial_id;
James Almer692e3232018-07-30 18:14:24432 int len = parse_obu_header(buf, size, &obu_size, &start_pos,
James Almer9888a192018-07-07 19:35:32433 &type, &temporal_id, &spatial_id);
James Almerded339f2018-07-30 18:15:43434 if (len < 0) {
435 ret = len;
436 goto fail;
437 }
James Almer9888a192018-07-07 19:35:32438
439 switch (type) {
440 case AV1_OBU_SEQUENCE_HEADER:
James Almerded339f2018-07-30 18:15:43441 nb_seq++;
442 if (!obu_size || nb_seq > 1) {
443 ret = AVERROR_INVALIDDATA;
444 goto fail;
445 }
James Almer8d5604a2018-08-16 21:01:44446 ret = parse_sequence_header(&seq_params, buf + start_pos, obu_size);
447 if (ret < 0)
448 goto fail;
449
Andreas Rheinhardt36fa84e2020-06-21 10:58:21450 seq = buf;
451 seq_size = len;
James Almerded339f2018-07-30 18:15:43452 break;
James Almer9888a192018-07-07 19:35:32453 case AV1_OBU_METADATA:
James Almerded339f2018-07-30 18:15:43454 if (!obu_size) {
455 ret = AVERROR_INVALIDDATA;
456 goto fail;
457 }
458 avio_write(meta_pb, buf, len);
James Almer9888a192018-07-07 19:35:32459 break;
460 default:
461 break;
462 }
James Almer692e3232018-07-30 18:14:24463 size -= len;
464 buf += len;
James Almer9888a192018-07-07 19:35:32465 }
466
Andreas Rheinhardt36fa84e2020-06-21 10:58:21467 if (!nb_seq) {
James Almerded339f2018-07-30 18:15:43468 ret = AVERROR_INVALIDDATA;
469 goto fail;
470 }
James Almer8d5604a2018-08-16 21:01:44471
472 init_put_bits(&pbc, header, sizeof(header));
473
474 put_bits(&pbc, 1, 1); // marker
475 put_bits(&pbc, 7, 1); // version
James Almer0d597a62019-07-30 14:48:38476 put_bits(&pbc, 3, seq_params.profile);
477 put_bits(&pbc, 5, seq_params.level);
478 put_bits(&pbc, 1, seq_params.tier);
James Almer9a44ec92019-07-30 14:55:26479 put_bits(&pbc, 1, seq_params.bitdepth > 8);
480 put_bits(&pbc, 1, seq_params.bitdepth == 12);
James Almer8d5604a2018-08-16 21:01:44481 put_bits(&pbc, 1, seq_params.monochrome);
482 put_bits(&pbc, 1, seq_params.chroma_subsampling_x);
483 put_bits(&pbc, 1, seq_params.chroma_subsampling_y);
484 put_bits(&pbc, 2, seq_params.chroma_sample_position);
Jeremy Dorfman via ffmpeg-develbb5efd12019-04-08 12:14:27485 put_bits(&pbc, 8, 0); // padding
James Almer8d5604a2018-08-16 21:01:44486 flush_put_bits(&pbc);
487
488 avio_write(pb, header, sizeof(header));
Vignesh Venkatasubramanian98ec4262022-05-02 21:36:28489 if (write_seq_header) {
490 avio_write(pb, seq, seq_size);
491 }
James Almerded339f2018-07-30 18:15:43492
Andreas Rheinhardta31f68f2019-11-27 12:22:07493 meta_size = avio_get_dyn_buf(meta_pb, &meta);
James Almerded339f2018-07-30 18:15:43494 if (meta_size)
495 avio_write(pb, meta, meta_size);
496
497fail:
Andreas Rheinhardta31f68f2019-11-27 12:22:07498 ffio_free_dyn_buf(&meta_pb);
James Almerded339f2018-07-30 18:15:43499
500 return ret;
James Almer9888a192018-07-07 19:35:32501}