summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Vignali <martin.vignali@gmail.com>2016-03-20 11:53:27 +0100
committerPaul B Mahol <onemda@gmail.com>2016-03-26 09:27:26 +0100
commit495f08edb444713e8a8915fff25c841dfccf09a5 (patch)
tree4f9736e8ac888e2c6bb830311ba64d0289b49305
parent585cfabb799d510780db673bd9012a968e29aaed (diff)
avcodec/exr: add support for B44 and B44A compression
-rw-r--r--libavcodec/exr.c119
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: