]> git.sesse.net Git - vlc/blob - plugins/fx/scope.c
0367a9e4616911faf45dc787432514d546f50ba7
[vlc] / plugins / fx / scope.c
1 /*****************************************************************************
2  * scope.c : Scope effect module
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: scope.c,v 1.8 2002/06/01 18:04:48 sam Exp $
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>                                              /* strdup() */
29 #include <errno.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/aout.h>
33 #include <vlc/vout.h>
34
35 #define SCOPE_WIDTH 320
36 #define SCOPE_HEIGHT 240
37 #define SCOPE_ASPECT (VOUT_ASPECT_FACTOR*SCOPE_WIDTH/SCOPE_HEIGHT)
38
39 /*****************************************************************************
40  * aout_sys_t: scope audio output method descriptor
41  *****************************************************************************
42  * This structure is part of the audio output thread descriptor.
43  * It describes some scope specific variables.
44  *****************************************************************************/
45 struct aout_sys_s
46 {
47     aout_thread_t aout;
48     aout_fifo_t *p_aout_fifo;
49
50     vout_thread_t *p_vout;
51 };
52
53 /*****************************************************************************
54  * Local prototypes.
55  *****************************************************************************/
56 static void    aout_getfunctions( function_list_t * p_function_list );
57
58 static int     aout_Open        ( aout_thread_t *p_aout );
59 static int     aout_SetFormat   ( aout_thread_t *p_aout );
60 static int     aout_GetBufInfo  ( aout_thread_t *p_aout, int i_buffer_info );
61 static void    aout_Play        ( aout_thread_t *p_aout,
62                                   byte_t *buffer, int i_size );
63 static void    aout_Close       ( aout_thread_t *p_aout );
64
65 /*****************************************************************************
66  * Build configuration tree.
67  *****************************************************************************/
68 MODULE_CONFIG_START
69 MODULE_CONFIG_STOP
70
71 MODULE_INIT_START
72     SET_DESCRIPTION( _("scope effect module") )
73     ADD_CAPABILITY( AOUT, 0 )
74     ADD_SHORTCUT( "scope" )
75 MODULE_INIT_STOP
76
77 MODULE_ACTIVATE_START
78     aout_getfunctions( &p_module->p_functions->aout );
79 MODULE_ACTIVATE_STOP
80
81 MODULE_DEACTIVATE_START
82 MODULE_DEACTIVATE_STOP
83
84 /*****************************************************************************
85  * Functions exported as capabilities. They are declared as static so that
86  * we don't pollute the namespace too much.
87  *****************************************************************************/
88 static void aout_getfunctions( function_list_t * p_function_list )
89 {
90     p_function_list->functions.aout.pf_open = aout_Open;
91     p_function_list->functions.aout.pf_setformat = aout_SetFormat;
92     p_function_list->functions.aout.pf_getbufinfo = aout_GetBufInfo;
93     p_function_list->functions.aout.pf_play = aout_Play;
94     p_function_list->functions.aout.pf_close = aout_Close;
95 }
96
97 /*****************************************************************************
98  * aout_Open: open a scope effect plugin
99  *****************************************************************************/
100 static int aout_Open( aout_thread_t *p_aout )
101 {
102     char *psz_method;
103
104     /* Allocate structure */
105     p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
106     if( p_aout->p_sys == NULL )
107     {
108         msg_Err( p_aout, "out of memory" );
109         return -1;
110     }
111
112     psz_method = config_GetPsz( p_aout, "aout" );
113     if( psz_method )
114     {
115         if( !*psz_method )
116         {
117             free( psz_method );
118             return -1;
119         }
120     }
121     else
122     {
123         return -1;
124     }
125
126     /* Open video output */
127     p_aout->p_sys->p_vout =
128         vout_CreateThread( p_aout, SCOPE_WIDTH, SCOPE_HEIGHT,
129                            FOURCC_I420, SCOPE_ASPECT );
130
131     if( p_aout->p_sys->p_vout == NULL )
132     {
133         msg_Err( p_aout, "no suitable vout module" );
134         free( p_aout->p_sys );
135         return -1;
136     }
137
138     /* Open audio output  */
139     p_aout->p_sys->aout.i_format   = p_aout->i_format;
140     p_aout->p_sys->aout.i_rate     = p_aout->i_rate;
141     p_aout->p_sys->aout.i_channels = p_aout->i_channels;
142
143     p_aout->p_sys->aout.p_module =
144                   module_Need( p_aout, MODULE_CAPABILITY_AOUT,
145                                "", (void *)&p_aout->p_sys->aout );
146     if( p_aout->p_sys->aout.p_module == NULL )
147     {
148         msg_Err( p_aout, "no suitable aout module" );
149         vout_DestroyThread( p_aout->p_sys->p_vout );
150         free( p_aout->p_sys );
151         return -1;
152     }
153
154 #define aout_functions p_aout->p_sys->aout.p_module->p_functions->aout.functions.aout
155     p_aout->p_sys->aout.pf_open       = aout_functions.pf_open;
156     p_aout->p_sys->aout.pf_setformat  = aout_functions.pf_setformat;
157     p_aout->p_sys->aout.pf_getbufinfo = aout_functions.pf_getbufinfo;
158     p_aout->p_sys->aout.pf_play       = aout_functions.pf_play;
159     p_aout->p_sys->aout.pf_close      = aout_functions.pf_close;
160 #undef aout_functions
161     
162     return( 0 );
163 }
164
165 /*****************************************************************************
166  * aout_SetFormat: set the output format
167  *****************************************************************************/
168 static int aout_SetFormat( aout_thread_t *p_aout )
169 {
170     int i_ret;
171
172     /* Force the output method */
173     p_aout->p_sys->aout.i_format = p_aout->i_format;
174     p_aout->p_sys->aout.i_channels = p_aout->i_channels;
175     p_aout->p_sys->aout.i_rate = p_aout->i_rate;
176
177     /*
178      * Initialize audio device
179      */
180     i_ret = p_aout->p_sys->aout.pf_setformat( &p_aout->p_sys->aout );
181
182     if( i_ret )
183     {
184         return i_ret;
185     }
186
187     if( p_aout->p_sys->aout.i_format != p_aout->i_format
188          || p_aout->p_sys->aout.i_channels != p_aout->i_channels )
189     {
190         msg_Err( p_aout, "plugin is not very cooperative" );
191         return 0;
192     }
193
194     p_aout->i_channels = p_aout->p_sys->aout.i_channels;
195     p_aout->i_format = p_aout->p_sys->aout.i_format;
196     p_aout->i_rate = p_aout->p_sys->aout.i_rate;
197
198     return 0;
199 }
200
201 /*****************************************************************************
202  * aout_GetBufInfo: buffer status query
203  *****************************************************************************/
204 static int aout_GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
205 {
206     return p_aout->p_sys->aout.pf_getbufinfo( &p_aout->p_sys->aout,
207                                               i_buffer_limit );
208 }
209
210 /*****************************************************************************
211  * aout_Play: play a sound samples buffer
212  *****************************************************************************
213  * This function writes a buffer of i_length bytes in the socket
214  *****************************************************************************/
215 static void aout_Play( aout_thread_t *p_aout, byte_t *p_buffer, int i_size )
216 {
217     picture_t *p_outpic;
218     int i_index, i_image;
219     u8  *ppp_area[2][3];
220     u16 *p_sample;
221
222     /* Play the real sound */
223     p_aout->p_sys->aout.pf_play( &p_aout->p_sys->aout, p_buffer, i_size );
224
225     for( i_image = 0; (i_image + 1) * SCOPE_WIDTH * 8 < i_size ; i_image++ )
226     {
227         /* Don't stay here forever */
228         if( mdate() >= p_aout->date - 10000 )
229         {
230             break;
231         }
232
233         /* This is a new frame. Get a structure from the video_output. */
234         while( ( p_outpic = vout_CreatePicture( p_aout->p_sys->p_vout, 0, 0, 0 ) )
235                   == NULL )
236         {
237             if( p_aout->b_die )
238             {
239                 return;
240             }
241             msleep( VOUT_OUTMEM_SLEEP );
242         }
243
244         /* Blank the picture */
245         for( i_index = 0 ; i_index < p_outpic->i_planes ; i_index++ )
246         {
247             memset( p_outpic->p[i_index].p_pixels, i_index ? 0x80 : 0x00,
248                     p_outpic->p[i_index].i_lines * p_outpic->p[i_index].i_pitch );
249         }
250
251         /* We only support 2 channels for now */
252         for( i_index = 0 ; i_index < 2 ; i_index++ )
253         {
254             int j;
255             for( j = 0 ; j < 3 ; j++ )
256             {
257                 ppp_area[i_index][j] =
258                     p_outpic->p[j].p_pixels + i_index * p_outpic->p[j].i_lines
259                                 / p_aout->i_channels * p_outpic->p[j].i_pitch;
260             }
261         }
262
263         for( i_index = 0, p_sample = (u16*)p_buffer;
264              i_index < SCOPE_WIDTH;
265              i_index++ )
266         {
267             int i;
268             u8 i_value;
269
270             for( i = 0 ; i < 2 ; i++ )
271             {
272                 /* Left channel */
273                 i_value = *p_sample++ / 256 + 128;
274                 *(ppp_area[0][0]
275                    + p_outpic->p[0].i_pitch * i_index / SCOPE_WIDTH
276                    + p_outpic->p[0].i_lines * i_value / 512
277                        * p_outpic->p[0].i_pitch) = 0xbf;
278                 *(ppp_area[0][1]
279                    + p_outpic->p[1].i_pitch * i_index / SCOPE_WIDTH
280                    + p_outpic->p[1].i_lines * i_value / 512
281                       * p_outpic->p[1].i_pitch) = 0xff;
282
283                 /* Right channel */
284                 i_value = *p_sample++ / 256 + 128;
285                 *(ppp_area[1][0]
286                    + p_outpic->p[0].i_pitch * i_index / SCOPE_WIDTH
287                    + p_outpic->p[0].i_lines * i_value / 512
288                       * p_outpic->p[0].i_pitch) = 0x9f;
289                 *(ppp_area[1][2]
290                    + p_outpic->p[2].i_pitch * i_index / SCOPE_WIDTH
291                    + p_outpic->p[2].i_lines * i_value / 512
292                       * p_outpic->p[2].i_pitch) = 0xdd;
293             }
294         }
295
296         /* Display the picture - FIXME: find a better date :-) */
297         vout_DatePicture( p_aout->p_sys->p_vout, p_outpic,
298                           p_aout->date + i_image * 20000 );
299         vout_DisplayPicture( p_aout->p_sys->p_vout, p_outpic );
300
301         p_buffer += SCOPE_WIDTH * 4;
302     }
303 }
304
305 /*****************************************************************************
306  * aout_Close: close the Esound socket
307  *****************************************************************************/
308 static void aout_Close( aout_thread_t *p_aout )
309 {
310     p_aout->p_sys->aout.pf_close( &p_aout->p_sys->aout );
311     module_Unneed( p_aout->p_sys->aout.p_module );
312     vout_DestroyThread( p_aout->p_sys->p_vout );
313     free( p_aout->p_sys );
314 }
315