aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2011-03-28 00:09:58 +0200
committerMichael Niedermayer <michaelni@gmx.at>2011-03-28 01:45:11 +0200
commit57e2ded4234356c26bf92b0a627ec383ea8d288f (patch)
treecd66f80bfb55358d892e5bb8e9c3460562157997
parent8e43b6fed905eb30ae941a3968825d88c78d5a12 (diff)
downloadffmpeg-57e2ded4234356c26bf92b0a627ec383ea8d288f.tar.gz
Implement interlaced scaling.
Fixes issue2632 if interl=1 is used or the automatic interlace detection is enabled and works. This has the advantage compared to the patch in issue2632 that it causes no speed loss and it also works when scaling is used. The disadvantage is that interlacing autodetection does not yet work very well it seems. This is the same method mplayer uses Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--libavfilter/vf_scale.c59
1 files changed, 47 insertions, 12 deletions
diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c
index 3f5491321c..b1f1ba581e 100644
--- a/libavfilter/vf_scale.c
+++ b/libavfilter/vf_scale.c
@@ -25,10 +25,12 @@
#include "avfilter.h"
#include "libavutil/pixdesc.h"
+#include "libavutil/avassert.h"
#include "libswscale/swscale.h"
typedef struct {
struct SwsContext *sws; ///< software scaler context
+ struct SwsContext *isws[2]; ///< software scaler context for interlaced material
/**
* New dimensions. Special values are:
@@ -41,6 +43,7 @@ typedef struct {
int hsub, vsub; ///< chroma subsampling
int slice_y; ///< top of current output slice
int input_is_pal; ///< set to 1 if the input format is paletted
+ int interlaced;
} ScaleContext;
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
@@ -53,6 +56,10 @@ static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
sscanf(args, "%d:%d", &scale->w, &scale->h);
p = strstr(args,"flags=");
if (p) scale->flags = strtoul(p+6, NULL, 0);
+ if(strstr(args,"interl=1")){
+ scale->interlaced=1;
+ }else if(strstr(args,"interl=-1"))
+ scale->interlaced=-1;
}
/* sanity check params */
@@ -70,6 +77,8 @@ static av_cold void uninit(AVFilterContext *ctx)
{
ScaleContext *scale = ctx->priv;
sws_freeContext(scale->sws);
+ sws_freeContext(scale->isws[0]);
+ sws_freeContext(scale->isws[1]);
scale->sws = NULL;
}
@@ -138,6 +147,12 @@ static int config_props(AVFilterLink *outlink)
scale->sws = sws_getContext(inlink ->w, inlink ->h, inlink ->format,
outlink->w, outlink->h, outlink->format,
scale->flags, NULL, NULL, NULL);
+ scale->isws[0] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
+ outlink->w, outlink->h/2, outlink->format,
+ scale->flags, NULL, NULL, NULL);
+ scale->isws[1] = sws_getContext(inlink ->w, inlink ->h/2, inlink ->format,
+ outlink->w, outlink->h/2, outlink->format,
+ scale->flags, NULL, NULL, NULL);
if (!scale->sws)
return AVERROR(EINVAL);
@@ -169,26 +184,46 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
avfilter_start_frame(outlink, avfilter_ref_buffer(outpicref, ~0));
}
+static int scale_slice(AVFilterLink *link, struct SwsContext *sws, int y, int h, int mul, int field)
+{
+ ScaleContext *scale = link->dst->priv;
+ AVFilterBufferRef *cur_pic = link->cur_buf;
+ AVFilterBufferRef *out_buf = link->dst->outputs[0]->out_buf;
+ const uint8_t *in[4], *out[4];
+ int in_stride[4],out_stride[4];
+ int i;
+
+ for(i=0; i<4; i++){
+ int vsub= ((i+1)&2) ? scale->vsub : 0;
+ in_stride[i] = cur_pic->linesize[i] * mul;
+ out_stride[i] = out_buf->linesize[i] * mul;
+ in[i] = cur_pic->data[i] + ((y>>vsub)+field) * cur_pic->linesize[i];
+ out[i] = out_buf->data[i] + field * out_buf->linesize[i];
+ }
+ if(scale->input_is_pal){
+ in[1] = cur_pic->data[1];
+ out[1] = out_buf->data[1];
+ }
+
+ return sws_scale(sws, in, in_stride, y/mul, h,
+ out,out_stride);
+}
+
static void draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
{
ScaleContext *scale = link->dst->priv;
int out_h;
- AVFilterBufferRef *cur_pic = link->cur_buf;
- const uint8_t *data[4];
if (scale->slice_y == 0 && slice_dir == -1)
scale->slice_y = link->dst->outputs[0]->h;
- data[0] = cur_pic->data[0] + y * cur_pic->linesize[0];
- data[1] = scale->input_is_pal ?
- cur_pic->data[1] :
- cur_pic->data[1] + (y>>scale->vsub) * cur_pic->linesize[1];
- data[2] = cur_pic->data[2] + (y>>scale->vsub) * cur_pic->linesize[2];
- data[3] = cur_pic->data[3] + y * cur_pic->linesize[3];
-
- out_h = sws_scale(scale->sws, data, cur_pic->linesize, y, h,
- link->dst->outputs[0]->out_buf->data,
- link->dst->outputs[0]->out_buf->linesize);
+ if(scale->interlaced>0 || (scale->interlaced<0 && link->cur_buf->video->interlaced)){
+ av_assert0(y%4 == 0);
+ out_h = scale_slice(link, scale->isws[0], y, (h+1)/2, 2, 0);
+ out_h+= scale_slice(link, scale->isws[1], y, h /2, 2, 1);
+ }else{
+ out_h = scale_slice(link, scale->sws, y, h, 1, 0);
+ }
if (slice_dir == -1)
scale->slice_y -= out_h;