diff options
author | Martin Vignali <martin.vignali@gmail.com> | 2016-03-20 11:53:27 +0100 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2016-03-26 09:27:26 +0100 |
commit | 495f08edb444713e8a8915fff25c841dfccf09a5 (patch) | |
tree | 4f9736e8ac888e2c6bb830311ba64d0289b49305 | |
parent | 585cfabb799d510780db673bd9012a968e29aaed (diff) | |
download | ffmpeg-495f08edb444713e8a8915fff25c841dfccf09a5.tar.gz |
avcodec/exr: add support for B44 and B44A compression
-rw-r--r-- | libavcodec/exr.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/libavcodec/exr.c b/libavcodec/exr.c index 9ec99d65a0..f6141fa09c 100644 --- a/libavcodec/exr.c +++ b/libavcodec/exr.c @@ -1,5 +1,6 @@ /* * OpenEXR (.exr) image decoder + * Copyright (c) 2006 Industrial Light & Magic, a division of Lucas Digital Ltd. LLC * Copyright (c) 2009 Jimmy Christensen * * This file is part of FFmpeg. @@ -34,6 +35,7 @@ #include <float.h> #include <zlib.h> +#include "libavutil/common.h" #include "libavutil/imgutils.h" #include "libavutil/intfloat.h" #include "libavutil/opt.h" @@ -826,6 +828,116 @@ static int pxr24_uncompress(EXRContext *s, const uint8_t *src, return 0; } +static void unpack_14(const uint8_t b[14], uint16_t s[16]) +{ + unsigned short shift = (b[ 2] >> 2); + unsigned short bias = (0x20 << shift); + int i; + + s[ 0] = (b[0] << 8) | b[1]; + + s[ 4] = s[ 0] + ((((b[ 2] << 4) | (b[ 3] >> 4)) & 0x3f) << shift) - bias; + s[ 8] = s[ 4] + ((((b[ 3] << 2) | (b[ 4] >> 6)) & 0x3f) << shift) - bias; + s[12] = s[ 8] + ((b[ 4] & 0x3f) << shift) - bias; + + s[ 1] = s[ 0] + ((b[ 5] >> 2) << shift) - bias; + s[ 5] = s[ 4] + ((((b[ 5] << 4) | (b[ 6] >> 4)) & 0x3f) << shift) - bias; + s[ 9] = s[ 8] + ((((b[ 6] << 2) | (b[ 7] >> 6)) & 0x3f) << shift) - bias; + s[13] = s[12] + ((b[ 7] & 0x3f) << shift) - bias; + + s[ 2] = s[ 1] + ((b[ 8] >> 2) << shift) - bias; + s[ 6] = s[ 5] + ((((b[ 8] << 4) | (b[ 9] >> 4)) & 0x3f) << shift) - bias; + s[10] = s[ 9] + ((((b[ 9] << 2) | (b[10] >> 6)) & 0x3f) << shift) - bias; + s[14] = s[13] + ((b[10] & 0x3f) << shift) - bias; + + s[ 3] = s[ 2] + ((b[11] >> 2) << shift) - bias; + s[ 7] = s[ 6] + ((((b[11] << 4) | (b[12] >> 4)) & 0x3f) << shift) - bias; + s[11] = s[10] + ((((b[12] << 2) | (b[13] >> 6)) & 0x3f) << shift) - bias; + s[15] = s[14] + ((b[13] & 0x3f) << shift) - bias; + + for (i = 0; i < 16; ++i) { + if (s[i] & 0x8000) + s[i] &= 0x7fff; + else + s[i] = ~s[i]; + } +} + +static void unpack_3(const uint8_t b[3], uint16_t s[16]) +{ + int i; + + s[0] = (b[0] << 8) | b[1]; + + if (s[0] & 0x8000) + s[0] &= 0x7fff; + else + s[0] = ~s[0]; + + for (i = 1; i < 16; i++) + s[i] = s[0]; +} + + +static int b44_uncompress(EXRContext *s, const uint8_t *src, int compressed_size, + int uncompressed_size, EXRThreadData *td){ + const int8_t *sr = src; + int stayToUncompress = compressed_size; + int nbB44BlockW, nbB44BlockH; + int indexHgX, indexHgY, indexOut, indexTmp; + uint16_t tmpBuffer[16]; /* B44 use 4x4 half float pixel */ + int c, iY, iX, y, x; + + /* calc B44 block count */ + nbB44BlockW = s->xdelta / 4; + if ((s->xdelta % 4) != 0) + nbB44BlockW++; + + nbB44BlockH = s->ysize / 4; + if ((s->ysize % 4) != 0) + nbB44BlockH++; + + for (c = 0; c < s->nb_channels; c++) { + for (iY = 0; iY < nbB44BlockH; iY++) { + for (iX = 0; iX < nbB44BlockW; iX++) {/* For each B44 block */ + if (stayToUncompress < 3){ + av_log(s, AV_LOG_ERROR, "Not enough data for B44A block: %d", stayToUncompress); + return AVERROR_INVALIDDATA; + } + + if (src[compressed_size - stayToUncompress + 2] == 0xfc) { /* B44A block */ + unpack_3(sr, tmpBuffer); + sr += 3; + stayToUncompress -= 3; + } else {/* B44 Block */ + if (stayToUncompress < 14) { + av_log(s, AV_LOG_ERROR, "Not enough data for B44 block: %d", stayToUncompress); + return AVERROR_INVALIDDATA; + } + unpack_14(sr, tmpBuffer); + sr += 14; + stayToUncompress -= 14; + } + + /* copy data to uncompress buffer (B44 block can exceed target resolution)*/ + indexHgX = iX * 4; + indexHgY = iY * 4; + + for (y = indexHgY; y < FFMIN(indexHgY + 4, s->ysize); y++) { + for (x = indexHgX; x < FFMIN(indexHgX + 4, s->xdelta); x++) { + indexOut = (c * s->xdelta + y * s->xdelta * s->nb_channels + x) * 2; + indexTmp = (y-indexHgY) * 4 + (x-indexHgX); + td->uncompressed_data[indexOut] = tmpBuffer[indexTmp] & 0xff; + td->uncompressed_data[indexOut + 1] = tmpBuffer[indexTmp] >> 8; + } + } + } + } + } + + return 0; +} + static int decode_block(AVCodecContext *avctx, void *tdata, int jobnr, int threadnr) { @@ -891,6 +1003,11 @@ static int decode_block(AVCodecContext *avctx, void *tdata, break; case EXR_RLE: ret = rle_uncompress(src, data_size, uncompressed_size, td); + break; + case EXR_B44: + case EXR_B44A: + ret = b44_uncompress(s, src, data_size, uncompressed_size, td); + break; } if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "decode_block() failed.\n"); @@ -1323,6 +1440,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, s->scan_lines_per_block = 16; break; case EXR_PIZ: + case EXR_B44: + case EXR_B44A: s->scan_lines_per_block = 32; break; default: |