Browse code

lavc: add a OpenEXR decoder

Signed-off-by: Michael Niedermayer <michaelni@gmx.at>

Jimmy Christensen authored on 2012/04/06 13:02:25
Showing 10 changed files
... ...
@@ -20,7 +20,7 @@ version next:
20 20
 - ZeroCodec decoder
21 21
 - tile video filter
22 22
 - Metal Gear Solid: The Twin Snakes demuxer
23
-
23
+- OpenEXR image decoder
24 24
 
25 25
 version 0.10:
26 26
 - Fixes: CVE-2011-3929, CVE-2011-3934, CVE-2011-3935, CVE-2011-3936,
... ...
@@ -372,6 +372,8 @@ following image formats are supported:
372 372
     @tab Microsoft BMP image
373 373
 @item DPX          @tab X @tab X
374 374
     @tab Digital Picture Exchange
375
+@item EXR          @tab   @tab X
376
+    @tab OpenEXR
375 377
 @item JPEG         @tab X @tab X
376 378
     @tab Progressive JPEG is not supported.
377 379
 @item JPEG 2000    @tab X @tab X
... ...
@@ -160,6 +160,7 @@ OBJS-$(CONFIG_EIGHTSVX_FIB_DECODER)    += 8svx.o
160 160
 OBJS-$(CONFIG_EIGHTSVX_RAW_DECODER)    += 8svx.o
161 161
 OBJS-$(CONFIG_ESCAPE124_DECODER)       += escape124.o
162 162
 OBJS-$(CONFIG_ESCAPE130_DECODER)       += escape130.o
163
+OBJS-$(CONFIG_EXR_DECODER)             += exr.o
163 164
 OBJS-$(CONFIG_FFV1_DECODER)            += ffv1.o rangecoder.o
164 165
 OBJS-$(CONFIG_FFV1_ENCODER)            += ffv1.o rangecoder.o
165 166
 OBJS-$(CONFIG_FFVHUFF_DECODER)         += huffyuv.o
... ...
@@ -113,6 +113,7 @@ void avcodec_register_all(void)
113 113
     REGISTER_DECODER (EIGHTSVX_FIB, eightsvx_fib);
114 114
     REGISTER_DECODER (ESCAPE124, escape124);
115 115
     REGISTER_DECODER (ESCAPE130, escape130);
116
+    REGISTER_DECODER (EXR, exr);
116 117
     REGISTER_ENCDEC  (FFV1, ffv1);
117 118
     REGISTER_ENCDEC  (FFVHUFF, ffvhuff);
118 119
     REGISTER_ENCDEC  (FLASHSV, flashsv);
... ...
@@ -251,6 +251,7 @@ enum CodecID {
251 251
     CODEC_ID_ZEROCODEC,
252 252
     CODEC_ID_Y41P       = MKBETAG('Y','4','1','P'),
253 253
     CODEC_ID_ESCAPE130  = MKBETAG('E','1','3','0'),
254
+    CODEC_ID_EXR        = MKBETAG('0','E','X','R'),
254 255
     CODEC_ID_AVRP       = MKBETAG('A','V','R','P'),
255 256
 
256 257
     CODEC_ID_G2M        = MKBETAG( 0 ,'G','2','M'),
257 258
new file mode 100644
... ...
@@ -0,0 +1,485 @@
0
+/*
1
+ * OpenEXR (.exr) image decoder
2
+ * Copyright (c) 2009 Jimmy Christensen
3
+ *
4
+ * This file is part of FFmpeg.
5
+ *
6
+ * FFmpeg is free software; you can redistribute it and/or
7
+ * modify it under the terms of the GNU Lesser General Public
8
+ * License as published by the Free Software Foundation; either
9
+ * version 2.1 of the License, or (at your option) any later version.
10
+ *
11
+ * FFmpeg is distributed in the hope that it will be useful,
12
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
+ * Lesser General Public License for more details.
15
+ *
16
+ * You should have received a copy of the GNU Lesser General Public
17
+ * License along with FFmpeg; if not, write to the Free Software
18
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19
+ */
20
+
21
+/**
22
+ * @file libavcodec/exr.c
23
+ * OpenEXR decoder
24
+ * @author Jimmy Christensen
25
+ *
26
+ * For more information on the OpenEXR format, visit:
27
+ *  http://openexr.com/
28
+ *
29
+ * exr_flt2uint() and exr_halflt2uint() is credited to  Reimar Döffinger
30
+ */
31
+
32
+#include "avcodec.h"
33
+#include "bytestream.h"
34
+#include "libavutil/imgutils.h"
35
+
36
+enum ExrCompr {
37
+    EXR_RAW   = 0,
38
+    EXR_RLE   = 1,
39
+    EXR_ZIP1  = 2,
40
+    EXR_ZIP16 = 3,
41
+    EXR_PIZ   = 4,
42
+    EXR_B44   = 6
43
+};
44
+
45
+typedef struct EXRContext {
46
+    AVFrame picture;
47
+    int compr;
48
+    int bits_per_color_id;
49
+    int8_t channel_offsets[3]; // 0 = red, 1 = green and 2 = blue
50
+} EXRContext;
51
+
52
+/**
53
+ * Converts from 32-bit float as uint32_t to uint16_t
54
+ *
55
+ * @param v 32-bit float
56
+ * @return normalized 16-bit unsigned int
57
+ */
58
+static inline uint16_t exr_flt2uint(uint32_t v)
59
+{
60
+    unsigned int exp = v >> 23;
61
+    // "HACK": negative values result in exp<  0, so clipping them to 0
62
+    // is also handled by this condition, avoids explicit check for sign bit.
63
+    if (exp<= 127 + 7 - 24) // we would shift out all bits anyway
64
+        return 0;
65
+    if (exp >= 127)
66
+        return 0xffff;
67
+    v &= 0x007fffff;
68
+    return (v + (1 << 23)) >> (127 + 7 - exp);
69
+}
70
+
71
+/**
72
+ * Converts from 16-bit float as uint16_t to uint16_t
73
+ *
74
+ * @param v 16-bit float
75
+ * @return normalized 16-bit unsigned int
76
+ */
77
+static inline uint16_t exr_halflt2uint(uint16_t v)
78
+{
79
+    int exp = v >> 10;
80
+    if (v & 0x8000)
81
+        return 0;
82
+    if (!exp)
83
+        return (v >> 9) & 1;
84
+    if (exp >= 15)
85
+        return 0xffff;
86
+    v <<= 6;
87
+    return (v + (1 << 16)) >> (15 - exp);
88
+}
89
+
90
+/**
91
+ * Gets the size of the header variable
92
+ *
93
+ * @param **buf the current pointer location in the header where
94
+ * the variable data starts
95
+ * @param *buf_end pointer location of the end of the buffer
96
+ * @return size of variable data
97
+ */
98
+static unsigned int get_header_variable_length(const uint8_t **buf,
99
+                                               const uint8_t *buf_end)
100
+{
101
+    unsigned int variable_buffer_data_size = bytestream_get_le32(buf);
102
+    if (variable_buffer_data_size >= buf_end - *buf)
103
+        return 0;
104
+    return variable_buffer_data_size;
105
+}
106
+
107
+/**
108
+ * Checks if the variable name corresponds with it's data type
109
+ *
110
+ * @param *avctx the AVCodecContext
111
+ * @param **buf the current pointer location in the header where
112
+ * the variable name starts
113
+ * @param *buf_end pointer location of the end of the buffer
114
+ * @param *value_name name of the varible to check
115
+ * @param *value_type type of the varible to check
116
+ * @param minimum_length minimum length of the variable data
117
+ * @param variable_buffer_data_size variable length read from the header
118
+ * after it's checked
119
+ * @return zero if variable is invalid and 1 if good
120
+ */
121
+static unsigned int check_header_variable(AVCodecContext *avctx,
122
+                                              const uint8_t **buf,
123
+                                              const uint8_t *buf_end,
124
+                                              const char *value_name,
125
+                                              const char *value_type,
126
+                                              unsigned int minimum_length,
127
+                                              unsigned int *variable_buffer_data_size)
128
+{
129
+    if (buf_end - *buf >= minimum_length && !strcmp(*buf, value_name)) {
130
+        *buf += strlen(value_name)+1;
131
+        if (!strcmp(*buf, value_type)) {
132
+            *buf += strlen(value_type)+1;
133
+            *variable_buffer_data_size = get_header_variable_length(buf, buf_end);
134
+            if (!*variable_buffer_data_size)
135
+                av_log(avctx, AVERROR_INVALIDDATA, "Incomplete header\n");
136
+            return 1;
137
+        }
138
+        *buf -= strlen(value_name)+1;
139
+        av_log(avctx, AV_LOG_WARNING, "Unknown data type for header variable %s\n", value_name);
140
+    }
141
+    return 0;
142
+}
143
+
144
+static int decode_frame(AVCodecContext *avctx,
145
+                        void *data,
146
+                        int *data_size,
147
+                        AVPacket *avpkt)
148
+{
149
+    const uint8_t *buf      = avpkt->data;
150
+    unsigned int   buf_size = avpkt->size;
151
+    const uint8_t *buf_end  = buf + buf_size;
152
+
153
+    EXRContext *const s = avctx->priv_data;
154
+    AVFrame *picture  = data;
155
+    AVFrame *const p = &s->picture;
156
+    uint8_t *ptr;
157
+
158
+    int x, y, stride, magic_number, version_flag;
159
+    int w = 0;
160
+    int h = 0;
161
+    unsigned int xmin   = ~0;
162
+    unsigned int xmax   = ~0;
163
+    unsigned int ymin   = ~0;
164
+    unsigned int ymax   = ~0;
165
+    unsigned int xdelta = ~0;
166
+
167
+    unsigned int current_channel_offset = 0;
168
+
169
+    s->channel_offsets[0] = -1;
170
+    s->channel_offsets[1] = -1;
171
+    s->channel_offsets[2] = -1;
172
+    s->bits_per_color_id = -1;
173
+
174
+    magic_number = bytestream_get_le32(&buf);
175
+    if (magic_number != 20000630) { // As per documentation of OpenEXR it's supposed to be int 20000630 little-endian
176
+        av_log(avctx, AVERROR_INVALIDDATA, "Wrong magic number %d\n", magic_number);
177
+        return -1;
178
+    }
179
+
180
+    version_flag = bytestream_get_le32(&buf);
181
+    if ((version_flag & 0x200) == 0x200) {
182
+        av_log(avctx, AVERROR_NOFMT, "Tile based images are not supported\n");
183
+        return -1;
184
+    }
185
+
186
+    if (buf_end - buf < 10) {
187
+        av_log(avctx, AVERROR_INVALIDDATA, "Too short header to parse\n");
188
+        return -1;
189
+    }
190
+
191
+    // Parse the header
192
+    while (buf[0] != 0x0) {
193
+        unsigned int variable_buffer_data_size;
194
+        // Process the channel list
195
+        if (check_header_variable(avctx, &buf, buf_end, "channels", "chlist", 38, &variable_buffer_data_size)) {
196
+            const uint8_t *channel_list_end;
197
+            if (!variable_buffer_data_size)
198
+                return -1;
199
+
200
+            channel_list_end = buf + variable_buffer_data_size + 4;
201
+            while (channel_list_end - buf >= 19) {
202
+                int current_bits_per_color_id = -1;
203
+                int channel_index = -1;
204
+
205
+                if (!strcmp(buf, "R"))
206
+                    channel_index = 0;
207
+                if (!strcmp(buf, "G"))
208
+                    channel_index = 1;
209
+                if (!strcmp(buf, "B"))
210
+                    channel_index = 2;
211
+
212
+                while (bytestream_get_byte(&buf) && buf < channel_list_end)
213
+                    continue; /* skip */
214
+
215
+                if (channel_list_end - * &buf < 4) {
216
+                    av_log(avctx, AVERROR_INVALIDDATA, "Incomplete header\n");
217
+                    return -1;
218
+                }
219
+
220
+                current_bits_per_color_id = bytestream_get_le32(&buf);
221
+                if (current_bits_per_color_id > 2) {
222
+                    av_log(avctx, AVERROR_NOFMT, "Unknown color format\n");
223
+                    return -1;
224
+                }
225
+
226
+                if (channel_index >= 0) {
227
+                    if (s->bits_per_color_id != -1 && s->bits_per_color_id != current_bits_per_color_id) {
228
+                        av_log(avctx, AVERROR_NOFMT, "RGB channels not of the same depth\n");
229
+                        return -1;
230
+                    }
231
+                    s->bits_per_color_id  = current_bits_per_color_id;
232
+                    s->channel_offsets[channel_index] = current_channel_offset;
233
+                }
234
+
235
+                current_channel_offset += 1 << current_bits_per_color_id;
236
+                buf += 12;
237
+            }
238
+
239
+            /* Check if all channels are set with an offset or if the channels
240
+             * are causing an overflow  */
241
+
242
+            if (FFMIN3(s->channel_offsets[0],
243
+                       s->channel_offsets[1],
244
+                       s->channel_offsets[2]) < 0) {
245
+                if (s->channel_offsets[0] < 0)
246
+                    av_log(avctx, AVERROR_NOFMT, "Missing red channel\n");
247
+                if (s->channel_offsets[1] < 0)
248
+                    av_log(avctx, AVERROR_NOFMT, "Missing green channel\n");
249
+                if (s->channel_offsets[2] < 0)
250
+                    av_log(avctx, AVERROR_NOFMT, "Missing blue channel\n");
251
+                return -1;
252
+            }
253
+
254
+            buf = channel_list_end;
255
+            continue;
256
+        }
257
+
258
+        // Process the dataWindow variable
259
+        if (check_header_variable(avctx, &buf, buf_end, "dataWindow", "box2i", 31, &variable_buffer_data_size)) {
260
+            if (!variable_buffer_data_size)
261
+                return -1;
262
+
263
+            xmin = AV_RL32(buf);
264
+            ymin = AV_RL32(buf + 4);
265
+            xmax = AV_RL32(buf + 8);
266
+            ymax = AV_RL32(buf + 12);
267
+            xdelta = (xmax-xmin) + 1;
268
+
269
+            buf += variable_buffer_data_size;
270
+            continue;
271
+        }
272
+
273
+        // Process the displayWindow variable
274
+        if (check_header_variable(avctx, &buf, buf_end, "displayWindow", "box2i", 34, &variable_buffer_data_size)) {
275
+            if (!variable_buffer_data_size)
276
+                return -1;
277
+
278
+            w = AV_RL32(buf + 8) + 1;
279
+            h = AV_RL32(buf + 12) + 1;
280
+
281
+            buf += variable_buffer_data_size;
282
+            continue;
283
+        }
284
+
285
+        // Process the lineOrder variable
286
+        if (check_header_variable(avctx, &buf, buf_end, "lineOrder", "lineOrder", 25, &variable_buffer_data_size)) {
287
+            if (!variable_buffer_data_size)
288
+                return -1;
289
+
290
+            if (*buf) {
291
+                av_log(avctx, AVERROR_NOFMT, "Doesn't support this line order : %d\n", *buf);
292
+                return -1;
293
+            }
294
+
295
+            buf += variable_buffer_data_size;
296
+            continue;
297
+        }
298
+
299
+        // Process the compression variable
300
+        if (check_header_variable(avctx, &buf, buf_end, "compression", "compression", 29, &variable_buffer_data_size)) {
301
+            if (!variable_buffer_data_size)
302
+                return -1;
303
+
304
+            switch (*buf) {
305
+            case EXR_RAW:
306
+                s->compr = *buf;
307
+                break;
308
+            case EXR_RLE:
309
+            case EXR_ZIP1:
310
+            case EXR_ZIP16:
311
+            case EXR_PIZ:
312
+            case EXR_B44:
313
+            default:
314
+                av_log(avctx, AVERROR_NOFMT, "This type of compression is not supported\n");
315
+                return -1;
316
+            }
317
+
318
+            buf += variable_buffer_data_size;
319
+            continue;
320
+        }
321
+
322
+        // Check if there is enough bytes for a header
323
+        if (buf_end - buf <= 9) {
324
+            av_log(avctx, AVERROR_INVALIDDATA, "Incomplete header\n");
325
+            return -1;
326
+        }
327
+
328
+        // Process unknown variables
329
+        for (int i = 0; i < 2; i++) {
330
+            // Skip variable name/type
331
+            while (buf++ < buf_end)
332
+                if (buf[0] == 0x0)
333
+                    break;
334
+        }
335
+        buf++;
336
+        // Skip variable length
337
+        if (buf_end - buf >= 5) {
338
+            variable_buffer_data_size = get_header_variable_length(&buf, buf_end);
339
+            if (!variable_buffer_data_size) {
340
+                av_log(avctx, AVERROR_INVALIDDATA, "Incomplete header\n");
341
+                return -1;
342
+            }
343
+            buf += variable_buffer_data_size;
344
+        }
345
+    }
346
+
347
+    if (buf >= buf_end) {
348
+        av_log(avctx, AVERROR_EOF, "Incomplete file\n");
349
+        return -1;
350
+    }
351
+    buf++;
352
+
353
+    switch (s->bits_per_color_id) {
354
+    case 2: // 32-bit
355
+    case 1: // 16-bit
356
+        avctx->pix_fmt = PIX_FMT_RGB48;
357
+        break;
358
+    // 8-bit
359
+    case 0:
360
+        av_log_missing_feature(avctx, "8-bit OpenEXR", 1);
361
+        return -1;
362
+    default:
363
+        av_log(avctx, AVERROR_NOFMT, "Unknown color format : %d\n", s->bits_per_color_id);
364
+        return -1;
365
+    }
366
+
367
+    if (s->picture.data[0])
368
+        avctx->release_buffer(avctx, &s->picture);
369
+    if (av_image_check_size(w, h, 0, avctx))
370
+        return -1;
371
+
372
+    // Verify the xmin, xmax, ymin, ymax and xdelta before setting the actual image size
373
+    if (xmin > w || xmin == ~0 ||
374
+        xmax > w || xmax == ~0 ||
375
+        ymin > h || ymin == ~0 ||
376
+        ymax > h || ymax == ~0 ||
377
+        xdelta == ~0) {
378
+        av_log(avctx, AVERROR_INVALIDDATA, "Wrong sizing or missing size information\n");
379
+        return -1;
380
+    }
381
+
382
+    if (w != avctx->width || h != avctx->height) {
383
+        avcodec_set_dimensions(avctx, w, h);
384
+    }
385
+
386
+    if (avctx->get_buffer(avctx, p) < 0) {
387
+        av_log(avctx, AVERROR_IO, "get_buffer() failed\n");
388
+        return -1;
389
+    }
390
+
391
+    ptr    = p->data[0];
392
+    stride = p->linesize[0];
393
+
394
+    // Zero out the start if ymin is not 0
395
+    for (y = 0; y < ymin; y++) {
396
+        memset(ptr, 0, avctx->width * 6);
397
+        ptr += stride;
398
+    }
399
+
400
+    // Process the actual lines
401
+    for (y = ymin; y <= ymax; y++) {
402
+        uint16_t *ptr_x = (uint16_t *)ptr;
403
+        if (buf_end - buf > 8) {
404
+            /* Read the lineoffset from the line offset table and add 8 bytes
405
+               to skip the coordinates and data size fields */
406
+            const uint64_t line_offset = bytestream_get_le64(&buf) + 8;
407
+            // Check if the buffer has the required bytes needed from the offset
408
+            if (line_offset > avpkt->size - xdelta * current_channel_offset) {
409
+                // Line offset is probably wrong and not inside the buffer
410
+                av_log(avctx, AV_LOG_WARNING, "Line offset for line %d is out of reach setting it to black\n", y);
411
+                memset(ptr_x, 0, avctx->width * 6);
412
+            } else {
413
+                const uint8_t *red_channel_buffer   = avpkt->data + line_offset + xdelta * s->channel_offsets[0];
414
+                const uint8_t *green_channel_buffer = avpkt->data + line_offset + xdelta * s->channel_offsets[1];
415
+                const uint8_t *blue_channel_buffer  = avpkt->data + line_offset + xdelta * s->channel_offsets[2];
416
+
417
+                // Zero out the start if xmin is not 0
418
+                memset(ptr_x, 0, xmin * 6);
419
+                ptr_x += xmin * 3;
420
+                if (s->bits_per_color_id == 2) {
421
+                    // 32-bit
422
+                    for (x = 0; x < xdelta; x++) {
423
+                        *ptr_x++ = exr_flt2uint(bytestream_get_le32(&red_channel_buffer));
424
+                        *ptr_x++ = exr_flt2uint(bytestream_get_le32(&green_channel_buffer));
425
+                        *ptr_x++ = exr_flt2uint(bytestream_get_le32(&blue_channel_buffer));
426
+                    }
427
+                } else {
428
+                    // 16-bit
429
+                    for (x = 0; x < xdelta; x++) {
430
+                        *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&red_channel_buffer));
431
+                        *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&green_channel_buffer));
432
+                        *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&blue_channel_buffer));
433
+                    }
434
+                }
435
+
436
+                // Zero out the end if xmax+1 is not w
437
+                memset(ptr_x, 0, (avctx->width - (xmax + 1)) * 6);
438
+                ptr_x += (avctx->width - (xmax + 1)) * 3;
439
+
440
+            }
441
+            // Move to next line
442
+            ptr += stride;
443
+        }
444
+    }
445
+
446
+    // Zero out the end if ymax+1 is not h
447
+    for (y = ymax; y < avctx->height; y++) {
448
+        memset(ptr, 0, avctx->width * 6);
449
+        ptr += stride;
450
+    }
451
+
452
+    *picture   = s->picture;
453
+    *data_size = sizeof(AVPicture);
454
+
455
+    return buf_size;
456
+}
457
+
458
+static av_cold int decode_init(AVCodecContext *avctx)
459
+{
460
+    EXRContext *s = avctx->priv_data;
461
+    avcodec_get_frame_defaults(&s->picture);
462
+    avctx->coded_frame = &s->picture;
463
+    return 0;
464
+}
465
+
466
+static av_cold int decode_end(AVCodecContext *avctx)
467
+{
468
+    EXRContext *s = avctx->priv_data;
469
+    if (s->picture.data[0])
470
+        avctx->release_buffer(avctx, &s->picture);
471
+
472
+    return 0;
473
+}
474
+
475
+AVCodec ff_exr_decoder = {
476
+    .name               = "exr",
477
+    .type               = AVMEDIA_TYPE_VIDEO,
478
+    .id                 = CODEC_ID_EXR,
479
+    .priv_data_size     = sizeof(EXRContext),
480
+    .init               = decode_init,
481
+    .close              = decode_end,
482
+    .decode             = decode_frame,
483
+    .long_name          = NULL_IF_CONFIG_SMALL("OpenEXR image"),
484
+};
... ...
@@ -21,7 +21,7 @@
21 21
 #define AVCODEC_VERSION_H
22 22
 
23 23
 #define LIBAVCODEC_VERSION_MAJOR 54
24
-#define LIBAVCODEC_VERSION_MINOR  12
24
+#define LIBAVCODEC_VERSION_MINOR  13
25 25
 #define LIBAVCODEC_VERSION_MICRO 100
26 26
 
27 27
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
... ...
@@ -70,6 +70,7 @@ static const IdStrMap img_tags[] = {
70 70
     { CODEC_ID_JPEG2000  , "jp2"},
71 71
     { CODEC_ID_JPEG2000  , "jpc"},
72 72
     { CODEC_ID_DPX       , "dpx"},
73
+    { CODEC_ID_EXR       , "exr"},
73 74
     { CODEC_ID_PICTOR    , "pic"},
74 75
     { CODEC_ID_XBM       , "xbm"},
75 76
     { CODEC_ID_XWD       , "xwd"},
... ...
@@ -225,6 +225,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
225 225
     { CODEC_ID_RAWVIDEO, MKTAG('A', 'V', 'u', 'p') },
226 226
     { CODEC_ID_SGI,   MKTAG('s', 'g', 'i', ' ') }, /* SGI  */
227 227
     { CODEC_ID_DPX,   MKTAG('d', 'p', 'x', ' ') }, /* DPX */
228
+    { CODEC_ID_EXR,   MKTAG('e', 'x', 'r', ' ') }, /* OpenEXR */
228 229
 
229 230
     { CODEC_ID_PRORES, MKTAG('a', 'p', 'c', 'h') }, /* Apple ProRes 422 High Quality */
230 231
     { CODEC_ID_PRORES, MKTAG('a', 'p', 'c', 'n') }, /* Apple ProRes 422 Standard Definition */
... ...
@@ -301,6 +301,7 @@ const AVCodecTag ff_codec_bmp_tags[] = {
301 301
     { CODEC_ID_ZEROCODEC,    MKTAG('Z', 'E', 'C', 'O') },
302 302
     { CODEC_ID_Y41P,         MKTAG('Y', '4', '1', 'P') },
303 303
     { CODEC_ID_FLIC,         MKTAG('A', 'F', 'L', 'C') },
304
+    { CODEC_ID_EXR,          MKTAG('e', 'x', 'r', ' ') },
304 305
     { CODEC_ID_NONE,         0 }
305 306
 };
306 307