]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/exr.c
ffplay: give more meaningful names to the buffersink instances
[ffmpeg] / libavcodec / exr.c
index 579399e90f54f981c24747d199e06be4e582eb73..a95423f1dfdbda81329c91febfdda6af7441c799 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 /**
- * @file libavcodec/exr.c
+ * @file
  * OpenEXR decoder
  * @author Jimmy Christensen
  *
@@ -47,7 +47,7 @@ typedef struct EXRContext {
     AVFrame picture;
     int compr;
     int bits_per_color_id;
-    int8_t channel_offsets[3]; // 0 = red, 1 = green and 2 = blue
+    int8_t channel_offsets[4]; // 0 = red, 1 = green, 2 = blue and 3 = alpha
 } EXRContext;
 
 /**
@@ -77,15 +77,13 @@ static inline uint16_t exr_flt2uint(uint32_t v)
  */
 static inline uint16_t exr_halflt2uint(uint16_t v)
 {
-    int exp = v >> 10;
-    if (v & 0x8000)
-        return 0;
-    if (!exp)
-        return (v >> 9) & 1;
-    if (exp >= 15)
-        return 0xffff;
+    unsigned exp = 14 - (v >> 10);
+    if (exp >= 14) {
+        if (exp == 14) return (v >> 9) & 1;
+        else           return (v & 0x8000) ? 0 : 0xffff;
+    }
     v <<= 6;
-    return (v + (1 << 16)) >> (15 - exp);
+    return (v + (1 << 16)) >> (exp + 1);
 }
 
 /**
@@ -117,9 +115,9 @@ static unsigned int get_header_variable_length(const uint8_t **buf,
  * @param minimum_length minimum length of the variable data
  * @param variable_buffer_data_size variable length read from the header
  * after it's checked
- * @return zero if variable is invalid and 1 if good
+ * @return negative if variable is invalid
  */
-static unsigned int check_header_variable(AVCodecContext *avctx,
+static int check_header_variable(AVCodecContext *avctx,
                                               const uint8_t **buf,
                                               const uint8_t *buf_end,
                                               const char *value_name,
@@ -133,13 +131,15 @@ static unsigned int check_header_variable(AVCodecContext *avctx,
             *buf += strlen(value_type)+1;
             *variable_buffer_data_size = get_header_variable_length(buf, buf_end);
             if (!*variable_buffer_data_size)
-                av_log(avctx, AVERROR_INVALIDDATA, "Incomplete header\n");
+                av_log(avctx, AV_LOG_ERROR, "Incomplete header\n");
+            if (*variable_buffer_data_size > buf_end - *buf)
+                return -1;
             return 1;
         }
         *buf -= strlen(value_name)+1;
         av_log(avctx, AV_LOG_WARNING, "Unknown data type for header variable %s\n", value_name);
     }
-    return 0;
+    return -1;
 }
 
 static int decode_frame(AVCodecContext *avctx,
@@ -156,7 +156,7 @@ static int decode_frame(AVCodecContext *avctx,
     AVFrame *const p = &s->picture;
     uint8_t *ptr;
 
-    int x, y, stride, magic_number, version_flag;
+    int i, x, y, stride, magic_number, version_flag;
     int w = 0;
     int h = 0;
     unsigned int xmin   = ~0;
@@ -170,8 +170,14 @@ static int decode_frame(AVCodecContext *avctx,
     s->channel_offsets[0] = -1;
     s->channel_offsets[1] = -1;
     s->channel_offsets[2] = -1;
+    s->channel_offsets[3] = -1;
     s->bits_per_color_id = -1;
 
+    if (buf_end - buf < 10) {
+        av_log(avctx, AV_LOG_ERROR, "Too short header to parse\n");
+        return -1;
+    }
+
     magic_number = bytestream_get_le32(&buf);
     if (magic_number != 20000630) { // As per documentation of OpenEXR it's supposed to be int 20000630 little-endian
         av_log(avctx, AV_LOG_ERROR, "Wrong magic number %d\n", magic_number);
@@ -180,25 +186,20 @@ static int decode_frame(AVCodecContext *avctx,
 
     version_flag = bytestream_get_le32(&buf);
     if ((version_flag & 0x200) == 0x200) {
-        av_log(avctx, AVERROR_NOFMT, "Tile based images are not supported\n");
-        return -1;
-    }
-
-    if (buf_end - buf < 10) {
-        av_log(avctx, AVERROR_INVALIDDATA, "Too short header to parse\n");
+        av_log(avctx, AV_LOG_ERROR, "Tile based images are not supported\n");
         return -1;
     }
 
     // Parse the header
-    while (buf[0] != 0x0) {
+    while (buf < buf_end && buf[0]) {
         unsigned int variable_buffer_data_size;
         // Process the channel list
-        if (check_header_variable(avctx, &buf, buf_end, "channels", "chlist", 38, &variable_buffer_data_size)) {
+        if (check_header_variable(avctx, &buf, buf_end, "channels", "chlist", 38, &variable_buffer_data_size) >= 0) {
             const uint8_t *channel_list_end;
             if (!variable_buffer_data_size)
                 return -1;
 
-            channel_list_end = buf + variable_buffer_data_size + 4;
+            channel_list_end = buf + variable_buffer_data_size;
             while (channel_list_end - buf >= 19) {
                 int current_bits_per_color_id = -1;
                 int channel_index = -1;
@@ -209,6 +210,8 @@ static int decode_frame(AVCodecContext *avctx,
                     channel_index = 1;
                 if (!strcmp(buf, "B"))
                     channel_index = 2;
+                if (!strcmp(buf, "A"))
+                    channel_index = 3;
 
                 while (bytestream_get_byte(&buf) && buf < channel_list_end)
                     continue; /* skip */
@@ -257,7 +260,7 @@ static int decode_frame(AVCodecContext *avctx,
         }
 
         // Process the dataWindow variable
-        if (check_header_variable(avctx, &buf, buf_end, "dataWindow", "box2i", 31, &variable_buffer_data_size)) {
+        if (check_header_variable(avctx, &buf, buf_end, "dataWindow", "box2i", 31, &variable_buffer_data_size) >= 0) {
             if (!variable_buffer_data_size)
                 return -1;
 
@@ -272,7 +275,7 @@ static int decode_frame(AVCodecContext *avctx,
         }
 
         // Process the displayWindow variable
-        if (check_header_variable(avctx, &buf, buf_end, "displayWindow", "box2i", 34, &variable_buffer_data_size)) {
+        if (check_header_variable(avctx, &buf, buf_end, "displayWindow", "box2i", 34, &variable_buffer_data_size) >= 0) {
             if (!variable_buffer_data_size)
                 return -1;
 
@@ -284,7 +287,7 @@ static int decode_frame(AVCodecContext *avctx,
         }
 
         // Process the lineOrder variable
-        if (check_header_variable(avctx, &buf, buf_end, "lineOrder", "lineOrder", 25, &variable_buffer_data_size)) {
+        if (check_header_variable(avctx, &buf, buf_end, "lineOrder", "lineOrder", 25, &variable_buffer_data_size) >= 0) {
             if (!variable_buffer_data_size)
                 return -1;
 
@@ -298,13 +301,13 @@ static int decode_frame(AVCodecContext *avctx,
         }
 
         // Process the compression variable
-        if (check_header_variable(avctx, &buf, buf_end, "compression", "compression", 29, &variable_buffer_data_size)) {
+        if (check_header_variable(avctx, &buf, buf_end, "compression", "compression", 29, &variable_buffer_data_size) >= 0) {
             if (!variable_buffer_data_size)
                 return -1;
 
-            switch (*buf) {
+            s->compr = *buf;
+            switch (s->compr) {
             case EXR_RAW:
-                s->compr = *buf;
                 break;
             case EXR_RLE:
             case EXR_ZIP1:
@@ -312,7 +315,7 @@ static int decode_frame(AVCodecContext *avctx,
             case EXR_PIZ:
             case EXR_B44:
             default:
-                av_log(avctx, AV_LOG_ERROR, "This type of compression is not supported\n");
+                av_log(avctx, AV_LOG_ERROR, "Compression type %d is not supported\n", s->compr);
                 return -1;
             }
 
@@ -327,9 +330,9 @@ static int decode_frame(AVCodecContext *avctx,
         }
 
         // Process unknown variables
-        for (int i = 0; i < 2; i++) {
+        for (i = 0; i < 2; i++) {
             // Skip variable name/type
-            while (buf++ < buf_end)
+            while (++buf < buf_end)
                 if (buf[0] == 0x0)
                     break;
         }
@@ -354,7 +357,10 @@ static int decode_frame(AVCodecContext *avctx,
     switch (s->bits_per_color_id) {
     case 2: // 32-bit
     case 1: // 16-bit
-        avctx->pix_fmt = PIX_FMT_RGB48;
+        if (s->channel_offsets[3] >= 0)
+            avctx->pix_fmt = PIX_FMT_RGBA64;
+        else
+            avctx->pix_fmt = PIX_FMT_RGB48;
         break;
     // 8-bit
     case 0:
@@ -371,11 +377,7 @@ static int decode_frame(AVCodecContext *avctx,
         return -1;
 
     // Verify the xmin, xmax, ymin, ymax and xdelta before setting the actual image size
-    if (xmin > w || xmin == ~0 ||
-        xmax > w || xmax == ~0 ||
-        ymin > h || ymin == ~0 ||
-        ymax > h || ymax == ~0 ||
-        xdelta == ~0) {
+    if (xmin > xmax || ymin > ymax || xdelta != xmax - xmin + 1 || xmax >= w || ymax >= h) {
         av_log(avctx, AV_LOG_ERROR, "Wrong sizing or missing size information\n");
         return -1;
     }
@@ -394,7 +396,7 @@ static int decode_frame(AVCodecContext *avctx,
 
     // Zero out the start if ymin is not 0
     for (y = 0; y < ymin; y++) {
-        memset(ptr, 0, avctx->width * 6);
+        memset(ptr, 0, avctx->width * 2 * av_pix_fmt_descriptors[avctx->pix_fmt].nb_components);
         ptr += stride;
     }
 
@@ -409,21 +411,27 @@ static int decode_frame(AVCodecContext *avctx,
             if (line_offset > avpkt->size - xdelta * current_channel_offset) {
                 // Line offset is probably wrong and not inside the buffer
                 av_log(avctx, AV_LOG_WARNING, "Line offset for line %d is out of reach setting it to black\n", y);
-                memset(ptr_x, 0, avctx->width * 6);
+                memset(ptr_x, 0, avctx->width * 2 * av_pix_fmt_descriptors[avctx->pix_fmt].nb_components);
             } else {
                 const uint8_t *red_channel_buffer   = avpkt->data + line_offset + xdelta * s->channel_offsets[0];
                 const uint8_t *green_channel_buffer = avpkt->data + line_offset + xdelta * s->channel_offsets[1];
                 const uint8_t *blue_channel_buffer  = avpkt->data + line_offset + xdelta * s->channel_offsets[2];
+                const uint8_t *alpha_channel_buffer = 0;
+
+                if (s->channel_offsets[3] >= 0)
+                    alpha_channel_buffer = avpkt->data + line_offset + xdelta * s->channel_offsets[3];
 
                 // Zero out the start if xmin is not 0
-                memset(ptr_x, 0, xmin * 6);
-                ptr_x += xmin * 3;
+                memset(ptr_x, 0, xmin * 2 * av_pix_fmt_descriptors[avctx->pix_fmt].nb_components);
+                ptr_x += xmin * av_pix_fmt_descriptors[avctx->pix_fmt].nb_components;
                 if (s->bits_per_color_id == 2) {
                     // 32-bit
                     for (x = 0; x < xdelta; x++) {
                         *ptr_x++ = exr_flt2uint(bytestream_get_le32(&red_channel_buffer));
                         *ptr_x++ = exr_flt2uint(bytestream_get_le32(&green_channel_buffer));
                         *ptr_x++ = exr_flt2uint(bytestream_get_le32(&blue_channel_buffer));
+                        if (alpha_channel_buffer)
+                            *ptr_x++ = exr_flt2uint(bytestream_get_le32(&alpha_channel_buffer));
                     }
                 } else {
                     // 16-bit
@@ -431,12 +439,14 @@ static int decode_frame(AVCodecContext *avctx,
                         *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&red_channel_buffer));
                         *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&green_channel_buffer));
                         *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&blue_channel_buffer));
+                        if (alpha_channel_buffer)
+                            *ptr_x++ = exr_halflt2uint(bytestream_get_le16(&alpha_channel_buffer));
                     }
                 }
 
                 // Zero out the end if xmax+1 is not w
-                memset(ptr_x, 0, (avctx->width - (xmax + 1)) * 6);
-                ptr_x += (avctx->width - (xmax + 1)) * 3;
+                memset(ptr_x, 0, (avctx->width - (xmax + 1)) * 2 * av_pix_fmt_descriptors[avctx->pix_fmt].nb_components);
+                ptr_x += (avctx->width - (xmax + 1)) * av_pix_fmt_descriptors[avctx->pix_fmt].nb_components;
 
             }
             // Move to next line
@@ -445,8 +455,8 @@ static int decode_frame(AVCodecContext *avctx,
     }
 
     // Zero out the end if ymax+1 is not h
-    for (y = ymax; y < avctx->height; y++) {
-        memset(ptr, 0, avctx->width * 6);
+    for (y = ymax + 1; y < avctx->height; y++) {
+        memset(ptr, 0, avctx->width * 2 * av_pix_fmt_descriptors[avctx->pix_fmt].nb_components);
         ptr += stride;
     }