avcodec/exr: read layers

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>
This commit is contained in:
Gonzalo Garramuno 2014-02-17 14:53:30 -03:00 committed by Michael Niedermayer
parent 7716eda0aa
commit 3d20260157

View 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,
};