summaryrefslogtreecommitdiff
path: root/libavcodec/exr.c
diff options
context:
space:
mode:
authorMark Reid <mindmark@gmail.com>2020-05-09 18:48:58 -0700
committerMichael Niedermayer <michael@niedermayer.cc>2020-05-20 15:47:22 +0200
commitaf5922a79a13e7ab48679c619bfcbf3a8491de1e (patch)
treedcbcd92bd584be1377fb89be1192bf07e6952e4d /libavcodec/exr.c
parent86822cfcd99e38c6a787ebc6141967df4ff80eb5 (diff)
avcodec/exr: output float pixels in float pixel format
changes since v1 - default behavior, no longer hidden behind decoder parameter - updated tests to reflect change Reviewed-by: Paul B Mahol <onemda@gmail.com> Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
Diffstat (limited to 'libavcodec/exr.c')
-rw-r--r--libavcodec/exr.c244
1 files changed, 125 insertions, 119 deletions
diff --git a/libavcodec/exr.c b/libavcodec/exr.c
index 73419eadb1..68d5befa40 100644
--- a/libavcodec/exr.c
+++ b/libavcodec/exr.c
@@ -30,7 +30,6 @@
* For more information on the OpenEXR format, visit:
* http://openexr.com/
*
- * exr_flt2uint() and exr_halflt2uint() is credited to Reimar Döffinger.
* exr_half2float() is credited to Aaftab Munshi, Dan Ginsburg, Dave Shreiner.
*/
@@ -160,7 +159,7 @@ typedef struct EXRContext {
enum AVColorTransferCharacteristic apply_trc_type;
float gamma;
- uint16_t gamma_table[65536];
+ union av_intfloat32 gamma_table[65536];
} EXRContext;
/* -15 stored using a single precision bias of 127 */
@@ -225,47 +224,6 @@ static union av_intfloat32 exr_half2float(uint16_t hf)
return f;
}
-
-/**
- * Convert from 32-bit float as uint32_t to uint16_t.
- *
- * @param v 32-bit float
- *
- * @return normalized 16-bit unsigned int
- */
-static inline uint16_t exr_flt2uint(int32_t v)
-{
- int32_t exp = v >> 23;
- // "HACK": negative values result in exp< 0, so clipping them to 0
- // is also handled by this condition, avoids explicit check for sign bit.
- if (exp <= 127 + 7 - 24) // we would shift out all bits anyway
- return 0;
- if (exp >= 127)
- return 0xffff;
- v &= 0x007fffff;
- return (v + (1 << 23)) >> (127 + 7 - exp);
-}
-
-/**
- * Convert from 16-bit float as uint16_t to uint16_t.
- *
- * @param v 16-bit float
- *
- * @return normalized 16-bit unsigned int
- */
-static inline uint16_t exr_halflt2uint(uint16_t v)
-{
- unsigned exp = 14 - (v >> 10);
- if (exp >= 14) {
- if (exp == 14)
- return (v >> 9) & 1;
- else
- return (v & 0x8000) ? 0 : 0xffff;
- }
- v <<= 6;
- return (v + (1 << 16)) >> (exp + 1);
-}
-
static int zip_uncompress(EXRContext *s, const uint8_t *src, int compressed_size,
int uncompressed_size, EXRThreadData *td)
{
@@ -1035,14 +993,14 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
const uint8_t *channel_buffer[4] = { 0 };
const uint8_t *buf = s->buf;
uint64_t line_offset, uncompressed_size;
- uint16_t *ptr_x;
uint8_t *ptr;
uint32_t data_size;
uint64_t line, col = 0;
uint64_t tile_x, tile_y, tile_level_x, tile_level_y;
const uint8_t *src;
- int axmax = (avctx->width - (s->xmax + 1)) * 2 * s->desc->nb_components; /* nb pixel to add at the right of the datawindow */
- int bxmin = s->xmin * 2 * s->desc->nb_components; /* nb pixel to add at the left of the datawindow */
+ int step = s->desc->flags & AV_PIX_FMT_FLAG_FLOAT ? 4 : 2 * s->desc->nb_components;
+ int axmax = (avctx->width - (s->xmax + 1)) * step; /* nb pixel to add at the right of the datawindow */
+ int bxmin = s->xmin * step; /* nb pixel to add at the left of the datawindow */
int i, x, buf_size = s->buf_size;
int c, rgb_channel_count;
float one_gamma = 1.0f / s->gamma;
@@ -1175,69 +1133,89 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
if (s->channel_offsets[3] >= 0)
channel_buffer[3] = src + td->xsize * s->channel_offsets[3];
- ptr = p->data[0] + line * p->linesize[0] + (col * s->desc->nb_components * 2);
+ if (s->desc->flags & AV_PIX_FMT_FLAG_FLOAT) {
- for (i = 0;
- i < td->ysize; i++, ptr += p->linesize[0]) {
-
- const uint8_t * a;
- const uint8_t *rgb[3];
-
- for (c = 0; c < rgb_channel_count; c++) {
- rgb[c] = channel_buffer[c];
+ /* todo: change this when a floating point pixel format with luma with alpha is implemented */
+ int channel_count = s->channel_offsets[3] >= 0 ? 4 : rgb_channel_count;
+ if (s->is_luma) {
+ channel_buffer[1] = channel_buffer[0];
+ channel_buffer[2] = channel_buffer[0];
}
- if (channel_buffer[3])
- a = channel_buffer[3];
+ for (c = 0; c < channel_count; c++) {
+ int plane = s->desc->comp[c].plane;
+ ptr = p->data[plane] + line * p->linesize[plane] + (col * 4);
- ptr_x = (uint16_t *) ptr;
+ for (i = 0; i < td->ysize; i++, ptr += p->linesize[plane]) {
+ const uint8_t *src;
+ union av_intfloat32 *ptr_x;
- // Zero out the start if xmin is not 0
- memset(ptr_x, 0, bxmin);
- ptr_x += s->xmin * s->desc->nb_components;
+ src = channel_buffer[c];
+ ptr_x = (union av_intfloat32 *)ptr;
- if (s->pixel_type == EXR_FLOAT) {
- // 32-bit
- if (trc_func) {
- for (x = 0; x < td->xsize; x++) {
- union av_intfloat32 t;
+ // Zero out the start if xmin is not 0
+ memset(ptr_x, 0, bxmin);
+ ptr_x += s->xmin;
- for (c = 0; c < rgb_channel_count; c++) {
- t.i = bytestream_get_le32(&rgb[c]);
- t.f = trc_func(t.f);
- *ptr_x++ = exr_flt2uint(t.i);
- }
- if (channel_buffer[3])
- *ptr_x++ = exr_flt2uint(bytestream_get_le32(&a));
- }
- } else {
- for (x = 0; x < td->xsize; x++) {
+ if (s->pixel_type == EXR_FLOAT) {
+ // 32-bit
union av_intfloat32 t;
- int c;
-
- for (c = 0; c < rgb_channel_count; c++) {
- t.i = bytestream_get_le32(&rgb[c]);
- if (t.f > 0.0f) /* avoid negative values */
- t.f = powf(t.f, one_gamma);
- *ptr_x++ = exr_flt2uint(t.i);
+ if (trc_func && c < 3) {
+ for (x = 0; x < td->xsize; x++) {
+ t.i = bytestream_get_le32(&src);
+ t.f = trc_func(t.f);
+ *ptr_x++ = t;
+ }
+ } else {
+ for (x = 0; x < td->xsize; x++) {
+ t.i = bytestream_get_le32(&src);
+ if (t.f > 0.0f && c < 3) /* avoid negative values */
+ t.f = powf(t.f, one_gamma);
+ *ptr_x++ = t;
+ }
+ }
+ } else if (s->pixel_type == EXR_HALF) {
+ // 16-bit
+ if (c < 3) {
+ for (x = 0; x < td->xsize; x++) {
+ *ptr_x++ = s->gamma_table[bytestream_get_le16(&src)];
+ }
+ } else {
+ for (x = 0; x < td->xsize; x++) {
+ *ptr_x++ = exr_half2float(bytestream_get_le16(&src));;
+ }
}
-
- if (channel_buffer[3])
- *ptr_x++ = exr_flt2uint(bytestream_get_le32(&a));
}
+
+ // Zero out the end if xmax+1 is not w
+ memset(ptr_x, 0, axmax);
+ channel_buffer[c] += td->channel_line_size;
}
- } else if (s->pixel_type == EXR_HALF) {
- // 16-bit
- for (x = 0; x < td->xsize; x++) {
- int c;
- for (c = 0; c < rgb_channel_count; c++) {
- *ptr_x++ = s->gamma_table[bytestream_get_le16(&rgb[c])];
- }
+ }
+ } else {
- if (channel_buffer[3])
- *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&a));
+ av_assert1(s->pixel_type == EXR_UINT);
+ ptr = p->data[0] + line * p->linesize[0] + (col * s->desc->nb_components * 2);
+
+ for (i = 0; i < td->ysize; i++, ptr += p->linesize[0]) {
+
+ const uint8_t * a;
+ const uint8_t *rgb[3];
+ uint16_t *ptr_x;
+
+ for (c = 0; c < rgb_channel_count; c++) {
+ rgb[c] = channel_buffer[c];
}
- } else if (s->pixel_type == EXR_UINT) {
+
+ if (channel_buffer[3])
+ a = channel_buffer[3];
+
+ ptr_x = (uint16_t *) ptr;
+
+ // Zero out the start if xmin is not 0
+ memset(ptr_x, 0, bxmin);
+ ptr_x += s->xmin * s->desc->nb_components;
+
for (x = 0; x < td->xsize; x++) {
for (c = 0; c < rgb_channel_count; c++) {
*ptr_x++ = bytestream_get_le32(&rgb[c]) >> 16;
@@ -1246,16 +1224,16 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
if (channel_buffer[3])
*ptr_x++ = bytestream_get_le32(&a) >> 16;
}
- }
- // Zero out the end if xmax+1 is not w
- memset(ptr_x, 0, axmax);
+ // Zero out the end if xmax+1 is not w
+ memset(ptr_x, 0, axmax);
- channel_buffer[0] += td->channel_line_size;
- channel_buffer[1] += td->channel_line_size;
- channel_buffer[2] += td->channel_line_size;
- if (channel_buffer[3])
- channel_buffer[3] += td->channel_line_size;
+ channel_buffer[0] += td->channel_line_size;
+ channel_buffer[1] += td->channel_line_size;
+ channel_buffer[2] += td->channel_line_size;
+ if (channel_buffer[3])
+ channel_buffer[3] += td->channel_line_size;
+ }
}
return 0;
@@ -1676,7 +1654,8 @@ static int decode_frame(AVCodecContext *avctx, void *data,
AVFrame *picture = data;
uint8_t *ptr;
- int y, ret;
+ int i, y, ret;
+ int planes;
int out_line_size;
int nb_blocks; /* nb scanline or nb tile */
uint64_t start_offset_table;
@@ -1691,6 +1670,21 @@ static int decode_frame(AVCodecContext *avctx, void *data,
switch (s->pixel_type) {
case EXR_FLOAT:
case EXR_HALF:
+ if (s->channel_offsets[3] >= 0) {
+ if (!s->is_luma) {
+ avctx->pix_fmt = AV_PIX_FMT_GBRAPF32;
+ } else {
+ /* todo: change this when a floating point pixel format with luma with alpha is implemented */
+ avctx->pix_fmt = AV_PIX_FMT_GBRAPF32;
+ }
+ } else {
+ if (!s->is_luma) {
+ avctx->pix_fmt = AV_PIX_FMT_GBRPF32;
+ } else {
+ avctx->pix_fmt = AV_PIX_FMT_GRAYF32;
+ }
+ }
+ break;
case EXR_UINT:
if (s->channel_offsets[3] >= 0) {
if (!s->is_luma) {
@@ -1751,7 +1745,14 @@ static int decode_frame(AVCodecContext *avctx, void *data,
s->desc = av_pix_fmt_desc_get(avctx->pix_fmt);
if (!s->desc)
return AVERROR_INVALIDDATA;
- out_line_size = avctx->width * 2 * s->desc->nb_components;
+
+ if (s->desc->flags & AV_PIX_FMT_FLAG_FLOAT) {
+ planes = s->desc->nb_components;
+ out_line_size = avctx->width * 4;
+ } else {
+ planes = 1;
+ out_line_size = avctx->width * 2 * s->desc->nb_components;
+ }
if (s->is_tile) {
nb_blocks = ((s->xdelta + s->tile_attr.xSize - 1) / s->tile_attr.xSize) *
@@ -1789,12 +1790,14 @@ static int decode_frame(AVCodecContext *avctx, void *data,
// save pointer we are going to use in decode_block
s->buf = avpkt->data;
s->buf_size = avpkt->size;
- ptr = picture->data[0];
// Zero out the start if ymin is not 0
- for (y = 0; y < s->ymin; y++) {
- memset(ptr, 0, out_line_size);
- ptr += picture->linesize[0];
+ for (i = 0; i < planes; i++) {
+ ptr = picture->data[i];
+ for (y = 0; y < s->ymin; y++) {
+ memset(ptr, 0, out_line_size);
+ ptr += picture->linesize[i];
+ }
}
s->picture = picture;
@@ -1802,10 +1805,12 @@ static int decode_frame(AVCodecContext *avctx, void *data,
avctx->execute2(avctx, decode_block, s->thread_data, NULL, nb_blocks);
// Zero out the end if ymax+1 is not h
- ptr = picture->data[0] + ((s->ymax+1) * picture->linesize[0]);
- for (y = s->ymax + 1; y < avctx->height; y++) {
- memset(ptr, 0, out_line_size);
- ptr += picture->linesize[0];
+ for (i = 0; i < planes; i++) {
+ ptr = picture->data[i] + ((s->ymax+1) * picture->linesize[i]);
+ for (y = s->ymax + 1; y < avctx->height; y++) {
+ memset(ptr, 0, out_line_size);
+ ptr += picture->linesize[i];
+ }
}
picture->pict_type = AV_PICTURE_TYPE_I;
@@ -1835,21 +1840,22 @@ static av_cold int decode_init(AVCodecContext *avctx)
for (i = 0; i < 65536; ++i) {
t = exr_half2float(i);
t.f = trc_func(t.f);
- s->gamma_table[i] = exr_flt2uint(t.i);
+ s->gamma_table[i] = t;
}
} else {
if (one_gamma > 0.9999f && one_gamma < 1.0001f) {
- for (i = 0; i < 65536; ++i)
- s->gamma_table[i] = exr_halflt2uint(i);
+ for (i = 0; i < 65536; ++i) {
+ s->gamma_table[i] = exr_half2float(i);
+ }
} else {
for (i = 0; i < 65536; ++i) {
t = exr_half2float(i);
/* If negative value we reuse half value */
if (t.f <= 0.0f) {
- s->gamma_table[i] = exr_halflt2uint(i);
+ s->gamma_table[i] = t;
} else {
t.f = powf(t.f, one_gamma);
- s->gamma_table[i] = exr_flt2uint(t.i);
+ s->gamma_table[i] = t;
}
}
}