lavfi/hue: use lookup tables
Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
parent
ca7f637a1e
commit
e6876c7b7b
@ -73,6 +73,8 @@ typedef struct {
|
|||||||
int32_t hue_sin;
|
int32_t hue_sin;
|
||||||
int32_t hue_cos;
|
int32_t hue_cos;
|
||||||
double var_values[VAR_NB];
|
double var_values[VAR_NB];
|
||||||
|
uint8_t lut_u[256][256];
|
||||||
|
uint8_t lut_v[256][256];
|
||||||
} HueContext;
|
} HueContext;
|
||||||
|
|
||||||
#define OFFSET(x) offsetof(HueContext, x)
|
#define OFFSET(x) offsetof(HueContext, x)
|
||||||
@ -94,12 +96,43 @@ static inline void compute_sin_and_cos(HueContext *hue)
|
|||||||
/*
|
/*
|
||||||
* Scale the value to the norm of the resulting (U,V) vector, that is
|
* Scale the value to the norm of the resulting (U,V) vector, that is
|
||||||
* the saturation.
|
* the saturation.
|
||||||
* This will be useful in the process_chrominance function.
|
* This will be useful in the apply_lut function.
|
||||||
*/
|
*/
|
||||||
hue->hue_sin = rint(sin(hue->hue) * (1 << 16) * hue->saturation);
|
hue->hue_sin = rint(sin(hue->hue) * (1 << 16) * hue->saturation);
|
||||||
hue->hue_cos = rint(cos(hue->hue) * (1 << 16) * hue->saturation);
|
hue->hue_cos = rint(cos(hue->hue) * (1 << 16) * hue->saturation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void create_chrominance_lut(HueContext *h, const int32_t c,
|
||||||
|
const int32_t s)
|
||||||
|
{
|
||||||
|
int32_t i, j, u, v, new_u, new_v;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we consider U and V as the components of a 2D vector then its angle
|
||||||
|
* is the hue and the norm is the saturation
|
||||||
|
*/
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
for (j = 0; j < 256; j++) {
|
||||||
|
/* Normalize the components from range [16;140] to [-112;112] */
|
||||||
|
u = i - 128;
|
||||||
|
v = j - 128;
|
||||||
|
/*
|
||||||
|
* Apply the rotation of the vector : (c * u) - (s * v)
|
||||||
|
* (s * u) + (c * v)
|
||||||
|
* De-normalize the components (without forgetting to scale 128
|
||||||
|
* by << 16)
|
||||||
|
* Finally scale back the result by >> 16
|
||||||
|
*/
|
||||||
|
new_u = ((c * u) - (s * v) + (1 << 15) + (128 << 16)) >> 16;
|
||||||
|
new_v = ((s * u) + (c * v) + (1 << 15) + (128 << 16)) >> 16;
|
||||||
|
|
||||||
|
/* Prevent a potential overflow */
|
||||||
|
h->lut_u[i][j] = av_clip_uint8_c(new_u);
|
||||||
|
h->lut_v[i][j] = av_clip_uint8_c(new_v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int set_expr(AVExpr **pexpr_ptr, char **expr_ptr,
|
static int set_expr(AVExpr **pexpr_ptr, char **expr_ptr,
|
||||||
const char *expr, const char *option, void *log_ctx)
|
const char *expr, const char *option, void *log_ctx)
|
||||||
{
|
{
|
||||||
@ -202,36 +235,20 @@ static int config_props(AVFilterLink *inlink)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_chrominance(uint8_t *udst, uint8_t *vdst, const int dst_linesize,
|
static void apply_lut(HueContext *s,
|
||||||
|
uint8_t *udst, uint8_t *vdst, const int dst_linesize,
|
||||||
uint8_t *usrc, uint8_t *vsrc, const int src_linesize,
|
uint8_t *usrc, uint8_t *vsrc, const int src_linesize,
|
||||||
int w, int h,
|
int w, int h)
|
||||||
const int32_t c, const int32_t s)
|
|
||||||
{
|
{
|
||||||
int32_t u, v, new_u, new_v;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
|
||||||
* If we consider U and V as the components of a 2D vector then its angle
|
|
||||||
* is the hue and the norm is the saturation
|
|
||||||
*/
|
|
||||||
while (h--) {
|
while (h--) {
|
||||||
for (i = 0; i < w; i++) {
|
for (i = 0; i < w; i++) {
|
||||||
/* Normalize the components from range [16;140] to [-112;112] */
|
const int u = usrc[i];
|
||||||
u = usrc[i] - 128;
|
const int v = vsrc[i];
|
||||||
v = vsrc[i] - 128;
|
|
||||||
/*
|
|
||||||
* Apply the rotation of the vector : (c * u) - (s * v)
|
|
||||||
* (s * u) + (c * v)
|
|
||||||
* De-normalize the components (without forgetting to scale 128
|
|
||||||
* by << 16)
|
|
||||||
* Finally scale back the result by >> 16
|
|
||||||
*/
|
|
||||||
new_u = ((c * u) - (s * v) + (1 << 15) + (128 << 16)) >> 16;
|
|
||||||
new_v = ((s * u) + (c * v) + (1 << 15) + (128 << 16)) >> 16;
|
|
||||||
|
|
||||||
/* Prevent a potential overflow */
|
udst[i] = s->lut_u[u][v];
|
||||||
udst[i] = av_clip_uint8_c(new_u);
|
vdst[i] = s->lut_v[u][v];
|
||||||
vdst[i] = av_clip_uint8_c(new_v);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
usrc += src_linesize;
|
usrc += src_linesize;
|
||||||
@ -249,6 +266,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
|
|||||||
HueContext *hue = inlink->dst->priv;
|
HueContext *hue = inlink->dst->priv;
|
||||||
AVFilterLink *outlink = inlink->dst->outputs[0];
|
AVFilterLink *outlink = inlink->dst->outputs[0];
|
||||||
AVFrame *outpic;
|
AVFrame *outpic;
|
||||||
|
const int32_t old_hue_sin = hue->hue_sin, old_hue_cos = hue->hue_cos;
|
||||||
int direct = 0;
|
int direct = 0;
|
||||||
|
|
||||||
if (av_frame_is_writable(inpic)) {
|
if (av_frame_is_writable(inpic)) {
|
||||||
@ -292,6 +310,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
|
|||||||
hue->var_values[VAR_T], (int)hue->var_values[VAR_N]);
|
hue->var_values[VAR_T], (int)hue->var_values[VAR_N]);
|
||||||
|
|
||||||
compute_sin_and_cos(hue);
|
compute_sin_and_cos(hue);
|
||||||
|
if (old_hue_sin != hue->hue_sin || old_hue_cos != hue->hue_cos)
|
||||||
|
create_chrominance_lut(hue, hue->hue_cos, hue->hue_sin);
|
||||||
|
|
||||||
if (!direct) {
|
if (!direct) {
|
||||||
av_image_copy_plane(outpic->data[0], outpic->linesize[0],
|
av_image_copy_plane(outpic->data[0], outpic->linesize[0],
|
||||||
@ -303,11 +323,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
|
|||||||
inlink->w, inlink->h);
|
inlink->w, inlink->h);
|
||||||
}
|
}
|
||||||
|
|
||||||
process_chrominance(outpic->data[1], outpic->data[2], outpic->linesize[1],
|
apply_lut(hue, outpic->data[1], outpic->data[2], outpic->linesize[1],
|
||||||
inpic->data[1], inpic->data[2], inpic->linesize[1],
|
inpic->data[1], inpic->data[2], inpic->linesize[1],
|
||||||
FF_CEIL_RSHIFT(inlink->w, hue->hsub),
|
FF_CEIL_RSHIFT(inlink->w, hue->hsub),
|
||||||
FF_CEIL_RSHIFT(inlink->h, hue->vsub),
|
FF_CEIL_RSHIFT(inlink->h, hue->vsub));
|
||||||
hue->hue_cos, hue->hue_sin);
|
|
||||||
|
|
||||||
if (!direct)
|
if (!direct)
|
||||||
av_frame_free(&inpic);
|
av_frame_free(&inpic);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user