[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