~ubuntu-branches/debian/wheezy/vlc/wheezy

« back to all changes in this revision

Viewing changes to modules/video_filter/distort.c

Tags: upstream-0.7.2.final
ImportĀ upstreamĀ versionĀ 0.7.2.final

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 * distort.c : Misc video effects plugin for vlc
 
3
 *****************************************************************************
 
4
 * Copyright (C) 2000, 2001, 2002, 2003 VideoLAN
 
5
 * $Id: distort.c 7453 2004-04-23 20:01:59Z gbazin $
 
6
 *
 
7
 * Authors: Samuel Hocevar <sam@zoy.org>
 
8
 *
 
9
 * This program is free software; you can redistribute it and/or modify
 
10
 * it under the terms of the GNU General Public License as published by
 
11
 * the Free Software Foundation; either version 2 of the License, or
 
12
 * (at your option) any later version.
 
13
 *
 
14
 * This program is distributed in the hope that it will be useful,
 
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
 * GNU General Public License for more details.
 
18
 *
 
19
 * You should have received a copy of the GNU General Public License
 
20
 * along with this program; if not, write to the Free Software
 
21
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 
22
 *****************************************************************************/
 
23
 
 
24
/*****************************************************************************
 
25
 * Preamble
 
26
 *****************************************************************************/
 
27
#include <stdlib.h>                                      /* malloc(), free() */
 
28
#include <string.h>
 
29
 
 
30
#include <math.h>                                            /* sin(), cos() */
 
31
 
 
32
#include <vlc/vlc.h>
 
33
#include <vlc/vout.h>
 
34
 
 
35
#include "filter_common.h"
 
36
 
 
37
#define DISTORT_MODE_WAVE    1
 
38
#define DISTORT_MODE_RIPPLE  2
 
39
 
 
40
/*****************************************************************************
 
41
 * Local prototypes
 
42
 *****************************************************************************/
 
43
static int  Create    ( vlc_object_t * );
 
44
static void Destroy   ( vlc_object_t * );
 
45
 
 
46
static int  Init      ( vout_thread_t * );
 
47
static void End       ( vout_thread_t * );
 
48
static void Render    ( vout_thread_t *, picture_t * );
 
49
 
 
50
static void DistortWave    ( vout_thread_t *, picture_t *, picture_t * );
 
51
static void DistortRipple  ( vout_thread_t *, picture_t *, picture_t * );
 
52
 
 
53
static int  SendEvents   ( vlc_object_t *, char const *,
 
54
                           vlc_value_t, vlc_value_t, void * );
 
55
 
 
56
/*****************************************************************************
 
57
 * Module descriptor
 
58
 *****************************************************************************/
 
59
#define MODE_TEXT N_("Distort mode")
 
60
#define MODE_LONGTEXT N_("Distort mode, one of \"wave\" and \"ripple\"")
 
61
 
 
62
static char *mode_list[] = { "wave", "ripple" };
 
63
static char *mode_list_text[] = { N_("Wave"), N_("Ripple") };
 
64
 
 
65
vlc_module_begin();
 
66
    set_description( _("Distort video filter") );
 
67
    set_capability( "video filter", 0 );
 
68
 
 
69
    add_string( "distort-mode", "wave", NULL, MODE_TEXT, MODE_LONGTEXT,
 
70
                VLC_FALSE );
 
71
        change_string_list( mode_list, mode_list_text, 0 );
 
72
 
 
73
    add_shortcut( "distort" );
 
74
    set_callbacks( Create, Destroy );
 
75
vlc_module_end();
 
76
 
 
77
/*****************************************************************************
 
78
 * vout_sys_t: Distort video output method descriptor
 
79
 *****************************************************************************
 
80
 * This structure is part of the video output thread descriptor.
 
81
 * It describes the Distort specific properties of an output thread.
 
82
 *****************************************************************************/
 
83
struct vout_sys_t
 
84
{
 
85
    int i_mode;
 
86
    vout_thread_t *p_vout;
 
87
 
 
88
    /* For the wave mode */
 
89
    double  f_angle;
 
90
    mtime_t last_date;
 
91
};
 
92
 
 
93
/*****************************************************************************
 
94
 * Control: control facility for the vout (forwards to child vout)
 
95
 *****************************************************************************/
 
96
static int Control( vout_thread_t *p_vout, int i_query, va_list args )
 
97
{
 
98
    return vout_vaControl( p_vout->p_sys->p_vout, i_query, args );
 
99
}
 
100
 
 
101
/*****************************************************************************
 
102
 * Create: allocates Distort video thread output method
 
103
 *****************************************************************************
 
104
 * This function allocates and initializes a Distort vout method.
 
105
 *****************************************************************************/
 
106
static int Create( vlc_object_t *p_this )
 
107
{
 
108
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
 
109
    char *psz_method, *psz_method_tmp;
 
110
 
 
111
    /* Allocate structure */
 
112
    p_vout->p_sys = malloc( sizeof( vout_sys_t ) );
 
113
    if( p_vout->p_sys == NULL )
 
114
    {
 
115
        msg_Err( p_vout, "out of memory" );
 
116
        return VLC_ENOMEM;
 
117
    }
 
118
 
 
119
    p_vout->pf_init = Init;
 
120
    p_vout->pf_end = End;
 
121
    p_vout->pf_manage = NULL;
 
122
    p_vout->pf_render = Render;
 
123
    p_vout->pf_display = NULL;
 
124
    p_vout->pf_control = Control;
 
125
 
 
126
    p_vout->p_sys->i_mode = 0;
 
127
 
 
128
    if( !(psz_method = psz_method_tmp
 
129
          = config_GetPsz( p_vout, "distort-mode" )) )
 
130
    {
 
131
        msg_Err( p_vout, "configuration variable %s empty, using 'wave'",
 
132
                         "distort-mode" );
 
133
        p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
 
134
    }
 
135
    else
 
136
    {
 
137
 
 
138
        if( !strcmp( psz_method, "wave" ) )
 
139
        {
 
140
            p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
 
141
        }
 
142
        else if( !strcmp( psz_method, "ripple" ) )
 
143
        {
 
144
            p_vout->p_sys->i_mode = DISTORT_MODE_RIPPLE;
 
145
        }
 
146
        else
 
147
        {
 
148
            msg_Err( p_vout, "no valid distort mode provided, "
 
149
                             "using wave" );
 
150
            p_vout->p_sys->i_mode = DISTORT_MODE_WAVE;
 
151
        }
 
152
    }
 
153
    free( psz_method_tmp );
 
154
 
 
155
    return VLC_SUCCESS;
 
156
}
 
157
 
 
158
/*****************************************************************************
 
159
 * Init: initialize Distort video thread output method
 
160
 *****************************************************************************/
 
161
static int Init( vout_thread_t *p_vout )
 
162
{
 
163
    int i_index;
 
164
    picture_t *p_pic;
 
165
 
 
166
    I_OUTPUTPICTURES = 0;
 
167
 
 
168
    /* Initialize the output structure */
 
169
    p_vout->output.i_chroma = p_vout->render.i_chroma;
 
170
    p_vout->output.i_width  = p_vout->render.i_width;
 
171
    p_vout->output.i_height = p_vout->render.i_height;
 
172
    p_vout->output.i_aspect = p_vout->render.i_aspect;
 
173
 
 
174
    /* Try to open the real video output */
 
175
    msg_Dbg( p_vout, "spawning the real video output" );
 
176
 
 
177
    p_vout->p_sys->p_vout = vout_Create( p_vout,
 
178
                           p_vout->render.i_width, p_vout->render.i_height,
 
179
                           p_vout->render.i_chroma, p_vout->render.i_aspect );
 
180
 
 
181
    /* Everything failed */
 
182
    if( p_vout->p_sys->p_vout == NULL )
 
183
    {
 
184
        msg_Err( p_vout, "cannot open vout, aborting" );
 
185
 
 
186
        return VLC_EGENERIC;
 
187
    }
 
188
 
 
189
    ALLOCATE_DIRECTBUFFERS( VOUT_MAX_PICTURES );
 
190
 
 
191
    ADD_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
 
192
 
 
193
    ADD_PARENT_CALLBACKS( SendEventsToChild );
 
194
 
 
195
    p_vout->p_sys->f_angle = 0.0;
 
196
    p_vout->p_sys->last_date = 0;
 
197
 
 
198
    return VLC_SUCCESS;
 
199
}
 
200
 
 
201
/*****************************************************************************
 
202
 * End: terminate Distort video thread output method
 
203
 *****************************************************************************/
 
204
static void End( vout_thread_t *p_vout )
 
205
{
 
206
    int i_index;
 
207
 
 
208
    /* Free the fake output buffers we allocated */
 
209
    for( i_index = I_OUTPUTPICTURES ; i_index ; )
 
210
    {
 
211
        i_index--;
 
212
        free( PP_OUTPUTPICTURE[ i_index ]->p_data_orig );
 
213
    }
 
214
}
 
215
 
 
216
/*****************************************************************************
 
217
 * Destroy: destroy Distort video thread output method
 
218
 *****************************************************************************
 
219
 * Terminate an output method created by DistortCreateOutputMethod
 
220
 *****************************************************************************/
 
221
static void Destroy( vlc_object_t *p_this )
 
222
{
 
223
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
 
224
 
 
225
    DEL_CALLBACKS( p_vout->p_sys->p_vout, SendEvents );
 
226
    vlc_object_detach( p_vout->p_sys->p_vout );
 
227
    vout_Destroy( p_vout->p_sys->p_vout );
 
228
 
 
229
    DEL_PARENT_CALLBACKS( SendEventsToChild );
 
230
 
 
231
    free( p_vout->p_sys );
 
232
}
 
233
 
 
234
/*****************************************************************************
 
235
 * Render: displays previously rendered output
 
236
 *****************************************************************************
 
237
 * This function send the currently rendered image to Distort image, waits
 
238
 * until it is displayed and switch the two rendering buffers, preparing next
 
239
 * frame.
 
240
 *****************************************************************************/
 
241
static void Render( vout_thread_t *p_vout, picture_t *p_pic )
 
242
{
 
243
    picture_t *p_outpic;
 
244
 
 
245
    /* This is a new frame. Get a structure from the video_output. */
 
246
    while( ( p_outpic = vout_CreatePicture( p_vout->p_sys->p_vout, 0, 0, 0 ) )
 
247
              == NULL )
 
248
    {
 
249
        if( p_vout->b_die || p_vout->b_error )
 
250
        {
 
251
            return;
 
252
        }
 
253
        msleep( VOUT_OUTMEM_SLEEP );
 
254
    }
 
255
 
 
256
    vout_DatePicture( p_vout->p_sys->p_vout, p_outpic, p_pic->date );
 
257
 
 
258
    switch( p_vout->p_sys->i_mode )
 
259
    {
 
260
        case DISTORT_MODE_WAVE:
 
261
            DistortWave( p_vout, p_pic, p_outpic );
 
262
            break;
 
263
 
 
264
        case DISTORT_MODE_RIPPLE:
 
265
            DistortRipple( p_vout, p_pic, p_outpic );
 
266
            break;
 
267
 
 
268
        default:
 
269
            break;
 
270
    }
 
271
 
 
272
    vout_DisplayPicture( p_vout->p_sys->p_vout, p_outpic );
 
273
}
 
274
 
 
275
/*****************************************************************************
 
276
 * DistortWave: draw a wave effect on the picture
 
277
 *****************************************************************************/
 
278
static void DistortWave( vout_thread_t *p_vout, picture_t *p_inpic,
 
279
                                                picture_t *p_outpic )
 
280
{
 
281
    int i_index;
 
282
    double f_angle;
 
283
    mtime_t new_date = mdate();
 
284
 
 
285
    p_vout->p_sys->f_angle += (new_date - p_vout->p_sys->last_date) / 200000.0;
 
286
    p_vout->p_sys->last_date = new_date;
 
287
    f_angle = p_vout->p_sys->f_angle;
 
288
 
 
289
    for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ )
 
290
    {
 
291
        int i_line, i_num_lines, i_offset;
 
292
        uint8_t black_pixel;
 
293
        uint8_t *p_in, *p_out;
 
294
 
 
295
        p_in = p_inpic->p[i_index].p_pixels;
 
296
        p_out = p_outpic->p[i_index].p_pixels;
 
297
 
 
298
        i_num_lines = p_inpic->p[i_index].i_lines;
 
299
 
 
300
        black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
 
301
 
 
302
        /* Ok, we do 3 times the sin() calculation for each line. So what ? */
 
303
        for( i_line = 0 ; i_line < i_num_lines ; i_line++ )
 
304
        {
 
305
            /* Calculate today's offset, don't go above 1/20th of the screen */
 
306
            i_offset = (int)( (double)(p_inpic->p[i_index].i_visible_pitch)
 
307
                         * sin( f_angle + 10.0 * (double)i_line
 
308
                                               / (double)i_num_lines )
 
309
                         / 20.0 );
 
310
 
 
311
            if( i_offset )
 
312
            {
 
313
                if( i_offset < 0 )
 
314
                {
 
315
                    p_vout->p_vlc->pf_memcpy( p_out, p_in - i_offset,
 
316
                             p_inpic->p[i_index].i_visible_pitch + i_offset );
 
317
                    p_in += p_inpic->p[i_index].i_pitch;
 
318
                    p_out += p_outpic->p[i_index].i_pitch;
 
319
                    memset( p_out + i_offset, black_pixel, -i_offset );
 
320
                }
 
321
                else
 
322
                {
 
323
                    p_vout->p_vlc->pf_memcpy( p_out + i_offset, p_in,
 
324
                             p_inpic->p[i_index].i_visible_pitch - i_offset );
 
325
                    memset( p_out, black_pixel, i_offset );
 
326
                    p_in += p_inpic->p[i_index].i_pitch;
 
327
                    p_out += p_outpic->p[i_index].i_pitch;
 
328
                }
 
329
            }
 
330
            else
 
331
            {
 
332
                p_vout->p_vlc->pf_memcpy( p_out, p_in,
 
333
                                          p_inpic->p[i_index].i_visible_pitch );
 
334
                p_in += p_inpic->p[i_index].i_pitch;
 
335
                p_out += p_outpic->p[i_index].i_pitch;
 
336
            }
 
337
 
 
338
        }
 
339
    }
 
340
}
 
341
 
 
342
/*****************************************************************************
 
343
 * DistortRipple: draw a ripple effect at the bottom of the picture
 
344
 *****************************************************************************/
 
345
static void DistortRipple( vout_thread_t *p_vout, picture_t *p_inpic,
 
346
                                                  picture_t *p_outpic )
 
347
{
 
348
    int i_index;
 
349
    double f_angle;
 
350
    mtime_t new_date = mdate();
 
351
 
 
352
    p_vout->p_sys->f_angle -= (p_vout->p_sys->last_date - new_date) / 100000.0;
 
353
    p_vout->p_sys->last_date = new_date;
 
354
    f_angle = p_vout->p_sys->f_angle;
 
355
 
 
356
    for( i_index = 0 ; i_index < p_inpic->i_planes ; i_index++ )
 
357
    {
 
358
        int i_line, i_first_line, i_num_lines, i_offset;
 
359
        uint8_t black_pixel;
 
360
        uint8_t *p_in, *p_out;
 
361
 
 
362
        black_pixel = ( i_index == Y_PLANE ) ? 0x00 : 0x80;
 
363
 
 
364
        i_num_lines = p_inpic->p[i_index].i_lines;
 
365
 
 
366
        i_first_line = i_num_lines * 4 / 5;
 
367
 
 
368
        p_in = p_inpic->p[i_index].p_pixels;
 
369
        p_out = p_outpic->p[i_index].p_pixels;
 
370
 
 
371
        for( i_line = 0 ; i_line < i_first_line ; i_line++ )
 
372
        {
 
373
            p_vout->p_vlc->pf_memcpy( p_out, p_in,
 
374
                                      p_inpic->p[i_index].i_visible_pitch );
 
375
            p_in += p_inpic->p[i_index].i_pitch;
 
376
            p_out += p_outpic->p[i_index].i_pitch;
 
377
        }
 
378
 
 
379
        /* Ok, we do 3 times the sin() calculation for each line. So what ? */
 
380
        for( i_line = i_first_line ; i_line < i_num_lines ; i_line++ )
 
381
        {
 
382
            /* Calculate today's offset, don't go above 1/20th of the screen */
 
383
            i_offset = (int)( (double)(p_inpic->p[i_index].i_pitch)
 
384
                         * sin( f_angle + 2.0 * (double)i_line
 
385
                                              / (double)( 1 + i_line
 
386
                                                            - i_first_line) )
 
387
                         * (double)(i_line - i_first_line)
 
388
                         / (double)i_num_lines
 
389
                         / 8.0 );
 
390
 
 
391
            if( i_offset )
 
392
            {
 
393
                if( i_offset < 0 )
 
394
                {
 
395
                    p_vout->p_vlc->pf_memcpy( p_out, p_in - i_offset,
 
396
                             p_inpic->p[i_index].i_visible_pitch + i_offset );
 
397
                    p_in -= p_inpic->p[i_index].i_pitch;
 
398
                    p_out += p_outpic->p[i_index].i_pitch;
 
399
                    memset( p_out + i_offset, black_pixel, -i_offset );
 
400
                }
 
401
                else
 
402
                {
 
403
                    p_vout->p_vlc->pf_memcpy( p_out + i_offset, p_in,
 
404
                             p_inpic->p[i_index].i_visible_pitch - i_offset );
 
405
                    memset( p_out, black_pixel, i_offset );
 
406
                    p_in -= p_inpic->p[i_index].i_pitch;
 
407
                    p_out += p_outpic->p[i_index].i_pitch;
 
408
                }
 
409
            }
 
410
            else
 
411
            {
 
412
                p_vout->p_vlc->pf_memcpy( p_out, p_in,
 
413
                                          p_inpic->p[i_index].i_visible_pitch );
 
414
                p_in -= p_inpic->p[i_index].i_pitch;
 
415
                p_out += p_outpic->p[i_index].i_pitch;
 
416
            }
 
417
 
 
418
        }
 
419
    }
 
420
}
 
421
 
 
422
/*****************************************************************************
 
423
 * SendEvents: forward mouse and keyboard events to the parent p_vout
 
424
 *****************************************************************************/
 
425
static int SendEvents( vlc_object_t *p_this, char const *psz_var,
 
426
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
 
427
{
 
428
    var_Set( (vlc_object_t *)p_data, psz_var, newval );
 
429
 
 
430
    return VLC_SUCCESS;
 
431
}
 
432
 
 
433
/*****************************************************************************
 
434
 * SendEventsToChild: forward events to the child/children vout
 
435
 *****************************************************************************/
 
436
static int SendEventsToChild( vlc_object_t *p_this, char const *psz_var,
 
437
                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
 
438
{
 
439
    vout_thread_t *p_vout = (vout_thread_t *)p_this;
 
440
    var_Set( p_vout->p_sys->p_vout, psz_var, newval );
 
441
    return VLC_SUCCESS;
 
442
}