[FFmpeg-devel] [PATCH] Add a gamma flag to exr loader to avoid banding
Clément Bœsch
u at pkh.me
Mon Apr 28 01:14:00 CEST 2014
On Sun, Apr 27, 2014 at 07:39:57PM -0300, Gonzalo Garramuno wrote:
> On 27/04/14 13:48, Michael Niedermayer wrote:
> >On Sun, Apr 27, 2014 at 01:28:15PM -0300, Gonzalo Garramuno wrote:
> >
> >you can do the gamma correction in the LUT for 16bit too
> >
> >[...]
> >
>
> Good idea. And here it is. The gamma table for the half float path.
> Now hopefully the powers that be accept the patch.
> diff --git a/Changelog b/Changelog
> index daaa1ea..a726823 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -2,6 +2,7 @@ Entries are sorted chronologically from oldest to youngest within each release,
> releases are sorted from youngest to oldest.
>
> version <next>:
> +- EXR loader supports a gamma flag
"Entries are sorted chronologically from oldest to youngest"
> - AC3 fixed-point decoding
> - shuffleplanes filter
> - subfile protocol
> diff --git a/libavcodec/exr.c b/libavcodec/exr.c
> index 084025a..55313f4 100644
> --- a/libavcodec/exr.c
> +++ b/libavcodec/exr.c
> @@ -31,9 +31,11 @@
> */
>
> #include <zlib.h>
> +#include <float.h>
>
> #include "libavutil/imgutils.h"
> #include "libavutil/opt.h"
> +#include "libavutil/intfloat.h"
>
> #include "avcodec.h"
> #include "bytestream.h"
> @@ -77,6 +79,7 @@ typedef struct EXRThreadData {
> uint16_t *lut;
> } EXRThreadData;
>
> +
> typedef struct EXRContext {
> AVClass *class;
> AVFrame *picture;
> @@ -106,8 +109,14 @@ typedef struct EXRContext {
> EXRThreadData *thread_data;
>
> const char *layer;
> +
> + float gamma;
> +
> + uint16_t gamma_table[32767];
> +
> } EXRContext;
>
> +
> /**
> * Convert from 32-bit float as uint32_t to uint16_t.
> *
> @@ -128,6 +137,23 @@ static inline uint16_t exr_flt2uint(uint32_t v)
> return (v + (1 << 23)) >> (127 + 7 - exp);
> }
>
> +/*
> + Safely convert a half float to a full float
> + */
> +static inline union av_intfloat32 half_to_float_full(uint16_t h)
> +{
> + static const union av_intfloat32 magic = { (254 - 15) << 23 };
> + static const union av_intfloat32 was_infnan = { (127 + 16) << 23 };
> + union av_intfloat32 o;
> +
> + o.i = (h & 0x7fff) << 13; // exponent/mantissa bits
> + o.f *= magic.f; // exponent adjust
> + if (o.f >= was_infnan.f) // make sure Inf/NaN survive
> + o.i |= 255 << 23;
> + o.i |= (h & 0x8000) << 16; // sign bit
> + return o;
> +}
> +
> /**
> * Convert from 16-bit float as uint16_t to uint16_t.
> *
> @@ -772,6 +798,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
> int bxmin = s->xmin * 2 * s->desc->nb_components;
> int i, x, buf_size = s->buf_size;
> int ret;
> + float one_gamma = 1.0f / s->gamma;
>
> line_offset = AV_RL64(s->gb.buffer + jobnr * 8);
> // Check if the buffer has the required bytes needed from the offset
> @@ -851,31 +878,40 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
> if (s->pixel_type == EXR_FLOAT) {
> // 32-bit
> for (x = 0; x < xdelta; x++) {
> - *ptr_x++ = exr_flt2uint(bytestream_get_le32(&r));
> - *ptr_x++ = exr_flt2uint(bytestream_get_le32(&g));
> - *ptr_x++ = exr_flt2uint(bytestream_get_le32(&b));
> + union av_intfloat32 t;
> + t.i = bytestream_get_le32(&r);;
> + t.f = powf(t.f, one_gamma);
> + *ptr_x++ = exr_flt2uint(t.i);
> +
> + t.i = bytestream_get_le32(&g);
> + t.f = powf(t.f, one_gamma);
> + *ptr_x++ = exr_flt2uint(t.i);
> +
> + t.i = bytestream_get_le32(&b);
> + t.f = powf(t.f, one_gamma);
> + *ptr_x++ = exr_flt2uint(t.i);
> if (channel_buffer[3])
> *ptr_x++ = exr_flt2uint(bytestream_get_le32(&a));
> }
> - } else {
> - // 16-bit
> - for (x = 0; x < xdelta; x++) {
> - *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&r));
> - *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&g));
> - *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&b));
> - if (channel_buffer[3])
> - *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&a));
> - }
> - }
> -
> - // Zero out the end if xmax+1 is not w
> - memset(ptr_x, 0, axmax);
> -
> - channel_buffer[0] += s->scan_line_size;
> - channel_buffer[1] += s->scan_line_size;
> - channel_buffer[2] += s->scan_line_size;
> - if (channel_buffer[3])
> - channel_buffer[3] += s->scan_line_size;
> + } else {
> + // 16-bit
> + for (x = 0; x < xdelta; x++) {
> + *ptr_x++ = s->gamma_table[bytestream_get_le16(&r)];
> + *ptr_x++ = s->gamma_table[bytestream_get_le16(&g)];
> + *ptr_x++ = s->gamma_table[bytestream_get_le16(&b)];
> + if (channel_buffer[3])
> + *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&a));
> + }
> + }
> +
> + // Zero out the end if xmax+1 is not w
> + memset(ptr_x, 0, axmax);
> +
> + channel_buffer[0] += s->scan_line_size;
> + channel_buffer[1] += s->scan_line_size;
> + channel_buffer[2] += s->scan_line_size;
> + if (channel_buffer[3])
> + channel_buffer[3] += s->scan_line_size;
> }
>
> return 0;
> @@ -1261,7 +1297,11 @@ static int decode_frame(AVCodecContext *avctx, void *data,
>
> static av_cold int decode_init(AVCodecContext *avctx)
> {
> + uint16_t i;
> + union av_intfloat32 t;
> EXRContext *s = avctx->priv_data;
> + float one_gamma = 1.0f / s->gamma;
> + av_log(avctx, AV_LOG_INFO, "gamma %f.\n", s->gamma);
>
> s->avctx = avctx;
> s->xmin = ~0;
> @@ -1280,6 +1320,13 @@ static av_cold int decode_init(AVCodecContext *avctx)
> s->w = 0;
> s->h = 0;
>
> + for ( i = 0; i < 32767; ++i )
> + {
style: "for (i = 0; i < 32767; i++) {"
> + t = half_to_float_full(i);
> + t.f = powf(t.f,one_gamma);
> + s->gamma_table[i] = exr_flt2uint( t.i );
trailing whitespace, style, and indent
> + }
> +
> // allocate thread data, used for non EXR_RAW compreesion types
> s->thread_data = av_mallocz_array(avctx->thread_count, sizeof(EXRThreadData));
> if (!s->thread_data)
> @@ -1322,6 +1369,8 @@ static av_cold int decode_end(AVCodecContext *avctx)
> static const AVOption options[] = {
> { "layer", "Set the decoding layer", OFFSET(layer),
> AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD },
> + { "gamma", "Set the float gamma value when decoding", OFFSET(gamma),
> + AV_OPT_TYPE_FLOAT, { .dbl = 2.2 }, 0.001, FLT_MAX, VD },
> { NULL },
> };
>
--
Clément B.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 490 bytes
Desc: not available
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20140428/1a8f1127/attachment.asc>
More information about the ffmpeg-devel
mailing list