]> git.sesse.net Git - vlc/blob - src/control/media_instance.c
media_instance.c: Fix the position callback to retun the time. (Next time, we'll...
[vlc] / src / control / media_instance.c
1 /*****************************************************************************
2  * media_instance.c: Libvlc API Media Instance management functions
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 #include <vlc/libvlc.h>
25 #include <vlc_demux.h>
26 #include <vlc_input.h>
27 #include "libvlc_internal.h"
28 #include "libvlc.h"
29
30 static const libvlc_state_t vlc_to_libvlc_state_array[] =
31 {
32     [INIT_S]        = libvlc_Opening,
33     [OPENING_S]     = libvlc_Opening,
34     [BUFFERING_S]   = libvlc_Buffering,    
35     [PLAYING_S]     = libvlc_Playing,    
36     [PAUSE_S]       = libvlc_Paused,    
37     [END_S]         = libvlc_Ended,    
38     [ERROR_S]       = libvlc_Error,    
39 };
40 static inline libvlc_state_t vlc_to_libvlc_state( int vlc_state )
41 {
42     if( vlc_state < 0 || vlc_state > 6 )
43         return libvlc_Stopped;
44
45     return vlc_to_libvlc_state_array[vlc_state];
46 }
47
48 /*
49  * Release the associated input thread
50  *
51  * Object lock is NOT held.
52  */
53 static void release_input_thread( libvlc_media_instance_t *p_mi )
54 {
55     input_thread_t *p_input_thread;
56
57     if( !p_mi || p_mi->i_input_id == -1 )
58         return;
59
60     p_input_thread = (input_thread_t*)vlc_object_get(
61                                              p_mi->p_libvlc_instance->p_libvlc_int,
62                                              p_mi->i_input_id );
63
64     p_mi->i_input_id = -1;
65
66     if( !p_input_thread )
67         return;
68  
69     /* release for previous vlc_object_get */
70     vlc_object_release( p_input_thread );
71
72     /* release for initial p_input_thread yield (see _new()) */
73     vlc_object_release( p_input_thread );
74
75     /* No one is tracking this input_thread appart us. Destroy it */
76     if( p_mi->b_own_its_input_thread )
77     {
78         /* We owned this one */
79         input_StopThread( p_input_thread );
80         var_Destroy( p_input_thread, "drawable" );
81         input_DestroyThread( p_input_thread );
82     }
83     else
84     {
85         /* XXX: hack the playlist doesn't retain the input thread,
86          * so we did it for the playlist (see _new_from_input_thread),
87          * revert that here. This will be deleted with the playlist API */
88         vlc_object_release( p_input_thread );
89     }
90 }
91
92 /*
93  * Retrieve the input thread. Be sure to release the object
94  * once you are done with it. (libvlc Internal)
95  *
96  * Object lock is held.
97  */
98 input_thread_t *libvlc_get_input_thread( libvlc_media_instance_t *p_mi,
99                                          libvlc_exception_t *p_e )
100 {
101     input_thread_t *p_input_thread;
102
103     vlc_mutex_lock( &p_mi->object_lock );
104
105     if( !p_mi || p_mi->i_input_id == -1 )
106     {
107         vlc_mutex_unlock( &p_mi->object_lock );
108         RAISENULL( "Input is NULL" );
109     }
110
111     p_input_thread = (input_thread_t*)vlc_object_get(
112                                              p_mi->p_libvlc_instance->p_libvlc_int,
113                                              p_mi->i_input_id );
114     if( !p_input_thread )
115     {
116         vlc_mutex_unlock( &p_mi->object_lock );
117         RAISENULL( "Input does not exist" );
118     }
119
120     vlc_mutex_unlock( &p_mi->object_lock );
121     return p_input_thread;
122 }
123
124 /*
125  * input_state_changed (Private) (input var "state" Callback)
126  */
127 static int
128 input_state_changed( vlc_object_t * p_this, char const * psz_cmd,
129                      vlc_value_t oldval, vlc_value_t newval,
130                      void * p_userdata )
131 {
132     libvlc_media_instance_t * p_mi = p_userdata;
133     libvlc_event_t event;
134
135     printf("input_state_changed!!!!!!!!\n");
136     if( newval.i_int == oldval.i_int )
137         return VLC_SUCCESS; /* No change since last time, don't propagate */
138
139     switch ( newval.i_int )
140     {
141         case END_S:
142             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
143             event.type = libvlc_MediaInstanceReachedEnd;
144             break;
145         case PAUSE_S:
146             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_Playing, NULL);
147             event.type = libvlc_MediaInstancePaused;
148             break;
149         case PLAYING_S:
150                 printf("PLAYING_S!!!!!!!!\n");
151             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_Playing, NULL);
152             event.type = libvlc_MediaInstancePlayed;
153             break;
154         case ERROR_S:
155             libvlc_media_descriptor_set_state( p_mi->p_md, libvlc_Error, NULL);
156             event.type = libvlc_MediaInstancePlayed;
157             break;
158         default:
159             return VLC_SUCCESS;
160     }
161
162     libvlc_event_send( p_mi->p_event_manager, &event );
163     return VLC_SUCCESS;
164 }
165
166 /*
167  * input_position_changed (Private) (input var "intf-change" Callback)
168  */
169 static int
170 input_position_changed( vlc_object_t * p_this, char const * psz_cmd,
171                      vlc_value_t oldval, vlc_value_t newval,
172                      void * p_userdata )
173 {
174     libvlc_media_instance_t * p_mi = p_userdata;
175     vlc_value_t val;
176  
177     if (!strncmp(psz_cmd, "intf", 4 /* "-change" no need to go further */))
178     {
179         vlc_value_t val2;
180         input_thread_t * p_input = (input_thread_t *)p_this;
181
182         var_Get( p_input, "time", &val );
183         if ((val.i_time % I64C(500000)) != 0)
184             return VLC_SUCCESS; /* No need to have a better precision */
185
186         var_Get( p_input, "state", &val2 );
187         if( val2.i_int != PLAYING_S )
188             return VLC_SUCCESS; /* Don't send the position while stopped */
189     }
190     else
191         val.i_time = newval.i_time;
192
193     libvlc_event_t event;
194     event.type = libvlc_MediaInstancePositionChanged;
195     event.u.media_instance_position_changed.new_position = val.i_time;
196
197     libvlc_event_send( p_mi->p_event_manager, &event );
198     return VLC_SUCCESS;
199 }
200
201 /**************************************************************************
202  * Create a Media Instance object
203  **************************************************************************/
204 libvlc_media_instance_t *
205 libvlc_media_instance_new( libvlc_instance_t * p_libvlc_instance,
206                            libvlc_exception_t * p_e )
207 {
208     libvlc_media_instance_t * p_mi;
209
210     if( !p_libvlc_instance )
211     {
212         libvlc_exception_raise( p_e, "invalid libvlc instance" );
213         return NULL;
214     }
215
216     p_mi = malloc( sizeof(libvlc_media_instance_t) );
217     p_mi->p_md = NULL;
218     p_mi->drawable = 0;
219     p_mi->p_libvlc_instance = p_libvlc_instance;
220     p_mi->i_input_id = -1;
221     /* refcount strategy:
222      * - All items created by _new start with a refcount set to 1
223      * - Accessor _release decrease the refcount by 1, if after that
224      *   operation the refcount is 0, the object is destroyed.
225      * - Accessor _retain increase the refcount by 1 (XXX: to implement) */
226     p_mi->i_refcount = 1;
227     p_mi->b_own_its_input_thread = VLC_TRUE;
228     /* object_lock strategy:
229      * - No lock held in constructor
230      * - Lock when accessing all variable this lock is held
231      * - Lock when attempting to destroy the object the lock is also held */
232     vlc_mutex_init( p_mi->p_libvlc_instance->p_libvlc_int,
233                     &p_mi->object_lock );
234     p_mi->p_event_manager = libvlc_event_manager_new( p_mi,
235             p_libvlc_instance, p_e );
236     if( libvlc_exception_raised( p_e ) )
237     {
238         free( p_mi );
239         return NULL;
240     }
241  
242     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
243             libvlc_MediaInstanceReachedEnd, p_e );
244     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
245             libvlc_MediaInstancePaused, p_e );
246     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
247             libvlc_MediaInstancePlayed, p_e );
248     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
249             libvlc_MediaInstancePositionChanged, p_e );
250
251     return p_mi;
252 }
253
254 /**************************************************************************
255  * Create a Media Instance object with a media descriptor
256  **************************************************************************/
257 libvlc_media_instance_t *
258 libvlc_media_instance_new_from_media_descriptor(
259                                     libvlc_media_descriptor_t * p_md,
260                                     libvlc_exception_t *p_e )
261 {
262     libvlc_media_instance_t * p_mi;
263     p_mi = libvlc_media_instance_new( p_md->p_libvlc_instance, p_e );
264
265     if( !p_mi )
266         return NULL;
267
268     libvlc_media_descriptor_retain( p_md );
269     p_mi->p_md = p_md;
270
271     return p_mi;
272 }
273
274 /**************************************************************************
275  * Create a new media instance object from an input_thread (Libvlc Internal)
276  **************************************************************************/
277 libvlc_media_instance_t * libvlc_media_instance_new_from_input_thread(
278                                    struct libvlc_instance_t *p_libvlc_instance,
279                                    input_thread_t *p_input,
280                                    libvlc_exception_t *p_e )
281 {
282     libvlc_media_instance_t * p_mi;
283
284     if( !p_input )
285     {
286         libvlc_exception_raise( p_e, "invalid input thread" );
287         return NULL;
288     }
289
290     p_mi = libvlc_media_instance_new( p_libvlc_instance, p_e );
291
292     if( !p_mi )
293         return NULL;
294
295     p_mi->p_md = libvlc_media_descriptor_new_from_input_item(
296                     p_libvlc_instance,
297                     input_GetItem( p_input ), p_e );
298
299     if( !p_mi->p_md )
300     {
301         libvlc_media_instance_destroy( p_mi );
302         return NULL;
303     }
304
305     p_mi->i_input_id = p_input->i_object_id;
306     p_mi->b_own_its_input_thread = VLC_FALSE;
307
308     /* will be released in media_instance_release() */
309     vlc_object_yield( p_input );
310
311     /* XXX: Hack as the playlist doesn't yield the input thread we retain
312      * the input for the playlist. (see corresponding hack in _release) */
313     vlc_object_yield( p_input );
314
315     return p_mi;
316 }
317
318 /**************************************************************************
319  * Destroy a Media Instance object (libvlc internal)
320  *
321  * Warning: No lock held here, but hey, this is internal.
322  **************************************************************************/
323 void libvlc_media_instance_destroy( libvlc_media_instance_t *p_mi )
324 {
325     input_thread_t *p_input_thread;
326     libvlc_exception_t p_e;
327
328     libvlc_exception_init( &p_e );
329
330     if( !p_mi )
331         return;
332
333     p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
334
335     if( libvlc_exception_raised( &p_e ) )
336     {
337         libvlc_event_manager_release( p_mi->p_event_manager );
338         libvlc_exception_clear( &p_e );
339         free( p_mi );
340         return; /* no need to worry about no input thread */
341     }
342     vlc_mutex_destroy( &p_mi->object_lock );
343
344     input_DestroyThread( p_input_thread );
345
346     libvlc_media_descriptor_release( p_mi->p_md );
347
348     free( p_mi );
349 }
350
351 /**************************************************************************
352  * Release a Media Instance object
353  **************************************************************************/
354 void libvlc_media_instance_release( libvlc_media_instance_t *p_mi )
355 {
356     if( !p_mi )
357         return;
358
359     vlc_mutex_lock( &p_mi->object_lock );
360  
361     p_mi->i_refcount--;
362
363     if( p_mi->i_refcount > 0 )
364     {
365         vlc_mutex_unlock( &p_mi->object_lock );
366         return;
367     }
368     vlc_mutex_unlock( &p_mi->object_lock );
369     vlc_mutex_destroy( &p_mi->object_lock );
370
371     release_input_thread( p_mi );
372
373     libvlc_event_manager_release( p_mi->p_event_manager );
374  
375     libvlc_media_descriptor_release( p_mi->p_md );
376
377     free( p_mi );
378 }
379
380 /**************************************************************************
381  * Retain a Media Instance object
382  **************************************************************************/
383 void libvlc_media_instance_retain( libvlc_media_instance_t *p_mi )
384 {
385     if( !p_mi )
386         return;
387
388     p_mi->i_refcount++;
389 }
390
391 /**************************************************************************
392  * Set the Media descriptor associated with the instance
393  **************************************************************************/
394 void libvlc_media_instance_set_media_descriptor(
395                             libvlc_media_instance_t *p_mi,
396                             libvlc_media_descriptor_t *p_md,
397                             libvlc_exception_t *p_e )
398 {
399     (void)p_e;
400
401     if( !p_mi )
402         return;
403
404     vlc_mutex_lock( &p_mi->object_lock );
405
406     release_input_thread( p_mi );
407
408     libvlc_media_descriptor_release( p_mi->p_md );
409
410     if( !p_md )
411     {
412         p_mi->p_md = NULL;
413         vlc_mutex_unlock( &p_mi->object_lock );
414         return; /* It is ok to pass a NULL md */
415     }
416
417     libvlc_media_descriptor_retain( p_md );
418     p_mi->p_md = p_md;
419  
420     /* The policy here is to ignore that we were created using a different
421      * libvlc_instance, because we don't really care */
422     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
423
424     vlc_mutex_unlock( &p_mi->object_lock );
425 }
426
427 /**************************************************************************
428  * Get the Media descriptor associated with the instance
429  **************************************************************************/
430 libvlc_media_descriptor_t *
431 libvlc_media_instance_get_media_descriptor(
432                             libvlc_media_instance_t *p_mi,
433                             libvlc_exception_t *p_e )
434 {
435     (void)p_e;
436
437     if( !p_mi->p_md )
438         return NULL;
439
440     libvlc_media_descriptor_retain( p_mi->p_md );
441     return p_mi->p_md;
442 }
443
444 /**************************************************************************
445  * Get the event Manager
446  **************************************************************************/
447 libvlc_event_manager_t *
448 libvlc_media_instance_event_manager(
449                             libvlc_media_instance_t *p_mi,
450                             libvlc_exception_t *p_e )
451 {
452     (void)p_e;
453
454     return p_mi->p_event_manager;
455 }
456
457 /**************************************************************************
458  * Play
459  **************************************************************************/
460 void libvlc_media_instance_play( libvlc_media_instance_t *p_mi,
461                                  libvlc_exception_t *p_e )
462 {
463     input_thread_t * p_input_thread;
464
465     if( (p_input_thread = libvlc_get_input_thread( p_mi, p_e )) )
466     {
467         /* A thread alread exists, send it a play message */
468         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
469         vlc_object_release( p_input_thread );
470         return;
471     }
472
473     /* Ignore previous exception */
474     libvlc_exception_clear( p_e );
475
476     vlc_mutex_lock( &p_mi->object_lock );
477  
478     if( !p_mi->p_md )
479     {
480         libvlc_exception_raise( p_e, "no associated media descriptor" );
481         vlc_mutex_unlock( &p_mi->object_lock );
482         return;
483     }
484
485     p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int,
486                                          p_mi->p_md->p_input_item );
487     p_mi->i_input_id = p_input_thread->i_object_id;
488
489     if( p_mi->drawable )
490     {
491         vlc_value_t val;
492         val.i_int = p_mi->drawable;
493         var_Create( p_input_thread, "drawable", VLC_VAR_DOINHERIT );
494         var_Set( p_input_thread, "drawable", val );
495     }
496     var_AddCallback( p_input_thread, "state", input_state_changed, p_mi );
497     var_AddCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
498
499     /* will be released in media_instance_release() */
500     vlc_object_yield( p_input_thread );
501
502     vlc_mutex_unlock( &p_mi->object_lock );
503 }
504
505 /**************************************************************************
506  * Pause
507  **************************************************************************/
508 void libvlc_media_instance_pause( libvlc_media_instance_t *p_mi,
509                                   libvlc_exception_t *p_e )
510 {
511     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
512
513     if( !p_input_thread )
514         return;
515
516     input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
517     vlc_object_release( p_input_thread );
518 }
519
520 /**************************************************************************
521  * Stop
522  **************************************************************************/
523 void libvlc_media_instance_stop( libvlc_media_instance_t *p_mi,
524                                  libvlc_exception_t *p_e )
525 {
526     if( p_mi->b_own_its_input_thread )
527         release_input_thread( p_mi ); /* This will stop the input thread */
528     else
529     {
530         input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
531
532         if( !p_input_thread )
533             return;
534
535         input_StopThread( p_input_thread );
536         vlc_object_release( p_input_thread );
537     }
538 }
539
540 /**************************************************************************
541  * Set Drawable
542  **************************************************************************/
543 void libvlc_media_instance_set_drawable( libvlc_media_instance_t *p_mi,
544                                          libvlc_drawable_t drawable,
545                                          libvlc_exception_t *p_e )
546 {
547     p_mi->drawable = drawable;
548 }
549
550 /**************************************************************************
551  * Getters for stream information
552  **************************************************************************/
553 vlc_int64_t libvlc_media_instance_get_length(
554                              libvlc_media_instance_t *p_mi,
555                              libvlc_exception_t *p_e )
556 {
557     input_thread_t *p_input_thread;
558     vlc_value_t val;
559
560     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
561     if( !p_input_thread )
562         return -1;
563
564     var_Get( p_input_thread, "length", &val );
565     vlc_object_release( p_input_thread );
566
567     return (val.i_time+500LL)/1000LL;
568 }
569
570 vlc_int64_t libvlc_media_instance_get_time(
571                                    libvlc_media_instance_t *p_mi,
572                                    libvlc_exception_t *p_e )
573 {
574     input_thread_t *p_input_thread;
575     vlc_value_t val;
576
577     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
578     if( !p_input_thread )
579         return -1;
580
581     var_Get( p_input_thread , "time", &val );
582     vlc_object_release( p_input_thread );
583     return (val.i_time+500LL)/1000LL;
584 }
585
586 void libvlc_media_instance_set_time(
587                                  libvlc_media_instance_t *p_mi,
588                                  vlc_int64_t time,
589                                  libvlc_exception_t *p_e )
590 {
591     input_thread_t *p_input_thread;
592     vlc_value_t value;
593
594     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
595     if( !p_input_thread )
596         return;
597
598     value.i_time = time*1000LL;
599     var_Set( p_input_thread, "time", value );
600     vlc_object_release( p_input_thread );
601 }
602
603 void libvlc_media_instance_set_position(
604                                 libvlc_media_instance_t *p_mi,
605                                 float position,
606                                 libvlc_exception_t *p_e )
607 {
608     input_thread_t *p_input_thread;
609     vlc_value_t val;
610     val.f_float = position;
611
612     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
613     if( !p_input_thread )
614         return;
615
616     var_Set( p_input_thread, "position", val );
617     vlc_object_release( p_input_thread );
618 }
619
620 float libvlc_media_instance_get_position(
621                                  libvlc_media_instance_t *p_mi,
622                                  libvlc_exception_t *p_e )
623 {
624     input_thread_t *p_input_thread;
625     vlc_value_t val;
626
627     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
628     if( !p_input_thread )
629         return -1.0;
630
631     var_Get( p_input_thread, "position", &val );
632     vlc_object_release( p_input_thread );
633
634     return val.f_float;
635 }
636
637 void libvlc_media_instance_set_chapter(
638                                  libvlc_media_instance_t *p_mi,
639                                  int chapter,
640                                  libvlc_exception_t *p_e )
641 {
642     input_thread_t *p_input_thread;
643     vlc_value_t val;
644     val.i_int = chapter;
645
646     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
647     if( !p_input_thread )
648         return;
649
650     var_Set( p_input_thread, "chapter", val );
651     vlc_object_release( p_input_thread );
652 }
653
654 int libvlc_media_instance_get_chapter(
655                                  libvlc_media_instance_t *p_mi,
656                                  libvlc_exception_t *p_e )
657 {
658     input_thread_t *p_input_thread;
659     vlc_value_t val;
660
661     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
662     if( !p_input_thread )
663         return -1.0;
664
665     var_Get( p_input_thread, "chapter", &val );
666     vlc_object_release( p_input_thread );
667
668     return val.i_int;
669 }
670
671 int libvlc_media_instance_get_chapter_count(
672                                  libvlc_media_instance_t *p_mi,
673                                  libvlc_exception_t *p_e )
674 {
675     input_thread_t *p_input_thread;
676     vlc_value_t val;
677
678     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
679     if( !p_input_thread )
680         return -1.0;
681
682     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
683     vlc_object_release( p_input_thread );
684
685     return val.i_int;
686 }
687
688 float libvlc_media_instance_get_fps(
689                                  libvlc_media_instance_t *p_mi,
690                                  libvlc_exception_t *p_e)
691 {
692     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
693     double f_fps = 0.0;
694
695     if( p_input_thread )
696     {
697         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
698             f_fps = 0.0;
699         vlc_object_release( p_input_thread );
700     }
701     return f_fps;
702 }
703
704 vlc_bool_t libvlc_media_instance_will_play(
705                                  libvlc_media_instance_t *p_mi,
706                                  libvlc_exception_t *p_e)
707 {
708     input_thread_t *p_input_thread =
709                             libvlc_get_input_thread ( p_mi, p_e);
710     if ( !p_input_thread )
711         return VLC_FALSE;
712
713     if ( !p_input_thread->b_die && !p_input_thread->b_dead )
714     {
715         vlc_object_release( p_input_thread );
716         return VLC_TRUE;
717     }
718     vlc_object_release( p_input_thread );
719     return VLC_FALSE;
720 }
721
722 void libvlc_media_instance_set_rate(
723                                  libvlc_media_instance_t *p_mi,
724                                  float rate,
725                                  libvlc_exception_t *p_e )
726 {
727     input_thread_t *p_input_thread;
728     vlc_value_t val;
729
730     if( rate <= 0 )
731         RAISEVOID( "Rate value is invalid" );
732
733     val.i_int = 1000.0f/rate;
734
735     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
736     if ( !p_input_thread )
737         return;
738
739     var_Set( p_input_thread, "rate", val );
740     vlc_object_release( p_input_thread );
741 }
742
743 float libvlc_media_instance_get_rate(
744                                  libvlc_media_instance_t *p_mi,
745                                  libvlc_exception_t *p_e )
746 {
747     input_thread_t *p_input_thread;
748     vlc_value_t val;
749
750     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
751     if ( !p_input_thread )
752         return -1.0;
753
754     var_Get( p_input_thread, "rate", &val );
755     vlc_object_release( p_input_thread );
756
757     return (float)1000.0f/val.i_int;
758 }
759
760 libvlc_state_t libvlc_media_instance_get_state(
761                                  libvlc_media_instance_t *p_mi,
762                                  libvlc_exception_t *p_e )
763 {
764     input_thread_t *p_input_thread;
765     vlc_value_t val;
766
767     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
768     if ( !p_input_thread )
769         return libvlc_Stopped;
770
771     var_Get( p_input_thread, "state", &val );
772     vlc_object_release( p_input_thread );
773
774     return vlc_to_libvlc_state(val.i_int);
775 }