Coverage Report

Created: 2026-09-14 08:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/pgxdec.c
Line
Count
Source
1
/*
2
 * PGX image format
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
#include "avcodec.h"
23
#include "bytestream.h"
24
#include "codec_internal.h"
25
#include "decode.h"
26
27
427k
static int pgx_get_number(AVCodecContext *avctx, GetByteContext *g, int *number) {
28
427k
    int ret = AVERROR_INVALIDDATA;
29
427k
    char digit;
30
31
427k
    *number = 0;
32
877k
    while (1) {
33
877k
        uint64_t temp;
34
877k
        if (bytestream2_get_bytes_left(g) <= 0)
35
1.10k
            return AVERROR_INVALIDDATA;
36
876k
        digit = bytestream2_get_byteu(g);
37
876k
        if (digit == ' ' || digit == 0xA || digit == 0xD)
38
415k
            break;
39
461k
        else if (digit < '0' || digit > '9')
40
9.34k
            return AVERROR_INVALIDDATA;
41
42
452k
        temp = (uint64_t)10 * (*number) + (digit - '0');
43
452k
        if (temp > INT_MAX)
44
1.25k
            return AVERROR_INVALIDDATA;
45
450k
        *number = temp;
46
450k
        ret = 0;
47
450k
    }
48
49
415k
    return ret;
50
427k
}
51
52
static int pgx_decode_header(AVCodecContext *avctx, GetByteContext *g,
53
                             int *depth, int *width, int *height,
54
                             int *sign)
55
270k
{
56
270k
    int byte;
57
58
270k
    if (bytestream2_get_bytes_left(g) < 12)
59
121k
        return AVERROR_INVALIDDATA;
60
61
148k
    bytestream2_skipu(g, 6);
62
63
    // Is the component signed?
64
148k
    byte = bytestream2_peek_byteu(g);
65
148k
    if (byte == '+') {
66
531
        *sign = 0;
67
531
        bytestream2_skipu(g, 1);
68
147k
    } else if (byte == '-') {
69
912
        *sign = 1;
70
912
        bytestream2_skipu(g, 1);
71
912
    }
72
73
148k
    byte = bytestream2_peek_byteu(g);
74
148k
    if (byte == ' ')
75
226
        bytestream2_skipu(g, 1);
76
77
148k
    if (pgx_get_number(avctx, g, depth))
78
7.94k
        goto error;
79
140k
    if (pgx_get_number(avctx, g, width))
80
2.61k
        goto error;
81
137k
    if (pgx_get_number(avctx, g, height))
82
2.57k
        goto error;
83
84
135k
    if (bytestream2_peek_byte(g) == 0xA)
85
771
        bytestream2_skip(g, 1);
86
135k
    return 0;
87
88
13.1k
error:
89
13.1k
    av_log(avctx, AV_LOG_ERROR, "Error in decoding header.\n");
90
13.1k
    return AVERROR_INVALIDDATA;
91
137k
}
92
93
#define WRITE_FRAME(D, PIXEL, suffix)                                                       \
94
    static inline void write_frame_ ##D(AVFrame *frame, GetByteContext *g, \
95
                                        int width, int height, int sign, int depth)         \
96
128k
    {                                                                                       \
97
128k
        const unsigned offset = sign ? (1 << (D - 1)) : 0;                                  \
98
128k
        int i, j;                                                                           \
99
1.86M
        for (i = 0; i < height; i++) {                                                      \
100
1.73M
            PIXEL *line = (PIXEL*)(frame->data[0] + i * frame->linesize[0]);                \
101
13.9M
            for (j = 0; j < width; j++) {                                                   \
102
12.2M
                unsigned val = bytestream2_get_ ##suffix##u(g) << (D - depth);              \
103
12.2M
                val ^= offset;                                                              \
104
12.2M
                *(line + j) = val;                                                          \
105
12.2M
            }                                                                               \
106
1.73M
        }                                                                                   \
107
128k
    }                                                                                       \
pgxdec.c:write_frame_8
Line
Count
Source
96
125k
    {                                                                                       \
97
125k
        const unsigned offset = sign ? (1 << (D - 1)) : 0;                                  \
98
125k
        int i, j;                                                                           \
99
1.77M
        for (i = 0; i < height; i++) {                                                      \
100
1.64M
            PIXEL *line = (PIXEL*)(frame->data[0] + i * frame->linesize[0]);                \
101
13.7M
            for (j = 0; j < width; j++) {                                                   \
102
12.0M
                unsigned val = bytestream2_get_ ##suffix##u(g) << (D - depth);              \
103
12.0M
                val ^= offset;                                                              \
104
12.0M
                *(line + j) = val;                                                          \
105
12.0M
            }                                                                               \
106
1.64M
        }                                                                                   \
107
125k
    }                                                                                       \
pgxdec.c:write_frame_16
Line
Count
Source
96
2.07k
    {                                                                                       \
97
2.07k
        const unsigned offset = sign ? (1 << (D - 1)) : 0;                                  \
98
2.07k
        int i, j;                                                                           \
99
85.8k
        for (i = 0; i < height; i++) {                                                      \
100
83.7k
            PIXEL *line = (PIXEL*)(frame->data[0] + i * frame->linesize[0]);                \
101
241k
            for (j = 0; j < width; j++) {                                                   \
102
157k
                unsigned val = bytestream2_get_ ##suffix##u(g) << (D - depth);              \
103
157k
                val ^= offset;                                                              \
104
157k
                *(line + j) = val;                                                          \
105
157k
            }                                                                               \
106
83.7k
        }                                                                                   \
107
2.07k
    }                                                                                       \
108
109
WRITE_FRAME(8, uint8_t, byte)
110
WRITE_FRAME(16, uint16_t, be16)
111
112
static int pgx_decode_frame(AVCodecContext *avctx, AVFrame *p,
113
                            int *got_frame, AVPacket *avpkt)
114
270k
{
115
270k
    int ret;
116
270k
    int bpp;
117
270k
    int width, height, depth;
118
270k
    int sign = 0;
119
270k
    GetByteContext g;
120
270k
    bytestream2_init(&g, avpkt->data, avpkt->size);
121
122
270k
    if ((ret = pgx_decode_header(avctx, &g, &depth, &width, &height, &sign)) < 0)
123
134k
        return ret;
124
125
135k
    if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
126
1.87k
        return ret;
127
128
133k
    if (depth > 0 && depth <= 8) {
129
128k
        avctx->pix_fmt = AV_PIX_FMT_GRAY8;
130
128k
        bpp = 8;
131
128k
    } else if (depth > 0 && depth <= 16) {
132
2.36k
        avctx->pix_fmt = AV_PIX_FMT_GRAY16;
133
2.36k
        bpp = 16;
134
2.51k
    } else {
135
2.51k
        av_log(avctx, AV_LOG_ERROR, "depth %d is invalid or unsupported.\n", depth);
136
2.51k
        return AVERROR_PATCHWELCOME;
137
2.51k
    }
138
131k
    if (bytestream2_get_bytes_left(&g) < width * height * (bpp >> 3))
139
3.00k
        return AVERROR_INVALIDDATA;
140
128k
    if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
141
0
        return ret;
142
128k
    avctx->bits_per_raw_sample = depth;
143
128k
    if (bpp == 8)
144
125k
        write_frame_8(p, &g, width, height, sign, depth);
145
2.07k
    else if (bpp == 16)
146
2.07k
        write_frame_16(p, &g, width, height, sign, depth);
147
128k
    *got_frame = 1;
148
128k
    return 0;
149
128k
}
150
151
const FFCodec ff_pgx_decoder = {
152
    .p.name         = "pgx",
153
    CODEC_LONG_NAME("PGX (JPEG2000 Test Format)"),
154
    .p.type         = AVMEDIA_TYPE_VIDEO,
155
    .p.id           = AV_CODEC_ID_PGX,
156
    .p.capabilities = AV_CODEC_CAP_DR1,
157
    FF_CODEC_DECODE_CB(pgx_decode_frame),
158
};