Merge fixes to the python binding from my branch
[vlc.git] / src / control / audio_video.c
1 /*****************************************************************************
2  * audio_video.c: Audio/Video management : volume, snapshot, OSD
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id: vlc.c 10786 2005-04-23 23:19:17Z zorglub $
6  *
7  * Authors: Olivier Aubert <olivier.aubert@liris.univ-lyon1.fr>
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 #include <vlc/control.h>
25
26 #include <vlc/intf.h>
27 #include <vlc/vout.h>
28 #include <vlc/aout.h>
29 #include <vlc_demux.h>
30
31 #include <vlc_osd.h>
32
33 #define HAS_SNAPSHOT 1
34
35 #ifdef HAS_SNAPSHOT
36 #include <snapshot.h>
37 #endif
38
39 #include <stdlib.h>                                      /* malloc(), free() */
40 #include <string.h>
41
42 #include <errno.h>                                                 /* ENOMEM */
43 #include <stdio.h>
44 #include <ctype.h>
45
46 #ifdef HAVE_UNISTD_H
47 #    include <unistd.h>
48 #endif
49 #ifdef HAVE_SYS_TIME_H
50 #    include <sys/time.h>
51 #endif
52 #ifdef HAVE_SYS_TYPES_H
53 #    include <sys/types.h>
54 #endif
55
56 #define RAISE( c, m )  exception->code = c; \
57                        exception->message = strdup(m);
58
59 mediacontrol_RGBPicture *
60 mediacontrol_snapshot( mediacontrol_Instance *self,
61                        const mediacontrol_Position * a_position,
62                        mediacontrol_Exception *exception )
63 {
64     mediacontrol_RGBPicture *retval = NULL;
65     input_thread_t* p_input = self->p_playlist->p_input;
66     vout_thread_t *p_vout = NULL;
67     int i_datasize;
68     snapshot_t **pointer;
69     vlc_value_t val;
70     int i_index;
71     snapshot_t *p_best_snapshot;
72     long searched_date;
73 #ifdef HAS_SNAPSHOT
74     int i_cachesize;
75 #endif
76
77     exception=mediacontrol_exception_init( exception );
78
79     /*
80        if( var_Get( self->p_vlc, "snapshot-id", &val ) == VLC_SUCCESS )
81        p_vout = vlc_object_get( self->p_vlc, val.i_int );
82     */
83
84     /* FIXME: if in p_libvlc, we cannot have multiple video outputs */
85     /* Once corrected, search for snapshot-id to modify all instances */
86     if( var_Get( p_input, "snapshot-id", &val ) != VLC_SUCCESS )
87     {
88         RAISE( mediacontrol_InternalException, "No snapshot-id in p_input" );
89         return NULL;
90     }
91     p_vout = vlc_object_get( self->p_vlc, val.i_int );
92
93     if( ! p_vout )
94     {
95         RAISE( mediacontrol_InternalException, "No snapshot module" );
96         return NULL;
97     }
98
99 #ifdef HAS_SNAPSHOT
100     /* We test if the vout is a snapshot module. We cannot test
101        pvout_psz_object_name( which is NULL ). But we can check if
102        there are snapshot-specific variables */
103     if( var_Get( p_vout, "snapshot-datasize", &val ) != VLC_SUCCESS )
104     {
105         RAISE( mediacontrol_InternalException, "No snapshot module" );
106         vlc_object_release( p_vout );
107         return NULL;
108     }
109     i_datasize = val.i_int;
110
111     /* Handle the a_position parameter */
112     if( ! ( a_position->origin == mediacontrol_RelativePosition
113             && a_position->value == 0 ) )
114     {
115         /* The position is not the current one. Go to it. */
116         mediacontrol_set_media_position( self,
117                                          ( mediacontrol_Position* ) a_position,
118                                          exception );
119         if( exception->code )
120         {
121             vlc_object_release( p_vout );
122             return NULL;
123         }
124     }
125
126     /* FIXME: We should not go further until we got past the position
127        ( which means that we had the possibility to capture the right
128        picture ). */
129
130     vlc_mutex_lock( &p_vout->picture_lock );
131
132     searched_date = mediacontrol_position2microsecond( p_input,
133                                                        ( mediacontrol_Position * ) a_position );
134
135     var_Get( p_vout, "snapshot-cache-size", &val );
136     i_cachesize = val.i_int  ;
137
138     var_Get( p_vout, "snapshot-list-pointer", &val );
139     pointer = ( snapshot_t ** )val.p_address;
140
141     if( ! pointer )
142     {
143         RAISE( mediacontrol_InternalException, "No available snapshot" );
144
145         vlc_mutex_unlock( &p_vout->picture_lock );
146         vlc_object_release( p_vout );
147         return NULL;
148     }
149
150     /* Find the more appropriate picture, based on date */
151     p_best_snapshot = pointer[0];
152
153     for( i_index = 1 ; i_index < i_cachesize ; i_index++ )
154     {
155         long l_diff = pointer[i_index]->date - searched_date;
156         if( l_diff > 0 && l_diff < abs( p_best_snapshot->date - searched_date ))
157         {
158             /* This one is closer, and _after_ the requested position */
159             p_best_snapshot = pointer[i_index];
160         }
161     }
162
163     /* FIXME: add a test for the case that no picture matched the test
164        ( we have p_best_snapshot == pointer[0] */
165     retval = _mediacontrol_createRGBPicture( p_best_snapshot->i_width,
166                                              p_best_snapshot->i_height,
167                                              p_vout->output.i_chroma,
168                                              p_best_snapshot->date,
169                                              p_best_snapshot->p_data,
170                                              i_datasize );
171
172     vlc_mutex_unlock( &p_vout->picture_lock );
173     vlc_object_release( p_vout );
174
175 #endif
176
177     return retval;
178 }
179
180 mediacontrol_RGBPicture **
181 mediacontrol_all_snapshots( mediacontrol_Instance *self,
182                             mediacontrol_Exception *exception )
183 {
184     mediacontrol_RGBPicture **retval = NULL;
185     vout_thread_t *p_vout = NULL;
186     int i_datasize;
187     int i_cachesize;
188     vlc_value_t val;
189     int i_index;
190 #ifdef HAS_SNAPSHOT
191     snapshot_t **pointer;
192 #endif
193
194     exception=mediacontrol_exception_init( exception );
195
196     if( var_Get( self->p_playlist->p_input, "snapshot-id", &val ) == VLC_SUCCESS )
197         p_vout = vlc_object_get( self->p_vlc, val.i_int );
198
199     if( ! p_vout )
200     {
201         RAISE( mediacontrol_InternalException, "No snapshot module" );
202         return NULL;
203     }
204 #ifdef HAS_SNAPSHOT
205     /* We test if the vout is a snapshot module. We cannot test
206        pvout_psz_object_name( which is NULL ). But we can check if
207        there are snapshot-specific variables */
208     if( var_Get( p_vout, "snapshot-datasize", &val ) != VLC_SUCCESS )
209     {
210         RAISE( mediacontrol_InternalException, "No snapshot module" );
211         vlc_object_release( p_vout );
212         return NULL;
213     }
214     i_datasize = val.i_int;
215
216     vlc_mutex_lock( &p_vout->picture_lock );
217
218     var_Get( p_vout, "snapshot-cache-size", &val );
219     i_cachesize = val.i_int  ;
220
221     var_Get( p_vout, "snapshot-list-pointer", &val );
222     pointer = ( snapshot_t ** )val.p_address;
223
224     if( ! pointer )
225     {
226         RAISE( mediacontrol_InternalException, "No available picture" );
227
228         vlc_mutex_unlock( &p_vout->picture_lock );
229         vlc_object_release( p_vout );
230         return NULL;
231     }
232
233     retval = ( mediacontrol_RGBPicture** )malloc( (i_cachesize + 1 ) * sizeof( char* ));
234
235     for( i_index = 0 ; i_index < i_cachesize ; i_index++ )
236     {
237         snapshot_t *p_s = pointer[i_index];
238         mediacontrol_RGBPicture *p_rgb;
239
240         p_rgb = _mediacontrol_createRGBPicture( p_s->i_width,
241                                                 p_s->i_height,
242                                                 p_vout->output.i_chroma,
243                                                 p_s->date,
244                                                 p_s->p_data,
245                                                 i_datasize );
246
247         retval[i_index] = p_rgb;
248     }
249
250     retval[i_cachesize] = NULL;
251
252     vlc_mutex_unlock( &p_vout->picture_lock );
253     vlc_object_release( p_vout );
254
255 #endif
256
257     return retval;
258 }
259
260 int mediacontrol_showtext( vout_thread_t *p_vout, int i_channel,
261                            char *psz_string, text_style_t *p_style,
262                            int i_flags, int i_hmargin, int i_vmargin,
263                            mtime_t i_start, mtime_t i_stop )
264 {
265     subpicture_t *p_spu;
266     video_format_t fmt;
267
268     if( !psz_string ) return VLC_EGENERIC;
269
270     p_spu = spu_CreateSubpicture( p_vout->p_spu );
271     if( !p_spu ) return VLC_EGENERIC;
272
273     /* Create a new subpicture region */
274     memset( &fmt, 0, sizeof(video_format_t) );
275     fmt.i_chroma = VLC_FOURCC('T','E','X','T');
276     fmt.i_aspect = 0;
277     fmt.i_width = fmt.i_height = 0;
278     fmt.i_x_offset = fmt.i_y_offset = 0;
279     p_spu->p_region = p_spu->pf_create_region( VLC_OBJECT(p_vout), &fmt );
280     if( !p_spu->p_region )
281     {
282         msg_Err( p_vout, "cannot allocate SPU region" );
283         spu_DestroySubpicture( p_vout->p_spu, p_spu );
284         return VLC_EGENERIC;
285     }
286
287     p_spu->p_region->psz_text = strdup( psz_string );
288     p_spu->i_start = i_start;
289     p_spu->i_stop = i_stop;
290     p_spu->b_ephemer = VLC_FALSE;
291     p_spu->b_absolute = VLC_FALSE;
292
293     p_spu->i_x = i_hmargin;
294     p_spu->i_y = i_vmargin;
295     p_spu->i_flags = i_flags;
296     p_spu->i_channel = i_channel;
297
298     spu_DisplaySubpicture( p_vout->p_spu, p_spu );
299
300     return VLC_SUCCESS;
301 }
302
303
304 void
305 mediacontrol_display_text( mediacontrol_Instance *self,
306                            const char * message,
307                            const mediacontrol_Position * begin,
308                            const mediacontrol_Position * end,
309                            mediacontrol_Exception *exception )
310 {
311     input_thread_t *p_input = NULL;
312     vout_thread_t *p_vout = NULL;
313     char* psz_message;
314
315     psz_message = strdup( message );
316     if( !psz_message )
317     {
318         RAISE( mediacontrol_InternalException, "No more memory" );
319         return;
320     }
321
322     p_vout = vlc_object_find( self->p_playlist, VLC_OBJECT_VOUT, FIND_CHILD );
323     if( ! p_vout )
324     {
325         RAISE( mediacontrol_InternalException, "No video output" );
326         return;
327     }
328
329     if( begin->origin == mediacontrol_RelativePosition &&
330         begin->value == 0 &&
331         end->origin == mediacontrol_RelativePosition )
332     {
333         mtime_t i_duration = 0;
334         mtime_t i_now = mdate();
335
336         i_duration = 1000 * mediacontrol_unit_convert( self->p_playlist->p_input,
337                                                        end->key,
338                                                        mediacontrol_MediaTime,
339                                                        end->value );
340
341         mediacontrol_showtext( p_vout, DEFAULT_CHAN, psz_message, NULL,
342                                OSD_ALIGN_BOTTOM | OSD_ALIGN_LEFT, 0, 0,
343                                i_now, i_now + i_duration );
344     }
345     else
346     {
347         mtime_t i_debut, i_fin, i_now;
348
349         p_input = self->p_playlist->p_input;
350         if( ! p_input )
351         {
352             RAISE( mediacontrol_InternalException, "No input" );
353             vlc_object_release( p_vout );
354             return;
355         }
356
357         /* FIXME */
358         /* i_now = input_ClockGetTS( p_input, NULL, 0 ); */
359         i_now = mdate();
360         
361         i_debut = mediacontrol_position2microsecond( p_input,
362                                                      ( mediacontrol_Position* ) begin );
363         i_debut += i_now;
364
365         i_fin = mediacontrol_position2microsecond( p_input,
366                                                    ( mediacontrol_Position * ) end );
367         i_fin += i_now;
368
369         vout_ShowTextAbsolute( p_vout, DEFAULT_CHAN, psz_message, NULL,
370                                OSD_ALIGN_BOTTOM | OSD_ALIGN_LEFT, 0, 0,
371                                i_debut, i_fin );
372     }
373
374     vlc_object_release( p_vout );
375 }
376
377 unsigned short
378 mediacontrol_sound_get_volume( mediacontrol_Instance *self,
379                                mediacontrol_Exception *exception )
380 {
381     short retval;
382     audio_volume_t i_volume;
383
384     if( !self->p_intf )
385     {
386         RAISE( mediacontrol_InternalException, "No interface module" );
387         return 0;
388     }
389     aout_VolumeGet( self->p_intf, &i_volume );
390     retval = i_volume;
391     return retval;
392 }
393
394 void
395 mediacontrol_sound_set_volume( mediacontrol_Instance *self,
396                                const unsigned short volume,
397                                mediacontrol_Exception *exception )
398 {
399     if( !self->p_intf )
400     {
401         RAISE( mediacontrol_InternalException, "No interface module" );
402         return;
403     }
404     aout_VolumeSet( self->p_intf,( audio_volume_t )volume );
405 }
406
407 vlc_bool_t mediacontrol_set_visual( mediacontrol_Instance *self,
408                                     WINDOWHANDLE visual_id,
409                                     mediacontrol_Exception *exception )
410 {
411     vlc_value_t value;
412     int ret;
413
414     if( !self->p_vlc )
415     {
416         RAISE( mediacontrol_InternalException, "No vlc reference" );
417         return 0;
418     }
419     value.i_int=visual_id;
420     ret = var_Set(self->p_vlc, "drawable", value);
421     
422     return (ret == VLC_SUCCESS);
423 }