[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 | 63 +++++++++++++++++++++++++++++++++++++++++------
4 files changed, 67 insertions(+), 10 deletions(-)
diff --git a/ffplay.c b/ffplay.c
index 38a2fe1..96e47bd 100644
--- a/ffplay.c
+++ b/ffplay.c
@@ -1606,6 +1606,7 @@ typedef struct {
VideoState *is;
AVFrame *frame;
int use_dr1;
+ int use_pos_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_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->use_pos_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_pos_linesizes)
+ picref->perms |= AV_PERM_POS_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..9773ebe 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_POS_LINESIZES ? "P" : "");
return buf;
}
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index 5d34bee..194a614 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
diff --git a/libavfilter/vf_vflip.c b/libavfilter/vf_vflip.c
index 95d90d3..84c92bd 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_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;
@@ -63,25 +68,67 @@ 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_POS_LINESIZES) {
+ picref2->perms |= AV_PERM_POS_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)
{
AVFilterContext *ctx = link->dst;
- avfilter_draw_slice(ctx->outputs[0], link->h - (y+h), h, -1 * slice_dir);
+ if (!(link->cur_buf->perms & AV_PERM_POS_LINESIZES))
+ 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 (!(inlink->cur_buf->perms & AV_PERM_POS_LINESIZES)) {
+ 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_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 +142,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
--azLHFNyN32YCQGCU--
More information about the ffmpeg-devel
mailing list