|
|
|
@ -97,11 +97,13 @@ typedef struct ThreadData { |
|
|
|
|
|
|
|
|
|
int h; |
|
|
|
|
|
|
|
|
|
float fimin[4]; |
|
|
|
|
float fomin[4]; |
|
|
|
|
int imin[4]; |
|
|
|
|
int omin[4]; |
|
|
|
|
} ThreadData; |
|
|
|
|
|
|
|
|
|
#define DO_COMMON(type, clip, preserve, planar) \ |
|
|
|
|
#define DO_COMMON(type, ptype, clip, preserve, planar) \ |
|
|
|
|
const ThreadData *td = arg; \
|
|
|
|
|
const int linesize = s->linesize; \
|
|
|
|
|
const int step = s->step; \
|
|
|
|
@ -118,14 +120,14 @@ typedef struct ThreadData { |
|
|
|
|
type *dst_g = (type *)(td->dstrow[G]) + src_linesize * slice_start; \
|
|
|
|
|
type *dst_b = (type *)(td->dstrow[B]) + src_linesize * slice_start; \
|
|
|
|
|
type *dst_a = (type *)(td->dstrow[A]) + src_linesize * slice_start; \
|
|
|
|
|
const int imin_r = td->imin[R]; \
|
|
|
|
|
const int imin_g = td->imin[G]; \
|
|
|
|
|
const int imin_b = td->imin[B]; \
|
|
|
|
|
const int imin_a = td->imin[A]; \
|
|
|
|
|
const int omin_r = td->omin[R]; \
|
|
|
|
|
const int omin_g = td->omin[G]; \
|
|
|
|
|
const int omin_b = td->omin[B]; \
|
|
|
|
|
const int omin_a = td->omin[A]; \
|
|
|
|
|
const ptype imin_r = s->depth == 32 ? td->fimin[R] : td->imin[R]; \
|
|
|
|
|
const ptype imin_g = s->depth == 32 ? td->fimin[G] : td->imin[G]; \
|
|
|
|
|
const ptype imin_b = s->depth == 32 ? td->fimin[B] : td->imin[B]; \
|
|
|
|
|
const ptype imin_a = s->depth == 32 ? td->fimin[A] : td->imin[A]; \
|
|
|
|
|
const ptype omin_r = s->depth == 32 ? td->fomin[R] : td->omin[R]; \
|
|
|
|
|
const ptype omin_g = s->depth == 32 ? td->fomin[G] : td->omin[G]; \
|
|
|
|
|
const ptype omin_b = s->depth == 32 ? td->fomin[B] : td->omin[B]; \
|
|
|
|
|
const ptype omin_a = s->depth == 32 ? td->fomin[A] : td->omin[A]; \
|
|
|
|
|
const float coeff_r = td->coeff[R]; \
|
|
|
|
|
const float coeff_g = td->coeff[G]; \
|
|
|
|
|
const float coeff_b = td->coeff[B]; \
|
|
|
|
@ -133,12 +135,12 @@ typedef struct ThreadData { |
|
|
|
|
\
|
|
|
|
|
for (int y = slice_start; y < slice_end; y++) { \
|
|
|
|
|
for (int x = 0; x < linesize; x += step) { \
|
|
|
|
|
int ir, ig, ib, or, og, ob; \
|
|
|
|
|
ptype ir, ig, ib, or, og, ob; \
|
|
|
|
|
ir = src_r[x]; \
|
|
|
|
|
ig = src_g[x]; \
|
|
|
|
|
ib = src_b[x]; \
|
|
|
|
|
if (preserve) { \
|
|
|
|
|
float ratio, icolor, ocolor, max = s->max; \
|
|
|
|
|
float ratio, icolor, ocolor, max = s->depth==32 ? 1.f : s->max; \
|
|
|
|
|
\
|
|
|
|
|
or = (ir - imin_r) * coeff_r + omin_r; \
|
|
|
|
|
og = (ig - imin_g) * coeff_g + omin_g; \
|
|
|
|
@ -180,39 +182,40 @@ typedef struct ThreadData { |
|
|
|
|
|
|
|
|
|
#define CLIP8(x, depth) av_clip_uint8(x) |
|
|
|
|
#define CLIP16(x, depth) av_clip_uint16(x) |
|
|
|
|
#define NOCLIP(x, depth) (x) |
|
|
|
|
|
|
|
|
|
static int colorlevels_slice_8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
DO_COMMON(uint8_t, CLIP8, 0, 0) |
|
|
|
|
DO_COMMON(uint8_t, int, CLIP8, 0, 0) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int colorlevels_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv;\
|
|
|
|
|
DO_COMMON(uint16_t, CLIP16, 0, 0) |
|
|
|
|
DO_COMMON(uint16_t, int, CLIP16, 0, 0) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int colorlevels_preserve_slice_8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
DO_COMMON(uint8_t, CLIP8, 1, 0) |
|
|
|
|
DO_COMMON(uint8_t, int, CLIP8, 1, 0) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int colorlevels_preserve_slice_16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
DO_COMMON(uint16_t, CLIP16, 1, 0) |
|
|
|
|
DO_COMMON(uint16_t, int, CLIP16, 1, 0) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int colorlevels_slice_8_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
DO_COMMON(uint8_t, CLIP8, 0, 1) |
|
|
|
|
DO_COMMON(uint8_t, int, CLIP8, 0, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -220,7 +223,7 @@ static int colorlevels_slice_9_planar(AVFilterContext *ctx, void *arg, int jobnr |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
const int depth = 9; |
|
|
|
|
DO_COMMON(uint16_t, av_clip_uintp2, 0, 1) |
|
|
|
|
DO_COMMON(uint16_t, int, av_clip_uintp2, 0, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -228,7 +231,7 @@ static int colorlevels_slice_10_planar(AVFilterContext *ctx, void *arg, int jobn |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
const int depth = 10; |
|
|
|
|
DO_COMMON(uint16_t, av_clip_uintp2, 0, 1) |
|
|
|
|
DO_COMMON(uint16_t, int, av_clip_uintp2, 0, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -236,7 +239,7 @@ static int colorlevels_slice_12_planar(AVFilterContext *ctx, void *arg, int jobn |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
const int depth = 12; |
|
|
|
|
DO_COMMON(uint16_t, av_clip_uintp2, 0, 1) |
|
|
|
|
DO_COMMON(uint16_t, int, av_clip_uintp2, 0, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -244,21 +247,28 @@ static int colorlevels_slice_14_planar(AVFilterContext *ctx, void *arg, int jobn |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
const int depth = 14; |
|
|
|
|
DO_COMMON(uint16_t, av_clip_uintp2, 0, 1) |
|
|
|
|
DO_COMMON(uint16_t, int, av_clip_uintp2, 0, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int colorlevels_slice_16_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
DO_COMMON(uint16_t, CLIP16, 0, 1) |
|
|
|
|
DO_COMMON(uint16_t, int, CLIP16, 0, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int colorlevels_slice_32_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
DO_COMMON(float, float, NOCLIP, 0, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int colorlevels_preserve_slice_8_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
DO_COMMON(uint8_t, CLIP8, 1, 1) |
|
|
|
|
DO_COMMON(uint8_t, int, CLIP8, 1, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -266,7 +276,7 @@ static int colorlevels_preserve_slice_9_planar(AVFilterContext *ctx, void *arg, |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
const int depth = 9; |
|
|
|
|
DO_COMMON(uint16_t, av_clip_uintp2, 1, 1) |
|
|
|
|
DO_COMMON(uint16_t, int, av_clip_uintp2, 1, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -274,7 +284,7 @@ static int colorlevels_preserve_slice_10_planar(AVFilterContext *ctx, void *arg, |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
const int depth = 10; |
|
|
|
|
DO_COMMON(uint16_t, av_clip_uintp2, 1, 1) |
|
|
|
|
DO_COMMON(uint16_t, int, av_clip_uintp2, 1, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -282,7 +292,7 @@ static int colorlevels_preserve_slice_12_planar(AVFilterContext *ctx, void *arg, |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
const int depth = 12; |
|
|
|
|
DO_COMMON(uint16_t, av_clip_uintp2, 1, 1) |
|
|
|
|
DO_COMMON(uint16_t, int, av_clip_uintp2, 1, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -290,14 +300,21 @@ static int colorlevels_preserve_slice_14_planar(AVFilterContext *ctx, void *arg, |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
const int depth = 14; |
|
|
|
|
DO_COMMON(uint16_t, av_clip_uintp2, 1, 1) |
|
|
|
|
DO_COMMON(uint16_t, int, av_clip_uintp2, 1, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int colorlevels_preserve_slice_16_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
DO_COMMON(uint16_t, CLIP16, 1, 1) |
|
|
|
|
DO_COMMON(uint16_t, int, CLIP16, 1, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int colorlevels_preserve_slice_32_planar(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) |
|
|
|
|
{ |
|
|
|
|
ColorLevelsContext *s = ctx->priv; |
|
|
|
|
DO_COMMON(float, float, NOCLIP, 1, 1) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -349,6 +366,10 @@ static int config_input(AVFilterLink *inlink) |
|
|
|
|
s->colorlevels_slice[0] = colorlevels_slice_16_planar; |
|
|
|
|
s->colorlevels_slice[1] = colorlevels_preserve_slice_16_planar; |
|
|
|
|
break; |
|
|
|
|
case 32: |
|
|
|
|
s->colorlevels_slice[0] = colorlevels_slice_32_planar; |
|
|
|
|
s->colorlevels_slice[1] = colorlevels_preserve_slice_32_planar; |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -479,6 +500,46 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
|
|
|
|
td.omin[i] = omin; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case 4: |
|
|
|
|
for (int i = 0; i < s->nb_comp; i++) { |
|
|
|
|
Range *r = &s->range[i]; |
|
|
|
|
const uint8_t offset = s->rgba_map[i]; |
|
|
|
|
const uint8_t *srcrow = in->data[0]; |
|
|
|
|
float imin = r->in_min; |
|
|
|
|
float imax = r->in_max; |
|
|
|
|
float omin = r->out_min; |
|
|
|
|
float omax = r->out_max; |
|
|
|
|
float coeff; |
|
|
|
|
|
|
|
|
|
if (imin < 0.f) { |
|
|
|
|
imin = 1.f; |
|
|
|
|
for (int y = 0; y < inlink->h; y++) { |
|
|
|
|
const float *src = (const float *)srcrow; |
|
|
|
|
|
|
|
|
|
for (int x = 0; x < s->linesize; x += step) |
|
|
|
|
imin = fminf(imin, src[x + offset]); |
|
|
|
|
srcrow += in->linesize[0]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (imax < 0.f) { |
|
|
|
|
srcrow = in->data[0]; |
|
|
|
|
imax = 0.f; |
|
|
|
|
for (int y = 0; y < inlink->h; y++) { |
|
|
|
|
const float *src = (const float *)srcrow; |
|
|
|
|
|
|
|
|
|
for (int x = 0; x < s->linesize; x += step) |
|
|
|
|
imax = fmaxf(imax, src[x + offset]); |
|
|
|
|
srcrow += in->linesize[0]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
coeff = (omax - omin) / (double)(imax - imin); |
|
|
|
|
|
|
|
|
|
td.coeff[i] = coeff; |
|
|
|
|
td.fimin[i] = imin; |
|
|
|
|
td.fomin[i] = omin; |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ff_filter_execute(ctx, s->colorlevels_slice[s->preserve_color > 0], &td, NULL, |
|
|
|
@ -524,7 +585,8 @@ const AVFilter ff_vf_colorlevels = { |
|
|
|
|
AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, |
|
|
|
|
AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, |
|
|
|
|
AV_PIX_FMT_GBRP14, |
|
|
|
|
AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16), |
|
|
|
|
AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, |
|
|
|
|
AV_PIX_FMT_GBRPF32, AV_PIX_FMT_GBRAPF32), |
|
|
|
|
.flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, |
|
|
|
|
.process_command = ff_filter_process_command, |
|
|
|
|
}; |
|
|
|
|