FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/cbs_apv.c
Date: 2025-05-09 06:10:30
Exec Total Coverage
Lines: 113 173 65.3%
Functions: 7 7 100.0%
Branches: 41 82 50.0%

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 "libavutil/mem.h"
20 #include "cbs.h"
21 #include "cbs_internal.h"
22 #include "cbs_apv.h"
23
24
25 17 static int cbs_apv_get_num_comp(const APVRawFrameHeader *fh)
26 {
27
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17 switch (fh->frame_info.chroma_format_idc) {
28 case APV_CHROMA_FORMAT_400:
29 return 1;
30 17 case APV_CHROMA_FORMAT_422:
31 case APV_CHROMA_FORMAT_444:
32 17 return 3;
33 case APV_CHROMA_FORMAT_4444:
34 return 4;
35 default:
36 av_assert0(0 && "Invalid chroma_format_idc");
37 }
38 }
39
40 17 static void cbs_apv_derive_tile_info(APVDerivedTileInfo *ti,
41 const APVRawFrameHeader *fh)
42 {
43 17 int frame_width_in_mbs = (fh->frame_info.frame_width + 15) / 16;
44 17 int frame_height_in_mbs = (fh->frame_info.frame_height + 15) / 16;
45 int start_mb, i;
46
47 17 start_mb = 0;
48
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 17 times.
51 for (i = 0; start_mb < frame_width_in_mbs; i++) {
49 34 ti->col_starts[i] = start_mb * APV_MB_WIDTH;
50 34 start_mb += fh->tile_info.tile_width_in_mbs;
51 }
52
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 av_assert0(i <= APV_MAX_TILE_COLS);
53 17 ti->col_starts[i] = frame_width_in_mbs * APV_MB_WIDTH;
54 17 ti->tile_cols = i;
55
56 17 start_mb = 0;
57
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 17 times.
34 for (i = 0; start_mb < frame_height_in_mbs; i++) {
58
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 av_assert0(i < APV_MAX_TILE_ROWS);
59 17 ti->row_starts[i] = start_mb * APV_MB_HEIGHT;
60 17 start_mb += fh->tile_info.tile_height_in_mbs;
61 }
62
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 av_assert0(i <= APV_MAX_TILE_ROWS);
63 17 ti->row_starts[i] = frame_height_in_mbs * APV_MB_HEIGHT;
64 17 ti->tile_rows = i;
65
66 17 ti->num_tiles = ti->tile_cols * ti->tile_rows;
67 17 }
68
69
70 #define HEADER(name) do { \
71 ff_cbs_trace_header(ctx, name); \
72 } while (0)
73
74 #define CHECK(call) do { \
75 err = (call); \
76 if (err < 0) \
77 return err; \
78 } while (0)
79
80 #define SUBSCRIPTS(subs, ...) (subs > 0 ? ((int[subs + 1]){ subs, __VA_ARGS__ }) : NULL)
81
82
83 #define u(width, name, range_min, range_max) \
84 xu(width, name, current->name, range_min, range_max, 0, )
85 #define ub(width, name) \
86 xu(width, name, current->name, 0, MAX_UINT_BITS(width), 0, )
87 #define us(width, name, range_min, range_max, subs, ...) \
88 xu(width, name, current->name, range_min, range_max, subs, __VA_ARGS__)
89 #define ubs(width, name, subs, ...) \
90 xu(width, name, current->name, 0, MAX_UINT_BITS(width), subs, __VA_ARGS__)
91
92 #define fixed(width, name, value) do { \
93 av_unused uint32_t fixed_value = value; \
94 xu(width, name, fixed_value, value, value, 0, ); \
95 } while (0)
96
97
98 #define READ
99 #define READWRITE read
100 #define RWContext GetBitContext
101 #define FUNC(name) cbs_apv_read_ ## name
102
103 #define xu(width, name, var, range_min, range_max, subs, ...) do { \
104 uint32_t value; \
105 CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \
106 SUBSCRIPTS(subs, __VA_ARGS__), \
107 &value, range_min, range_max)); \
108 var = value; \
109 } while (0)
110
111 #define infer(name, value) do { \
112 current->name = value; \
113 } while (0)
114
115 #define byte_alignment(rw) (get_bits_count(rw) % 8)
116
117 #include "cbs_apv_syntax_template.c"
118
119 #undef READ
120 #undef READWRITE
121 #undef RWContext
122 #undef FUNC
123 #undef xu
124 #undef infer
125 #undef byte_alignment
126
127 #define WRITE
128 #define READWRITE write
129 #define RWContext PutBitContext
130 #define FUNC(name) cbs_apv_write_ ## name
131
132 #define xu(width, name, var, range_min, range_max, subs, ...) do { \
133 uint32_t value = var; \
134 CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \
135 SUBSCRIPTS(subs, __VA_ARGS__), \
136 value, range_min, range_max)); \
137 } while (0)
138
139 #define infer(name, value) do { \
140 if (current->name != (value)) { \
141 av_log(ctx->log_ctx, AV_LOG_ERROR, \
142 "%s does not match inferred value: " \
143 "%"PRId64", but should be %"PRId64".\n", \
144 #name, (int64_t)current->name, (int64_t)(value)); \
145 return AVERROR_INVALIDDATA; \
146 } \
147 } while (0)
148
149 #define byte_alignment(rw) (put_bits_count(rw) % 8)
150
151 #include "cbs_apv_syntax_template.c"
152
153 #undef WRITE
154 #undef READWRITE
155 #undef RWContext
156 #undef FUNC
157 #undef xu
158 #undef infer
159 #undef byte_alignment
160
161
162 16 static int cbs_apv_split_fragment(CodedBitstreamContext *ctx,
163 CodedBitstreamFragment *frag,
164 int header)
165 {
166 16 uint8_t *data = frag->data;
167 16 size_t size = frag->data_size;
168 uint32_t signature;
169 int err, trace;
170
171
3/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 14 times.
16 if (header || !frag->data_size) {
172 // Ignore empty or extradata fragments.
173 2 return 0;
174 }
175
176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (frag->data_size < 4) {
177 // Too small to be a valid fragment.
178 return AVERROR_INVALIDDATA;
179 }
180
181 // Don't include parsing here in trace output.
182 14 trace = ctx->trace_enable;
183 14 ctx->trace_enable = 0;
184
185 14 signature = AV_RB32(data);
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (signature != APV_SIGNATURE) {
187 av_log(ctx->log_ctx, AV_LOG_ERROR,
188 "Invalid APV access unit: bad signature %08x.\n",
189 signature);
190 err = AVERROR_INVALIDDATA;
191 goto fail;
192 }
193 14 data += 4;
194 14 size -= 4;
195
196
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 14 times.
42 while (size > 0) {
197 GetBitContext gbc;
198 uint32_t pbu_size;
199 APVRawPBUHeader pbu_header;
200
201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (size < 8) {
202 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: "
203 "fragment too short (%"SIZE_SPECIFIER" bytes).\n",
204 size);
205 err = AVERROR_INVALIDDATA;
206 goto fail;
207 }
208
209 28 pbu_size = AV_RB32(data);
210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (pbu_size < 8) {
211 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: "
212 "pbu_size too small (%"PRIu32" bytes).\n",
213 pbu_size);
214 err = AVERROR_INVALIDDATA;
215 goto fail;
216 }
217
218 28 data += 4;
219 28 size -= 4;
220
221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (pbu_size > size) {
222 av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid PBU: "
223 "pbu_size too large (%"PRIu32" bytes).\n",
224 pbu_size);
225 err = AVERROR_INVALIDDATA;
226 goto fail;
227 }
228
229 28 init_get_bits(&gbc, data, 8 * pbu_size);
230
231 28 err = cbs_apv_read_pbu_header(ctx, &gbc, &pbu_header);
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (err < 0)
233 goto fail;
234
235 // Could select/skip frames based on type/group_id here.
236
237 28 err = ff_cbs_append_unit_data(frag, pbu_header.pbu_type,
238 data, pbu_size, frag->data_ref);
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (err < 0)
240 goto fail;
241
242 28 data += pbu_size;
243 28 size -= pbu_size;
244 }
245
246 14 err = 0;
247 14 fail:
248 14 ctx->trace_enable = trace;
249 14 return err;
250 }
251
252 22 static int cbs_apv_read_unit(CodedBitstreamContext *ctx,
253 CodedBitstreamUnit *unit)
254 {
255 GetBitContext gbc;
256 int err;
257
258 22 err = init_get_bits(&gbc, unit->data, 8 * unit->data_size);
259
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (err < 0)
260 return err;
261
262 22 err = ff_cbs_alloc_unit_content(ctx, unit);
263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 if (err < 0)
264 return err;
265
266
2/5
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
22 switch (unit->type) {
267 14 case APV_PBU_PRIMARY_FRAME:
268 case APV_PBU_NON_PRIMARY_FRAME:
269 case APV_PBU_PREVIEW_FRAME:
270 case APV_PBU_DEPTH_FRAME:
271 case APV_PBU_ALPHA_FRAME:
272 {
273 14 APVRawFrame *frame = unit->content;
274
275 14 err = cbs_apv_read_frame(ctx, &gbc, frame);
276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (err < 0)
277 return err;
278
279 // Each tile inside the frame has pointers into the unit
280 // data buffer; make a single reference here for all of
281 // them together.
282 14 frame->tile_data_ref = av_buffer_ref(unit->data_ref);
283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 if (!frame->tile_data_ref)
284 return AVERROR(ENOMEM);
285 }
286 14 break;
287 case APV_PBU_ACCESS_UNIT_INFORMATION:
288 {
289 err = cbs_apv_read_au_info(ctx, &gbc, unit->content);
290 if (err < 0)
291 return err;
292 }
293 break;
294 8 case APV_PBU_METADATA:
295 {
296 8 err = cbs_apv_read_metadata(ctx, &gbc, unit->content);
297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (err < 0)
298 return err;
299 }
300 8 break;
301 case APV_PBU_FILLER:
302 {
303 err = cbs_apv_read_filler(ctx, &gbc, unit->content);
304 if (err < 0)
305 return err;
306 }
307 break;
308 default:
309 return AVERROR(ENOSYS);
310 }
311
312 22 return 0;
313 }
314
315 6 static int cbs_apv_write_unit(CodedBitstreamContext *ctx,
316 CodedBitstreamUnit *unit,
317 PutBitContext *pbc)
318 {
319 int err;
320
321
2/5
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
6 switch (unit->type) {
322 3 case APV_PBU_PRIMARY_FRAME:
323 case APV_PBU_NON_PRIMARY_FRAME:
324 case APV_PBU_PREVIEW_FRAME:
325 case APV_PBU_DEPTH_FRAME:
326 case APV_PBU_ALPHA_FRAME:
327 {
328 3 APVRawFrame *frame = unit->content;
329
330 3 err = cbs_apv_write_frame(ctx, pbc, frame);
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (err < 0)
332 return err;
333 }
334 3 break;
335 case APV_PBU_ACCESS_UNIT_INFORMATION:
336 {
337 err = cbs_apv_write_au_info(ctx, pbc, unit->content);
338 if (err < 0)
339 return err;
340 }
341 break;
342 3 case APV_PBU_METADATA:
343 {
344 3 err = cbs_apv_write_metadata(ctx, pbc, unit->content);
345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (err < 0)
346 return err;
347 }
348 3 break;
349 case APV_PBU_FILLER:
350 {
351 err = cbs_apv_write_filler(ctx, pbc, unit->content);
352 if (err < 0)
353 return err;
354 }
355 break;
356 default:
357 return AVERROR(ENOSYS);
358 }
359
360 6 return 0;
361 }
362
363 3 static int cbs_apv_assemble_fragment(CodedBitstreamContext *ctx,
364 CodedBitstreamFragment *frag)
365 {
366 3 size_t size = 4, pos;
367
368
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 for (int i = 0; i < frag->nb_units; i++)
369 6 size += frag->units[i].data_size + 4;
370
371 3 frag->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
372
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (!frag->data_ref)
373 return AVERROR(ENOMEM);
374 3 frag->data = frag->data_ref->data;
375 3 memset(frag->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
376
377 3 AV_WB32(frag->data, APV_SIGNATURE);
378 3 pos = 4;
379
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 for (int i = 0; i < frag->nb_units; i++) {
380 6 AV_WB32(frag->data + pos, frag->units[i].data_size);
381 6 pos += 4;
382
383 6 memcpy(frag->data + pos, frag->units[i].data,
384 6 frag->units[i].data_size);
385 6 pos += frag->units[i].data_size;
386 }
387
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 av_assert0(pos == size);
388 3 frag->data_size = size;
389
390 3 return 0;
391 }
392
393
394 8 static void cbs_apv_free_metadata(AVRefStructOpaque unused, void *content)
395 {
396 8 APVRawMetadata *md = content;
397
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 av_assert0(md->pbu_header.pbu_type == APV_PBU_METADATA);
398
399
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 8 times.
24 for (int i = 0; i < md->metadata_count; i++) {
400 16 APVRawMetadataPayload *pl = &md->payloads[i];
401
402
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 switch (pl->payload_type) {
403 case APV_METADATA_MDCV:
404 case APV_METADATA_CLL:
405 case APV_METADATA_FILLER:
406 break;
407 case APV_METADATA_ITU_T_T35:
408 av_buffer_unref(&pl->itu_t_t35.data_ref);
409 break;
410 16 case APV_METADATA_USER_DEFINED:
411 16 av_buffer_unref(&pl->user_defined.data_ref);
412 16 break;
413 default:
414 av_buffer_unref(&pl->undefined.data_ref);
415 }
416 }
417 8 }
418
419 static const CodedBitstreamUnitTypeDescriptor cbs_apv_unit_types[] = {
420 {
421 .nb_unit_types = CBS_UNIT_TYPE_RANGE,
422 .unit_type.range = {
423 .start = APV_PBU_PRIMARY_FRAME,
424 .end = APV_PBU_ALPHA_FRAME,
425 },
426 .content_type = CBS_CONTENT_TYPE_INTERNAL_REFS,
427 .content_size = sizeof(APVRawFrame),
428 .type.ref = {
429 .nb_offsets = 1,
430 .offsets = { offsetof(APVRawFrame, tile_data_ref) -
431 sizeof(void*) },
432 },
433 },
434
435 CBS_UNIT_TYPE_COMPLEX(APV_PBU_METADATA, APVRawMetadata,
436 &cbs_apv_free_metadata),
437
438 CBS_UNIT_TYPE_POD(APV_PBU_ACCESS_UNIT_INFORMATION, APVRawAUInfo),
439 CBS_UNIT_TYPE_POD(APV_PBU_FILLER, APVRawFiller),
440
441 CBS_UNIT_TYPE_END_OF_LIST
442 };
443
444 const CodedBitstreamType ff_cbs_type_apv = {
445 .codec_id = AV_CODEC_ID_APV,
446
447 .priv_data_size = sizeof(CodedBitstreamAPVContext),
448
449 .unit_types = cbs_apv_unit_types,
450
451 .split_fragment = &cbs_apv_split_fragment,
452 .read_unit = &cbs_apv_read_unit,
453 .write_unit = &cbs_apv_write_unit,
454 .assemble_fragment = &cbs_apv_assemble_fragment,
455 };
456