2 * Radiance HDR image format
4 * This file is part of FFmpeg.
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.
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.
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
21 #include "libavutil/mem.h"
23 #include "bytestream.h"
24 #include "codec_internal.h"
27 typedef struct HDREncContext
{
31 static av_cold
int hdr_encode_init(AVCodecContext
*avctx
)
33 HDREncContext
*s
= avctx
->priv_data
;
35 s
->scanline
= av_calloc(avctx
->width
* 4, sizeof(*s
->scanline
));
37 return AVERROR(ENOMEM
);
42 static av_cold
int hdr_encode_close(AVCodecContext
*avctx
)
44 HDREncContext
*s
= avctx
->priv_data
;
46 av_freep(&s
->scanline
);
51 static void bytestream_put_str(uint8_t **buf
, const char *const line
)
53 bytestream_put_buffer(buf
, line
, strlen(line
));
56 static void float2rgbe(uint8_t *rgbe
, float red
, float green
, float blue
)
61 v
= FFMAX3(red
, green
, blue
);
64 rgbe
[0] = rgbe
[1] = rgbe
[2] = rgbe
[3] = 0;
66 v
= frexpf(v
, &e
) * 256.f
/ v
;
68 rgbe
[0] = av_clip_uint8(red
* v
);
69 rgbe
[1] = av_clip_uint8(green
* v
);
70 rgbe
[2] = av_clip_uint8(blue
* v
);
71 rgbe
[3] = av_clip_uint8(e
+ 128);
75 static void rle(uint8_t **buffer
, const uint8_t *data
, int width
)
81 int run_count
= 0, old_run_count
= 0;
85 while (run_count
< MIN_RLE
&& beg_run
< width
) {
87 old_run_count
= run_count
;
89 while ((beg_run
+ run_count
< width
) && (run_count
< 127) &&
90 (data
[beg_run
* 4] == data
[(beg_run
+ run_count
) * 4]))
94 if ((old_run_count
> 1) && (old_run_count
== beg_run
- cur
)) {
95 buf
[0] = 128 + old_run_count
;
96 buf
[1] = data
[cur
* 4];
97 bytestream_put_buffer(buffer
, buf
, sizeof(buf
));
101 while (cur
< beg_run
) {
102 int nonrun_count
= FFMIN(128, beg_run
- cur
);
103 buf
[0] = nonrun_count
;
104 bytestream_put_byte(buffer
, buf
[0]);
105 for (int n
= 0; n
< nonrun_count
; n
++)
106 bytestream_put_byte(buffer
, data
[(cur
+ n
) * 4]);
110 if (run_count
>= MIN_RLE
) {
111 buf
[0] = 128 + run_count
;
112 buf
[1] = data
[beg_run
* 4];
113 bytestream_put_buffer(buffer
, buf
, sizeof(buf
));
119 static int hdr_encode_frame(AVCodecContext
*avctx
, AVPacket
*pkt
,
120 const AVFrame
*frame
, int *got_packet
)
122 HDREncContext
*s
= avctx
->priv_data
;
127 packet_size
= avctx
->height
* 4LL + avctx
->width
* avctx
->height
* 8LL + 1024LL;
128 if ((ret
= ff_get_encode_buffer(avctx
, pkt
, packet_size
, 0)) < 0)
132 bytestream_put_str(&buf
, "#?RADIANCE\n");
133 bytestream_put_str(&buf
, "SOFTWARE=lavc\n");
134 ret
= snprintf(buf
, 32, "PIXASPECT=%f\n", av_q2d(av_inv_q(avctx
->sample_aspect_ratio
)));
137 bytestream_put_str(&buf
, "FORMAT=32-bit_rle_rgbe\n\n");
138 ret
= snprintf(buf
, 32, "-Y %d +X %d\n", avctx
->height
, avctx
->width
);
142 for (int y
= 0; y
< avctx
->height
; y
++) {
143 const float *red
= (const float *)(frame
->data
[2] + y
* frame
->linesize
[2]);
144 const float *green
= (const float *)(frame
->data
[0] + y
* frame
->linesize
[0]);
145 const float *blue
= (const float *)(frame
->data
[1] + y
* frame
->linesize
[1]);
147 if (avctx
->width
< 8 || avctx
->width
> 0x7fff) {
148 for (int x
= 0; x
< avctx
->width
; x
++) {
149 float2rgbe(buf
, red
[x
], green
[x
], blue
[x
]);
153 bytestream_put_byte(&buf
, 2);
154 bytestream_put_byte(&buf
, 2);
155 bytestream_put_byte(&buf
, avctx
->width
>> 8);
156 bytestream_put_byte(&buf
, avctx
->width
& 0xFF);
158 for (int x
= 0; x
< avctx
->width
; x
++)
159 float2rgbe(s
->scanline
+ 4 * x
, red
[x
], green
[x
], blue
[x
]);
160 for (int p
= 0; p
< 4; p
++)
161 rle(&buf
, s
->scanline
+ p
, avctx
->width
);
165 pkt
->flags
|= AV_PKT_FLAG_KEY
;
167 av_shrink_packet(pkt
, buf
- pkt
->data
);
174 const FFCodec ff_hdr_encoder
= {
176 CODEC_LONG_NAME("HDR (Radiance RGBE format) image"),
177 .priv_data_size
= sizeof(HDREncContext
),
178 .p
.type
= AVMEDIA_TYPE_VIDEO
,
179 .p
.id
= AV_CODEC_ID_RADIANCE_HDR
,
180 .p
.capabilities
= AV_CODEC_CAP_DR1
| AV_CODEC_CAP_FRAME_THREADS
|
181 AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE
,
182 .init
= hdr_encode_init
,
183 FF_CODEC_ENCODE_CB(hdr_encode_frame
),
184 .close
= hdr_encode_close
,
185 .p
.pix_fmts
= (const enum AVPixelFormat
[]){
189 .caps_internal
= FF_CODEC_CAP_INIT_CLEANUP
,