Hello, in attach patch who add support for B44 and B44A compression in openexr file.
The B44/B44A block decoding function (unpack_14 and unpack_3) come from the official library. B44 only compress Half float data (Float data stay uncompress) The compression use bloc of 4x4 pixels, and reduce the size from 32 bits to 14. B44A use the same method than B44, except for uniform blocks who are stored with only 3 bits. Some B44/B44A samples can be found here http://www.datafilehost.com/d/a3dc072e Comments welcome Martin Vignali Jokyo Images
From 9170a9331425017b4e8d513e5990372f4ff4935f Mon Sep 17 00:00:00 2001 From: Martin Vignali <martin.vign...@gmail.com> Date: Sat, 19 Mar 2016 16:25:44 +0100 Subject: [PATCH] libavcodec/exr : add support for B44 and B44A compression --- libavcodec/exr.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/libavcodec/exr.c b/libavcodec/exr.c index 9ec99d6..72b8ffa 100644 --- a/libavcodec/exr.c +++ b/libavcodec/exr.c @@ -34,6 +34,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 +827,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]){ + /* From openExr library */ + s[ 0] = (b[0] << 8) | b[1]; + + unsigned short shift = (b[ 2] >> 2); + unsigned short bias = (0x20 << shift); + + 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 (int 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]){ + /* From openExr library */ + s[0] = (b[0] << 8) | b[1]; + + if (s[0] & 0x8000) + s[0] &= 0x7fff; + else + s[0] = ~s[0]; + + for (int 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 heightScanline = uncompressed_size/(s->nb_channels * s->xdelta); + int nbB44BlockW, nbB44BlockH; + int indexHgX, indexHgY, indexOut, indexTmp; + 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++; + + uint16_t tmpBuffer[16];/* B44 use 4x4 half float pixel */ + + for (c = 0; c < s->nb_channels; c++) { + for (iY = 0; iY < nbB44BlockH; iY++) { + for (iX = 0; iX < nbB44BlockW; iX++) {/* For each B44 bloc */ + if (stayToUncompress < 3){ + av_log(s, AV_LOG_ERROR, "Not enough data for B44A bloc : %d", stayToUncompress); + return AVERROR_INVALIDDATA; + } + + if (src[compressed_size - stayToUncompress + 2] == 0xfc) {/* B44A bloc */ + unpack_3(sr, tmpBuffer); + sr += 3; + stayToUncompress -= 3; + } + else{/* B44 Bloc */ + if (stayToUncompress < 14) {/* Not enough data for B44 bloc */ + av_log(s, AV_LOG_ERROR, "Not enough data for B44 bloc : %d", stayToUncompress); + return AVERROR_INVALIDDATA; + } + unpack_14(sr, tmpBuffer); + sr += 14; + stayToUncompress -= 14; + } + + /* copy data to uncompress buffer (B44 bloc 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 +1002,10 @@ 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); } if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "decode_block() failed.\n"); @@ -1323,6 +1438,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: -- 1.9.3 (Apple Git-50)
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel