avcodec/exr: read layers
authorGonzalo Garramuno <ggarra13@gmail.com>
Mon, 17 Feb 2014 17:53:30 +0000 (14:53 -0300)
committerMichael Niedermayer <michaelni@gmx.at>
Tue, 18 Feb 2014 17:11:23 +0000 (18:11 +0100)
EXR files have, like tiffs, multiple channels and layers.  I have a
patch for exr.c that allows you to select the layer you want to process
thru a -layer flag.  It is not bulletproof but works for all layers that
have 3 channels in them (normals, motion vectors, etc).
The calling convention for ffmpeg is:

ffmpeg -layer Diffuse -i myexr.%d.exr test.mov

Here's an exr image with multiple layers:

http://www.datafilehost.com/d/e45d9a1c

Reviewed-by: Paul B Mahol <onemda@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
libavcodec/exr.c

index f231b70..77247fc 100644 (file)
@@ -40,6 +40,7 @@
 #include "thread.h"
 #include "libavutil/imgutils.h"
 #include "libavutil/avassert.h"
+#include "libavutil/opt.h"
 
 enum ExrCompr {
     EXR_RAW   = 0,
@@ -75,6 +76,7 @@ typedef struct EXRThreadData {
 } EXRThreadData;
 
 typedef struct EXRContext {
+    AVClass        *class;
     AVFrame *picture;
     int compr;
     enum ExrPixelType pixel_type;
@@ -98,8 +100,24 @@ typedef struct EXRContext {
 
     EXRThreadData *thread_data;
     int thread_data_size;
+
+    const char* layer;
 } EXRContext;
 
+#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},
+    { NULL },
+};
+
+static const AVClass exr_class = {
+    .class_name = "EXR",
+    .item_name  = av_default_item_name,
+    .option     = options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
 /**
  * Converts from 32-bit float as uint32_t to uint16_t
  *
@@ -990,13 +1008,25 @@ static int decode_frame(AVCodecContext *avctx,
                 int channel_index = -1;
                 int xsub, ysub;
 
-                if (!strcmp(buf, "R"))
+                const char* b = buf;
+
+                if ( strcmp( s->layer, "" ) != 0 ) {
+                    if ( strncmp( b, s->layer, strlen(s->layer) ) == 0 ) {
+                        b += strlen(s->layer);
+                        if ( *b == '.' ) ++b;   /* skip dot if not given */
+                        av_log( avctx, AV_LOG_INFO, "Layer %s.%s matched\n",
+                               s->layer, b );
+                    }
+                }
+
+
+                if (!strcmp(b, "R")||!strcmp(b, "X")||!strcmp(b,"U"))
                     channel_index = 0;
-                else if (!strcmp(buf, "G"))
+                else if (!strcmp(b, "G")||!strcmp(b, "Y")||!strcmp(b,"V"))
                     channel_index = 1;
-                else if (!strcmp(buf, "B"))
+                else if (!strcmp(b, "B")||!strcmp(b, "Z")||!strcmp(b,"W"))
                     channel_index = 2;
-                else if (!strcmp(buf, "A"))
+                else if (!strcmp(b, "A"))
                     channel_index = 3;
                 else
                     av_log(avctx, AV_LOG_WARNING, "Unsupported channel %.256s\n", buf);
@@ -1275,4 +1305,5 @@ AVCodec ff_exr_decoder = {
     .close              = decode_end,
     .decode             = decode_frame,
     .capabilities       = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS | CODEC_CAP_SLICE_THREADS,
+    .priv_class         = &exr_class,
 };