Coverage Report

Created: 2026-07-25 07:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/jpegxs_parser.c
Line
Count
Source
1
/*
2
 * This file is part of FFmpeg.
3
 *
4
 * FFmpeg is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Lesser General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2.1 of the License, or (at your option) any later version.
8
 *
9
 * FFmpeg is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public
15
 * License along with FFmpeg; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
 */
18
19
#include "libavutil/mem.h"
20
21
#include "bytestream.h"
22
#include "get_bits.h"
23
#include "jpegxs.h"
24
#include "parser.h"
25
#include "parser_internal.h"
26
27
typedef struct JPEGXSParseContext {
28
    ParseContext pc;
29
30
    int eoc_found;
31
} JPEGXSParseContext;
32
33
/**
34
 * Find the end of the current frame in the bitstream.
35
 * @return the position of the first byte of the next frame, or -1
36
 */
37
static int jpegxs_find_frame_end(JPEGXSParseContext *jpegxs, const uint8_t *buf,
38
                                 int buf_size)
39
202
{
40
202
    ParseContext *pc = &jpegxs->pc;
41
202
    int pic_found, i = 0;
42
202
    uint32_t state;
43
44
202
    pic_found = pc->frame_start_found;
45
202
    state = pc->state;
46
47
202
    if (!pic_found) {
48
56
        for (i = 0; i < buf_size; i++) {
49
52
            state = (state << 8) | buf[i];
50
52
            if ((uint16_t)state == JPEGXS_MARKER_SOC) {
51
26
                i++;
52
26
                pic_found = 1;
53
26
                break;
54
26
            }
55
52
        }
56
30
    }
57
58
202
    if (buf_size == 0) {
59
52
        if (jpegxs->eoc_found) {
60
4
            pc->frame_start_found = jpegxs->eoc_found = 0;
61
4
            pc->state = -1;
62
4
        }
63
52
        return 0;
64
52
    }
65
66
360
    while (pic_found && i < buf_size) {
67
210
        if (jpegxs->eoc_found) {
68
120
            for(; i < buf_size; i++) {
69
120
                state = (state << 8) | buf[i];
70
120
                if ((state >> 16) == JPEGXS_MARKER_EOC) {
71
60
                    if ((uint16_t)state == JPEGXS_MARKER_SOC) {
72
                        // New image
73
0
                        pc->frame_start_found = jpegxs->eoc_found = 0;
74
0
                        pc->state = -1;
75
0
                        return i - 1;
76
60
                    } else {
77
                        // False positive
78
60
                        i++;
79
60
                        jpegxs->eoc_found = 0;
80
60
                        break;
81
60
                    }
82
60
                }
83
120
            }
84
60
        }
85
86
546k
        for(; i < buf_size; i++) {
87
546k
            state = (state << 8) | buf[i];
88
546k
            if ((uint16_t)state == JPEGXS_MARKER_EOC) {
89
                // EOC candidate
90
64
                i++;
91
64
                jpegxs->eoc_found = 1;
92
64
                break;
93
64
            }
94
546k
        }
95
210
    }
96
97
150
    pc->frame_start_found = pic_found;
98
150
    pc->state = state;
99
150
    return END_NOT_FOUND;
100
150
}
101
102
static int jpegxs_parse_frame(AVCodecParserContext *s, AVCodecContext *avctx,
103
                              const uint8_t *buf, int buf_size)
104
52
{
105
52
    GetByteContext gbc;
106
52
    GetBitContext gb;
107
52
    int8_t bpc[3], log2_chroma_w[3], log2_chroma_h[3];
108
52
    int size, marker, components;
109
110
52
    s->key_frame = 1;
111
52
    s->pict_type = AV_PICTURE_TYPE_I;
112
113
52
    if (buf_size < 4)
114
26
        return 0;
115
116
26
    bytestream2_init(&gbc, buf, buf_size);
117
26
    marker = bytestream2_get_be16(&gbc);
118
26
    if (marker != JPEGXS_MARKER_SOC)
119
0
        return 0;
120
121
26
    marker = bytestream2_get_be16(&gbc);
122
26
    if (marker != JPEGXS_MARKER_CAP)
123
0
        return 0;
124
26
    size = bytestream2_get_be16(&gbc);
125
26
    bytestream2_skip(&gbc, FFMAX(size - 2, 0));
126
127
26
    marker = bytestream2_get_be16(&gbc);
128
26
    if (marker != JPEGXS_MARKER_PIH)
129
6
        return 0;
130
20
    size = bytestream2_get_be16(&gbc);
131
20
    bytestream2_skip(&gbc, 4); // Lcod
132
20
    bytestream2_skip(&gbc, 2); // Ppih
133
20
    bytestream2_skip(&gbc, 2); // Plev
134
20
    size -= 8;
135
136
20
    s->width  = bytestream2_get_be16(&gbc);
137
20
    s->height = bytestream2_get_be16(&gbc);
138
20
    size -= 4;
139
140
20
    bytestream2_skip(&gbc, 2); // Cw
141
20
    bytestream2_skip(&gbc, 2); // Hsl
142
20
    size -= 4;
143
144
20
    components = bytestream2_get_byte(&gbc);
145
20
    if (components != 1 && components != 3)
146
2
        return 0;
147
18
    size--;
148
149
18
    bytestream2_skip(&gbc, FFMAX(size - 2, 0));
150
151
27
    while (bytestream2_get_bytes_left(&gbc) > 0) {
152
20
        marker = bytestream2_get_be16(&gbc);
153
154
20
        switch(marker) {
155
11
        case JPEGXS_MARKER_CDT:
156
11
            size = bytestream2_get_be16(&gbc);
157
11
            init_get_bits8(&gb, gbc.buffer, FFMIN(FFMAX(size - 2, 0), bytestream2_get_bytes_left(&gbc)));
158
159
31
            for (int i = 0; i < components; i++) {
160
24
                bpc[i] = get_bits(&gb, 8);
161
24
                if (i && bpc[i] != bpc[i-1])
162
3
                    return 0;
163
164
21
                log2_chroma_w[i] = get_bits(&gb, 4);
165
21
                log2_chroma_h[i] = get_bits(&gb, 4);
166
167
21
                if (log2_chroma_h[i] > log2_chroma_w[i])
168
1
                    return 0;
169
20
                if (i == 2 && (log2_chroma_h[2] != log2_chroma_h[1] ||
170
5
                               log2_chroma_w[2] != log2_chroma_w[1]))
171
0
                    return 0;
172
20
            }
173
174
7
            switch (bpc[0]) {
175
6
            case 8:
176
6
                if (components == 1)                                     s->format = AV_PIX_FMT_GRAY8;
177
5
                else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P;
178
0
                else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P;
179
0
                else                                                     s->format = AV_PIX_FMT_YUV420P;
180
6
                break;
181
0
            case 10:
182
0
                if (components == 1)                                     s->format = AV_PIX_FMT_GRAY10;
183
0
                else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P10;
184
0
                else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P10;
185
0
                else                                                     s->format = AV_PIX_FMT_YUV420P10;
186
0
                break;
187
0
            case 12:
188
0
                if (components == 1)                                     s->format = AV_PIX_FMT_GRAY12;
189
0
                else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P12;
190
0
                else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P12;
191
0
                else                                                     s->format = AV_PIX_FMT_YUV420P12;
192
0
                break;
193
0
            case 14:
194
0
                if (components == 1)                                     s->format = AV_PIX_FMT_GRAY14;
195
0
                else if (log2_chroma_w[1] == 1 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV444P14;
196
0
                else if (log2_chroma_w[1] == 2 && log2_chroma_h[1] == 1) s->format = AV_PIX_FMT_YUV422P14;
197
0
                else                                                     s->format = AV_PIX_FMT_YUV420P14;
198
0
                break;
199
1
            default:
200
1
                s->format = AV_PIX_FMT_NONE;
201
1
                break;
202
7
            }
203
7
            return 0;
204
9
        default:
205
9
            size = bytestream2_get_be16(&gbc);
206
9
            bytestream2_skip(&gbc, FFMAX(size - 2, 0));
207
9
            break;
208
20
        }
209
20
    }
210
211
7
    return 0;
212
18
}
213
214
static int jpegxsvideo_parse(AVCodecParserContext *s,
215
                             AVCodecContext *avctx,
216
                             const uint8_t **poutbuf, int *poutbuf_size,
217
                             const uint8_t *buf, int buf_size)
218
202
{
219
202
    JPEGXSParseContext *jpegxs = s->priv_data;
220
202
    ParseContext *pc = &jpegxs->pc;
221
202
    int next;
222
223
202
    next = jpegxs_find_frame_end(jpegxs, buf, buf_size);
224
225
202
    if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
226
150
        *poutbuf = NULL;
227
150
        *poutbuf_size = 0;
228
150
        return buf_size;
229
150
    }
230
231
52
    jpegxs_parse_frame(s, avctx, buf, buf_size);
232
233
52
    *poutbuf = buf;
234
52
    *poutbuf_size = buf_size;
235
52
    return next;
236
202
}
237
238
static av_cold void jpegxsparse_close(AVCodecParserContext *s)
239
26
{
240
26
    JPEGXSParseContext *jpegxs = s->priv_data;
241
26
    ParseContext *pc = &jpegxs->pc;
242
243
26
    av_freep(&pc->buffer);
244
26
}
245
246
const FFCodecParser ff_jpegxs_parser = {
247
    PARSER_CODEC_LIST(AV_CODEC_ID_JPEGXS),
248
    .priv_data_size = sizeof(JPEGXSParseContext),
249
    .parse          = jpegxsvideo_parse,
250
    .close          = jpegxsparse_close,
251
};