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

« back to all changes in this revision

Viewing changes to modules/visualization/goom.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
 * goom.c: based on libgoom (see http://ios.free.fr/?page=projet&quoi=1)
 
3
 *****************************************************************************
 
4
 * Copyright (C) 2003 VideoLAN
 
5
 * $Id: goom.c 7652 2004-05-13 21:13:38Z gbazin $
 
6
 *
 
7
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 
8
 *          Gildas Bazin <gbazin@videolan.org>
 
9
 *
 
10
 * This program is free software; you can redistribute it and/or modify
 
11
 * it under the terms of the GNU General Public License as published by
 
12
 * the Free Software Foundation; either version 2 of the License, or
 
13
 * (at your option) any later version.
 
14
 *
 
15
 * This program is distributed in the hope that it will be useful,
 
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
18
 * GNU General Public License for more details.
 
19
 *
 
20
 * You should have received a copy of the GNU General Public License
 
21
 * along with this program; if not, write to the Free Software
 
22
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 
23
 *****************************************************************************/
 
24
 
 
25
/*****************************************************************************
 
26
 * Preamble
 
27
 *****************************************************************************/
 
28
#include <stdlib.h>                                      /* malloc(), free() */
 
29
#include <string.h>                                              /* strdup() */
 
30
#include <errno.h>
 
31
 
 
32
#include <vlc/vlc.h>
 
33
#include <vlc/input.h>
 
34
#include <vlc/aout.h>
 
35
#include <vlc/vout.h>
 
36
#include "aout_internal.h"
 
37
 
 
38
#ifdef USE_GOOM_TREE
 
39
#   ifdef OLD_GOOM
 
40
#       include "goom_core.h"
 
41
#       define PluginInfo void
 
42
#       define goom_update(a,b,c,d,e,f) goom_update(b,c,d,e,f)
 
43
#       define goom_close(a) goom_close()
 
44
#       define goom_init(a,b) NULL; goom_init(a,b,0); goom_set_font(0,0,0)
 
45
#   else
 
46
#       include "goom.h"
 
47
#   endif
 
48
#else
 
49
#   include <goom/goom.h>
 
50
#endif
 
51
 
 
52
/*****************************************************************************
 
53
 * Module descriptor
 
54
 *****************************************************************************/
 
55
static int  Open         ( vlc_object_t * );
 
56
static void Close        ( vlc_object_t * );
 
57
 
 
58
#define WIDTH_TEXT N_("Goom display width")
 
59
#define HEIGHT_TEXT N_("Goom display height")
 
60
#define RES_LONGTEXT N_("Allows you to change the resolution of the " \
 
61
  "Goom display (bigger resolution will be prettier but more CPU intensive).")
 
62
 
 
63
#define SPEED_TEXT N_("Goom animation speed")
 
64
#define SPEED_LONGTEXT N_("Allows you to reduce the speed of the animation " \
 
65
  "(default 6, max 10).")
 
66
 
 
67
#define MAX_SPEED 10
 
68
 
 
69
vlc_module_begin();
 
70
    set_description( _("Goom effect") );
 
71
    set_capability( "audio filter", 0 );
 
72
    add_integer( "goom-width", 320, NULL,
 
73
                 WIDTH_TEXT, RES_LONGTEXT, VLC_FALSE );
 
74
    add_integer( "goom-height", 240, NULL,
 
75
                 HEIGHT_TEXT, RES_LONGTEXT, VLC_FALSE );
 
76
    add_integer( "goom-speed", 6, NULL,
 
77
                 SPEED_TEXT, SPEED_LONGTEXT, VLC_FALSE );
 
78
    set_callbacks( Open, Close );
 
79
    add_shortcut( "goom" );
 
80
vlc_module_end();
 
81
 
 
82
/*****************************************************************************
 
83
 * Local prototypes
 
84
 *****************************************************************************/
 
85
#define MAX_BLOCKS 10
 
86
#define GOOM_DELAY 400000
 
87
 
 
88
typedef struct
 
89
{
 
90
    VLC_COMMON_MEMBERS
 
91
    vout_thread_t *p_vout;
 
92
 
 
93
    char          *psz_title;
 
94
 
 
95
    vlc_mutex_t   lock;
 
96
    vlc_cond_t    wait;
 
97
 
 
98
    /* Audio properties */
 
99
    int i_channels;
 
100
 
 
101
    /* Audio samples queue */
 
102
    block_t       *pp_blocks[MAX_BLOCKS];
 
103
    int           i_blocks;
 
104
 
 
105
    audio_date_t  date;
 
106
 
 
107
} goom_thread_t;
 
108
 
 
109
typedef struct aout_filter_sys_t
 
110
{
 
111
    goom_thread_t *p_thread;
 
112
 
 
113
} aout_filter_sys_t;
 
114
 
 
115
static void DoWork   ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
 
116
                       aout_buffer_t * );
 
117
 
 
118
static void Thread   ( vlc_object_t * );
 
119
 
 
120
static char *TitleGet( vlc_object_t * );
 
121
 
 
122
/*****************************************************************************
 
123
 * Open: open a scope effect plugin
 
124
 *****************************************************************************/
 
125
static int Open( vlc_object_t *p_this )
 
126
{
 
127
    aout_filter_t     *p_filter = (aout_filter_t *)p_this;
 
128
    aout_filter_sys_t *p_sys;
 
129
    goom_thread_t     *p_thread;
 
130
    vlc_value_t       width, height;
 
131
 
 
132
    if ( p_filter->input.i_format != VLC_FOURCC('f','l','3','2' )
 
133
         || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
 
134
    {
 
135
        msg_Warn( p_filter, "Bad input or output format" );
 
136
        return VLC_EGENERIC;
 
137
    }
 
138
    if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
 
139
    {
 
140
        msg_Warn( p_filter, "input and output formats are not similar" );
 
141
        return VLC_EGENERIC;
 
142
    }
 
143
 
 
144
    p_filter->pf_do_work = DoWork;
 
145
    p_filter->b_in_place = 1;
 
146
 
 
147
    /* Allocate structure */
 
148
    p_sys = p_filter->p_sys = malloc( sizeof( aout_filter_sys_t ) );
 
149
 
 
150
    /* Create goom thread */
 
151
    p_sys->p_thread = p_thread =
 
152
        vlc_object_create( p_filter, sizeof( goom_thread_t ) );
 
153
    vlc_object_attach( p_thread, p_this );
 
154
 
 
155
    var_Create( p_thread, "goom-width", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
 
156
    var_Get( p_thread, "goom-width", &width );
 
157
    var_Create( p_thread, "goom-height", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
 
158
    var_Get( p_thread, "goom-height", &height );
 
159
 
 
160
    p_thread->p_vout =
 
161
        vout_Request( p_filter, NULL, width.i_int, height.i_int,
 
162
                      VLC_FOURCC('R','V','3','2'),
 
163
                      VOUT_ASPECT_FACTOR * width.i_int/height.i_int );
 
164
    if( p_thread->p_vout == NULL )
 
165
    {
 
166
        msg_Err( p_filter, "no suitable vout module" );
 
167
        vlc_object_detach( p_thread );
 
168
        vlc_object_destroy( p_thread );
 
169
        free( p_sys );
 
170
        return VLC_EGENERIC;
 
171
    }
 
172
    vlc_mutex_init( p_filter, &p_thread->lock );
 
173
    vlc_cond_init( p_filter, &p_thread->wait );
 
174
 
 
175
    p_thread->i_blocks = 0;
 
176
    aout_DateInit( &p_thread->date, p_filter->output.i_rate );
 
177
    aout_DateSet( &p_thread->date, 0 );
 
178
    p_thread->i_channels = aout_FormatNbChannels( &p_filter->input );
 
179
 
 
180
    p_thread->psz_title = TitleGet( VLC_OBJECT( p_filter ) );
 
181
 
 
182
    if( vlc_thread_create( p_thread, "Goom Update Thread", Thread,
 
183
                           VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
 
184
    {
 
185
        msg_Err( p_filter, "cannot lauch goom thread" );
 
186
        vout_Destroy( p_thread->p_vout );
 
187
        vlc_mutex_destroy( &p_thread->lock );
 
188
        vlc_cond_destroy( &p_thread->wait );
 
189
        if( p_thread->psz_title ) free( p_thread->psz_title );
 
190
        vlc_object_detach( p_thread );
 
191
        vlc_object_destroy( p_thread );
 
192
        free( p_sys );
 
193
        return VLC_EGENERIC;
 
194
    }
 
195
 
 
196
    return VLC_SUCCESS;
 
197
}
 
198
 
 
199
/*****************************************************************************
 
200
 * DoWork: process samples buffer
 
201
 *****************************************************************************
 
202
 * This function queues the audio buffer to be processed by the goom thread
 
203
 *****************************************************************************/
 
204
static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
 
205
                    aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
 
206
{
 
207
    aout_filter_sys_t *p_sys = p_filter->p_sys;
 
208
    block_t *p_block;
 
209
 
 
210
    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
 
211
    p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
 
212
 
 
213
    /* Queue sample */
 
214
    vlc_mutex_lock( &p_sys->p_thread->lock );
 
215
    if( p_sys->p_thread->i_blocks == MAX_BLOCKS )
 
216
    {
 
217
        vlc_mutex_unlock( &p_sys->p_thread->lock );
 
218
        return;
 
219
    }
 
220
 
 
221
    p_block = block_New( p_sys->p_thread, p_in_buf->i_nb_bytes );
 
222
    if( !p_block ) return;
 
223
    memcpy( p_block->p_buffer, p_in_buf->p_buffer, p_in_buf->i_nb_bytes );
 
224
    p_block->i_pts = p_in_buf->start_date;
 
225
 
 
226
    p_sys->p_thread->pp_blocks[p_sys->p_thread->i_blocks++] = p_block;
 
227
 
 
228
    vlc_cond_signal( &p_sys->p_thread->wait );
 
229
    vlc_mutex_unlock( &p_sys->p_thread->lock );
 
230
}
 
231
 
 
232
/*****************************************************************************
 
233
 * float to s16 conversion
 
234
 *****************************************************************************/
 
235
static inline int16_t FloatToInt16( float f )
 
236
{
 
237
    if( f >= 1.0 )
 
238
        return 32767;
 
239
    else if( f < -1.0 )
 
240
        return -32768;
 
241
    else
 
242
        return (int16_t)( f * 32768.0 );
 
243
}
 
244
 
 
245
/*****************************************************************************
 
246
 * Fill buffer
 
247
 *****************************************************************************/
 
248
static int FillBuffer( int16_t *p_data, int *pi_data,
 
249
                       audio_date_t *pi_date, audio_date_t *pi_date_end,
 
250
                       goom_thread_t *p_this )
 
251
{
 
252
    int i_samples = 0;
 
253
    block_t *p_block;
 
254
 
 
255
    while( *pi_data < 512 )
 
256
    {
 
257
        if( !p_this->i_blocks ) return VLC_EGENERIC;
 
258
 
 
259
        p_block = p_this->pp_blocks[0];
 
260
        i_samples = __MIN( 512 - *pi_data, p_block->i_buffer /
 
261
                           sizeof(float) / p_this->i_channels );
 
262
 
 
263
        /* Date management */
 
264
        if( p_block->i_pts > 0 &&
 
265
            p_block->i_pts != aout_DateGet( pi_date_end ) )
 
266
        {
 
267
           aout_DateSet( pi_date_end, p_block->i_pts );
 
268
        }
 
269
        p_block->i_pts = 0;
 
270
 
 
271
        aout_DateIncrement( pi_date_end, i_samples );
 
272
 
 
273
        while( i_samples > 0 )
 
274
        {
 
275
            float *p_float = (float *)p_block->p_buffer;
 
276
 
 
277
            p_data[*pi_data] = FloatToInt16( p_float[0] );
 
278
            if( p_this->i_channels > 1 )
 
279
                p_data[512 + *pi_data] = FloatToInt16( p_float[1] );
 
280
 
 
281
            (*pi_data)++;
 
282
            p_block->p_buffer += (sizeof(float) * p_this->i_channels);
 
283
            p_block->i_buffer -= (sizeof(float) * p_this->i_channels);
 
284
            i_samples--;
 
285
        }
 
286
 
 
287
        if( !p_block->i_buffer )
 
288
        {
 
289
            block_Release( p_block );
 
290
            p_this->i_blocks--;
 
291
            if( p_this->i_blocks )
 
292
                memmove( p_this->pp_blocks, p_this->pp_blocks + 1,
 
293
                         p_this->i_blocks * sizeof(block_t *) );
 
294
        }
 
295
    }
 
296
 
 
297
    *pi_date = *pi_date_end;
 
298
    *pi_data = 0;
 
299
    return VLC_SUCCESS;
 
300
}
 
301
 
 
302
/*****************************************************************************
 
303
 * Thread:
 
304
 *****************************************************************************/
 
305
static void Thread( vlc_object_t *p_this )
 
306
{
 
307
    goom_thread_t *p_thread = (goom_thread_t*)p_this;
 
308
    vlc_value_t width, height, speed;
 
309
    audio_date_t i_pts;
 
310
    int16_t p_data[2][512];
 
311
    int i_data = 0, i_count = 0;
 
312
    PluginInfo *p_plugin_info;
 
313
 
 
314
    var_Get( p_this, "goom-width", &width );
 
315
    var_Get( p_this, "goom-height", &height );
 
316
 
 
317
    var_Create( p_thread, "goom-speed", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
 
318
    var_Get( p_thread, "goom-speed", &speed );
 
319
    speed.i_int = MAX_SPEED - speed.i_int;
 
320
    if( speed.i_int < 0 ) speed.i_int = 0;
 
321
 
 
322
    p_plugin_info = goom_init( width.i_int, height.i_int );
 
323
 
 
324
    while( !p_thread->b_die )
 
325
    {
 
326
        uint32_t  *plane;
 
327
        picture_t *p_pic;
 
328
 
 
329
        /* goom_update is damn slow, so just copy data and release the lock */
 
330
        vlc_mutex_lock( &p_thread->lock );
 
331
        if( FillBuffer( (int16_t *)p_data, &i_data, &i_pts,
 
332
                        &p_thread->date, p_thread ) != VLC_SUCCESS )
 
333
            vlc_cond_wait( &p_thread->wait, &p_thread->lock );
 
334
        vlc_mutex_unlock( &p_thread->lock );
 
335
 
 
336
        /* Speed selection */
 
337
        if( speed.i_int && (++i_count % (speed.i_int+1)) ) continue;
 
338
 
 
339
        /* Frame dropping if necessary */
 
340
        if( aout_DateGet( &i_pts ) + GOOM_DELAY <= mdate() ) continue;
 
341
 
 
342
        plane = goom_update( p_plugin_info, p_data, 0, 0.0,
 
343
                             p_thread->psz_title, NULL );
 
344
 
 
345
        if( p_thread->psz_title )
 
346
        {
 
347
            free( p_thread->psz_title );
 
348
            p_thread->psz_title = NULL;
 
349
        }
 
350
 
 
351
        while( !( p_pic = vout_CreatePicture( p_thread->p_vout, 0, 0, 0 ) ) &&
 
352
               !p_thread->b_die )
 
353
        {
 
354
            msleep( VOUT_OUTMEM_SLEEP );
 
355
        }
 
356
 
 
357
        if( p_pic == NULL ) break;
 
358
 
 
359
        memcpy( p_pic->p[0].p_pixels, plane, width.i_int * height.i_int * 4 );
 
360
        vout_DatePicture( p_thread->p_vout, p_pic,
 
361
                          aout_DateGet( &i_pts ) + GOOM_DELAY );
 
362
        vout_DisplayPicture( p_thread->p_vout, p_pic );
 
363
    }
 
364
 
 
365
    goom_close( p_plugin_info );
 
366
}
 
367
 
 
368
/*****************************************************************************
 
369
 * Close: close the plugin
 
370
 *****************************************************************************/
 
371
static void Close( vlc_object_t *p_this )
 
372
{
 
373
    aout_filter_t     *p_filter = (aout_filter_t *)p_this;
 
374
    aout_filter_sys_t *p_sys = p_filter->p_sys;
 
375
 
 
376
    /* Stop Goom Thread */
 
377
    p_sys->p_thread->b_die = VLC_TRUE;
 
378
 
 
379
    vlc_mutex_lock( &p_sys->p_thread->lock );
 
380
    vlc_cond_signal( &p_sys->p_thread->wait );
 
381
    vlc_mutex_unlock( &p_sys->p_thread->lock );
 
382
 
 
383
    vlc_thread_join( p_sys->p_thread );
 
384
 
 
385
    /* Free data */
 
386
    vout_Request( p_filter, p_sys->p_thread->p_vout, 0, 0, 0, 0 );
 
387
    vlc_mutex_destroy( &p_sys->p_thread->lock );
 
388
    vlc_cond_destroy( &p_sys->p_thread->wait );
 
389
    vlc_object_detach( p_sys->p_thread );
 
390
 
 
391
    while( p_sys->p_thread->i_blocks-- )
 
392
    {
 
393
        block_Release( p_sys->p_thread->pp_blocks[p_sys->p_thread->i_blocks] );
 
394
    }
 
395
 
 
396
    vlc_object_destroy( p_sys->p_thread );
 
397
 
 
398
    free( p_sys );
 
399
}
 
400
 
 
401
static char *TitleGet( vlc_object_t *p_this )
 
402
{
 
403
    char *psz_title = NULL;
 
404
    input_thread_t *p_input =
 
405
        vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
 
406
 
 
407
    if( p_input )
 
408
    {
 
409
        char *psz = strrchr( p_input->psz_source, '/' );
 
410
 
 
411
        if( psz )
 
412
        {
 
413
            psz++;
 
414
        }
 
415
        else
 
416
        {
 
417
            psz = p_input->psz_source;
 
418
        }
 
419
        if( psz && *psz )
 
420
        {
 
421
            psz_title = strdup( psz );
 
422
        }
 
423
        vlc_object_release( p_input );
 
424
    }
 
425
 
 
426
    return psz_title;
 
427
}