• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
reset_context(JPEG2000ParserContext * m)49 static inline void reset_context(JPEG2000ParserContext *m)
50 {
51     ParseContext *pc = &m->pc;
52 
53     pc->frame_start_found= 0;
54     pc->state64 = 0;
55     m->bytes_read = 0;
56     m->ft = 0;
57     m->skipped_codestream = 0;
58     m->fheader_read = 0;
59     m->skip_bytes = 0;
60     m->read_tp = 0;
61     m->in_codestream = 0;
62 }
63 
64 /* Returns 1 if marker has any data which can be skipped
65 */
info_marker(uint16_t marker)66 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     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  */
find_frame_end(JPEG2000ParserContext * m,const uint8_t * buf,int buf_size)93 static int find_frame_end(JPEG2000ParserContext *m, const uint8_t *buf, int buf_size)
94 {
95     ParseContext *pc= &m->pc;
96     int i;
97     uint64_t state64 = pc->state64;
98     uint64_t bytes_read = m->bytes_read;
99 
100     if (buf_size == 0) {
101         return 0;
102     }
103 
104     for (i = 0; i < buf_size; i++) {
105         state64 = state64 << 8 | buf[i];
106         bytes_read++;
107         if (m->skip_bytes) {
108             // handle long skips
109             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                 int skip = FFMIN(FFMIN((int64_t)m->skip_bytes - 8, buf_size - i - 9), INT_MAX);
113                 if (skip > 0) {
114                     m->skip_bytes -= skip;
115                     i += skip;
116                     bytes_read += skip;
117                 }
118             }
119             m->skip_bytes--;
120             continue;
121         }
122         if (m->read_tp) { // Find out how many bytes inside Tile part codestream to skip.
123             if (m->read_tp == 1) {
124                 m->skip_bytes = (state64 & 0xFFFFFFFF) - 9 > 0?
125                                 (state64 & 0xFFFFFFFF) - 9 : 0;
126             }
127             m->read_tp--;
128             continue;
129         }
130         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         if ((state64 & 0xFFFFFFFF) == 0x0000000C && bytes_read >= 3) { // Indicates start of JP2 file. Check signature next.
146             m->fheader_read = 8;
147         } else if ((state64 & 0xFFFF) == 0xFF4F) {
148             m->in_codestream = 1;
149             if (!pc->frame_start_found) {
150                 pc->frame_start_found = 1;
151                 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         } else if ((state64 & 0xFFFF) == 0xFFD9) {
157             if (pc->frame_start_found && m->ft == jp2_file) {
158                 m->skipped_codestream = 1;
159             } else if (pc->frame_start_found && m->ft == j2k_cstream) {
160                 reset_context(m);
161                 return i + 1; // End of frame detected, return frame size.
162             }
163             m->in_codestream = 0;
164         } else if (m->in_codestream) {
165             if ((state64 & 0xFFFF) == 0xFF90) { // Are we in tile part header?
166                 m->read_tp = 8;
167             } 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                 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                 if (i + m->skip_bytes + 1 < buf_size) {
173                     uint32_t next_state = (buf[i + m->skip_bytes] << 8) | buf[i + m->skip_bytes + 1];
174                     if (info_marker(next_state)) {
175                         // Skip an additional 2 bytes to get to the end of the marker length.
176                         m->skip_bytes += 2;
177                     }
178                 }
179             }
180         }
181     }
182 
183     pc->state64 = state64;
184     m->bytes_read = bytes_read;
185     return END_NOT_FOUND;
186 }
187 
jpeg2000_parse(AVCodecParserContext * s,AVCodecContext * avctx,const uint8_t ** poutbuf,int * poutbuf_size,const uint8_t * buf,int buf_size)188 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     JPEG2000ParserContext *m = s->priv_data;
194     ParseContext *pc = &m->pc;
195     int next;
196 
197     if(s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
198         next= buf_size;
199     } else {
200         next= find_frame_end(m, buf, buf_size);
201 
202         if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
203             *poutbuf = NULL;
204             *poutbuf_size = 0;
205             return buf_size;
206         }
207     }
208 
209     *poutbuf = buf;
210     *poutbuf_size = buf_size;
211     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