<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix"><br>
      <small>Hi,<br>
        <br>
      </small><small>Please find below and in 2 additional patches the
        modified freeze video filter<br>
        Unfortunately I was not able to keep the file wrapped to 79
        columns when including your comments.<br>
        <br>
        Of course I'll do the same for the other proposed filters.<br>
        <br>
        Best regards<br>
        <br>
        Vianney<br>
        <br>
        <br>
        <br>
        ---<br>
         modules/video_filter/freeze.c | 430
        ++++++++++++++++++++++++++++++++++++++++++<br>
         1 file changed, 430 insertions(+)<br>
         create mode 100644 modules/video_filter/freeze.c<br>
        <br>
        diff --git a/modules/video_filter/freeze.c
        b/modules/video_filter/freeze.c<br>
        new file mode 100644<br>
        index 0000000..75c134a<br>
        --- /dev/null<br>
        +++ b/modules/video_filter/freeze.c<br>
        @@ -0,0 +1,430 @@<br>
+/*****************************************************************************<br>
        + * freeze.c : Freezing video filter<br>
        +
*****************************************************************************<br>
        + * Copyright (C) 2013      Vianney Boyer<br>
        + * $Id$<br>
        + *<br>
        + * Authors: Vianney Boyer <vlcvboyer -at- gmail -dot-
        com><br>
        + *<br>
        + * This program is free software; you can redistribute it
        and/or modify it<br>
        + * under the terms of the GNU Lesser General Public License as
        published by<br>
        + * the Free Software Foundation; either version 2.1 of the
        License, or<br>
        + * (at your option) any later version.<br>
        + *<br>
        + * This program is distributed in the hope that it will be
        useful,<br>
        + * but WITHOUT ANY WARRANTY; without even the implied warranty
        of<br>
        + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br>
        + * GNU Lesser General Public License for more details.<br>
        + *<br>
        + * You should have received a copy of the GNU Lesser General
        Public License<br>
        + * along with this program; if not, write to the Free Software
        Foundation,<br>
        + * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301,
        USA.<br>
        +
*****************************************************************************/<br>
        +<br>
+/*****************************************************************************<br>
        + * Preamble<br>
        +
*****************************************************************************/<br>
        +<br>
        +#ifdef HAVE_CONFIG_H<br>
        +# include "config.h"<br>
        +#endif<br>
        +<br>
        +#include <vlc_common.h><br>
        +#include <vlc_plugin.h><br>
        +#include <vlc_filter.h><br>
        +<br>
        +#include "filter_picture.h"<br>
        +<br>
        +#ifndef MOD<br>
        +#   define MOD(a, b) ((((a)%(b)) + (b))%(b))<br>
        +#endif<br>
        +<br>
        +struct filter_sys_t {<br>
        +    bool b_init;<br>
        +<br>
        +    int32_t i_planes;<br>
        +    int32_t *i_height;<br>
        +    int32_t *i_width;<br>
        +    int32_t *i_visible_pitch;<br>
        +    int8_t  ***pi_freezed_picture;   /* records freezed pixels
        */<br>
        +    int16_t **pi_freezing_countdown; /* freezed pixel delay   
        */<br>
        +    bool    **pb_update_cache;       /* update chache request 
        */<br>
        +    vlc_mutex_t lock;<br>
        +<br>
        +};<br>
        +<br>
+/*****************************************************************************<br>
        + * Prototypes<br>
        +
*****************************************************************************/<br>
        +<br>
        +picture_t *Filter( filter_t *, picture_t * );<br>
        +<br>
        +int  freeze_mouse( filter_t *, vlc_mouse_t *,<br>
        +                   const vlc_mouse_t *, const vlc_mouse_t * );<br>
        +int  freeze_allocate_data( filter_t *, picture_t * );<br>
        +void freeze_free_allocated_data( filter_t * );<br>
        +<br>
        +<br>
+/*****************************************************************************<br>
        + * Module descriptor<br>
        +
*****************************************************************************/<br>
        +<br>
        +#define CFG_PREFIX "freeze-"<br>
        +<br>
        +int  Open ( vlc_object_t * );<br>
        +void Close( vlc_object_t * );<br>
        +<br>
        +vlc_module_begin()<br>
        +    set_description( N_("Freezing interactive video filter") )<br>
        +    set_shortname(   N_("Freeze" ) )<br>
        +    set_capability(  "video filter2", 0 )<br>
        +    set_category(    CAT_VIDEO )<br>
        +    set_subcategory( SUBCAT_VIDEO_VFILTER )<br>
        +<br>
        +    set_callbacks( Open, Close )<br>
        +vlc_module_end()<br>
        +<br>
+/*****************************************************************************<br>
        + * Local prototypes<br>
        +
*****************************************************************************/<br>
        +<br>
        +/**<br>
        + * Open the filter<br>
        + */<br>
        +int Open( vlc_object_t *p_this )<br>
        +{<br>
        +    filter_t *p_filter = (filter_t *)p_this;<br>
        +    filter_sys_t *p_sys;<br>
        +<br>
        +    /* Assert video in match with video out */<br>
        +    if( !es_format_IsSimilar( &p_filter->fmt_in,
        &p_filter->fmt_out ) ) {<br>
        +        msg_Err( p_filter, "Input and output format does not
        match" );<br>
        +        return VLC_EGENERIC;<br>
        +    }<br>
        +<br>
        +    /* Reject 0 bpp and unsupported chroma */<br>
        +    const vlc_fourcc_t fourcc =
        p_filter->fmt_in.video.i_chroma;<br>
        +    const vlc_chroma_description_t *p_chroma<br>
        +          = vlc_fourcc_GetChromaDescription(
        p_filter->fmt_in.video.i_chroma );<br>
        +    if( !p_chroma || p_chroma->pixel_size == 0<br>
        +        || p_chroma->plane_count < 3 ||
        p_chroma->pixel_size > 1<br>
        +        || !vlc_fourcc_IsYUV( fourcc ) )<br>
        +    {<br>
        +        msg_Err( p_filter, "Unsupported chroma (%4.4s)",
        (char*)&fourcc );<br>
        +        return VLC_EGENERIC;<br>
        +    }<br>
        +<br>
        +    /* Allocate structure */<br>
        +    p_filter->p_sys = p_sys = calloc(1, sizeof( *p_sys ) );<br>
        +    if( unlikely(!p_sys) )<br>
        +        return VLC_ENOMEM;<br>
        +<br>
        +    /* init data */<br>
        +<br>
        +    vlc_mutex_init( &p_sys->lock );<br>
        +<br>
        +    p_filter->pf_video_filter = Filter;<br>
        +    p_filter->pf_video_mouse  = freeze_mouse;<br>
        +<br>
        +    return VLC_SUCCESS;<br>
        +}<br>
        +<br>
        +/**<br>
        + * Close the filter<br>
        + */<br>
        +void Close( vlc_object_t *p_this ) {<br>
        +    filter_t *p_filter  = (filter_t *)p_this;<br>
        +    filter_sys_t *p_sys = p_filter->p_sys;<br>
        +<br>
        +    vlc_mutex_destroy( &p_sys->lock );<br>
        +<br>
        +    /* Free allocated memory */<br>
        +    freeze_free_allocated_data( p_filter );<br>
        +    free( p_sys );<br>
        +}<br>
        +<br>
        +/**<br>
        + * Filter a picture<br>
        + */<br>
        +picture_t *Filter( filter_t *p_filter, picture_t *p_pic_in ) {<br>
        +    if( !p_pic_in || !p_filter) return NULL;<br>
        +<br>
        +    filter_sys_t *p_sys = p_filter->p_sys;<br>
        +<br>
        +    picture_t *p_pic_out = filter_NewPicture( p_filter );<br>
        +    if( unlikely(!p_pic_out) ) {<br>
        +        picture_Release( p_pic_in );<br>
        +        return NULL;<br>
        +    }<br>
        +<br>
        +   /*<br>
        +    * allocate data<br>
        +    */<br>
        +    if ( unlikely(!p_sys->b_init) )<br>
        +        if (freeze_allocate_data( p_filter, p_pic_in ) !=
        VLC_SUCCESS)<br>
        +        {<br>
        +            picture_Release( p_pic_in );<br>
        +            return NULL;<br>
        +        }<br>
        +    p_sys->b_init = true;<br>
        +<br>
        +   /*<br>
        +    * preset output pic: raw copy src to dst<br>
        +    */<br>
        +    picture_CopyPixels(p_pic_out, p_pic_in);<br>
        +<br>
        +   /*<br>
        +    * lock shared data mutex<br>
        +    */<br>
        +    vlc_mutex_lock( &p_sys->lock );<br>
        +<br>
        +   /*<br>
        +    * cache original pict pixels selected with mouse pointer<br>
        +    */<br>
        +    for ( int32_t i_p = 0; i_p < p_sys->i_planes; i_p++ )<br>
        +        for ( int32_t i_r = 0; i_r <
        p_sys->i_height[i_p]; i_r++ )<br>
        +            for ( int32_t i_c = 0; i_c <
        p_sys->i_width[i_p]; i_c++ )<br>
        +            {<br>
        +                uint32_t i_Yr = i_r *
        p_sys->i_height[Y_PLANE]<br>
        +                              / p_sys->i_height[i_p];<br>
        +                uint32_t i_Yc = i_c *
        p_sys->i_width[Y_PLANE]<br>
        +                              / p_sys->i_width[i_p];<br>
        +<br>
        +                if ( p_sys->pb_update_cache[i_Yr][i_Yc] )<br>
        +                    p_sys->pi_freezed_picture[i_p][i_r][i_c]<br>
        +                        =
        p_pic_in->p[i_p].p_pixels[i_r*p_pic_out->p[i_p].i_pitch<br>
        +                        +
        i_c*p_pic_out->p[i_p].i_pixel_pitch];<br>
        +            }<br>
        +<br>
        +   /*<br>
        +    * countdown freezed pixel delay & reset pb_update_cache
        flag<br>
        +    */<br>
        +    for ( int32_t i_Yr = 0; i_Yr <
        p_sys->i_height[Y_PLANE]; i_Yr++)<br>
        +        for ( int32_t i_Yc = 0; i_Yc <
        p_sys->i_width[Y_PLANE]; i_Yc++)<br>
        +        {<br>
        +            if ( p_sys->pi_freezing_countdown[i_Yr][i_Yc]
        > 0 )<br>
        +                 p_sys->pi_freezing_countdown[i_Yr][i_Yc]--;<br>
        +            p_sys->pb_update_cache[i_Yr][i_Yc] = false;<br>
        +        }<br>
        +<br>
        +   /*<br>
        +    * apply filter: draw freezed pixels over current picture<br>
        +    */<br>
        +    for ( int32_t i_p = 0; i_p < p_sys->i_planes; i_p++ )<br>
        +        for ( int32_t i_r = 0; i_r <
        p_sys->i_height[i_p]; i_r++ )<br>
        +            for ( int32_t i_c = 0; i_c <
        p_sys->i_width[i_p]; i_c++ )<br>
        +            {<br>
        +                uint32_t i_Yr = i_r *
        p_sys->i_height[Y_PLANE]<br>
        +                              / p_sys->i_height[i_p];<br>
        +                uint32_t i_Yc = i_c *
        p_sys->i_width[Y_PLANE]<br>
        +                              / p_sys->i_width[i_p];<br>
        +<br>
        +                if (
        p_sys->pi_freezing_countdown[i_Yr][i_Yc] > 0 )<br>
        +                    p_pic_out->p[i_p].p_pixels[i_r *
        p_pic_out->p[i_p].i_pitch<br>
        +                        + i_c *
        p_pic_out->p[i_p].i_pixel_pitch]<br>
        +                        =
        p_sys->pi_freezed_picture[i_p][i_r][i_c];<br>
        +            }<br>
        +<br>
        +   /*<br>
        +    * release shared data mutex<br>
        +    */<br>
        +    vlc_mutex_unlock( &p_sys->lock );<br>
        +<br>
        +    return CopyInfoAndRelease( p_pic_out, p_pic_in );<br>
        +}<br>
        +<br>
        +/*<br>
        + * mouse callback<br>
        + **/<br>
        +int freeze_mouse( filter_t *p_filter, vlc_mouse_t *p_mouse,<br>
        +                  const vlc_mouse_t *p_old, const vlc_mouse_t
        *p_new )<br>
        +{<br>
        +    filter_sys_t *p_sys = p_filter->p_sys;<br>
        +    const video_format_t  *p_fmt_in =
        &p_filter->fmt_in.video;<br>
        +<br>
        +    /* Only take events inside the video area */<br>
        +    if( p_new->i_x < 0 || p_new->i_x >=
        (int)p_fmt_in->i_width ||<br>
        +        p_new->i_y < 0 || p_new->i_y >=
        (int)p_fmt_in->i_height )<br>
        +        return VLC_EGENERIC;<br>
        +<br>
        +    if ( unlikely(!p_sys->b_init) )<br>
        +    {<br>
        +        *p_mouse = *p_new;<br>
        +        return VLC_SUCCESS;<br>
        +    }<br>
        +<br>
        +    int32_t i_base_timeout = 0;<br>
        +    if( vlc_mouse_HasPressed( p_old, p_new, MOUSE_BUTTON_LEFT )
        )<br>
        +        i_base_timeout = 100;<br>
        +    else if( vlc_mouse_IsLeftPressed( p_new ) )<br>
        +        i_base_timeout = 50;<br>
        +<br>
        +    vlc_mutex_lock( &p_sys->lock );<br>
        +<br>
        +    if( i_base_timeout > 0 )<br>
        +    {<br>
        +        /*<br>
        +         * find pixels selected by user to apply freezing
        filter<br>
        +         */<br>
        +        int32_t i_min_sq_radius = (p_sys->i_width[Y_PLANE] /
        15)<br>
        +                                * (p_sys->i_width[Y_PLANE] /
        15);<br>
        +        for ( int32_t i_r = 0; i_r <
        p_sys->i_height[Y_PLANE]; i_r++)<br>
        +            for ( int32_t i_c = 0; i_c <
        p_sys->i_width[Y_PLANE]; i_c++)<br>
        +            {<br>
        +                int32_t i_sq_dist =   ( p_new->i_x - i_c )<br>
        +                                    * ( p_new->i_x - i_c )<br>
        +                                    + ( p_new->i_y - i_r )<br>
        +                                    * ( p_new->i_y - i_r );<br>
        +                i_sq_dist = __MAX(0, i_sq_dist -
        i_min_sq_radius);<br>
        +<br>
        +                uint16_t i_timeout = __MAX(i_base_timeout -
        i_sq_dist, 0);<br>
        +<br>
        +                /* ask to update chache for pixel to be freezed
        just now */<br>
        +                if ( p_sys->pi_freezing_countdown[i_r][i_c]
        == 0 && i_timeout > 0)<br>
        +                     p_sys->pb_update_cache[i_r][i_c] =
        true;<br>
        +<br>
        +                /* set freezing delay */<br>
        +                if ( p_sys->pi_freezing_countdown[i_r][i_c]
        < i_timeout )<br>
        +                     p_sys->pi_freezing_countdown[i_r][i_c]
        = i_timeout;<br>
        +            }<br>
        +    }<br>
        +<br>
        +    vlc_mutex_unlock( &p_sys->lock );<br>
        +<br>
        +    return VLC_EGENERIC;<br>
        +}<br>
        +<br>
        +<br>
        +/*<br>
        + * Allocate data<br>
        + */<br>
        +int freeze_allocate_data( filter_t *p_filter, picture_t
        *p_pic_in )<br>
        +{<br>
        +    filter_sys_t *p_sys = p_filter->p_sys;<br>
        +<br>
        +    freeze_free_allocated_data( p_filter );<br>
        +<br>
        +   /*<br>
        +    * take into account different characteristics for each
        plane<br>
        +    */<br>
        +    p_sys->i_planes        = p_pic_in->i_planes;<br>
        +    p_sys->i_height        = calloc( p_sys->i_planes,
        sizeof(int32_t) );<br>
        +    p_sys->i_width         = calloc( p_sys->i_planes,
        sizeof(int32_t) );<br>
        +    p_sys->i_visible_pitch = calloc( p_sys->i_planes,
        sizeof(int32_t) );<br>
        +<br>
        +    if ( unlikely( !p_sys->i_height || !p_sys->i_width ||
        !p_sys->i_visible_pitch ) )<br>
        +    {<br>
        +        freeze_free_allocated_data( p_filter );<br>
        +        return VLC_ENOMEM;<br>
        +    }<br>
        +<br>
        +    /* init data */<br>
        +    for ( int32_t i_p = 0; i_p < p_sys->i_planes; i_p++ )<br>
        +    {<br>
        +        p_sys->i_visible_pitch [i_p] = (int)
        p_pic_in->p[i_p].i_visible_pitch;<br>
        +        p_sys->i_height[i_p]         = (int)
        p_pic_in->p[i_p].i_visible_lines;<br>
        +        p_sys->i_width[i_p]          = (int)
        p_pic_in->p[i_p].i_visible_pitch<br>
        +                                     /
        p_pic_in->p[i_p].i_pixel_pitch;<br>
        +    }<br>
        +<br>
        +    /* buffer used to countdown freezing delay */<br>
        +    p_sys->pi_freezing_countdown<br>
        +        = calloc( p_sys->i_height[Y_PLANE], sizeof(int16_t*)
        );<br>
        +    if ( unlikely( !p_sys->pi_freezing_countdown ) )<br>
        +    {<br>
        +        freeze_free_allocated_data( p_filter );<br>
        +        return VLC_ENOMEM;<br>
        +    }<br>
        +<br>
        +    for ( int32_t i_r = 0; i_r <
        p_sys->i_height[Y_PLANE]; i_r++ )<br>
        +    {<br>
        +        p_sys->pi_freezing_countdown[i_r]<br>
        +            = calloc( p_sys->i_width[Y_PLANE],
        sizeof(int16_t) );<br>
        +        if ( unlikely( !p_sys->pi_freezing_countdown[i_r] )
        )<br>
        +        {<br>
        +            freeze_free_allocated_data( p_filter );<br>
        +            return VLC_ENOMEM;<br>
        +        }<br>
        +    }<br>
        +<br>
        +    /* buffer used to cache freezed pixels colors */<br>
        +    p_sys->pi_freezed_picture = calloc( p_sys->i_planes,
        sizeof(int8_t**) );<br>
        +    if( unlikely( !p_sys->pi_freezed_picture ) )<br>
        +    {<br>
        +        freeze_free_allocated_data( p_filter );<br>
        +        return VLC_ENOMEM;<br>
        +    }<br>
        +<br>
        +    for ( int32_t i_p = 0; i_p < p_sys->i_planes; i_p++)<br>
        +    {<br>
        +        p_sys->pi_freezed_picture[i_p]<br>
        +            = calloc( p_sys->i_height[i_p], sizeof(int8_t*)
        );<br>
        +        if ( unlikely(!p_sys->pi_freezed_picture[i_p]) )<br>
        +        {<br>
        +            freeze_free_allocated_data( p_filter );<br>
        +            return VLC_ENOMEM;<br>
        +        }<br>
        +        for ( int32_t i_r = 0; i_r <
        p_sys->i_height[i_p]; i_r++ )<br>
        +        {<br>
        +            p_sys->pi_freezed_picture[i_p][i_r]<br>
        +                = calloc( p_sys->i_width[i_p],
        sizeof(int8_t) );<br>
        +            if ( unlikely(
        !p_sys->pi_freezed_picture[i_p][i_r] ) )<br>
        +            {<br>
        +                freeze_free_allocated_data( p_filter );<br>
        +                return VLC_ENOMEM;<br>
        +            }<br>
        +        }<br>
        +    }<br>
        +<br>
        +    /* flag used to manage freezed pixels cache update */<br>
        +    p_sys->pb_update_cache<br>
        +        = calloc( p_sys->i_height[Y_PLANE], sizeof(bool*) );<br>
        +    if( unlikely( !p_sys->pb_update_cache ) )<br>
        +    {<br>
        +        freeze_free_allocated_data( p_filter );<br>
        +        return VLC_ENOMEM;<br>
        +    }<br>
        +<br>
        +    for ( int32_t i_r = 0; i_r <
        p_sys->i_height[Y_PLANE]; i_r++ )<br>
        +    {<br>
        +        p_sys->pb_update_cache[i_r]<br>
        +            = calloc( p_sys->i_width[Y_PLANE], sizeof(bool)
        );<br>
        +        if ( unlikely( !p_sys->pb_update_cache[i_r] ) )<br>
        +        {<br>
        +            freeze_free_allocated_data( p_filter );<br>
        +            return VLC_ENOMEM;<br>
        +        }<br>
        +    }<br>
        +<br>
        +    return VLC_SUCCESS;<br>
        +}<br>
        +<br>
        +/**<br>
        + * Free allocated data<br>
        + */<br>
        +void freeze_free_allocated_data( filter_t *p_filter ) {<br>
        +    filter_sys_t *p_sys = p_filter->p_sys;<br>
        +<br>
        +    if (p_sys->pi_freezing_countdown)<br>
        +        for ( int32_t i_r = 0; i_r <
        p_sys->i_height[Y_PLANE]; i_r++ )<br>
        +            free( p_sys->pi_freezing_countdown[i_r] );<br>
        +    FREENULL( p_sys->pi_freezing_countdown );<br>
        +<br>
        +    if ( p_sys->pb_update_cache )<br>
        +        for ( int32_t i_r = 0; i_r <
        p_sys->i_height[Y_PLANE]; i_r++ )<br>
        +            free( p_sys->pb_update_cache[i_r] );<br>
        +    FREENULL( p_sys->pb_update_cache );<br>
        +<br>
        +    if ( p_sys->pi_freezed_picture )<br>
        +        for ( int32_t i_p=0; i_p < p_sys->i_planes; i_p++
        ) {<br>
        +            for ( int32_t i_r=0; i_r <
        p_sys->i_height[i_p]; i_r++ )<br>
        +                free( p_sys->pi_freezed_picture[i_p][i_r] );<br>
        +            free( p_sys->pi_freezed_picture[i_p] );<br>
        +            }<br>
        +    FREENULL( p_sys->pi_freezed_picture );<br>
        +<br>
        +    p_sys->i_planes = 0;<br>
        +    FREENULL( p_sys->i_height );<br>
        +    FREENULL( p_sys->i_width );<br>
        +    FREENULL( p_sys->i_visible_pitch );<br>
        +}<br>
        -- <br>
        1.8.1.2<br>
        <br>
        <br>
      </small><br>
      Le 25/07/2013 13:37, Jean-Baptiste Kempf a écrit :<br>
    </div>
    <blockquote cite="mid:20130725113734.GA21257@videolan.org"
      type="cite">
      <pre wrap="">On 25 Jul, Vianney Boyer wrote :
</pre>
      <blockquote type="cite">
        <pre wrap=""> modules/video_filter/freeze.c | 402
++++++++++++++++++++++++++++++++++++++++++
 modules/video_filter/freeze.h |  49 +++++
</pre>
      </blockquote>
      <pre wrap="">
Why do you need a .h here?

</pre>
      <blockquote type="cite">
        <pre wrap="">+    /* Allocate structure */
+    p_filter->p_sys = p_sys = calloc(1, sizeof( *p_sys ) );
+    if( !p_sys )
</pre>
      </blockquote>
      <pre wrap="">
unlikely()

</pre>
      <blockquote type="cite">
        <pre wrap="">+    for (int32_t i_p=0; i_p < p_sys->i_planes; i_p++)
</pre>
      </blockquote>
      <pre wrap="">
Please use spaces around = signs.
And the style does not match the previous one.

</pre>
      <blockquote type="cite">
        <pre wrap="">+    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) );
</pre>
      </blockquote>
      <pre wrap="">
Those calloc are confusing.

</pre>
      <blockquote type="cite">
        <pre wrap="">+    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 );
</pre>
      </blockquote>
      <pre wrap="">
free(NULL) is OK in VLC.

Best regards,

</pre>
    </blockquote>
    <br>
  </body>
</html>