]> git.sesse.net Git - vlc/blob - modules/control/corba/mediacontrol-core.c
d7a412e206c70d9d5b616fd32acf03da009f3933
[vlc] / modules / control / corba / mediacontrol-core.c
1 #include "mediacontrol-core.h"
2
3 #include <vlc/intf.h>
4 #include <vlc/vout.h>
5 #include <vlc/aout.h>
6
7 #include <osd.h>
8
9 #define HAS_SNAPSHOT 1
10
11 #ifdef HAS_SNAPSHOT
12 #include <snapshot.h>
13 #endif
14
15 #include <stdlib.h>                                      /* malloc(), free() */
16 #include <string.h>
17
18 #include <errno.h>                                                 /* ENOMEM */
19 #include <stdio.h>
20 #include <ctype.h>
21
22 #ifdef HAVE_UNISTD_H
23 #    include <unistd.h>
24 #endif
25
26 #ifdef HAVE_SYS_TIME_H
27 #    include <sys/time.h>
28 #endif
29 #include <sys/types.h>
30
31 #define RAISE( c, m )  exception->code = c; \
32                        exception->message = strdup(m);
33
34 long long mediacontrol_unit_convert( input_thread_t *p_input,
35                                      mediacontrol_PositionKey from,
36                                      mediacontrol_PositionKey to,
37                                      long long value )
38 {
39     if( to == from )
40         return value;
41     
42     /* For all conversions, we need data from p_input */
43     if( !p_input )
44         return 0;
45     
46     switch( from )
47     {
48     case mediacontrol_MediaTime:
49         if( to == mediacontrol_ByteCount )
50             return value * 50 * p_input->stream.i_mux_rate / 1000;
51       
52         if( to == mediacontrol_SampleCount )
53         {
54             double f_fps;
55           
56             if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
57                 return 0;
58             else
59                 return( value * f_fps / 1000.0 );
60         }
61         /* Cannot happen */
62         /* See http://catb.org/~esr/jargon/html/entry/can't-happen.html */
63         break;
64       
65     case mediacontrol_SampleCount:
66     {
67         double f_fps;
68       
69         if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
70             return 0;
71       
72         if( to == mediacontrol_ByteCount )
73             return ( long long )( value * 50 * p_input->stream.i_mux_rate / f_fps );
74         
75         if( to == mediacontrol_MediaTime )
76             return( long long )( value * 1000.0 / ( double )f_fps );
77         
78         /* Cannot happen */
79         break;
80     }
81     case mediacontrol_ByteCount:
82         if( p_input->stream.i_mux_rate == 0 )
83             return 0;
84       
85         /* Convert an offset into milliseconds. Taken from input_ext-intf.c.
86            The 50 hardcoded constant comes from the definition of i_mux_rate :
87            i_mux_rate : the rate we read the stream (in units of 50 bytes/s) ;
88            0 if undef */
89         if( to == mediacontrol_MediaTime )
90             return ( long long )( 1000 * value / 50 / p_input->stream.i_mux_rate );
91       
92         if( to == mediacontrol_SampleCount )
93         {
94             double f_fps;
95             if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
96                 return 0;
97             else
98                 return ( long long )( value * f_fps / 50 / p_input->stream.i_mux_rate );
99         }
100         /* Cannot happen */
101         break;
102     }
103     /* Cannot happen */
104     return 0;
105 }
106
107 /* Converts a mediacontrol_Position into a time in microseconds in
108    movie clock time */
109 long long
110 mediacontrol_position2microsecond( input_thread_t* p_input, const mediacontrol_Position * pos )
111 {
112     switch( pos->origin )
113     {
114     case mediacontrol_AbsolutePosition:
115         return ( 1000 * mediacontrol_unit_convert( p_input, 
116                                                    pos->key, /* from */
117                                                    mediacontrol_MediaTime,  /* to */
118                                                    pos->value ) );
119         break;
120     case mediacontrol_RelativePosition:
121     {
122         long long l_pos;
123         vlc_value_t val;
124         
125         val.i_time = 0;
126         if( p_input )
127         {
128             var_Get( p_input, "time", &val );
129         }
130         
131         l_pos = 1000 * mediacontrol_unit_convert( p_input, 
132                                                   pos->key,
133                                                   mediacontrol_MediaTime,
134                                                   pos->value );
135         return val.i_time + l_pos;
136         break;
137     }
138     case mediacontrol_ModuloPosition:
139     {
140         long long l_pos;
141         vlc_value_t val;
142         
143         val.i_time = 0;
144         if( p_input )
145         {
146             var_Get( p_input, "length", &val );
147         }
148
149         if( val.i_time > 0)
150         {
151             l_pos = ( 1000 * mediacontrol_unit_convert( p_input, 
152                                                         pos->key,
153                                                         mediacontrol_MediaTime,
154                                                         pos->value ) );
155         }
156         else
157             l_pos = 0;
158         
159         return l_pos % val.i_time;
160         break;
161     }
162     }
163     return 0;
164 }
165
166 mediacontrol_RGBPicture*
167 mediacontrol_RGBPicture__alloc( int datasize )
168 {
169     mediacontrol_RGBPicture* pic;
170     
171     pic = ( mediacontrol_RGBPicture * )malloc( sizeof( mediacontrol_RGBPicture ) );
172     if( ! pic )
173         return NULL;
174     
175     pic->size = datasize;
176     pic->data = ( char* )malloc( datasize );
177     return pic;
178 }
179
180 void
181 mediacontrol_RGBPicture__free( mediacontrol_RGBPicture* pic )
182 {
183     if( pic )
184         free( pic->data );
185     free( pic );
186 }
187
188 mediacontrol_PlaylistSeq*
189 mediacontrol_PlaylistSeq__alloc( int size )
190 {
191     mediacontrol_PlaylistSeq* ps;
192   
193     ps =( mediacontrol_PlaylistSeq* )malloc( sizeof( mediacontrol_PlaylistSeq ) );
194     if( ! ps )
195         return NULL;
196
197     ps->size = size;
198     ps->data = ( char** )malloc( size * sizeof( char* ) );
199     return ps;
200 }
201
202 void
203 mediacontrol_PlaylistSeq__free( mediacontrol_PlaylistSeq* ps )
204 {
205     if( ps )
206     {
207         int i;
208         for( i = 0 ; i < ps->size ; i++ )
209             free( ps->data[i] );
210     }
211     free( ps->data );    
212     free( ps );
213 }
214
215 mediacontrol_Exception*
216 mediacontrol_exception_init( mediacontrol_Exception *exception )
217 {
218     if( exception == NULL )
219     {
220         exception = ( mediacontrol_Exception* )malloc( sizeof( mediacontrol_Exception ) );
221     }
222
223     exception->code = 0;
224     exception->message = NULL;
225     return exception;
226 }
227
228 void
229 mediacontrol_exception_free( mediacontrol_Exception *exception )
230 {
231     if( ! exception )
232         return;
233
234     free( exception->message );
235     free( exception );
236 }
237
238 mediacontrol_Instance* mediacontrol_new_from_object( vlc_object_t* p_object,
239                                                      mediacontrol_Exception *exception )
240 {
241     mediacontrol_Instance* retval;
242     vlc_object_t *p_vlc;
243     
244     p_vlc = vlc_object_find( p_object, VLC_OBJECT_ROOT, FIND_PARENT );
245     if( ! p_vlc )
246     {
247         RAISE( mediacontrol_InternalException, "Unable to initialize VLC" );
248         return NULL;
249     }
250     retval = ( mediacontrol_Instance* )malloc( sizeof( mediacontrol_Instance ) );
251     retval->p_vlc = p_vlc;
252     retval->vlc_object_id = p_vlc->i_object_id;
253
254     /* We can keep references on these, which should not change. Is it true ? */
255     retval->p_playlist = vlc_object_find( p_vlc, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
256     retval->p_intf = vlc_object_find( p_vlc, VLC_OBJECT_INTF, FIND_ANYWHERE );
257
258     if( ! retval->p_playlist || ! retval->p_intf )
259     {
260         RAISE( mediacontrol_InternalException, "No available interface" );
261         return NULL;
262     }
263     return retval;
264 };
265
266 /* Returns the current position in the stream. The returned value can
267    be relative or absolute( according to PositionOrigin ) and the unit
268    is set by PositionKey */
269 mediacontrol_Position*
270 mediacontrol_get_media_position( mediacontrol_Instance *self,
271                                  const mediacontrol_PositionOrigin an_origin,
272                                  const mediacontrol_PositionKey a_key,
273                                  mediacontrol_Exception *exception )
274 {
275     mediacontrol_Position* retval;
276     vlc_value_t val;
277     input_thread_t * p_input = self->p_playlist->p_input;
278     
279     exception = mediacontrol_exception_init( exception );
280
281     retval = ( mediacontrol_Position* )malloc( sizeof( mediacontrol_Position ) );
282     retval->origin = an_origin;
283     retval->key = a_key;
284   
285     if( ! p_input )
286     {
287         /* 
288            RAISE( mediacontrol_InternalException, "No input thread." );
289            return( NULL );
290         */
291         retval->value = 0;
292         return retval;
293     }
294
295     if(  an_origin == mediacontrol_RelativePosition
296          || an_origin == mediacontrol_ModuloPosition )
297     {
298         /* Relative or ModuloPosition make no sense */
299         retval->value = 0;
300         return retval;
301     }
302
303     /* We are asked for an AbsolutePosition. */
304     val.i_time = 0;
305     var_Get( p_input, "time", &val );
306     /* FIXME: check val.i_time > 0 */
307     
308     retval->value = mediacontrol_unit_convert( p_input,
309                                                mediacontrol_MediaTime,
310                                                a_key,
311                                                val.i_time / 1000 );
312     return retval;
313 }
314
315 /* Sets the media position */
316 void
317 mediacontrol_set_media_position( mediacontrol_Instance *self,
318                                  const mediacontrol_Position * a_position,
319                                  mediacontrol_Exception *exception )
320 {
321     vlc_value_t val;
322     input_thread_t * p_input = self->p_playlist->p_input;
323
324     exception=mediacontrol_exception_init( exception );
325     if( ! p_input )
326     {
327         RAISE( mediacontrol_InternalException, "No input thread." );
328         return;
329     }
330
331     if(  !p_input->stream.b_seekable )
332     {
333         RAISE( mediacontrol_InvalidPosition, "Stream not seekable" );
334         return;
335     }
336
337     val.i_time = mediacontrol_position2microsecond( p_input, a_position );
338     var_Set( p_input, "time", val );
339     return;
340 }
341
342 /* Starts playing a stream */
343 void
344 mediacontrol_start( mediacontrol_Instance *self,
345                     const mediacontrol_Position * a_position, 
346                     mediacontrol_Exception *exception )
347 {
348     playlist_t * p_playlist = self->p_playlist;
349
350     exception = mediacontrol_exception_init( exception );
351     if( ! p_playlist )
352     {
353         RAISE( mediacontrol_PlaylistException, "No available playlist" );
354         return;
355     }
356
357     vlc_mutex_lock( &p_playlist->object_lock );
358     if( p_playlist->i_size )
359     {
360         vlc_value_t val;
361
362         vlc_mutex_unlock( &p_playlist->object_lock );
363
364         /* Set start time */
365         val.i_int = mediacontrol_position2microsecond( p_playlist->p_input, a_position ) / 1000000;
366         var_Set( p_playlist, "start-time", val );
367
368         playlist_Play( p_playlist );      
369     }
370     else
371     {
372         RAISE( mediacontrol_PlaylistException, "Empty playlist." );
373         vlc_mutex_unlock( &p_playlist->object_lock );
374         return;
375     }
376
377     return;
378 }
379
380 void
381 mediacontrol_pause( mediacontrol_Instance *self,
382                     const mediacontrol_Position * a_position, 
383                     mediacontrol_Exception *exception )
384 {
385     input_thread_t *p_input = self->p_playlist->p_input;;
386
387     /* FIXME: use the a_position parameter */
388     exception=mediacontrol_exception_init( exception );
389     if( p_input != NULL )
390     {
391         var_SetInteger( p_input, "state", PAUSE_S );
392     }
393     else
394     {
395         RAISE( mediacontrol_InternalException, "No input" );
396     }
397   
398     return;
399 }
400
401 void
402 mediacontrol_resume( mediacontrol_Instance *self,
403                      const mediacontrol_Position * a_position, 
404                      mediacontrol_Exception *exception )
405 {
406     input_thread_t *p_input = self->p_playlist->p_input;
407
408     /* FIXME: use the a_position parameter */
409     exception=mediacontrol_exception_init( exception );
410     if( p_input != NULL )
411     {
412         var_SetInteger( p_input, "state", PAUSE_S );
413     }
414     else
415     {
416         RAISE( mediacontrol_InternalException, "No input" );
417     }
418 }
419
420 void
421 mediacontrol_stop( mediacontrol_Instance *self,
422                    const mediacontrol_Position * a_position, 
423                    mediacontrol_Exception *exception )
424 {
425     /* FIXME: use the a_position parameter */
426     exception=mediacontrol_exception_init( exception );
427     if( !self->p_playlist )
428     {
429         RAISE( mediacontrol_PlaylistException, "No playlist" );
430         return;
431     }
432
433     playlist_Stop( self->p_playlist );
434 }
435
436 void
437 mediacontrol_playlist_add_item( mediacontrol_Instance *self,
438                                 const char * psz_file,
439                                 mediacontrol_Exception *exception )
440 {
441     exception=mediacontrol_exception_init( exception );
442     if( !self->p_playlist )
443     {
444         RAISE( mediacontrol_InternalException, "No playlist" );
445         return;
446     }
447
448     playlist_Add( self->p_playlist, psz_file, psz_file , PLAYLIST_REPLACE, 0 );
449 }
450
451 void
452 mediacontrol_playlist_clear( mediacontrol_Instance *self,
453                              mediacontrol_Exception *exception )
454 {
455     exception=mediacontrol_exception_init( exception );
456     if( !self->p_playlist )
457     {
458         RAISE( mediacontrol_PlaylistException, "No playlist" );
459         return;
460     }
461
462     playlist_Clear( self->p_playlist );
463   
464     return;
465 }
466
467 mediacontrol_PlaylistSeq *
468 mediacontrol_playlist_get_list( mediacontrol_Instance *self,
469                                 mediacontrol_Exception *exception )
470 {
471     mediacontrol_PlaylistSeq *retval;
472     int i_index;
473     playlist_t * p_playlist = self->p_playlist;;
474     int i_playlist_size;
475
476     exception=mediacontrol_exception_init( exception );
477     if( !p_playlist )
478     {
479         RAISE( mediacontrol_PlaylistException, "No playlist" );
480         return NULL;
481     }
482   
483     vlc_mutex_lock( &p_playlist->object_lock );
484     i_playlist_size = p_playlist->i_size;
485   
486     retval = mediacontrol_PlaylistSeq__alloc( i_playlist_size );
487   
488     for( i_index = 0 ; i_index < i_playlist_size ; i_index++ )
489     {
490         retval->data[i_index] = strdup( p_playlist->pp_items[i_index]->input.psz_uri );
491     }
492     vlc_mutex_unlock( &p_playlist->object_lock );
493   
494     return retval;
495 }
496
497 mediacontrol_RGBPicture*
498 _mediacontrol_createRGBPicture( int i_width, int i_height, long i_chroma, long long l_date,
499                                 char* p_data, int i_datasize )
500 {
501     mediacontrol_RGBPicture *retval;
502
503     retval = mediacontrol_RGBPicture__alloc( i_datasize );
504     if( retval )
505     {
506         retval->width  = i_width;
507         retval->height = i_height;
508         retval->type   = i_chroma;
509         retval->date   = l_date;
510         retval->size   = i_datasize;
511         memcpy( retval->data, p_data, i_datasize );
512     }
513     return retval;
514 }
515
516 mediacontrol_RGBPicture *
517 mediacontrol_snapshot( mediacontrol_Instance *self,
518                        const mediacontrol_Position * a_position,
519                        mediacontrol_Exception *exception )
520 {
521     mediacontrol_RGBPicture *retval = NULL;
522     input_thread_t* p_input = self->p_playlist->p_input;
523     vout_thread_t *p_vout = NULL;
524     int i_datasize;
525     snapshot_t **pointer;
526     vlc_value_t val;
527     int i_index;
528     snapshot_t *p_best_snapshot;
529     long searched_date;
530 #ifdef HAS_SNAPSHOT
531     int i_cachesize;
532 #endif
533
534     exception=mediacontrol_exception_init( exception );
535
536     /* 
537        if( var_Get( self->p_vlc, "snapshot-id", &val ) == VLC_SUCCESS )
538        p_vout = vlc_object_get( self->p_vlc, val.i_int );
539     */
540
541     /* FIXME: if in p_libvlc, we cannot have multiple video outputs */
542     /* Once corrected, search for snapshot-id to modify all instances */
543     if( var_Get( p_input, "snapshot-id", &val ) != VLC_SUCCESS )
544     {
545         RAISE( mediacontrol_InternalException, "No snapshot-id in p_input" );
546         return NULL;
547     }
548     p_vout = vlc_object_get( self->p_vlc, val.i_int );
549
550     if( ! p_vout )
551     {
552         RAISE( mediacontrol_InternalException, "No snapshot module" );
553         return NULL;
554     }
555
556 #ifdef HAS_SNAPSHOT   
557     /* We test if the vout is a snapshot module. We cannot test
558        pvout_psz_object_name( which is NULL ). But we can check if
559        there are snapshot-specific variables */
560     if( var_Get( p_vout, "snapshot-datasize", &val ) != VLC_SUCCESS )
561     {
562         RAISE( mediacontrol_InternalException, "No snapshot module" );
563         vlc_object_release( p_vout );
564         return NULL;
565     }
566     i_datasize = val.i_int;
567    
568     /* Handle the a_position parameter */
569     if( ! ( a_position->origin == mediacontrol_RelativePosition
570             && a_position->value == 0 ) )
571     {
572         /* The position is not the current one. Go to it. */
573         mediacontrol_set_media_position( self, 
574                                          ( mediacontrol_Position* ) a_position, 
575                                          exception );
576         if( exception->code )
577         {
578             vlc_object_release( p_vout );
579             return NULL;
580         }
581     }
582
583     /* FIXME: We should not go further until we got past the position
584        ( which means that we had the possibility to capture the right
585        picture ). */
586    
587     vlc_mutex_lock( &p_vout->picture_lock );
588    
589     searched_date = mediacontrol_position2microsecond( p_input, 
590                                                        ( mediacontrol_Position * ) a_position );
591     
592     var_Get( p_vout, "snapshot-cache-size", &val );
593     i_cachesize = val.i_int  ;
594    
595     var_Get( p_vout, "snapshot-list-pointer", &val );
596     pointer = ( snapshot_t ** )val.p_address;
597    
598     if( ! pointer )
599     {
600         RAISE( mediacontrol_InternalException, "No available snapshot" );
601        
602         vlc_mutex_unlock( &p_vout->picture_lock );
603         vlc_object_release( p_vout );
604         return NULL;
605     }
606
607     /* Find the more appropriate picture, based on date */
608     p_best_snapshot = pointer[0];
609
610     for( i_index = 1 ; i_index < i_cachesize ; i_index++ )
611     {
612         long l_diff = pointer[i_index]->date - searched_date;
613         if( l_diff > 0 && l_diff < abs( p_best_snapshot->date - searched_date ))
614         {
615             /* This one is closer, and _after_ the requested position */
616             p_best_snapshot = pointer[i_index];
617         }
618     }
619    
620     /* FIXME: add a test for the case that no picture matched the test
621        ( we have p_best_snapshot == pointer[0] */
622     retval = _mediacontrol_createRGBPicture( p_best_snapshot->i_width,
623                                              p_best_snapshot->i_height,
624                                              p_vout->output.i_chroma,
625                                              p_best_snapshot->date,
626                                              p_best_snapshot->p_data,
627                                              i_datasize );
628
629     vlc_mutex_unlock( &p_vout->picture_lock );
630     vlc_object_release( p_vout );
631
632 #endif
633
634     return retval;
635 }
636
637 mediacontrol_RGBPicture **
638 mediacontrol_all_snapshots( mediacontrol_Instance *self,
639                             mediacontrol_Exception *exception )
640 {
641     mediacontrol_RGBPicture **retval = NULL;
642     vout_thread_t *p_vout = NULL;
643     int i_datasize;
644     int i_cachesize;
645     vlc_value_t val;
646     int i_index;
647 #ifdef HAS_SNAPSHOT
648     snapshot_t **pointer;
649 #endif
650
651     exception=mediacontrol_exception_init( exception );
652
653     if( var_Get( self->p_playlist->p_input, "snapshot-id", &val ) == VLC_SUCCESS )
654         p_vout = vlc_object_get( self->p_vlc, val.i_int );
655
656     if( ! p_vout )
657     {
658         RAISE( mediacontrol_InternalException, "No snapshot module" );
659         return NULL;
660     }
661 #ifdef HAS_SNAPSHOT
662     /* We test if the vout is a snapshot module. We cannot test
663        pvout_psz_object_name( which is NULL ). But we can check if
664        there are snapshot-specific variables */
665     if( var_Get( p_vout, "snapshot-datasize", &val ) != VLC_SUCCESS )
666     {
667         RAISE( mediacontrol_InternalException, "No snapshot module" );
668         vlc_object_release( p_vout );
669         return NULL;
670     }
671     i_datasize = val.i_int;
672
673     vlc_mutex_lock( &p_vout->picture_lock );
674
675     var_Get( p_vout, "snapshot-cache-size", &val );
676     i_cachesize = val.i_int  ;
677
678     var_Get( p_vout, "snapshot-list-pointer", &val );
679     pointer = ( snapshot_t ** )val.p_address;
680
681     if( ! pointer )
682     {
683         RAISE( mediacontrol_InternalException, "No available picture" );
684
685         vlc_mutex_unlock( &p_vout->picture_lock );
686         vlc_object_release( p_vout );
687         return NULL;
688     }
689
690     retval = ( mediacontrol_RGBPicture** )malloc( (i_cachesize + 1 ) * sizeof( char* ));
691
692     for( i_index = 0 ; i_index < i_cachesize ; i_index++ )
693     {
694         snapshot_t *p_s = pointer[i_index];
695         mediacontrol_RGBPicture *p_rgb;
696
697         p_rgb = _mediacontrol_createRGBPicture( p_s->i_width,
698                                                 p_s->i_height,
699                                                 p_vout->output.i_chroma,
700                                                 p_s->date,
701                                                 p_s->p_data,
702                                                 i_datasize );
703        
704         retval[i_index] = p_rgb;
705     }
706
707     retval[i_cachesize] = NULL;
708    
709     vlc_mutex_unlock( &p_vout->picture_lock );
710     vlc_object_release( p_vout );
711
712 #endif
713
714     return retval;
715 }
716
717 void
718 mediacontrol_display_text( mediacontrol_Instance *self,
719                            const char * message,
720                            const mediacontrol_Position * begin,
721                            const mediacontrol_Position * end,
722                            mediacontrol_Exception *exception )
723 {
724     input_thread_t *p_input = NULL;
725     vout_thread_t *p_vout = NULL;
726
727     p_vout = vlc_object_find( self->p_playlist, VLC_OBJECT_VOUT, FIND_CHILD ); 
728     if( ! p_vout )
729     {
730         RAISE( mediacontrol_InternalException, "No video output" );
731         return;
732     }
733   
734     if( begin->origin == mediacontrol_RelativePosition &&
735         begin->value == 0 && 
736         end->origin == mediacontrol_RelativePosition )
737     {
738         mtime_t i_duration = 0;
739       
740         i_duration = 1000 * mediacontrol_unit_convert( self->p_playlist->p_input,
741                                                        end->key,
742                                                        mediacontrol_MediaTime,
743                                                        end->value );
744
745         vout_ShowTextRelative( p_vout, SUBT1_CHAN, ( char* ) message, NULL, 
746                                OSD_ALIGN_BOTTOM | OSD_ALIGN_LEFT, 20, 20, 
747                                i_duration );
748     }
749     else
750     {
751         mtime_t i_debut, i_fin, i_now;
752       
753         p_input = self->p_playlist->p_input;
754         if( ! p_input )
755         {
756             RAISE( mediacontrol_InternalException, "No input" );
757             vlc_object_release( p_vout );
758             return;
759         }
760       
761         i_now = input_ClockGetTS( p_input, NULL, 0 );
762       
763         i_debut = mediacontrol_position2microsecond( p_input, 
764                                                      ( mediacontrol_Position* ) begin );
765         i_debut += i_now;
766       
767         i_fin = mediacontrol_position2microsecond( p_input, 
768                                                    ( mediacontrol_Position * ) end );
769         i_fin += i_now;
770       
771         vout_ShowTextAbsolute( p_vout, SUBT1_CHAN, ( char* )message, NULL, 
772                                OSD_ALIGN_BOTTOM | OSD_ALIGN_LEFT, 20, 20, 
773                                i_debut, i_fin );
774     }
775   
776     vlc_object_release( p_vout );
777 }
778
779 mediacontrol_StreamInformation *
780 mediacontrol_get_stream_information( mediacontrol_Instance *self,
781                                      mediacontrol_PositionKey a_key,
782                                      mediacontrol_Exception *exception )
783 {
784     mediacontrol_StreamInformation *retval;
785     input_thread_t *p_input = self->p_playlist->p_input;
786     vlc_value_t val;
787   
788     retval = ( mediacontrol_StreamInformation* )malloc( sizeof( mediacontrol_StreamInformation ) );
789     if( ! retval )
790     {
791         RAISE( mediacontrol_InternalException, "Out of memory" );
792         return NULL;
793     }
794   
795     if( ! p_input )
796     {
797         /* No p_input defined */
798         retval->streamstatus = mediacontrol_UndefinedStatus;
799         retval->url          = strdup( "None" );
800         retval->position     = 0;
801         retval->length       = 0;
802     }
803     else
804     {
805         switch( p_input->stream.control.i_status )
806         {
807         case UNDEF_S       :
808             retval->streamstatus = mediacontrol_UndefinedStatus;
809             break;
810         case PLAYING_S     :
811             retval->streamstatus = mediacontrol_PlayingStatus;
812             break;
813         case PAUSE_S       :
814             retval->streamstatus = mediacontrol_PauseStatus;
815             break;
816         case FORWARD_S     :
817             retval->streamstatus = mediacontrol_ForwardStatus;
818             break;
819         case BACKWARD_S    :
820             retval->streamstatus = mediacontrol_BackwardStatus;
821             break;
822         case INIT_S        :
823             retval->streamstatus = mediacontrol_InitStatus;
824             break;
825         case END_S         :
826             retval->streamstatus = mediacontrol_EndStatus;
827             break;
828         default :
829             retval->streamstatus = mediacontrol_UndefinedStatus;
830             break;
831         }
832       
833         retval->url = strdup( p_input->psz_source );
834
835         /* TIME and LENGTH are in microseconds. We want them in ms */
836         var_Get( p_input, "time", &val);
837         retval->position = val.i_time / 1000;
838
839         var_Get( p_input, "length", &val);
840         retval->length = val.i_time / 1000;
841
842         retval->position = mediacontrol_unit_convert( p_input, 
843                                                       mediacontrol_MediaTime, a_key, 
844                                                       retval->position );
845         retval->length   = mediacontrol_unit_convert( p_input, 
846                                                       mediacontrol_MediaTime, a_key, 
847                                                       retval->length );
848     }
849     return retval;
850 }
851
852 unsigned short
853 mediacontrol_sound_get_volume( mediacontrol_Instance *self,
854                                mediacontrol_Exception *exception )
855 {
856     short retval;
857     audio_volume_t i_volume;
858
859     if( !self->p_intf )
860     {
861         RAISE( mediacontrol_InternalException, "No interface module" );
862         return 0;
863     }
864     aout_VolumeGet( self->p_intf, &i_volume );
865     retval = i_volume;
866     return retval;
867 }
868
869 void
870 mediacontrol_sound_set_volume( mediacontrol_Instance *self,
871                                const unsigned short volume,
872                                mediacontrol_Exception *exception )
873 {
874     if( !self->p_intf )
875     {
876         RAISE( mediacontrol_InternalException, "No interface module" );
877         return;
878     }
879     aout_VolumeSet( self->p_intf,( audio_volume_t )volume );
880 }