[FFmpeg-devel] [PATCH] Add a gamma flag to exr loader to avoid banding
Michael Niedermayer
michaelni at gmx.at
Thu May 1 19:19:43 CEST 2014
On Thu, May 01, 2014 at 10:18:43AM -0300, Gonzalo Garramuno wrote:
> Here's an updated patch to fix trailing whitespace and other things
> patcheck caught.
> libavcodec/exr.c | 108 ++++++++++++++++++++++++++++++++---------
> tests/ref/fate/exr-slice-raw | 2
> tests/ref/fate/exr-slice-rle | 2
> tests/ref/fate/exr-slice-zip1 | 2
> tests/ref/fate/exr-slice-zip16 | 2
> 5 files changed, 89 insertions(+), 27 deletions(-)
> 81b08653e65f24190d107efd8977e8669292ab92 exr_patch8.diff
> diff --git a/libavcodec/exr.c b/libavcodec/exr.c
> index 084025a..3ca7552 100644
> --- a/libavcodec/exr.c
> +++ b/libavcodec/exr.c
> @@ -27,13 +27,17 @@
> * For more information on the OpenEXR format, visit:
> * http://openexr.com/
> *
> - * exr_flt2uint() and exr_halflt2uint() is credited to Reimar Döffinger
> + * exr_flt2uint() and exr_halflt2uint() is credited to Reimar Döffinger.
> + * exr_half2float() is credited to Fabian “ryg” Giesen.
> + *
> */
>
> #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 +81,7 @@ typedef struct EXRThreadData {
> uint16_t *lut;
> } EXRThreadData;
>
> +
> typedef struct EXRContext {
> AVClass *class;
> AVFrame *picture;
> @@ -106,6 +111,11 @@ typedef struct EXRContext {
> EXRThreadData *thread_data;
>
> const char *layer;
> +
> + float gamma;
> +
> + uint16_t gamma_table[65536];
> +
> } EXRContext;
>
> /**
> @@ -128,6 +138,29 @@ static inline uint16_t exr_flt2uint(uint32_t v)
> return (v + (1 << 23)) >> (127 + 7 - exp);
> }
>
> +
> +/*
> + * Convert a half float as a uint16_t into a full float.
> + *
> + * @param h half float as uint16_t
> + *
> + * @return float value
> + */
> +static inline float exr_half2float(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.f;
> +}
> +
> /**
> * Convert from 16-bit float as uint16_t to uint16_t.
> *
> @@ -772,6 +805,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 +885,43 @@ 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);
> + if ( t.f < 0.0f ) t.f = 0.0f; /* avoid negative values */
> + t.f = powf(t.f, one_gamma);
> + *ptr_x++ = exr_flt2uint(t.i);
> +
> + t.i = bytestream_get_le32(&g);
> + if ( t.f < 0.0f ) t.f = 0.0f;
> + t.f = powf(t.f, one_gamma);
> + *ptr_x++ = exr_flt2uint(t.i);
> +
> + t.i = bytestream_get_le32(&b);
> + if ( t.f < 0.0f ) t.f = 0.0f;
> + 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;
please dont mess up the indention of otherwise unchanged code
[...]
> diff --git a/tests/ref/fate/exr-slice-raw b/tests/ref/fate/exr-slice-raw
> index a8b4b27..8534f88 100644
> --- a/tests/ref/fate/exr-slice-raw
> +++ b/tests/ref/fate/exr-slice-raw
> @@ -1,2 +1,2 @@
> #tb 0: 1/25
> -0, 0, 0, 1, 3169800, 0x6a356d0d
> +0, 0, 0, 1, 3169800, 0x1f656d7a
> diff --git a/tests/ref/fate/exr-slice-rle b/tests/ref/fate/exr-slice-rle
> index a8b4b27..8534f88 100644
> --- a/tests/ref/fate/exr-slice-rle
> +++ b/tests/ref/fate/exr-slice-rle
> @@ -1,2 +1,2 @@
> #tb 0: 1/25
> -0, 0, 0, 1, 3169800, 0x6a356d0d
> +0, 0, 0, 1, 3169800, 0x1f656d7a
> diff --git a/tests/ref/fate/exr-slice-zip1 b/tests/ref/fate/exr-slice-zip1
> index a8b4b27..8534f88 100644
> --- a/tests/ref/fate/exr-slice-zip1
> +++ b/tests/ref/fate/exr-slice-zip1
> @@ -1,2 +1,2 @@
> #tb 0: 1/25
> -0, 0, 0, 1, 3169800, 0x6a356d0d
> +0, 0, 0, 1, 3169800, 0x1f656d7a
> diff --git a/tests/ref/fate/exr-slice-zip16 b/tests/ref/fate/exr-slice-zip16
> index a8b4b27..8534f88 100644
> --- a/tests/ref/fate/exr-slice-zip16
> +++ b/tests/ref/fate/exr-slice-zip16
> @@ -1,2 +1,2 @@
> #tb 0: 1/25
> -0, 0, 0, 1, 3169800, 0x6a356d0d
> +0, 0, 0, 1, 3169800, 0x1f656d7a
make fate still fails:
unraster-1bit-raw
TEST sunraster-1bit-rle
TEST sunraster-8bit-raw
TEST sunraster-8bit_gray-raw
--- ./tests/ref/fate/exr-slice-raw 2014-05-01 18:55:23.191949620 +0200
+++ tests/data/fate/exr-slice-raw 2014-05-01 19:12:22.391971092 +0200
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 3169800, 0x1f656d7a
+0, 0, 0, 1, 3169800, 0xc96ed674
TEST sunraster-8bit-rle
TEST sunraster-24bit-raw
Test exr-slice-raw failed. Look at tests/data/fate/exr-slice-raw.err for details.
make: *** [fate-exr-slice-raw] Error 1
make: *** Waiting for unfinished jobs....
--- ./tests/ref/fate/exr-slice-rle 2014-05-01 18:55:23.195949620 +0200
+++ tests/data/fate/exr-slice-rle 2014-05-01 19:12:22.419971092 +0200
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 3169800, 0x1f656d7a
+0, 0, 0, 1, 3169800, 0xc96ed674
Test exr-slice-rle failed. Look at tests/data/fate/exr-slice-rle.err for details.
make: *** [fate-exr-slice-rle] Error 1
--- ./tests/ref/fate/exr-slice-zip16 2014-05-01 18:55:23.199949620 +0200
+++ tests/data/fate/exr-slice-zip16 2014-05-01 19:12:22.439971093 +0200
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 3169800, 0x1f656d7a
+0, 0, 0, 1, 3169800, 0xc96ed674
Test exr-slice-zip16 failed. Look at tests/data/fate/exr-slice-zip16.err for details.
make: *** [fate-exr-slice-zip16] Error 1
--- ./tests/ref/fate/exr-slice-zip1 2014-05-01 18:55:23.199949620 +0200
+++ tests/data/fate/exr-slice-zip1 2014-05-01 19:12:22.443971092 +0200
@@ -1,2 +1,2 @@
#tb 0: 1/25
-0, 0, 0, 1, 3169800, 0x1f656d7a
+0, 0, 0, 1, 3169800, 0xc96ed674
Test exr-slice-zip1 failed. Look at tests/data/fate/exr-slice-zip1.err for details.
make: *** [fate-exr-slice-zip1] Error 1
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
I know you won't believe me, but the highest form of Human Excellence is
to question oneself and others. -- Socrates
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: Digital signature
URL: <http://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20140501/9444e301/attachment.asc>
More information about the ffmpeg-devel
mailing list