[PATCH] Fix vflip+DR crash.

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


---
 ffplay.c                     |    8 +++++-
 libavfilter/avfilter.c       |    6 ++--
 libavfilter/avfilter.h       |   11 +++++---
 libavfilter/defaults.c       |    8 +++---
 libavfilter/vf_aspect.c      |    4 +-
 libavfilter/vf_crop.c        |    4 +-
 libavfilter/vf_fifo.c        |    4 +-
 libavfilter/vf_frei0r.c      |    2 +-
 libavfilter/vf_overlay.c     |    6 ++--
 libavfilter/vf_pad.c         |    6 ++--
 libavfilter/vf_pixdesctest.c |    4 +-
 libavfilter/vf_scale.c       |    4 +-
 libavfilter/vf_setpts.c      |    4 +-
 libavfilter/vf_settb.c       |    4 +-
 libavfilter/vf_slicify.c     |    4 +-
 libavfilter/vf_transpose.c   |    4 +-
 libavfilter/vf_vflip.c       |   62 +++++++++++++++++++++++++++++++++++++----
 libavfilter/vf_yadif.c       |    6 ++--
 libavfilter/vsink_nullsink.c |    2 +-
 libavfilter/vsrc_buffer.c    |    2 +-
 20 files changed, 107 insertions(+), 48 deletions(-)

diff --git a/ffplay.c b/ffplay.c
index 38a2fe1..005fe2f 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -1606,6 +1606,7 @@ typedef struct {
     VideoState *is;
     AVFrame *frame;
     int use_dr1;
+    int start_frame_flags;
 } 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_POS_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->start_frame_flags = AVFILTER_START_FRAME_FLAG_INVERTED_BUFFER;
     }
 
     priv->frame = avcodec_alloc_frame();
@@ -1730,7 +1736,7 @@ static int input_request_frame(AVFilterLink *link)
     picref->pts = pts;
     picref->pos = pkt.pos;
     picref->video->pixel_aspect = priv->is->video_st->codec->sample_aspect_ratio;
-    avfilter_start_frame(link, picref);
+    avfilter_start_frame(link, picref, priv->start_frame_flags);
     avfilter_draw_slice(link, 0, link->h, 1);
     avfilter_end_frame(link);
 
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index db254d6..96f1090 100644
--- a/libavfilter/avfilter.c
+++ b/libavfilter/avfilter.c
@@ -356,9 +356,9 @@ int avfilter_poll_frame(AVFilterLink *link)
 
 /* XXX: should we do the duplicating of the picture ref here, instead of
  * forcing the source filter to do it? */
-void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags)
 {
-    void (*start_frame)(AVFilterLink *, AVFilterBufferRef *);
+    void (*start_frame)(AVFilterLink *, AVFilterBufferRef *, int);
     AVFilterPad *dst = link->dstpad;
 
     FF_DPRINTF_START(NULL, start_frame); ff_dprintf_link(NULL, link, 0); dprintf(NULL, " "); ff_dprintf_ref(NULL, picref, 1);
@@ -381,7 +381,7 @@ void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
     else
         link->cur_buf = picref;
 
-    start_frame(link, link->cur_buf);
+    start_frame(link, link->cur_buf, flags);
 }
 
 void avfilter_end_frame(AVFilterLink *link)
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 5d34bee..a8b0285 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_POS_LINESIZES  0x20  ///< the buffer requested cannot have negative linesizes
 
 /**
  * Audio specific properties in a reference to an AVFilterBuffer. Since
@@ -349,7 +350,7 @@ struct AVFilterPad {
      *
      * Input video pads only.
      */
-    void (*start_frame)(AVFilterLink *link, AVFilterBufferRef *picref);
+    void (*start_frame)(AVFilterLink *link, AVFilterBufferRef *picref, int flags);
 
     /**
      * Callback function to get a video buffer. If NULL, the filter system will
@@ -432,7 +433,7 @@ struct AVFilterPad {
 };
 
 /** default handler for start_frame() for video inputs */
-void avfilter_default_start_frame(AVFilterLink *link, AVFilterBufferRef *picref);
+void avfilter_default_start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags);
 
 /** default handler for draw_slice() for video inputs */
 void avfilter_default_draw_slice(AVFilterLink *link, int y, int h, int slice_dir);
@@ -469,7 +470,7 @@ void avfilter_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
 int avfilter_default_query_formats(AVFilterContext *ctx);
 
 /** start_frame() handler for filters which simply pass video along */
-void avfilter_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref);
+void avfilter_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags);
 
 /** draw_slice() handler for filters which simply pass video along */
 void avfilter_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir);
@@ -697,6 +698,8 @@ int avfilter_request_frame(AVFilterLink *link);
  */
 int avfilter_poll_frame(AVFilterLink *link);
 
+#define AVFILTER_START_FRAME_FLAG_INVERTED_BUFFER  0x01
+
 /**
  * Notifie the next filter of the start of a frame.
  *
@@ -706,7 +709,7 @@ int avfilter_poll_frame(AVFilterLink *link);
  *               portion. The receiving filter will free this reference when
  *               it no longer needs it.
  */
-void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref);
+void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags);
 
 /**
  * Notifie the next filter that the current frame has finished.
diff --git a/libavfilter/defaults.c b/libavfilter/defaults.c
index aa3739c..59b7198 100644
--- a/libavfilter/defaults.c
+++ b/libavfilter/defaults.c
@@ -134,7 +134,7 @@ fail:
     return NULL;
 }
 
-void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref, int flags)
 {
     AVFilterLink *outlink = NULL;
 
@@ -144,7 +144,7 @@ void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picre
     if (outlink) {
         outlink->out_buf = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
         avfilter_copy_buffer_ref_props(outlink->out_buf, picref);
-        avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0));
+        avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0), flags);
     }
 }
 
@@ -266,9 +266,9 @@ int avfilter_default_query_formats(AVFilterContext *ctx)
     return 0;
 }
 
-void avfilter_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+void avfilter_null_start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags)
 {
-    avfilter_start_frame(link->dst->outputs[0], picref);
+    avfilter_start_frame(link->dst->outputs[0], picref, flags);
 }
 
 void avfilter_null_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
diff --git a/libavfilter/vf_aspect.c b/libavfilter/vf_aspect.c
index 6f86bf2..fb95fd4 100644
--- a/libavfilter/vf_aspect.c
+++ b/libavfilter/vf_aspect.c
@@ -61,12 +61,12 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
     return 0;
 }
 
-static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags)
 {
     AspectContext *aspect = link->dst->priv;
 
     picref->video->pixel_aspect = aspect->aspect;
-    avfilter_start_frame(link->dst->outputs[0], picref);
+    avfilter_start_frame(link->dst->outputs[0], picref, flags);
 }
 
 #if CONFIG_SETDAR_FILTER
diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c
index 311ee30..caf0dad 100644
--- a/libavfilter/vf_crop.c
+++ b/libavfilter/vf_crop.c
@@ -233,7 +233,7 @@ static int config_output(AVFilterLink *link)
     return 0;
 }
 
-static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags)
 {
     AVFilterContext *ctx = link->dst;
     CropContext *crop = ctx->priv;
@@ -284,7 +284,7 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
         ref2->data[3] += crop->x * crop->max_step[3];
     }
 
-    avfilter_start_frame(link->dst->outputs[0], ref2);
+    avfilter_start_frame(link->dst->outputs[0], ref2, flags);
 }
 
 static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
diff --git a/libavfilter/vf_fifo.c b/libavfilter/vf_fifo.c
index 32199ed..2c5b14a 100644
--- a/libavfilter/vf_fifo.c
+++ b/libavfilter/vf_fifo.c
@@ -56,7 +56,7 @@ static av_cold void uninit(AVFilterContext *ctx)
     }
 }
 
-static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref, int flags)
 {
     FifoContext *fifo = inlink->dst->priv;
 
@@ -82,7 +82,7 @@ static int request_frame(AVFilterLink *outlink)
 
     /* by doing this, we give ownership of the reference to the next filter,
      * so we don't have to worry about dereferencing it ourselves. */
-    avfilter_start_frame(outlink, fifo->root.next->picref);
+    avfilter_start_frame(outlink, fifo->root.next->picref, 0);
     avfilter_draw_slice (outlink, 0, outlink->h, 1);
     avfilter_end_frame  (outlink);
 
diff --git a/libavfilter/vf_frei0r.c b/libavfilter/vf_frei0r.c
index 03d4f28..750e9f5 100644
--- a/libavfilter/vf_frei0r.c
+++ b/libavfilter/vf_frei0r.c
@@ -434,7 +434,7 @@ static int source_request_frame(AVFilterLink *outlink)
     picref->pts = frei0r->pts++;
     picref->pos = -1;
 
-    avfilter_start_frame(outlink, avfilter_ref_buffer(picref, ~0));
+    avfilter_start_frame(outlink, avfilter_ref_buffer(picref, ~0), 0);
     frei0r->update(frei0r->instance, av_rescale_q(picref->pts, frei0r->time_base, (AVRational){1,1000}),
                    NULL, (uint32_t *)picref->data[0]);
     avfilter_draw_slice(outlink, 0, outlink->h, 1);
diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c
index a170e81..92d7087 100644
--- a/libavfilter/vf_overlay.c
+++ b/libavfilter/vf_overlay.c
@@ -205,7 +205,7 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms, int w,
     return avfilter_get_video_buffer(link->dst->outputs[0], perms, w, h);
 }
 
-static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref, int flags)
 {
     AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0);
     AVFilterContext *ctx = inlink->dst;
@@ -226,10 +226,10 @@ static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
             over->overpicref = old;
     }
 
-    avfilter_start_frame(inlink->dst->outputs[0], outpicref);
+    avfilter_start_frame(inlink->dst->outputs[0], outpicref, flags);
 }
 
-static void start_frame_overlay(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static void start_frame_overlay(AVFilterLink *inlink, AVFilterBufferRef *inpicref, int flags)
 {
     AVFilterContext *ctx = inlink->dst;
     OverlayContext *over = ctx->priv;
diff --git a/libavfilter/vf_pad.c b/libavfilter/vf_pad.c
index a661b9c..083b0bb 100644
--- a/libavfilter/vf_pad.c
+++ b/libavfilter/vf_pad.c
@@ -243,7 +243,7 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink *inlink, int perms, int
     return picref;
 }
 
-static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref, int flags)
 {
     PadContext *pad = inlink->dst->priv;
     AVFilterBufferRef *outpicref = avfilter_ref_buffer(inpicref, ~0);
@@ -259,7 +259,7 @@ static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
             (pad->y >> vsub) * outpicref->linesize[plane];
     }
 
-    avfilter_start_frame(inlink->dst->outputs[0], outpicref);
+    avfilter_start_frame(inlink->dst->outputs[0], outpicref, flags);
 }
 
 static void end_frame(AVFilterLink *link)
@@ -434,7 +434,7 @@ static int color_request_frame(AVFilterLink *link)
     picref->pts                 = av_rescale_q(color->pts++, color->time_base, AV_TIME_BASE_Q);
     picref->pos                 = 0;
 
-    avfilter_start_frame(link, avfilter_ref_buffer(picref, ~0));
+    avfilter_start_frame(link, avfilter_ref_buffer(picref, ~0), 0);
     draw_rectangle(picref,
                    color->line, color->line_step, color->hsub, color->vsub,
                    0, 0, color->w, color->h);
diff --git a/libavfilter/vf_pixdesctest.c b/libavfilter/vf_pixdesctest.c
index 1fb577e..e70eafa 100644
--- a/libavfilter/vf_pixdesctest.c
+++ b/libavfilter/vf_pixdesctest.c
@@ -49,7 +49,7 @@ static int config_props(AVFilterLink *inlink)
     return 0;
 }
 
-static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref, int flags)
 {
     PixdescTestContext *priv = inlink->dst->priv;
     AVFilterLink *outlink    = inlink->dst->outputs[0];
@@ -75,7 +75,7 @@ static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
     if (priv->pix_desc->flags & PIX_FMT_PAL)
         memcpy(outpicref->data[1], outpicref->data[1], 256*4);
 
-    avfilter_start_frame(outlink, avfilter_ref_buffer(outpicref, ~0));
+    avfilter_start_frame(outlink, avfilter_ref_buffer(outpicref, ~0), flags);
 }
 
 static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 100ba2b..6e38435 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -142,7 +142,7 @@ static int config_props(AVFilterLink *outlink)
     return !scale->sws;
 }
 
-static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags)
 {
     ScaleContext *scale = link->dst->priv;
     AVFilterLink *outlink = link->dst->outputs[0];
@@ -164,7 +164,7 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
               INT_MAX);
 
     scale->slice_y = 0;
-    avfilter_start_frame(outlink, avfilter_ref_buffer(outpicref, ~0));
+    avfilter_start_frame(outlink, avfilter_ref_buffer(outpicref, ~0), flags);
 }
 
 static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
diff --git a/libavfilter/vf_setpts.c b/libavfilter/vf_setpts.c
index 0921df7..1f2c947 100644
--- a/libavfilter/vf_setpts.c
+++ b/libavfilter/vf_setpts.c
@@ -98,7 +98,7 @@ static int config_input(AVFilterLink *inlink)
 #define D2TS(d)  (isnan(d) ? AV_NOPTS_VALUE : (int64_t)(d))
 #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
 
-static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
+static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref, int flags)
 {
     SetPTSContext *setpts = inlink->dst->priv;
     double d;
@@ -127,7 +127,7 @@ static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *inpicref)
     setpts->var_values[VAR_N] += 1.0;
     setpts->var_values[VAR_PREV_INPTS ] = TS2D(inpicref ->pts);
     setpts->var_values[VAR_PREV_OUTPTS] = TS2D(outpicref->pts);
-    avfilter_start_frame(inlink->dst->outputs[0], outpicref);
+    avfilter_start_frame(inlink->dst->outputs[0], outpicref, flags);
 }
 
 static av_cold void uninit(AVFilterContext *ctx)
diff --git a/libavfilter/vf_settb.c b/libavfilter/vf_settb.c
index 3e48ac4..f99ef42 100644
--- a/libavfilter/vf_settb.c
+++ b/libavfilter/vf_settb.c
@@ -102,7 +102,7 @@ static int config_output_props(AVFilterLink *outlink)
     return 0;
 }
 
-static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref, int flags)
 {
     AVFilterContext *ctx = inlink->dst;
     AVFilterLink *outlink = ctx->outputs[0];
@@ -117,7 +117,7 @@ static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
         avfilter_unref_buffer(picref);
     }
 
-    avfilter_start_frame(outlink, picref2);
+    avfilter_start_frame(outlink, picref2, flags);
 }
 
 AVFilter avfilter_vf_settb = {
diff --git a/libavfilter/vf_slicify.c b/libavfilter/vf_slicify.c
index 177ac1f..f958d46 100644
--- a/libavfilter/vf_slicify.c
+++ b/libavfilter/vf_slicify.c
@@ -57,7 +57,7 @@ static int config_props(AVFilterLink *link)
     return 0;
 }
 
-static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags)
 {
     SliceContext *slice = link->dst->priv;
 
@@ -72,7 +72,7 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
 
     av_log(link->dst, AV_LOG_DEBUG, "h:%d\n", slice->h);
 
-    avfilter_start_frame(link->dst->outputs[0], picref);
+    avfilter_start_frame(link->dst->outputs[0], picref, flags);
 }
 
 static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
diff --git a/libavfilter/vf_transpose.c b/libavfilter/vf_transpose.c
index 970c381..b8dff0e 100644
--- a/libavfilter/vf_transpose.c
+++ b/libavfilter/vf_transpose.c
@@ -109,7 +109,7 @@ static int config_props_output(AVFilterLink *outlink)
     return 0;
 }
 
-static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref, int flags)
 {
     AVFilterLink *outlink = inlink->dst->outputs[0];
 
@@ -124,7 +124,7 @@ static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref)
         outlink->out_buf->video->pixel_aspect.den = picref->video->pixel_aspect.num;
     }
 
-    avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0));
+    avfilter_start_frame(outlink, avfilter_ref_buffer(outlink->out_buf, ~0), flags);
 }
 
 static void end_frame(AVFilterLink *inlink)
diff --git a/libavfilter/vf_vflip.c b/libavfilter/vf_vflip.c
index 95d90d3..4206fc9 100644
--- a/libavfilter/vf_vflip.c
+++ b/libavfilter/vf_vflip.c
@@ -24,10 +24,13 @@
  */
 
 #include "libavutil/pixdesc.h"
+#include "libavcore/imgutils.h"
 #include "avfilter.h"
 
 typedef struct {
     int vsub;   ///< vertical chroma subsampling
+    int linesizes[4];
+    int flip_image;
 } FlipContext;
 
 static int config_input(AVFilterLink *link)
@@ -35,6 +38,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 +47,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_POS_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;
 
@@ -60,11 +66,18 @@ static AVFilterBufferRef *get_video_buffer(AVFilterLink *link, int perms,
     return picref;
 }
 
-static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags)
 {
     FlipContext *flip = link->dst->priv;
     int i;
 
+    if (flags & AVFILTER_START_FRAME_FLAG_INVERTED_BUFFER) {
+        flags = flags & ~AVFILTER_START_FRAME_FLAG_INVERTED_BUFFER;
+        flip->flip_image = 1;
+        avfilter_default_start_frame(link, picref, flags);
+        return;
+    }
+
     for (i = 0; i < 4; i ++) {
         int vsub = i == 1 || i == 2 ? flip->vsub : 0;
 
@@ -74,14 +87,51 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
         }
     }
 
-    avfilter_start_frame(link->dst->outputs[0], picref);
+    avfilter_start_frame(link->dst->outputs[0], picref, flags);
 }
 
 static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
 {
     AVFilterContext *ctx = link->dst;
+    FlipContext *flip = ctx->priv;
+
+    if (!flip->flip_image)
+        avfilter_draw_slice(ctx->outputs[0], link->h - (y+h), h, -1 * slice_dir);
+}
+
+static void end_frame(AVFilterLink *inlink)
+{
+    FlipContext *flip = inlink->dst->priv;
+    AVFilterLink *outlink = inlink->dst->outputs[0];
+    AVFilterBufferRef *inpic  = inlink->cur_buf;
+    AVFilterBufferRef *outpic = outlink->out_buf;
+    uint8_t *inrow, *outrow;
+    int plane, i, h;
+
+    if (!flip->flip_image) {
+        avfilter_null_end_frame(inlink);
+        return;
+    }
+
+    /* vflip image */
+    for (plane = 0; plane < 4 && inpic->data[plane]; plane++) {
+        h = plane == 1 || plane == 2 ? inlink->h>>flip->vsub : inlink->h;
+
+        inrow  = inpic ->data[plane];
+        outrow = outpic->data[plane] + outpic->linesize[plane] * (h-1);
+
+        for (i = 0; i < h; i++) {
+            memcpy(outrow, inrow, flip->linesizes[plane]);
+            inrow  += inpic ->linesize[plane];
+            outrow -= outpic->linesize[plane];
+        }
+    }
 
-    avfilter_draw_slice(ctx->outputs[0], link->h - (y+h), h, -1 * slice_dir);
+    flip->flip_image = 0;
+    avfilter_unref_buffer(inpic);
+    avfilter_draw_slice(outlink, 0, inlink->h, 1);
+    avfilter_end_frame(outlink);
+    avfilter_unref_buffer(outpic);
 }
 
 AVFilter avfilter_vf_vflip = {
@@ -95,7 +145,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",
diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c
index d96e587..b89204c 100644
--- a/libavfilter/vf_yadif.c
+++ b/libavfilter/vf_yadif.c
@@ -184,7 +184,7 @@ static void return_frame(AVFilterContext *ctx, int is_second)
         } else {
             yadif->out->pts = AV_NOPTS_VALUE;
         }
-        avfilter_start_frame(ctx->outputs[0], yadif->out);
+        avfilter_start_frame(ctx->outputs[0], yadif->out, 0);
     }
     avfilter_draw_slice(ctx->outputs[0], 0, link->h, 1);
     avfilter_end_frame(ctx->outputs[0]);
@@ -192,7 +192,7 @@ static void return_frame(AVFilterContext *ctx, int is_second)
     yadif->frame_pending = (yadif->mode&1) && !is_second;
 }
 
-static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags)
 {
     AVFilterContext *ctx = link->dst;
     YADIFContext *yadif = ctx->priv;
@@ -217,7 +217,7 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
 
     avfilter_copy_buffer_ref_props(yadif->out, yadif->cur);
     yadif->out->video->interlaced = 0;
-    avfilter_start_frame(ctx->outputs[0], yadif->out);
+    avfilter_start_frame(ctx->outputs[0], yadif->out, flags);
 }
 
 static void end_frame(AVFilterLink *link)
diff --git a/libavfilter/vsink_nullsink.c b/libavfilter/vsink_nullsink.c
index 0998bd0..2d8406a 100644
--- a/libavfilter/vsink_nullsink.c
+++ b/libavfilter/vsink_nullsink.c
@@ -18,7 +18,7 @@
 
 #include "avfilter.h"
 
-static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
+static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref, int flags)
 {
 }
 
diff --git a/libavfilter/vsrc_buffer.c b/libavfilter/vsrc_buffer.c
index 74d9bf6..81da3a3 100644
--- a/libavfilter/vsrc_buffer.c
+++ b/libavfilter/vsrc_buffer.c
@@ -130,7 +130,7 @@ static int request_frame(AVFilterLink *link)
     picref->video->pixel_aspect    = c->pixel_aspect;
     picref->video->interlaced      = c->frame.interlaced_frame;
     picref->video->top_field_first = c->frame.top_field_first;
-    avfilter_start_frame(link, avfilter_ref_buffer(picref, ~0));
+    avfilter_start_frame(link, avfilter_ref_buffer(picref, ~0), 0);
     avfilter_draw_slice(link, 0, link->h, 1);
     avfilter_end_frame(link);
     avfilter_unref_buffer(picref);
-- 
1.7.2.3


--zYM0uCDKw75PZbzx--



More information about the ffmpeg-devel mailing list