[vlc-devel] [PATCH 2/6] OldMovie: Old movie style video filter

Vianney Boyer vlcvboyer at gmail.com
Thu Jul 25 07:41:38 CEST 2013



New video filter making the video like an old movie (projector, damages 
on film...)


---
  modules/video_filter/oldmovie.c | 862 
++++++++++++++++++++++++++++++++++++++++
  modules/video_filter/oldmovie.h | 106 +++++
  2 files changed, 968 insertions(+)
  create mode 100644 modules/video_filter/oldmovie.c
  create mode 100644 modules/video_filter/oldmovie.h

diff --git a/modules/video_filter/oldmovie.c 
b/modules/video_filter/oldmovie.c
new file mode 100644
index 0000000..6d2fc8e
--- /dev/null
+++ b/modules/video_filter/oldmovie.c
@@ -0,0 +1,862 @@
+/*****************************************************************************
+ * oldmovie.c : Old movie effect video filter
+ 
*****************************************************************************
+ * Copyright (C) 2013      Vianney Boyer
+ * $Id$
+ *
+ * Authors: Vianney Boyer <vlcvboyer -at- gmail -dot- com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ 
*****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ 
*****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <math.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_filter.h>
+#include <vlc_rand.h>
+#include <vlc_mtime.h>
+
+#include "filter_picture.h"
+
+#include "oldmovie.h"
+
+#ifndef M_PI
+#   define M_PI 3.14159265358979323846
+#endif
+#ifndef MOD
+#   define MOD(a, b) ((((a)%(b)) + (b))%(b))
+#endif
+#ifndef TIME_UNIT_PER_S
+#   define TIME_UNIT_PER_S ( ((int64_t) 1) << 32 )
+#endif
+
+#define SUB_MIN(val, sub_val, min) val = \
+ ((val-(int32_t)sub_val)<min?min:val-sub_val)
+#define ADD_MAX(val, add_val, max) val = \
+ ((val+(int32_t)add_val)>max?max:val+add_val)
+
+#define PIX_OFS(i_x, i_y, s_plane) ( \
+        (i_x) * s_plane.i_pixel_pitch \
+      + (i_y) * s_plane.i_pitch \
+    )
+
+#define CHECK_PIX_OFS(i_x, i_y, s_plane) ( \
+        (i_x) >= 0 && (i_y) >= 0 && \
+        (i_x) * s_plane.i_pixel_pitch < s_plane.i_visible_pitch && \
+        (i_y) < s_plane.i_visible_lines \
+    )
+
+#define DARKEN_PIXEL(i_x, i_y, intensity, s_plane) \
+        SUB_MIN(s_plane.p_pixels[ PIX_OFS(i_x, i_y, s_plane) ], 
intensity, 0)
+
+#define LIGHTEN_PIXEL(i_x, i_y, intensity, s_plane) \
+        ADD_MAX(s_plane.p_pixels[PIX_OFS(i_x, i_y, s_plane)], 
intensity, 0xFF)
+
+#define CHECK_N_DARKEN_PIXEL(i_x, i_y, intensity, s_plane) \
+        if ( CHECK_PIX_OFS(i_x, i_y, s_plane) ) \
+            DARKEN_PIXEL(i_x, i_y, intensity, s_plane) \
+
+#define CHECK_N_LIGHTEN_PIXEL(i_x, i_y, intensity, s_plane) \
+        if ( CHECK_PIX_OFS(i_x, i_y, s_plane) ) \
+            LIGHTEN_PIXEL(i_x, i_y, intensity, s_plane) \
+
+/*****************************************************************************
+ * Prototypes
+ 
*****************************************************************************/
+
+void oldmovie_define_hair_location( filter_t *p_filter, hair_t* ps_hair );
+void oldmovie_define_dust_location( filter_t *p_filter, dust_t* ps_dust );
+int  oldmovie_sliding_offset_apply( filter_t *p_filter, picture_t 
*p_pic_out );
+
+/*****************************************************************************
+ * Module descriptor
+ 
*****************************************************************************/
+
+#define CFG_PREFIX "oldmovie-"
+
+int  Open ( vlc_object_t * );
+void Close( vlc_object_t * );
+
+vlc_module_begin()
+    set_description( N_("Old movie effect video filter") )
+    set_shortname( N_( "Old movie" ))
+    set_capability( "video filter2", 0 )
+    set_category( CAT_VIDEO )
+    set_subcategory( SUBCAT_VIDEO_VFILTER )
+
+    set_callbacks( Open, Close )
+vlc_module_end()
+
+/**
+ * Open the filter
+ */
+int Open( vlc_object_t *p_this )
+{
+    filter_t *p_filter = (filter_t *)p_this;
+    filter_sys_t *p_sys;
+
+    /* Assert video in match with video out */
+    if( !es_format_IsSimilar( &p_filter->fmt_in, &p_filter->fmt_out ) ) {
+        msg_Err( p_filter, "Input and output format does not match" );
+        return VLC_EGENERIC;
+    }
+
+    /* Reject 0 bpp and unsupported chroma */
+    const vlc_fourcc_t fourcc = p_filter->fmt_in.video.i_chroma;
+    const vlc_chroma_description_t *p_chroma =
+        vlc_fourcc_GetChromaDescription( p_filter->fmt_in.video.i_chroma );
+    if( !p_chroma || p_chroma->pixel_size == 0
+        || p_chroma->plane_count < 3 || p_chroma->pixel_size > 1
+        || !vlc_fourcc_IsYUV( fourcc ) )
+    {
+        msg_Err( p_filter, "Unsupported chroma (%4.4s)", (char*)&fourcc );
+        return VLC_EGENERIC;
+    }
+
+    /* Allocate structure */
+    p_filter->p_sys = p_sys = calloc(1, sizeof( *p_sys ) );
+    if( !p_sys )
+        return VLC_ENOMEM;
+
+    /* init data */
+    p_filter->pf_video_filter = Filter;
+    p_sys->i_start_time = p_sys->i_cur_time = p_sys->i_last_time = 
NTPtime64();
+
+    return VLC_SUCCESS;
+}
+
+/**
+ * Close the filter
+ */
+void Close( vlc_object_t *p_this ) {
+    filter_t *p_filter = (filter_t *)p_this;
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    /* Free allocated memory */
+    oldmovie_free_allocated_data( p_filter );
+    free( p_sys );
+}
+
+/**
+ * Filter a picture
+ */
+picture_t *Filter( filter_t *p_filter, picture_t *p_pic_in ) {
+    if( !p_pic_in || !p_filter) return NULL;
+
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    picture_t *p_pic_out = filter_NewPicture( p_filter );
+    if( !p_pic_out ) {
+        picture_Release( p_pic_in );
+        return NULL;
+    }
+
+   /*
+    * manage time
+    */
+    p_sys->i_last_time = p_sys->i_cur_time;
+    p_sys->i_cur_time = NTPtime64();
+
+   /*
+    * allocate data
+    */
+    if ( !p_sys->b_init )
+        if (oldmovie_allocate_data( p_filter, p_pic_in ) != VLC_SUCCESS)
+        {
+            picture_Release( p_pic_in );
+            return NULL;
+        }
+    p_sys->b_init = true;
+
+   /*
+    * preset output pic: raw copy src to dst
+    */
+    picture_CopyPixels(p_pic_out, p_pic_in);
+
+   /*
+    * apply several effects on picture
+    */
+    oldmovie_black_n_white_effect( p_pic_out );
+
+    /* simulates projector shutter blinking effect */
+    oldmovie_shutter_effect(p_filter, p_pic_out);
+
+    if ( oldmovie_sliding_offset_effect( p_filter, p_pic_out ) != 
VLC_SUCCESS)
+        return CopyInfoAndRelease( p_pic_out, p_pic_in );
+
+    oldmovie_dark_border_effect( p_filter, p_pic_out );
+
+    if (oldmovie_film_scratch_effect(p_filter, p_pic_out) != VLC_SUCCESS)
+        return CopyInfoAndRelease( p_pic_out, p_pic_in );
+
+    oldmovie_film_blotch_effect(p_filter, p_pic_out);
+
+    if (oldmovie_lens_hair_effect( p_filter, p_pic_out ) != VLC_SUCCESS)
+        return CopyInfoAndRelease( p_pic_out, p_pic_in );
+
+    if (oldmovie_lens_dust_effect( p_filter, p_pic_out ) != VLC_SUCCESS)
+        return CopyInfoAndRelease( p_pic_out, p_pic_in );
+
+    oldmovie_film_dust_effect( p_filter, p_pic_out );
+
+    return CopyInfoAndRelease( p_pic_out, p_pic_in );
+}
+
+/*
+ * Allocate data
+ */
+int oldmovie_allocate_data( filter_t *p_filter, picture_t *p_pic_in ) {
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    oldmovie_free_allocated_data( p_filter );
+
+   /*
+    * take into account different characteristics for each plane
+    */
+    p_sys->i_planes = p_pic_in->i_planes;
+    p_sys->i_height = calloc( p_sys->i_planes, 
sizeof(*(p_sys->i_height)) );
+    p_sys->i_width  = calloc( p_sys->i_planes, sizeof(*(p_sys->i_width)) );
+    p_sys->i_visible_pitch
+                 = calloc( p_sys->i_planes, 
sizeof(*(p_sys->i_visible_pitch)));
+
+    if( !p_sys->i_height || !p_sys->i_width || !p_sys->i_visible_pitch ) {
+        oldmovie_free_allocated_data( p_filter );
+        return VLC_ENOMEM;
+    }
+
+    for (int32_t i_p=0; i_p < p_sys->i_planes; i_p++) {
+        p_sys->i_visible_pitch [i_p] = (int) 
p_pic_in->p[i_p].i_visible_pitch;
+        p_sys->i_height[i_p] = (int) p_pic_in->p[i_p].i_visible_lines;
+        p_sys->i_width [i_p] = (int) p_pic_in->p[i_p].i_visible_pitch
+                                         / p_pic_in->p[i_p].i_pixel_pitch;
+    }
+    return VLC_SUCCESS;
+}
+
+/**
+ * Free allocated data
+ */
+void oldmovie_free_allocated_data( filter_t *p_filter ) {
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    for (uint32_t i_s=0; i_s < MAX_SCRATCH; i_s++)
+        if (p_sys->p_scratch[i_s])
+            FREENULL(p_sys->p_scratch[i_s]);
+
+    for (uint32_t i_h=0; i_h < MAX_HAIR; i_h++)
+        if (p_sys->p_hair[i_h])
+            FREENULL(p_sys->p_hair[i_h]);
+
+    for (uint32_t i_d=0; i_d < MAX_DUST; i_d++)
+        if (p_sys->p_dust[i_d])
+            FREENULL(p_sys->p_dust[i_d]);
+
+    p_sys->i_planes = 0;
+    if (p_sys->i_height) FREENULL( p_sys->i_height );
+    if (p_sys->i_width)  FREENULL( p_sys->i_width );
+    if (p_sys->i_visible_pitch)  FREENULL( p_sys->i_visible_pitch );
+}
+
+/**
+ * Projector shutter effect
+ */
+void oldmovie_shutter_effect( filter_t *p_filter, picture_t *p_pic_out )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+#define SHUTTER_FREQ      2   // 4
+#define SHUTTER_SPEED     25  //15
+#define SHUTTER_HEIGHT    1.5 // 2
+
+#define SHUTTER_INTENSITY 50
+
+#define SUB_FRAME (p_sys->i_cur_time % (TIME_UNIT_PER_S / SHUTTER_FREQ))
+
+   /*
+    * depending on current time: define shutter location on picture
+    */
+    int32_t i_shutter_sup =
+                VLC_CLIP((int64_t)SUB_FRAME
+                    * p_pic_out->p[Y_PLANE].i_visible_lines
+                    * SHUTTER_SPEED / TIME_UNIT_PER_S,
+                    0, p_pic_out->p[Y_PLANE].i_visible_lines);
+
+    int32_t i_shutter_inf =
+                VLC_CLIP((int64_t)SUB_FRAME
+                    * p_pic_out->p[Y_PLANE].i_visible_lines
+                    * SHUTTER_SPEED / TIME_UNIT_PER_S
+                    - SHUTTER_HEIGHT * 
p_pic_out->p[Y_PLANE].i_visible_lines,
+                    0, p_pic_out->p[Y_PLANE].i_visible_lines);
+
+    int32_t i_width = p_pic_out->p[Y_PLANE].i_visible_pitch
+                / p_pic_out->p[Y_PLANE].i_pixel_pitch;
+
+   /*
+    * darken pixels currently occulted by shutter
+    */
+    for (int32_t i_y = i_shutter_inf; i_y < i_shutter_sup; i_y++)
+        for (int32_t i_x=0; i_x < i_width; i_x++)
+            DARKEN_PIXEL(i_x, i_y, SHUTTER_INTENSITY, 
p_pic_out->p[Y_PLANE]);
+}
+
+/**
+ * sliding & offset effect
+ */
+int oldmovie_sliding_offset_effect( filter_t *p_filter, picture_t 
*p_pic_out )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+
+   /**
+    * one shot offset section
+    */
+
+#define OFFSET_AVERAGE_PERIOD   (10 * TIME_UNIT_PER_S)
+
+    /* start trigger to be (re)initialized */
+    if (p_sys->i_offset_trigger == 0
+        || p_sys->i_sliding_speed != 0) /* do not mix sliding and offset */
+    {
+        /* random trigger for offset effect */
+        p_sys->i_offset_trigger
+            = p_sys->i_cur_time
+            + ((uint64_t) vlc_mrand48() ) % OFFSET_AVERAGE_PERIOD
+            + OFFSET_AVERAGE_PERIOD / 2;
+        p_sys->i_offset_ofs = 0;
+    }
+    else
+    /* trigger for offset effect */
+    if (p_sys->i_offset_trigger <= p_sys->i_cur_time)
+    {
+        p_sys->i_offset_trigger = 0;
+        p_sys->i_offset_ofs = MOD(((uint32_t) vlc_mrand48()),
+                                  p_sys->i_height[Y_PLANE]) * 100;
+    }
+    else
+        p_sys->i_offset_ofs = 0;
+
+
+    /**
+    * sliding section
+    */
+
+#define SLIDING_AVERAGE_PERIOD   (20 * TIME_UNIT_PER_S)
+#define SLIDING_AVERAGE_DURATION ( 3 * TIME_UNIT_PER_S)
+
+    /* start trigger to be (re)initialized */
+    if ( (p_sys->i_sliding_stop_trig  == 0) &&
+         (p_sys->i_sliding_trigger == 0) &&
+         (p_sys->i_sliding_speed == 0) )
+    {
+        /* random trigger which enable sliding effect */
+        p_sys->i_sliding_trigger
+            = p_sys->i_cur_time
+            + ((uint64_t) vlc_mrand48() ) % SLIDING_AVERAGE_PERIOD
+            + SLIDING_AVERAGE_PERIOD / 2;
+    }
+    /* start trigger just occurs */
+    else if ( (p_sys->i_sliding_stop_trig  == 0 ) &&
+         (p_sys->i_sliding_trigger <= p_sys->i_cur_time) &&
+         (p_sys->i_sliding_speed == 0 ) )
+    {
+        /* init sliding parameters */
+        p_sys->i_sliding_trigger = 0;
+        p_sys->i_sliding_stop_trig
+            = p_sys->i_cur_time
+            + ((uint64_t) vlc_mrand48() ) % SLIDING_AVERAGE_DURATION
+            + SLIDING_AVERAGE_DURATION / 2;
+        p_sys->i_sliding_ofs = 0;
+        /* note: sliding speed unit = image per 100 s */
+        p_sys->i_sliding_speed = MOD(((int32_t) vlc_mrand48() ), 201) - 
100;
+    }
+    /* stop trigger disabling sliding effect */
+    else if ((p_sys->i_sliding_stop_trig  <= p_sys->i_cur_time) &&
+        (p_sys->i_sliding_trigger == 0 ))
+    {
+        /* first increase speed to ensure we will come back to stable 
image */
+        if ( abs(p_sys->i_sliding_speed) < 50 )
+            p_sys->i_sliding_speed += 5;
+
+        /* check if offset is close to 0 and then ready to stop */
+        if ( abs(p_sys->i_sliding_ofs) < abs( p_sys->i_sliding_speed
+             * p_sys->i_height[Y_PLANE]
+             * ( p_sys->i_cur_time - p_sys->i_last_time) / 
TIME_UNIT_PER_S )
+             ||  abs(p_sys->i_sliding_ofs) < p_sys->i_height[Y_PLANE] 
*100/20)
+        {
+            /* reset sliding parameters */
+            p_sys->i_sliding_ofs = p_sys->i_sliding_speed = 0;
+            p_sys->i_sliding_trigger = p_sys->i_sliding_stop_trig = 0;
+        }
+    }
+
+    /* update offset */
+    p_sys->i_sliding_ofs += p_sys->i_sliding_speed * 
p_sys->i_height[Y_PLANE]
+                         * ( p_sys->i_cur_time - p_sys->i_last_time)
+                         / TIME_UNIT_PER_S;
+
+    p_sys->i_sliding_ofs = MOD(p_sys->i_sliding_ofs,
+                               p_sys->i_height[Y_PLANE]*100);
+
+    /* apply offset */
+    return oldmovie_sliding_offset_apply( p_filter, p_pic_out );
+}
+
+/**
+* apply both sliding and offset effect
+*/
+int oldmovie_sliding_offset_apply( filter_t *p_filter, picture_t 
*p_pic_out )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+
+    for ( uint8_t i_p = 0; i_p < p_pic_out->i_planes; i_p++ )
+    {
+        /* first allocate temporary buffer for swap operation */
+        uint8_t *p_temp_buf = calloc(1, p_pic_out->p[i_p].i_lines
+                                        * p_pic_out->p[i_p].i_pitch);
+        if (!p_temp_buf)
+            return VLC_ENOMEM;
+        memcpy(p_temp_buf,p_pic_out->p[i_p].p_pixels,
+                p_pic_out->p[i_p].i_lines * p_pic_out->p[i_p].i_pitch);
+
+        /* copy lines to output_pic */
+        for (int32_t i_y=0; i_y < p_pic_out->p[i_p].i_visible_lines; i_y++)
+        {
+            int32_t i_ofs = MOD((p_sys->i_offset_ofs + 
p_sys->i_sliding_ofs)
+                                /100,
+                                p_sys->i_height[Y_PLANE]);
+            i_ofs *= p_pic_out->p[i_p].i_visible_lines;
+            i_ofs /= p_sys->i_height[Y_PLANE];
+
+ memcpy(&p_pic_out->p[i_p].p_pixels[i_y*p_pic_out->p[i_p].i_pitch],
+ &p_temp_buf[((i_y+i_ofs)%p_pic_out->p[i_p].i_visible_lines)
+                                *p_pic_out->p[i_p].i_pitch],
+                   p_pic_out->p[i_p].i_visible_pitch);
+        }
+        free(p_temp_buf);
+    }
+
+    return VLC_SUCCESS;
+}
+
+/**
+ * Black and white transform including a touch of sepia effect
+ */
+void oldmovie_black_n_white_effect( picture_t *p_pic_out )
+{
+    for (int32_t i_y=0; i_y < p_pic_out->p[Y_PLANE].i_visible_lines; i_y++)
+        for (int32_t i_x=0; i_x < p_pic_out->p[Y_PLANE].i_visible_pitch;
+                     i_x += p_pic_out->p[Y_PLANE].i_pixel_pitch)
+        {
+            uint32_t i_pix_ofs = i_x+i_y*p_pic_out->p[Y_PLANE].i_pitch;
+            p_pic_out->p[Y_PLANE].p_pixels[i_pix_ofs]
+                -= p_pic_out->p[Y_PLANE].p_pixels[i_pix_ofs] >> 2;
+            p_pic_out->p[Y_PLANE].p_pixels[i_pix_ofs] += 30;
+        }
+    memset(p_pic_out->p[U_PLANE].p_pixels, 122, 
p_pic_out->p[U_PLANE].i_lines
+                                              * 
p_pic_out->p[U_PLANE].i_pitch);
+    memset(p_pic_out->p[V_PLANE].p_pixels, 132, 
p_pic_out->p[V_PLANE].i_lines
+                                              * 
p_pic_out->p[V_PLANE].i_pitch);
+}
+
+/**
+ * Smooth darker borders effect
+ */
+int oldmovie_dark_border_effect( filter_t *p_filter, picture_t *p_pic_out )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+#define BORDER_DIST 20
+
+    for (int32_t i_y=0; i_y < p_sys->i_height[Y_PLANE]; i_y++)
+        for (int32_t i_x=0; i_x < p_sys->i_width[Y_PLANE]; i_x++)
+        {
+            int32_t i_x_border_dist
+                = __MIN( i_x, p_sys->i_width[Y_PLANE] - i_x);
+            int32_t i_y_border_dist
+                = __MIN( i_y, p_sys->i_height[Y_PLANE] - i_y);
+
+            int32_t i_border_dist
+                = __MAX(BORDER_DIST - i_x_border_dist,0)
+                + __MAX(BORDER_DIST - i_y_border_dist,0);
+
+            i_border_dist = __MIN(BORDER_DIST, i_border_dist);
+
+            if (i_border_dist == 0)
+                continue;
+
+            uint32_t i_pix_ofs = i_x * p_pic_out->p[Y_PLANE].i_pixel_pitch
+                               + i_y * p_pic_out->p[Y_PLANE].i_pitch;
+
+            SUB_MIN(p_pic_out->p[Y_PLANE].p_pixels[i_pix_ofs],
+                         i_border_dist * 255 / BORDER_DIST, 0);
+        }
+
+    return VLC_SUCCESS;
+}
+
+/**
+ * Vertical scratch random management and effect
+ */
+int oldmovie_film_scratch_effect( filter_t *p_filter, picture_t 
*p_pic_out )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+#define SCRATCH_GENERATOR_PERIOD ( TIME_UNIT_PER_S * 2 )
+#define SCRATCH_DURATION         ( TIME_UNIT_PER_S * 1 / 2)
+
+    /* generate new scratch */
+    if ( p_sys->i_scratch_trigger <= p_sys->i_cur_time )
+    {
+        for (uint32_t i_s=0; i_s < MAX_SCRATCH; i_s++)
+            if (p_sys->p_scratch[i_s] == NULL)
+            {
+                /* allocate data */
+                p_sys->p_scratch[i_s]
+                    =calloc(1, sizeof( *(p_sys->p_scratch[i_s]) ));
+                if (!p_sys->p_scratch[i_s])
+                    return VLC_ENOMEM;
+
+                /* set random parameters */
+                p_sys->p_scratch[i_s]->i_offset
+                    =(((unsigned) vlc_mrand48() )
+                    % __MAX((p_sys->i_width[Y_PLANE] - 10),1))
+                    + 5;
+                p_sys->p_scratch[i_s]->i_width
+                    =(((unsigned) vlc_mrand48() )
+                    % __MAX((p_sys->i_width[Y_PLANE] / 500),1))
+                    + 1;
+                p_sys->p_scratch[i_s]->i_intensity
+                    =((unsigned) vlc_mrand48() ) % 50 + 10;
+                p_sys->p_scratch[i_s]->i_stop_trigger
+                    = p_sys->i_cur_time
+                    + ((uint64_t) vlc_mrand48() ) % SCRATCH_DURATION
+                    + SCRATCH_DURATION / 2;
+
+                break;
+            }
+        p_sys->i_scratch_trigger = p_sys->i_cur_time
+            + ((uint64_t) vlc_mrand48() ) % SCRATCH_GENERATOR_PERIOD
+            + SCRATCH_GENERATOR_PERIOD / 2;
+    }
+
+    /* manage and apply current scratch */
+    for (uint32_t i_s=0; i_s < MAX_SCRATCH; i_s++)
+        if (p_sys->p_scratch[i_s])
+        {
+            /* remove outdated scratch */
+            if (p_sys->p_scratch[i_s]->i_stop_trigger <= p_sys->i_cur_time)
+            {
+                FREENULL(p_sys->p_scratch[i_s]);
+                continue;
+            }
+
+            /* otherwise apply scratch */
+            for (int32_t i_y=0;
+                         i_y < p_pic_out->p[Y_PLANE].i_visible_lines; 
i_y++)
+                for (int32_t i_x=p_sys->p_scratch[i_s]->i_offset;
+                        i_x < __MIN(p_sys->p_scratch[i_s]->i_offset
+                                    + p_sys->p_scratch[i_s]->i_width,
+                                    p_sys->i_width[Y_PLANE]);
+                        i_x++)
+                    DARKEN_PIXEL(i_x, i_y, 
p_sys->p_scratch[i_s]->i_intensity,
+                                 p_pic_out->p[Y_PLANE]);
+        }
+
+    return VLC_SUCCESS;
+}
+
+/**
+ * Blotch addition
+ *    bigger than dust but only during one frame (due to a local film 
damage)
+ */
+void oldmovie_film_blotch_effect( filter_t *p_filter, picture_t 
*p_pic_out )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+#define BLOTCH_GENERATOR_PERIOD ( TIME_UNIT_PER_S * 5 )
+
+    /* generate blotch */
+    if ( p_sys->i_blotch_trigger <= p_sys->i_cur_time )
+    {
+        /* set random parameters */
+        int32_t i_bx =(((unsigned) vlc_mrand48() ) % 
p_sys->i_width[Y_PLANE]);
+        int32_t i_by =(((unsigned) vlc_mrand48() ) % 
p_sys->i_height[Y_PLANE]);
+        int32_t i_width =(((unsigned) vlc_mrand48() )
+                        % __MAX(1,p_sys->i_width[Y_PLANE]/10)) + 1;
+        int32_t i_intensity =((unsigned) vlc_mrand48() ) % 50 + 20;
+
+        if (((unsigned) vlc_mrand48() ) & 0x01)
+        {
+            /* draw dark blotch */
+            for (int32_t i_y =-i_width+1; i_y < i_width; i_y++)
+                for (int32_t i_x =-i_width+1; i_x < i_width; i_x++)
+                    if ( i_x * i_x + i_y * i_y <= i_width * i_width )
+                        CHECK_N_DARKEN_PIXEL(i_x + i_bx, i_y + i_by,
+                                           i_intensity, 
p_pic_out->p[Y_PLANE]);
+        } else {
+            /* draw light blotch */
+            for (int32_t i_y =-i_width+1; i_y < i_width; i_y++)
+                for (int32_t i_x =-i_width+1; i_x < i_width; i_x++)
+                    if ( i_x * i_x + i_y * i_y <= i_width * i_width )
+                        CHECK_N_LIGHTEN_PIXEL(i_x + i_bx, i_y + i_by,
+                                           i_intensity, 
p_pic_out->p[Y_PLANE]);
+        }
+
+        p_sys->i_blotch_trigger = p_sys->i_cur_time
+            + ((uint64_t) vlc_mrand48() ) % BLOTCH_GENERATOR_PERIOD
+            + BLOTCH_GENERATOR_PERIOD / 2;
+    }
+}
+
+/**
+ * Dust dots addition, visible during one frame only (film damages)
+ */
+void oldmovie_film_dust_effect( filter_t *p_filter, picture_t *p_pic_out )
+{
+#define ONESHOT_DUST_RATIO 1000
+
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    for (int32_t i_dust = 0;
+                   i_dust < p_sys->i_width[Y_PLANE] * 
p_sys->i_height[Y_PLANE]
+                   / ONESHOT_DUST_RATIO;
+                   i_dust++)
+        if ((unsigned) vlc_mrand48() % 5 < 3)
+            DARKEN_PIXEL( ((unsigned) vlc_mrand48()) % 
p_sys->i_width[Y_PLANE],
+                        ((unsigned) vlc_mrand48()) % 
p_sys->i_height[Y_PLANE],
+                        150, p_pic_out->p[Y_PLANE]);
+        else
+            LIGHTEN_PIXEL(((unsigned) vlc_mrand48()) % 
p_sys->i_width[Y_PLANE],
+                        ((unsigned) vlc_mrand48()) % 
p_sys->i_height[Y_PLANE],
+                        50, p_pic_out->p[Y_PLANE]);
+}
+
+/**
+ * Hair and dust on projector lens
+ *
+ */
+#define HAIR_GENERATOR_PERIOD ( TIME_UNIT_PER_S * 50 )
+#define HAIR_DURATION         ( TIME_UNIT_PER_S * 50)
+#define DUST_GENERATOR_PERIOD ( TIME_UNIT_PER_S * 100 )
+#define DUST_DURATION         ( TIME_UNIT_PER_S * 4 )
+
+/**
+ * Define hair location on the lens and timeout
+ *
+ */
+void oldmovie_define_hair_location( filter_t *p_filter, hair_t* ps_hair )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    ps_hair->i_x = ((unsigned) vlc_mrand48() )% p_sys->i_width[Y_PLANE];
+    ps_hair->i_y = ((unsigned) vlc_mrand48() ) % p_sys->i_height[Y_PLANE];
+    ps_hair->i_rotation = ((unsigned) vlc_mrand48() ) % 200;
+
+    ps_hair->i_stop_trigger = p_sys->i_cur_time
+                            + ((uint64_t) vlc_mrand48() ) % HAIR_DURATION
+                            + HAIR_DURATION / 2;
+}
+
+/**
+ * Show black hair on the screen
+ *       after random duration it is removed or re-located
+ */
+int oldmovie_lens_hair_effect( filter_t *p_filter, picture_t *p_pic_out )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    /* generate new hair */
+    if ( p_sys->i_hair_trigger <= p_sys->i_cur_time )
+    {
+        for (uint32_t i_h=0; i_h < MAX_HAIR; i_h++)
+            if (p_sys->p_hair[i_h] == NULL)
+            {
+                /* allocate data */
+                p_sys->p_hair[i_h]
+                    =calloc(1, sizeof( *(p_sys->p_hair[i_h]) ));
+                if (!p_sys->p_hair[i_h])
+                    return VLC_ENOMEM;
+
+                /* set random parameters */
+                p_sys->p_hair[i_h]->i_length
+                    =(((unsigned) vlc_mrand48() )
+                    % (p_sys->i_width[Y_PLANE]/3)) + 5;
+                p_sys->p_hair[i_h]->i_curve
+                    = MOD(((int32_t) vlc_mrand48() ), 80) - 40;
+                p_sys->p_hair[i_h]->i_width
+                    =(((unsigned) vlc_mrand48() )
+                    % __MAX(1,p_sys->i_width[Y_PLANE]/1500)) + 1;
+                p_sys->p_hair[i_h]->i_intensity
+                    =((unsigned) vlc_mrand48() ) % 50 + 20;
+
+                oldmovie_define_hair_location( p_filter, 
p_sys->p_hair[i_h] );
+
+                break;
+            }
+        p_sys->i_hair_trigger = p_sys->i_cur_time
+            + ((uint64_t) vlc_mrand48() ) % HAIR_GENERATOR_PERIOD
+            + HAIR_GENERATOR_PERIOD / 2;
+    }
+
+    /* manage and apply current hair */
+    for (uint32_t i_h=0; i_h < MAX_HAIR; i_h++)
+        if (p_sys->p_hair[i_h])
+        {
+            /* remove outdated ones */
+            if (p_sys->p_hair[i_h]->i_stop_trigger <= p_sys->i_cur_time)
+            {
+                /* select between moving or removing hair */
+                if (((unsigned)vlc_mrand48() % 2) == 0)
+                    /* move hair */
+                    oldmovie_define_hair_location( p_filter,
+ p_sys->p_hair[i_h] );
+                else
+                {
+                    /* remove hair */
+                    FREENULL(p_sys->p_hair[i_h]);
+                    continue;
+                }
+            }
+
+            /* draw hair */
+            double  f_base_x   = (double) p_sys->p_hair[i_h]->i_x;
+            double  f_base_y   = (double) p_sys->p_hair[i_h]->i_y;
+
+            for (int32_t i_l=0; i_l < p_sys->p_hair[i_h]->i_length; i_l++)
+            {
+                uint32_t i_current_rot = p_sys->p_hair[i_h]->i_rotation
+                                       + 
p_sys->p_hair[i_h]->i_curve*i_l / 100;
+                f_base_x += cos(((double)i_current_rot)/128.0*M_PI);
+                f_base_y += sin(((double)i_current_rot)/128.0*M_PI);
+                double f_current_x = f_base_x;
+                double f_current_y = f_base_y;
+                for (int32_t i_w=0; i_w < p_sys->p_hair[i_h]->i_width; 
i_w++)
+                {
+                    f_current_x += sin(((double)i_current_rot)/128.0*M_PI);
+                    f_current_y += cos(((double)i_current_rot)/128.0*M_PI);
+                    CHECK_N_DARKEN_PIXEL((int32_t) f_current_x,
+                                         (int32_t) f_current_y,
+ p_sys->p_hair[i_h]->i_intensity,
+                                         p_pic_out->p[Y_PLANE]);
+                }
+            }
+        }
+
+    return VLC_SUCCESS;
+}
+
+/**
+ * Define dust location on the lens and timeout
+ *
+ */
+void oldmovie_define_dust_location( filter_t *p_filter, dust_t* ps_dust )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    ps_dust->i_x = ((unsigned) vlc_mrand48() )% p_sys->i_width[Y_PLANE];
+    ps_dust->i_y = ((unsigned) vlc_mrand48() ) % p_sys->i_height[Y_PLANE];
+
+    ps_dust->i_stop_trigger = p_sys->i_cur_time
+                            + ((uint64_t) vlc_mrand48() ) % HAIR_DURATION
+                            + HAIR_DURATION / 2;
+
+
+    ps_dust->i_x = MOD(((int32_t) vlc_mrand48() ), 
p_sys->i_width[Y_PLANE]);
+    ps_dust->i_y = MOD(((int32_t) vlc_mrand48() ), 
p_sys->i_height[Y_PLANE]);
+
+    ps_dust->i_stop_trigger = p_sys->i_cur_time
+                            + ((uint64_t) vlc_mrand48() ) % DUST_DURATION
+                            + DUST_DURATION / 2;
+}
+
+/**
+ * Dust addition
+ *    smaller than blotch but will remain on the screen for long time
+ */
+int oldmovie_lens_dust_effect( filter_t *p_filter, picture_t *p_pic_out )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+
+    /* generate new dust */
+    if ( p_sys->i_dust_trigger <= p_sys->i_cur_time )
+    {
+        for (uint32_t i_d=0; i_d < MAX_DUST; i_d++)
+            if (p_sys->p_dust[i_d] == NULL)
+            {
+                /* allocate data */
+                p_sys->p_dust[i_d]
+                    =calloc(1, sizeof( *(p_sys->p_dust[i_d]) ));
+                if (!p_sys->p_dust[i_d])
+                    return VLC_ENOMEM;
+
+                /* set random parameters */
+                oldmovie_define_dust_location( p_filter, 
p_sys->p_dust[i_d] );
+                p_sys->p_dust[i_d]->i_width
+                    =MOD(((int32_t) vlc_mrand48() ), 5) + 1;
+                p_sys->p_dust[i_d]->i_intensity
+                    =((unsigned) vlc_mrand48() ) % 30 + 30;
+
+                break;
+            }
+        p_sys->i_dust_trigger = p_sys->i_cur_time
+            + ((uint64_t) vlc_mrand48() ) % DUST_GENERATOR_PERIOD
+            + DUST_GENERATOR_PERIOD / 2;
+    }
+
+    /* manage and apply current dust */
+    for (uint32_t i_d=0; i_d < MAX_DUST; i_d++)
+        if (p_sys->p_dust[i_d])
+        {
+            /* remove outdated ones */
+            if (p_sys->p_dust[i_d]->i_stop_trigger <= p_sys->i_cur_time)
+            {
+                /* select between moving or removing dust */
+                if (((unsigned)vlc_mrand48() % 2) == 0)
+                    /* move dust */
+                    oldmovie_define_dust_location( p_filter,
+ p_sys->p_dust[i_d] );
+                else
+                {
+                    /* remove dust */
+                    FREENULL(p_sys->p_dust[i_d]);
+                    continue;
+                }
+            }
+
+            /* draw dust */
+            for (int32_t i_y =-p_sys->p_dust[i_d]->i_width+1;
+                         i_y < p_sys->p_dust[i_d]->i_width; i_y++)
+                for (int32_t i_x =-p_sys->p_dust[i_d]->i_width+1;
+                             i_x < p_sys->p_dust[i_d]->i_width; i_x++)
+                    if ( i_x * i_x + i_y * i_y <= 
p_sys->p_dust[i_d]->i_width
+                                                * 
p_sys->p_dust[i_d]->i_width )
+                        CHECK_N_DARKEN_PIXEL(i_x + p_sys->p_dust[i_d]->i_x,
+                                         i_y + p_sys->p_dust[i_d]->i_y,
+ p_sys->p_dust[i_d]->i_intensity,
+                                         p_pic_out->p[Y_PLANE]);
+        }
+
+    return VLC_SUCCESS;
+}
diff --git a/modules/video_filter/oldmovie.h 
b/modules/video_filter/oldmovie.h
new file mode 100644
index 0000000..7f09d83
--- /dev/null
+++ b/modules/video_filter/oldmovie.h
@@ -0,0 +1,106 @@
+/*****************************************************************************
+ * oldmovie.h : Old movie effect video filter
+ 
*****************************************************************************
+ * Copyright (C) 2013      Vianney Boyer
+ * $Id$
+ *
+ * Authors: Vianney Boyer <vlcvboyer -at- gmail -dot- com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ 
*****************************************************************************/
+
+#ifndef VLC_OLDMOVIE_H
+#define VLC_OLDMOVIE_H 1
+
+#define MAX_SCRATCH        20
+#define MAX_HAIR           10
+#define MAX_DUST           10
+
+typedef struct {
+    int32_t  i_offset;
+    int32_t i_width;
+    uint16_t i_intensity;
+    uint64_t i_stop_trigger;
+} scratch_t;
+
+typedef struct {
+    int32_t  i_x, i_y;
+    uint8_t  i_rotation;
+    int32_t i_width;
+    int32_t i_length;
+    int32_t i_curve;
+    uint16_t i_intensity;
+    uint64_t i_stop_trigger;
+} hair_t;
+
+typedef struct {
+    int32_t  i_x, i_y;
+    int32_t i_width;
+    uint16_t i_intensity;
+    uint64_t i_stop_trigger;
+} dust_t;
+
+struct filter_sys_t {
+
+    /* general data */
+    bool b_init;
+    int32_t i_planes;
+    int32_t *i_height;
+    int32_t *i_width;
+    int32_t *i_visible_pitch;
+    uint64_t i_start_time;
+    uint64_t i_last_time;
+    uint64_t i_cur_time;
+
+    /* sliding & offset effect */
+    uint64_t i_offset_trigger;
+    uint64_t i_sliding_trigger;
+    uint64_t i_sliding_stop_trig;
+    int32_t  i_offset_ofs;
+    int32_t  i_sliding_ofs;
+    int32_t  i_sliding_speed;
+
+    /* scratch on film */
+    uint64_t   i_scratch_trigger;
+    scratch_t *p_scratch[MAX_SCRATCH];
+
+    /* hair on lens */
+    uint64_t   i_hair_trigger;
+    hair_t    *p_hair[MAX_HAIR];
+
+    /* blotch on film */
+    uint64_t   i_blotch_trigger;
+
+    /* dust on lens */
+    uint64_t   i_dust_trigger;
+    dust_t    *p_dust[MAX_DUST];
+};
+
+picture_t *Filter( filter_t *, picture_t * );
+
+int  oldmovie_allocate_data( filter_t *, picture_t * );
+void oldmovie_free_allocated_data( filter_t * );
+
+void oldmovie_shutter_effect( filter_t *, picture_t * );
+int  oldmovie_sliding_offset_effect( filter_t *, picture_t * );
+void oldmovie_black_n_white_effect( picture_t * );
+int  oldmovie_dark_border_effect( filter_t *, picture_t * );
+int  oldmovie_film_scratch_effect( filter_t *, picture_t * );
+void oldmovie_film_blotch_effect( filter_t *, picture_t * );
+void oldmovie_film_dust_effect( filter_t *, picture_t * );
+int  oldmovie_lens_hair_effect( filter_t *, picture_t * );
+int  oldmovie_lens_dust_effect( filter_t *, picture_t * );
+
+#endif
-- 
1.8.1.2





More information about the vlc-devel mailing list