[PATCH] Fix vflip+DR crash.

Stefano Sabatini stefano.sabatini-lala
Sun Dec 5 03:37:06 CET 2010


---
 ffplay.c               |    8 ++++++
 libavfilter/avfilter.c |    5 ++-
 libavfilter/avfilter.h |    1 +
 libavfilter/vf_vflip.c |   65 ++++++++++++++++++++++++++++++++++++++++-------
 4 files changed, 67 insertions(+), 12 deletions(-)

diff --git a/ffplay.c b/ffplay.c
index 38a2fe1..169944b 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -1606,6 +1606,7 @@ typedef struct {
     VideoState *is;
     AVFrame *frame;
     int use_dr1;
+    int use_neg_linesizes;
 } FilterPriv;
 
 static int input_get_buffer(AVCodecContext *codec, AVFrame *pic)
@@ -1616,6 +1617,9 @@ static int input_get_buffer(AVCodecContext *codec, AVFrame *pic)
     int i, w, h, stride[4];
     unsigned edge;
 
+    if (codec->codec->capabilities & CODEC_CAP_NEG_LINESIZES)
+        perms |= AV_PERM_NEG_LINESIZES;
+
     if(pic->buffer_hints & FF_BUFFER_HINTS_VALID) {
         if(pic->buffer_hints & FF_BUFFER_HINTS_READABLE) perms |= AV_PERM_READ;
         if(pic->buffer_hints & FF_BUFFER_HINTS_PRESERVE) perms |= AV_PERM_PRESERVE;
@@ -1691,6 +1695,8 @@ static int input_init(AVFilterContext *ctx, const char *args, void *opaque)
         codec->get_buffer     = input_get_buffer;
         codec->release_buffer = input_release_buffer;
         codec->reget_buffer   = input_reget_buffer;
+        if (codec->codec->capabilities & CODEC_CAP_NEG_LINESIZES)
+            priv->use_neg_linesizes = 1;
     }
 
     priv->frame = avcodec_alloc_frame();
@@ -1719,6 +1725,8 @@ static int input_request_frame(AVFilterLink *link)
 
     if(priv->use_dr1) {
         picref = avfilter_ref_buffer(priv->frame->opaque, ~0);
+        if (priv->use_neg_linesizes)
+            picref->perms |= AV_PERM_NEG_LINESIZES;
     } else {
         picref = avfilter_get_video_buffer(link, AV_PERM_WRITE, link->w, link->h);
         av_image_copy(picref->data, picref->linesize,
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index db254d6..da11185 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -197,12 +197,13 @@ int avfilter_config_links(AVFilterContext *filter)
 
 char *ff_get_ref_perms_string(char *buf, size_t buf_size, int perms)
 {
-    snprintf(buf, buf_size, "%s%s%s%s%s",
+    snprintf(buf, buf_size, "%s%s%s%s%s%s",
              perms & AV_PERM_READ      ? "r" : "",
              perms & AV_PERM_WRITE     ? "w" : "",
              perms & AV_PERM_PRESERVE  ? "p" : "",
              perms & AV_PERM_REUSE     ? "u" : "",
-             perms & AV_PERM_REUSE2    ? "U" : "");
+             perms & AV_PERM_REUSE2    ? "U" : "",
+             perms & AV_PERM_NEG_LINESIZES ? "n" : "");
     return buf;
 }
 
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 5d34bee..dd22661 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -86,6 +86,7 @@ typedef struct AVFilterBuffer {
 #define AV_PERM_PRESERVE 0x04   ///< nobody else can overwrite the buffer
 #define AV_PERM_REUSE    0x08   ///< can output the buffer multiple times, with the same contents each time
 #define AV_PERM_REUSE2   0x10   ///< can output the buffer multiple times, modified each time
+#define AV_PERM_NEG_LINESIZES  0x20  ///< the buffer requested can have negative linesizes
 
 /**
  * Audio specific properties in a reference to an AVFilterBuffer. Since
diff --git a/libavfilter/vf_vflip.c b/libavfilter/vf_vflip.c
index 95d90d3..b0cd370 100644
--- a/libavfilter/vf_vflip.c
+++ b/libavfilter/vf_vflip.c
@@ -24,10 +24,12 @@
  */
 
 #include "libavutil/pixdesc.h"
+#include "libavcore/imgutils.h"
 #include "avfilter.h"
 
 typedef struct {
     int vsub;   ///< vertical chroma subsampling
+    int linesizes[4];
 } FlipContext;
 
 static int config_input(AVFilterLink *link)
@@ -35,6 +37,7 @@ static int config_input(AVFilterLink *link)
     FlipContext *flip = link->dst->priv;
 
     flip->vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h;
+    av_image_fill_linesizes(flip->linesizes, link->format, link->w);
 
     return 0;
 }
@@ -43,11 +46,13 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms,
                                         int w, int h)
 {
     FlipContext *flip = link->dst->priv;
+    AVFilterBufferRef *picref;
     int i;
 
-    AVFilterBufferRef *picref = avfilter_get_video_buffer(link->dst->outputs[0],
-                                                       perms, w, h);
+    if (!(perms & AV_PERM_NEG_LINESIZES))
+        return avfilter_default_get_video_buffer(link, perms, w, h);
 
+    picref = avfilter_get_video_buffer(link->dst->outputs[0], perms, w, h);
     for (i = 0; i < 4; i ++) {
         int vsub = i == 1 || i == 2 ? flip->vsub : 0;
 
@@ -63,25 +68,65 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms,
 static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
 {
     FlipContext *flip = link->dst->priv;
+    AVFilterBufferRef *picref2 = avfilter_ref_buffer(picref, ~0);
     int i;
 
+    if (!(picref->perms & AV_PERM_NEG_LINESIZES)) {
+        picref2->perms |= AV_PERM_NEG_LINESIZES;
+        avfilter_default_start_frame(link, picref2);
+        return;
+    }
+
     for (i = 0; i < 4; i ++) {
         int vsub = i == 1 || i == 2 ? flip->vsub : 0;
 
-        if (picref->data[i]) {
-            picref->data[i] += ((link->h >> vsub)-1) * picref->linesize[i];
-            picref->linesize[i] = -picref->linesize[i];
+        if (picref2->data[i]) {
+            picref2->data[i] += ((link->h >> vsub)-1) * picref->linesize[i];
+            picref2->linesize[i] = -picref->linesize[i];
         }
     }
 
-    avfilter_start_frame(link->dst->outputs[0], picref);
+    avfilter_start_frame(link->dst->outputs[0], picref2);
 }
 
-static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
+static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
 {
-    AVFilterContext *ctx = link->dst;
+    AVFilterContext *ctx = inlink->dst;
+    FlipContext *flip = ctx->priv;
+    AVFilterLink *outlink = ctx->outputs[0];
+
+    if (!(inlink->cur_buf->perms & AV_PERM_NEG_LINESIZES)) {
+        AVFilterBufferRef *inpic  = inlink ->cur_buf;
+        AVFilterBufferRef *outpic = outlink->out_buf;
+        uint8_t *inrow, *outrow;
+        int plane, i;
+
+        /* vflip slice */
+        for (plane = 0; plane < 4 && inpic->data[plane]; plane++) {
+            int frame_h = plane == 1 || plane == 2 ? (inlink->h)>>flip->vsub : inlink->h;
+            int y1      = plane == 1 || plane == 2 ? y>>flip->vsub : y;
+            int h1      = plane == 1 || plane == 2 ? h>>flip->vsub : h;
+
+            inrow  = inpic ->data[plane] + inpic ->linesize[plane] * y1;
+            outrow = outpic->data[plane] + outpic->linesize[plane] * (frame_h -y1-1);
+
+            for (i = 0; i < h1; i++) {
+                memcpy(outrow, inrow, flip->linesizes[plane]);
+                inrow  += inpic ->linesize[plane];
+                outrow -= outpic->linesize[plane];
+            }
+        }
+    }
+
+    avfilter_draw_slice(outlink, inlink->h - (y+h), h, -1 * slice_dir);
+}
 
-    avfilter_draw_slice(ctx->outputs[0], link->h - (y+h), h, -1 * slice_dir);
+static void end_frame(AVFilterLink *inlink)
+{
+    if (!(inlink->cur_buf->perms & AV_PERM_NEG_LINESIZES)) {
+        avfilter_default_end_frame(inlink);
+    } else
+        avfilter_null_end_frame(inlink);
 }
 
 AVFilter avfilter_vf_vflip = {
@@ -95,7 +140,7 @@ AVFilter avfilter_vf_vflip = {
                                     .get_video_buffer = get_video_buffer,
                                     .start_frame      = start_frame,
                                     .draw_slice       = draw_slice,
-                                    .end_frame        = avfilter_null_end_frame,
+                                    .end_frame        = end_frame,
                                     .config_props     = config_input, },
                                   { .name = NULL}},
     .outputs   = (AVFilterPad[]) {{ .name             = "default",
-- 
1.7.2.3


--zYM0uCDKw75PZbzx--



More information about the ffmpeg-devel mailing list