Coverage Report

Created: 2026-01-16 07:48

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
40
{
40
40
    ParseContext *pc = &jpegxs->pc;
41
40
    int pic_found, i = 0;
42
40
    uint32_t state;
43
44
40
    pic_found = pc->frame_start_found;
45
40
    state = pc->state;
46
47
40
    if (!pic_found) {
48
6
        for (i = 0; i < buf_size; i++) {
49
4
            state = (state << 8) | buf[i];
50
4
            if ((uint16_t)state == JPEGXS_MARKER_SOC) {
51
2
                i++;
52
2
                pic_found = 1;
53
2
                break;
54
2
            }
55
4
        }
56
4
    }
57
58
40
    if (buf_size == 0) {
59
4
        if (jpegxs->eoc_found) {
60
2
            pc->frame_start_found = jpegxs->eoc_found = 0;
61
2
            pc->state = -1;
62
2
        }
63
4
        return 0;
64
4
    }
65
66
74
    while (pic_found && i < buf_size) {
67
38
        if (jpegxs->eoc_found) {
68
4
            for(; i < buf_size; i++) {
69
4
                state = (state << 8) | buf[i];
70
4
                if ((state >> 16) == JPEGXS_MARKER_EOC) {
71
2
                    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
2
                    } else {
77
                        // False positive
78
2
                        i++;
79
2
                        jpegxs->eoc_found = 0;
80
2
                        break;
81
2
                    }
82
2
                }
83
4
            }
84
2
        }
85
86
147k
        for(; i < buf_size; i++) {
87
147k
            state = (state << 8) | buf[i];
88
147k
            if ((uint16_t)state == JPEGXS_MARKER_EOC) {
89
                // EOC candidate
90
4
                i++;
91
4
                jpegxs->eoc_found = 1;
92
4
                break;
93
4
            }
94
147k
        }
95
38
    }
96
97
36
    pc->frame_start_found = pic_found;
98
36
    pc->state = state;
99
36
    return END_NOT_FOUND;
100
36
}
101
102
static int jpegxs_parse_frame(AVCodecParserContext *s, AVCodecContext *avctx,
103
                              const uint8_t *buf, int buf_size)
104
4
{
105
4
    GetByteContext gbc;
106
4
    GetBitContext gb;
107
4
    int8_t bpc[3], log2_chroma_w[3], log2_chroma_h[3];
108
4
    int size, marker, components;
109
110
4
    s->key_frame = 1;
111
4
    s->pict_type = AV_PICTURE_TYPE_I;
112
113
4
    if (buf_size < 4)
114
2
        return 0;
115
116
2
    bytestream2_init(&gbc, buf, buf_size);
117
2
    marker = bytestream2_get_be16(&gbc);
118
2
    if (marker != JPEGXS_MARKER_SOC)
119
0
        return 0;
120
121
2
    marker = bytestream2_get_be16(&gbc);
122
2
    if (marker != JPEGXS_MARKER_CAP)
123
0
        return 0;
124
2
    size = bytestream2_get_be16(&gbc);
125
2
    bytestream2_skip(&gbc, FFMAX(size - 2, 0));
126
127
2
    marker = bytestream2_get_be16(&gbc);
128
2
    if (marker != JPEGXS_MARKER_PIH)
129
0
        return 0;
130
2
    size = bytestream2_get_be16(&gbc);
131
2
    bytestream2_skip(&gbc, 4); // Lcod
132
2
    bytestream2_skip(&gbc, 2); // Ppih
133
2
    bytestream2_skip(&gbc, 2); // Plev
134
2
    size -= 8;
135
136
2
    s->width  = bytestream2_get_be16(&gbc);
137
2
    s->height = bytestream2_get_be16(&gbc);
138
2
    size -= 4;
139
140
2
    bytestream2_skip(&gbc, 2); // Cw
141
2
    bytestream2_skip(&gbc, 2); // Hsl
142
2
    size -= 4;
143
144
2
    components = bytestream2_get_byte(&gbc);
145
2
    if (components != 1 && components != 3)
146
0
        return 0;
147
2
    size--;
148
149
2
    bytestream2_skip(&gbc, FFMAX(size - 2, 0));
150
151
2
    while (bytestream2_get_bytes_left(&gbc) > 0) {
152
2
        marker = bytestream2_get_be16(&gbc);
153
154
2
        switch(marker) {
155
2
        case JPEGXS_MARKER_CDT:
156
2
            size = bytestream2_get_be16(&gbc);
157
2
            init_get_bits8(&gb, gbc.buffer, FFMIN(FFMAX(size - 2, 0), bytestream2_get_bytes_left(&gbc)));
158
159
8
            for (int i = 0; i < components; i++) {
160
6
                bpc[i] = get_bits(&gb, 8);
161
6
                if (i && bpc[i] != bpc[i-1])
162
0
                    return 0;
163
164
6
                log2_chroma_w[i] = get_bits(&gb, 4);
165
6
                log2_chroma_h[i] = get_bits(&gb, 4);
166
167
6
                if (log2_chroma_h[i] > log2_chroma_w[i])
168
0
                    return 0;
169
6
                if (i == 2 && (log2_chroma_h[2] != log2_chroma_h[1] ||
170
2
                               log2_chroma_w[2] != log2_chroma_w[1]))
171
0
                    return 0;
172
6
            }
173
174
2
            switch (bpc[0]) {
175
2
            case 8:
176
2
                if (components == 1)                                     s->format = AV_PIX_FMT_GRAY8;
177
2
                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
2
                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
0
            default:
200
0
                s->format = AV_PIX_FMT_NONE;
201
0
                break;
202
2
            }
203
2
            return 0;
204
0
        default:
205
0
            size = bytestream2_get_be16(&gbc);
206
0
            bytestream2_skip(&gbc, FFMAX(size - 2, 0));
207
0
            break;
208
2
        }
209
2
    }
210
211
0
    return 0;
212
2
}
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
40
{
219
40
    JPEGXSParseContext *jpegxs = s->priv_data;
220
40
    ParseContext *pc = &jpegxs->pc;
221
40
    int next;
222
223
40
    next = jpegxs_find_frame_end(jpegxs, buf, buf_size);
224
225
40
    if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
226
36
        *poutbuf = NULL;
227
36
        *poutbuf_size = 0;
228
36
        return buf_size;
229
36
    }
230
231
4
    jpegxs_parse_frame(s, avctx, buf, buf_size);
232
233
4
    *poutbuf = buf;
234
4
    *poutbuf_size = buf_size;
235
4
    return next;
236
40
}
237
238
static av_cold void jpegxsparse_close(AVCodecParserContext *s)
239
2
{
240
2
    JPEGXSParseContext *jpegxs = s->priv_data;
241
2
    ParseContext *pc = &jpegxs->pc;
242
243
2
    av_freep(&pc->buffer);
244
2
}
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
};