FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/hdrdec.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 0 117 0.0%
Functions: 0 4 0.0%
Branches: 0 92 0.0%

Line Branch Exec 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 #define MINELEN 8
28 #define MAXELEN 0x7fff
29
30 static int hdr_get_line(GetByteContext *gb, uint8_t *buffer, int size)
31 {
32 int n = 0, c;
33
34 memset(buffer, 0, size);
35
36 do {
37 c = bytestream2_get_byte(gb);
38 if (n < size - 1)
39 buffer[n++] = c;
40 } while (bytestream2_get_bytes_left(gb) > 0 && c != '\n');
41
42 return 0;
43 }
44
45 static float convert(int expo, int val)
46 {
47 if (expo == -128) {
48 return 0.f;
49 } else {
50 const float v = val / 256.f;
51
52 return ldexpf(v, expo);
53 }
54 }
55
56 static int decompress(uint8_t *scanline, int w, GetByteContext *gb, const uint8_t *start)
57 {
58 int rshift = 0;
59
60 while (w > 0) {
61 if (bytestream2_get_bytes_left(gb) < 4)
62 return AVERROR_INVALIDDATA;
63 scanline[0] = bytestream2_get_byte(gb);
64 scanline[1] = bytestream2_get_byte(gb);
65 scanline[2] = bytestream2_get_byte(gb);
66 scanline[3] = bytestream2_get_byte(gb);
67
68 if (scanline[0] == 1 &&
69 scanline[1] == 1 &&
70 scanline[2] == 1) {
71 int run = scanline[3];
72 for (int i = run << rshift; i > 0 && w > 0 && scanline >= start + 4; i--) {
73 memcpy(scanline, scanline - 4, 4);
74 scanline += 4;
75 w -= 4;
76 }
77 rshift += 8;
78 if (rshift > 16)
79 break;
80 } else {
81 scanline += 4;
82 w--;
83 rshift = 0;
84 }
85 }
86
87 return 1;
88 }
89
90 static int hdr_decode_frame(AVCodecContext *avctx, AVFrame *p,
91 int *got_frame, AVPacket *avpkt)
92 {
93 int width = 0, height = 0;
94 GetByteContext gb;
95 uint8_t line[512];
96 float sar;
97 int ret;
98
99 bytestream2_init(&gb, avpkt->data, avpkt->size);
100 hdr_get_line(&gb, line, sizeof(line));
101 if (memcmp("#?RADIANCE\n", line, 11))
102 return AVERROR_INVALIDDATA;
103
104 do {
105 hdr_get_line(&gb, line, sizeof(line));
106 if (sscanf(line, "PIXASPECT=%f\n", &sar) == 1)
107 avctx->sample_aspect_ratio = p->sample_aspect_ratio = av_inv_q(av_d2q(sar, 4096));
108 } while (line[0] != '\n' && line[0]);
109
110 hdr_get_line(&gb, line, sizeof(line));
111 if (sscanf(line, "-Y %d +X %d\n", &height, &width) == 2) {
112 ;
113 } else if (sscanf(line, "+Y %d +X %d\n", &height, &width) == 2) {
114 ;
115 } else if (sscanf(line, "-Y %d -X %d\n", &height, &width) == 2) {
116 ;
117 } else if (sscanf(line, "+Y %d -X %d\n", &height, &width) == 2) {
118 ;
119 } else if (sscanf(line, "-X %d +Y %d\n", &width, &height) == 2) {
120 ;
121 } else if (sscanf(line, "+X %d +Y %d\n", &width, &height) == 2) {
122 ;
123 } else if (sscanf(line, "-X %d -Y %d\n", &width, &height) == 2) {
124 ;
125 } else if (sscanf(line, "+X %d -Y %d\n", &width, &height) == 2) {
126 ;
127 }
128
129 if ((ret = ff_set_dimensions(avctx, width, height)) < 0)
130 return ret;
131
132 avctx->pix_fmt = AV_PIX_FMT_GBRPF32;
133
134 if (avctx->skip_frame >= AVDISCARD_ALL)
135 return avpkt->size;
136
137 if ((ret = ff_thread_get_buffer(avctx, p, 0)) < 0)
138 return ret;
139
140 for (int y = 0; y < height; y++) {
141 float *dst_r = (float *)(p->data[2] + y * p->linesize[2]);
142 float *dst_g = (float *)(p->data[0] + y * p->linesize[0]);
143 float *dst_b = (float *)(p->data[1] + y * p->linesize[1]);
144 uint8_t *scanline = p->data[0] + y * p->linesize[0];
145 int i;
146
147 if (width < MINELEN || width > MAXELEN) {
148 ret = decompress(scanline, width, &gb, scanline);
149 if (ret < 0)
150 return ret;
151 goto convert;
152 }
153
154 i = bytestream2_peek_byte(&gb);
155 if (i != 2) {
156 ret = decompress(scanline, width, &gb, scanline);
157 if (ret < 0)
158 return ret;
159 goto convert;
160 }
161 bytestream2_skip(&gb, 1);
162
163 scanline[1] = bytestream2_get_byte(&gb);
164 scanline[2] = bytestream2_get_byte(&gb);
165 i = bytestream2_get_byte(&gb);
166
167 if (scanline[1] != 2 || scanline[2] & 128) {
168 scanline[0] = 2;
169 scanline[3] = i;
170 ret = decompress(scanline + 4, width - 1, &gb, scanline);
171 if (ret < 0)
172 return ret;
173 goto convert;
174 }
175
176 for (int i = 0; i < 4; i++) {
177 uint8_t *scanline = p->data[0] + y * p->linesize[0] + i;
178
179 for (int j = 0; j < width * 4 && bytestream2_get_bytes_left(&gb) > 0;) {
180 int run = bytestream2_get_byte(&gb);
181 if (run > 128) {
182 uint8_t val = bytestream2_get_byte(&gb);
183 run &= 127;
184 while (run--) {
185 if (j >= width * 4)
186 break;
187 scanline[j] = val;
188 j += 4;
189 }
190 } else if (run > 0) {
191 while (run--) {
192 if (j >= width * 4)
193 break;
194 scanline[j] = bytestream2_get_byte(&gb);
195 j += 4;
196 }
197 }
198 }
199 }
200
201 convert:
202 for (int x = 0; x < width; x++) {
203 uint8_t rgbe[4];
204 int expo;
205
206 memcpy(rgbe, p->data[0] + y * p->linesize[0] + x * 4, 4);
207 expo = rgbe[3] - 128;
208
209 dst_r[x] = convert(expo, rgbe[0]);
210 dst_b[x] = convert(expo, rgbe[2]);
211 dst_g[x] = convert(expo, rgbe[1]);
212 }
213 }
214
215 *got_frame = 1;
216
217 return avpkt->size;
218 }
219
220 const FFCodec ff_hdr_decoder = {
221 .p.name = "hdr",
222 CODEC_LONG_NAME("HDR (Radiance RGBE format) image"),
223 .p.type = AVMEDIA_TYPE_VIDEO,
224 .p.id = AV_CODEC_ID_RADIANCE_HDR,
225 .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
226 .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM,
227 FF_CODEC_DECODE_CB(hdr_decode_frame),
228 };
229