* modules/codec/ffmpeg/*: modified the ffmpeg video codec to use direct
[vlc.git] / modules / visualization / scope / scope.c
1 /*****************************************************************************
2  * scope.c : Scope effect module
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: scope.c,v 1.2 2002/08/12 09:34:15 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_t
46 {
47     aout_fifo_t *p_aout_fifo;
48
49     aout_thread_t *p_aout;
50     vout_thread_t *p_vout;
51 };
52
53 /*****************************************************************************
54  * Local prototypes
55  *****************************************************************************/
56 static int  Open         ( vlc_object_t * );             
57 static void Close        ( vlc_object_t * );                   
58
59 static int  SetFormat    ( aout_thread_t * );  
60 static int  GetBufInfo   ( aout_thread_t *, int );
61 static void Play         ( aout_thread_t *, byte_t *, int );
62
63 /*****************************************************************************
64  * Module descriptor
65  *****************************************************************************/
66 vlc_module_begin();
67     set_description( _("scope effect") ); 
68     set_capability( "audio output", 0 );
69     set_callbacks( Open, Close );
70     add_shortcut( "scope" );
71 vlc_module_end();
72
73 /*****************************************************************************
74  * Open: open a scope effect plugin
75  *****************************************************************************/
76 static int Open( vlc_object_t *p_this )
77 {
78     aout_thread_t *p_aout = (aout_thread_t *)p_this;
79     char *psz_method;
80
81     /* Allocate structure */
82     p_aout->p_sys = malloc( sizeof( aout_sys_t ) );
83     if( p_aout->p_sys == NULL )
84     {
85         msg_Err( p_aout, "out of memory" );
86         return -1;
87     }
88
89     psz_method = config_GetPsz( p_aout, "aout" );
90     if( psz_method )
91     {
92         if( !*psz_method )
93         {
94             free( psz_method );
95             return -1;
96         }
97     }
98     else
99     {
100         return -1;
101     }
102
103     /* Open video output */
104     p_aout->p_sys->p_vout =
105         vout_CreateThread( p_aout, SCOPE_WIDTH, SCOPE_HEIGHT,
106                            VLC_FOURCC('I','4','2','0'), SCOPE_ASPECT );
107
108     if( p_aout->p_sys->p_vout == NULL )
109     {
110         msg_Err( p_aout, "no suitable vout module" );
111         free( p_aout->p_sys );
112         return -1;
113     }
114
115     /* Open audio output  */
116     p_aout->p_sys->p_aout = vlc_object_create( p_aout, VLC_OBJECT_AOUT );
117
118     p_aout->p_sys->p_aout->i_format   = p_aout->i_format;
119     p_aout->p_sys->p_aout->i_rate     = p_aout->i_rate;
120     p_aout->p_sys->p_aout->i_channels = p_aout->i_channels;
121
122     p_aout->p_sys->p_aout->p_module =
123                   module_Need( p_aout->p_sys->p_aout, "audio output", "" );
124     if( p_aout->p_sys->p_aout->p_module == NULL )
125     {
126         msg_Err( p_aout, "no suitable aout module" );
127         vlc_object_destroy( p_aout->p_sys->p_aout );
128         vout_DestroyThread( p_aout->p_sys->p_vout );
129         free( p_aout->p_sys );
130         return -1;
131     }
132
133     vlc_object_attach( p_aout->p_sys->p_aout, p_aout );
134
135     p_aout->pf_setformat = SetFormat;
136     p_aout->pf_getbufinfo = GetBufInfo;
137     p_aout->pf_play = Play;
138
139     return( 0 );
140 }
141
142 /*****************************************************************************
143  * SetFormat: set the output format
144  *****************************************************************************/
145 static int SetFormat( aout_thread_t *p_aout )
146 {
147     int i_ret;
148
149     /* Force the output method */
150     p_aout->p_sys->p_aout->i_format = p_aout->i_format;
151     p_aout->p_sys->p_aout->i_channels = p_aout->i_channels;
152     p_aout->p_sys->p_aout->i_rate = p_aout->i_rate;
153
154     /*
155      * Initialize audio device
156      */
157     i_ret = p_aout->p_sys->p_aout->pf_setformat( p_aout->p_sys->p_aout );
158
159     if( i_ret )
160     {
161         return i_ret;
162     }
163
164     if( p_aout->p_sys->p_aout->i_format != p_aout->i_format
165          || p_aout->p_sys->p_aout->i_channels != p_aout->i_channels )
166     {
167         msg_Err( p_aout, "plugin is not very cooperative" );
168         return 0;
169     }
170
171     p_aout->i_channels = p_aout->p_sys->p_aout->i_channels;
172     p_aout->i_format = p_aout->p_sys->p_aout->i_format;
173     p_aout->i_rate = p_aout->p_sys->p_aout->i_rate;
174
175     return 0;
176 }
177
178 /*****************************************************************************
179  * GetBufInfo: buffer status query
180  *****************************************************************************/
181 static int GetBufInfo( aout_thread_t *p_aout, int i_buffer_limit )
182 {
183     return p_aout->p_sys->p_aout->pf_getbufinfo( p_aout->p_sys->p_aout,
184                                                  i_buffer_limit );
185 }
186
187 /*****************************************************************************
188  * Play: play a sound samples buffer
189  *****************************************************************************
190  * This function writes a buffer of i_length bytes in the socket
191  *****************************************************************************/
192 static void Play( aout_thread_t *p_aout, byte_t *p_buffer, int i_size )
193 {
194     picture_t *p_outpic;
195     int i_index, i_image;
196     u8  *ppp_area[2][3];
197     u16 *p_sample;
198
199     /* Play the real sound */
200     p_aout->p_sys->p_aout->pf_play( p_aout->p_sys->p_aout, p_buffer, i_size );
201
202     for( i_image = 0; (i_image + 1) * SCOPE_WIDTH * 8 < i_size ; i_image++ )
203     {
204         /* Don't stay here forever */
205         if( mdate() >= p_aout->date - 10000 )
206         {
207             break;
208         }
209
210         /* This is a new frame. Get a structure from the video_output. */
211         while( ( p_outpic = vout_CreatePicture( p_aout->p_sys->p_vout, 0, 0, 0 ) )
212                   == NULL )
213         {
214             if( p_aout->b_die )
215             {
216                 return;
217             }
218             msleep( VOUT_OUTMEM_SLEEP );
219         }
220
221         /* Blank the picture */
222         for( i_index = 0 ; i_index < p_outpic->i_planes ; i_index++ )
223         {
224             memset( p_outpic->p[i_index].p_pixels, i_index ? 0x80 : 0x00,
225                     p_outpic->p[i_index].i_lines * p_outpic->p[i_index].i_pitch );
226         }
227
228         /* We only support 2 channels for now */
229         for( i_index = 0 ; i_index < 2 ; i_index++ )
230         {
231             int j;
232             for( j = 0 ; j < 3 ; j++ )
233             {
234                 ppp_area[i_index][j] =
235                     p_outpic->p[j].p_pixels + i_index * p_outpic->p[j].i_lines
236                                 / p_aout->i_channels * p_outpic->p[j].i_pitch;
237             }
238         }
239
240         for( i_index = 0, p_sample = (u16*)p_buffer;
241              i_index < SCOPE_WIDTH;
242              i_index++ )
243         {
244             int i;
245             u8 i_value;
246
247             for( i = 0 ; i < 2 ; i++ )
248             {
249                 /* Left channel */
250                 i_value = *p_sample++ / 256 + 128;
251                 *(ppp_area[0][0]
252                    + p_outpic->p[0].i_pitch * i_index / SCOPE_WIDTH
253                    + p_outpic->p[0].i_lines * i_value / 512
254                        * p_outpic->p[0].i_pitch) = 0xbf;
255                 *(ppp_area[0][1]
256                    + p_outpic->p[1].i_pitch * i_index / SCOPE_WIDTH
257                    + p_outpic->p[1].i_lines * i_value / 512
258                       * p_outpic->p[1].i_pitch) = 0xff;
259
260                 /* Right channel */
261                 i_value = *p_sample++ / 256 + 128;
262                 *(ppp_area[1][0]
263                    + p_outpic->p[0].i_pitch * i_index / SCOPE_WIDTH
264                    + p_outpic->p[0].i_lines * i_value / 512
265                       * p_outpic->p[0].i_pitch) = 0x9f;
266                 *(ppp_area[1][2]
267                    + p_outpic->p[2].i_pitch * i_index / SCOPE_WIDTH
268                    + p_outpic->p[2].i_lines * i_value / 512
269                       * p_outpic->p[2].i_pitch) = 0xdd;
270             }
271         }
272
273         /* Display the picture - FIXME: find a better date :-) */
274         vout_DatePicture( p_aout->p_sys->p_vout, p_outpic,
275                           p_aout->date + i_image * 20000 );
276         vout_DisplayPicture( p_aout->p_sys->p_vout, p_outpic );
277
278         p_buffer += SCOPE_WIDTH * 4;
279     }
280 }
281
282 /*****************************************************************************
283  * Close: close the plugin
284  *****************************************************************************/
285 static void Close( vlc_object_t *p_this )
286 {
287     aout_thread_t *p_aout = (aout_thread_t *)p_this;
288
289     /* Kill audio output */
290     module_Unneed( p_aout->p_sys->p_aout, p_aout->p_sys->p_aout->p_module );
291     vlc_object_detach( p_aout->p_sys->p_aout );
292     vlc_object_destroy( p_aout->p_sys->p_aout );
293
294     /* Kill video output */
295     vout_DestroyThread( p_aout->p_sys->p_vout );
296
297     free( p_aout->p_sys );
298 }
299