2016-04-10 19:23 GMT+02:00 Paul B Mahol <one...@gmail.com>: > On 4/10/16, Martin Vignali <martin.vign...@gmail.com> wrote: > > 2016-04-10 18:12 GMT+02:00 Paul B Mahol <one...@gmail.com>: > > > >> On 4/10/16, Martin Vignali <martin.vign...@gmail.com> wrote: > >> > 2016-04-09 6:54 GMT+02:00 Paul B Mahol <one...@gmail.com>: > >> > > >> >> On 4/9/16, Martin Vignali <martin.vign...@gmail.com> wrote: > >> >> > 2016-04-08 22:11 GMT+02:00 Paul B Mahol <one...@gmail.com>: > >> >> > > >> >> >> On 4/7/16, Martin Vignali <martin.vign...@gmail.com> wrote: > >> >> >> > Hello, > >> >> >> > > >> >> >> > in attach, a patch with some modifications in size/data window > >> >> >> management, > >> >> >> > in order to manage > >> >> >> > negative datawindow/display window, and datawindow who can > exceed > >> >> >> > display > >> >> >> > window > >> >> >> > > >> >> >> > Size of the picture is now set from min and max value of the > >> display > >> >> >> window > >> >> >> > (before the patch, xmin, ymin of the display window are ignored > >> (and > >> >> >> assume > >> >> >> > to be 0)) > >> >> >> > > >> >> >> > With the previous patch (fix channel detection), official > samples > >> >> >> > ./scanline/Blobbies.exr > >> >> >> > can now be correctly decode. > >> >> >> > > >> >> >> > > >> >> >> > DataWindow bigger than display window is a feature of the > >> >> >> > openExr. > >> >> >> > It can be use in some softwares, (for example to improve blur > >> >> >> > quality) > >> >> >> > Following the official documentation, for display, we need to > use > >> the > >> >> >> > display window only. > >> >> >> > > >> >> >> > > >> >> >> > In this patch, xmin, xmax, ymin, ymax, are now int32_t instead > of > >> >> >> uint32_t, > >> >> >> > because these values can be negative. (See officiel sample > >> >> >> ./Displaywindow > >> >> >> > > >> >> >> > >> >> > >> > http://download.savannah.nongnu.org/releases/openexr/openexr-images-1.7.0.tar.gz > >> >> >> > ) > >> >> >> > > >> >> >> > Comments welcome > >> >> >> > >> >> >> Crashes with: > >> >> >> > >> >> >> openexr-images-1.7.0/DisplayWindow/t03.exr > >> >> >> > >> >> >> Strange, this sample didn't crash for me (Clang, OS 10.9). Decode > >> it's > >> >> > still not good after the patch but it's piz compression. > >> >> > Can you tell me, what configure line, you use ? > >> >> > >> >> > >> >> I still can't reproduce the crash for this sample. > >> > Is it the only sample who crash in openexr-images-1.7.0/DisplayWindow > >> > for > >> > you ? > >> > >> No, also t05.exr. > >> > >> > > Can you test with the new version of the patch in attach ? > > This one doesn't crash. > > > Thanks for testing.
I remove the log line, in the patch in attach. I also add a test for wrong display window in decode_header func. Martin Jokyo Images
From 4bda39071e6cb8a30aad236524337318637e3192 Mon Sep 17 00:00:00 2001 From: Martin Vignali <martin.vign...@gmail.com> Date: Sun, 10 Apr 2016 19:46:14 +0200 Subject: [PATCH] libavcodec/exr : add support for datawindow who exceed display window --- libavcodec/exr.c | 185 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 122 insertions(+), 63 deletions(-) diff --git a/libavcodec/exr.c b/libavcodec/exr.c index 2763126..4a51e2e 100644 --- a/libavcodec/exr.c +++ b/libavcodec/exr.c @@ -112,12 +112,15 @@ typedef struct EXRContext { enum ExrCompr compression; enum ExrPixelType pixel_type; + int pixel_size; int channel_offsets[4]; // 0 = red, 1 = green, 2 = blue and 3 = alpha const AVPixFmtDescriptor *desc; int w, h; - uint32_t xmax, xmin; - uint32_t ymax, ymin; + int xmax, xmin; + int ymax, ymin; + int xmax_display, xmin_display; + int ymax_display, ymin_display; uint32_t xdelta, ydelta; int ysize, xsize; @@ -985,17 +988,28 @@ 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, col = 0; + unsigned int data_size; + int line, target_line, col = 0; + int xmin_block, xmax_block, ymin_block, ymax_block;/* coord block */ + int xmin_used = 0, xmax_used = 0, ymin_used, ymax_used;/* used coord of the data window in the final picture */ + int xmin_unused = 0, xmax_unused = 0, line_to_skip = 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; /* 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 axmax = 0, bxmin = 0; 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; + /* calc nb pixels to add at the left of the data window */ + if (s->xmin_display < s->xmin) + bxmin = (s->xmin - s->xmin_display) * 2 * s->desc->nb_components; + + /* calc nb pixel to add at the right of the data window */ + if (s->xmax_display > s->xmax) + axmax = (s->xmax_display - s->xmax) * 2 * s->desc->nb_components; + line_offset = AV_RL64(s->gb.buffer + jobnr * 8); if (s->is_tile) { @@ -1023,10 +1037,15 @@ static int decode_block(AVCodecContext *avctx, void *tdata, 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); + + xmin_block = s->xmin + col; + ymin_block = s->ymin + line; + target_line = ymin_block; + 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 */ + bxmin = 0; /* doesn't add pixel at the left of the datawindow */ } if ((col + s->xsize) != s->xdelta)/* not the last tile of the line */ @@ -1035,17 +1054,24 @@ static int decode_block(AVCodecContext *avctx, void *tdata, if (line_offset > buf_size - 8) return AVERROR_INVALIDDATA; + channelLineSize = s->scan_line_size; src = buf + line_offset + 8; - line = AV_RL32(src - 8); + line = (int)AV_RL32(src - 8); if (line < s->ymin || line > s->ymax) return AVERROR_INVALIDDATA; + target_line = line; + 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->ysize = FFMIN(s->scan_lines_per_block, s->ymax - line + 1); s->xsize = s->xdelta; + + xmin_block = s->xmin; + ymin_block = line; + uncompressed_size = s->scan_line_size * s->ysize; if ((s->compression == EXR_RAW && (data_size != uncompressed_size || line_offset > buf_size - uncompressed_size)) || @@ -1055,6 +1081,26 @@ static int decode_block(AVCodecContext *avctx, void *tdata, } } + xmax_block = xmin_block + s->xsize - 1; + ymax_block = ymin_block + s->ysize - 1; + xmax_used = FFMIN(xmax_block, s->xmax_display); + xmin_used = FFMAX(xmin_block, s->xmin_display); + ymax_used = FFMIN(ymax_block, s->ymax_display); + + if ((ymax_block < s->ymin_display)||(ymin_block > s->ymax_display)) {/* scanline not use at start or end*/ + av_log(s->avctx, AV_LOG_DEBUG, "entire scanline not visible. Skip it.\n"); + return 0; + } + + ymin_used = FFMAX(ymin_block, s->ymin_display); + line_to_skip = ymin_used - ymin_block; + + if (xmin_block < xmin_used) + xmin_unused = xmin_used - xmin_block;/* nb pixel to skip at the start of each line of the block */ + + if (xmax_block > xmax_used) + xmax_unused = xmax_block - xmax_used;/* nb pixel to skip at the end of each line of the block */ + 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) @@ -1097,9 +1143,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, if (s->is_tile) { indexSrc = 0; - channelLineSize = s->xsize * 2; - if (s->pixel_type == EXR_FLOAT) - channelLineSize *= 2; + channelLineSize = s->xsize * s->pixel_size; /* reorganise tile data to have each channel one after the other instead of line by line */ for (tY = 0; tY < s->ysize; tY ++) { @@ -1124,29 +1168,36 @@ static int decode_block(AVCodecContext *avctx, void *tdata, channel_buffer[3] = src + xdelta * s->channel_offsets[3]; } - ptr = p->data[0] + line * p->linesize[0] + (col * s->desc->nb_components * 2); + channel_buffer[0] += channelLineSize * line_to_skip; + channel_buffer[1] += channelLineSize * line_to_skip; + channel_buffer[2] += channelLineSize * line_to_skip; + if (channel_buffer[3]) + channel_buffer[3] += channelLineSize * line_to_skip; - for (i = 0; - i < s->ysize; i++, ptr += p->linesize[0]) { + target_line += line_to_skip - s->ymin_display; + ptr = p->data[0] + target_line * p->linesize[0] + (col * s->desc->nb_components * 2); + + for (i = ymin_used; + i <= ymax_used; i++, ptr += p->linesize[0]) { const uint8_t *r, *g, *b, *a; - r = channel_buffer[0]; - g = channel_buffer[1]; - b = channel_buffer[2]; + r = channel_buffer[0] + xmin_unused * s->pixel_size; + g = channel_buffer[1] + xmin_unused * s->pixel_size; + b = channel_buffer[2] + xmin_unused * s->pixel_size; if (channel_buffer[3]) - a = channel_buffer[3]; + a = channel_buffer[3] + xmin_unused * s->pixel_size; ptr_x = (uint16_t *) ptr; - // Zero out the start if xmin is not 0 + // Zero out the start if display window begin before datawindow memset(ptr_x, 0, bxmin); - ptr_x += s->xmin * s->desc->nb_components; + ptr_x += bxmin/2; if (s->pixel_type == EXR_FLOAT) { // 32-bit if (trc_func) { - for (x = 0; x < s->xsize; x++) { + for (x = xmin_used; x <= xmax_used; x++) { union av_intfloat32 t; t.i = bytestream_get_le32(&r); t.f = trc_func(t.f); @@ -1163,7 +1214,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, *ptr_x++ = exr_flt2uint(bytestream_get_le32(&a)); } } else { - for (x = 0; x < s->xsize; x++) { + for (x = xmin_used; x <= xmax_used; x++) { union av_intfloat32 t; t.i = bytestream_get_le32(&r); if (t.f > 0.0f) /* avoid negative values */ @@ -1185,7 +1236,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, } } else { // 16-bit - for (x = 0; x < s->xsize; x++) { + for (x = xmin_used; x <= xmax_used; 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)]; @@ -1194,22 +1245,14 @@ static int decode_block(AVCodecContext *avctx, void *tdata, } } - // Zero out the end if xmax+1 is not w + // Zero out the end if datawindow end before display window memset(ptr_x, 0, axmax); - 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; - } + channel_buffer[0] += channelLineSize; + channel_buffer[1] += channelLineSize; + channel_buffer[2] += channelLineSize; + if (channel_buffer[3]) + channel_buffer[3] += channelLineSize; } return 0; @@ -1258,13 +1301,17 @@ static int check_header_variable(EXRContext *s, static int decode_header(EXRContext *s) { - int magic_number, version, i, flags, sar = 0; + int magic_number, version, i, flags, sar = 0, ret; s->current_channel_offset = 0; s->xmin = ~0; s->xmax = ~0; s->ymin = ~0; s->ymax = ~0; + s->xmin_display = ~0; + s->xmax_display = ~0; + s->ymin_display = ~0; + s->ymax_display = ~0; s->xdelta = ~0; s->ydelta = ~0; s->channel_offsets[0] = -1; @@ -1434,15 +1481,29 @@ static int decode_header(EXRContext *s) s->xdelta = (s->xmax - s->xmin) + 1; s->ydelta = (s->ymax - s->ymin) + 1; + if (s->xmin > s->xmax || s->ymin > s->ymax) { + av_log(s->avctx, AV_LOG_ERROR, "Wrong datawindow.\n"); + return AVERROR_INVALIDDATA; + } + continue; } else if ((var_size = check_header_variable(s, "displayWindow", "box2i", 34)) >= 0) { if (!var_size) return AVERROR_INVALIDDATA; - bytestream2_skip(&s->gb, 8); - s->w = bytestream2_get_le32(&s->gb) + 1; - s->h = bytestream2_get_le32(&s->gb) + 1; + s->xmin_display = bytestream2_get_le32(&s->gb); + s->ymin_display = bytestream2_get_le32(&s->gb); + s->xmax_display = bytestream2_get_le32(&s->gb); + s->ymax_display = bytestream2_get_le32(&s->gb); + + if (s->xmin_display > s->xmax_display || s->ymin_display > s->ymax_display) { + av_log(s->avctx, AV_LOG_ERROR, "Wrong displaywindow.\n"); + return AVERROR_INVALIDDATA; + } + + s->w = (s->xmax_display - s->xmin_display) + 1; + s->h = (s->ymax_display - s->ymin_display) + 1; continue; } else if ((var_size = check_header_variable(s, "lineOrder", @@ -1521,6 +1582,8 @@ static int decode_header(EXRContext *s) bytestream2_skip(&s->gb, bytestream2_get_le32(&s->gb)); } + if ((ret = ff_set_dimensions(s->avctx, s->w, s->h)) < 0) + return ret; ff_set_sar(s->avctx, av_d2q(av_int2float(sar), 255)); if (s->compression == EXR_UNKN) { @@ -1542,6 +1605,12 @@ static int decode_header(EXRContext *s) return AVERROR_INVALIDDATA; } + if (s->pixel_type == EXR_HALF) { + s->pixel_size = 2; + } else { + s->pixel_size = 4; + } + // aaand we are done bytestream2_skip(&s->gb, 1); return 0; @@ -1603,20 +1672,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, return AVERROR_PATCHWELCOME; } - /* Verify the xmin, xmax, ymin, ymax and xdelta before setting - * the actual image size. */ - if (s->xmin > s->xmax || - 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"); - return AVERROR_INVALIDDATA; - } - - if ((ret = ff_set_dimensions(avctx, s->w, s->h)) < 0) - return ret; - s->desc = av_pix_fmt_desc_get(avctx->pix_fmt); if (!s->desc) return AVERROR_INVALIDDATA; @@ -1641,20 +1696,24 @@ static int decode_frame(AVCodecContext *avctx, void *data, s->buf_size = avpkt->size; ptr = picture->data[0]; - // Zero out the start if ymin is not 0 - for (y = 0; y < s->ymin; y++) { - memset(ptr, 0, out_line_size); - ptr += picture->linesize[0]; + // Zero out the start lines if need + if (s->ymin_display < s->ymin) { + for (y = s->ymin_display; y < s->ymin; y++) { + memset(ptr, 0, out_line_size); + ptr += picture->linesize[0]; + } } s->picture = picture; 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++) { - memset(ptr, 0, out_line_size); - ptr += picture->linesize[0]; + // Zero out the end lines if need + if (s->ymax_display > s->ymax) { + for (y = s->ymax + 1; y < s->ymax_display; y++) { + memset(ptr, 0, out_line_size); + ptr += picture->linesize[0]; + } } picture->pict_type = AV_PICTURE_TYPE_I; -- 1.9.3 (Apple Git-50)
_______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel