Commit fdcb7a85 authored by Paul B Mahol's avatar Paul B Mahol

avfilter/vf_deband: add planes coupling mode

Signed-off-by: 's avatarPaul B Mahol <onemda@gmail.com>
parent 47cd8eff
...@@ -6203,11 +6203,16 @@ absolute value will be picked. For example direction 0, -PI or -2*PI radians ...@@ -6203,11 +6203,16 @@ absolute value will be picked. For example direction 0, -PI or -2*PI radians
will pick only pixels on same row and -PI/2 will pick only pixels on same will pick only pixels on same row and -PI/2 will pick only pixels on same
column. column.
@item blur @item blur, b
If enabled, current pixel is compared with average value of all four If enabled, current pixel is compared with average value of all four
surrounding pixels. The default is enabled. If disabled current pixel is surrounding pixels. The default is enabled. If disabled current pixel is
compared with all four surrounding pixels. The pixel is considered banded compared with all four surrounding pixels. The pixel is considered banded
if only all four differences with surrounding pixels are less than threshold. if only all four differences with surrounding pixels are less than threshold.
@item coupling, c
If enabled, current pixel is changed if and only if all pixel components are banded,
e.g. banding detection threshold is triggered for all color components.
The default is disabled.
@end table @end table
@anchor{decimate} @anchor{decimate}
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
typedef struct DebandContext { typedef struct DebandContext {
const AVClass *class; const AVClass *class;
int coupling;
float threshold[4]; float threshold[4];
int range; int range;
int blur; int blur;
...@@ -38,6 +39,7 @@ typedef struct DebandContext { ...@@ -38,6 +39,7 @@ typedef struct DebandContext {
int nb_components; int nb_components;
int planewidth[4]; int planewidth[4];
int planeheight[4]; int planeheight[4];
int shift[2];
int thr[4]; int thr[4];
int *x_pos; int *x_pos;
...@@ -59,6 +61,9 @@ static const AVOption deband_options[] = { ...@@ -59,6 +61,9 @@ static const AVOption deband_options[] = {
{ "direction", "set direction", OFFSET(direction), AV_OPT_TYPE_FLOAT, {.dbl=2*M_PI},-2*M_PI, 2*M_PI, FLAGS }, { "direction", "set direction", OFFSET(direction), AV_OPT_TYPE_FLOAT, {.dbl=2*M_PI},-2*M_PI, 2*M_PI, FLAGS },
{ "d", "set direction", OFFSET(direction), AV_OPT_TYPE_FLOAT, {.dbl=2*M_PI},-2*M_PI, 2*M_PI, FLAGS }, { "d", "set direction", OFFSET(direction), AV_OPT_TYPE_FLOAT, {.dbl=2*M_PI},-2*M_PI, 2*M_PI, FLAGS },
{ "blur", "set blur", OFFSET(blur), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, { "blur", "set blur", OFFSET(blur), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
{ "b", "set blur", OFFSET(blur), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS },
{ "coupling", "set plane coupling", OFFSET(coupling), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
{ "c", "set plane coupling", OFFSET(coupling), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS },
{ NULL } { NULL }
}; };
...@@ -66,6 +71,8 @@ AVFILTER_DEFINE_CLASS(deband); ...@@ -66,6 +71,8 @@ AVFILTER_DEFINE_CLASS(deband);
static int query_formats(AVFilterContext *ctx) static int query_formats(AVFilterContext *ctx)
{ {
DebandContext *s = ctx->priv;
static const enum AVPixelFormat pix_fmts[] = { static const enum AVPixelFormat pix_fmts[] = {
AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY16,
AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P,
...@@ -86,7 +93,21 @@ static int query_formats(AVFilterContext *ctx) ...@@ -86,7 +93,21 @@ static int query_formats(AVFilterContext *ctx)
AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16,
AV_PIX_FMT_NONE AV_PIX_FMT_NONE
}; };
AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts);
static const enum AVPixelFormat cpix_fmts[] = {
AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P,
AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P9,
AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA444P10,
AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14,
AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUVA444P16,
AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP,
AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10,
AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14,
AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16,
AV_PIX_FMT_NONE
};
AVFilterFormats *fmts_list = ff_make_format_list(s->coupling ? cpix_fmts : pix_fmts);
if (!fmts_list) if (!fmts_list)
return AVERROR(ENOMEM); return AVERROR(ENOMEM);
...@@ -158,6 +179,138 @@ static int deband_8_c(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) ...@@ -158,6 +179,138 @@ static int deband_8_c(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
return 0; return 0;
} }
static int deband_8_coupling_c(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{
DebandContext *s = ctx->priv;
ThreadData *td = arg;
AVFrame *in = td->in;
AVFrame *out = td->out;
const int start = (s->planeheight[0] * jobnr ) / nb_jobs;
const int end = (s->planeheight[0] * (jobnr+1)) / nb_jobs;
int x, y, p;
for (y = start; y < end; y++) {
const int pos = y * s->planewidth[0];
for (x = 0; x < s->planewidth[p]; x++) {
const int x_pos = s->x_pos[pos + x];
const int y_pos = s->y_pos[pos + x];
int avg[4], cmp[4] = { 0 }, src[4];
for (p = 0; p < s->nb_components; p++) {
const uint8_t *src_ptr = (const uint8_t *)in->data[p];
const int src_linesize = in->linesize[p];
const int thr = s->thr[p];
const int w = s->planewidth[p] - 1;
const int h = s->planeheight[p] - 1;
const int ref0 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)];
const int ref1 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)];
const int ref2 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)];
const int ref3 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)];
const int src0 = src_ptr[y * src_linesize + x];
src[p] = src0;
avg[p] = get_avg(ref0, ref1, ref2, ref3);
if (s->blur) {
cmp[p] = FFABS(src0 - avg[p]) < thr;
} else {
cmp[p] = (FFABS(src0 - ref0) < thr) &&
(FFABS(src0 - ref1) < thr) &&
(FFABS(src0 - ref2) < thr) &&
(FFABS(src0 - ref3) < thr);
}
}
for (p = 0; p < s->nb_components; p++)
if (!cmp[p])
break;
if (p == s->nb_components) {
for (p = 0; p < s->nb_components; p++) {
const int dst_linesize = out->linesize[p];
out->data[p][y * dst_linesize + x] = avg[p];
}
} else {
for (p = 0; p < s->nb_components; p++) {
const int dst_linesize = out->linesize[p];
out->data[p][y * dst_linesize + x] = src[p];
}
}
}
}
return 0;
}
static int deband_16_coupling_c(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{
DebandContext *s = ctx->priv;
ThreadData *td = arg;
AVFrame *in = td->in;
AVFrame *out = td->out;
const int start = (s->planeheight[0] * jobnr ) / nb_jobs;
const int end = (s->planeheight[0] * (jobnr+1)) / nb_jobs;
int x, y, p, z;
for (y = start; y < end; y++) {
const int pos = y * s->planewidth[0];
for (x = 0; x < s->planewidth[p]; x++) {
const int x_pos = s->x_pos[pos + x];
const int y_pos = s->y_pos[pos + x];
int avg[4], cmp[4] = { 0 }, src[4];
for (p = 0; p < s->nb_components; p++) {
const uint16_t *src_ptr = (const uint16_t *)in->data[p];
const int src_linesize = in->linesize[p] / 2;
const int thr = s->thr[p];
const int w = s->planewidth[p] - 1;
const int h = s->planeheight[p] - 1;
const int ref0 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)];
const int ref1 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + x_pos, 0, w)];
const int ref2 = src_ptr[av_clip(y + -y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)];
const int ref3 = src_ptr[av_clip(y + y_pos, 0, h) * src_linesize + av_clip(x + -x_pos, 0, w)];
const int src0 = src_ptr[y * src_linesize + x];
src[p] = src0;
avg[p] = get_avg(ref0, ref1, ref2, ref3);
if (s->blur) {
cmp[p] = FFABS(src0 - avg[p]) < thr;
} else {
cmp[p] = (FFABS(src0 - ref0) < thr) &&
(FFABS(src0 - ref1) < thr) &&
(FFABS(src0 - ref2) < thr) &&
(FFABS(src0 - ref3) < thr);
}
}
for (z = 0; z < s->nb_components; z++)
if (!cmp[z])
break;
if (z == s->nb_components) {
for (p = 0; p < s->nb_components; p++) {
const int dst_linesize = out->linesize[p] / 2;
uint16_t *dst = (uint16_t *)out->data[p] + y * dst_linesize + x;
dst[0] = avg[p];
}
} else {
for (p = 0; p < s->nb_components; p++) {
const int dst_linesize = out->linesize[p] / 2;
uint16_t *dst = (uint16_t *)out->data[p] + y * dst_linesize + x;
dst[0] = src[p];
}
}
}
}
return 0;
}
static int deband_16_c(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) static int deband_16_c(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
{ {
DebandContext *s = ctx->priv; DebandContext *s = ctx->priv;
...@@ -222,8 +375,13 @@ static int config_input(AVFilterLink *inlink) ...@@ -222,8 +375,13 @@ static int config_input(AVFilterLink *inlink)
s->planeheight[0] = s->planeheight[3] = inlink->h; s->planeheight[0] = s->planeheight[3] = inlink->h;
s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
s->planewidth[0] = s->planewidth[3] = inlink->w; s->planewidth[0] = s->planewidth[3] = inlink->w;
s->shift[0] = desc->log2_chroma_w;
s->shift[1] = desc->log2_chroma_h;
s->deband = desc->comp[0].depth > 8 ? deband_16_c : deband_8_c; if (s->coupling)
s->deband = desc->comp[0].depth > 8 ? deband_16_coupling_c : deband_8_coupling_c;
else
s->deband = desc->comp[0].depth > 8 ? deband_16_c : deband_8_c;
s->thr[0] = ((1 << desc->comp[0].depth) - 1) * s->threshold[0]; s->thr[0] = ((1 << desc->comp[0].depth) - 1) * s->threshold[0];
s->thr[1] = ((1 << desc->comp[1].depth) - 1) * s->threshold[1]; s->thr[1] = ((1 << desc->comp[1].depth) - 1) * s->threshold[1];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment