exr.c 44.1 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
 * exr_flt2uint() and exr_halflt2uint() is credited to Reimar Döffinger.
 * exr_half2float() is credited to Aaftab Munshi, Dan Ginsburg, Dave Shreiner.
32 33
 */

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

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

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

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

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

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

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

    uint8_t *tmp;
    int tmp_size;
78 79 80

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

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

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

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

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

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

106 107 108
    EXRChannel *channels;
    int nb_channels;

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

Jimmy Christensen's avatar
Jimmy Christensen committed
111
    const char *layer;
112 113 114

    float gamma;
    uint16_t gamma_table[65536];
115 116
} EXRContext;

117 118
/* -15 stored using a single precision bias of 127 */
#define HALF_FLOAT_MIN_BIASED_EXP_AS_SINGLE_FP_EXP 0x38000000
119

120 121 122 123 124 125 126 127 128
/* 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)

129
/**
130 131 132 133 134 135 136 137
 * 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)
{
138 139 140 141
    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;
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

    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;
}


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

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

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

    while (t < stop) {
Jimmy Christensen's avatar
Jimmy Christensen committed
226
        int d = (int) t[-1] + (int) t[0] - 128;
Paul B Mahol's avatar
Paul B Mahol committed
227 228 229 230 231 232 233 234 235
        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
236 237
    int8_t *s        = dst;
    int8_t *stop     = s + size;
Paul B Mahol's avatar
Paul B Mahol committed
238 239 240 241 242 243 244 245 246 247 248 249 250 251

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

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

252 253
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
254
{
255 256 257 258
    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
259
        return AVERROR_INVALIDDATA;
260 261 262 263 264 265 266 267 268 269

    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
270 271 272 273 274
    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
275 276 277 278 279 280 281 282
    int count;

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

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

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

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

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

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

            s++;
        }
    }

303 304 305 306 307 308 309
    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
310 311
}

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

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

Jimmy Christensen's avatar
Jimmy Christensen committed
319
    for (i = 0; i < USHORT_RANGE; i++)
320 321 322 323 324
        if ((i == 0) || (bitmap[i >> 3] & (1 << (i & 7))))
            lut[k++] = i;

    i = k - 1;

325
    memset(lut + k, 0, (USHORT_RANGE - k) * 2);
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341

    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
342
#define HUF_DECSIZE (1 << HUF_DECBITS)        // decoding table size
343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362
#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
363
        c    = nc;
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
    }

    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;
383 384 385
    int ret = init_get_bits8(&gbit, gb->buffer, bytestream2_get_bytes_left(gb));
    if (ret < 0)
        return ret;
386 387 388 389 390 391 392 393 394 395 396 397 398 399

    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
400
        } else if (l >= SHORT_ZEROCODE_RUN) {
401 402 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
            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
436
            pl->p = av_realloc(pl->p, pl->lit * sizeof(int));
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455
            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
456 457 458 459
#define get_char(c, lc, gb)                                                   \
{                                                                             \
        c   = (c << 8) | bytestream2_get_byte(gb);                            \
        lc += 8;                                                              \
460 461
}

Jimmy Christensen's avatar
Jimmy Christensen committed
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482
#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;                                       \
        }                                                                     \
483 484 485 486 487 488
}

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
489 490 491
    uint64_t c        = 0;
    uint16_t *outb    = out;
    uint16_t *oe      = out + no;
492 493 494 495 496 497 498 499
    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
500
            const HufDec pl = hdecod[(c >> (lc - HUF_DECBITS)) & HUF_DECMASK];
501 502 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

            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
533
    i   = (8 - nbits) & 7;
534 535 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
    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
563 564
    im       = bytestream2_get_le32(gb);
    iM       = bytestream2_get_le32(gb);
565 566 567 568 569 570 571 572 573
    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
574 575
    freq = av_mallocz_array(HUF_ENCSIZE, sizeof(*freq));
    hdec = av_mallocz_array(HUF_DECSIZE, sizeof(*hdec));
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593
    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
594
    for (i = 0; i < HUF_DECSIZE; i++)
595
        if (hdec)
596
            av_freep(&hdec[i].p);
597 598 599 600 601 602 603 604 605 606 607

    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
608 609
    int hi     = hs;
    int ai     = ls + (hi & 1) + (hi >> 1);
610 611 612 613 614 615 616 617
    int16_t as = ai;
    int16_t bs = ai - hi;

    *a = as;
    *b = bs;
}

#define NBITS      16
Jimmy Christensen's avatar
Jimmy Christensen committed
618
#define A_OFFSET  (1 << (NBITS - 1))
619 620 621 622
#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
623 624
    int m  = l;
    int d  = h;
625 626 627 628 629 630 631 632 633 634
    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
635 636
    int n   = (nx > ny) ? ny : nx;
    int p   = 1;
637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
    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
660 661
                uint16_t *p01 = px + ox1;
                uint16_t *p10 = px + oy1;
662 663 664
                uint16_t *p11 = p10 + ox1;

                if (w14) {
Jimmy Christensen's avatar
Jimmy Christensen committed
665
                    wdec14(*px, *p10, &i00, &i10);
666
                    wdec14(*p01, *p11, &i01, &i11);
Jimmy Christensen's avatar
Jimmy Christensen committed
667
                    wdec14(i00, i01, px, p01);
668 669
                    wdec14(i10, i11, p10, p11);
                } else {
Jimmy Christensen's avatar
Jimmy Christensen committed
670
                    wdec16(*px, *p10, &i00, &i10);
671
                    wdec16(*p01, *p11, &i01, &i11);
Jimmy Christensen's avatar
Jimmy Christensen committed
672
                    wdec16(i00, i01, px, p01);
673 674 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
                    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
705
        p2  = p;
706 707 708 709
        p >>= 1;
    }
}

Jimmy Christensen's avatar
Jimmy Christensen committed
710 711
static int piz_uncompress(EXRContext *s, const uint8_t *src, int ssize,
                          int dsize, EXRThreadData *td)
712 713 714
{
    GetByteContext gb;
    uint16_t maxval, min_non_zero, max_non_zero;
Jimmy Christensen's avatar
Jimmy Christensen committed
715 716 717
    uint16_t *ptr;
    uint16_t *tmp = (uint16_t *)td->tmp;
    uint8_t *out;
718 719 720 721 722 723
    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
724
    if (!td->bitmap || !td->lut) {
725 726
        av_freep(&td->bitmap);
        av_freep(&td->lut);
727
        return AVERROR(ENOMEM);
Jimmy Christensen's avatar
Jimmy Christensen committed
728
    }
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744

    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
745
    ret = huf_uncompress(&gb, tmp, dsize / sizeof(uint16_t));
746 747 748 749 750 751 752 753 754
    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
755 756
            wav_decode(ptr + j, s->xdelta, size, s->ysize,
                       s->xdelta * size, maxval);
757 758 759
        ptr += s->xdelta * s->ysize * size;
    }

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

    out = td->uncompressed_data;
Jimmy Christensen's avatar
Jimmy Christensen committed
763
    for (i = 0; i < s->ysize; i++)
764 765 766 767 768 769 770 771 772
        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
773 774 775 776 777 778 779 780 781 782 783
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
784
        return AVERROR_INVALIDDATA;
Paul B Mahol's avatar
Paul B Mahol committed
785 786

    out = td->uncompressed_data;
Jimmy Christensen's avatar
Jimmy Christensen committed
787
    for (i = 0; i < s->ysize; i++)
Paul B Mahol's avatar
Paul B Mahol committed
788 789 790 791 792 793 794 795 796 797
        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
798
                in     = ptr[2] + s->xdelta;
Paul B Mahol's avatar
Paul B Mahol committed
799 800 801 802

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

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

    return 0;
}

Paul B Mahol's avatar
Paul B Mahol committed
827 828 829 830
static int decode_block(AVCodecContext *avctx, void *tdata,
                        int jobnr, int threadnr)
{
    EXRContext *s = avctx->priv_data;
831
    AVFrame *const p = s->picture;
Paul B Mahol's avatar
Paul B Mahol committed
832 833 834 835 836 837 838
    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
839
    uint32_t data_size, line;
Paul B Mahol's avatar
Paul B Mahol committed
840 841 842
    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;
843
    int i, x, buf_size = s->buf_size;
844
    float one_gamma = 1.0f / s->gamma;
Jimmy Christensen's avatar
Jimmy Christensen committed
845
    int ret;
Paul B Mahol's avatar
Paul B Mahol committed
846

Jimmy Christensen's avatar
Jimmy Christensen committed
847
    line_offset = AV_RL64(s->gb.buffer + jobnr * 8);
Paul B Mahol's avatar
Paul B Mahol committed
848 849 850 851
    // 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
852
    src  = buf + line_offset + 8;
Paul B Mahol's avatar
Paul B Mahol committed
853 854 855 856 857 858 859 860
    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
861
    s->ysize          = FFMIN(s->scan_lines_per_block, s->ymax - line + 1);
Paul B Mahol's avatar
Paul B Mahol committed
862
    uncompressed_size = s->scan_line_size * s->ysize;
Jimmy Christensen's avatar
Jimmy Christensen committed
863
    if ((s->compression == EXR_RAW && (data_size != uncompressed_size ||
Paul B Mahol's avatar
Paul B Mahol committed
864
                                 line_offset > buf_size - uncompressed_size)) ||
Jimmy Christensen's avatar
Jimmy Christensen committed
865
        (s->compression != EXR_RAW && (data_size > uncompressed_size ||
866
                                 line_offset > buf_size - data_size))) {
Paul B Mahol's avatar
Paul B Mahol committed
867 868 869 870
        return AVERROR_INVALIDDATA;
    }

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

899 900 901 902 903 904
    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
905
    ptr = p->data[0] + line * p->linesize[0];
Jimmy Christensen's avatar
Jimmy Christensen committed
906 907 908
    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
909 910 911 912 913 914 915 916
        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
917
        ptr_x = (uint16_t *) ptr;
Paul B Mahol's avatar
Paul B Mahol committed
918 919 920 921

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

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

                t.i = bytestream_get_le32(&b);
937
                if (t.f > 0.0f)
938 939
                    t.f = powf(t.f, one_gamma);
                *ptr_x++ = exr_flt2uint(t.i);
Paul B Mahol's avatar
Paul B Mahol committed
940 941 942 943 944 945
                if (channel_buffer[3])
                    *ptr_x++ = exr_flt2uint(bytestream_get_le32(&a));
            }
        } else {
            // 16-bit
            for (x = 0; x < xdelta; x++) {
946 947 948
                *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
949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966
                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
967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
/**
 * 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)
983
{
Jimmy Christensen's avatar
Jimmy Christensen committed
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003
    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);
        }
    }
1004

Jimmy Christensen's avatar
Jimmy Christensen committed
1005 1006
    return var_size;
}
Paul B Mahol's avatar
Paul B Mahol committed
1007

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

1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
    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;

Jimmy Christensen's avatar
Jimmy Christensen committed
1029 1030
    if (bytestream2_get_bytes_left(&s->gb) < 10) {
        av_log(s->avctx, AV_LOG_ERROR, "Header too short to parse.\n");
1031
        return AVERROR_INVALIDDATA;
1032 1033
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1034 1035 1036 1037 1038
    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);
1039
        return AVERROR_INVALIDDATA;
1040 1041
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1042
    version = bytestream2_get_byte(&s->gb);
Paul B Mahol's avatar
Paul B Mahol committed
1043
    if (version != 2) {
Jimmy Christensen's avatar
Jimmy Christensen committed
1044
        avpriv_report_missing_feature(s->avctx, "Version %d", version);
Paul B Mahol's avatar
Paul B Mahol committed
1045 1046 1047
        return AVERROR_PATCHWELCOME;
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1048 1049 1050
    flags = bytestream2_get_le24(&s->gb);
    if (flags & 0x02) {
        avpriv_report_missing_feature(s->avctx, "Tile support");
1051
        return AVERROR_PATCHWELCOME;
1052 1053 1054
    }

    // Parse the header
Jimmy Christensen's avatar
Jimmy Christensen committed
1055 1056 1057 1058 1059 1060
    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)
1061
                return AVERROR_INVALIDDATA;
1062

Jimmy Christensen's avatar
Jimmy Christensen committed
1063 1064 1065
            bytestream2_init(&ch_gb, s->gb.buffer, var_size);

            while (bytestream2_get_bytes_left(&ch_gb) >= 19) {
1066
                EXRChannel *channel;
1067
                enum ExrPixelType current_pixel_type;
1068
                int channel_index = -1;
1069
                int xsub, ysub;
1070

Jimmy Christensen's avatar
Jimmy Christensen committed
1071 1072 1073 1074 1075 1076 1077
                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);
1078 1079 1080
                    }
                }

Jimmy Christensen's avatar
Jimmy Christensen committed
1081 1082 1083
                if (!strcmp(ch_gb.buffer, "R") ||
                    !strcmp(ch_gb.buffer, "X") ||
                    !strcmp(ch_gb.buffer, "U"))
1084
                    channel_index = 0;
Jimmy Christensen's avatar
Jimmy Christensen committed
1085 1086 1087
                else if (!strcmp(ch_gb.buffer, "G") ||
                         !strcmp(ch_gb.buffer, "Y") ||
                         !strcmp(ch_gb.buffer, "V"))
1088
                    channel_index = 1;
Jimmy Christensen's avatar
Jimmy Christensen committed
1089 1090 1091
                else if (!strcmp(ch_gb.buffer, "B") ||
                         !strcmp(ch_gb.buffer, "Z") ||
                         !strcmp(ch_gb.buffer, "W"))
1092
                    channel_index = 2;
Jimmy Christensen's avatar
Jimmy Christensen committed
1093
                else if (!strcmp(ch_gb.buffer, "A"))
Paul B Mahol's avatar
Paul B Mahol committed
1094
                    channel_index = 3;
1095
                else
Jimmy Christensen's avatar
Jimmy Christensen committed
1096 1097
                    av_log(s->avctx, AV_LOG_WARNING,
                           "Unsupported channel %.256s.\n", ch_gb.buffer);
1098

Jimmy Christensen's avatar
Jimmy Christensen committed
1099 1100 1101 1102
                /* skip until you get a 0 */
                while (bytestream2_get_bytes_left(&ch_gb) > 0 &&
                       bytestream2_get_byte(&ch_gb))
                    continue;
1103

Jimmy Christensen's avatar
Jimmy Christensen committed
1104 1105
                if (bytestream2_get_bytes_left(&ch_gb) < 4) {
                    av_log(s->avctx, AV_LOG_ERROR, "Incomplete header.\n");
1106
                    return AVERROR_INVALIDDATA;
1107 1108
                }

Jimmy Christensen's avatar
Jimmy Christensen committed
1109 1110 1111 1112 1113 1114
                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;
1115 1116
                }

Jimmy Christensen's avatar
Jimmy Christensen committed
1117 1118 1119
                bytestream2_skip(&ch_gb, 4);
                xsub = bytestream2_get_le32(&ch_gb);
                ysub = bytestream2_get_le32(&ch_gb);
1120
                if (xsub != 1 || ysub != 1) {
Jimmy Christensen's avatar
Jimmy Christensen committed
1121 1122 1123
                    avpriv_report_missing_feature(s->avctx,
                                                  "Subsampling %dx%d",
                                                  xsub, ysub);
1124 1125 1126
                    return AVERROR_PATCHWELCOME;
                }

1127
                if (channel_index >= 0) {
Jimmy Christensen's avatar
Jimmy Christensen committed
1128 1129 1130 1131
                    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");
1132
                        return AVERROR_INVALIDDATA;
1133
                    }
Jimmy Christensen's avatar
Jimmy Christensen committed
1134
                    s->pixel_type                     = current_pixel_type;
1135 1136 1137
                    s->channel_offsets[channel_index] = current_channel_offset;
                }

Jimmy Christensen's avatar
Jimmy Christensen committed
1138 1139
                s->channels = av_realloc(s->channels,
                                         ++s->nb_channels * sizeof(EXRChannel));
1140 1141
                if (!s->channels)
                    return AVERROR(ENOMEM);
Jimmy Christensen's avatar
Jimmy Christensen committed
1142
                channel             = &s->channels[s->nb_channels - 1];
1143
                channel->pixel_type = current_pixel_type;
Jimmy Christensen's avatar
Jimmy Christensen committed
1144 1145
                channel->xsub       = xsub;
                channel->ysub       = ysub;
1146

1147
                current_channel_offset += 1 << current_pixel_type;
1148 1149 1150 1151 1152 1153 1154 1155
            }

            /* 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
1156
                    av_log(s->avctx, AV_LOG_ERROR, "Missing red channel.\n");
1157
                if (s->channel_offsets[1] < 0)
Jimmy Christensen's avatar
Jimmy Christensen committed
1158
                    av_log(s->avctx, AV_LOG_ERROR, "Missing green channel.\n");
1159
                if (s->channel_offsets[2] < 0)
Jimmy Christensen's avatar
Jimmy Christensen committed
1160
                    av_log(s->avctx, AV_LOG_ERROR, "Missing blue channel.\n");
1161
                return AVERROR_INVALIDDATA;
1162 1163
            }

Jimmy Christensen's avatar
Jimmy Christensen committed
1164 1165
            // skip one last byte and update main gb
            s->gb.buffer = ch_gb.buffer + 1;
1166
            continue;
Jimmy Christensen's avatar
Jimmy Christensen committed
1167 1168 1169
        } else if ((var_size = check_header_variable(s, "dataWindow", "box2i",
                                                     31)) >= 0) {
            if (!var_size)
1170
                return AVERROR_INVALIDDATA;
1171

Jimmy Christensen's avatar
Jimmy Christensen committed
1172 1173 1174 1175
            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
1176 1177
            s->xdelta = (s->xmax - s->xmin) + 1;
            s->ydelta = (s->ymax - s->ymin) + 1;
1178 1179

            continue;
Jimmy Christensen's avatar
Jimmy Christensen committed
1180 1181 1182
        } else if ((var_size = check_header_variable(s, "displayWindow",
                                                     "box2i", 34)) >= 0) {
            if (!var_size)
1183
                return AVERROR_INVALIDDATA;
1184

Jimmy Christensen's avatar
Jimmy Christensen committed
1185 1186 1187
            bytestream2_skip(&s->gb, 8);
            s->w = bytestream2_get_le32(&s->gb) + 1;
            s->h = bytestream2_get_le32(&s->gb) + 1;
1188 1189

            continue;
Jimmy Christensen's avatar
Jimmy Christensen committed
1190 1191 1192 1193
        } else if ((var_size = check_header_variable(s, "lineOrder",
                                                     "lineOrder", 25)) >= 0) {
            int line_order;
            if (!var_size)
1194
                return AVERROR_INVALIDDATA;
1195

Jimmy Christensen's avatar
Jimmy Christensen committed
1196 1197 1198 1199
            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");
1200
                return AVERROR_INVALIDDATA;
1201 1202 1203
            }

            continue;
Jimmy Christensen's avatar
Jimmy Christensen committed
1204 1205 1206
        } else if ((var_size = check_header_variable(s, "pixelAspectRatio",
                                                     "float", 31)) >= 0) {
            if (!var_size)
1207
                return AVERROR_INVALIDDATA;
1208

1209 1210
            ff_set_sar(s->avctx,
                       av_d2q(av_int2float(bytestream2_get_le32(&s->gb)), 255));
1211 1212

            continue;
Jimmy Christensen's avatar
Jimmy Christensen committed
1213 1214 1215
        } else if ((var_size = check_header_variable(s, "compression",
                                                     "compression", 29)) >= 0) {
            if (!var_size)
1216
                return AVERROR_INVALIDDATA;
1217

Jimmy Christensen's avatar
Jimmy Christensen committed
1218 1219
            if (s->compression == EXR_UNKN)
                s->compression = bytestream2_get_byte(&s->gb);
1220
            else
Jimmy Christensen's avatar
Jimmy Christensen committed
1221 1222
                av_log(s->avctx, AV_LOG_WARNING,
                       "Found more than one compression attribute.\n");
1223 1224 1225 1226

            continue;
        }

Jimmy Christensen's avatar
Jimmy Christensen committed
1227 1228 1229
        // 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");
1230
            return AVERROR_INVALIDDATA;
1231 1232 1233
        }

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

1237
        // Skip variable length
Jimmy Christensen's avatar
Jimmy Christensen committed
1238
        bytestream2_skip(&s->gb, bytestream2_get_le32(&s->gb));
1239 1240
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1241 1242
    if (s->compression == EXR_UNKN) {
        av_log(s->avctx, AV_LOG_ERROR, "Missing compression attribute.\n");
1243 1244
        return AVERROR_INVALIDDATA;
    }
Jimmy Christensen's avatar
Jimmy Christensen committed
1245
    s->scan_line_size = s->xdelta * current_channel_offset;
1246

Jimmy Christensen's avatar
Jimmy Christensen committed
1247 1248
    if (bytestream2_get_bytes_left(&s->gb) <= 0) {
        av_log(s->avctx, AV_LOG_ERROR, "Incomplete frame.\n");
1249
        return AVERROR_INVALIDDATA;
1250
    }
Jimmy Christensen's avatar
Jimmy Christensen committed
1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272

    // 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;
1273

1274 1275 1276
    switch (s->pixel_type) {
    case EXR_FLOAT:
    case EXR_HALF:
Paul B Mahol's avatar
Paul B Mahol committed
1277
        if (s->channel_offsets[3] >= 0)
1278
            avctx->pix_fmt = AV_PIX_FMT_RGBA64;
Paul B Mahol's avatar
Paul B Mahol committed
1279
        else
1280
            avctx->pix_fmt = AV_PIX_FMT_RGB48;
1281
        break;
1282
    case EXR_UINT:
1283
        avpriv_request_sample(avctx, "32-bit unsigned int");
1284
        return AVERROR_PATCHWELCOME;
1285
    default:
Jimmy Christensen's avatar
Jimmy Christensen committed
1286
        av_log(avctx, AV_LOG_ERROR, "Missing channel list.\n");
1287
        return AVERROR_INVALIDDATA;
1288 1289
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1290
    switch (s->compression) {
Paul B Mahol's avatar
Paul B Mahol committed
1291
    case EXR_RAW:
Paul B Mahol's avatar
Paul B Mahol committed
1292
    case EXR_RLE:
Paul B Mahol's avatar
Paul B Mahol committed
1293
    case EXR_ZIP1:
Paul B Mahol's avatar
Paul B Mahol committed
1294
        s->scan_lines_per_block = 1;
Paul B Mahol's avatar
Paul B Mahol committed
1295
        break;
Paul B Mahol's avatar
Paul B Mahol committed
1296
    case EXR_PXR24:
Paul B Mahol's avatar
Paul B Mahol committed
1297
    case EXR_ZIP16:
Paul B Mahol's avatar
Paul B Mahol committed
1298
        s->scan_lines_per_block = 16;
Paul B Mahol's avatar
Paul B Mahol committed
1299
        break;
1300 1301 1302
    case EXR_PIZ:
        s->scan_lines_per_block = 32;
        break;
Paul B Mahol's avatar
Paul B Mahol committed
1303
    default:
Jimmy Christensen's avatar
Jimmy Christensen committed
1304
        avpriv_report_missing_feature(avctx, "Compression %d", s->compression);
Paul B Mahol's avatar
Paul B Mahol committed
1305
        return AVERROR_PATCHWELCOME;
Paul B Mahol's avatar
Paul B Mahol committed
1306 1307
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1308 1309 1310 1311
    /* 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
1312
        s->xdelta != s->xmax - s->xmin + 1 ||
Jimmy Christensen's avatar
Jimmy Christensen committed
1313 1314 1315
        s->xmax >= s->w                    ||
        s->ymax >= s->h) {
        av_log(avctx, AV_LOG_ERROR, "Wrong or missing size information.\n");
1316
        return AVERROR_INVALIDDATA;
1317 1318
    }

Jimmy Christensen's avatar
Jimmy Christensen committed
1319
    if ((ret = ff_set_dimensions(avctx, s->w, s->h)) < 0)
1320
        return ret;
1321

Jimmy Christensen's avatar
Jimmy Christensen committed
1322 1323 1324 1325 1326 1327
    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
1328

1329
    if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
1330
        return ret;
1331

Jimmy Christensen's avatar
Jimmy Christensen committed
1332
    if (bytestream2_get_bytes_left(&s->gb) < scan_line_blocks * 8)
Paul B Mahol's avatar
Paul B Mahol committed
1333
        return AVERROR_INVALIDDATA;
Jimmy Christensen's avatar
Jimmy Christensen committed
1334 1335 1336 1337 1338

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

    // Zero out the start if ymin is not 0
Paul B Mahol's avatar
Paul B Mahol committed
1341
    for (y = 0; y < s->ymin; y++) {
Paul B Mahol's avatar
Paul B Mahol committed
1342
        memset(ptr, 0, out_line_size);
1343
        ptr += picture->linesize[0];
1344 1345
    }

1346
    s->picture = picture;
Paul B Mahol's avatar
Paul B Mahol committed
1347
    avctx->execute2(avctx, decode_block, s->thread_data, NULL, scan_line_blocks);
1348 1349

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

Paul B Mahol's avatar
Paul B Mahol committed
1355
    picture->pict_type = AV_PICTURE_TYPE_I;
1356
    *got_frame = 1;
1357

Jimmy Christensen's avatar
Jimmy Christensen committed
1358 1359 1360 1361 1362 1363
    return avpkt->size;
}

static av_cold int decode_init(AVCodecContext *avctx)
{
    EXRContext *s = avctx->priv_data;
1364 1365 1366
    uint32_t i;
    union av_intfloat32 t;
    float one_gamma = 1.0f / s->gamma;
Jimmy Christensen's avatar
Jimmy Christensen committed
1367 1368 1369

    s->avctx              = avctx;

1370 1371
    if (one_gamma > 0.9999f && one_gamma < 1.0001f) {
        for (i = 0; i < 65536; ++i)
1372 1373
            s->gamma_table[i] = exr_halflt2uint(i);
    } else {
1374
        for (i = 0; i < 65536; ++i) {
1375 1376
            t = exr_half2float(i);
            /* If negative value we reuse half value */
1377
            if (t.f <= 0.0f) {
1378 1379 1380 1381 1382 1383 1384 1385
                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
1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402
    // 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;
1403 1404 1405 1406 1407
}

static av_cold int decode_end(AVCodecContext *avctx)
{
    EXRContext *s = avctx->priv_data;
Paul B Mahol's avatar
Paul B Mahol committed
1408
    int i;
Jimmy Christensen's avatar
Jimmy Christensen committed
1409
    for (i = 0; i < avctx->thread_count; i++) {
Paul B Mahol's avatar
Paul B Mahol committed
1410
        EXRThreadData *td = &s->thread_data[i];
1411 1412 1413 1414
        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
1415 1416 1417
    }

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

1420 1421 1422
    return 0;
}

Jimmy Christensen's avatar
Jimmy Christensen committed
1423 1424 1425 1426 1427
#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 },
1428
    { "gamma", "Set the float gamma value when decoding", OFFSET(gamma),
1429
        AV_OPT_TYPE_FLOAT, { .dbl = 1.0f }, 0.001, FLT_MAX, VD },
Jimmy Christensen's avatar
Jimmy Christensen committed
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439
    { NULL },
};

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

1440
AVCodec ff_exr_decoder = {
Jimmy Christensen's avatar
Jimmy Christensen committed
1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452
    .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,
1453
};