[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