FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/jpeg2000_parser.c
Date: 2024-04-19 17:50:32
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
29 /* Whether frame is jp2 file or codestream
30 */
31 enum frame_type {
32 jp2_file = 1,
33 j2k_cstream
34 };
35
36 typedef struct JPEG2000ParserContext {
37 ParseContext pc;
38 uint64_t bytes_read;
39 uint64_t fheader_state;
40 uint32_t skip_bytes; // skip bytes inside codestream data
41 enum frame_type ft; // 1 if file, 2 if codestream
42 uint8_t fheader_read; // are we reading
43 uint8_t reading_file_header;
44 uint8_t skipped_codestream;
45 uint8_t read_tp;
46 uint8_t in_codestream;
47 } JPEG2000ParserContext;
48
49 14 static inline void reset_context(JPEG2000ParserContext *m)
50 {
51 14 ParseContext *pc = &m->pc;
52
53 14 pc->frame_start_found= 0;
54 14 pc->state64 = 0;
55 14 m->bytes_read = 0;
56 14 m->ft = 0;
57 14 m->skipped_codestream = 0;
58 14 m->fheader_read = 0;
59 14 m->skip_bytes = 0;
60 14 m->read_tp = 0;
61 14 m->in_codestream = 0;
62 14 }
63
64 /* Returns 1 if marker has any data which can be skipped
65 */
66 204 static uint8_t info_marker(uint16_t marker)
67 {
68 static const uint8_t lut[256] = {
69 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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, 0, // 0xFF4F
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, 1,
77 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
78 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xFF90 0xFF92 0xFF93
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 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, 0, 1, 1, 1, 1, 1, 1, // 0xFFD9
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 };
86
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 28 times.
204 return marker < 0xFF00 ? 0 : lut[marker & 0xFF];
87 }
88
89 /**
90 * Find the end of the current frame in the bitstream.
91 * @return the position of the first byte of the next frame, or -1
92 */
93 3279 static int find_frame_end(JPEG2000ParserContext *m, const uint8_t *buf, int buf_size)
94 {
95 3279 ParseContext *pc= &m->pc;
96 int i;
97 3279 uint64_t state64 = pc->state64;
98 3279 uint64_t bytes_read = m->bytes_read;
99
100
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 3265 times.
3279 if (buf_size == 0) {
101 14 return 0;
102 }
103
104
2/2
✓ Branch 0 taken 34751 times.
✓ Branch 1 taken 3251 times.
38002 for (i = 0; i < buf_size; i++) {
105 34751 state64 = state64 << 8 | buf[i];
106 34751 bytes_read++;
107
2/2
✓ Branch 0 taken 32102 times.
✓ Branch 1 taken 2649 times.
34751 if (m->skip_bytes) {
108 // handle long skips
109
2/2
✓ Branch 0 taken 29609 times.
✓ Branch 1 taken 2493 times.
32102 if (m->skip_bytes > 8) {
110 // need -9 else buf_size - i == 8 ==> i == buf_size after this,
111 // and thus i == buf_size + 1 after the loop
112 29609 int skip = FFMIN(FFMIN((int64_t)m->skip_bytes - 8, buf_size - i - 9), INT_MAX);
113
2/2
✓ Branch 0 taken 3601 times.
✓ Branch 1 taken 26008 times.
29609 if (skip > 0) {
114 3601 m->skip_bytes -= skip;
115 3601 i += skip;
116 3601 bytes_read += skip;
117 }
118 }
119 32102 m->skip_bytes--;
120 32102 continue;
121 }
122
2/2
✓ Branch 0 taken 2208 times.
✓ Branch 1 taken 441 times.
2649 if (m->read_tp) { // Find out how many bytes inside Tile part codestream to skip.
123
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 1932 times.
2208 if (m->read_tp == 1) {
124
1/2
✓ Branch 0 taken 276 times.
✗ Branch 1 not taken.
552 m->skip_bytes = (state64 & 0xFFFFFFFF) - 9 > 0?
125 276 (state64 & 0xFFFFFFFF) - 9 : 0;
126 }
127 2208 m->read_tp--;
128 2208 continue;
129 }
130
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 441 times.
441 if (m->fheader_read) {
131 if (m->fheader_read == 1) {
132 if (state64 == 0x6A5020200D0A870A) { // JP2 signature box value.
133 if (pc->frame_start_found) {
134 pc->frame_start_found = 0;
135 reset_context(m);
136 return i - 11;
137 } else {
138 pc->frame_start_found = 1;
139 m->ft = jp2_file;
140 }
141 }
142 }
143 m->fheader_read--;
144 }
145
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 441 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
441 if ((state64 & 0xFFFFFFFF) == 0x0000000C && bytes_read >= 3) { // Indicates start of JP2 file. Check signature next.
146 m->fheader_read = 8;
147
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 427 times.
441 } else if ((state64 & 0xFFFF) == 0xFF4F) {
148 14 m->in_codestream = 1;
149
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (!pc->frame_start_found) {
150 14 pc->frame_start_found = 1;
151 14 m->ft = j2k_cstream;
152 } else if (pc->frame_start_found && m->ft == jp2_file && m->skipped_codestream) {
153 reset_context(m);
154 return i - 1;
155 }
156
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 413 times.
427 } else if ((state64 & 0xFFFF) == 0xFFD9) {
157
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 14 times.
14 if (pc->frame_start_found && m->ft == jp2_file) {
158 m->skipped_codestream = 1;
159
2/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 } else if (pc->frame_start_found && m->ft == j2k_cstream) {
160 14 reset_context(m);
161 14 return i + 1; // End of frame detected, return frame size.
162 }
163 m->in_codestream = 0;
164
2/2
✓ Branch 0 taken 399 times.
✓ Branch 1 taken 14 times.
413 } else if (m->in_codestream) {
165
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 123 times.
399 if ((state64 & 0xFFFF) == 0xFF90) { // Are we in tile part header?
166 276 m->read_tp = 8;
167
4/6
✓ Branch 1 taken 81 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 81 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 81 times.
✗ Branch 6 not taken.
123 } else if (info_marker((state64 & 0xFFFF0000)>>16) && pc->frame_start_found && (state64 & 0xFFFF)) {
168 // Calculate number of bytes to skip to get to end of the next marker.
169 81 m->skip_bytes = (state64 & 0xFFFF)-1;
170
171 // If the next marker is an info marker, skip to the end of of the marker length.
172
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 if (i + m->skip_bytes + 1 < buf_size) {
173 81 uint32_t next_state = (buf[i + m->skip_bytes] << 8) | buf[i + m->skip_bytes + 1];
174
2/2
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 13 times.
81 if (info_marker(next_state)) {
175 // Skip an additional 2 bytes to get to the end of the marker length.
176 68 m->skip_bytes += 2;
177 }
178 }
179 }
180 }
181 }
182
183 3251 pc->state64 = state64;
184 3251 m->bytes_read = bytes_read;
185 3251 return END_NOT_FOUND;
186 }
187
188 4099 static int jpeg2000_parse(AVCodecParserContext *s,
189 AVCodecContext *avctx,
190 const uint8_t **poutbuf, int *poutbuf_size,
191 const uint8_t *buf, int buf_size)
192 {
193 4099 JPEG2000ParserContext *m = s->priv_data;
194 4099 ParseContext *pc = &m->pc;
195 int next;
196
197
2/2
✓ Branch 0 taken 820 times.
✓ Branch 1 taken 3279 times.
4099 if(s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
198 820 next= buf_size;
199 } else {
200 3279 next= find_frame_end(m, buf, buf_size);
201
202
2/2
✓ Branch 1 taken 3251 times.
✓ Branch 2 taken 28 times.
3279 if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
203 3251 *poutbuf = NULL;
204 3251 *poutbuf_size = 0;
205 3251 return buf_size;
206 }
207 }
208
209 848 *poutbuf = buf;
210 848 *poutbuf_size = buf_size;
211 848 return next;
212 }
213
214 const AVCodecParser ff_jpeg2000_parser = {
215 .codec_ids = { AV_CODEC_ID_JPEG2000 },
216 .priv_data_size = sizeof(JPEG2000ParserContext),
217 .parser_parse = jpeg2000_parse,
218 .parser_close = ff_parse_close,
219 };
220