[FFmpeg-devel] EXR patch to read layers

Gonzalo Garramuno ggarra13 at gmail.com
Sun Feb 16 00:50:24 CET 2014


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 Normals -i myexr.%04d.exr test.mov


-------------- next part --------------
diff --git a/libavcodec/exr.c b/libavcodec/exr.c
index f231b70..b96f17f 100644
--- a/libavcodec/exr.c
+++ b/libavcodec/exr.c
@@ -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,16 +1008,28 @@ static int decode_frame(AVCodecContext *avctx,
                 int channel_index = -1;
                 int xsub, ysub;
 
-                if (!strcmp(buf, "R"))
-                    channel_index = 0;
-                else if (!strcmp(buf, "G"))
-                    channel_index = 1;
-                else if (!strcmp(buf, "B"))
-                    channel_index = 2;
-                else if (!strcmp(buf, "A"))
-                    channel_index = 3;
+                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(b, "G")||!strcmp(b, "Y")||!strcmp(b,"V"))
+                   channel_index = 1;
+                else if (!strcmp(b, "B")||!strcmp(b, "Z")||!strcmp(b,"W"))
+                   channel_index = 2;
+                else if (!strcmp(b, "A"))
+                   channel_index = 3;
                 else
-                    av_log(avctx, AV_LOG_WARNING, "Unsupported channel %.256s\n", buf);
+                   av_log(avctx, AV_LOG_WARNING, "Unsupported channel %.256s\n", buf);
 
                 while (bytestream_get_byte(&buf) && buf < channel_list_end)
                     continue; /* skip */
@@ -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,
 };


More information about the ffmpeg-devel mailing list