FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/bsf/extract_extradata.c
Date: 2026-04-24 19:58:39
Exec Total Coverage
Lines: 265 342 77.5%
Functions: 13 13 100.0%
Branches: 163 236 69.1%

Line Branch Exec Source
1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <stdint.h>
20
21 #include "libavutil/log.h"
22 #include "libavutil/mem.h"
23 #include "libavutil/opt.h"
24
25 #include "av1.h"
26 #include "av1_parse.h"
27 #include "bsf.h"
28 #include "bsf_internal.h"
29 #include "bytestream.h"
30 #include "h2645_parse.h"
31 #include "h264.h"
32 #include "lcevc.h"
33 #include "lcevc_parse.h"
34 #include "startcode.h"
35 #include "vc1_common.h"
36 #include "vvc.h"
37
38 #include "hevc/hevc.h"
39
40 typedef struct ExtractExtradataContext {
41 const AVClass *class;
42
43 int (*extract)(AVBSFContext *ctx, AVPacket *pkt,
44 uint8_t **data, int *size);
45
46 /* AV1 specific fields */
47 AV1Packet av1_pkt;
48
49 /* H264/HEVC specific fields */
50 H2645Packet h2645_pkt;
51
52 /* AVOptions */
53 int remove;
54 } ExtractExtradataContext;
55
56 6590 static int val_in_array(const int *arr, size_t len, int val)
57 {
58
2/2
✓ Branch 0 taken 15305 times.
✓ Branch 1 taken 3642 times.
18947 for (size_t i = 0; i < len; i++)
59
2/2
✓ Branch 0 taken 2948 times.
✓ Branch 1 taken 12357 times.
15305 if (arr[i] == val)
60 2948 return 1;
61 3642 return 0;
62 }
63
64 8 static int metadata_is_global(const AV1OBU *obu)
65 {
66 static const int metadata_obu_types[] = {
67 AV1_METADATA_TYPE_HDR_CLL, AV1_METADATA_TYPE_HDR_MDCV,
68 };
69 GetBitContext gb;
70 int metadata_type;
71
72
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
8 if (init_get_bits(&gb, obu->data, obu->size_bits) < 0)
73 return 0;
74
75 8 metadata_type = get_leb(&gb);
76
77 8 return val_in_array(metadata_obu_types, FF_ARRAY_ELEMS(metadata_obu_types),
78 metadata_type);
79 }
80
81 219 static int obu_is_global(const AV1OBU *obu)
82 {
83 static const int extradata_obu_types[] = {
84 AV1_OBU_SEQUENCE_HEADER, AV1_OBU_METADATA,
85 };
86
87
2/2
✓ Branch 0 taken 169 times.
✓ Branch 1 taken 50 times.
219 if (!val_in_array(extradata_obu_types, FF_ARRAY_ELEMS(extradata_obu_types),
88 219 obu->type))
89 169 return 0;
90
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 8 times.
50 if (obu->type != AV1_OBU_METADATA)
91 42 return 1;
92
93 8 return metadata_is_global(obu);
94 }
95
96 44 static int extract_extradata_av1(AVBSFContext *ctx, AVPacket *pkt,
97 uint8_t **data, int *size)
98 {
99
100 44 ExtractExtradataContext *s = ctx->priv_data;
101
102 44 int extradata_size = 0, filtered_size = 0;
103 44 int i, has_seq = 0, ret = 0;
104
105 44 ret = ff_av1_packet_split(&s->av1_pkt, pkt->data, pkt->size, ctx);
106
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 if (ret < 0)
107 return ret;
108
109
2/2
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 44 times.
181 for (i = 0; i < s->av1_pkt.nb_obus; i++) {
110 137 AV1OBU *obu = &s->av1_pkt.obus[i];
111
2/2
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 112 times.
137 if (obu_is_global(obu)) {
112 25 extradata_size += obu->raw_size;
113
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 4 times.
25 if (obu->type == AV1_OBU_SEQUENCE_HEADER)
114 21 has_seq = 1;
115 } else {
116 112 filtered_size += obu->raw_size;
117 }
118 }
119
120
3/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
44 if (extradata_size && has_seq) {
121 21 AVBufferRef *filtered_buf = NULL;
122 PutByteContext pb_filtered_data, pb_extradata;
123 uint8_t *extradata;
124
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (s->remove) {
126 filtered_buf = av_buffer_alloc(filtered_size + AV_INPUT_BUFFER_PADDING_SIZE);
127 if (!filtered_buf) {
128 return AVERROR(ENOMEM);
129 }
130 memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
131 }
132
133 21 extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (!extradata) {
135 av_buffer_unref(&filtered_buf);
136 return AVERROR(ENOMEM);
137 }
138
139 21 *data = extradata;
140 21 *size = extradata_size;
141
142 21 bytestream2_init_writer(&pb_extradata, extradata, extradata_size);
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (s->remove)
144 bytestream2_init_writer(&pb_filtered_data, filtered_buf->data, filtered_size);
145
146
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 21 times.
103 for (i = 0; i < s->av1_pkt.nb_obus; i++) {
147 82 AV1OBU *obu = &s->av1_pkt.obus[i];
148
2/2
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 57 times.
82 if (obu_is_global(obu)) {
149 25 bytestream2_put_bufferu(&pb_extradata, obu->raw_data, obu->raw_size);
150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 } else if (s->remove) {
151 bytestream2_put_bufferu(&pb_filtered_data, obu->raw_data, obu->raw_size);
152 }
153 }
154
155
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if (s->remove) {
156 av_buffer_unref(&pkt->buf);
157 pkt->buf = filtered_buf;
158 pkt->data = filtered_buf->data;
159 pkt->size = filtered_size;
160 }
161 }
162
163 44 return 0;
164 }
165
166 588 static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt,
167 uint8_t **data, int *size)
168 {
169 static const int extradata_nal_types_vvc[] = {
170 VVC_VPS_NUT, VVC_SPS_NUT, VVC_PPS_NUT,
171 };
172 static const int extradata_nal_types_hevc[] = {
173 HEVC_NAL_VPS, HEVC_NAL_SPS, HEVC_NAL_PPS,
174 };
175 static const int extradata_nal_types_h264[] = {
176 H264_NAL_SPS, H264_NAL_PPS,
177 };
178
179 588 ExtractExtradataContext *s = ctx->priv_data;
180
181 588 int extradata_size = 0, filtered_size = 0;
182 const int *extradata_nal_types;
183 size_t nb_extradata_nal_types;
184 588 int filtered_nb_nals = 0;
185 588 int i, has_sps = 0, has_vps = 0, ret = 0;
186
187
2/2
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 523 times.
588 if (ctx->par_in->codec_id == AV_CODEC_ID_VVC) {
188 65 extradata_nal_types = extradata_nal_types_vvc;
189 65 nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_vvc);
190
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 272 times.
523 } else if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) {
191 251 extradata_nal_types = extradata_nal_types_hevc;
192 251 nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_hevc);
193 } else {
194 272 extradata_nal_types = extradata_nal_types_h264;
195 272 nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_h264);
196 }
197
198 588 ret = ff_h2645_packet_split(&s->h2645_pkt, pkt->data, pkt->size,
199 588 ctx, 0, ctx->par_in->codec_id, H2645_FLAG_SMALL_PADDING);
200
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
588 if (ret < 0)
201 return ret;
202
203
2/2
✓ Branch 0 taken 3339 times.
✓ Branch 1 taken 588 times.
3927 for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
204 3339 H2645NAL *nal = &s->h2645_pkt.nals[i];
205
2/2
✓ Branch 1 taken 1439 times.
✓ Branch 2 taken 1900 times.
3339 if (val_in_array(extradata_nal_types, nb_extradata_nal_types, nal->type)) {
206 1439 extradata_size += nal->raw_size + 4;
207
2/2
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 1238 times.
1439 if (ctx->par_in->codec_id == AV_CODEC_ID_VVC) {
208
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 132 times.
201 if (nal->type == VVC_SPS_NUT) has_sps = 1;
209
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 197 times.
201 if (nal->type == VVC_VPS_NUT) has_vps = 1;
210
2/2
✓ Branch 0 taken 757 times.
✓ Branch 1 taken 481 times.
1238 } else if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) {
211
2/2
✓ Branch 0 taken 233 times.
✓ Branch 1 taken 524 times.
757 if (nal->type == HEVC_NAL_SPS) has_sps = 1;
212
2/2
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 529 times.
757 if (nal->type == HEVC_NAL_VPS) has_vps = 1;
213 } else {
214
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 245 times.
481 if (nal->type == H264_NAL_SPS) has_sps = 1;
215 }
216 } else {
217 1900 filtered_size += nal->raw_size + 3 +
218 1900 ff_h2645_unit_requires_zero_byte(ctx->par_in->codec_id, nal->type, filtered_nb_nals++);
219 }
220 }
221
222
2/2
✓ Branch 0 taken 519 times.
✓ Branch 1 taken 69 times.
588 if (extradata_size &&
223
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 454 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 65 times.
519 ((ctx->par_in->codec_id == AV_CODEC_ID_VVC && has_sps) ||
224
4/6
✓ Branch 0 taken 218 times.
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 218 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 218 times.
454 (ctx->par_in->codec_id == AV_CODEC_ID_HEVC && has_sps && has_vps) ||
225
2/4
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 236 times.
✗ Branch 3 not taken.
236 (ctx->par_in->codec_id == AV_CODEC_ID_H264 && has_sps))) {
226 519 AVBufferRef *filtered_buf = NULL;
227 PutByteContext pb_filtered_data, pb_extradata;
228 uint8_t *extradata;
229
230
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 519 times.
519 if (s->remove) {
231 filtered_buf = av_buffer_alloc(filtered_size + AV_INPUT_BUFFER_PADDING_SIZE);
232 if (!filtered_buf) {
233 return AVERROR(ENOMEM);
234 }
235 memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
236 }
237
238 519 extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 519 times.
519 if (!extradata) {
240 av_buffer_unref(&filtered_buf);
241 return AVERROR(ENOMEM);
242 }
243
244 519 *data = extradata;
245 519 *size = extradata_size;
246
247 519 bytestream2_init_writer(&pb_extradata, extradata, extradata_size);
248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 519 times.
519 if (s->remove)
249 bytestream2_init_writer(&pb_filtered_data, filtered_buf->data, filtered_size);
250
251 519 filtered_nb_nals = 0;
252
2/2
✓ Branch 0 taken 3012 times.
✓ Branch 1 taken 519 times.
3531 for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
253 3012 H2645NAL *nal = &s->h2645_pkt.nals[i];
254
2/2
✓ Branch 1 taken 1439 times.
✓ Branch 2 taken 1573 times.
3012 if (val_in_array(extradata_nal_types, nb_extradata_nal_types,
255 nal->type)) {
256 1439 bytestream2_put_be32u(&pb_extradata, 1); //startcode
257 1439 bytestream2_put_bufferu(&pb_extradata, nal->raw_data, nal->raw_size);
258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1573 times.
1573 } else if (s->remove) {
259 if (ff_h2645_unit_requires_zero_byte(ctx->par_in->codec_id, nal->type, filtered_nb_nals++))
260 bytestream2_put_byteu(&pb_filtered_data, 0); // zero_byte
261 bytestream2_put_be24u(&pb_filtered_data, 1); // startcode
262 bytestream2_put_bufferu(&pb_filtered_data, nal->raw_data, nal->raw_size);
263 }
264 }
265
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 519 times.
519 if (s->remove) {
267 av_buffer_unref(&pkt->buf);
268 pkt->buf = filtered_buf;
269 pkt->data = filtered_buf->data;
270 pkt->size = filtered_size;
271 }
272 }
273
274 588 return 0;
275 }
276
277 /**
278 * Rewrite the NALu stripping the unneeded blocks.
279 * Given that length fields coded inside the NALu are not aware of any emulation_3bytes
280 * present in the bitstream, we need to keep track of the raw buffer as we navigate
281 * the stripped buffer.
282 */
283 12 static int process_lcevc_nalu(PutByteContext *extradata, PutByteContext *data,
284 int *extradata_sizep, int *data_sizep, const H2645NAL *nal)
285 {
286 GetByteContext gbc, raw_gbc;
287 12 int sc = 0, gc = 0;
288 12 int skipped_byte_pos = 0;
289 12 int extradata_size = 0, data_size = 0;
290
291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (nal->size < 2)
292 return AVERROR_INVALIDDATA;
293
294 12 bytestream2_init(&gbc, nal->data, nal->size);
295 12 bytestream2_init(&raw_gbc, nal->raw_data, nal->raw_size);
296
297 12 unsigned nalu_header = bytestream2_get_be16u(&gbc);
298
299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (data)
300 bytestream2_put_be16u(data, nalu_header);
301 12 data_size += 2;
302 12 bytestream2_skipu(&raw_gbc, 2);
303
304
2/2
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 12 times.
84 while (bytestream2_get_bytes_left(&gbc) > 1) {
305 GetBitContext gb;
306 int payload_size_type, payload_type;
307 uint64_t payload_size;
308 int block_size, raw_block_size, block_end;
309
310 72 av_unused int ret = init_get_bits8(&gb, gbc.buffer, bytestream2_get_bytes_left(&gbc));
311 av_assert1(ret >= 0); // h2645_parse already opened a GetBitContext with this data
312
313 72 payload_size_type = get_bits(&gb, 3);
314 72 payload_type = get_bits(&gb, 5);
315 72 payload_size = payload_size_type;
316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
72 if (payload_size_type == 6)
317 return AVERROR_INVALIDDATA;
318
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
72 if (payload_size_type == 7)
319 36 payload_size = get_mb(&gb);
320
321
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
72 if (payload_size > INT_MAX - (get_bits_count(&gb) >> 3))
322 return AVERROR_INVALIDDATA;
323
324 72 block_size = raw_block_size = payload_size + (get_bits_count(&gb) >> 3);
325
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
72 if (block_size >= bytestream2_get_bytes_left(&gbc))
326 return AVERROR_INVALIDDATA;
327
328 72 block_end = bytestream2_tell(&gbc) + block_size;
329 // Take into account removed emulation 3bytes, as payload_size in
330 // the bitstream is not aware of them.
331
2/2
✓ Branch 0 taken 328 times.
✓ Branch 1 taken 24 times.
352 for (; skipped_byte_pos < nal->skipped_bytes; skipped_byte_pos++) {
332
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 280 times.
328 if (nal->skipped_bytes_pos[skipped_byte_pos] >= block_end)
333 48 break;
334 280 raw_block_size++;
335 }
336
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
72 if (raw_block_size > bytestream2_get_bytes_left(&raw_gbc))
337 return AVERROR_INVALIDDATA;
338
339
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 24 times.
72 switch (payload_type) {
340 48 case LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG:
341 case LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG:
342 case LCEVC_PAYLOAD_TYPE_ADDITIONAL_INFO:
343
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 36 times.
48 if (!extradata_size) {
344 12 extradata_size = 2;
345
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (extradata)
346 6 bytestream2_put_be16u(extradata, nalu_header);
347 }
348
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
48 if (extradata)
349 24 bytestream2_put_bufferu(extradata, raw_gbc.buffer, raw_block_size);
350 48 extradata_size += raw_block_size;
351 48 sc |= payload_type == LCEVC_PAYLOAD_TYPE_SEQUENCE_CONFIG;
352 48 gc |= payload_type == LCEVC_PAYLOAD_TYPE_GLOBAL_CONFIG;
353 48 break;
354 24 default:
355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (data)
356 bytestream2_put_bufferu(data, raw_gbc.buffer, raw_block_size);
357 24 data_size += raw_block_size;
358 24 break;
359 }
360
361 72 bytestream2_skip(&gbc, block_size);
362 72 bytestream2_skip(&raw_gbc, raw_block_size);
363 }
364
365 12 ++data_size;
366 12 *data_sizep = data_size;
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (data)
368 bytestream2_put_byteu(data, 0x80); // rbsp_alignment bits
369
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (extradata_size > 0) {
370
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
12 if (!sc && !gc)
371 return AVERROR_INVALIDDATA;
372
373 12 ++extradata_size;
374
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (extradata) {
375 6 bytestream2_put_byteu(extradata, 0x80); // rbsp_alignment bits
376 } else
377 6 *extradata_sizep = extradata_size;
378 12 return 1; // has extradata
379 }
380 return 0; // no extradata
381 }
382
383 6 static int extract_extradata_lcevc(AVBSFContext *ctx, AVPacket *pkt,
384 uint8_t **data, int *size)
385 {
386 static const int extradata_nal_types[] = {
387 LCEVC_IDR_NUT, LCEVC_NON_IDR_NUT,
388 };
389
390 6 ExtractExtradataContext *s = ctx->priv_data;
391 6 unsigned extradata_size = 0, filtered_size = 0;
392 6 size_t nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types);
393 6 int i, ret = 0;
394
395 6 ret = ff_h2645_packet_split(&s->h2645_pkt, pkt->data, pkt->size,
396 ctx, 0, AV_CODEC_ID_LCEVC, H2645_FLAG_SMALL_PADDING);
397
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (ret < 0)
398 return ret;
399
400
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
401 6 H2645NAL *nal = &s->h2645_pkt.nals[i];
402
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 unsigned start_code_size = 3 + !filtered_size;
403
404
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (val_in_array(extradata_nal_types, nb_extradata_nal_types, nal->type)) {
405 int extra_size, data_size;
406 6 ret = process_lcevc_nalu(NULL, NULL, &extra_size, &data_size, nal);
407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (ret < 0)
408 return ret;
409
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (ret > 0) { // has extradata
410
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 unsigned extra_start_code_size = 3 + !extradata_size;
411 6 extradata_size += extra_start_code_size + extra_size;
412
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (extradata_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
413 return AVERROR_INVALIDDATA;
414 }
415 6 filtered_size += start_code_size + data_size;
416 } else
417 filtered_size += start_code_size + nal->raw_size;
418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (filtered_size > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE)
419 return AVERROR_INVALIDDATA;
420 }
421
422
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (extradata_size) {
423 6 AVBufferRef *filtered_buf = NULL;
424 PutByteContext pb_extradata;
425 PutByteContext pb_filtered_data;
426 uint8_t *extradata;
427
428
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (s->remove) {
429 ret = av_buffer_realloc(&filtered_buf, filtered_size + AV_INPUT_BUFFER_PADDING_SIZE);
430 if (ret < 0)
431 return ret;
432 bytestream2_init_writer(&pb_filtered_data, filtered_buf->data, filtered_size);
433 // this is the first byte of a four-byte startcode; we write it here
434 // so that we only need to write three-byte startcodes below
435 bytestream2_put_byteu(&pb_filtered_data, 0x00);
436 }
437
438 6 extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!extradata) {
440 av_buffer_unref(&filtered_buf);
441 return AVERROR(ENOMEM);
442 }
443
444 6 *data = extradata;
445 6 *size = extradata_size;
446
447 6 bytestream2_init_writer(&pb_extradata, extradata, extradata_size);
448 // We write the startcodes before the actual units because we do not
449 // know in advance whether a given unit will contribute to extradata,
450 // but we know when we have encountered the last unit containing
451 // extradata. (The alternative is writing it and then undoing this
452 // if the NALU did not contain extradata.)
453 6 bytestream2_put_be32u(&pb_extradata, 0x00000001);
454
455
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 for (i = 0; i < s->h2645_pkt.nb_nals; i++) {
456 6 H2645NAL *nal = &s->h2645_pkt.nals[i];
457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (s->remove)
458 bytestream2_put_be24u(&pb_filtered_data, 0x000001);
459
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 if (val_in_array(extradata_nal_types, nb_extradata_nal_types,
460 nal->type)) {
461 int dummy;
462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 ret = process_lcevc_nalu(&pb_extradata, s->remove ? &pb_filtered_data : NULL,
463 NULL, &dummy, nal);
464 av_assert1(ret >= 0); // already checked in the first pass
465
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (ret > 0) {// NALU contained extradata
466
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (extradata_size != bytestream2_tell_p(&pb_extradata)) {
467 // There will be another NALU containing extradata.
468 // Already write the next start code.
469 bytestream2_put_be24u(&pb_extradata, 0x000001);
470 }
471 }
472 } else if (s->remove) {
473 bytestream2_put_bufferu(&pb_filtered_data, nal->raw_data, nal->raw_size);
474 }
475 }
476 av_assert1(bytestream2_tell_p(&pb_extradata) == extradata_size);
477
478
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (s->remove) {
479 av_assert1(bytestream2_tell_p(&pb_filtered_data) == filtered_size);
480 memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
481 av_buffer_unref(&pkt->buf);
482 pkt->buf = filtered_buf;
483 pkt->data = filtered_buf->data;
484 pkt->size = filtered_size;
485 }
486 }
487
488 6 return 0;
489 }
490
491 6 static int extract_extradata_vc1(AVBSFContext *ctx, AVPacket *pkt,
492 uint8_t **data, int *size)
493 {
494 6 ExtractExtradataContext *s = ctx->priv_data;
495 6 const uint8_t *ptr = pkt->data, *end = pkt->data + pkt->size;
496 6 uint32_t state = UINT32_MAX;
497 6 int has_extradata = 0, extradata_size = 0;
498
499
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 while (ptr < end) {
500 23 ptr = avpriv_find_start_code(ptr, end, &state);
501
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 6 times.
23 if (state == VC1_CODE_SEQHDR || state == VC1_CODE_ENTRYPOINT) {
502 17 has_extradata = 1;
503
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
6 } else if (has_extradata && IS_MARKER(state)) {
504 6 extradata_size = ptr - 4 - pkt->data;
505 6 break;
506 }
507 }
508
509
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (extradata_size) {
510 6 *data = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!*data)
512 return AVERROR(ENOMEM);
513
514 6 memcpy(*data, pkt->data, extradata_size);
515 6 *size = extradata_size;
516
517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (s->remove) {
518 pkt->data += extradata_size;
519 pkt->size -= extradata_size;
520 }
521 }
522
523 6 return 0;
524 }
525
526 470 static int extract_extradata_mpeg12(AVBSFContext *ctx, AVPacket *pkt,
527 uint8_t **data, int *size)
528 {
529 470 ExtractExtradataContext *s = ctx->priv_data;
530 470 uint32_t state = UINT32_MAX;
531 470 int i, found = 0;
532
533
2/2
✓ Branch 0 taken 4340556 times.
✓ Branch 1 taken 275 times.
4340831 for (i = 0; i < pkt->size; i++) {
534 4340556 state = (state << 8) | pkt->data[i];
535
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 4340361 times.
4340556 if (state == 0x1B3)
536 195 found = 1;
537
8/8
✓ Branch 0 taken 5857 times.
✓ Branch 1 taken 4334504 times.
✓ Branch 2 taken 5656 times.
✓ Branch 3 taken 201 times.
✓ Branch 4 taken 464 times.
✓ Branch 5 taken 5192 times.
✓ Branch 6 taken 195 times.
✓ Branch 7 taken 269 times.
4340361 else if (found && state != 0x1B5 && state < 0x200 && state >= 0x100) {
538 195 *size = i - 3;
539 195 *data = av_malloc(*size + AV_INPUT_BUFFER_PADDING_SIZE);
540
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 if (!*data)
541 return AVERROR(ENOMEM);
542
543 195 memcpy(*data, pkt->data, *size);
544
545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 if (s->remove) {
546 pkt->data += *size;
547 pkt->size -= *size;
548 }
549 195 break;
550 }
551 }
552 470 return 0;
553 }
554
555 121 static int extract_extradata_mpeg4(AVBSFContext *ctx, AVPacket *pkt,
556 uint8_t **data, int *size)
557 {
558 121 ExtractExtradataContext *s = ctx->priv_data;
559 121 const uint8_t *ptr = pkt->data, *end = pkt->data + pkt->size;
560 121 uint32_t state = UINT32_MAX;
561
562
1/2
✓ Branch 0 taken 397 times.
✗ Branch 1 not taken.
397 while (ptr < end) {
563 397 ptr = avpriv_find_start_code(ptr, end, &state);
564
4/4
✓ Branch 0 taken 325 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 276 times.
397 if (state == 0x1B3 || state == 0x1B6) {
565
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 50 times.
121 if (ptr - pkt->data > 4) {
566 71 *size = ptr - 4 - pkt->data;
567 71 *data = av_malloc(*size + AV_INPUT_BUFFER_PADDING_SIZE);
568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 if (!*data)
569 return AVERROR(ENOMEM);
570
571 71 memcpy(*data, pkt->data, *size);
572
573
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 if (s->remove) {
574 pkt->data += *size;
575 pkt->size -= *size;
576 }
577 }
578 121 break;
579 }
580 }
581 121 return 0;
582 }
583
584 static const struct {
585 enum AVCodecID id;
586 int (*extract)(AVBSFContext *ctx, AVPacket *pkt,
587 uint8_t **data, int *size);
588 } extract_tab[] = {
589 { AV_CODEC_ID_AV1, extract_extradata_av1 },
590 { AV_CODEC_ID_AVS2, extract_extradata_mpeg4 },
591 { AV_CODEC_ID_AVS3, extract_extradata_mpeg4 },
592 { AV_CODEC_ID_CAVS, extract_extradata_mpeg4 },
593 { AV_CODEC_ID_H264, extract_extradata_h2645 },
594 { AV_CODEC_ID_HEVC, extract_extradata_h2645 },
595 { AV_CODEC_ID_LCEVC, extract_extradata_lcevc },
596 { AV_CODEC_ID_MPEG1VIDEO, extract_extradata_mpeg12 },
597 { AV_CODEC_ID_MPEG2VIDEO, extract_extradata_mpeg12 },
598 { AV_CODEC_ID_MPEG4, extract_extradata_mpeg4 },
599 { AV_CODEC_ID_VC1, extract_extradata_vc1 },
600 { AV_CODEC_ID_VVC, extract_extradata_h2645 },
601 };
602
603 817 static int extract_extradata_init(AVBSFContext *ctx)
604 {
605 817 ExtractExtradataContext *s = ctx->priv_data;
606 int i;
607
608
1/2
✓ Branch 0 taken 5825 times.
✗ Branch 1 not taken.
5825 for (i = 0; i < FF_ARRAY_ELEMS(extract_tab); i++) {
609
2/2
✓ Branch 0 taken 817 times.
✓ Branch 1 taken 5008 times.
5825 if (extract_tab[i].id == ctx->par_in->codec_id) {
610 817 s->extract = extract_tab[i].extract;
611 817 break;
612 }
613 }
614
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 817 times.
817 if (!s->extract)
615 return AVERROR_BUG;
616
617 817 return 0;
618 }
619
620 1654 static int extract_extradata_filter(AVBSFContext *ctx, AVPacket *pkt)
621 {
622 1654 ExtractExtradataContext *s = ctx->priv_data;
623 1654 uint8_t *extradata = NULL;
624 int extradata_size;
625 1654 int ret = 0;
626
627 1654 ret = ff_bsf_get_packet_ref(ctx, pkt);
628
2/2
✓ Branch 0 taken 419 times.
✓ Branch 1 taken 1235 times.
1654 if (ret < 0)
629 419 return ret;
630
631 1235 ret = s->extract(ctx, pkt, &extradata, &extradata_size);
632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1235 times.
1235 if (ret < 0)
633 goto fail;
634
635
2/2
✓ Branch 0 taken 818 times.
✓ Branch 1 taken 417 times.
1235 if (extradata) {
636 818 memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
637 818 ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA,
638 extradata, extradata_size);
639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 818 times.
818 if (ret < 0) {
640 av_freep(&extradata);
641 goto fail;
642 }
643 }
644
645 1235 return 0;
646
647 fail:
648 av_packet_unref(pkt);
649 return ret;
650 }
651
652 817 static void extract_extradata_close(AVBSFContext *ctx)
653 {
654 817 ExtractExtradataContext *s = ctx->priv_data;
655 817 ff_av1_packet_uninit(&s->av1_pkt);
656 817 ff_h2645_packet_uninit(&s->h2645_pkt);
657 817 }
658
659 static const enum AVCodecID codec_ids[] = {
660 AV_CODEC_ID_AV1,
661 AV_CODEC_ID_AVS2,
662 AV_CODEC_ID_AVS3,
663 AV_CODEC_ID_CAVS,
664 AV_CODEC_ID_H264,
665 AV_CODEC_ID_HEVC,
666 AV_CODEC_ID_LCEVC,
667 AV_CODEC_ID_MPEG1VIDEO,
668 AV_CODEC_ID_MPEG2VIDEO,
669 AV_CODEC_ID_MPEG4,
670 AV_CODEC_ID_VC1,
671 AV_CODEC_ID_VVC,
672 AV_CODEC_ID_NONE,
673 };
674
675 #define OFFSET(x) offsetof(ExtractExtradataContext, x)
676 #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM)
677 static const AVOption options[] = {
678 { "remove", "remove the extradata from the bitstream", OFFSET(remove), AV_OPT_TYPE_INT,
679 { .i64 = 0 }, 0, 1, FLAGS },
680 { NULL },
681 };
682
683 static const AVClass extract_extradata_class = {
684 .class_name = "extract_extradata",
685 .item_name = av_default_item_name,
686 .option = options,
687 .version = LIBAVUTIL_VERSION_INT,
688 };
689
690 const FFBitStreamFilter ff_extract_extradata_bsf = {
691 .p.name = "extract_extradata",
692 .p.codec_ids = codec_ids,
693 .p.priv_class = &extract_extradata_class,
694 .priv_data_size = sizeof(ExtractExtradataContext),
695 .init = extract_extradata_init,
696 .filter = extract_extradata_filter,
697 .close = extract_extradata_close,
698 };
699