[FFmpeg-cvslog] lavfi/hue: use lookup tables
Paul B Mahol
git at videolan.org
Wed Aug 21 17:39:51 CEST 2013
ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Mon Aug 19 19:09:58 2013 +0000| [e6876c7b7b5524fcb6acadf711cda592687402f7] | committer: Paul B Mahol
lavfi/hue: use lookup tables
Signed-off-by: Paul B Mahol <onemda at gmail.com>
> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=e6876c7b7b5524fcb6acadf711cda592687402f7
---
libavfilter/vf_hue.c | 79 +++++++++++++++++++++++++++++++-------------------
1 file changed, 49 insertions(+), 30 deletions(-)
diff --git a/libavfilter/vf_hue.c b/libavfilter/vf_hue.c
index cc8ac78..d066c40 100644
--- a/libavfilter/vf_hue.c
+++ b/libavfilter/vf_hue.c
@@ -73,6 +73,8 @@ typedef struct {
int32_t hue_sin;
int32_t hue_cos;
double var_values[VAR_NB];
+ uint8_t lut_u[256][256];
+ uint8_t lut_v[256][256];
} HueContext;
#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
* 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_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,
const char *expr, const char *option, void *log_ctx)
{
@@ -202,36 +235,20 @@ static int config_props(AVFilterLink *inlink)
return 0;
}
-static void process_chrominance(uint8_t *udst, uint8_t *vdst, const int dst_linesize,
- uint8_t *usrc, uint8_t *vsrc, const int src_linesize,
- int w, int h,
- const int32_t c, const int32_t s)
+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,
+ int w, int h)
{
- int32_t u, v, new_u, new_v;
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--) {
for (i = 0; i < w; i++) {
- /* Normalize the components from range [16;140] to [-112;112] */
- u = usrc[i] - 128;
- 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;
+ const int u = usrc[i];
+ const int v = vsrc[i];
- /* Prevent a potential overflow */
- udst[i] = av_clip_uint8_c(new_u);
- vdst[i] = av_clip_uint8_c(new_v);
+ udst[i] = s->lut_u[u][v];
+ vdst[i] = s->lut_v[u][v];
}
usrc += src_linesize;
@@ -249,6 +266,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
HueContext *hue = inlink->dst->priv;
AVFilterLink *outlink = inlink->dst->outputs[0];
AVFrame *outpic;
+ const int32_t old_hue_sin = hue->hue_sin, old_hue_cos = hue->hue_cos;
int direct = 0;
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]);
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) {
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);
}
- process_chrominance(outpic->data[1], outpic->data[2], outpic->linesize[1],
- inpic->data[1], inpic->data[2], inpic->linesize[1],
- FF_CEIL_RSHIFT(inlink->w, hue->hsub),
- FF_CEIL_RSHIFT(inlink->h, hue->vsub),
- hue->hue_cos, hue->hue_sin);
+ apply_lut(hue, outpic->data[1], outpic->data[2], outpic->linesize[1],
+ inpic->data[1], inpic->data[2], inpic->linesize[1],
+ FF_CEIL_RSHIFT(inlink->w, hue->hsub),
+ FF_CEIL_RSHIFT(inlink->h, hue->vsub));
if (!direct)
av_frame_free(&inpic);
More information about the ffmpeg-cvslog
mailing list