@@ -161,6 +161,7 @@ typedef struct EXRContext {
enum AVColorTransferCharacteristic apply_trc_type;
float gamma;
uint16_t gamma_table[65536];
+ int output_float;
} EXRContext;
/* -15 stored using a single precision bias of 127 */
@@ -1035,14 +1036,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,6 +1176,58 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
if (s->channel_offsets[3] >= 0)
channel_buffer[3] = src + td->xsize * s->channel_offsets[3];
+ if (s->desc->flags & AV_PIX_FMT_FLAG_FLOAT) {
+
+ /* 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];
+ }
+
+ for (c = 0; c < channel_count; c++) {
+ int plane = s->desc->comp[c].plane;
+ ptr = p->data[plane] + line * p->linesize[plane] + (col * 4);
+
+ for (i = 0; i < td->ysize; i++, ptr += p->linesize[plane]) {
+ const uint8_t *src;
+ union av_intfloat32 *ptr_x;
+
+ src = channel_buffer[c];
+ ptr_x = (union av_intfloat32 *)ptr;
+
+ // Zero out the start if xmin is not 0
+ memset(ptr_x, 0, bxmin);
+ ptr_x += s->xmin;
+
+ if (s->pixel_type == EXR_FLOAT) {
+ // 32-bit
+ for (x = 0; x < td->xsize; x++) {
+ ptr_x->i = bytestream_get_le32(&src);
+ ptr_x++;
+ }
+ } else if (s->pixel_type == EXR_HALF) {
+ // 16-bit
+ for (x = 0; x < td->xsize; x++) {
+ *ptr_x++ = exr_half2float(bytestream_get_le16(&src));
+ }
+ } else if (s->pixel_type == EXR_UINT) {
+ const float float_mult = 1.0f / (float)UINT32_MAX;
+ for (x = 0; x < td->xsize; x++) {
+ ptr_x->f = float_mult * (float)bytestream_get_le32(&src);
+ ptr_x++;
+ }
+ }
+
+ // Zero out the end if xmax+1 is not w
+ memset(ptr_x, 0, axmax);
+ channel_buffer[c] += td->channel_line_size;
+ }
+ }
+
+ return 0;
+ }
+
ptr = p->data[0] + line * p->linesize[0] + (col * s->desc->nb_components * 2);
for (i = 0;
@@ -1182,6 +1235,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
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];
@@ -1676,7 +1730,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;
@@ -1694,15 +1749,16 @@ static int decode_frame(AVCodecContext *avctx, void *data,
case EXR_UINT:
if (s->channel_offsets[3] >= 0) {
if (!s->is_luma) {
- avctx->pix_fmt = AV_PIX_FMT_RGBA64;
+ avctx->pix_fmt = s->output_float ? AV_PIX_FMT_GBRAPF32 : AV_PIX_FMT_RGBA64;
} else {
- avctx->pix_fmt = AV_PIX_FMT_YA16;
+ /* todo: change this when a floating point pixel format with luma with alpha is implemented */
+ avctx->pix_fmt = s->output_float ? AV_PIX_FMT_GBRAPF32 : AV_PIX_FMT_YA16;
}
} else {
if (!s->is_luma) {
- avctx->pix_fmt = AV_PIX_FMT_RGB48;
+ avctx->pix_fmt = s->output_float ? AV_PIX_FMT_GBRPF32 : AV_PIX_FMT_RGB48;
} else {
- avctx->pix_fmt = AV_PIX_FMT_GRAY16;
+ avctx->pix_fmt = s->output_float ? AV_PIX_FMT_GRAYF32 : AV_PIX_FMT_GRAY16;
}
}
break;
@@ -1751,7 +1807,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 +1852,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 +1867,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;
@@ -1888,6 +1955,8 @@ static const AVOption options[] = {
AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD },
{ "gamma", "Set the float gamma value when decoding", OFFSET(gamma),
AV_OPT_TYPE_FLOAT, { .dbl = 1.0f }, 0.001, FLT_MAX, VD },
+ { "float", "Output frame in floating point pixel format, apply_trc does not get applied", OFFSET(output_float),
+ AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VD},
// XXX: Note the abuse of the enum using AVCOL_TRC_UNSPECIFIED to subsume the existing gamma option
{ "apply_trc", "color transfer characteristics to apply to EXR linear input", OFFSET(apply_trc_type),
From: Mark Reid <mindmark@gmail.com> --- libavcodec/exr.c | 103 +++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 17 deletions(-)