[PATCH] Introduce the AV_PERM_NEG_LINESIZES flag, which allows to explicitely request a buffer which can have negative linesizes, so that if it is not specified in the permissions for the requested buffer the returned buffer must have positive linesizes.
Stefano Sabatini
stefano.sabatini-lala
Sun Dec 5 03:37:06 CET 2010
This is required in particular with direct rendering as implemented in
ffply, as some codecs cannot process an image buffer with negative
linesizes and will crash.
Fix issue #1913.
---
ffplay.c | 8 +++++
libavfilter/allfilters.c | 1 +
libavfilter/avfilter.c | 11 +++++---
libavfilter/avfilter.h | 1 +
libavfilter/vf_null.c | 19 +++++++++++++
libavfilter/vf_scale.c | 2 +-
libavfilter/vf_vflip.c | 65 ++++++++++++++++++++++++++++++++++++++-------
7 files changed, 92 insertions(+), 15 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/allfilters.c b/libavfilter/allfilters.c
index 7f7e46d..292bd21 100644
--- a/libavfilter/allfilters.c
+++ b/libavfilter/allfilters.c
@@ -56,6 +56,7 @@ void avfilter_register_all(void)
REGISTER_FILTER (OVERLAY, overlay, vf);
REGISTER_FILTER (PAD, pad, vf);
REGISTER_FILTER (PIXDESCTEST, pixdesctest, vf);
+ REGISTER_FILTER (POSLS, posls, vf);
REGISTER_FILTER (SCALE, scale, vf);
REGISTER_FILTER (SETDAR, setdar, vf);
REGISTER_FILTER (SETPTS, setpts, vf);
diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c
index db254d6..04cb020 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;
}
@@ -360,15 +361,17 @@ void avfilter_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
{
void (*start_frame)(AVFilterLink *, AVFilterBufferRef *);
AVFilterPad *dst = link->dstpad;
+ int perms = picref->perms;
FF_DPRINTF_START(NULL, start_frame); ff_dprintf_link(NULL, link, 0); dprintf(NULL, " "); ff_dprintf_ref(NULL, picref, 1);
if (!(start_frame = dst->start_frame))
start_frame = avfilter_default_start_frame;
+ if (picref->linesize[0] < 0)
+ perms |= AV_PERM_NEG_LINESIZES;
/* prepare to copy the picture if it has insufficient permissions */
- if ((dst->min_perms & picref->perms) != dst->min_perms ||
- dst->rej_perms & picref->perms) {
+ if ((dst->min_perms & perms) != dst->min_perms || dst->rej_perms & perms) {
av_log(link->dst, AV_LOG_DEBUG,
"frame copy needed (have perms %x, need %x, reject %x)\n",
picref->perms,
diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h
index a4bc978..fccf5ff 100644
--- a/libavfilter/avfilter.h
+++ b/libavfilter/avfilter.h
@@ -87,6 +87,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_null.c b/libavfilter/vf_null.c
index 989cd86..8db939b 100644
--- a/libavfilter/vf_null.c
+++ b/libavfilter/vf_null.c
@@ -40,3 +40,22 @@ AVFilter avfilter_vf_null = {
.type = AVMEDIA_TYPE_VIDEO, },
{ .name = NULL}},
};
+
+AVFilter avfilter_vf_posls = {
+ .name = "posls",
+ .description = NULL_IF_CONFIG_SMALL("Make the output buffer have positive linesizes."),
+
+ .priv_size = 0,
+
+ .inputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO,
+ .get_video_buffer = avfilter_null_get_video_buffer,
+ .start_frame = avfilter_null_start_frame,
+ .end_frame = avfilter_null_end_frame,
+ .rej_perms = AV_PERM_NEG_LINESIZES, },
+ { .name = NULL}},
+
+ .outputs = (AVFilterPad[]) {{ .name = "default",
+ .type = AVMEDIA_TYPE_VIDEO, },
+ { .name = NULL}},
+};
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 100ba2b..7b0efd5 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -151,7 +151,7 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
scale->hsub = av_pix_fmt_descriptors[link->format].log2_chroma_w;
scale->vsub = av_pix_fmt_descriptors[link->format].log2_chroma_h;
- outpicref = avfilter_get_video_buffer(outlink, AV_PERM_WRITE, outlink->w, outlink->h);
+ outpicref = avfilter_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_NEG_LINESIZES, outlink->w, outlink->h);
avfilter_copy_buffer_ref_props(outpicref, picref);
outpicref->video->w = outlink->w;
outpicref->video->h = outlink->h;
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
--AhhlLboLdkugWU4S--
More information about the ffmpeg-devel
mailing list