../../../ffmpeg/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
78 / 99
78.8%
Branches:
44 / 74
59.5%
Functions:
4 / 4
100.0%

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