Coverage Report

Created: 2026-10-28 08:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ffmpeg/libavcodec/hdrdec.c
Line
Count
Source
1
/*
2
 * Radiance HDR image format
3
 *
4
 * This file is part of FFmpeg.
5
 *
6
 * FFmpeg is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2.1 of the License, or (at your option) any later version.
10
 *
11
 * FFmpeg is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with FFmpeg; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
 */
20
21
#include "avcodec.h"
22
#include "bytestream.h"
23
#include "codec_internal.h"
24
#include "decode.h"
25
#include "thread.h"
26
27
1.84M
#define MINELEN 8
28
82.3k
#define MAXELEN 0x7fff
29
30
static int hdr_get_line(GetByteContext *gb, uint8_t *buffer, int size)
31
831k
{
32
831k
    int n = 0, c;
33
34
831k
    memset(buffer, 0, size);
35
36
7.09M
    do {
37
7.09M
        c = bytestream2_get_byte(gb);
38
7.09M
        if (n < size - 1)
39
5.80M
            buffer[n++] = c;
40
7.09M
    } while (bytestream2_get_bytes_left(gb) > 0 && c != '\n');
41
42
831k
    return 0;
43
831k
}
44
45
static float convert(int expo, int val)
46
286M
{
47
286M
    if (expo == -128) {
48
221M
        return 0.f;
49
221M
    } else {
50
65.5M
        const float v = val / 256.f;
51
52
65.5M
        return ldexpf(v, expo);
53
65.5M
    }
54
286M
}
55
56
static int decompress(uint8_t *scanline, int w, GetByteContext *gb, const uint8_t *start)
57
917k
{
58
917k
    int rshift = 0;
59
60
2.89M
    while (w > 0) {
61
1.98M
        if (bytestream2_get_bytes_left(gb) < 4)
62
5.93k
            return AVERROR_INVALIDDATA;
63
1.98M
        scanline[0] = bytestream2_get_byte(gb);
64
1.98M
        scanline[1] = bytestream2_get_byte(gb);
65
1.98M
        scanline[2] = bytestream2_get_byte(gb);
66
1.98M
        scanline[3] = bytestream2_get_byte(gb);
67
68
1.98M
        if (scanline[0] == 1 &&
69
77.9k
            scanline[1] == 1 &&
70
21.9k
            scanline[2] == 1) {
71
18.7k
            int run = scanline[3];
72
24.6M
            for (int i = run << rshift; i > 0 && w > 0 && scanline >= start + 4; i--) {
73
24.6M
                memcpy(scanline, scanline - 4, 4);
74
24.6M
                scanline += 4;
75
24.6M
                w--;
76
24.6M
            }
77
18.7k
            rshift += 8;
78
18.7k
            if (rshift > 16)
79
4.72k
                break;
80
1.96M
        } else {
81
1.96M
            scanline += 4;
82
1.96M
            w--;
83
1.96M
            rshift = 0;
84
1.96M
        }
85
1.98M
    }
86
87
911k
    return 1;
88
917k
}
89
90
static int hdr_decode_frame(AVCodecContext *avctx, AVFrame *p,
91
                            int *got_frame, AVPacket *avpkt)
92
313k
{
93
313k
    int width = 0, height = 0;
94
313k
    GetByteContext gb;
95
313k
    uint8_t line[512];
96
313k
    float sar;
97
313k
    int ret;
98
99
313k
    bytestream2_init(&gb, avpkt->data, avpkt->size);
100
313k
    hdr_get_line(&gb, line, sizeof(line));
101
313k
    if (memcmp("#?RADIANCE\n", line, 11) && memcmp("#?RGBE\n", line, 7))
102
62.2k
        return AVERROR_INVALIDDATA;
103
104
266k
    do {
105
266k
        hdr_get_line(&gb, line, sizeof(line));
106
266k
        if (sscanf(line, "PIXASPECT=%f\n", &sar) == 1)
107
6.15k
            avctx->sample_aspect_ratio = p->sample_aspect_ratio = av_inv_q(av_d2q(sar, 4096));
108
266k
    } while (line[0] != '\n' && line[0]);
109
110
251k
    hdr_get_line(&gb, line, sizeof(line));
111
251k
    if (sscanf(line, "-Y %d +X %d\n", &height, &width) == 2) {
112
394
        ;
113
250k
    } else if (sscanf(line, "+Y %d +X %d\n", &height, &width) == 2) {
114
279
        ;
115
250k
    } else if (sscanf(line, "-Y %d -X %d\n", &height, &width) == 2) {
116
225k
        ;
117
225k
    } else if (sscanf(line, "+Y %d -X %d\n", &height, &width) == 2) {
118
224
        ;
119
24.5k
    } else if (sscanf(line, "-X %d +Y %d\n", &width, &height) == 2) {
120
738
        ;
121
23.7k
    } else if (sscanf(line, "+X %d +Y %d\n", &width, &height) == 2) {
122
9.02k
        ;
123
14.7k
    } else if (sscanf(line, "-X %d -Y %d\n", &width, &height) == 2) {
124
308
        ;
125
14.4k
    } else if (sscanf(line, "+X %d -Y %d\n", &width, &height) == 2) {
126
0
        ;
127
0
    }
128
129
251k
    if (bytestream2_get_bytes_left(&gb) < height * 4)
130
18.8k
        return AVERROR_INVALIDDATA;
131
132
232k
    if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
133
16.3k
        return ret;
134
135
216k
    avctx->pix_fmt = AV_PIX_FMT_GBRPF32;
136
137
216k
    if (avctx->skip_frame >= AVDISCARD_ALL)
138
8.81k
        return avpkt->size;
139
140
207k
    if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
141
0
        return ret;
142
143
1.12M
    for (int y = 0; y < height; y++) {
144
921k
        float *dst_r = (float *)(p->data[2] + y * p->linesize[2]);
145
921k
        float *dst_g = (float *)(p->data[0] + y * p->linesize[0]);
146
921k
        float *dst_b = (float *)(p->data[1] + y * p->linesize[1]);
147
921k
        uint8_t *scanline = p->data[0] + y * p->linesize[0];
148
921k
        int i;
149
150
921k
        if (width < MINELEN || width > MAXELEN) {
151
840k
            ret = decompress(scanline, width, &gb, scanline);
152
840k
            if (ret < 0)
153
497
                return ret;
154
840k
            goto convert;
155
840k
        }
156
157
80.5k
        i = bytestream2_peek_byte(&gb);
158
80.5k
        if (i != 2) {
159
74.0k
            ret = decompress(scanline, width, &gb, scanline);
160
74.0k
            if (ret < 0)
161
4.56k
                return ret;
162
69.5k
            goto convert;
163
74.0k
        }
164
6.46k
        bytestream2_skip(&gb, 1);
165
166
6.46k
        scanline[1] = bytestream2_get_byte(&gb);
167
6.46k
        scanline[2] = bytestream2_get_byte(&gb);
168
6.46k
        i = bytestream2_get_byte(&gb);
169
170
6.46k
        if (scanline[1] != 2 || scanline[2] & 128) {
171
2.03k
            scanline[0] = 2;
172
2.03k
            scanline[3] = i;
173
2.03k
            ret = decompress(scanline + 4, width - 1, &gb, scanline);
174
2.03k
            if (ret < 0)
175
873
                return ret;
176
1.16k
            goto convert;
177
2.03k
        }
178
179
22.1k
        for (int i = 0; i < 4; i++) {
180
17.7k
            uint8_t *scanline = p->data[0] + y * p->linesize[0] + i;
181
182
67.0k
            for (int j = 0; j < width * 4 && bytestream2_get_bytes_left(&gb) > 0;) {
183
49.3k
                int run = bytestream2_get_byte(&gb);
184
49.3k
                if (run > 128) {
185
7.36k
                    uint8_t val = bytestream2_get_byte(&gb);
186
7.36k
                    run &= 127;
187
241k
                    while (run--) {
188
238k
                        if (j >= width * 4)
189
5.28k
                            break;
190
233k
                        scanline[j] = val;
191
233k
                        j += 4;
192
233k
                    }
193
41.9k
                } else if (run > 0) {
194
265k
                    while (run--) {
195
255k
                        if (j >= width * 4)
196
7.36k
                            break;
197
248k
                        scanline[j] = bytestream2_get_byte(&gb);
198
248k
                        j += 4;
199
248k
                    }
200
17.0k
                }
201
49.3k
            }
202
17.7k
        }
203
204
915k
convert:
205
96.4M
        for (int x = 0; x < width; x++) {
206
95.5M
            uint8_t rgbe[4];
207
95.5M
            int expo;
208
209
95.5M
            memcpy(rgbe, p->data[0] + y * p->linesize[0] + x * 4, 4);
210
95.5M
            expo = rgbe[3] - 128;
211
212
95.5M
            dst_r[x] = convert(expo, rgbe[0]);
213
95.5M
            dst_b[x] = convert(expo, rgbe[2]);
214
95.5M
            dst_g[x] = convert(expo, rgbe[1]);
215
95.5M
        }
216
915k
    }
217
218
201k
    *got_frame   = 1;
219
220
201k
    return avpkt->size;
221
207k
}
222
223
const FFCodec ff_hdr_decoder = {
224
    .p.name         = "hdr",
225
    CODEC_LONG_NAME("HDR (Radiance RGBE format) image"),
226
    .p.type         = AVMEDIA_TYPE_VIDEO,
227
    .p.id           = AV_CODEC_ID_RADIANCE_HDR,
228
    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
229
    .caps_internal  = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
230
    FF_CODEC_DECODE_CB(hdr_decode_frame),
231
};