FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/jpegxs_parser.c
Date: 2026-01-23 14:02:51
Exec Total Coverage
Lines: 104 139 74.8%
Functions: 4 4 100.0%
Branches: 50 105 47.6%

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
21 #include "bytestream.h"
22 #include "get_bits.h"
23 #include "jpegxs.h"
24 #include "parser.h"
25 #include "parser_internal.h"
26
27 typedef struct JPEGXSParseContext {
28 ParseContext pc;
29
30 int eoc_found;
31 } JPEGXSParseContext;
32
33 /**
34 * Find the end of the current frame in the bitstream.
35 * @return the position of the first byte of the next frame, or -1
36 */
37 11 static int jpegxs_find_frame_end(JPEGXSParseContext *jpegxs, const uint8_t *buf,
38 int buf_size)
39 {
40 11 ParseContext *pc = &jpegxs->pc;
41 11 int pic_found, i = 0;
42 uint32_t state;
43
44 11 pic_found = pc->frame_start_found;
45 11 state = pc->state;
46
47
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 if (!pic_found) {
48
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < buf_size; i++) {
49 4 state = (state << 8) | buf[i];
50
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if ((uint16_t)state == JPEGXS_MARKER_SOC) {
51 2 i++;
52 2 pic_found = 1;
53 2 break;
54 }
55 }
56 }
57
58
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9 times.
11 if (buf_size == 0) {
59
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (jpegxs->eoc_found) {
60 1 pc->frame_start_found = jpegxs->eoc_found = 0;
61 1 pc->state = -1;
62 }
63 2 return 0;
64 }
65
66
3/4
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 8 times.
28 while (pic_found && i < buf_size) {
67
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 if (jpegxs->eoc_found) {
68
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 for(; i < buf_size; i++) {
69 6 state = (state << 8) | buf[i];
70
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if ((state >> 16) == JPEGXS_MARKER_EOC) {
71
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if ((uint16_t)state == JPEGXS_MARKER_SOC) {
72 // New image
73 1 pc->frame_start_found = jpegxs->eoc_found = 0;
74 1 pc->state = -1;
75 1 return i - 1;
76 } else {
77 // False positive
78 2 i++;
79 2 jpegxs->eoc_found = 0;
80 2 break;
81 }
82 }
83 }
84 }
85
86
2/2
✓ Branch 0 taken 32760 times.
✓ Branch 1 taken 6 times.
32766 for(; i < buf_size; i++) {
87 32760 state = (state << 8) | buf[i];
88
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 32756 times.
32760 if ((uint16_t)state == JPEGXS_MARKER_EOC) {
89 // EOC candidate
90 4 i++;
91 4 jpegxs->eoc_found = 1;
92 4 break;
93 }
94 }
95 }
96
97 8 pc->frame_start_found = pic_found;
98 8 pc->state = state;
99 8 return END_NOT_FOUND;
100 }
101
102 3 static int jpegxs_parse_frame(AVCodecParserContext *s, AVCodecContext *avctx,
103 const uint8_t *buf, int buf_size)
104 {
105 GetByteContext gbc;
106 GetBitContext gb;
107 int8_t bpc[3], log2_chroma_w[3], log2_chroma_h[3];
108 int size, marker, components;
109
110 3 s->key_frame = 1;
111 3 s->pict_type = AV_PICTURE_TYPE_I;
112
113
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (buf_size < 4)
114 1 return 0;
115
116 2 bytestream2_init(&gbc, buf, buf_size);
117 2 marker = bytestream2_get_be16(&gbc);
118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (marker != JPEGXS_MARKER_SOC)
119 return 0;
120
121 2 marker = bytestream2_get_be16(&gbc);
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (marker != JPEGXS_MARKER_CAP)
123 return 0;
124 2 size = bytestream2_get_be16(&gbc);
125 2 bytestream2_skip(&gbc, FFMAX(size - 2, 0));
126
127 2 marker = bytestream2_get_be16(&gbc);
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (marker != JPEGXS_MARKER_PIH)
129 return 0;
130 2 size = bytestream2_get_be16(&gbc);
131 2 bytestream2_skip(&gbc, 4); // Lcod
132 2 bytestream2_skip(&gbc, 2); // Ppih
133 2 bytestream2_skip(&gbc, 2); // Plev
134 2 size -= 8;
135
136 2 s->width = bytestream2_get_be16(&gbc);
137 2 s->height = bytestream2_get_be16(&gbc);
138 2 size -= 4;
139
140 2 bytestream2_skip(&gbc, 2); // Cw
141 2 bytestream2_skip(&gbc, 2); // Hsl
142 2 size -= 4;
143
144 2 components = bytestream2_get_byte(&gbc);
145
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
2 if (components != 1 && components != 3)
146 return 0;
147 2 size--;
148
149 2 bytestream2_skip(&gbc, FFMAX(size - 2, 0));
150
151
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 while (bytestream2_get_bytes_left(&gbc) > 0) {
152 2 marker = bytestream2_get_be16(&gbc);
153
154
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 switch(marker) {
155 2 case JPEGXS_MARKER_CDT:
156 2 size = bytestream2_get_be16(&gbc);
157
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 init_get_bits8(&gb, gbc.buffer, FFMIN(FFMAX(size - 2, 0), bytestream2_get_bytes_left(&gbc)));
158
159
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for (int i = 0; i < components; i++) {
160 6 bpc[i] = get_bits(&gb, 8);
161
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
6 if (i && bpc[i] != bpc[i-1])
162 return 0;
163
164 6 log2_chroma_w[i] = get_bits(&gb, 4);
165 6 log2_chroma_h[i] = get_bits(&gb, 4);
166
167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (log2_chroma_h[i] > log2_chroma_w[i])
168 return 0;
169
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
6 if (i == 2 && (log2_chroma_h[2] != log2_chroma_h[1] ||
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 log2_chroma_w[2] != log2_chroma_w[1]))
171 return 0;
172 }
173
174
1/5
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2 switch (bpc[0]) {
175 2 case 8:
176
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (components == 1) s->format = AV_PIX_FMT_GRAY8;
177
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
2 else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P;
178 else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P;
179 else s->format = AV_PIX_FMT_YUV420P;
180 2 break;
181 case 10:
182 if (components == 1) s->format = AV_PIX_FMT_GRAY10;
183 else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P10;
184 else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P10;
185 else s->format = AV_PIX_FMT_YUV420P10;
186 break;
187 case 12:
188 if (components == 1) s->format = AV_PIX_FMT_GRAY12;
189 else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P12;
190 else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P12;
191 else s->format = AV_PIX_FMT_YUV420P12;
192 break;
193 case 14:
194 if (components == 1) s->format = AV_PIX_FMT_GRAY14;
195 else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P14;
196 else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P14;
197 else s->format = AV_PIX_FMT_YUV420P14;
198 break;
199 default:
200 s->format = AV_PIX_FMT_NONE;
201 break;
202 }
203 2 return 0;
204 default:
205 size = bytestream2_get_be16(&gbc);
206 bytestream2_skip(&gbc, FFMAX(size - 2, 0));
207 break;
208 }
209 }
210
211 return 0;
212 }
213
214 11 static int jpegxsvideo_parse(AVCodecParserContext *s,
215 AVCodecContext *avctx,
216 const uint8_t **poutbuf, int *poutbuf_size,
217 const uint8_t *buf, int buf_size)
218 {
219 11 JPEGXSParseContext *jpegxs = s->priv_data;
220 11 ParseContext *pc = &jpegxs->pc;
221 int next;
222
223 11 next = jpegxs_find_frame_end(jpegxs, buf, buf_size);
224
225
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 3 times.
11 if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
226 8 *poutbuf = NULL;
227 8 *poutbuf_size = 0;
228 8 return buf_size;
229 }
230
231 3 jpegxs_parse_frame(s, avctx, buf, buf_size);
232
233 3 *poutbuf = buf;
234 3 *poutbuf_size = buf_size;
235 3 return next;
236 }
237
238 1 static av_cold void jpegxsparse_close(AVCodecParserContext *s)
239 {
240 1 JPEGXSParseContext *jpegxs = s->priv_data;
241 1 ParseContext *pc = &jpegxs->pc;
242
243 1 av_freep(&pc->buffer);
244 1 }
245
246 const FFCodecParser ff_jpegxs_parser = {
247 PARSER_CODEC_LIST(AV_CODEC_ID_JPEGXS),
248 .priv_data_size = sizeof(JPEGXSParseContext),
249 .parse = jpegxsvideo_parse,
250 .close = jpegxsparse_close,
251 };
252