avcodec/exr: add support data windows larger or outside display window

pull/352/head
Mark Reid 4 years ago committed by Paul B Mahol
parent 6a5b38ef44
commit 1c094563fe
  1. 110
      libavcodec/exr.c
  2. 31
      tests/fate/image.mak
  3. 6
      tests/ref/fate/exr-rgb-scanline-float-zip-dw-large
  4. 6
      tests/ref/fate/exr-rgb-scanline-half-piz-dw-large
  5. 6
      tests/ref/fate/exr-rgb-scanline-half-zip-dw-large
  6. 6
      tests/ref/fate/exr-rgb-scanline-half-zip-dw-outside
  7. 6
      tests/ref/fate/exr-rgb-scanline-uint32-piz-dw-large
  8. 6
      tests/ref/fate/exr-rgb-tile-half-piz-dw-large
  9. 6
      tests/ref/fate/exr-rgb-tile-half-zip
  10. 6
      tests/ref/fate/exr-rgb-tile-half-zip-dw-outside
  11. 6
      tests/ref/fate/exr-rgb-tile-uint32-piz-dw-large
  12. 6
      tests/ref/fate/exr-ya-scanline-zip-half-12x8

@ -134,8 +134,8 @@ typedef struct EXRContext {
const AVPixFmtDescriptor *desc; const AVPixFmtDescriptor *desc;
int w, h; int w, h;
uint32_t xmax, xmin; int32_t xmax, xmin;
uint32_t ymax, ymin; int32_t ymax, ymin;
uint32_t xdelta, ydelta; uint32_t xdelta, ydelta;
int scan_lines_per_block; int scan_lines_per_block;
@ -995,12 +995,13 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
uint64_t line_offset, uncompressed_size; uint64_t line_offset, uncompressed_size;
uint8_t *ptr; uint8_t *ptr;
uint32_t data_size; uint32_t data_size;
uint64_t line, col = 0; int line, col = 0;
uint64_t tile_x, tile_y, tile_level_x, tile_level_y; uint64_t tile_x, tile_y, tile_level_x, tile_level_y;
const uint8_t *src; const uint8_t *src;
int step = s->desc->flags & AV_PIX_FMT_FLAG_FLOAT ? 4 : 2 * s->desc->nb_components; int step = s->desc->flags & AV_PIX_FMT_FLAG_FLOAT ? 4 : 2 * s->desc->nb_components;
int axmax = (avctx->width - (s->xmax + 1)) * step; /* nb pixel to add at the right of the datawindow */ int bxmin, axmax, window_xoffset = 0;
int bxmin = s->xmin * step; /* nb pixel to add at the left of the datawindow */ int window_xmin, window_xmax, window_ymin, window_ymax;
int data_xoffset, data_yoffset, data_window_offset, xsize, ysize;
int i, x, buf_size = s->buf_size; int i, x, buf_size = s->buf_size;
int c, rgb_channel_count; int c, rgb_channel_count;
float one_gamma = 1.0f / s->gamma; float one_gamma = 1.0f / s->gamma;
@ -1029,28 +1030,16 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
return AVERROR_PATCHWELCOME; return AVERROR_PATCHWELCOME;
} }
if (s->xmin || s->ymin) { line = s->ymin + s->tile_attr.ySize * tile_y;
avpriv_report_missing_feature(s->avctx, "Tiles with xmin/ymin");
return AVERROR_PATCHWELCOME;
}
line = s->tile_attr.ySize * tile_y;
col = s->tile_attr.xSize * tile_x; col = s->tile_attr.xSize * tile_x;
if (line < s->ymin || line > s->ymax || if (line < s->ymin || line > s->ymax ||
col < s->xmin || col > s->xmax) s->xmin + col < s->xmin || s->xmin + col > s->xmax)
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
td->ysize = FFMIN(s->tile_attr.ySize, s->ydelta - tile_y * s->tile_attr.ySize); td->ysize = FFMIN(s->tile_attr.ySize, s->ydelta - tile_y * s->tile_attr.ySize);
td->xsize = FFMIN(s->tile_attr.xSize, s->xdelta - tile_x * s->tile_attr.xSize); td->xsize = FFMIN(s->tile_attr.xSize, s->xdelta - tile_x * s->tile_attr.xSize);
if (col) { /* not the first tile of the line */
bxmin = 0; /* doesn't add pixel at the left of the datawindow */
}
if ((col + td->xsize) != s->xdelta)/* not the last tile of the line */
axmax = 0; /* doesn't add pixel at the right of the datawindow */
td->channel_line_size = td->xsize * s->current_channel_offset;/* uncompress size of one line */ td->channel_line_size = td->xsize * s->current_channel_offset;/* uncompress size of one line */
uncompressed_size = td->channel_line_size * (uint64_t)td->ysize;/* uncompress size of the block */ uncompressed_size = td->channel_line_size * (uint64_t)td->ysize;/* uncompress size of the block */
} else { } else {
@ -1081,6 +1070,33 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
} }
} }
window_xmin = FFMIN(avctx->width, FFMAX(0, s->xmin + col));
window_xmax = FFMIN(avctx->width, FFMAX(0, s->xmin + col + td->xsize));
window_ymin = FFMIN(avctx->height, FFMAX(0, line ));
window_ymax = FFMIN(avctx->height, FFMAX(0, line + td->ysize));
xsize = window_xmax - window_xmin;
ysize = window_ymax - window_ymin;
/* tile or scanline not visible skip decoding */
if (xsize <= 0 || ysize <= 0)
return 0;
/* is the first tile or is a scanline */
if(col == 0) {
window_xmin = 0;
/* pixels to add at the left of the display window */
window_xoffset = FFMAX(0, s->xmin);
/* bytes to add at the left of the display window */
bxmin = window_xoffset * step;
}
/* is the last tile or is a scanline */
if(col + td->xsize == s->xdelta) {
window_xmax = avctx->width;
/* bytes to add at the right of the display window */
axmax = FFMAX(0, (avctx->width - (s->xmax + 1))) * step;
}
if (data_size < uncompressed_size || s->is_tile) { /* td->tmp is use for tile reorganization */ 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); av_fast_padded_malloc(&td->tmp, &td->tmp_size, uncompressed_size);
if (!td->tmp) if (!td->tmp)
@ -1121,17 +1137,22 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
src = td->uncompressed_data; src = td->uncompressed_data;
} }
/* offsets to crop data outside display window */
data_xoffset = FFABS(FFMIN(0, s->xmin + col)) * (s->pixel_type == EXR_HALF ? 2 : 4);
data_yoffset = FFABS(FFMIN(0, line));
data_window_offset = (data_yoffset * td->channel_line_size) + data_xoffset;
if (!s->is_luma) { if (!s->is_luma) {
channel_buffer[0] = src + td->xsize * s->channel_offsets[0]; channel_buffer[0] = src + (td->xsize * s->channel_offsets[0]) + data_window_offset;
channel_buffer[1] = src + td->xsize * s->channel_offsets[1]; channel_buffer[1] = src + (td->xsize * s->channel_offsets[1]) + data_window_offset;
channel_buffer[2] = src + td->xsize * s->channel_offsets[2]; channel_buffer[2] = src + (td->xsize * s->channel_offsets[2]) + data_window_offset;
rgb_channel_count = 3; rgb_channel_count = 3;
} else { /* put y data in the first channel_buffer */ } else { /* put y data in the first channel_buffer */
channel_buffer[0] = src + td->xsize * s->channel_offsets[1]; channel_buffer[0] = src + (td->xsize * s->channel_offsets[1]) + data_window_offset;
rgb_channel_count = 1; rgb_channel_count = 1;
} }
if (s->channel_offsets[3] >= 0) if (s->channel_offsets[3] >= 0)
channel_buffer[3] = src + td->xsize * s->channel_offsets[3]; channel_buffer[3] = src + (td->xsize * s->channel_offsets[3]) + data_window_offset;
if (s->desc->flags & AV_PIX_FMT_FLAG_FLOAT) { if (s->desc->flags & AV_PIX_FMT_FLAG_FLOAT) {
@ -1144,9 +1165,9 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
for (c = 0; c < channel_count; c++) { for (c = 0; c < channel_count; c++) {
int plane = s->desc->comp[c].plane; int plane = s->desc->comp[c].plane;
ptr = p->data[plane] + line * p->linesize[plane] + (col * 4); ptr = p->data[plane] + window_ymin * p->linesize[plane] + (window_xmin * 4);
for (i = 0; i < td->ysize; i++, ptr += p->linesize[plane]) { for (i = 0; i < ysize; i++, ptr += p->linesize[plane]) {
const uint8_t *src; const uint8_t *src;
union av_intfloat32 *ptr_x; union av_intfloat32 *ptr_x;
@ -1155,19 +1176,19 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
// Zero out the start if xmin is not 0 // Zero out the start if xmin is not 0
memset(ptr_x, 0, bxmin); memset(ptr_x, 0, bxmin);
ptr_x += s->xmin; ptr_x += window_xoffset;
if (s->pixel_type == EXR_FLOAT) { if (s->pixel_type == EXR_FLOAT) {
// 32-bit // 32-bit
union av_intfloat32 t; union av_intfloat32 t;
if (trc_func && c < 3) { if (trc_func && c < 3) {
for (x = 0; x < td->xsize; x++) { for (x = 0; x < xsize; x++) {
t.i = bytestream_get_le32(&src); t.i = bytestream_get_le32(&src);
t.f = trc_func(t.f); t.f = trc_func(t.f);
*ptr_x++ = t; *ptr_x++ = t;
} }
} else { } else {
for (x = 0; x < td->xsize; x++) { for (x = 0; x < xsize; x++) {
t.i = bytestream_get_le32(&src); t.i = bytestream_get_le32(&src);
if (t.f > 0.0f && c < 3) /* avoid negative values */ if (t.f > 0.0f && c < 3) /* avoid negative values */
t.f = powf(t.f, one_gamma); t.f = powf(t.f, one_gamma);
@ -1177,11 +1198,11 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
} else if (s->pixel_type == EXR_HALF) { } else if (s->pixel_type == EXR_HALF) {
// 16-bit // 16-bit
if (c < 3) { if (c < 3) {
for (x = 0; x < td->xsize; x++) { for (x = 0; x < xsize; x++) {
*ptr_x++ = s->gamma_table[bytestream_get_le16(&src)]; *ptr_x++ = s->gamma_table[bytestream_get_le16(&src)];
} }
} else { } else {
for (x = 0; x < td->xsize; x++) { for (x = 0; x < xsize; x++) {
*ptr_x++ = exr_half2float(bytestream_get_le16(&src));; *ptr_x++ = exr_half2float(bytestream_get_le16(&src));;
} }
} }
@ -1195,9 +1216,9 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
} else { } else {
av_assert1(s->pixel_type == EXR_UINT); av_assert1(s->pixel_type == EXR_UINT);
ptr = p->data[0] + line * p->linesize[0] + (col * s->desc->nb_components * 2); ptr = p->data[0] + window_ymin * p->linesize[0] + (window_xmin * s->desc->nb_components * 2);
for (i = 0; i < td->ysize; i++, ptr += p->linesize[0]) { for (i = 0; i < ysize; i++, ptr += p->linesize[0]) {
const uint8_t * a; const uint8_t * a;
const uint8_t *rgb[3]; const uint8_t *rgb[3];
@ -1214,9 +1235,9 @@ static int decode_block(AVCodecContext *avctx, void *tdata,
// Zero out the start if xmin is not 0 // Zero out the start if xmin is not 0
memset(ptr_x, 0, bxmin); memset(ptr_x, 0, bxmin);
ptr_x += s->xmin * s->desc->nb_components; ptr_x += window_xoffset * s->desc->nb_components;
for (x = 0; x < td->xsize; x++) { for (x = 0; x < xsize; x++) {
for (c = 0; c < rgb_channel_count; c++) { for (c = 0; c < rgb_channel_count; c++) {
*ptr_x++ = bytestream_get_le32(&rgb[c]) >> 16; *ptr_x++ = bytestream_get_le32(&rgb[c]) >> 16;
} }
@ -1654,7 +1675,7 @@ static int decode_frame(AVCodecContext *avctx, void *data,
AVFrame *picture = data; AVFrame *picture = data;
uint8_t *ptr; uint8_t *ptr;
int i, y, ret; int i, y, ret, ymax;
int planes; int planes;
int out_line_size; int out_line_size;
int nb_blocks; /* nb scanline or nb tile */ int nb_blocks; /* nb scanline or nb tile */
@ -1728,13 +1749,9 @@ static int decode_frame(AVCodecContext *avctx, void *data,
return AVERROR_PATCHWELCOME; return AVERROR_PATCHWELCOME;
} }
/* Verify the xmin, xmax, ymin, ymax and xdelta before setting /* Verify the xmin, xmax, ymin and ymax before setting the actual image size.
* the actual image size. */ * It's possible for the data window can larger or outside the display window */
if (s->xmin > s->xmax || if (s->xmin > s->xmax || s->ymin > s->ymax) {
s->ymin > s->ymax ||
s->xdelta != s->xmax - s->xmin + 1 ||
s->xmax >= s->w ||
s->ymax >= s->h) {
av_log(avctx, AV_LOG_ERROR, "Wrong or missing size information.\n"); av_log(avctx, AV_LOG_ERROR, "Wrong or missing size information.\n");
return AVERROR_INVALIDDATA; return AVERROR_INVALIDDATA;
} }
@ -1804,10 +1821,11 @@ static int decode_frame(AVCodecContext *avctx, void *data,
avctx->execute2(avctx, decode_block, s->thread_data, NULL, nb_blocks); avctx->execute2(avctx, decode_block, s->thread_data, NULL, nb_blocks);
ymax = FFMAX(0, s->ymax + 1);
// Zero out the end if ymax+1 is not h // Zero out the end if ymax+1 is not h
for (i = 0; i < planes; i++) { for (i = 0; i < planes; i++) {
ptr = picture->data[i] + ((s->ymax+1) * picture->linesize[i]); ptr = picture->data[i] + (ymax * picture->linesize[i]);
for (y = s->ymax + 1; y < avctx->height; y++) { for (y = ymax; y < avctx->height; y++) {
memset(ptr, 0, out_line_size); memset(ptr, 0, out_line_size);
ptr += picture->linesize[i]; ptr += picture->linesize[i];
} }

@ -287,6 +287,37 @@ fate-exr-rgb-scanline-half-piz-dw-t08: CMD = framecrc -i $(TARGET_SAMPLES)/exr/r
FATE_EXR += fate-exr-rgba-zip16-16x32-flag4 FATE_EXR += fate-exr-rgba-zip16-16x32-flag4
fate-exr-rgba-zip16-16x32-flag4: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_zip16_16x32_flag4.exr -pix_fmt gbrapf32le fate-exr-rgba-zip16-16x32-flag4: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_zip16_16x32_flag4.exr -pix_fmt gbrapf32le
FATE_EXR += fate-exr-ya-scanline-zip-half-12x8
fate-exr-ya-scanline-zip-half-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/ya_scanline_zip_half_12x8.exr -pix_fmt gbrapf32le
FATE_EXR += fate-exr-rgb-tile-half-zip
fate-exr-rgb-tile-half-zip: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_zip.exr -pix_fmt gbrpf32le
FATE_EXR += fate-exr-rgb-scanline-float-zip-dw-large
fate-exr-rgb-scanline-float-zip-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_float_zip_dw_large.exr -pix_fmt gbrpf32le
FATE_EXR += fate-exr-rgb-scanline-half-piz-dw-large
fate-exr-rgb-scanline-half-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_dw_large.exr -pix_fmt gbrpf32le
FATE_EXR += fate-exr-rgb-scanline-half-zip-dw-large
fate-exr-rgb-scanline-half-zip-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_zip_dw_large.exr -pix_fmt gbrpf32le
FATE_EXR += fate-exr-rgb-scanline-uint32-piz-dw-large
fate-exr-rgb-scanline-uint32-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_uint32_piz_dw_large.exr -pix_fmt rgb48le
FATE_EXR += fate-exr-rgb-tile-half-piz-dw-large
fate-exr-rgb-tile-half-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_piz_dw_large.exr -pix_fmt gbrpf32le
FATE_EXR += fate-exr-rgb-tile-uint32-piz-dw-large
fate-exr-rgb-tile-uint32-piz-dw-large: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_uint32_piz_dw_large.exr -pix_fmt rgb48le
FATE_EXR += fate-exr-rgb-scanline-half-zip-dw-outside
fate-exr-rgb-scanline-half-zip-dw-outside: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_zip_dw_outside.exr -pix_fmt gbrpf32le
FATE_EXR += fate-exr-rgb-tile-half-zip-dw-outside
fate-exr-rgb-tile-half-zip-dw-outside: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_tile_half_zip_dw_outside.exr -pix_fmt gbrpf32le
FATE_EXR-$(call DEMDEC, IMAGE2, EXR) += $(FATE_EXR) FATE_EXR-$(call DEMDEC, IMAGE2, EXR) += $(FATE_EXR)
FATE_IMAGE += $(FATE_EXR-yes) FATE_IMAGE += $(FATE_EXR-yes)

@ -0,0 +1,6 @@
#tb 0: 1/25
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 50x50
#sar 0: 1/1
0, 0, 0, 1, 30000, 0x947ce379

@ -0,0 +1,6 @@
#tb 0: 1/25
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 50x50
#sar 0: 1/1
0, 0, 0, 1, 30000, 0xb329ee9c

@ -0,0 +1,6 @@
#tb 0: 1/25
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 50x50
#sar 0: 1/1
0, 0, 0, 1, 30000, 0xb329ee9c

@ -0,0 +1,6 @@
#tb 0: 1/25
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 501x401
#sar 0: 1/1
0, 0, 0, 1, 2410812, 0x00000000

@ -0,0 +1,6 @@
#tb 0: 1/25
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 50x50
#sar 0: 1/1
0, 0, 0, 1, 15000, 0xeeacd171

@ -0,0 +1,6 @@
#tb 0: 1/25
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 50x50
#sar 0: 1/1
0, 0, 0, 1, 30000, 0xb329ee9c

@ -0,0 +1,6 @@
#tb 0: 1/25
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 501x401
#sar 0: 1/1
0, 0, 0, 1, 2410812, 0x2dd1b00b

@ -0,0 +1,6 @@
#tb 0: 1/25
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 501x401
#sar 0: 1/1
0, 0, 0, 1, 2410812, 0x00000000

@ -0,0 +1,6 @@
#tb 0: 1/25
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 50x50
#sar 0: 1/1
0, 0, 0, 1, 15000, 0xeeacd171

@ -0,0 +1,6 @@
#tb 0: 1/25
#media_type 0: video
#codec_id 0: rawvideo
#dimensions 0: 12x8
#sar 0: 1/1
0, 0, 0, 1, 1536, 0x9473ee5c
Loading…
Cancel
Save