f112c2e50ec7c6e071aae1d5154a4f0356e354a8
[vlc.git] / src / control / media_player.c
1 /*****************************************************************************
2  * media_player.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 "libvlc_internal.h"
25
26 #include <vlc/libvlc.h>
27 #include <vlc_demux.h>
28 #include <vlc_input.h>
29 #include "libvlc.h"
30
31 static int
32 input_state_changed( vlc_object_t * p_this, char const * psz_cmd,
33                      vlc_value_t oldval, vlc_value_t newval,
34                      void * p_userdata );
35 static int
36 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
37                         vlc_value_t oldval, vlc_value_t newval,
38                         void * p_userdata );
39 static int
40 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
41                         vlc_value_t oldval, vlc_value_t newval,
42                         void * p_userdata );
43 static int
44 input_position_changed( vlc_object_t * p_this, char const * psz_cmd,
45                      vlc_value_t oldval, vlc_value_t newval,
46                      void * p_userdata );
47 static int
48 input_time_changed( vlc_object_t * p_this, char const * psz_cmd,
49                      vlc_value_t oldval, vlc_value_t newval,
50                      void * p_userdata );
51
52 static const libvlc_state_t vlc_to_libvlc_state_array[] =
53 {
54     [INIT_S]        = libvlc_Opening,
55     [OPENING_S]     = libvlc_Opening,
56     [BUFFERING_S]   = libvlc_Buffering,    
57     [PLAYING_S]     = libvlc_Playing,    
58     [PAUSE_S]       = libvlc_Paused,    
59     [END_S]         = libvlc_Ended,    
60     [ERROR_S]       = libvlc_Error,    
61 };
62 static inline libvlc_state_t vlc_to_libvlc_state( int vlc_state )
63 {
64     if( vlc_state < 0 || vlc_state > 6 )
65         return libvlc_Stopped;
66
67     return vlc_to_libvlc_state_array[vlc_state];
68 }
69
70 /*
71  * Release the associated input thread
72  *
73  * Object lock is NOT held.
74  */
75 static void release_input_thread( libvlc_media_player_t *p_mi )
76 {
77     input_thread_t * p_input_thread;
78
79     if( !p_mi || !p_mi->p_input_thread )
80         return;
81
82     p_input_thread = p_mi->p_input_thread;
83
84     /* No one is tracking this input_thread appart us. Destroy it */
85     if( p_mi->b_own_its_input_thread )
86     {
87         var_DelCallback( p_input_thread, "state", input_state_changed, p_mi );
88         var_DelCallback( p_input_thread, "seekable", input_seekable_changed, p_mi );
89         var_DelCallback( p_input_thread, "pausable", input_pausable_changed, p_mi );
90         var_DelCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
91         var_DelCallback( p_input_thread, "intf-change", input_time_changed, p_mi );
92
93         /* We owned this one */
94         input_StopThread( p_input_thread );
95
96         var_Destroy( p_input_thread, "drawable" );
97     }
98
99     vlc_object_release( p_input_thread );
100
101     p_mi->p_input_thread = NULL;
102 }
103
104 /*
105  * Retrieve the input thread. Be sure to release the object
106  * once you are done with it. (libvlc Internal)
107  *
108  * Object lock is held.
109  */
110 input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi,
111                                          libvlc_exception_t *p_e )
112 {
113     input_thread_t *p_input_thread;
114
115     if( !p_mi ) RAISENULL( "Media Instance is NULL" );
116     
117     vlc_mutex_lock( &p_mi->object_lock );
118
119     if( !p_mi->p_input_thread )
120     {
121         vlc_mutex_unlock( &p_mi->object_lock );
122         RAISENULL( "Input is NULL" );
123     }
124
125     p_input_thread = p_mi->p_input_thread;
126     vlc_object_yield( p_input_thread );
127
128     vlc_mutex_unlock( &p_mi->object_lock );
129
130     return p_input_thread;
131 }
132
133 /*
134  * input_state_changed (Private) (input var "state" Callback)
135  */
136 static int
137 input_state_changed( vlc_object_t * p_this, char const * psz_cmd,
138                      vlc_value_t oldval, vlc_value_t newval,
139                      void * p_userdata )
140 {
141     VLC_UNUSED(oldval);
142     VLC_UNUSED(p_this);
143     VLC_UNUSED(psz_cmd);
144     libvlc_media_player_t * p_mi = p_userdata;
145     libvlc_event_t event;
146     libvlc_event_type_t type = newval.i_int;
147
148     switch ( type )
149     {
150         case END_S:
151             libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
152             event.type = libvlc_MediaPlayerEndReached;
153             break;
154         case PAUSE_S:
155             libvlc_media_set_state( p_mi->p_md, libvlc_Playing, NULL);
156             event.type = libvlc_MediaPlayerPaused;
157             break;
158         case PLAYING_S:
159             libvlc_media_set_state( p_mi->p_md, libvlc_Playing, NULL);
160             event.type = libvlc_MediaPlayerPlayed;
161             break;
162         case ERROR_S:
163             libvlc_media_set_state( p_mi->p_md, libvlc_Error, NULL);
164             event.type = libvlc_MediaPlayerEncounteredError;
165             break;
166         default:
167             return VLC_SUCCESS;
168     }
169
170     libvlc_event_send( p_mi->p_event_manager, &event );
171     return VLC_SUCCESS;
172 }
173
174 static int
175 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
176                         vlc_value_t oldval, vlc_value_t newval,
177                         void * p_userdata )
178 {
179     VLC_UNUSED(oldval);
180     VLC_UNUSED(p_this);
181     VLC_UNUSED(psz_cmd);
182     libvlc_media_player_t * p_mi = p_userdata;
183     libvlc_event_t event;
184
185     libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
186     event.type = libvlc_MediaPlayerSeekableChanged;
187     event.u.media_player_seekable_changed.new_seekable = newval.b_bool;
188
189     libvlc_event_send( p_mi->p_event_manager, &event );
190     return VLC_SUCCESS;
191 }
192
193 static int
194 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
195                         vlc_value_t oldval, vlc_value_t newval,
196                         void * p_userdata )
197 {
198     VLC_UNUSED(oldval);
199     VLC_UNUSED(p_this);
200     VLC_UNUSED(psz_cmd);
201     libvlc_media_player_t * p_mi = p_userdata;
202     libvlc_event_t event;
203
204     libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
205     event.type = libvlc_MediaPlayerPausableChanged;
206     event.u.media_player_pausable_changed.new_pausable = newval.b_bool;
207
208     libvlc_event_send( p_mi->p_event_manager, &event );
209     return VLC_SUCCESS;
210 }
211
212 /*
213  * input_position_changed (Private) (input var "intf-change" Callback)
214  */
215 static int
216 input_position_changed( vlc_object_t * p_this, char const * psz_cmd,
217                      vlc_value_t oldval, vlc_value_t newval,
218                      void * p_userdata )
219 {
220     VLC_UNUSED(oldval);
221     libvlc_media_player_t * p_mi = p_userdata;
222     vlc_value_t val;
223
224     if (!strncmp(psz_cmd, "intf", 4 /* "-change" no need to go further */))
225     {
226         input_thread_t * p_input = (input_thread_t *)p_this;
227
228         var_Get( p_input, "state", &val );
229         if( val.i_int != PLAYING_S )
230             return VLC_SUCCESS; /* Don't send the position while stopped */
231
232         var_Get( p_input, "position", &val );
233     }
234     else
235         val.i_time = newval.i_time;
236
237     libvlc_event_t event;
238     event.type = libvlc_MediaPlayerPositionChanged;
239     event.u.media_player_position_changed.new_position = val.f_float;
240
241     libvlc_event_send( p_mi->p_event_manager, &event );
242     return VLC_SUCCESS;
243 }
244
245 /*
246  * input_time_changed (Private) (input var "intf-change" Callback)
247  */
248 static int
249 input_time_changed( vlc_object_t * p_this, char const * psz_cmd,
250                      vlc_value_t oldval, vlc_value_t newval,
251                      void * p_userdata )
252 {
253     VLC_UNUSED(oldval);
254     libvlc_media_player_t * p_mi = p_userdata;
255     vlc_value_t val;
256
257     if (!strncmp(psz_cmd, "intf", 4 /* "-change" no need to go further */))
258     {
259         input_thread_t * p_input = (input_thread_t *)p_this;
260     
261         var_Get( p_input, "state", &val );
262         if( val.i_int != PLAYING_S )
263             return VLC_SUCCESS; /* Don't send the position while stopped */
264
265         var_Get( p_input, "time", &val );
266     }
267     else
268         val.i_time = newval.i_time;
269
270     libvlc_event_t event;
271     event.type = libvlc_MediaPlayerTimeChanged;
272     event.u.media_player_time_changed.new_time = val.i_time;
273     libvlc_event_send( p_mi->p_event_manager, &event );
274     return VLC_SUCCESS;
275 }
276
277 /**************************************************************************
278  * Create a Media Instance object
279  **************************************************************************/
280 libvlc_media_player_t *
281 libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
282                            libvlc_exception_t * p_e )
283 {
284     libvlc_media_player_t * p_mi;
285
286     if( !p_libvlc_instance )
287     {
288         libvlc_exception_raise( p_e, "invalid libvlc instance" );
289         return NULL;
290     }
291
292     p_mi = malloc( sizeof(libvlc_media_player_t) );
293     p_mi->p_md = NULL;
294     p_mi->drawable = 0;
295     p_mi->p_libvlc_instance = p_libvlc_instance;
296     p_mi->p_input_thread = NULL;
297     /* refcount strategy:
298      * - All items created by _new start with a refcount set to 1
299      * - Accessor _release decrease the refcount by 1, if after that
300      *   operation the refcount is 0, the object is destroyed.
301      * - Accessor _retain increase the refcount by 1 (XXX: to implement) */
302     p_mi->i_refcount = 1;
303     p_mi->b_own_its_input_thread = true;
304     /* object_lock strategy:
305      * - No lock held in constructor
306      * - Lock when accessing all variable this lock is held
307      * - Lock when attempting to destroy the object the lock is also held */
308     vlc_mutex_init( &p_mi->object_lock );
309     p_mi->p_event_manager = libvlc_event_manager_new( p_mi,
310             p_libvlc_instance, p_e );
311     if( libvlc_exception_raised( p_e ) )
312     {
313         free( p_mi );
314         return NULL;
315     }
316
317     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
318             libvlc_MediaPlayerEndReached, p_e );
319     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
320             libvlc_MediaPlayerStopped, p_e );
321     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
322             libvlc_MediaPlayerEncounteredError, p_e );
323     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
324             libvlc_MediaPlayerPaused, p_e );
325     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
326             libvlc_MediaPlayerPlayed, p_e );
327     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
328             libvlc_MediaPlayerPositionChanged, p_e );
329     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
330             libvlc_MediaPlayerTimeChanged, p_e );
331     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
332             libvlc_MediaPlayerSeekableChanged, p_e );
333     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
334             libvlc_MediaPlayerPausableChanged, p_e );
335
336     return p_mi;
337 }
338
339 /**************************************************************************
340  * Create a Media Instance object with a media descriptor
341  **************************************************************************/
342 libvlc_media_player_t *
343 libvlc_media_player_new_from_media(
344                                     libvlc_media_t * p_md,
345                                     libvlc_exception_t *p_e )
346 {
347     libvlc_media_player_t * p_mi;
348     p_mi = libvlc_media_player_new( p_md->p_libvlc_instance, p_e );
349
350     if( !p_mi )
351         return NULL;
352
353     libvlc_media_retain( p_md );
354     p_mi->p_md = p_md;
355
356     return p_mi;
357 }
358
359 /**************************************************************************
360  * Create a new media instance object from an input_thread (Libvlc Internal)
361  **************************************************************************/
362 libvlc_media_player_t * libvlc_media_player_new_from_input_thread(
363                                    struct libvlc_instance_t *p_libvlc_instance,
364                                    input_thread_t *p_input,
365                                    libvlc_exception_t *p_e )
366 {
367     libvlc_media_player_t * p_mi;
368
369     if( !p_input )
370     {
371         libvlc_exception_raise( p_e, "invalid input thread" );
372         return NULL;
373     }
374
375     p_mi = libvlc_media_player_new( p_libvlc_instance, p_e );
376
377     if( !p_mi )
378         return NULL;
379
380     p_mi->p_md = libvlc_media_new_from_input_item(
381                     p_libvlc_instance,
382                     input_GetItem( p_input ), p_e );
383
384     if( !p_mi->p_md )
385     {
386         libvlc_media_player_destroy( p_mi );
387         return NULL;
388     }
389
390     /* will be released in media_player_release() */
391     vlc_object_yield( p_input );
392
393     p_mi->p_input_thread = p_input;
394     p_mi->b_own_its_input_thread = false;
395
396     return p_mi;
397 }
398
399 /**************************************************************************
400  * Destroy a Media Instance object (libvlc internal)
401  *
402  * Warning: No lock held here, but hey, this is internal.
403  **************************************************************************/
404 void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
405 {
406     input_thread_t *p_input_thread;
407     libvlc_exception_t p_e;
408
409     libvlc_exception_init( &p_e );
410
411     if( !p_mi )
412         return;
413
414     p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
415
416     if( libvlc_exception_raised( &p_e ) )
417     {
418         libvlc_event_manager_release( p_mi->p_event_manager );
419         libvlc_exception_clear( &p_e );
420         free( p_mi );
421         return; /* no need to worry about no input thread */
422     }
423     vlc_mutex_destroy( &p_mi->object_lock );
424
425     vlc_object_release( p_input_thread );
426
427     libvlc_media_release( p_mi->p_md );
428
429     free( p_mi );
430 }
431
432 /**************************************************************************
433  * Release a Media Instance object
434  **************************************************************************/
435 void libvlc_media_player_release( libvlc_media_player_t *p_mi )
436 {
437     if( !p_mi )
438         return;
439
440     vlc_mutex_lock( &p_mi->object_lock );
441  
442     p_mi->i_refcount--;
443
444     if( p_mi->i_refcount > 0 )
445     {
446         vlc_mutex_unlock( &p_mi->object_lock );
447         return;
448     }
449     vlc_mutex_unlock( &p_mi->object_lock );
450     vlc_mutex_destroy( &p_mi->object_lock );
451
452     release_input_thread( p_mi );
453
454     libvlc_event_manager_release( p_mi->p_event_manager );
455  
456     libvlc_media_release( p_mi->p_md );
457
458     free( p_mi );
459 }
460
461 /**************************************************************************
462  * Retain a Media Instance object
463  **************************************************************************/
464 void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
465 {
466     if( !p_mi )
467         return;
468
469     p_mi->i_refcount++;
470 }
471
472 /**************************************************************************
473  * Set the Media descriptor associated with the instance
474  **************************************************************************/
475 void libvlc_media_player_set_media(
476                             libvlc_media_player_t *p_mi,
477                             libvlc_media_t *p_md,
478                             libvlc_exception_t *p_e )
479 {
480     (void)p_e;
481
482     if( !p_mi )
483         return;
484
485     vlc_mutex_lock( &p_mi->object_lock );
486
487     release_input_thread( p_mi );
488
489     if( p_mi->p_md )
490         libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, p_e );
491
492     libvlc_media_release( p_mi->p_md );
493
494     if( !p_md )
495     {
496         p_mi->p_md = NULL;
497         vlc_mutex_unlock( &p_mi->object_lock );
498         return; /* It is ok to pass a NULL md */
499     }
500
501     libvlc_media_retain( p_md );
502     p_mi->p_md = p_md;
503  
504     /* The policy here is to ignore that we were created using a different
505      * libvlc_instance, because we don't really care */
506     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
507
508     vlc_mutex_unlock( &p_mi->object_lock );
509 }
510
511 /**************************************************************************
512  * Get the Media descriptor associated with the instance
513  **************************************************************************/
514 libvlc_media_t *
515 libvlc_media_player_get_media(
516                             libvlc_media_player_t *p_mi,
517                             libvlc_exception_t *p_e )
518 {
519     (void)p_e;
520
521     if( !p_mi->p_md )
522         return NULL;
523
524     libvlc_media_retain( p_mi->p_md );
525     return p_mi->p_md;
526 }
527
528 /**************************************************************************
529  * Get the event Manager
530  **************************************************************************/
531 libvlc_event_manager_t *
532 libvlc_media_player_event_manager(
533                             libvlc_media_player_t *p_mi,
534                             libvlc_exception_t *p_e )
535 {
536     (void)p_e;
537
538     return p_mi->p_event_manager;
539 }
540
541 /**************************************************************************
542  * Play
543  **************************************************************************/
544 void libvlc_media_player_play( libvlc_media_player_t *p_mi,
545                                  libvlc_exception_t *p_e )
546 {
547     input_thread_t * p_input_thread;
548
549     if( (p_input_thread = libvlc_get_input_thread( p_mi, p_e )) )
550     {
551         /* A thread already exists, send it a play message */
552         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
553         vlc_object_release( p_input_thread );
554         return;
555     }
556
557     /* Ignore previous exception */
558     libvlc_exception_clear( p_e );
559
560     vlc_mutex_lock( &p_mi->object_lock );
561  
562     if( !p_mi->p_md )
563     {
564         libvlc_exception_raise( p_e, "no associated media descriptor" );
565         vlc_mutex_unlock( &p_mi->object_lock );
566         return;
567     }
568
569     p_mi->p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int,
570                       p_mi->p_md->p_input_item );
571
572
573     if( !p_mi->p_input_thread )
574     {
575         vlc_mutex_unlock( &p_mi->object_lock );
576         return;
577     }
578
579     p_input_thread = p_mi->p_input_thread;
580
581     if( p_mi->drawable )
582     {
583         vlc_value_t val;
584         val.i_int = p_mi->drawable;
585         var_Create( p_input_thread, "drawable", VLC_VAR_DOINHERIT );
586         var_Set( p_input_thread, "drawable", val );
587     }
588     var_AddCallback( p_input_thread, "state", input_state_changed, p_mi );
589     var_AddCallback( p_input_thread, "seekable", input_seekable_changed, p_mi );
590     var_AddCallback( p_input_thread, "pausable", input_pausable_changed, p_mi );
591     var_AddCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
592     var_AddCallback( p_input_thread, "intf-change", input_time_changed, p_mi );
593
594     vlc_mutex_unlock( &p_mi->object_lock );
595 }
596
597 /**************************************************************************
598  * Pause
599  **************************************************************************/
600 void libvlc_media_player_pause( libvlc_media_player_t *p_mi,
601                                   libvlc_exception_t *p_e )
602 {
603     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
604
605     if( !p_input_thread )
606         return;
607
608     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
609
610     if( state == libvlc_Playing )
611     {
612         if( libvlc_media_player_can_pause( p_mi, p_e ) )
613             input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
614         else
615             libvlc_media_player_stop( p_mi, p_e );
616     }
617     else
618         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
619
620     vlc_object_release( p_input_thread );
621 }
622
623 /**************************************************************************
624  * Stop
625  **************************************************************************/
626 void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
627                                  libvlc_exception_t *p_e )
628 {
629     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
630
631     if( state == libvlc_Playing || state == libvlc_Paused )
632     {
633         /* Send a stop notification event only of we are in playing or paused states */
634
635         libvlc_media_set_state( p_mi->p_md, libvlc_Stopped, p_e );
636
637         /* Construct and send the event */
638         libvlc_event_t event;
639         event.type = libvlc_MediaPlayerStopped;
640         libvlc_event_send( p_mi->p_event_manager, &event );
641     }
642
643     if( p_mi->b_own_its_input_thread )
644     {
645         vlc_mutex_lock( &p_mi->object_lock );
646         release_input_thread( p_mi ); /* This will stop the input thread */
647         vlc_mutex_unlock( &p_mi->object_lock );
648     }
649     else
650     {
651         input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
652
653         if( !p_input_thread )
654             return;
655
656         input_StopThread( p_input_thread );
657         vlc_object_release( p_input_thread );
658     }
659 }
660
661 /**************************************************************************
662  * Set Drawable
663  **************************************************************************/
664 void libvlc_media_player_set_drawable( libvlc_media_player_t *p_mi,
665                                          libvlc_drawable_t drawable,
666                                          libvlc_exception_t *p_e )
667 {
668     (void)p_e;
669     p_mi->drawable = drawable;
670 }
671
672 /**************************************************************************
673  * Get Drawable
674  **************************************************************************/
675 libvlc_drawable_t
676 libvlc_media_player_get_drawable ( libvlc_media_player_t *p_mi, libvlc_exception_t *p_e )
677 {
678     (void)p_e;
679     return p_mi->drawable;
680 }
681
682 /**************************************************************************
683  * Getters for stream information
684  **************************************************************************/
685 libvlc_time_t libvlc_media_player_get_length(
686                              libvlc_media_player_t *p_mi,
687                              libvlc_exception_t *p_e )
688 {
689     input_thread_t *p_input_thread;
690     vlc_value_t val;
691
692     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
693     if( !p_input_thread )
694         return -1;
695
696     var_Get( p_input_thread, "length", &val );
697     vlc_object_release( p_input_thread );
698
699     return (val.i_time+500LL)/1000LL;
700 }
701
702 libvlc_time_t libvlc_media_player_get_time(
703                                    libvlc_media_player_t *p_mi,
704                                    libvlc_exception_t *p_e )
705 {
706     input_thread_t *p_input_thread;
707     vlc_value_t val;
708
709     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
710     if( !p_input_thread )
711         return -1;
712
713     var_Get( p_input_thread , "time", &val );
714     vlc_object_release( p_input_thread );
715     return (val.i_time+500LL)/1000LL;
716 }
717
718 void libvlc_media_player_set_time(
719                                  libvlc_media_player_t *p_mi,
720                                  libvlc_time_t time,
721                                  libvlc_exception_t *p_e )
722 {
723     input_thread_t *p_input_thread;
724     vlc_value_t value;
725
726     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
727     if( !p_input_thread )
728         return;
729
730     value.i_time = time*1000LL;
731     var_Set( p_input_thread, "time", value );
732     vlc_object_release( p_input_thread );
733 }
734
735 void libvlc_media_player_set_position(
736                                 libvlc_media_player_t *p_mi,
737                                 float position,
738                                 libvlc_exception_t *p_e )
739 {
740     input_thread_t *p_input_thread;
741     vlc_value_t val;
742     val.f_float = position;
743
744     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
745     if( !p_input_thread )
746         return;
747
748     var_Set( p_input_thread, "position", val );
749     vlc_object_release( p_input_thread );
750 }
751
752 float libvlc_media_player_get_position(
753                                  libvlc_media_player_t *p_mi,
754                                  libvlc_exception_t *p_e )
755 {
756     input_thread_t *p_input_thread;
757     vlc_value_t val;
758
759     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
760     if( !p_input_thread )
761         return -1.0;
762
763     var_Get( p_input_thread, "position", &val );
764     vlc_object_release( p_input_thread );
765
766     return val.f_float;
767 }
768
769 void libvlc_media_player_set_chapter(
770                                  libvlc_media_player_t *p_mi,
771                                  int chapter,
772                                  libvlc_exception_t *p_e )
773 {
774     input_thread_t *p_input_thread;
775     vlc_value_t val;
776     val.i_int = chapter;
777
778     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
779     if( !p_input_thread )
780         return;
781
782     var_Set( p_input_thread, "chapter", val );
783     vlc_object_release( p_input_thread );
784 }
785
786 int libvlc_media_player_get_chapter(
787                                  libvlc_media_player_t *p_mi,
788                                  libvlc_exception_t *p_e )
789 {
790     input_thread_t *p_input_thread;
791     vlc_value_t val;
792
793     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
794     if( !p_input_thread )
795         return -1.0;
796
797     var_Get( p_input_thread, "chapter", &val );
798     vlc_object_release( p_input_thread );
799
800     return val.i_int;
801 }
802
803 int libvlc_media_player_get_chapter_count(
804                                  libvlc_media_player_t *p_mi,
805                                  libvlc_exception_t *p_e )
806 {
807     input_thread_t *p_input_thread;
808     vlc_value_t val;
809
810     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
811     if( !p_input_thread )
812         return -1.0;
813
814     var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
815     vlc_object_release( p_input_thread );
816
817     return val.i_int;
818 }
819
820 float libvlc_media_player_get_fps(
821                                  libvlc_media_player_t *p_mi,
822                                  libvlc_exception_t *p_e)
823 {
824     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
825     double f_fps = 0.0;
826
827     if( p_input_thread )
828     {
829         if( input_Control( p_input_thread, INPUT_GET_VIDEO_FPS, &f_fps ) )
830             f_fps = 0.0;
831         vlc_object_release( p_input_thread );
832     }
833     return f_fps;
834 }
835
836 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi,
837                                      libvlc_exception_t *p_e)
838 {
839     input_thread_t *p_input_thread =
840                             libvlc_get_input_thread ( p_mi, p_e);
841     if ( !p_input_thread )
842         return false;
843
844     if ( !p_input_thread->b_die && !p_input_thread->b_dead )
845     {
846         vlc_object_release( p_input_thread );
847         return true;
848     }
849     vlc_object_release( p_input_thread );
850     return false;
851 }
852
853 void libvlc_media_player_set_rate(
854                                  libvlc_media_player_t *p_mi,
855                                  float rate,
856                                  libvlc_exception_t *p_e )
857 {
858     input_thread_t *p_input_thread;
859     vlc_value_t val;
860
861     if( rate <= 0 )
862         RAISEVOID( "Rate value is invalid" );
863
864     val.i_int = 1000.0f/rate;
865
866     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
867     if ( !p_input_thread )
868         return;
869
870     var_Set( p_input_thread, "rate", val );
871     vlc_object_release( p_input_thread );
872 }
873
874 float libvlc_media_player_get_rate(
875                                  libvlc_media_player_t *p_mi,
876                                  libvlc_exception_t *p_e )
877 {
878     input_thread_t *p_input_thread;
879     vlc_value_t val;
880
881     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
882     if ( !p_input_thread )
883         return -1.0;
884
885     var_Get( p_input_thread, "rate", &val );
886     vlc_object_release( p_input_thread );
887
888     return (float)1000.0f/val.i_int;
889 }
890
891 libvlc_state_t libvlc_media_player_get_state(
892                                  libvlc_media_player_t *p_mi,
893                                  libvlc_exception_t *p_e )
894 {
895     input_thread_t *p_input_thread;
896     vlc_value_t val;
897
898     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
899     if ( !p_input_thread )
900     {
901         /* We do return the right value, no need to throw an exception */
902         if( libvlc_exception_raised( p_e ) )
903             libvlc_exception_clear( p_e );
904         return libvlc_Stopped;
905     }
906
907     var_Get( p_input_thread, "state", &val );
908     vlc_object_release( p_input_thread );
909
910     return vlc_to_libvlc_state(val.i_int);
911 }
912
913 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi,
914                                        libvlc_exception_t *p_e )
915 {
916     input_thread_t *p_input_thread;
917     vlc_value_t val;
918
919     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
920     if ( !p_input_thread )
921     {
922         /* We do return the right value, no need to throw an exception */
923         if( libvlc_exception_raised( p_e ) )
924             libvlc_exception_clear( p_e );
925         return false;
926     }
927     var_Get( p_input_thread, "seekable", &val );
928     vlc_object_release( p_input_thread );
929
930     return val.b_bool;
931 }
932
933 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi,
934                                      libvlc_exception_t *p_e )
935 {
936     input_thread_t *p_input_thread;
937     vlc_value_t val;
938
939     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
940     if ( !p_input_thread )
941     {
942         /* We do return the right value, no need to throw an exception */
943         if( libvlc_exception_raised( p_e ) )
944             libvlc_exception_clear( p_e );
945         return false;
946     }
947     var_Get( p_input_thread, "can-pause", &val );
948     vlc_object_release( p_input_thread );
949
950     return val.b_bool;
951 }