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

Reply via email to