FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/jpeg2000_parser.c
Date: 2026-01-21 02:14:00
Exec Total Coverage
Lines: 75 90 83.3%
Functions: 4 4 100.0%
Branches: 43 68 63.2%

Line Branch Exec Source
1 /*
2 * JPEG2000 parser
3 * Copyright (c) 2020 Gautam Ramakrishnan
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
22 /**
23 * @file
24 * JPEG2000 parser.
25 */
26
27 #include "parser.h"
28 #include "parser_internal.h"
29
30 /* Whether frame is jp2 file or codestream
31 */
32 enum frame_type {
33 jp2_file = 1,
34 j2k_cstream
35 };
36
37 typedef struct JPEG2000ParserContext {
38 ParseContext pc;
39 uint64_t bytes_read;
40 uint64_t fheader_state;
41 uint32_t skip_bytes; // skip bytes inside codestream data
42 enum frame_type ft; // 1 if file, 2 if codestream
43 uint8_t fheader_read; // are we reading
44 uint8_t reading_file_header;
45 uint8_t skipped_codestream;
46 uint8_t read_tp;
47 uint8_t in_codestream;
48 } JPEG2000ParserContext;
49
50 15 static inline void reset_context(JPEG2000ParserContext *m)
51 {
52 15 ParseContext *pc = &m->pc;
53
54 15 pc->frame_start_found= 0;
55 15 pc->state64 = 0;
56 15 m->bytes_read = 0;
57 15 m->ft = 0;
58 15 m->skipped_codestream = 0;
59 15 m->fheader_read = 0;
60 15 m->skip_bytes = 0;
61 15 m->read_tp = 0;
62 15 m->in_codestream = 0;
63 15 }
64
65 /* Returns 1 if marker has any data which can be skipped
66 */
67 213 static uint8_t info_marker(uint16_t marker)
68 {
69 static const uint8_t lut[256] = {
70 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
71 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
72 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
73 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
74 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 0xFF4F
75 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
76 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
77 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
78 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
79 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xFF90 0xFF92 0xFF93
80 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
81 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
82 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
83 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, // 0xFFD9
84 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
85 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
86 };
87
2/2
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 30 times.
213 return marker < 0xFF00 ? 0 : lut[marker & 0xFF];
88 }
89
90 /**
91 * Find the end of the current frame in the bitstream.
92 * @return the position of the first byte of the next frame, or -1
93 */
94 3284 static int find_frame_end(JPEG2000ParserContext *m, const uint8_t *buf, int buf_size)
95 {
96 3284 ParseContext *pc= &m->pc;
97 int i;
98 3284 uint64_t state64 = pc->state64;
99 3284 uint64_t bytes_read = m->bytes_read;
100
101
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 3269 times.
3284 if (buf_size == 0) {
102 15 return 0;
103 }
104
105
2/2
✓ Branch 0 taken 34961 times.
✓ Branch 1 taken 3254 times.
38215 for (i = 0; i < buf_size; i++) {
106 34961 state64 = state64 << 8 | buf[i];
107 34961 bytes_read++;
108
2/2
✓ Branch 0 taken 32222 times.
✓ Branch 1 taken 2739 times.
34961 if (m->skip_bytes) {
109 // handle long skips
110
2/2
✓ Branch 0 taken 29647 times.
✓ Branch 1 taken 2575 times.
32222 if (m->skip_bytes > 8) {
111 // need -9 else buf_size - i == 8 ==> i == buf_size after this,
112 // and thus i == buf_size + 1 after the loop
113 29647 int skip = FFMIN(FFMIN((int64_t)m->skip_bytes - 8, buf_size - i - 9), INT_MAX);
114
2/2
✓ Branch 0 taken 3615 times.
✓ Branch 1 taken 26032 times.
29647 if (skip > 0) {
115 3615 m->skip_bytes -= skip;
116 3615 i += skip;
117 3615 bytes_read += skip;
118 }
119 }
120 32222 m->skip_bytes--;
121 32222 continue;
122 }
123
2/2
✓ Branch 0 taken 2280 times.
✓ Branch 1 taken 459 times.
2739 if (m->read_tp) { // Find out how many bytes inside Tile part codestream to skip.
124
2/2
✓ Branch 0 taken 285 times.
✓ Branch 1 taken 1995 times.
2280 if (m->read_tp == 1) {
125
1/2
✓ Branch 0 taken 285 times.
✗ Branch 1 not taken.
570 m->skip_bytes = (state64 & 0xFFFFFFFF) - 9 > 0?
126 285 (state64 & 0xFFFFFFFF) - 9 : 0;
127 }
128 2280 m->read_tp--;
129 2280 continue;
130 }
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 459 times.
459 if (m->fheader_read) {
132 if (m->fheader_read == 1) {
133 if (state64 == 0x6A5020200D0A870A) { // JP2 signature box value.
134 if (pc->frame_start_found) {
135 pc->frame_start_found = 0;
136 reset_context(m);
137 return i - 11;
138 } else {
139 pc->frame_start_found = 1;
140 m->ft = jp2_file;
141 }
142 }
143 }
144 m->fheader_read--;
145 }
146
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 459 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
459 if ((state64 & 0xFFFFFFFF) == 0x0000000C && bytes_read >= 3) { // Indicates start of JP2 file. Check signature next.
147 m->fheader_read = 8;
148
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 444 times.
459 } else if ((state64 & 0xFFFF) == 0xFF4F) {
149 15 m->in_codestream = 1;
150
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (!pc->frame_start_found) {
151 15 pc->frame_start_found = 1;
152 15 m->ft = j2k_cstream;
153 } else if (pc->frame_start_found && m->ft == jp2_file && m->skipped_codestream) {
154 reset_context(m);
155 return i - 1;
156 }
157
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 429 times.
444 } else if ((state64 & 0xFFFF) == 0xFFD9) {
158
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
15 if (pc->frame_start_found && m->ft == jp2_file) {
159 m->skipped_codestream = 1;
160
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
15 } else if (pc->frame_start_found && m->ft == j2k_cstream) {
161 15 reset_context(m);
162 15 return i + 1; // End of frame detected, return frame size.
163 }
164 m->in_codestream = 0;
165
2/2
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 15 times.
429 } else if (m->in_codestream) {
166
2/2
✓ Branch 0 taken 285 times.
✓ Branch 1 taken 129 times.
414 if ((state64 & 0xFFFF) == 0xFF90) { // Are we in tile part header?
167 285 m->read_tp = 8;
168
4/6
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 84 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 84 times.
✗ Branch 6 not taken.
129 } else if (info_marker((state64 & 0xFFFF0000)>>16) && pc->frame_start_found && (state64 & 0xFFFF)) {
169 // Calculate number of bytes to skip to get to end of the next marker.
170 84 m->skip_bytes = (state64 & 0xFFFF)-1;
171
172 // If the next marker is an info marker, skip to the end of of the marker length.
173
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 if (i + m->skip_bytes + 1 < buf_size) {
174 84 uint32_t next_state = (buf[i + m->skip_bytes] << 8) | buf[i + m->skip_bytes + 1];
175
2/2
✓ Branch 1 taken 70 times.
✓ Branch 2 taken 14 times.
84 if (info_marker(next_state)) {
176 // Skip an additional 2 bytes to get to the end of the marker length.
177 70 m->skip_bytes += 2;
178 }
179 }
180 }
181 }
182 }
183
184 3254 pc->state64 = state64;
185 3254 m->bytes_read = bytes_read;
186 3254 return END_NOT_FOUND;
187 }
188
189 4104 static int jpeg2000_parse(AVCodecParserContext *s,
190 AVCodecContext *avctx,
191 const uint8_t **poutbuf, int *poutbuf_size,
192 const uint8_t *buf, int buf_size)
193 {
194 4104 JPEG2000ParserContext *m = s->priv_data;
195 4104 ParseContext *pc = &m->pc;
196 int next;
197
198
2/2
✓ Branch 0 taken 820 times.
✓ Branch 1 taken 3284 times.
4104 if(s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
199 820 next= buf_size;
200 } else {
201 3284 next= find_frame_end(m, buf, buf_size);
202
203
2/2
✓ Branch 1 taken 3254 times.
✓ Branch 2 taken 30 times.
3284 if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
204 3254 *poutbuf = NULL;
205 3254 *poutbuf_size = 0;
206 3254 return buf_size;
207 }
208 }
209
210 850 *poutbuf = buf;
211 850 *poutbuf_size = buf_size;
212 850 return next;
213 }
214
215 const FFCodecParser ff_jpeg2000_parser = {
216 PARSER_CODEC_LIST(AV_CODEC_ID_JPEG2000),
217 .priv_data_size = sizeof(JPEG2000ParserContext),
218 .parse = jpeg2000_parse,
219 .close = ff_parse_close,
220 };
221