exr.c 44.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 * OpenEXR (.exr) image decoder
 * Copyright (c) 2009 Jimmy Christensen
 *
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * FFmpeg is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with FFmpeg; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
23
 * @file
24 25 26 27 28 29
 * OpenEXR decoder
 * @author Jimmy Christensen
 *
 * For more information on the OpenEXR format, visit:
 *  http://openexr.com/
 *
30 31 32
 * exr_flt2uint() and exr_halflt2uint() is credited to  Reimar Döffinger.
 * exr_half2float() is credited to Aaftab Munshi; Dan Ginsburg, Dave Shreiner.
 *
33 34
 */

Paul B Mahol's avatar
Paul B Mahol committed
35
#include <zlib.h>
36
#include <float.h>
Paul B Mahol's avatar
Paul B Mahol committed
37

Jimmy Christensen's avatar
Jimmy Christensen committed
38 39
#include "libavutil/imgutils.h"
#include "libavutil/opt.h"
40
#include "libavutil/intfloat.h"
Jimmy Christensen's avatar
Jimmy Christensen committed
41

42 43
#include "avcodec.h"
#include "bytestream.h"
Jimmy Christensen's avatar
Jimmy Christensen committed
44
#include "get_bits.h"
45
#include "internal.h"
Paul B Mahol's avatar
Paul B Mahol committed
46
#include "mathops.h"
47
#include "thread.h"
48 49

enum ExrCompr {
Jimmy Christensen's avatar
Jimmy Christensen committed
50 51 52 53 54 55 56 57 58
    EXR_RAW,
    EXR_RLE,
    EXR_ZIP1,
    EXR_ZIP16,
    EXR_PIZ,
    EXR_PXR24,
    EXR_B44,
    EXR_B44A,
    EXR_UNKN,
59 60
};

61 62 63
enum ExrPixelType {
    EXR_UINT,
    EXR_HALF,
Jimmy Christensen's avatar
Jimmy Christensen committed
64 65
    EXR_FLOAT,
    EXR_UNKNOWN,
66 67 68
};

typedef struct EXRChannel {
Jimmy Christensen's avatar
Jimmy Christensen committed
69
    int xsub, ysub;
70 71 72
    enum ExrPixelType pixel_type;
} EXRChannel;

Paul B Mahol's avatar
Paul B Mahol committed
73 74 75 76 77 78
typedef struct EXRThreadData {
    uint8_t *uncompressed_data;
    int uncompressed_size;

    uint8_t *tmp;
    int tmp_size;
79 80 81

    uint8_t *bitmap;
    uint16_t *lut;
Paul B Mahol's avatar
Paul B Mahol committed
82 83
} EXRThreadData;

84
typedef struct EXRContext {
Jimmy Christensen's avatar
Jimmy Christensen committed
85
    AVClass *class;
86
    AVFrame *picture;
Jimmy Christensen's avatar
Jimmy Christensen committed
87 88 89
    AVCodecContext *avctx;

    enum ExrCompr compression;
90
    enum ExrPixelType pixel_type;
91
    int channel_offsets[4]; // 0 = red, 1 = green, 2 = blue and 3 = alpha
Paul B Mahol's avatar
Paul B Mahol committed
92
    const AVPixFmtDescriptor *desc;
Paul B Mahol's avatar
Paul B Mahol committed
93

Jimmy Christensen's avatar
Jimmy Christensen committed
94
    int w, h;
Paul B Mahol's avatar
Paul B Mahol committed
95 96 97
    uint32_t xmax, xmin;
    uint32_t ymax, ymin;
    uint32_t xdelta, ydelta;
Paul B Mahol's avatar
Paul B Mahol committed
98 99
    int ysize;

Paul B Mahol's avatar
Paul B Mahol committed
100 101 102
    uint64_t scan_line_size;
    int scan_lines_per_block;

Jimmy Christensen's avatar
Jimmy Christensen committed
103 104
    GetByteContext gb;
    const uint8_t *buf;
Paul B Mahol's avatar
Paul B Mahol committed
105 106
    int buf_size;

107 108 109
    EXRChannel *channels;
    int nb_channels;

Paul B Mahol's avatar
Paul B Mahol committed
110
    EXRThreadData *thread_data;
111

Jimmy Christensen's avatar
Jimmy Christensen committed
112
    const char *layer;
113 114 115 116 117

    float gamma;

    uint16_t gamma_table[65536];

118 119
} EXRContext;

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
/* -15 stored using a single precision bias of 127 */
#define HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP 0x38000000
/* max exponent value in single precision that will be converted
 * to Inf or Nan when stored as a half-float */
#define HALF_FLOAT_MAX_BIASED_EXP_AS_SINGLE_FP_EXP 0x47800000

/* 255 is the max exponent biased value */
#define FLOAT_MAX_BIASED_EXP (0xFF << 23)

#define HALF_FLOAT_MAX_BIASED_EXP (0x1F << 10)

/*
 * Convert a half float as a uint16_t into a full float.
 *
 * @param hf half float as uint16_t
 *
 * @return float value
 */
static union av_intfloat32 exr_half2float(uint16_t hf)
{
    unsigned int    sign = (unsigned int)(hf >> 15);
    unsigned int    mantissa = (unsigned int)(hf & ((1 << 10) - 1));
    unsigned int    exp = (unsigned int)(hf & HALF_FLOAT_MAX_BIASED_EXP);
    union av_intfloat32   f;

    if (exp == HALF_FLOAT_MAX_BIASED_EXP) {
        // we have a half-float NaN or Inf
        // half-float NaNs will be converted to a single precision NaN
        // half-float Infs will be converted to a single precision Inf
        exp = FLOAT_MAX_BIASED_EXP;
        if (mantissa)
            mantissa = (1 << 23) - 1;    // set all bits to indicate a NaN
    } else if (exp == 0x0) {
        // convert half-float zero/denorm to single precision value
        if (mantissa) {
            mantissa <<= 1;
            exp = HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP;
            // check for leading 1 in denorm mantissa
            while ((mantissa & (1 << 10))) {
                // for every leading 0, decrement single precision exponent by 1
                // and shift half-float mantissa value to the left
                mantissa <<= 1;
                exp -= (1 << 23);
            }
            // clamp the mantissa to 10-bits
            mantissa &= ((1 << 10) - 1);
            // shift left to generate single-precision mantissa of 23-bits
            mantissa <<= 13;
        }
    } else {
        // shift left to generate single-precision mantissa of 23-bits
        mantissa <<= 13;
        // generate single precision biased exponent value
        exp = (exp << 13) + HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP;
    }

    f.i = (sign << 31) | exp | mantissa;

    return f;
}


182
/**
Jimmy Christensen's avatar
Jimmy Christensen committed
183
 * Convert from 32-bit float as uint32_t to uint16_t.
184 185
 *
 * @param v 32-bit float
Jimmy Christensen's avatar
Jimmy Christensen committed
186
 *
187 188 189 190 191 192 193
 * @return normalized 16-bit unsigned int
 */
static inline uint16_t exr_flt2uint(uint32_t v)
{
    unsigned int 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.
Jimmy Christensen's avatar
Jimmy Christensen committed
194
    if (exp <= 127 + 7 - 24) // we would shift out all bits anyway
195 196 197 198 199 200 201 202
        return 0;
    if (exp >= 127)
        return 0xffff;
    v &= 0x007fffff;
    return (v + (1 << 23)) >> (127 + 7 - exp);
}

/**
Jimmy Christensen's avatar
Jimmy Christensen committed
203
 * Convert from 16-bit float as uint16_t to uint16_t.
204 205
 *
 * @param v 16-bit float
Jimmy Christensen's avatar
Jimmy Christensen committed
206
 *
207 208 209 210
 * @return normalized 16-bit unsigned int
 */
static inline uint16_t exr_halflt2uint(uint16_t v)
{
211 212
    unsigned exp = 14 - (v >> 10);
    if (exp >= 14) {
Jimmy Christensen's avatar
Jimmy Christensen committed
213 214 215 216
        if (exp == 14)
            return (v >> 9) & 1;
        else
            return (v & 0x8000) ? 0 : 0xffff;
217
    }
218
    v <<= 6;
219
    return (v + (1 << 16)) >> (exp + 1);
220 221
}

Paul B Mahol's avatar
Paul B Mahol committed
222 223
static void predictor(uint8_t *src, int size)
{
Jimmy Christensen's avatar
Jimmy Christensen committed
224
    uint8_t *t    = src + 1;
Paul B Mahol's avatar
Paul B Mahol committed
225 226 227
    uint8_t *stop = src + size;

    while (t < stop) {
Jimmy Christensen's avatar
Jimmy Christensen committed
228
        int d = (int) t[-1] + (int) t[0] - 128;
Paul B Mahol's avatar
Paul B Mahol committed
229 230 231 232 233 234 235 236 237
        t[0] = d;
        ++t;
    }
}

static void reorder_pixels(uint8_t *src, uint8_t *dst, int size)
{
    const int8_t *t1 = src;
    const int8_t *t2 = src + (size + 1) / 2;
Jimmy Christensen's avatar
Jimmy Christensen committed
238 239
    int8_t *s        = dst;
    int8_t *stop     = s + size;
Paul B Mahol's avatar
Paul B Mahol committed
240 241 242 243 244 245 246 247 248 249 250 251 252 253

    while (1) {
        if (s < stop)
            *(s++) = *(t1++);
        else
            break;

        if (s < stop)
            *(s++) = *(t2++);
        else
            break;
    }
}

254 255
static int zip_uncompress(const uint8_t *src, int compressed_size,
                          int uncompressed_size, EXRThreadData *td)
Paul B Mahol's avatar
Paul B Mahol committed
256
{
257 258 259 260
    unsigned long dest_len = uncompressed_size;

    if (uncompress(td->tmp, &dest_len, src, compressed_size) != Z_OK ||
        dest_len != uncompressed_size)
Jimmy Christensen's avatar
Jimmy Christensen committed
261
        return AVERROR_INVALIDDATA;
262 263 264 265 266 267 268 269 270 271

    predictor(td->tmp, uncompressed_size);
    reorder_pixels(td->tmp, td->uncompressed_data, uncompressed_size);

    return 0;
}

static int rle_uncompress(const uint8_t *src, int compressed_size,
                          int uncompressed_size, EXRThreadData *td)
{
Jimmy Christensen's avatar
Jimmy Christensen committed
272 273 274 275 276
    uint8_t *d      = td->tmp;
    const int8_t *s = src;
    int ssize       = compressed_size;
    int dsize       = uncompressed_size;
    uint8_t *dend   = d + dsize;
Paul B Mahol's avatar
Paul B Mahol committed
277 278 279 280 281 282 283 284
    int count;

    while (ssize > 0) {
        count = *s++;

        if (count < 0) {
            count = -count;

Jimmy Christensen's avatar
Jimmy Christensen committed
285
            if ((dsize -= count) < 0 ||
Paul B Mahol's avatar
Paul B Mahol committed
286
                (ssize -= count + 1) < 0)
Jimmy Christensen's avatar
Jimmy Christensen committed
287
                return AVERROR_INVALIDDATA;
Paul B Mahol's avatar
Paul B Mahol committed
288 289 290 291 292 293 294

            while (count--)
                *d++ = *s++;
        } else {
            count++;

            if ((dsize -= count) < 0 ||
Jimmy Christensen's avatar
Jimmy Christensen committed
295 296
                (ssize -= 2) < 0)
                return AVERROR_INVALIDDATA;
Paul B Mahol's avatar
Paul B Mahol committed
297 298 299 300 301 302 303 304

            while (count--)
                *d++ = *s;

            s++;
        }
    }

305 306 307 308 309 310 311
    if (dend != d)
        return AVERROR_INVALIDDATA;

    predictor(td->tmp, uncompressed_size);
    reorder_pixels(td->tmp, td->uncompressed_data, uncompressed_size);

    return 0;
Paul B Mahol's avatar
Paul B Mahol committed
312 313
}

314
#define USHORT_RANGE (1 << 16)
Jimmy Christensen's avatar
Jimmy Christensen committed
315
#define BITMAP_SIZE  (1 << 13)
316 317 318 319 320

static uint16_t reverse_lut(const uint8_t *bitmap, uint16_t *lut)
{
    int i, k = 0;

Jimmy Christensen's avatar
Jimmy Christensen committed
321
    for (i = 0; i < USHORT_RANGE; i++)
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
        if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
            lut[k++] = i;

    i = k - 1;

    memset(lut + k, 0, (USHORT_RANGE - k) * 2);

    return i;
}

static void apply_lut(const uint16_t *lut, uint16_t *dst, int dsize)
{
    int i;

    for (i = 0; i < dsize; ++i)
        dst[i] = lut[dst[i]];
}

#define HUF_ENCBITS 16  // literal (value) bit length
#define HUF_DECBITS 14  // decoding bit size (>= 8)

#define HUF_ENCSIZE ((1 << HUF_ENCBITS) + 1)  // encoding table size
Jimmy Christensen's avatar
Jimmy Christensen committed
344
#define HUF_DECSIZE (1 << HUF_DECBITS)        // decoding table size
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
#define HUF_DECMASK (HUF_DECSIZE - 1)

typedef struct HufDec {
    int len;
    int lit;
    int *p;
} HufDec;

static void huf_canonical_code_table(uint64_t *hcode)
{
    uint64_t c, n[59] = { 0 };
    int i;

    for (i = 0; i < HUF_ENCSIZE; ++i)
        n[hcode[i]] += 1;

    c = 0;
    for (i = 58; i > 0; --i) {
        uint64_t nc = ((c + n[i]) >> 1);
        n[i] = c;
Jimmy Christensen's avatar
Jimmy Christensen committed
365
        c    = nc;
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
    }

    for (i = 0; i < HUF_ENCSIZE; ++i) {
        int l = hcode[i];

        if (l > 0)
            hcode[i] = l | (n[l]++ << 6);
    }
}

#define SHORT_ZEROCODE_RUN  59
#define LONG_ZEROCODE_RUN   63
#define SHORTEST_LONG_RUN   (2 + LONG_ZEROCODE_RUN - SHORT_ZEROCODE_RUN)
#define LONGEST_LONG_RUN    (255 + SHORTEST_LONG_RUN)

static int huf_unpack_enc_table(GetByteContext *gb,
                                int32_t im, int32_t iM, uint64_t *hcode)
{
    GetBitContext gbit;
385 386 387
    int ret = init_get_bits8(&gbit, gb->buffer, bytestream2_get_bytes_left(gb));
    if (ret < 0)
        return ret;
388 389 390 391 392 393 394 395 396 397 398 399 400 401

    for (; im <= iM; im++) {
        uint64_t l = hcode[im] = get_bits(&gbit, 6);

        if (l == LONG_ZEROCODE_RUN) {
            int zerun = get_bits(&gbit, 8) + SHORTEST_LONG_RUN;

            if (im + zerun > iM + 1)
                return AVERROR_INVALIDDATA;

            while (zerun--)
                hcode[im++] = 0;

            im--;
Jimmy Christensen's avatar
Jimmy Christensen committed
402
        } else if (l >= SHORT_ZEROCODE_RUN) {
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437
            int zerun = l - SHORT_ZEROCODE_RUN + 2;

            if (im + zerun > iM + 1)
                return AVERROR_INVALIDDATA;

            while (zerun--)
                hcode[im++] = 0;

            im--;
        }
    }

    bytestream2_skip(gb, (get_bits_count(&gbit) + 7) / 8);
    huf_canonical_code_table(hcode);

    return 0;
}

static int huf_build_dec_table(const uint64_t *hcode, int im,
                               int iM, HufDec *hdecod)
{
    for (; im <= iM; im++) {
        uint64_t c = hcode[im] >> 6;
        int i, l = hcode[im] & 63;

        if (c >> l)
            return AVERROR_INVALIDDATA;

        if (l > HUF_DECBITS) {
            HufDec *pl = hdecod + (c >> (l - HUF_DECBITS));
            if (pl->len)
                return AVERROR_INVALIDDATA;

            pl->lit++;

Jimmy Christensen's avatar
Jimmy Christensen committed
438
            pl->p = av_realloc(pl->p, pl->lit * sizeof(int));
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
            if (!pl->p)
                return AVERROR(ENOMEM);

            pl->p[pl->lit - 1] = im;
        } else if (l) {
            HufDec *pl = hdecod + (c << (HUF_DECBITS - l));

            for (i = 1 << (HUF_DECBITS - l); i > 0; i--, pl++) {
                if (pl->len || pl->p)
                    return AVERROR_INVALIDDATA;
                pl->len = l;
                pl->lit = im;
            }
        }
    }

    return 0;
}

Jimmy Christensen's avatar
Jimmy Christensen committed
458 459 460 461
#define get_char(c, lc, gb)                                                   \
{                                                                             \
        c   = (c << 8) | bytestream2_get_byte(gb);                            \
        lc += 8;                                                              \
462 463
}

Jimmy Christensen's avatar
Jimmy Christensen committed
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484
#define get_code(po, rlc, c, lc, gb, out, oe)                                 \
{                                                                             \
        if (po == rlc) {                                                      \
            if (lc < 8)                                                       \
                get_char(c, lc, gb);                                          \
            lc -= 8;                                                          \
                                                                              \
            cs = c >> lc;                                                     \
                                                                              \
            if (out + cs > oe)                                                \
                return AVERROR_INVALIDDATA;                                   \
                                                                              \
            s = out[-1];                                                      \
                                                                              \
            while (cs-- > 0)                                                  \
                *out++ = s;                                                   \
        } else if (out < oe) {                                                \
            *out++ = po;                                                      \
        } else {                                                              \
            return AVERROR_INVALIDDATA;                                       \
        }                                                                     \
485 486 487 488 489 490
}

static int huf_decode(const uint64_t *hcode, const HufDec *hdecod,
                      GetByteContext *gb, int nbits,
                      int rlc, int no, uint16_t *out)
{
Jimmy Christensen's avatar
Jimmy Christensen committed
491 492 493
    uint64_t c        = 0;
    uint16_t *outb    = out;
    uint16_t *oe      = out + no;
494 495 496 497 498 499 500 501
    const uint8_t *ie = gb->buffer + (nbits + 7) / 8; // input byte size
    uint8_t cs, s;
    int i, lc = 0;

    while (gb->buffer < ie) {
        get_char(c, lc, gb);

        while (lc >= HUF_DECBITS) {
Jimmy Christensen's avatar
Jimmy Christensen committed
502
            const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK];
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534

            if (pl.len) {
                lc -= pl.len;
                get_code(pl.lit, rlc, c, lc, gb, out, oe);
            } else {
                int j;

                if (!pl.p)
                    return AVERROR_INVALIDDATA;

                for (j = 0; j < pl.lit; j++) {
                    int l = hcode[pl.p[j]] & 63;

                    while (lc < l && bytestream2_get_bytes_left(gb) > 0)
                        get_char(c, lc, gb);

                    if (lc >= l) {
                        if ((hcode[pl.p[j]] >> 6) ==
                            ((c >> (lc - l)) & ((1LL << l) - 1))) {
                            lc -= l;
                            get_code(pl.p[j], rlc, c, lc, gb, out, oe);
                            break;
                        }
                    }
                }

                if (j == pl.lit)
                    return AVERROR_INVALIDDATA;
            }
        }
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
535
    i   = (8 - nbits) & 7;
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
    c >>= i;
    lc -= i;

    while (lc > 0) {
        const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK];

        if (pl.len) {
            lc -= pl.len;
            get_code(pl.lit, rlc, c, lc, gb, out, oe);
        } else {
            return AVERROR_INVALIDDATA;
        }
    }

    if (out - outb != no)
        return AVERROR_INVALIDDATA;
    return 0;
}

static int huf_uncompress(GetByteContext *gb,
                          uint16_t *dst, int dst_size)
{
    int32_t src_size, im, iM;
    uint32_t nBits;
    uint64_t *freq;
    HufDec *hdec;
    int ret, i;

    src_size = bytestream2_get_le32(gb);
Jimmy Christensen's avatar
Jimmy Christensen committed
565 566
    im       = bytestream2_get_le32(gb);
    iM       = bytestream2_get_le32(gb);
567 568 569 570 571 572 573 574 575
    bytestream2_skip(gb, 4);
    nBits = bytestream2_get_le32(gb);
    if (im < 0 || im >= HUF_ENCSIZE ||
        iM < 0 || iM >= HUF_ENCSIZE ||
        src_size < 0)
        return AVERROR_INVALIDDATA;

    bytestream2_skip(gb, 4);

Jimmy Christensen's avatar
Jimmy Christensen committed
576 577
    freq = av_mallocz_array(HUF_ENCSIZE, sizeof(*freq));
    hdec = av_mallocz_array(HUF_DECSIZE, sizeof(*hdec));
578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
    if (!freq || !hdec) {
        ret = AVERROR(ENOMEM);
        goto fail;
    }

    if ((ret = huf_unpack_enc_table(gb, im, iM, freq)) < 0)
        goto fail;

    if (nBits > 8 * bytestream2_get_bytes_left(gb)) {
        ret = AVERROR_INVALIDDATA;
        goto fail;
    }

    if ((ret = huf_build_dec_table(freq, im, iM, hdec)) < 0)
        goto fail;
    ret = huf_decode(freq, hdec, gb, nBits, iM, dst_size, dst);

fail:
Jimmy Christensen's avatar
Jimmy Christensen committed
596
    for (i = 0; i < HUF_DECSIZE; i++)
597
        if (hdec)
598
            av_freep(&hdec[i].p);
599 600 601 602 603 604 605 606 607 608 609

    av_free(freq);
    av_free(hdec);

    return ret;
}

static inline void wdec14(uint16_t l, uint16_t h, uint16_t *a, uint16_t *b)
{
    int16_t ls = l;
    int16_t hs = h;
Jimmy Christensen's avatar
Jimmy Christensen committed
610 611
    int hi     = hs;
    int ai     = ls + (hi & 1) + (hi >> 1);
612 613 614 615 616 617 618 619
    int16_t as = ai;
    int16_t bs = ai - hi;

    *a = as;
    *b = bs;
}

#define NBITS      16
Jimmy Christensen's avatar
Jimmy Christensen committed
620
#define A_OFFSET  (1 << (NBITS - 1))
621 622 623 624
#define MOD_MASK  ((1 << NBITS) - 1)

static inline void wdec16(uint16_t l, uint16_t h, uint16_t *a, uint16_t *b)
{
Jimmy Christensen's avatar
Jimmy Christensen committed
625 626
    int m  = l;
    int d  = h;
627 628 629 630 631 632 633 634 635 636
    int bb = (m - (d >> 1)) & MOD_MASK;
    int aa = (d + bb - A_OFFSET) & MOD_MASK;
    *b = bb;
    *a = aa;
}

static void wav_decode(uint16_t *in, int nx, int ox,
                       int ny, int oy, uint16_t mx)
{
    int w14 = (mx < (1 << 14));
Jimmy Christensen's avatar
Jimmy Christensen committed
637 638
    int n   = (nx > ny) ? ny : nx;
    int p   = 1;
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
    int p2;

    while (p <= n)
        p <<= 1;

    p >>= 1;
    p2  = p;
    p >>= 1;

    while (p >= 1) {
        uint16_t *py = in;
        uint16_t *ey = in + oy * (ny - p2);
        uint16_t i00, i01, i10, i11;
        int oy1 = oy * p;
        int oy2 = oy * p2;
        int ox1 = ox * p;
        int ox2 = ox * p2;

        for (; py <= ey; py += oy2) {
            uint16_t *px = py;
            uint16_t *ex = py + ox * (nx - p2);

            for (; px <= ex; px += ox2) {
Jimmy Christensen's avatar
Jimmy Christensen committed
662 663
                uint16_t *p01 = px + ox1;
                uint16_t *p10 = px + oy1;
664 665 666
                uint16_t *p11 = p10 + ox1;

                if (w14) {
Jimmy Christensen's avatar
Jimmy Christensen committed
667
                    wdec14(*px, *p10, &i00, &i10);
668
                    wdec14(*p01, *p11, &i01, &i11);
Jimmy Christensen's avatar
Jimmy Christensen committed
669
                    wdec14(i00, i01, px, p01);
670 671
                    wdec14(i10, i11, p10, p11);
                } else {
Jimmy Christensen's avatar
Jimmy Christensen committed
672
                    wdec16(*px, *p10, &i00, &i10);
673
                    wdec16(*p01, *p11, &i01, &i11);
Jimmy Christensen's avatar
Jimmy Christensen committed
674
                    wdec16(i00, i01, px, p01);
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
                    wdec16(i10, i11, p10, p11);
                }
            }

            if (nx & p) {
                uint16_t *p10 = px + oy1;

                if (w14)
                    wdec14(*px, *p10, &i00, p10);
                else
                    wdec16(*px, *p10, &i00, p10);

                *px = i00;
            }
        }

        if (ny & p) {
            uint16_t *px = py;
            uint16_t *ex = py + ox * (nx - p2);

            for (; px <= ex; px += ox2) {
                uint16_t *p01 = px + ox1;

                if (w14)
                    wdec14(*px, *p01, &i00, p01);
                else
                    wdec16(*px, *p01, &i00, p01);

                *px = i00;
            }
        }

Jimmy Christensen's avatar
Jimmy Christensen committed
707
        p2  = p;
708 709 710 711
        p >>= 1;
    }
}

Jimmy Christensen's avatar
Jimmy Christensen committed
712 713
static int piz_uncompress(EXRContext *s, const uint8_t *src, int ssize,
                          int dsize, EXRThreadData *td)
714 715 716
{
    GetByteContext gb;
    uint16_t maxval, min_non_zero, max_non_zero;
Jimmy Christensen's avatar
Jimmy Christensen committed
717 718 719
    uint16_t *ptr;
    uint16_t *tmp = (uint16_t *)td->tmp;
    uint8_t *out;
720 721 722 723 724 725
    int ret, i, j;

    if (!td->bitmap)
        td->bitmap = av_malloc(BITMAP_SIZE);
    if (!td->lut)
        td->lut = av_malloc(1 << 17);
Jimmy Christensen's avatar
Jimmy Christensen committed
726
    if (!td->bitmap || !td->lut) {
727 728
        av_freep(&td->bitmap);
        av_freep(&td->lut);
729
        return AVERROR(ENOMEM);
Jimmy Christensen's avatar
Jimmy Christensen committed
730
    }
731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746

    bytestream2_init(&gb, src, ssize);
    min_non_zero = bytestream2_get_le16(&gb);
    max_non_zero = bytestream2_get_le16(&gb);

    if (max_non_zero >= BITMAP_SIZE)
        return AVERROR_INVALIDDATA;

    memset(td->bitmap, 0, FFMIN(min_non_zero, BITMAP_SIZE));
    if (min_non_zero <= max_non_zero)
        bytestream2_get_buffer(&gb, td->bitmap + min_non_zero,
                               max_non_zero - min_non_zero + 1);
    memset(td->bitmap + max_non_zero, 0, BITMAP_SIZE - max_non_zero);

    maxval = reverse_lut(td->bitmap, td->lut);

Jimmy Christensen's avatar
Jimmy Christensen committed
747
    ret = huf_uncompress(&gb, tmp, dsize / sizeof(uint16_t));
748 749 750 751 752 753 754 755 756
    if (ret)
        return ret;

    ptr = tmp;
    for (i = 0; i < s->nb_channels; i++) {
        EXRChannel *channel = &s->channels[i];
        int size = channel->pixel_type;

        for (j = 0; j < size; j++)
Jimmy Christensen's avatar
Jimmy Christensen committed
757 758
            wav_decode(ptr + j, s->xdelta, size, s->ysize,
                       s->xdelta * size, maxval);
759 760 761
        ptr += s->xdelta * s->ysize * size;
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
762
    apply_lut(td->lut, tmp, dsize / sizeof(uint16_t));
763 764

    out = td->uncompressed_data;
Jimmy Christensen's avatar
Jimmy Christensen committed
765
    for (i = 0; i < s->ysize; i++)
766 767 768 769 770 771 772 773 774
        for (j = 0; j < s->nb_channels; j++) {
            uint16_t *in = tmp + j * s->xdelta * s->ysize + i * s->xdelta;
            memcpy(out, in, s->xdelta * 2);
            out += s->xdelta * 2;
        }

    return 0;
}

Paul B Mahol's avatar
Paul B Mahol committed
775 776 777 778 779 780 781 782 783 784 785
static int pxr24_uncompress(EXRContext *s, const uint8_t *src,
                            int compressed_size, int uncompressed_size,
                            EXRThreadData *td)
{
    unsigned long dest_len = uncompressed_size;
    const uint8_t *in = td->tmp;
    uint8_t *out;
    int c, i, j;

    if (uncompress(td->tmp, &dest_len, src, compressed_size) != Z_OK ||
        dest_len != uncompressed_size)
Jimmy Christensen's avatar
Jimmy Christensen committed
786
        return AVERROR_INVALIDDATA;
Paul B Mahol's avatar
Paul B Mahol committed
787 788

    out = td->uncompressed_data;
Jimmy Christensen's avatar
Jimmy Christensen committed
789
    for (i = 0; i < s->ysize; i++)
Paul B Mahol's avatar
Paul B Mahol committed
790 791 792 793 794 795 796 797 798 799
        for (c = 0; c < s->nb_channels; c++) {
            EXRChannel *channel = &s->channels[c];
            const uint8_t *ptr[4];
            uint32_t pixel = 0;

            switch (channel->pixel_type) {
            case EXR_FLOAT:
                ptr[0] = in;
                ptr[1] = ptr[0] + s->xdelta;
                ptr[2] = ptr[1] + s->xdelta;
Jimmy Christensen's avatar
Jimmy Christensen committed
800
                in     = ptr[2] + s->xdelta;
Paul B Mahol's avatar
Paul B Mahol committed
801 802 803 804

                for (j = 0; j < s->xdelta; ++j) {
                    uint32_t diff = (*(ptr[0]++) << 24) |
                                    (*(ptr[1]++) << 16) |
Jimmy Christensen's avatar
Jimmy Christensen committed
805
                                    (*(ptr[2]++) << 8);
Paul B Mahol's avatar
Paul B Mahol committed
806
                    pixel += diff;
807
                    bytestream_put_le32(&out, pixel);
Paul B Mahol's avatar
Paul B Mahol committed
808 809 810 811 812
                }
                break;
            case EXR_HALF:
                ptr[0] = in;
                ptr[1] = ptr[0] + s->xdelta;
Jimmy Christensen's avatar
Jimmy Christensen committed
813
                in     = ptr[1] + s->xdelta;
814
                for (j = 0; j < s->xdelta; j++) {
Paul B Mahol's avatar
Paul B Mahol committed
815 816 817
                    uint32_t diff = (*(ptr[0]++) << 8) | *(ptr[1]++);

                    pixel += diff;
818
                    bytestream_put_le16(&out, pixel);
Paul B Mahol's avatar
Paul B Mahol committed
819 820 821
                }
                break;
            default:
Jimmy Christensen's avatar
Jimmy Christensen committed
822
                return AVERROR_INVALIDDATA;
Paul B Mahol's avatar
Paul B Mahol committed
823 824 825 826 827 828
            }
        }

    return 0;
}

Paul B Mahol's avatar
Paul B Mahol committed
829 830 831 832
static int decode_block(AVCodecContext *avctx, void *tdata,
                        int jobnr, int threadnr)
{
    EXRContext *s = avctx->priv_data;
833
    AVFrame *const p = s->picture;
Paul B Mahol's avatar
Paul B Mahol committed
834 835 836 837 838 839 840
    EXRThreadData *td = &s->thread_data[threadnr];
    const uint8_t *channel_buffer[4] = { 0 };
    const uint8_t *buf = s->buf;
    uint64_t line_offset, uncompressed_size;
    uint32_t xdelta = s->xdelta;
    uint16_t *ptr_x;
    uint8_t *ptr;
Jimmy Christensen's avatar
Jimmy Christensen committed
841
    uint32_t data_size, line;
Paul B Mahol's avatar
Paul B Mahol committed
842 843 844
    const uint8_t *src;
    int axmax = (avctx->width - (s->xmax + 1)) * 2 * s->desc->nb_components;
    int bxmin = s->xmin * 2 * s->desc->nb_components;
845
    int i, x, buf_size = s->buf_size;
Jimmy Christensen's avatar
Jimmy Christensen committed
846
    int ret;
847
    float one_gamma = 1.0f / s->gamma;
Paul B Mahol's avatar
Paul B Mahol committed
848

Jimmy Christensen's avatar
Jimmy Christensen committed
849
    line_offset = AV_RL64(s->gb.buffer + jobnr * 8);
Paul B Mahol's avatar
Paul B Mahol committed
850 851 852 853
    // Check if the buffer has the required bytes needed from the offset
    if (line_offset > buf_size - 8)
        return AVERROR_INVALIDDATA;

Jimmy Christensen's avatar
Jimmy Christensen committed
854
    src  = buf + line_offset + 8;
Paul B Mahol's avatar
Paul B Mahol committed
855 856 857 858 859 860 861 862
    line = AV_RL32(src - 8);
    if (line < s->ymin || line > s->ymax)
        return AVERROR_INVALIDDATA;

    data_size = AV_RL32(src - 4);
    if (data_size <= 0 || data_size > buf_size)
        return AVERROR_INVALIDDATA;

Jimmy Christensen's avatar
Jimmy Christensen committed
863
    s->ysize          = FFMIN(s->scan_lines_per_block, s->ymax - line + 1);
Paul B Mahol's avatar
Paul B Mahol committed
864
    uncompressed_size = s->scan_line_size * s->ysize;
Jimmy Christensen's avatar
Jimmy Christensen committed
865
    if ((s->compression == EXR_RAW && (data_size != uncompressed_size ||
Paul B Mahol's avatar
Paul B Mahol committed
866
                                 line_offset > buf_size - uncompressed_size)) ||
Jimmy Christensen's avatar
Jimmy Christensen committed
867
        (s->compression != EXR_RAW && (data_size > uncompressed_size ||
868
                                 line_offset > buf_size - data_size))) {
Paul B Mahol's avatar
Paul B Mahol committed
869 870 871 872
        return AVERROR_INVALIDDATA;
    }

    if (data_size < uncompressed_size) {
Jimmy Christensen's avatar
Jimmy Christensen committed
873 874
        av_fast_padded_malloc(&td->uncompressed_data,
                              &td->uncompressed_size, uncompressed_size);
Paul B Mahol's avatar
Paul B Mahol committed
875 876 877 878
        av_fast_padded_malloc(&td->tmp, &td->tmp_size, uncompressed_size);
        if (!td->uncompressed_data || !td->tmp)
            return AVERROR(ENOMEM);

Jimmy Christensen's avatar
Jimmy Christensen committed
879 880
        ret = AVERROR_INVALIDDATA;
        switch (s->compression) {
881 882 883 884
        case EXR_ZIP1:
        case EXR_ZIP16:
            ret = zip_uncompress(src, data_size, uncompressed_size, td);
            break;
885 886 887
        case EXR_PIZ:
            ret = piz_uncompress(s, src, data_size, uncompressed_size, td);
            break;
Paul B Mahol's avatar
Paul B Mahol committed
888 889 890
        case EXR_PXR24:
            ret = pxr24_uncompress(s, src, data_size, uncompressed_size, td);
            break;
891 892
        case EXR_RLE:
            ret = rle_uncompress(src, data_size, uncompressed_size, td);
Paul B Mahol's avatar
Paul B Mahol committed
893
        }
Jimmy Christensen's avatar
Jimmy Christensen committed
894 895 896 897
        if (ret < 0) {
            av_log(avctx, AV_LOG_ERROR, "decode_block() failed.\n");
            return ret;
        }
898
        src = td->uncompressed_data;
Paul B Mahol's avatar
Paul B Mahol committed
899 900
    }

901 902 903 904 905 906
    channel_buffer[0] = src + xdelta * s->channel_offsets[0];
    channel_buffer[1] = src + xdelta * s->channel_offsets[1];
    channel_buffer[2] = src + xdelta * s->channel_offsets[2];
    if (s->channel_offsets[3] >= 0)
        channel_buffer[3] = src + xdelta * s->channel_offsets[3];

Paul B Mahol's avatar
Paul B Mahol committed
907
    ptr = p->data[0] + line * p->linesize[0];
Jimmy Christensen's avatar
Jimmy Christensen committed
908 909 910
    for (i = 0;
         i < s->scan_lines_per_block && line + i <= s->ymax;
         i++, ptr += p->linesize[0]) {
Paul B Mahol's avatar
Paul B Mahol committed
911 912 913 914 915 916 917 918
        const uint8_t *r, *g, *b, *a;

        r = channel_buffer[0];
        g = channel_buffer[1];
        b = channel_buffer[2];
        if (channel_buffer[3])
            a = channel_buffer[3];

Jimmy Christensen's avatar
Jimmy Christensen committed
919
        ptr_x = (uint16_t *) ptr;
Paul B Mahol's avatar
Paul B Mahol committed
920 921 922 923

        // Zero out the start if xmin is not 0
        memset(ptr_x, 0, bxmin);
        ptr_x += s->xmin * s->desc->nb_components;
924
        if (s->pixel_type == EXR_FLOAT) {
Paul B Mahol's avatar
Paul B Mahol committed
925 926
            // 32-bit
            for (x = 0; x < xdelta; x++) {
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
                union av_intfloat32 t;
                t.i = bytestream_get_le32(&r);
                if ( t.f > 0.0f )  /* avoid negative values */
                    t.f = powf(t.f, one_gamma);
                *ptr_x++ = exr_flt2uint(t.i);

                t.i = bytestream_get_le32(&g);
                if ( t.f > 0.0f )
                    t.f = powf(t.f, one_gamma);
                *ptr_x++ = exr_flt2uint(t.i);

                t.i = bytestream_get_le32(&b);
                if ( t.f > 0.0f )
                    t.f = powf(t.f, one_gamma);
                *ptr_x++ = exr_flt2uint(t.i);
Paul B Mahol's avatar
Paul B Mahol committed
942 943 944 945 946 947
                if (channel_buffer[3])
                    *ptr_x++ = exr_flt2uint(bytestream_get_le32(&a));
            }
        } else {
            // 16-bit
            for (x = 0; x < xdelta; x++) {
948 949 950
                *ptr_x++ = s->gamma_table[bytestream_get_le16(&r)];
                *ptr_x++ = s->gamma_table[bytestream_get_le16(&g)];
                *ptr_x++ = s->gamma_table[bytestream_get_le16(&b)];
Paul B Mahol's avatar
Paul B Mahol committed
951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968
                if (channel_buffer[3])
                    *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&a));
            }
        }

        // Zero out the end if xmax+1 is not w
        memset(ptr_x, 0, axmax);

        channel_buffer[0] += s->scan_line_size;
        channel_buffer[1] += s->scan_line_size;
        channel_buffer[2] += s->scan_line_size;
        if (channel_buffer[3])
            channel_buffer[3] += s->scan_line_size;
    }

    return 0;
}

Jimmy Christensen's avatar
Jimmy Christensen committed
969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984
/**
 * Check if the variable name corresponds to its data type.
 *
 * @param s              the EXRContext
 * @param value_name     name of the variable to check
 * @param value_type     type of the variable to check
 * @param minimum_length minimum length of the variable data
 *
 * @return bytes to read containing variable data
 *         -1 if variable is not found
 *         0 if buffer ended prematurely
 */
static int check_header_variable(EXRContext *s,
                                 const char *value_name,
                                 const char *value_type,
                                 unsigned int minimum_length)
985
{
Jimmy Christensen's avatar
Jimmy Christensen committed
986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
    int var_size = -1;

    if (bytestream2_get_bytes_left(&s->gb) >= minimum_length &&
        !strcmp(s->gb.buffer, value_name)) {
        // found value_name, jump to value_type (null terminated strings)
        s->gb.buffer += strlen(value_name) + 1;
        if (!strcmp(s->gb.buffer, value_type)) {
            s->gb.buffer += strlen(value_type) + 1;
            var_size = bytestream2_get_le32(&s->gb);
            // don't go read past boundaries
            if (var_size > bytestream2_get_bytes_left(&s->gb))
                var_size = 0;
        } else {
            // value_type not found, reset the buffer
            s->gb.buffer -= strlen(value_name) + 1;
            av_log(s->avctx, AV_LOG_WARNING,
                   "Unknown data type %s for header variable %s.\n",
                   value_type, value_name);
        }
    }
1006

Jimmy Christensen's avatar
Jimmy Christensen committed
1007 1008
    return var_size;
}
Paul B Mahol's avatar
Paul B Mahol committed
1009

Jimmy Christensen's avatar
Jimmy Christensen committed
1010 1011 1012 1013
static int decode_header(EXRContext *s)
{
    int current_channel_offset = 0;
    int magic_number, version, flags, i;
1014

Jimmy Christensen's avatar
Jimmy Christensen committed
1015 1016
    if (bytestream2_get_bytes_left(&s->gb) < 10) {
        av_log(s->avctx, AV_LOG_ERROR, "Header too short to parse.\n");
1017
        return AVERROR_INVALIDDATA;
1018 1019
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1020 1021 1022 1023 1024
    magic_number = bytestream2_get_le32(&s->gb);
    if (magic_number != 20000630) {
        /* As per documentation of OpenEXR, it is supposed to be
         * int 20000630 little-endian */
        av_log(s->avctx, AV_LOG_ERROR, "Wrong magic number %d.\n", magic_number);
1025
        return AVERROR_INVALIDDATA;
1026 1027
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1028
    version = bytestream2_get_byte(&s->gb);
Paul B Mahol's avatar
Paul B Mahol committed
1029
    if (version != 2) {
Jimmy Christensen's avatar
Jimmy Christensen committed
1030
        avpriv_report_missing_feature(s->avctx, "Version %d", version);
Paul B Mahol's avatar
Paul B Mahol committed
1031 1032 1033
        return AVERROR_PATCHWELCOME;
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1034 1035 1036
    flags = bytestream2_get_le24(&s->gb);
    if (flags & 0x02) {
        avpriv_report_missing_feature(s->avctx, "Tile support");
1037
        return AVERROR_PATCHWELCOME;
1038 1039 1040
    }

    // Parse the header
Jimmy Christensen's avatar
Jimmy Christensen committed
1041 1042 1043 1044 1045 1046
    while (bytestream2_get_bytes_left(&s->gb) > 0 && *s->gb.buffer) {
        int var_size;
        if ((var_size = check_header_variable(s, "channels",
                                              "chlist", 38)) >= 0) {
            GetByteContext ch_gb;
            if (!var_size)
1047
                return AVERROR_INVALIDDATA;
1048

Jimmy Christensen's avatar
Jimmy Christensen committed
1049 1050 1051
            bytestream2_init(&ch_gb, s->gb.buffer, var_size);

            while (bytestream2_get_bytes_left(&ch_gb) >= 19) {
1052
                EXRChannel *channel;
1053
                enum ExrPixelType current_pixel_type;
1054
                int channel_index = -1;
1055
                int xsub, ysub;
1056

Jimmy Christensen's avatar
Jimmy Christensen committed
1057 1058 1059 1060 1061 1062 1063
                if (strcmp(s->layer, "") != 0) {
                    if (strncmp(ch_gb.buffer, s->layer, strlen(s->layer)) == 0) {
                        ch_gb.buffer += strlen(s->layer);
                        if (*ch_gb.buffer == '.')
                            ch_gb.buffer++;         /* skip dot if not given */
                        av_log(s->avctx, AV_LOG_INFO,
                               "Layer %s.%s matched.\n", s->layer, ch_gb.buffer);
1064 1065 1066
                    }
                }

Jimmy Christensen's avatar
Jimmy Christensen committed
1067 1068 1069
                if (!strcmp(ch_gb.buffer, "R") ||
                    !strcmp(ch_gb.buffer, "X") ||
                    !strcmp(ch_gb.buffer, "U"))
1070
                    channel_index = 0;
Jimmy Christensen's avatar
Jimmy Christensen committed
1071 1072 1073
                else if (!strcmp(ch_gb.buffer, "G") ||
                         !strcmp(ch_gb.buffer, "Y") ||
                         !strcmp(ch_gb.buffer, "V"))
1074
                    channel_index = 1;
Jimmy Christensen's avatar
Jimmy Christensen committed
1075 1076 1077
                else if (!strcmp(ch_gb.buffer, "B") ||
                         !strcmp(ch_gb.buffer, "Z") ||
                         !strcmp(ch_gb.buffer, "W"))
1078
                    channel_index = 2;
Jimmy Christensen's avatar
Jimmy Christensen committed
1079
                else if (!strcmp(ch_gb.buffer, "A"))
Paul B Mahol's avatar
Paul B Mahol committed
1080
                    channel_index = 3;
1081
                else
Jimmy Christensen's avatar
Jimmy Christensen committed
1082 1083
                    av_log(s->avctx, AV_LOG_WARNING,
                           "Unsupported channel %.256s.\n", ch_gb.buffer);
1084

Jimmy Christensen's avatar
Jimmy Christensen committed
1085 1086 1087 1088
                /* skip until you get a 0 */
                while (bytestream2_get_bytes_left(&ch_gb) > 0 &&
                       bytestream2_get_byte(&ch_gb))
                    continue;
1089

Jimmy Christensen's avatar
Jimmy Christensen committed
1090 1091
                if (bytestream2_get_bytes_left(&ch_gb) < 4) {
                    av_log(s->avctx, AV_LOG_ERROR, "Incomplete header.\n");
1092
                    return AVERROR_INVALIDDATA;
1093 1094
                }

Jimmy Christensen's avatar
Jimmy Christensen committed
1095 1096 1097 1098 1099 1100
                current_pixel_type = bytestream2_get_le32(&ch_gb);
                if (current_pixel_type >= EXR_UNKNOWN) {
                    avpriv_report_missing_feature(s->avctx,
                                                  "Pixel type %d.\n",
                                                  current_pixel_type);
                    return AVERROR_PATCHWELCOME;
1101 1102
                }

Jimmy Christensen's avatar
Jimmy Christensen committed
1103 1104 1105
                bytestream2_skip(&ch_gb, 4);
                xsub = bytestream2_get_le32(&ch_gb);
                ysub = bytestream2_get_le32(&ch_gb);
1106
                if (xsub != 1 || ysub != 1) {
Jimmy Christensen's avatar
Jimmy Christensen committed
1107 1108 1109
                    avpriv_report_missing_feature(s->avctx,
                                                  "Subsampling %dx%d",
                                                  xsub, ysub);
1110 1111 1112
                    return AVERROR_PATCHWELCOME;
                }

1113
                if (channel_index >= 0) {
Jimmy Christensen's avatar
Jimmy Christensen committed
1114 1115 1116 1117
                    if (s->pixel_type != EXR_UNKNOWN &&
                        s->pixel_type != current_pixel_type) {
                        av_log(s->avctx, AV_LOG_ERROR,
                               "RGB channels not of the same depth.\n");
1118
                        return AVERROR_INVALIDDATA;
1119
                    }
Jimmy Christensen's avatar
Jimmy Christensen committed
1120
                    s->pixel_type                     = current_pixel_type;
1121 1122 1123
                    s->channel_offsets[channel_index] = current_channel_offset;
                }

Jimmy Christensen's avatar
Jimmy Christensen committed
1124 1125
                s->channels = av_realloc(s->channels,
                                         ++s->nb_channels * sizeof(EXRChannel));
1126 1127
                if (!s->channels)
                    return AVERROR(ENOMEM);
Jimmy Christensen's avatar
Jimmy Christensen committed
1128
                channel             = &s->channels[s->nb_channels - 1];
1129
                channel->pixel_type = current_pixel_type;
Jimmy Christensen's avatar
Jimmy Christensen committed
1130 1131
                channel->xsub       = xsub;
                channel->ysub       = ysub;
1132

1133
                current_channel_offset += 1 << current_pixel_type;
1134 1135 1136 1137 1138 1139 1140 1141
            }

            /* Check if all channels are set with an offset or if the channels
             * are causing an overflow  */
            if (FFMIN3(s->channel_offsets[0],
                       s->channel_offsets[1],
                       s->channel_offsets[2]) < 0) {
                if (s->channel_offsets[0] < 0)
Jimmy Christensen's avatar
Jimmy Christensen committed
1142
                    av_log(s->avctx, AV_LOG_ERROR, "Missing red channel.\n");
1143
                if (s->channel_offsets[1] < 0)
Jimmy Christensen's avatar
Jimmy Christensen committed
1144
                    av_log(s->avctx, AV_LOG_ERROR, "Missing green channel.\n");
1145
                if (s->channel_offsets[2] < 0)
Jimmy Christensen's avatar
Jimmy Christensen committed
1146
                    av_log(s->avctx, AV_LOG_ERROR, "Missing blue channel.\n");
1147
                return AVERROR_INVALIDDATA;
1148 1149
            }

Jimmy Christensen's avatar
Jimmy Christensen committed
1150 1151
            // skip one last byte and update main gb
            s->gb.buffer = ch_gb.buffer + 1;
1152
            continue;
Jimmy Christensen's avatar
Jimmy Christensen committed
1153 1154 1155
        } else if ((var_size = check_header_variable(s, "dataWindow", "box2i",
                                                     31)) >= 0) {
            if (!var_size)
1156
                return AVERROR_INVALIDDATA;
1157

Jimmy Christensen's avatar
Jimmy Christensen committed
1158 1159 1160 1161
            s->xmin   = bytestream2_get_le32(&s->gb);
            s->ymin   = bytestream2_get_le32(&s->gb);
            s->xmax   = bytestream2_get_le32(&s->gb);
            s->ymax   = bytestream2_get_le32(&s->gb);
Paul B Mahol's avatar
Paul B Mahol committed
1162 1163
            s->xdelta = (s->xmax - s->xmin) + 1;
            s->ydelta = (s->ymax - s->ymin) + 1;
1164 1165

            continue;
Jimmy Christensen's avatar
Jimmy Christensen committed
1166 1167 1168
        } else if ((var_size = check_header_variable(s, "displayWindow",
                                                     "box2i", 34)) >= 0) {
            if (!var_size)
1169
                return AVERROR_INVALIDDATA;
1170

Jimmy Christensen's avatar
Jimmy Christensen committed
1171 1172 1173
            bytestream2_skip(&s->gb, 8);
            s->w = bytestream2_get_le32(&s->gb) + 1;
            s->h = bytestream2_get_le32(&s->gb) + 1;
1174 1175

            continue;
Jimmy Christensen's avatar
Jimmy Christensen committed
1176 1177 1178 1179
        } else if ((var_size = check_header_variable(s, "lineOrder",
                                                     "lineOrder", 25)) >= 0) {
            int line_order;
            if (!var_size)
1180
                return AVERROR_INVALIDDATA;
1181

Jimmy Christensen's avatar
Jimmy Christensen committed
1182 1183 1184 1185
            line_order = bytestream2_get_byte(&s->gb);
            av_log(s->avctx, AV_LOG_DEBUG, "line order: %d.\n", line_order);
            if (line_order > 2) {
                av_log(s->avctx, AV_LOG_ERROR, "Unknown line order.\n");
1186
                return AVERROR_INVALIDDATA;
1187 1188 1189
            }

            continue;
Jimmy Christensen's avatar
Jimmy Christensen committed
1190 1191 1192
        } else if ((var_size = check_header_variable(s, "pixelAspectRatio",
                                                     "float", 31)) >= 0) {
            if (!var_size)
1193
                return AVERROR_INVALIDDATA;
1194

1195 1196
            ff_set_sar(s->avctx,
                       av_d2q(av_int2float(bytestream2_get_le32(&s->gb)), 255));
1197 1198

            continue;
Jimmy Christensen's avatar
Jimmy Christensen committed
1199 1200 1201
        } else if ((var_size = check_header_variable(s, "compression",
                                                     "compression", 29)) >= 0) {
            if (!var_size)
1202
                return AVERROR_INVALIDDATA;
1203

Jimmy Christensen's avatar
Jimmy Christensen committed
1204 1205
            if (s->compression == EXR_UNKN)
                s->compression = bytestream2_get_byte(&s->gb);
1206
            else
Jimmy Christensen's avatar
Jimmy Christensen committed
1207 1208
                av_log(s->avctx, AV_LOG_WARNING,
                       "Found more than one compression attribute.\n");
1209 1210 1211 1212

            continue;
        }

Jimmy Christensen's avatar
Jimmy Christensen committed
1213 1214 1215
        // Check if there are enough bytes for a header
        if (bytestream2_get_bytes_left(&s->gb) <= 9) {
            av_log(s->avctx, AV_LOG_ERROR, "Incomplete header\n");
1216
            return AVERROR_INVALIDDATA;
1217 1218 1219
        }

        // Process unknown variables
Jimmy Christensen's avatar
Jimmy Christensen committed
1220 1221 1222
        for (i = 0; i < 2; i++) // value_name and value_type
            while (bytestream2_get_byte(&s->gb) != 0);

1223
        // Skip variable length
Jimmy Christensen's avatar
Jimmy Christensen committed
1224
        bytestream2_skip(&s->gb, bytestream2_get_le32(&s->gb));
1225 1226
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1227 1228
    if (s->compression == EXR_UNKN) {
        av_log(s->avctx, AV_LOG_ERROR, "Missing compression attribute.\n");
1229 1230
        return AVERROR_INVALIDDATA;
    }
Jimmy Christensen's avatar
Jimmy Christensen committed
1231
    s->scan_line_size = s->xdelta * current_channel_offset;
1232

Jimmy Christensen's avatar
Jimmy Christensen committed
1233 1234
    if (bytestream2_get_bytes_left(&s->gb) <= 0) {
        av_log(s->avctx, AV_LOG_ERROR, "Incomplete frame.\n");
1235
        return AVERROR_INVALIDDATA;
1236
    }
Jimmy Christensen's avatar
Jimmy Christensen committed
1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258

    // aaand we are done
    bytestream2_skip(&s->gb, 1);
    return 0;
}

static int decode_frame(AVCodecContext *avctx, void *data,
                        int *got_frame, AVPacket *avpkt)
{
    EXRContext *s = avctx->priv_data;
    ThreadFrame frame = { .f = data };
    AVFrame *picture = data;
    uint8_t *ptr;

    int y, ret;
    int out_line_size;
    int scan_line_blocks;

    bytestream2_init(&s->gb, avpkt->data, avpkt->size);

    if ((ret = decode_header(s)) < 0)
        return ret;
1259

1260 1261 1262
    switch (s->pixel_type) {
    case EXR_FLOAT:
    case EXR_HALF:
Paul B Mahol's avatar
Paul B Mahol committed
1263
        if (s->channel_offsets[3] >= 0)
1264
            avctx->pix_fmt = AV_PIX_FMT_RGBA64;
Paul B Mahol's avatar
Paul B Mahol committed
1265
        else
1266
            avctx->pix_fmt = AV_PIX_FMT_RGB48;
1267
        break;
1268
    case EXR_UINT:
1269
        avpriv_request_sample(avctx, "32-bit unsigned int");
1270
        return AVERROR_PATCHWELCOME;
1271
    default:
Jimmy Christensen's avatar
Jimmy Christensen committed
1272
        av_log(avctx, AV_LOG_ERROR, "Missing channel list.\n");
1273
        return AVERROR_INVALIDDATA;
1274 1275
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1276
    switch (s->compression) {
Paul B Mahol's avatar
Paul B Mahol committed
1277
    case EXR_RAW:
Paul B Mahol's avatar
Paul B Mahol committed
1278
    case EXR_RLE:
Paul B Mahol's avatar
Paul B Mahol committed
1279
    case EXR_ZIP1:
Paul B Mahol's avatar
Paul B Mahol committed
1280
        s->scan_lines_per_block = 1;
Paul B Mahol's avatar
Paul B Mahol committed
1281
        break;
Paul B Mahol's avatar
Paul B Mahol committed
1282
    case EXR_PXR24:
Paul B Mahol's avatar
Paul B Mahol committed
1283
    case EXR_ZIP16:
Paul B Mahol's avatar
Paul B Mahol committed
1284
        s->scan_lines_per_block = 16;
Paul B Mahol's avatar
Paul B Mahol committed
1285
        break;
1286 1287 1288
    case EXR_PIZ:
        s->scan_lines_per_block = 32;
        break;
Paul B Mahol's avatar
Paul B Mahol committed
1289
    default:
Jimmy Christensen's avatar
Jimmy Christensen committed
1290
        avpriv_report_missing_feature(avctx, "Compression %d", s->compression);
Paul B Mahol's avatar
Paul B Mahol committed
1291
        return AVERROR_PATCHWELCOME;
Paul B Mahol's avatar
Paul B Mahol committed
1292 1293
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1294 1295 1296 1297
    /* Verify the xmin, xmax, ymin, ymax and xdelta before setting
     * the actual image size. */
    if (s->xmin > s->xmax                  ||
        s->ymin > s->ymax                  ||
Paul B Mahol's avatar
Paul B Mahol committed
1298
        s->xdelta != s->xmax - s->xmin + 1 ||
Jimmy Christensen's avatar
Jimmy Christensen committed
1299 1300 1301
        s->xmax >= s->w                    ||
        s->ymax >= s->h) {
        av_log(avctx, AV_LOG_ERROR, "Wrong or missing size information.\n");
1302
        return AVERROR_INVALIDDATA;
1303 1304
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1305
    if ((ret = ff_set_dimensions(avctx, s->w, s->h)) < 0)
1306
        return ret;
1307

Jimmy Christensen's avatar
Jimmy Christensen committed
1308 1309 1310 1311 1312 1313
    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;
    scan_line_blocks = (s->ydelta + s->scan_lines_per_block - 1) /
                       s->scan_lines_per_block;
Paul B Mahol's avatar
Paul B Mahol committed
1314

1315
    if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
1316
        return ret;
1317

Jimmy Christensen's avatar
Jimmy Christensen committed
1318
    if (bytestream2_get_bytes_left(&s->gb) < scan_line_blocks * 8)
Paul B Mahol's avatar
Paul B Mahol committed
1319
        return AVERROR_INVALIDDATA;
Jimmy Christensen's avatar
Jimmy Christensen committed
1320 1321 1322 1323 1324

    // save pointer we are going to use in decode_block
    s->buf      = avpkt->data;
    s->buf_size = avpkt->size;
    ptr         = picture->data[0];
1325 1326

    // Zero out the start if ymin is not 0
Paul B Mahol's avatar
Paul B Mahol committed
1327
    for (y = 0; y < s->ymin; y++) {
Paul B Mahol's avatar
Paul B Mahol committed
1328
        memset(ptr, 0, out_line_size);
1329
        ptr += picture->linesize[0];
1330 1331
    }

1332
    s->picture = picture;
Paul B Mahol's avatar
Paul B Mahol committed
1333
    avctx->execute2(avctx, decode_block, s->thread_data, NULL, scan_line_blocks);
1334 1335

    // Zero out the end if ymax+1 is not h
Paul B Mahol's avatar
Paul B Mahol committed
1336
    for (y = s->ymax + 1; y < avctx->height; y++) {
Paul B Mahol's avatar
Paul B Mahol committed
1337
        memset(ptr, 0, out_line_size);
1338
        ptr += picture->linesize[0];
1339 1340
    }

Paul B Mahol's avatar
Paul B Mahol committed
1341
    picture->pict_type = AV_PICTURE_TYPE_I;
1342
    *got_frame = 1;
1343

Jimmy Christensen's avatar
Jimmy Christensen committed
1344 1345 1346 1347 1348
    return avpkt->size;
}

static av_cold int decode_init(AVCodecContext *avctx)
{
1349 1350
    uint32_t i;
    union av_intfloat32 t;
Jimmy Christensen's avatar
Jimmy Christensen committed
1351
    EXRContext *s = avctx->priv_data;
1352
    float one_gamma = 1.0f / s->gamma;
Jimmy Christensen's avatar
Jimmy Christensen committed
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370

    s->avctx              = avctx;
    s->xmin               = ~0;
    s->xmax               = ~0;
    s->ymin               = ~0;
    s->ymax               = ~0;
    s->xdelta             = ~0;
    s->ydelta             = ~0;
    s->channel_offsets[0] = -1;
    s->channel_offsets[1] = -1;
    s->channel_offsets[2] = -1;
    s->channel_offsets[3] = -1;
    s->pixel_type         = EXR_UNKNOWN;
    s->compression        = EXR_UNKN;
    s->nb_channels        = 0;
    s->w                  = 0;
    s->h                  = 0;

1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
    if ( one_gamma > 0.9999f && one_gamma < 1.0001f ) {
        for ( i = 0; i < 65536; ++i ) {
            s->gamma_table[i] = exr_halflt2uint(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);
            } else {
                t.f = powf(t.f, one_gamma);
                s->gamma_table[i] = exr_flt2uint(t.i);
            }
        }
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404
    // allocate thread data, used for non EXR_RAW compreesion types
    s->thread_data = av_mallocz_array(avctx->thread_count, sizeof(EXRThreadData));
    if (!s->thread_data)
        return AVERROR_INVALIDDATA;

    return 0;
}

static int decode_init_thread_copy(AVCodecContext *avctx)
{    EXRContext *s = avctx->priv_data;

    // allocate thread data, used for non EXR_RAW compreesion types
    s->thread_data = av_mallocz_array(avctx->thread_count, sizeof(EXRThreadData));
    if (!s->thread_data)
        return AVERROR_INVALIDDATA;

    return 0;
1405 1406 1407 1408 1409
}

static av_cold int decode_end(AVCodecContext *avctx)
{
    EXRContext *s = avctx->priv_data;
Paul B Mahol's avatar
Paul B Mahol committed
1410
    int i;
Jimmy Christensen's avatar
Jimmy Christensen committed
1411
    for (i = 0; i < avctx->thread_count; i++) {
Paul B Mahol's avatar
Paul B Mahol committed
1412
        EXRThreadData *td = &s->thread_data[i];
1413 1414 1415 1416
        av_freep(&td->uncompressed_data);
        av_freep(&td->tmp);
        av_freep(&td->bitmap);
        av_freep(&td->lut);
Paul B Mahol's avatar
Paul B Mahol committed
1417 1418 1419
    }

    av_freep(&s->thread_data);
1420
    av_freep(&s->channels);
Paul B Mahol's avatar
Paul B Mahol committed
1421

1422 1423 1424
    return 0;
}

Jimmy Christensen's avatar
Jimmy Christensen committed
1425 1426 1427 1428 1429
#define OFFSET(x) offsetof(EXRContext, x)
#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM
static const AVOption options[] = {
    { "layer", "Set the decoding layer", OFFSET(layer),
        AV_OPT_TYPE_STRING, { .str = "" }, 0, 0, VD },
1430
    { "gamma", "Set the float gamma value when decoding (experimental/unsupported)", OFFSET(gamma),
1431
        AV_OPT_TYPE_FLOAT, { .dbl = 1.0f }, 0.001, FLT_MAX, VD },
Jimmy Christensen's avatar
Jimmy Christensen committed
1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
    { NULL },
};

static const AVClass exr_class = {
    .class_name = "EXR",
    .item_name  = av_default_item_name,
    .option     = options,
    .version    = LIBAVUTIL_VERSION_INT,
};

1442
AVCodec ff_exr_decoder = {
Jimmy Christensen's avatar
Jimmy Christensen committed
1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454
    .name             = "exr",
    .long_name        = NULL_IF_CONFIG_SMALL("OpenEXR image"),
    .type             = AVMEDIA_TYPE_VIDEO,
    .id               = AV_CODEC_ID_EXR,
    .priv_data_size   = sizeof(EXRContext),
    .init             = decode_init,
    .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy),
    .close            = decode_end,
    .decode           = decode_frame,
    .capabilities     = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS |
                        CODEC_CAP_SLICE_THREADS,
    .priv_class       = &exr_class,
1455
};