FFmpeg
Loading...
Searching...
No Matches
jpeg2000_parser.c
Go to the documentation of this file.
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*/
36
37typedef struct JPEG2000ParserContext {
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
46 uint8_t read_tp;
49
51{
52 ParseContext *pc = &m->pc;
53
54 pc->frame_start_found= 0;
55 pc->state64 = 0;
56 m->bytes_read = 0;
57 m->ft = 0;
58 m->skipped_codestream = 0;
59 m->fheader_read = 0;
60 m->skip_bytes = 0;
61 m->read_tp = 0;
62 m->in_codestream = 0;
63}
64
65/* Returns 1 if marker has any data which can be skipped
66*/
67static 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 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 */
94static int find_frame_end(JPEG2000ParserContext *m, const uint8_t *buf, int buf_size)
95{
96 ParseContext *pc= &m->pc;
97 int i;
98 uint64_t state64 = pc->state64;
99 uint64_t bytes_read = m->bytes_read;
100
101 if (buf_size == 0) {
102 return 0;
103 }
104
105 for (i = 0; i < buf_size; i++) {
106 state64 = state64 << 8 | buf[i];
107 bytes_read++;
108 if (m->skip_bytes) {
109 // handle long skips
110 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 int skip = FFMIN(FFMIN((int64_t)m->skip_bytes - 8, buf_size - i - 9), INT_MAX);
114 if (skip > 0) {
115 m->skip_bytes -= skip;
116 i += skip;
117 bytes_read += skip;
118 }
119 }
120 m->skip_bytes--;
121 continue;
122 }
123 if (m->read_tp) { // Find out how many bytes inside Tile part codestream to skip.
124 if (m->read_tp == 1) {
125 m->skip_bytes = (state64 & 0xFFFFFFFF) - 9 > 0?
126 (state64 & 0xFFFFFFFF) - 9 : 0;
127 }
128 m->read_tp--;
129 continue;
130 }
131 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 if ((state64 & 0xFFFFFFFF) == 0x0000000C && bytes_read >= 3) { // Indicates start of JP2 file. Check signature next.
147 m->fheader_read = 8;
148 } else if ((state64 & 0xFFFF) == 0xFF4F) {
149 m->in_codestream = 1;
150 if (!pc->frame_start_found) {
151 pc->frame_start_found = 1;
152 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 } else if ((state64 & 0xFFFF) == 0xFFD9) {
158 if (pc->frame_start_found && m->ft == jp2_file) {
159 m->skipped_codestream = 1;
160 } else if (pc->frame_start_found && m->ft == j2k_cstream) {
161 reset_context(m);
162 return i + 1; // End of frame detected, return frame size.
163 }
164 m->in_codestream = 0;
165 } else if (m->in_codestream) {
166 if ((state64 & 0xFFFF) == 0xFF90) { // Are we in tile part header?
167 m->read_tp = 8;
168 } 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 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 if (i + m->skip_bytes + 1 < buf_size) {
174 uint32_t next_state = (buf[i + m->skip_bytes] << 8) | buf[i + m->skip_bytes + 1];
175 if (info_marker(next_state)) {
176 // Skip an additional 2 bytes to get to the end of the marker length.
177 m->skip_bytes += 2;
178 }
179 }
180 }
181 }
182 }
183
184 pc->state64 = state64;
185 m->bytes_read = bytes_read;
186 return END_NOT_FOUND;
187}
188
190 AVCodecContext *avctx,
191 const uint8_t **poutbuf, int *poutbuf_size,
192 const uint8_t *buf, int buf_size)
193{
194 JPEG2000ParserContext *m = s->priv_data;
195 ParseContext *pc = &m->pc;
196 int next;
197
198 if(s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
199 next= buf_size;
200 } else {
201 next= find_frame_end(m, buf, buf_size);
202
203 if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
204 *poutbuf = NULL;
205 *poutbuf_size = 0;
206 return buf_size;
207 }
208 }
209
210 *poutbuf = buf;
211 *poutbuf_size = buf_size;
212 return next;
213}
214
static int parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size)
Definition apv_parser.c:92
static av_cold void close(AVCodecParserContext *s)
Definition apv_parser.c:197
#define PARSER_FLAG_COMPLETE_FRAMES
Definition avcodec.h:2651
static void BS_FUNC skip(BSCTX *bc, unsigned int n)
Skip n bits in the buffer.
#define i(width, name, range_min, range_max)
Definition cbs_h264.c:63
#define s(width, name)
Definition cbs_vp9.c:198
#define NULL
Definition coverity.c:32
long long int64_t
Definition coverity.c:34
@ AV_CODEC_ID_JPEG2000
Definition codec_id.h:138
frame_type
@ j2k_cstream
@ jp2_file
static uint8_t info_marker(uint16_t marker)
static void reset_context(JPEG2000ParserContext *m)
const FFCodecParser ff_jpeg2000_parser
static int jpeg2000_parse(AVCodecParserContext *s, AVCodecContext *avctx, const uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size)
static int find_frame_end(JPEG2000ParserContext *m, const uint8_t *buf, int buf_size)
Find the end of the current frame in the bitstream.
#define FFMIN(a, b)
Definition macros.h:49
av_cold void ff_parse_close(AVCodecParserContext *s)
Definition parser.c:300
int ff_combine_frame(ParseContext *pc, int next, const uint8_t **buf, int *buf_size)
Combine the (truncated) bitstream to a complete frame.
Definition parser.c:213
#define END_NOT_FOUND
Definition parser.h:40
#define PARSER_CODEC_LIST(...)
main external API structure.
Definition avcodec.h:443
uint64_t state64
contains the last 8 bytes in MSB order
Definition parser.h:37
int frame_start_found
Definition parser.h:34