|
|
|
@@ -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; |
|
|
|
|