FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/apv_parser.c
Date: 2026-01-16 07:34:38
Exec Total Coverage
Lines: 61 99 61.6%
Functions: 4 5 80.0%
Branches: 13 40 32.5%

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/avassert.h"
20 #include "libavutil/buffer.h"
21 #include "libavutil/mem.h"
22
23 #include "avcodec.h"
24 #include "apv.h"
25 #include "cbs.h"
26 #include "cbs_apv.h"
27 #include "parser.h"
28 #include "parser_internal.h"
29
30 typedef struct APVParseContext {
31 ParseContext pc;
32
33 CodedBitstreamContext *cbc;
34 CodedBitstreamFragment au;
35 } APVParseContext;
36
37 static const enum AVPixelFormat apv_format_table[5][5] = {
38 { AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_GRAY16 },
39 { 0 }, // 4:2:0 is not valid.
40 { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV422P16 },
41 { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUV444P16 },
42 { AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_YUVA444P12, AV_PIX_FMT_GRAY14, AV_PIX_FMT_YUVA444P16 },
43 };
44
45 static int find_frame_end(APVParseContext *p, const uint8_t *buf, int buf_size)
46 {
47 ParseContext *pc = &p->pc;
48 int pic_found, i = 0;
49 uint32_t state;
50
51 pic_found = pc->frame_start_found;
52 state = pc->state;
53
54 if (buf_size == 0) {
55 pc->frame_start_found = 0;
56 pc->state = -1;
57 return 0;
58 }
59
60 if (!pic_found) {
61 for (; i < buf_size; i++) {
62 state = (state << 8) | buf[i];
63 if (state == APV_SIGNATURE) {
64 i++;
65 pic_found = 1;
66 break;
67 }
68 }
69 }
70
71 if (pic_found) {
72 for(; i < buf_size; i++) {
73 state = (state << 8) | buf[i];
74 if (state == APV_SIGNATURE) {
75 pc->frame_start_found = 0;
76 pc->state = -1;
77 return i - 3;
78 }
79 }
80 }
81
82 pc->frame_start_found = pic_found;
83 pc->state = state;
84 return END_NOT_FOUND;
85 }
86
87 18 static void dummy_free(void *opaque, uint8_t *data)
88 {
89
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 av_assert0(opaque == data);
90 18 }
91
92 24 static int parse(AVCodecParserContext *s,
93 AVCodecContext *avctx,
94 const uint8_t **poutbuf, int *poutbuf_size,
95 const uint8_t *buf, int buf_size)
96 {
97 24 APVParseContext *p = s->priv_data;
98 24 CodedBitstreamFragment *au = &p->au;
99 24 AVBufferRef *ref = NULL;
100 int next, ret;
101
102
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
103 24 next = buf_size;
104 } else {
105 next = find_frame_end(p, buf, buf_size);
106
107 if (ff_combine_frame(&p->pc, next, &buf, &buf_size) < 0) {
108 *poutbuf = NULL;
109 *poutbuf_size = 0;
110 return buf_size;
111 }
112 }
113
114 24 *poutbuf = buf;
115 24 *poutbuf_size = buf_size;
116
117
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 18 times.
24 if (!buf_size)
118 6 return 0;
119
120 18 ref = av_buffer_create((uint8_t *)buf, buf_size, dummy_free,
121 (void *)buf, AV_BUFFER_FLAG_READONLY);
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!ref)
123 return next;
124
125 18 p->cbc->log_ctx = avctx;
126
127 18 ret = ff_cbs_read(p->cbc, au, ref, buf, buf_size);
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (ret < 0) {
129 av_log(avctx, AV_LOG_ERROR, "Failed to parse access unit.\n");
130 goto end;
131 }
132
133 18 s->key_frame = 1;
134 18 s->pict_type = AV_PICTURE_TYPE_I;
135 18 s->field_order = AV_FIELD_UNKNOWN;
136 18 s->picture_structure = AV_PICTURE_STRUCTURE_FRAME;
137
138
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 for (int i = 0; i < au->nb_units; i++) {
139 18 const CodedBitstreamUnit *pbu = &au->units[i];
140
141
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 switch (pbu->type) {
142 18 case APV_PBU_PRIMARY_FRAME: {
143 18 const APVRawFrame *frame = pbu->content;
144 18 const APVRawFrameHeader *header = &frame->frame_header;
145 18 const APVRawFrameInfo *info = &header->frame_info;
146 18 int bit_depth = info->bit_depth_minus8 + 8;
147
148
3/6
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
18 if (bit_depth < 8 || bit_depth > 16 || bit_depth % 2)
149 break;
150
151 18 s->width = info->frame_width;
152 18 s->height = info->frame_height;
153 18 s->format = apv_format_table[info->chroma_format_idc][bit_depth - 4 >> 2];
154 18 avctx->profile = info->profile_idc;
155 18 avctx->level = info->level_idc;
156 18 avctx->chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
157 18 avctx->color_primaries = header->color_primaries;
158 18 avctx->color_trc = header->transfer_characteristics;
159 18 avctx->colorspace = header->matrix_coefficients;
160 36 avctx->color_range = header->full_range_flag ? AVCOL_RANGE_JPEG
161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 : AVCOL_RANGE_MPEG;
162 18 goto end;
163 }
164 default:
165 break;
166 }
167 }
168
169 end:
170 18 ff_cbs_fragment_reset(au);
171 av_assert1(av_buffer_get_ref_count(ref) == 1);
172 18 av_buffer_unref(&ref);
173 18 p->cbc->log_ctx = NULL;
174
175 18 return next;
176 }
177
178 static const CodedBitstreamUnitType decompose_unit_types[] = {
179 APV_PBU_PRIMARY_FRAME,
180 };
181
182 6 static av_cold int init(AVCodecParserContext *s)
183 {
184 6 APVParseContext *p = s->priv_data;
185 int ret;
186
187 6 ret = ff_cbs_init(&p->cbc, AV_CODEC_ID_APV, NULL);
188
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (ret < 0)
189 return ret;
190
191 6 p->cbc->decompose_unit_types = decompose_unit_types;
192 6 p->cbc->nb_decompose_unit_types = FF_ARRAY_ELEMS(decompose_unit_types);
193
194 6 return 0;
195 }
196
197 6 static av_cold void close(AVCodecParserContext *s)
198 {
199 6 APVParseContext *p = s->priv_data;
200 6 ParseContext *pc = &p->pc;
201
202 6 av_freep(&pc->buffer);
203 6 ff_cbs_fragment_free(&p->au);
204 6 ff_cbs_close(&p->cbc);
205 6 }
206
207 const FFCodecParser ff_apv_parser = {
208 PARSER_CODEC_LIST(AV_CODEC_ID_APV),
209 .priv_data_size = sizeof(APVParseContext),
210 .init = init,
211 .parse = parse,
212 .close = close,
213 };
214