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