exr.c 25.5 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 30 31 32
 * OpenEXR decoder
 * @author Jimmy Christensen
 *
 * For more information on the OpenEXR format, visit:
 *  http://openexr.com/
 *
 * exr_flt2uint() and exr_halflt2uint() is credited to  Reimar Döffinger
 */

Paul B Mahol's avatar
Paul B Mahol committed
33 34
#include <zlib.h>

35 36
#include "avcodec.h"
#include "bytestream.h"
Paul B Mahol's avatar
Paul B Mahol committed
37
#include "mathops.h"
38
#include "thread.h"
39
#include "libavutil/imgutils.h"
Paul B Mahol's avatar
Paul B Mahol committed
40
#include "libavutil/avassert.h"
41 42 43 44 45 46 47

enum ExrCompr {
    EXR_RAW   = 0,
    EXR_RLE   = 1,
    EXR_ZIP1  = 2,
    EXR_ZIP16 = 3,
    EXR_PIZ   = 4,
Paul B Mahol's avatar
Paul B Mahol committed
48
    EXR_PXR24 = 5,
Paul B Mahol's avatar
Paul B Mahol committed
49 50
    EXR_B44   = 6,
    EXR_B44A  = 7,
51 52
};

53 54 55 56 57 58 59 60 61 62 63
enum ExrPixelType {
    EXR_UINT,
    EXR_HALF,
    EXR_FLOAT
};

typedef struct EXRChannel {
    int               xsub, ysub;
    enum ExrPixelType pixel_type;
} EXRChannel;

Paul B Mahol's avatar
Paul B Mahol committed
64 65 66 67 68 69 70 71
typedef struct EXRThreadData {
    uint8_t *uncompressed_data;
    int uncompressed_size;

    uint8_t *tmp;
    int tmp_size;
} EXRThreadData;

72
typedef struct EXRContext {
73
    AVFrame *picture;
74
    int compr;
75
    enum ExrPixelType pixel_type;
76
    int channel_offsets[4]; // 0 = red, 1 = green, 2 = blue and 3 = alpha
Paul B Mahol's avatar
Paul B Mahol committed
77
    const AVPixFmtDescriptor *desc;
Paul B Mahol's avatar
Paul B Mahol committed
78

Paul B Mahol's avatar
Paul B Mahol committed
79 80 81
    uint32_t xmax, xmin;
    uint32_t ymax, ymin;
    uint32_t xdelta, ydelta;
Paul B Mahol's avatar
Paul B Mahol committed
82

Paul B Mahol's avatar
Paul B Mahol committed
83 84
    int ysize;

Paul B Mahol's avatar
Paul B Mahol committed
85 86 87 88 89 90
    uint64_t scan_line_size;
    int scan_lines_per_block;

    const uint8_t *buf, *table;
    int buf_size;

91 92 93
    EXRChannel *channels;
    int nb_channels;

Paul B Mahol's avatar
Paul B Mahol committed
94 95
    EXRThreadData *thread_data;
    int thread_data_size;
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
} EXRContext;

/**
 * Converts from 32-bit float as uint32_t to uint16_t
 *
 * @param v 32-bit float
 * @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.
    if (exp<= 127 + 7 - 24) // we would shift out all bits anyway
        return 0;
    if (exp >= 127)
        return 0xffff;
    v &= 0x007fffff;
    return (v + (1 << 23)) >> (127 + 7 - exp);
}

/**
 * Converts from 16-bit float as uint16_t to uint16_t
 *
 * @param v 16-bit float
 * @return normalized 16-bit unsigned int
 */
static inline uint16_t exr_halflt2uint(uint16_t v)
{
125 126 127 128 129
    unsigned exp = 14 - (v >> 10);
    if (exp >= 14) {
        if (exp == 14) return (v >> 9) & 1;
        else           return (v & 0x8000) ? 0 : 0xffff;
    }
130
    v <<= 6;
131
    return (v + (1 << 16)) >> (exp + 1);
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
}

/**
 * Gets the size of the header variable
 *
 * @param **buf the current pointer location in the header where
 * the variable data starts
 * @param *buf_end pointer location of the end of the buffer
 * @return size of variable data
 */
static unsigned int get_header_variable_length(const uint8_t **buf,
                                               const uint8_t *buf_end)
{
    unsigned int variable_buffer_data_size = bytestream_get_le32(buf);
    if (variable_buffer_data_size >= buf_end - *buf)
        return 0;
    return variable_buffer_data_size;
}

/**
 * Checks if the variable name corresponds with it's data type
 *
 * @param *avctx the AVCodecContext
 * @param **buf the current pointer location in the header where
 * the variable name starts
 * @param *buf_end pointer location of the end of the buffer
 * @param *value_name name of the varible to check
 * @param *value_type type of the varible to check
 * @param minimum_length minimum length of the variable data
 * @param variable_buffer_data_size variable length read from the header
 * after it's checked
163
 * @return negative if variable is invalid
164
 */
165
static int check_header_variable(AVCodecContext *avctx,
166 167 168 169 170 171 172 173 174 175 176 177 178
                                              const uint8_t **buf,
                                              const uint8_t *buf_end,
                                              const char *value_name,
                                              const char *value_type,
                                              unsigned int minimum_length,
                                              unsigned int *variable_buffer_data_size)
{
    if (buf_end - *buf >= minimum_length && !strcmp(*buf, value_name)) {
        *buf += strlen(value_name)+1;
        if (!strcmp(*buf, value_type)) {
            *buf += strlen(value_type)+1;
            *variable_buffer_data_size = get_header_variable_length(buf, buf_end);
            if (!*variable_buffer_data_size)
179
                av_log(avctx, AV_LOG_ERROR, "Incomplete header\n");
180 181 182 183 184
            return 1;
        }
        *buf -= strlen(value_name)+1;
        av_log(avctx, AV_LOG_WARNING, "Unknown data type for header variable %s\n", value_name);
    }
185
    return -1;
186 187
}

Paul B Mahol's avatar
Paul B Mahol committed
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
static void predictor(uint8_t *src, int size)
{
    uint8_t *t = src + 1;
    uint8_t *stop = src + size;

    while (t < stop) {
        int d = (int)t[-1] + (int)t[0] - 128;
        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;
    int8_t *s = dst;
    int8_t *stop = s + size;

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

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

220 221
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
222
{
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
    unsigned long dest_len = uncompressed_size;

    if (uncompress(td->tmp, &dest_len, src, compressed_size) != Z_OK ||
        dest_len != uncompressed_size)
        return AVERROR(EINVAL);

    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)
{
    int8_t *d = (int8_t *)td->tmp;
239
    const int8_t *s = (const int8_t *)src;
240 241
    int ssize = compressed_size;
    int dsize = uncompressed_size;
Paul B Mahol's avatar
Paul B Mahol committed
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
    int8_t *dend = d + dsize;
    int count;

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

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

            if ((dsize -= count    ) < 0 ||
                (ssize -= count + 1) < 0)
                return -1;

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

            if ((dsize -= count) < 0 ||
                (ssize -= 2    ) < 0)
                return -1;

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

            s++;
        }
    }

271 272 273 274 275 276 277
    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
278 279
}

Paul B Mahol's avatar
Paul B Mahol committed
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
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)
        return AVERROR(EINVAL);

    out = td->uncompressed_data;
    for (i = 0; i < s->ysize; i++) {
        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;
                in = ptr[2] + s->xdelta;

                for (j = 0; j < s->xdelta; ++j) {
                    uint32_t diff = (*(ptr[0]++) << 24) |
                                    (*(ptr[1]++) << 16) |
                                    (*(ptr[2]++) <<  8);
                    pixel += diff;
312
                    bytestream_put_le32(&out, pixel);
Paul B Mahol's avatar
Paul B Mahol committed
313 314 315 316 317 318
                }
                break;
            case EXR_HALF:
                ptr[0] = in;
                ptr[1] = ptr[0] + s->xdelta;
                in = ptr[1] + s->xdelta;
319
                for (j = 0; j < s->xdelta; j++) {
Paul B Mahol's avatar
Paul B Mahol committed
320 321 322
                    uint32_t diff = (*(ptr[0]++) << 8) | *(ptr[1]++);

                    pixel += diff;
323
                    bytestream_put_le16(&out, pixel);
Paul B Mahol's avatar
Paul B Mahol committed
324 325 326 327 328 329 330 331 332 333 334
                }
                break;
            default:
                av_assert1(0);
            }
        }
    }

    return 0;
}

Paul B Mahol's avatar
Paul B Mahol committed
335 336 337 338
static int decode_block(AVCodecContext *avctx, void *tdata,
                        int jobnr, int threadnr)
{
    EXRContext *s = avctx->priv_data;
339
    AVFrame *const p = s->picture;
Paul B Mahol's avatar
Paul B Mahol committed
340 341 342 343 344 345 346 347 348 349 350
    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;
    int32_t data_size, line;
    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;
351 352
    int i, x, buf_size = s->buf_size;
    int av_unused ret;
Paul B Mahol's avatar
Paul B Mahol committed
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367

    line_offset = AV_RL64(s->table + jobnr * 8);
    // Check if the buffer has the required bytes needed from the offset
    if (line_offset > buf_size - 8)
        return AVERROR_INVALIDDATA;

    src = buf + line_offset + 8;
    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;

Paul B Mahol's avatar
Paul B Mahol committed
368 369
    s->ysize = FFMIN(s->scan_lines_per_block, s->ymax - line + 1);
    uncompressed_size = s->scan_line_size * s->ysize;
Paul B Mahol's avatar
Paul B Mahol committed
370 371
    if ((s->compr == EXR_RAW && (data_size != uncompressed_size ||
                                 line_offset > buf_size - uncompressed_size)) ||
372 373
        (s->compr != EXR_RAW && (data_size > uncompressed_size ||
                                 line_offset > buf_size - data_size))) {
Paul B Mahol's avatar
Paul B Mahol committed
374 375 376 377 378 379 380 381 382
        return AVERROR_INVALIDDATA;
    }

    if (data_size < uncompressed_size) {
        av_fast_padded_malloc(&td->uncompressed_data, &td->uncompressed_size, uncompressed_size);
        av_fast_padded_malloc(&td->tmp, &td->tmp_size, uncompressed_size);
        if (!td->uncompressed_data || !td->tmp)
            return AVERROR(ENOMEM);

383 384 385 386 387
        switch (s->compr) {
        case EXR_ZIP1:
        case EXR_ZIP16:
            ret = zip_uncompress(src, data_size, uncompressed_size, td);
            break;
Paul B Mahol's avatar
Paul B Mahol committed
388 389 390
        case EXR_PXR24:
            ret = pxr24_uncompress(s, src, data_size, uncompressed_size, td);
            break;
391 392
        case EXR_RLE:
            ret = rle_uncompress(src, data_size, uncompressed_size, td);
Paul B Mahol's avatar
Paul B Mahol committed
393 394
        }

395
        src = td->uncompressed_data;
Paul B Mahol's avatar
Paul B Mahol committed
396 397
    }

398 399 400 401 402 403
    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
404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
    ptr = p->data[0] + line * p->linesize[0];
    for (i = 0; i < s->scan_lines_per_block && line + i <= s->ymax; i++, ptr += p->linesize[0]) {
        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];

        ptr_x = (uint16_t *)ptr;

        // Zero out the start if xmin is not 0
        memset(ptr_x, 0, bxmin);
        ptr_x += s->xmin * s->desc->nb_components;
419
        if (s->pixel_type == EXR_FLOAT) {
Paul B Mahol's avatar
Paul B Mahol committed
420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451
            // 32-bit
            for (x = 0; x < xdelta; x++) {
                *ptr_x++ = exr_flt2uint(bytestream_get_le32(&r));
                *ptr_x++ = exr_flt2uint(bytestream_get_le32(&g));
                *ptr_x++ = exr_flt2uint(bytestream_get_le32(&b));
                if (channel_buffer[3])
                    *ptr_x++ = exr_flt2uint(bytestream_get_le32(&a));
            }
        } else {
            // 16-bit
            for (x = 0; x < xdelta; x++) {
                *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&r));
                *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&g));
                *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&b));
                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;
}

452 453
static int decode_frame(AVCodecContext *avctx,
                        void *data,
454
                        int *got_frame,
455 456 457 458 459 460 461
                        AVPacket *avpkt)
{
    const uint8_t *buf      = avpkt->data;
    unsigned int   buf_size = avpkt->size;
    const uint8_t *buf_end  = buf + buf_size;

    EXRContext *const s = avctx->priv_data;
462
    ThreadFrame frame = { .f = data };
463 464 465
    AVFrame *picture  = data;
    uint8_t *ptr;

Paul B Mahol's avatar
Paul B Mahol committed
466
    int i, y, magic_number, version, flags, ret;
467 468 469
    int w = 0;
    int h = 0;

Paul B Mahol's avatar
Paul B Mahol committed
470
    int out_line_size;
Paul B Mahol's avatar
Paul B Mahol committed
471
    int scan_line_blocks;
Paul B Mahol's avatar
Paul B Mahol committed
472

473 474
    unsigned int current_channel_offset = 0;

Paul B Mahol's avatar
Paul B Mahol committed
475 476 477 478 479 480
    s->xmin = ~0;
    s->xmax = ~0;
    s->ymin = ~0;
    s->ymax = ~0;
    s->xdelta = ~0;
    s->ydelta = ~0;
481 482 483
    s->channel_offsets[0] = -1;
    s->channel_offsets[1] = -1;
    s->channel_offsets[2] = -1;
Paul B Mahol's avatar
Paul B Mahol committed
484
    s->channel_offsets[3] = -1;
485
    s->pixel_type = -1;
486
    s->nb_channels = 0;
487
    s->compr = -1;
Paul B Mahol's avatar
Paul B Mahol committed
488 489
    s->buf = buf;
    s->buf_size = buf_size;
490

491
    if (buf_size < 10) {
492
        av_log(avctx, AV_LOG_ERROR, "Too short header to parse\n");
493
        return AVERROR_INVALIDDATA;
494 495
    }

496 497
    magic_number = bytestream_get_le32(&buf);
    if (magic_number != 20000630) { // As per documentation of OpenEXR it's supposed to be int 20000630 little-endian
Michael Niedermayer's avatar
Michael Niedermayer committed
498
        av_log(avctx, AV_LOG_ERROR, "Wrong magic number %d\n", magic_number);
499
        return AVERROR_INVALIDDATA;
500 501
    }

Paul B Mahol's avatar
Paul B Mahol committed
502 503 504 505 506 507 508 509
    version = bytestream_get_byte(&buf);
    if (version != 2) {
        av_log(avctx, AV_LOG_ERROR, "Unsupported version %d\n", version);
        return AVERROR_PATCHWELCOME;
    }

    flags = bytestream_get_le24(&buf);
    if (flags & 0x2) {
510
        av_log(avctx, AV_LOG_ERROR, "Tile based images are not supported\n");
511
        return AVERROR_PATCHWELCOME;
512 513 514
    }

    // Parse the header
515
    while (buf < buf_end && buf[0]) {
516 517
        unsigned int variable_buffer_data_size;
        // Process the channel list
518
        if (check_header_variable(avctx, &buf, buf_end, "channels", "chlist", 38, &variable_buffer_data_size) >= 0) {
519 520
            const uint8_t *channel_list_end;
            if (!variable_buffer_data_size)
521
                return AVERROR_INVALIDDATA;
522

Jean First's avatar
Jean First committed
523
            channel_list_end = buf + variable_buffer_data_size;
524
            while (channel_list_end - buf >= 19) {
525
                EXRChannel *channel;
526
                int current_pixel_type = -1;
527
                int channel_index = -1;
528
                int xsub, ysub;
529 530 531

                if (!strcmp(buf, "R"))
                    channel_index = 0;
532
                else if (!strcmp(buf, "G"))
533
                    channel_index = 1;
534
                else if (!strcmp(buf, "B"))
535
                    channel_index = 2;
536
                else if (!strcmp(buf, "A"))
Paul B Mahol's avatar
Paul B Mahol committed
537
                    channel_index = 3;
538 539
                else
                    av_log(avctx, AV_LOG_WARNING, "Unsupported channel %.256s\n", buf);
540 541 542 543 544

                while (bytestream_get_byte(&buf) && buf < channel_list_end)
                    continue; /* skip */

                if (channel_list_end - * &buf < 4) {
Michael Niedermayer's avatar
Michael Niedermayer committed
545
                    av_log(avctx, AV_LOG_ERROR, "Incomplete header\n");
546
                    return AVERROR_INVALIDDATA;
547 548
                }

549 550 551
                current_pixel_type = bytestream_get_le32(&buf);
                if (current_pixel_type > 2) {
                    av_log(avctx, AV_LOG_ERROR, "Unknown pixel type\n");
552
                    return AVERROR_INVALIDDATA;
553 554
                }

555 556 557 558 559 560 561 562
                buf += 4;
                xsub = bytestream_get_le32(&buf);
                ysub = bytestream_get_le32(&buf);
                if (xsub != 1 || ysub != 1) {
                    av_log(avctx, AV_LOG_ERROR, "Unsupported subsampling %dx%d\n", xsub, ysub);
                    return AVERROR_PATCHWELCOME;
                }

563
                if (channel_index >= 0) {
564
                    if (s->pixel_type != -1 && s->pixel_type != current_pixel_type) {
Michael Niedermayer's avatar
Michael Niedermayer committed
565
                        av_log(avctx, AV_LOG_ERROR, "RGB channels not of the same depth\n");
566
                        return AVERROR_INVALIDDATA;
567
                    }
568
                    s->pixel_type = current_pixel_type;
569 570 571
                    s->channel_offsets[channel_index] = current_channel_offset;
                }

572 573 574 575
                s->channels = av_realloc_f(s->channels, ++s->nb_channels, sizeof(EXRChannel));
                if (!s->channels)
                    return AVERROR(ENOMEM);
                channel = &s->channels[s->nb_channels - 1];
576
                channel->pixel_type = current_pixel_type;
577 578 579
                channel->xsub = xsub;
                channel->ysub = ysub;

580
                current_channel_offset += 1 << current_pixel_type;
581 582 583 584 585 586 587 588 589
            }

            /* 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)
Michael Niedermayer's avatar
Michael Niedermayer committed
590
                    av_log(avctx, AV_LOG_ERROR, "Missing red channel\n");
591
                if (s->channel_offsets[1] < 0)
Michael Niedermayer's avatar
Michael Niedermayer committed
592
                    av_log(avctx, AV_LOG_ERROR, "Missing green channel\n");
593
                if (s->channel_offsets[2] < 0)
Michael Niedermayer's avatar
Michael Niedermayer committed
594
                    av_log(avctx, AV_LOG_ERROR, "Missing blue channel\n");
595
                return AVERROR_INVALIDDATA;
596 597 598 599
            }

            buf = channel_list_end;
            continue;
600
        } else if (check_header_variable(avctx, &buf, buf_end, "dataWindow", "box2i", 31, &variable_buffer_data_size) >= 0) {
601
            if (!variable_buffer_data_size)
602
                return AVERROR_INVALIDDATA;
603

Paul B Mahol's avatar
Paul B Mahol committed
604 605 606 607 608 609
            s->xmin = AV_RL32(buf);
            s->ymin = AV_RL32(buf + 4);
            s->xmax = AV_RL32(buf + 8);
            s->ymax = AV_RL32(buf + 12);
            s->xdelta = (s->xmax - s->xmin) + 1;
            s->ydelta = (s->ymax - s->ymin) + 1;
610 611 612

            buf += variable_buffer_data_size;
            continue;
613
        } else if (check_header_variable(avctx, &buf, buf_end, "displayWindow", "box2i", 34, &variable_buffer_data_size) >= 0) {
614
            if (!variable_buffer_data_size)
615
                return AVERROR_INVALIDDATA;
616 617 618 619 620 621

            w = AV_RL32(buf + 8) + 1;
            h = AV_RL32(buf + 12) + 1;

            buf += variable_buffer_data_size;
            continue;
622
        } else if (check_header_variable(avctx, &buf, buf_end, "lineOrder", "lineOrder", 25, &variable_buffer_data_size) >= 0) {
623
            if (!variable_buffer_data_size)
624
                return AVERROR_INVALIDDATA;
625

626 627 628 629
            av_log(avctx, AV_LOG_DEBUG, "line order : %d\n", *buf);
            if (*buf > 2) {
                av_log(avctx, AV_LOG_ERROR, "Unknown line order\n");
                return AVERROR_INVALIDDATA;
630 631 632 633
            }

            buf += variable_buffer_data_size;
            continue;
634
        } else if (check_header_variable(avctx, &buf, buf_end, "pixelAspectRatio", "float", 31, &variable_buffer_data_size) >= 0) {
635
            if (!variable_buffer_data_size)
636
                return AVERROR_INVALIDDATA;
637 638 639 640 641

            avctx->sample_aspect_ratio = av_d2q(av_int2float(AV_RL32(buf)), 255);

            buf += variable_buffer_data_size;
            continue;
642
        } else if (check_header_variable(avctx, &buf, buf_end, "compression", "compression", 29, &variable_buffer_data_size) >= 0) {
643
            if (!variable_buffer_data_size)
644
                return AVERROR_INVALIDDATA;
645

646 647 648 649
            if (s->compr == -1)
                s->compr = *buf;
            else
                av_log(avctx, AV_LOG_WARNING, "Found more than one compression attribute\n");
650 651 652 653 654 655 656

            buf += variable_buffer_data_size;
            continue;
        }

        // Check if there is enough bytes for a header
        if (buf_end - buf <= 9) {
Michael Niedermayer's avatar
Michael Niedermayer committed
657
            av_log(avctx, AV_LOG_ERROR, "Incomplete header\n");
658
            return AVERROR_INVALIDDATA;
659 660 661
        }

        // Process unknown variables
662
        for (i = 0; i < 2; i++) {
663
            // Skip variable name/type
664
            while (++buf < buf_end)
665 666 667 668 669 670 671 672
                if (buf[0] == 0x0)
                    break;
        }
        buf++;
        // Skip variable length
        if (buf_end - buf >= 5) {
            variable_buffer_data_size = get_header_variable_length(&buf, buf_end);
            if (!variable_buffer_data_size) {
Michael Niedermayer's avatar
Michael Niedermayer committed
673
                av_log(avctx, AV_LOG_ERROR, "Incomplete header\n");
674
                return AVERROR_INVALIDDATA;
675 676 677 678 679
            }
            buf += variable_buffer_data_size;
        }
    }

680 681 682 683 684
    if (s->compr == -1) {
        av_log(avctx, AV_LOG_ERROR, "Missing compression attribute\n");
        return AVERROR_INVALIDDATA;
    }

685
    if (buf >= buf_end) {
Michael Niedermayer's avatar
Michael Niedermayer committed
686
        av_log(avctx, AV_LOG_ERROR, "Incomplete frame\n");
687
        return AVERROR_INVALIDDATA;
688 689 690
    }
    buf++;

691 692 693
    switch (s->pixel_type) {
    case EXR_FLOAT:
    case EXR_HALF:
Paul B Mahol's avatar
Paul B Mahol committed
694
        if (s->channel_offsets[3] >= 0)
695
            avctx->pix_fmt = AV_PIX_FMT_RGBA64;
Paul B Mahol's avatar
Paul B Mahol committed
696
        else
697
            avctx->pix_fmt = AV_PIX_FMT_RGB48;
698
        break;
699
    case EXR_UINT:
700
        avpriv_request_sample(avctx, "32-bit unsigned int");
701
        return AVERROR_PATCHWELCOME;
702
    default:
703
        av_log(avctx, AV_LOG_ERROR, "Missing channel list\n");
704
        return AVERROR_INVALIDDATA;
705 706
    }

Paul B Mahol's avatar
Paul B Mahol committed
707 708
    switch (s->compr) {
    case EXR_RAW:
Paul B Mahol's avatar
Paul B Mahol committed
709
    case EXR_RLE:
Paul B Mahol's avatar
Paul B Mahol committed
710
    case EXR_ZIP1:
Paul B Mahol's avatar
Paul B Mahol committed
711
        s->scan_lines_per_block = 1;
Paul B Mahol's avatar
Paul B Mahol committed
712
        break;
Paul B Mahol's avatar
Paul B Mahol committed
713
    case EXR_PXR24:
Paul B Mahol's avatar
Paul B Mahol committed
714
    case EXR_ZIP16:
Paul B Mahol's avatar
Paul B Mahol committed
715
        s->scan_lines_per_block = 16;
Paul B Mahol's avatar
Paul B Mahol committed
716
        break;
Paul B Mahol's avatar
Paul B Mahol committed
717 718 719
    default:
        av_log(avctx, AV_LOG_ERROR, "Compression type %d is not supported\n", s->compr);
        return AVERROR_PATCHWELCOME;
Paul B Mahol's avatar
Paul B Mahol committed
720 721
    }

722
    if (av_image_check_size(w, h, 0, avctx))
723
        return AVERROR_INVALIDDATA;
724 725

    // Verify the xmin, xmax, ymin, ymax and xdelta before setting the actual image size
Paul B Mahol's avatar
Paul B Mahol committed
726 727 728 729
    if (s->xmin > s->xmax ||
        s->ymin > s->ymax ||
        s->xdelta != s->xmax - s->xmin + 1 ||
        s->xmax >= w || s->ymax >= h) {
Michael Niedermayer's avatar
Michael Niedermayer committed
730
        av_log(avctx, AV_LOG_ERROR, "Wrong sizing or missing size information\n");
731
        return AVERROR_INVALIDDATA;
732 733 734 735 736 737
    }

    if (w != avctx->width || h != avctx->height) {
        avcodec_set_dimensions(avctx, w, h);
    }

Paul B Mahol's avatar
Paul B Mahol committed
738 739 740 741
    s->desc = av_pix_fmt_desc_get(avctx->pix_fmt);
    out_line_size = avctx->width * 2 * s->desc->nb_components;
    s->scan_line_size = s->xdelta * current_channel_offset;
    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
742 743

    if (s->compr != EXR_RAW) {
744
        size_t thread_data_size, prev_size;
Paul B Mahol's avatar
Paul B Mahol committed
745 746 747 748 749 750 751 752
        EXRThreadData *m;

        prev_size = s->thread_data_size;
        if (av_size_mult(avctx->thread_count, sizeof(EXRThreadData), &thread_data_size))
            return AVERROR(EINVAL);

        m = av_fast_realloc(s->thread_data, &s->thread_data_size, thread_data_size);
        if (!m)
Paul B Mahol's avatar
Paul B Mahol committed
753
            return AVERROR(ENOMEM);
Paul B Mahol's avatar
Paul B Mahol committed
754 755
        s->thread_data = m;
        memset(s->thread_data + prev_size, 0, s->thread_data_size - prev_size);
Paul B Mahol's avatar
Paul B Mahol committed
756 757
    }

758
    if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0)
759
        return ret;
760

Paul B Mahol's avatar
Paul B Mahol committed
761 762 763
    if (buf_end - buf < scan_line_blocks * 8)
        return AVERROR_INVALIDDATA;
    s->table = buf;
764
    ptr = picture->data[0];
765 766

    // Zero out the start if ymin is not 0
Paul B Mahol's avatar
Paul B Mahol committed
767
    for (y = 0; y < s->ymin; y++) {
Paul B Mahol's avatar
Paul B Mahol committed
768
        memset(ptr, 0, out_line_size);
769
        ptr += picture->linesize[0];
770 771
    }

772
    s->picture = picture;
Paul B Mahol's avatar
Paul B Mahol committed
773
    avctx->execute2(avctx, decode_block, s->thread_data, NULL, scan_line_blocks);
774 775

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

781
    *got_frame = 1;
782 783 784 785 786 787 788

    return buf_size;
}

static av_cold int decode_end(AVCodecContext *avctx)
{
    EXRContext *s = avctx->priv_data;
Paul B Mahol's avatar
Paul B Mahol committed
789
    int i;
Paul B Mahol's avatar
Paul B Mahol committed
790

Paul B Mahol's avatar
Paul B Mahol committed
791 792 793 794 795 796 797 798
    for (i = 0; i < s->thread_data_size / sizeof(EXRThreadData); i++) {
        EXRThreadData *td = &s->thread_data[i];
        av_free(td->uncompressed_data);
        av_free(td->tmp);
    }

    av_freep(&s->thread_data);
    s->thread_data_size = 0;
799
    av_freep(&s->channels);
Paul B Mahol's avatar
Paul B Mahol committed
800

801 802 803 804 805 806
    return 0;
}

AVCodec ff_exr_decoder = {
    .name               = "exr",
    .type               = AVMEDIA_TYPE_VIDEO,
807
    .id                 = AV_CODEC_ID_EXR,
808 809 810
    .priv_data_size     = sizeof(EXRContext),
    .close              = decode_end,
    .decode             = decode_frame,
Paul B Mahol's avatar
Paul B Mahol committed
811
    .capabilities       = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS | CODEC_CAP_SLICE_THREADS,
812 813
    .long_name          = NULL_IF_CONFIG_SMALL("OpenEXR image"),
};