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