|
|
|
@ -3,6 +3,8 @@ |
|
|
|
|
* Copyright (c) 2006 Industrial Light & Magic, a division of Lucas Digital Ltd. LLC |
|
|
|
|
* Copyright (c) 2009 Jimmy Christensen |
|
|
|
|
* |
|
|
|
|
* B44/B44A, Tile added by Jokyo Images support by CNC - French National Center for Cinema |
|
|
|
|
* |
|
|
|
|
* This file is part of FFmpeg. |
|
|
|
|
* |
|
|
|
|
* FFmpeg is free software; you can redistribute it and/or |
|
|
|
@ -67,11 +69,29 @@ enum ExrPixelType { |
|
|
|
|
EXR_UNKNOWN, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
enum ExrTileLevelMode { |
|
|
|
|
EXR_TILE_LEVEL_ONE, |
|
|
|
|
EXR_TILE_LEVEL_MIPMAP, |
|
|
|
|
EXR_TILE_LEVEL_RIPMAP, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
enum ExrTileLevelRound { |
|
|
|
|
EXR_TILE_ROUND_UP, |
|
|
|
|
EXR_TILE_ROUND_DOWN, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
typedef struct EXRChannel { |
|
|
|
|
int xsub, ysub; |
|
|
|
|
enum ExrPixelType pixel_type; |
|
|
|
|
} EXRChannel; |
|
|
|
|
|
|
|
|
|
typedef struct EXRTileAttribute { |
|
|
|
|
int32_t xSize; |
|
|
|
|
int32_t ySize; |
|
|
|
|
enum ExrTileLevelMode level_mode; |
|
|
|
|
enum ExrTileLevelRound level_round; |
|
|
|
|
} EXRTileAttribute; |
|
|
|
|
|
|
|
|
|
typedef struct EXRThreadData { |
|
|
|
|
uint8_t *uncompressed_data; |
|
|
|
|
int uncompressed_size; |
|
|
|
@ -97,17 +117,21 @@ typedef struct EXRContext { |
|
|
|
|
uint32_t xmax, xmin; |
|
|
|
|
uint32_t ymax, ymin; |
|
|
|
|
uint32_t xdelta, ydelta; |
|
|
|
|
int ysize; |
|
|
|
|
int ysize, xsize; |
|
|
|
|
|
|
|
|
|
uint64_t scan_line_size; |
|
|
|
|
int scan_lines_per_block; |
|
|
|
|
|
|
|
|
|
EXRTileAttribute tile_attr; /* header data attribute of tile */ |
|
|
|
|
int is_tile; /* 0 if scanline, 1 if tile */ |
|
|
|
|
|
|
|
|
|
GetByteContext gb; |
|
|
|
|
const uint8_t *buf; |
|
|
|
|
int buf_size; |
|
|
|
|
|
|
|
|
|
EXRChannel *channels; |
|
|
|
|
int nb_channels; |
|
|
|
|
int current_channel_offset; |
|
|
|
|
|
|
|
|
|
EXRThreadData *thread_data; |
|
|
|
|
|
|
|
|
@ -792,7 +816,7 @@ static int pxr24_uncompress(EXRContext *s, const uint8_t *src, |
|
|
|
|
|
|
|
|
|
if (uncompress(td->tmp, &dest_len, src, compressed_size) != Z_OK) { |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
} else if (dest_len != expected_len){ |
|
|
|
|
} else if (dest_len != expected_len) { |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -889,7 +913,7 @@ static void unpack_3(const uint8_t b[3], uint16_t s[16]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int b44_uncompress(EXRContext *s, const uint8_t *src, int compressed_size, |
|
|
|
|
int uncompressed_size, EXRThreadData *td){ |
|
|
|
|
int uncompressed_size, EXRThreadData *td) { |
|
|
|
|
const int8_t *sr = src; |
|
|
|
|
int stayToUncompress = compressed_size; |
|
|
|
|
int nbB44BlockW, nbB44BlockH; |
|
|
|
@ -909,7 +933,7 @@ static int b44_uncompress(EXRContext *s, const uint8_t *src, int compressed_size |
|
|
|
|
for (c = 0; c < s->nb_channels; c++) { |
|
|
|
|
for (iY = 0; iY < nbB44BlockH; iY++) { |
|
|
|
|
for (iX = 0; iX < nbB44BlockW; iX++) {/* For each B44 block */ |
|
|
|
|
if (stayToUncompress < 3){ |
|
|
|
|
if (stayToUncompress < 3) { |
|
|
|
|
av_log(s, AV_LOG_ERROR, "Not enough data for B44A block: %d", stayToUncompress); |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
} |
|
|
|
@ -959,43 +983,87 @@ static int decode_block(AVCodecContext *avctx, void *tdata, |
|
|
|
|
uint32_t xdelta = s->xdelta; |
|
|
|
|
uint16_t *ptr_x; |
|
|
|
|
uint8_t *ptr; |
|
|
|
|
uint32_t data_size, line; |
|
|
|
|
uint32_t data_size, line, col = 0; |
|
|
|
|
uint32_t tileX, tileY, tileLevelX, tileLevelY; |
|
|
|
|
int channelLineSize, indexSrc, tX, tY, tCh; |
|
|
|
|
const uint8_t *src; |
|
|
|
|
int axmax = (avctx->width - (s->xmax + 1)) * 2 * s->desc->nb_components; |
|
|
|
|
int bxmin = s->xmin * 2 * s->desc->nb_components; |
|
|
|
|
int axmax = (avctx->width - (s->xmax + 1)) * 2 * s->desc->nb_components; /* nb pixel to add at the right of the datawindow */ |
|
|
|
|
int bxmin = s->xmin * 2 * s->desc->nb_components; /* nb pixel to add at the left of the datawindow */ |
|
|
|
|
int i, x, buf_size = s->buf_size; |
|
|
|
|
float one_gamma = 1.0f / s->gamma; |
|
|
|
|
avpriv_trc_function trc_func = avpriv_get_trc_function_from_trc(s->apply_trc_type); |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
line_offset = AV_RL64(s->gb.buffer + jobnr * 8); |
|
|
|
|
// Check if the buffer has the required bytes needed from the offset
|
|
|
|
|
if (line_offset > buf_size - 8) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
|
src = buf + line_offset + 8; |
|
|
|
|
line = AV_RL32(src - 8); |
|
|
|
|
if (line < s->ymin || line > s->ymax) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
if (s->is_tile) { |
|
|
|
|
if (line_offset > buf_size - 20) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
|
data_size = AV_RL32(src - 4); |
|
|
|
|
if (data_size <= 0 || data_size > buf_size) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
src = buf + line_offset + 20; |
|
|
|
|
|
|
|
|
|
s->ysize = FFMIN(s->scan_lines_per_block, s->ymax - line + 1); |
|
|
|
|
uncompressed_size = s->scan_line_size * s->ysize; |
|
|
|
|
if ((s->compression == EXR_RAW && (data_size != uncompressed_size || |
|
|
|
|
line_offset > buf_size - uncompressed_size)) || |
|
|
|
|
(s->compression != EXR_RAW && (data_size > uncompressed_size || |
|
|
|
|
line_offset > buf_size - data_size))) { |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
tileX = AV_RL32(src - 20); |
|
|
|
|
tileY = AV_RL32(src - 16); |
|
|
|
|
tileLevelX = AV_RL32(src - 12); |
|
|
|
|
tileLevelY = AV_RL32(src - 8); |
|
|
|
|
|
|
|
|
|
data_size = AV_RL32(src - 4); |
|
|
|
|
if (data_size <= 0 || data_size > buf_size) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
|
if (tileLevelX || tileLevelY) { /* tile of low resolution (Mipmap, rimmap) */ |
|
|
|
|
av_log(s->avctx, AV_LOG_ERROR, "Wrong Tile level %i / %i.\n", tileLevelX, tileLevelY); |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
line = s->tile_attr.ySize * tileY; |
|
|
|
|
col = s->tile_attr.xSize * tileX; |
|
|
|
|
|
|
|
|
|
s->ysize = FFMIN(s->tile_attr.ySize, s->ydelta - tileY * s->tile_attr.ySize); |
|
|
|
|
s->xsize = FFMIN(s->tile_attr.xSize, s->xdelta - tileX * s->tile_attr.xSize); |
|
|
|
|
uncompressed_size = s->current_channel_offset * s->ysize * s->xsize; |
|
|
|
|
|
|
|
|
|
if (col) { /* not the first tile of the line */ |
|
|
|
|
bxmin = 0; axmax = 0; /* doesn't add pixel at the left of the datawindow */ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ((col + s->xsize) != s->xdelta)/* not the last tile of the line */ |
|
|
|
|
axmax = 0; /* doesn't add pixel at the right of the datawindow */ |
|
|
|
|
} else { |
|
|
|
|
if (line_offset > buf_size - 8) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
|
src = buf + line_offset + 8; |
|
|
|
|
line = AV_RL32(src - 8); |
|
|
|
|
if (line < s->ymin || line > s->ymax) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
|
data_size = AV_RL32(src - 4); |
|
|
|
|
if (data_size <= 0 || data_size > buf_size) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
|
s->ysize = FFMIN(s->scan_lines_per_block, s->ymax - line + 1); /* s->ydelta - line ?? */ |
|
|
|
|
s->xsize = s->xdelta; |
|
|
|
|
uncompressed_size = s->scan_line_size * s->ysize; |
|
|
|
|
if ((s->compression == EXR_RAW && (data_size != uncompressed_size || |
|
|
|
|
line_offset > buf_size - uncompressed_size)) || |
|
|
|
|
(s->compression != EXR_RAW && (data_size > uncompressed_size || |
|
|
|
|
line_offset > buf_size - data_size))) { |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (data_size < uncompressed_size || s->is_tile) { /* td->tmp is use for tile reorganization */ |
|
|
|
|
av_fast_padded_malloc(&td->tmp, &td->tmp_size, uncompressed_size); |
|
|
|
|
if (!td->tmp) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (data_size < uncompressed_size) { |
|
|
|
|
av_fast_padded_malloc(&td->uncompressed_data, |
|
|
|
|
&td->uncompressed_size, uncompressed_size); |
|
|
|
|
av_fast_padded_malloc(&td->tmp, &td->tmp_size, uncompressed_size); |
|
|
|
|
if (!td->uncompressed_data || !td->tmp) |
|
|
|
|
|
|
|
|
|
if (!td->uncompressed_data) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
|
|
|
|
|
ret = AVERROR_INVALIDDATA; |
|
|
|
@ -1025,16 +1093,40 @@ static int decode_block(AVCodecContext *avctx, void *tdata, |
|
|
|
|
src = td->uncompressed_data; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
channel_buffer[0] = src + xdelta * s->channel_offsets[0]; |
|
|
|
|
channel_buffer[1] = src + xdelta * s->channel_offsets[1]; |
|
|
|
|
channel_buffer[2] = src + xdelta * s->channel_offsets[2]; |
|
|
|
|
if (s->channel_offsets[3] >= 0) |
|
|
|
|
channel_buffer[3] = src + xdelta * s->channel_offsets[3]; |
|
|
|
|
if (s->is_tile) { |
|
|
|
|
indexSrc = 0; |
|
|
|
|
channelLineSize = s->xsize * 2; |
|
|
|
|
if (s->pixel_type == EXR_FLOAT) |
|
|
|
|
channelLineSize *= 2; |
|
|
|
|
|
|
|
|
|
/* reorganise tile data to have each channel one after the other instead of line by line */ |
|
|
|
|
for (tY = 0; tY < s->ysize; tY ++) { |
|
|
|
|
for (tCh = 0; tCh < s->nb_channels; tCh++) { |
|
|
|
|
for (tX = 0; tX < channelLineSize; tX++) { |
|
|
|
|
td->tmp[tCh * channelLineSize * s->ysize + tY * channelLineSize + tX] = src[indexSrc]; |
|
|
|
|
indexSrc++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
channel_buffer[0] = td->tmp + s->xsize * s->channel_offsets[0] * s->ysize; |
|
|
|
|
channel_buffer[1] = td->tmp + s->xsize * s->channel_offsets[1] * s->ysize; |
|
|
|
|
channel_buffer[2] = td->tmp + s->xsize * s->channel_offsets[2] * s->ysize; |
|
|
|
|
if (s->channel_offsets[3] >= 0) |
|
|
|
|
channel_buffer[3] = td->tmp + s->xsize * s->channel_offsets[3]; |
|
|
|
|
} else { |
|
|
|
|
channel_buffer[0] = src + xdelta * s->channel_offsets[0]; |
|
|
|
|
channel_buffer[1] = src + xdelta * s->channel_offsets[1]; |
|
|
|
|
channel_buffer[2] = src + xdelta * s->channel_offsets[2]; |
|
|
|
|
if (s->channel_offsets[3] >= 0) |
|
|
|
|
channel_buffer[3] = src + xdelta * s->channel_offsets[3]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ptr = p->data[0] + line * p->linesize[0] + (col * s->desc->nb_components * 2); |
|
|
|
|
|
|
|
|
|
ptr = p->data[0] + line * p->linesize[0]; |
|
|
|
|
for (i = 0; |
|
|
|
|
i < s->scan_lines_per_block && line + i <= s->ymax; |
|
|
|
|
i++, ptr += p->linesize[0]) { |
|
|
|
|
i < s->ysize; i++, ptr += p->linesize[0]) { |
|
|
|
|
|
|
|
|
|
const uint8_t *r, *g, *b, *a; |
|
|
|
|
|
|
|
|
|
r = channel_buffer[0]; |
|
|
|
@ -1048,10 +1140,11 @@ static int decode_block(AVCodecContext *avctx, void *tdata, |
|
|
|
|
// Zero out the start if xmin is not 0
|
|
|
|
|
memset(ptr_x, 0, bxmin); |
|
|
|
|
ptr_x += s->xmin * s->desc->nb_components; |
|
|
|
|
|
|
|
|
|
if (s->pixel_type == EXR_FLOAT) { |
|
|
|
|
// 32-bit
|
|
|
|
|
if (trc_func) { |
|
|
|
|
for (x = 0; x < xdelta; x++) { |
|
|
|
|
for (x = 0; x < s->xsize; x++) { |
|
|
|
|
union av_intfloat32 t; |
|
|
|
|
t.i = bytestream_get_le32(&r); |
|
|
|
|
t.f = trc_func(t.f); |
|
|
|
@ -1068,7 +1161,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, |
|
|
|
|
*ptr_x++ = exr_flt2uint(bytestream_get_le32(&a)); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
for (x = 0; x < xdelta; x++) { |
|
|
|
|
for (x = 0; x < s->xsize; x++) { |
|
|
|
|
union av_intfloat32 t; |
|
|
|
|
t.i = bytestream_get_le32(&r); |
|
|
|
|
if (t.f > 0.0f) /* avoid negative values */ |
|
|
|
@ -1090,7 +1183,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// 16-bit
|
|
|
|
|
for (x = 0; x < xdelta; x++) { |
|
|
|
|
for (x = 0; x < s->xsize; x++) { |
|
|
|
|
*ptr_x++ = s->gamma_table[bytestream_get_le16(&r)]; |
|
|
|
|
*ptr_x++ = s->gamma_table[bytestream_get_le16(&g)]; |
|
|
|
|
*ptr_x++ = s->gamma_table[bytestream_get_le16(&b)]; |
|
|
|
@ -1102,11 +1195,20 @@ static int decode_block(AVCodecContext *avctx, void *tdata, |
|
|
|
|
// Zero out the end if xmax+1 is not w
|
|
|
|
|
memset(ptr_x, 0, axmax); |
|
|
|
|
|
|
|
|
|
channel_buffer[0] += s->scan_line_size; |
|
|
|
|
channel_buffer[1] += s->scan_line_size; |
|
|
|
|
channel_buffer[2] += s->scan_line_size; |
|
|
|
|
if (channel_buffer[3]) |
|
|
|
|
channel_buffer[3] += s->scan_line_size; |
|
|
|
|
if (s->is_tile) { |
|
|
|
|
channel_buffer[0] += channelLineSize; |
|
|
|
|
channel_buffer[1] += channelLineSize; |
|
|
|
|
channel_buffer[2] += channelLineSize; |
|
|
|
|
if (channel_buffer[3]) |
|
|
|
|
channel_buffer[3] += channelLineSize; |
|
|
|
|
} |
|
|
|
|
else{ |
|
|
|
|
channel_buffer[0] += s->scan_line_size; |
|
|
|
|
channel_buffer[1] += s->scan_line_size; |
|
|
|
|
channel_buffer[2] += s->scan_line_size; |
|
|
|
|
if (channel_buffer[3]) |
|
|
|
|
channel_buffer[3] += s->scan_line_size; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
@ -1155,9 +1257,9 @@ static int check_header_variable(EXRContext *s, |
|
|
|
|
|
|
|
|
|
static int decode_header(EXRContext *s) |
|
|
|
|
{ |
|
|
|
|
int current_channel_offset = 0; |
|
|
|
|
int magic_number, version, flags, i, sar = 0; |
|
|
|
|
int magic_number, version, i, flags, sar = 0; |
|
|
|
|
|
|
|
|
|
s->current_channel_offset = 0; |
|
|
|
|
s->xmin = ~0; |
|
|
|
|
s->xmax = ~0; |
|
|
|
|
s->ymin = ~0; |
|
|
|
@ -1173,6 +1275,9 @@ static int decode_header(EXRContext *s) |
|
|
|
|
s->nb_channels = 0; |
|
|
|
|
s->w = 0; |
|
|
|
|
s->h = 0; |
|
|
|
|
s->tile_attr.xSize = -1; |
|
|
|
|
s->tile_attr.ySize = -1; |
|
|
|
|
s->is_tile = 0; |
|
|
|
|
|
|
|
|
|
if (bytestream2_get_bytes_left(&s->gb) < 10) { |
|
|
|
|
av_log(s->avctx, AV_LOG_ERROR, "Header too short to parse.\n"); |
|
|
|
@ -1194,8 +1299,13 @@ static int decode_header(EXRContext *s) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
flags = bytestream2_get_le24(&s->gb); |
|
|
|
|
if (flags & 0x02) { |
|
|
|
|
avpriv_report_missing_feature(s->avctx, "Tile support"); |
|
|
|
|
|
|
|
|
|
if (flags == 0x00) |
|
|
|
|
s->is_tile = 0; |
|
|
|
|
else if (flags & 0x02) |
|
|
|
|
s->is_tile = 1; |
|
|
|
|
else{ |
|
|
|
|
avpriv_report_missing_feature(s->avctx, "flags %d", flags); |
|
|
|
|
return AVERROR_PATCHWELCOME; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1279,7 +1389,7 @@ static int decode_header(EXRContext *s) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
} |
|
|
|
|
s->pixel_type = current_pixel_type; |
|
|
|
|
s->channel_offsets[channel_index] = current_channel_offset; |
|
|
|
|
s->channel_offsets[channel_index] = s->current_channel_offset; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s->channels = av_realloc(s->channels, |
|
|
|
@ -1291,7 +1401,7 @@ static int decode_header(EXRContext *s) |
|
|
|
|
channel->xsub = xsub; |
|
|
|
|
channel->ysub = ysub; |
|
|
|
|
|
|
|
|
|
current_channel_offset += 1 << current_pixel_type; |
|
|
|
|
s->current_channel_offset += 1 << current_pixel_type; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Check if all channels are set with an offset or if the channels
|
|
|
|
@ -1367,6 +1477,32 @@ static int decode_header(EXRContext *s) |
|
|
|
|
av_log(s->avctx, AV_LOG_WARNING, |
|
|
|
|
"Found more than one compression attribute.\n"); |
|
|
|
|
|
|
|
|
|
continue; |
|
|
|
|
} else if ((var_size = check_header_variable(s, "tiles", |
|
|
|
|
"tiledesc", 22)) >= 0) { |
|
|
|
|
if (!s->is_tile) |
|
|
|
|
av_log(s->avctx, AV_LOG_WARNING, |
|
|
|
|
"Found tile attribute and scanline flags. Exr will be interpreted as scanline.\n"); |
|
|
|
|
|
|
|
|
|
s->tile_attr.xSize = bytestream2_get_le32(&s->gb); |
|
|
|
|
s->tile_attr.ySize = bytestream2_get_le32(&s->gb); |
|
|
|
|
|
|
|
|
|
char tileLevel = bytestream2_get_byte(&s->gb); |
|
|
|
|
s->tile_attr.level_mode = tileLevel & 0x0f; |
|
|
|
|
s->tile_attr.level_round = (tileLevel >> 4) & 0x0f; |
|
|
|
|
|
|
|
|
|
if (s->tile_attr.level_mode != EXR_TILE_LEVEL_ONE) { |
|
|
|
|
avpriv_report_missing_feature(s->avctx, "Tile level mode %d", |
|
|
|
|
s->tile_attr.level_mode); |
|
|
|
|
return AVERROR_PATCHWELCOME; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (s->tile_attr.level_round != EXR_TILE_ROUND_UP) { |
|
|
|
|
avpriv_report_missing_feature(s->avctx, "Tile level round %d", |
|
|
|
|
s->tile_attr.level_round); |
|
|
|
|
return AVERROR_PATCHWELCOME; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
continue; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1390,7 +1526,20 @@ static int decode_header(EXRContext *s) |
|
|
|
|
av_log(s->avctx, AV_LOG_ERROR, "Missing compression attribute.\n"); |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
} |
|
|
|
|
s->scan_line_size = s->xdelta * current_channel_offset; |
|
|
|
|
|
|
|
|
|
if (s->is_tile) { |
|
|
|
|
if (s->tile_attr.xSize < 1 || s->tile_attr.ySize < 1) { |
|
|
|
|
av_log(s->avctx, AV_LOG_ERROR, "Invalid tile attribute.\n"); |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (s->compression != EXR_RAW) { |
|
|
|
|
avpriv_report_missing_feature(s->avctx, "Compression in tile %d", s->compression); |
|
|
|
|
return AVERROR_PATCHWELCOME; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s->scan_line_size = s->xdelta * s->current_channel_offset; |
|
|
|
|
|
|
|
|
|
if (bytestream2_get_bytes_left(&s->gb) <= 0) { |
|
|
|
|
av_log(s->avctx, AV_LOG_ERROR, "Incomplete frame.\n"); |
|
|
|
@ -1412,7 +1561,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, |
|
|
|
|
|
|
|
|
|
int y, ret; |
|
|
|
|
int out_line_size; |
|
|
|
|
int scan_line_blocks; |
|
|
|
|
int nb_blocks;/* nb scanline or nb tile */ |
|
|
|
|
|
|
|
|
|
bytestream2_init(&s->gb, avpkt->data, avpkt->size); |
|
|
|
|
|
|
|
|
@ -1476,13 +1625,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, |
|
|
|
|
if (!s->desc) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
out_line_size = avctx->width * 2 * s->desc->nb_components; |
|
|
|
|
scan_line_blocks = (s->ydelta + s->scan_lines_per_block - 1) / |
|
|
|
|
s->scan_lines_per_block; |
|
|
|
|
|
|
|
|
|
if (s->is_tile) { |
|
|
|
|
nb_blocks = ((s->xdelta + s->tile_attr.xSize - 1) / s->tile_attr.xSize) * |
|
|
|
|
((s->ydelta + s->tile_attr.ySize - 1) / s->tile_attr.ySize); |
|
|
|
|
} else { /* scanline */ |
|
|
|
|
nb_blocks = (s->ydelta + s->scan_lines_per_block - 1) / |
|
|
|
|
s->scan_lines_per_block; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) |
|
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
if (bytestream2_get_bytes_left(&s->gb) < scan_line_blocks * 8) |
|
|
|
|
if (bytestream2_get_bytes_left(&s->gb) < nb_blocks * 8) |
|
|
|
|
return AVERROR_INVALIDDATA; |
|
|
|
|
|
|
|
|
|
// save pointer we are going to use in decode_block
|
|
|
|
@ -1497,7 +1652,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
s->picture = picture; |
|
|
|
|
avctx->execute2(avctx, decode_block, s->thread_data, NULL, scan_line_blocks); |
|
|
|
|
|
|
|
|
|
avctx->execute2(avctx, decode_block, s->thread_data, NULL, nb_blocks); |
|
|
|
|
|
|
|
|
|
// Zero out the end if ymax+1 is not h
|
|
|
|
|
for (y = s->ymax + 1; y < avctx->height; y++) { |
|
|
|
|