1cabdff1aSopenharmony_ci/*
2cabdff1aSopenharmony_ci * JPEG2000 parser
3cabdff1aSopenharmony_ci * Copyright (c) 2020 Gautam Ramakrishnan
4cabdff1aSopenharmony_ci *
5cabdff1aSopenharmony_ci * This file is part of FFmpeg.
6cabdff1aSopenharmony_ci *
7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or
8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public
9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either
10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version.
11cabdff1aSopenharmony_ci *
12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful,
13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15cabdff1aSopenharmony_ci * Lesser General Public License for more details.
16cabdff1aSopenharmony_ci *
17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public
18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software
19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20cabdff1aSopenharmony_ci */
21cabdff1aSopenharmony_ci
22cabdff1aSopenharmony_ci/**
23cabdff1aSopenharmony_ci * @file
24cabdff1aSopenharmony_ci * JPEG2000 parser.
25cabdff1aSopenharmony_ci */
26cabdff1aSopenharmony_ci
27cabdff1aSopenharmony_ci#include "parser.h"
28cabdff1aSopenharmony_ci
29cabdff1aSopenharmony_ci/* Whether frame is jp2 file or codestream
30cabdff1aSopenharmony_ci*/
31cabdff1aSopenharmony_cienum frame_type {
32cabdff1aSopenharmony_ci    jp2_file = 1,
33cabdff1aSopenharmony_ci    j2k_cstream
34cabdff1aSopenharmony_ci};
35cabdff1aSopenharmony_ci
36cabdff1aSopenharmony_citypedef struct JPEG2000ParserContext {
37cabdff1aSopenharmony_ci    ParseContext pc;
38cabdff1aSopenharmony_ci    uint64_t bytes_read;
39cabdff1aSopenharmony_ci    uint64_t fheader_state;
40cabdff1aSopenharmony_ci    uint32_t skip_bytes; // skip bytes inside codestream data
41cabdff1aSopenharmony_ci    enum frame_type ft; // 1 if file, 2 if codestream
42cabdff1aSopenharmony_ci    uint8_t fheader_read; // are we reading
43cabdff1aSopenharmony_ci    uint8_t reading_file_header;
44cabdff1aSopenharmony_ci    uint8_t skipped_codestream;
45cabdff1aSopenharmony_ci    uint8_t read_tp;
46cabdff1aSopenharmony_ci    uint8_t in_codestream;
47cabdff1aSopenharmony_ci} JPEG2000ParserContext;
48cabdff1aSopenharmony_ci
49cabdff1aSopenharmony_cistatic inline void reset_context(JPEG2000ParserContext *m)
50cabdff1aSopenharmony_ci{
51cabdff1aSopenharmony_ci    ParseContext *pc = &m->pc;
52cabdff1aSopenharmony_ci
53cabdff1aSopenharmony_ci    pc->frame_start_found= 0;
54cabdff1aSopenharmony_ci    pc->state64 = 0;
55cabdff1aSopenharmony_ci    m->bytes_read = 0;
56cabdff1aSopenharmony_ci    m->ft = 0;
57cabdff1aSopenharmony_ci    m->skipped_codestream = 0;
58cabdff1aSopenharmony_ci    m->fheader_read = 0;
59cabdff1aSopenharmony_ci    m->skip_bytes = 0;
60cabdff1aSopenharmony_ci    m->read_tp = 0;
61cabdff1aSopenharmony_ci    m->in_codestream = 0;
62cabdff1aSopenharmony_ci}
63cabdff1aSopenharmony_ci
64cabdff1aSopenharmony_ci/* Returns 1 if marker has any data which can be skipped
65cabdff1aSopenharmony_ci*/
66cabdff1aSopenharmony_cistatic uint8_t info_marker(uint16_t marker)
67cabdff1aSopenharmony_ci{
68cabdff1aSopenharmony_ci    static const uint8_t lut[256] = {
69cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
70cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
71cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
72cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
73cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 0xFF4F
74cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
75cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
76cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
77cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
78cabdff1aSopenharmony_ci        0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xFF90 0xFF92 0xFF93
79cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
80cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
81cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
82cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, // 0xFFD9
83cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
84cabdff1aSopenharmony_ci        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
85cabdff1aSopenharmony_ci    };
86cabdff1aSopenharmony_ci    return marker < 0xFF00 ? 0 : lut[marker & 0xFF];
87cabdff1aSopenharmony_ci}
88cabdff1aSopenharmony_ci
89cabdff1aSopenharmony_ci/**
90cabdff1aSopenharmony_ci * Find the end of the current frame in the bitstream.
91cabdff1aSopenharmony_ci * @return the position of the first byte of the next frame, or -1
92cabdff1aSopenharmony_ci */
93cabdff1aSopenharmony_cistatic int find_frame_end(JPEG2000ParserContext *m, const uint8_t *buf, int buf_size)
94cabdff1aSopenharmony_ci{
95cabdff1aSopenharmony_ci    ParseContext *pc= &m->pc;
96cabdff1aSopenharmony_ci    int i;
97cabdff1aSopenharmony_ci    uint64_t state64 = pc->state64;
98cabdff1aSopenharmony_ci    uint64_t bytes_read = m->bytes_read;
99cabdff1aSopenharmony_ci
100cabdff1aSopenharmony_ci    if (buf_size == 0) {
101cabdff1aSopenharmony_ci        return 0;
102cabdff1aSopenharmony_ci    }
103cabdff1aSopenharmony_ci
104cabdff1aSopenharmony_ci    for (i = 0; i < buf_size; i++) {
105cabdff1aSopenharmony_ci        state64 = state64 << 8 | buf[i];
106cabdff1aSopenharmony_ci        bytes_read++;
107cabdff1aSopenharmony_ci        if (m->skip_bytes) {
108cabdff1aSopenharmony_ci            // handle long skips
109cabdff1aSopenharmony_ci            if (m->skip_bytes > 8) {
110cabdff1aSopenharmony_ci                // need -9 else buf_size - i == 8 ==> i == buf_size after this,
111cabdff1aSopenharmony_ci                // and thus i == buf_size + 1 after the loop
112cabdff1aSopenharmony_ci                int skip = FFMIN(FFMIN((int64_t)m->skip_bytes - 8, buf_size - i - 9), INT_MAX);
113cabdff1aSopenharmony_ci                if (skip > 0) {
114cabdff1aSopenharmony_ci                    m->skip_bytes -= skip;
115cabdff1aSopenharmony_ci                    i += skip;
116cabdff1aSopenharmony_ci                    bytes_read += skip;
117cabdff1aSopenharmony_ci                }
118cabdff1aSopenharmony_ci            }
119cabdff1aSopenharmony_ci            m->skip_bytes--;
120cabdff1aSopenharmony_ci            continue;
121cabdff1aSopenharmony_ci        }
122cabdff1aSopenharmony_ci        if (m->read_tp) { // Find out how many bytes inside Tile part codestream to skip.
123cabdff1aSopenharmony_ci            if (m->read_tp == 1) {
124cabdff1aSopenharmony_ci                m->skip_bytes = (state64 & 0xFFFFFFFF) - 9 > 0?
125cabdff1aSopenharmony_ci                                (state64 & 0xFFFFFFFF) - 9 : 0;
126cabdff1aSopenharmony_ci            }
127cabdff1aSopenharmony_ci            m->read_tp--;
128cabdff1aSopenharmony_ci            continue;
129cabdff1aSopenharmony_ci        }
130cabdff1aSopenharmony_ci        if (m->fheader_read) {
131cabdff1aSopenharmony_ci            if (m->fheader_read == 1) {
132cabdff1aSopenharmony_ci                if (state64 == 0x6A5020200D0A870A) { // JP2 signature box value.
133cabdff1aSopenharmony_ci                    if (pc->frame_start_found) {
134cabdff1aSopenharmony_ci                        pc->frame_start_found = 0;
135cabdff1aSopenharmony_ci                        reset_context(m);
136cabdff1aSopenharmony_ci                        return i - 11;
137cabdff1aSopenharmony_ci                    } else {
138cabdff1aSopenharmony_ci                        pc->frame_start_found = 1;
139cabdff1aSopenharmony_ci                        m->ft = jp2_file;
140cabdff1aSopenharmony_ci                    }
141cabdff1aSopenharmony_ci                }
142cabdff1aSopenharmony_ci            }
143cabdff1aSopenharmony_ci            m->fheader_read--;
144cabdff1aSopenharmony_ci        }
145cabdff1aSopenharmony_ci        if ((state64 & 0xFFFFFFFF) == 0x0000000C && bytes_read >= 3) { // Indicates start of JP2 file. Check signature next.
146cabdff1aSopenharmony_ci            m->fheader_read = 8;
147cabdff1aSopenharmony_ci        } else if ((state64 & 0xFFFF) == 0xFF4F) {
148cabdff1aSopenharmony_ci            m->in_codestream = 1;
149cabdff1aSopenharmony_ci            if (!pc->frame_start_found) {
150cabdff1aSopenharmony_ci                pc->frame_start_found = 1;
151cabdff1aSopenharmony_ci                m->ft = j2k_cstream;
152cabdff1aSopenharmony_ci            } else if (pc->frame_start_found && m->ft == jp2_file && m->skipped_codestream) {
153cabdff1aSopenharmony_ci                reset_context(m);
154cabdff1aSopenharmony_ci                return i - 1;
155cabdff1aSopenharmony_ci            }
156cabdff1aSopenharmony_ci        } else if ((state64 & 0xFFFF) == 0xFFD9) {
157cabdff1aSopenharmony_ci            if (pc->frame_start_found && m->ft == jp2_file) {
158cabdff1aSopenharmony_ci                m->skipped_codestream = 1;
159cabdff1aSopenharmony_ci            } else if (pc->frame_start_found && m->ft == j2k_cstream) {
160cabdff1aSopenharmony_ci                reset_context(m);
161cabdff1aSopenharmony_ci                return i + 1; // End of frame detected, return frame size.
162cabdff1aSopenharmony_ci            }
163cabdff1aSopenharmony_ci            m->in_codestream = 0;
164cabdff1aSopenharmony_ci        } else if (m->in_codestream) {
165cabdff1aSopenharmony_ci            if ((state64 & 0xFFFF) == 0xFF90) { // Are we in tile part header?
166cabdff1aSopenharmony_ci                m->read_tp = 8;
167cabdff1aSopenharmony_ci            } else if (info_marker((state64 & 0xFFFF0000)>>16) && pc->frame_start_found && (state64 & 0xFFFF)) {
168cabdff1aSopenharmony_ci                // Calculate number of bytes to skip to get to end of the next marker.
169cabdff1aSopenharmony_ci                m->skip_bytes = (state64 & 0xFFFF)-1;
170cabdff1aSopenharmony_ci
171cabdff1aSopenharmony_ci                // If the next marker is an info marker, skip to the end of of the marker length.
172cabdff1aSopenharmony_ci                if (i + m->skip_bytes + 1 < buf_size) {
173cabdff1aSopenharmony_ci                    uint32_t next_state = (buf[i + m->skip_bytes] << 8) | buf[i + m->skip_bytes + 1];
174cabdff1aSopenharmony_ci                    if (info_marker(next_state)) {
175cabdff1aSopenharmony_ci                        // Skip an additional 2 bytes to get to the end of the marker length.
176cabdff1aSopenharmony_ci                        m->skip_bytes += 2;
177cabdff1aSopenharmony_ci                    }
178cabdff1aSopenharmony_ci                }
179cabdff1aSopenharmony_ci            }
180cabdff1aSopenharmony_ci        }
181cabdff1aSopenharmony_ci    }
182cabdff1aSopenharmony_ci
183cabdff1aSopenharmony_ci    pc->state64 = state64;
184cabdff1aSopenharmony_ci    m->bytes_read = bytes_read;
185cabdff1aSopenharmony_ci    return END_NOT_FOUND;
186cabdff1aSopenharmony_ci}
187cabdff1aSopenharmony_ci
188cabdff1aSopenharmony_cistatic int jpeg2000_parse(AVCodecParserContext *s,
189cabdff1aSopenharmony_ci                          AVCodecContext *avctx,
190cabdff1aSopenharmony_ci                          const uint8_t **poutbuf, int *poutbuf_size,
191cabdff1aSopenharmony_ci                          const uint8_t *buf, int buf_size)
192cabdff1aSopenharmony_ci{
193cabdff1aSopenharmony_ci    JPEG2000ParserContext *m = s->priv_data;
194cabdff1aSopenharmony_ci    ParseContext *pc = &m->pc;
195cabdff1aSopenharmony_ci    int next;
196cabdff1aSopenharmony_ci
197cabdff1aSopenharmony_ci    if(s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
198cabdff1aSopenharmony_ci        next= buf_size;
199cabdff1aSopenharmony_ci    } else {
200cabdff1aSopenharmony_ci        next= find_frame_end(m, buf, buf_size);
201cabdff1aSopenharmony_ci
202cabdff1aSopenharmony_ci        if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
203cabdff1aSopenharmony_ci            *poutbuf = NULL;
204cabdff1aSopenharmony_ci            *poutbuf_size = 0;
205cabdff1aSopenharmony_ci            return buf_size;
206cabdff1aSopenharmony_ci        }
207cabdff1aSopenharmony_ci    }
208cabdff1aSopenharmony_ci
209cabdff1aSopenharmony_ci    *poutbuf = buf;
210cabdff1aSopenharmony_ci    *poutbuf_size = buf_size;
211cabdff1aSopenharmony_ci    return next;
212cabdff1aSopenharmony_ci}
213cabdff1aSopenharmony_ci
214cabdff1aSopenharmony_ciconst AVCodecParser ff_jpeg2000_parser = {
215cabdff1aSopenharmony_ci    .codec_ids      = { AV_CODEC_ID_JPEG2000 },
216cabdff1aSopenharmony_ci    .priv_data_size = sizeof(JPEG2000ParserContext),
217cabdff1aSopenharmony_ci    .parser_parse   = jpeg2000_parse,
218cabdff1aSopenharmony_ci    .parser_close   = ff_parse_close,
219cabdff1aSopenharmony_ci};
220