input: fix skipping data in stream-oriented access
[vlc/vlc-test.git] / lib / media_player.c
1 /*****************************************************************************
2  * media_player.c: Libvlc API Media Instance management functions
3  *****************************************************************************
4  * Copyright (C) 2005-2015 VLC authors and VideoLAN
5  *
6  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
7  *
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU Lesser General Public License as published by
10  * the Free Software Foundation; either version 2.1 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <assert.h>
28
29 #include <vlc/libvlc.h>
30 #include <vlc/libvlc_media.h>
31 #include <vlc/libvlc_events.h>
32
33 #include <vlc_demux.h>
34 #include <vlc_input.h>
35 #include <vlc_vout.h>
36 #include <vlc_aout.h>
37 #include <vlc_keys.h>
38
39 #include "libvlc_internal.h"
40 #include "media_internal.h" // libvlc_media_set_state()
41 #include "media_player_internal.h"
42
43 static int
44 input_seekable_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_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
49                         vlc_value_t oldval, vlc_value_t newval,
50                         void * p_userdata );
51 static int
52 input_scrambled_changed( vlc_object_t * p_this, char const * psz_cmd,
53                         vlc_value_t oldval, vlc_value_t newval,
54                         void * p_userdata );
55 static int
56 input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
57                      vlc_value_t oldval, vlc_value_t newval,
58                      void * p_userdata );
59
60 static int
61 input_es_changed( vlc_object_t * p_this, char const * psz_cmd,
62                   int action, vlc_value_t *p_val,
63                   void *p_userdata);
64
65 static int
66 input_es_selected( vlc_object_t * p_this, char const * psz_cmd,
67                    vlc_value_t oldval, vlc_value_t newval,
68                    void * p_userdata );
69
70 static int
71 corks_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
72               vlc_value_t cur, void *opaque);
73
74 static int
75 mute_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
76              vlc_value_t cur, void *opaque);
77
78 static int
79 volume_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
80                vlc_value_t cur, void *opaque);
81
82 static void
83 add_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi );
84
85 static void
86 del_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi );
87
88 static int
89 snapshot_was_taken( vlc_object_t *p_this, char const *psz_cmd,
90                     vlc_value_t oldval, vlc_value_t newval, void *p_data );
91
92 static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi );
93
94 /*
95  * Shortcuts
96  */
97
98 /*
99  * The input lock protects the input and input resource pointer.
100  * It MUST NOT be used from callbacks.
101  *
102  * The object lock protects the reset, namely the media and the player state.
103  * It can, and usually needs to be taken from callbacks.
104  * The object lock can be acquired under the input lock... and consequently
105  * the opposite order is STRICTLY PROHIBITED.
106  */
107 static inline void lock(libvlc_media_player_t *mp)
108 {
109     vlc_mutex_lock(&mp->object_lock);
110 }
111
112 static inline void unlock(libvlc_media_player_t *mp)
113 {
114     vlc_mutex_unlock(&mp->object_lock);
115 }
116
117 static inline void lock_input(libvlc_media_player_t *mp)
118 {
119     vlc_mutex_lock(&mp->input.lock);
120 }
121
122 static inline void unlock_input(libvlc_media_player_t *mp)
123 {
124     vlc_mutex_unlock(&mp->input.lock);
125 }
126
127 static void input_item_preparsed_changed( const vlc_event_t *p_event,
128                                           void * user_data )
129 {
130     libvlc_media_t *p_md = user_data;
131     if( p_event->u.input_item_preparsed_changed.new_status & ITEM_PREPARSED )
132     {
133         /* Send the event */
134         libvlc_event_t event;
135         event.type = libvlc_MediaParsedChanged;
136         event.u.media_parsed_changed.new_status = libvlc_media_parsed_status_done;
137         libvlc_event_send( p_md->p_event_manager, &event );
138     }
139 }
140
141 static void media_attach_preparsed_event( libvlc_media_t *p_md )
142 {
143     vlc_event_attach( &p_md->p_input_item->event_manager,
144                       vlc_InputItemPreparsedChanged,
145                       input_item_preparsed_changed, p_md );
146 }
147
148 static void media_detach_preparsed_event( libvlc_media_t *p_md )
149 {
150     vlc_event_detach( &p_md->p_input_item->event_manager,
151                       vlc_InputItemPreparsedChanged,
152                       input_item_preparsed_changed,
153                       p_md );
154 }
155
156 /*
157  * Release the associated input thread.
158  *
159  * Object lock is NOT held.
160  * Input lock is held or instance is being destroyed.
161  */
162 static void release_input_thread( libvlc_media_player_t *p_mi )
163 {
164     assert( p_mi );
165
166     input_thread_t *p_input_thread = p_mi->input.p_thread;
167     if( !p_input_thread )
168         return;
169     p_mi->input.p_thread = NULL;
170
171     media_detach_preparsed_event( p_mi->p_md );
172
173     var_DelCallback( p_input_thread, "can-seek",
174                      input_seekable_changed, p_mi );
175     var_DelCallback( p_input_thread, "can-pause",
176                     input_pausable_changed, p_mi );
177     var_DelCallback( p_input_thread, "program-scrambled",
178                     input_scrambled_changed, p_mi );
179     var_DelCallback( p_input_thread, "intf-event",
180                      input_event_changed, p_mi );
181     del_es_callbacks( p_input_thread, p_mi );
182
183     /* We owned this one */
184     input_Stop( p_input_thread );
185     input_Close( p_input_thread );
186 }
187
188 /*
189  * Retrieve the input thread. Be sure to release the object
190  * once you are done with it. (libvlc Internal)
191  */
192 input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi )
193 {
194     input_thread_t *p_input_thread;
195
196     assert( p_mi );
197
198     lock_input(p_mi);
199     p_input_thread = p_mi->input.p_thread;
200     if( p_input_thread )
201         vlc_object_hold( p_input_thread );
202     else
203         libvlc_printerr( "No active input" );
204     unlock_input(p_mi);
205
206     return p_input_thread;
207 }
208
209 /*
210  * Set the internal state of the media_player. (media player Internal)
211  *
212  * Function will lock the media_player.
213  */
214 static void set_state( libvlc_media_player_t *p_mi, libvlc_state_t state,
215     bool b_locked )
216 {
217     if(!b_locked)
218         lock(p_mi);
219     p_mi->state = state;
220
221     libvlc_media_t *media = p_mi->p_md;
222     if (media)
223         libvlc_media_retain(media);
224
225     if(!b_locked)
226         unlock(p_mi);
227
228     if (media)
229     {
230         // Also set the state of the corresponding media
231         // This is strictly for convenience.
232         libvlc_media_set_state(media, state);
233
234         libvlc_media_release(media);
235     }
236 }
237
238 static int
239 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
240                         vlc_value_t oldval, vlc_value_t newval,
241                         void * p_userdata )
242 {
243     VLC_UNUSED(oldval);
244     VLC_UNUSED(p_this);
245     VLC_UNUSED(psz_cmd);
246     libvlc_media_player_t * p_mi = p_userdata;
247     libvlc_event_t event;
248
249     event.type = libvlc_MediaPlayerSeekableChanged;
250     event.u.media_player_seekable_changed.new_seekable = newval.b_bool;
251
252     libvlc_event_send( p_mi->p_event_manager, &event );
253     return VLC_SUCCESS;
254 }
255
256 static int
257 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
258                         vlc_value_t oldval, vlc_value_t newval,
259                         void * p_userdata )
260 {
261     VLC_UNUSED(oldval);
262     VLC_UNUSED(p_this);
263     VLC_UNUSED(psz_cmd);
264     libvlc_media_player_t * p_mi = p_userdata;
265     libvlc_event_t event;
266
267     event.type = libvlc_MediaPlayerPausableChanged;
268     event.u.media_player_pausable_changed.new_pausable = newval.b_bool;
269
270     libvlc_event_send( p_mi->p_event_manager, &event );
271     return VLC_SUCCESS;
272 }
273
274 static int
275 input_scrambled_changed( vlc_object_t * p_this, char const * psz_cmd,
276                         vlc_value_t oldval, vlc_value_t newval,
277                         void * p_userdata )
278 {
279     VLC_UNUSED(oldval);
280     VLC_UNUSED(p_this);
281     VLC_UNUSED(psz_cmd);
282     libvlc_media_player_t * p_mi = p_userdata;
283     libvlc_event_t event;
284
285     event.type = libvlc_MediaPlayerScrambledChanged;
286     event.u.media_player_scrambled_changed.new_scrambled = newval.b_bool;
287
288     libvlc_event_send( p_mi->p_event_manager, &event );
289     return VLC_SUCCESS;
290 }
291
292 static int
293 input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
294                      vlc_value_t oldval, vlc_value_t newval,
295                      void * p_userdata )
296 {
297     VLC_UNUSED(oldval); VLC_UNUSED(psz_cmd);
298     input_thread_t * p_input = (input_thread_t *)p_this;
299     libvlc_media_player_t * p_mi = p_userdata;
300     libvlc_event_t event;
301
302     assert( !strcmp( psz_cmd, "intf-event" ) );
303
304     if( newval.i_int == INPUT_EVENT_STATE )
305     {
306         libvlc_state_t libvlc_state;
307
308         switch ( var_GetInteger( p_input, "state" ) )
309         {
310             case INIT_S:
311                 libvlc_state = libvlc_NothingSpecial;
312                 event.type = libvlc_MediaPlayerNothingSpecial;
313                 break;
314             case OPENING_S:
315                 libvlc_state = libvlc_Opening;
316                 event.type = libvlc_MediaPlayerOpening;
317                 break;
318             case PLAYING_S:
319                 libvlc_state = libvlc_Playing;
320                 event.type = libvlc_MediaPlayerPlaying;
321                 break;
322             case PAUSE_S:
323                 libvlc_state = libvlc_Paused;
324                 event.type = libvlc_MediaPlayerPaused;
325                 break;
326             case END_S:
327                 libvlc_state = libvlc_Ended;
328                 event.type = libvlc_MediaPlayerEndReached;
329                 break;
330             case ERROR_S:
331                 libvlc_state = libvlc_Error;
332                 event.type = libvlc_MediaPlayerEncounteredError;
333                 break;
334
335             default:
336                 return VLC_SUCCESS;
337         }
338
339         set_state( p_mi, libvlc_state, false );
340         libvlc_event_send( p_mi->p_event_manager, &event );
341     }
342     else if( newval.i_int == INPUT_EVENT_DEAD )
343     {
344         libvlc_state_t libvlc_state = libvlc_Ended;
345         event.type = libvlc_MediaPlayerStopped;
346
347         set_state( p_mi, libvlc_state, false );
348         libvlc_event_send( p_mi->p_event_manager, &event );
349     }
350     else if( newval.i_int == INPUT_EVENT_POSITION )
351     {
352         if( var_GetInteger( p_input, "state" ) != PLAYING_S )
353             return VLC_SUCCESS; /* Don't send the position while stopped */
354
355         /* */
356         event.type = libvlc_MediaPlayerPositionChanged;
357         event.u.media_player_position_changed.new_position =
358                                           var_GetFloat( p_input, "position" );
359         libvlc_event_send( p_mi->p_event_manager, &event );
360
361         /* */
362         event.type = libvlc_MediaPlayerTimeChanged;
363         event.u.media_player_time_changed.new_time =
364            from_mtime(var_GetInteger( p_input, "time" ));
365         libvlc_event_send( p_mi->p_event_manager, &event );
366     }
367     else if( newval.i_int == INPUT_EVENT_LENGTH )
368     {
369         event.type = libvlc_MediaPlayerLengthChanged;
370         event.u.media_player_length_changed.new_length =
371            from_mtime(var_GetInteger( p_input, "length" ));
372         libvlc_event_send( p_mi->p_event_manager, &event );
373     }
374     else if( newval.i_int == INPUT_EVENT_CACHE )
375     {
376         event.type = libvlc_MediaPlayerBuffering;
377         event.u.media_player_buffering.new_cache = (int)(100 *
378             var_GetFloat( p_input, "cache" ));
379         libvlc_event_send( p_mi->p_event_manager, &event );
380     }
381     else if( newval.i_int == INPUT_EVENT_VOUT )
382     {
383         vout_thread_t **pp_vout;
384         size_t i_vout;
385         if( input_Control( p_input, INPUT_GET_VOUTS, &pp_vout, &i_vout ) )
386         {
387             i_vout  = 0;
388         }
389         else
390         {
391             for( size_t i = 0; i < i_vout; i++ )
392                 vlc_object_release( pp_vout[i] );
393             free( pp_vout );
394         }
395
396         event.type = libvlc_MediaPlayerVout;
397         event.u.media_player_vout.new_count = i_vout;
398         libvlc_event_send( p_mi->p_event_manager, &event );
399     }
400     else if ( newval.i_int == INPUT_EVENT_TITLE )
401     {
402         event.type = libvlc_MediaPlayerTitleChanged;
403         event.u.media_player_title_changed.new_title = var_GetInteger( p_input, "title" );
404         libvlc_event_send( p_mi->p_event_manager, &event );
405     }
406     else if ( newval.i_int == INPUT_EVENT_CHAPTER )
407     {
408         event.type = libvlc_MediaPlayerChapterChanged;
409         event.u.media_player_chapter_changed.new_chapter = var_GetInteger( p_input, "chapter" );
410         libvlc_event_send( p_mi->p_event_manager, &event );
411     }
412
413     return VLC_SUCCESS;
414 }
415
416 static int track_type_from_name(const char *psz_name)
417 {
418    if( !strcmp( psz_name, "video-es" ) )
419        return libvlc_track_video;
420     else if( !strcmp( psz_name, "audio-es" ) )
421         return libvlc_track_audio;
422     else if( !strcmp( psz_name, "spu-es" ) )
423         return libvlc_track_text;
424     else
425         return libvlc_track_unknown;
426 }
427
428 static int input_es_changed( vlc_object_t *p_this,
429                              char const *psz_cmd,
430                              int action,
431                              vlc_value_t *p_val,
432                              void *p_userdata )
433 {
434     VLC_UNUSED(p_this);
435     libvlc_media_player_t *mp = p_userdata;
436     libvlc_event_t event;
437
438     /* Ignore the "Disable" element */
439     if (p_val && p_val->i_int < 0)
440         return VLC_EGENERIC;
441
442     switch (action)
443     {
444     case VLC_VAR_ADDCHOICE:
445         event.type = libvlc_MediaPlayerESAdded;
446         break;
447     case VLC_VAR_DELCHOICE:
448     case VLC_VAR_CLEARCHOICES:
449         event.type = libvlc_MediaPlayerESDeleted;
450         break;
451     default:
452         return VLC_EGENERIC;
453     }
454
455     event.u.media_player_es_changed.i_type = track_type_from_name(psz_cmd);
456
457     int i_id;
458     if (action != VLC_VAR_CLEARCHOICES)
459     {
460         if (!p_val)
461             return VLC_EGENERIC;
462         i_id = p_val->i_int;
463     }
464     else
465     {
466         /* -1 means all ES tracks of this type were deleted. */
467         i_id = -1;
468     }
469     event.u.media_player_es_changed.i_id = i_id;
470
471     libvlc_event_send(mp->p_event_manager, &event);
472
473     return VLC_SUCCESS;
474 }
475
476 static int
477 input_es_selected( vlc_object_t * p_this, char const * psz_cmd,
478                    vlc_value_t oldval, vlc_value_t newval,
479                    void * p_userdata )
480 {
481     VLC_UNUSED(p_this);
482     VLC_UNUSED(oldval);
483     libvlc_media_player_t *mp = p_userdata;
484     libvlc_event_t event;
485
486     event.type = libvlc_MediaPlayerESSelected;
487     event.u.media_player_es_changed.i_type = track_type_from_name(psz_cmd);
488     event.u.media_player_es_changed.i_id = newval.i_int;
489
490     libvlc_event_send(mp->p_event_manager, &event);
491
492     return VLC_SUCCESS;
493 }
494
495 /**************************************************************************
496  * Snapshot Taken Event.
497  *
498  * FIXME: This snapshot API interface makes no sense in media_player.
499  *************************************************************************/
500 static int snapshot_was_taken(vlc_object_t *p_this, char const *psz_cmd,
501                               vlc_value_t oldval, vlc_value_t newval, void *p_data )
502 {
503     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_this);
504
505     libvlc_media_player_t *mp = p_data;
506     libvlc_event_t event;
507     event.type = libvlc_MediaPlayerSnapshotTaken;
508     event.u.media_player_snapshot_taken.psz_filename = newval.psz_string;
509     libvlc_event_send(mp->p_event_manager, &event);
510
511     return VLC_SUCCESS;
512 }
513
514 static int corks_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
515                          vlc_value_t cur, void *opaque)
516 {
517     libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
518
519     if (!old.i_int != !cur.i_int)
520     {
521         libvlc_event_t event;
522
523         event.type = cur.i_int ? libvlc_MediaPlayerCorked
524                                : libvlc_MediaPlayerUncorked;
525         libvlc_event_send(mp->p_event_manager, &event);
526     }
527     VLC_UNUSED(name); VLC_UNUSED(opaque);
528     return VLC_SUCCESS;
529 }
530
531 static int audio_device_changed(vlc_object_t *obj, const char *name,
532                                 vlc_value_t old, vlc_value_t cur, void *opaque)
533 {
534     libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
535     libvlc_event_t event;
536
537     event.type = libvlc_MediaPlayerAudioDevice;
538     event.u.media_player_audio_device.device = cur.psz_string;
539     libvlc_event_send(mp->p_event_manager, &event);
540     VLC_UNUSED(name); VLC_UNUSED(old); VLC_UNUSED(opaque);
541     return VLC_SUCCESS;
542 }
543
544 static int mute_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
545                         vlc_value_t cur, void *opaque)
546 {
547     libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
548
549     if (old.b_bool != cur.b_bool)
550     {
551         libvlc_event_t event;
552
553         event.type = cur.b_bool ? libvlc_MediaPlayerMuted
554                                 : libvlc_MediaPlayerUnmuted;
555         libvlc_event_send(mp->p_event_manager, &event);
556     }
557     VLC_UNUSED(name); VLC_UNUSED(opaque);
558     return VLC_SUCCESS;
559 }
560
561 static int volume_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
562                           vlc_value_t cur, void *opaque)
563 {
564     libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
565     libvlc_event_t event;
566
567     event.type = libvlc_MediaPlayerAudioVolume;
568     event.u.media_player_audio_volume.volume = cur.f_float;
569     libvlc_event_send(mp->p_event_manager, &event);
570     VLC_UNUSED(name); VLC_UNUSED(old); VLC_UNUSED(opaque);
571     return VLC_SUCCESS;
572 }
573
574 /**************************************************************************
575  * Create a Media Instance object.
576  *
577  * Refcount strategy:
578  * - All items created by _new start with a refcount set to 1.
579  * - Accessor _release decrease the refcount by 1, if after that
580  *   operation the refcount is 0, the object is destroyed.
581  * - Accessor _retain increase the refcount by 1 (XXX: to implement)
582  *
583  * Object locking strategy:
584  * - No lock held while in constructor.
585  * - When accessing any member variable this lock is held. (XXX who locks?)
586  * - When attempting to destroy the object the lock is also held.
587  **************************************************************************/
588 libvlc_media_player_t *
589 libvlc_media_player_new( libvlc_instance_t *instance )
590 {
591     libvlc_media_player_t * mp;
592
593     assert(instance);
594
595     mp = vlc_object_create (instance->p_libvlc_int, sizeof(*mp));
596     if (unlikely(mp == NULL))
597     {
598         libvlc_printerr("Not enough memory");
599         return NULL;
600     }
601
602     /* Input */
603     var_Create (mp, "rate", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT);
604
605     /* Video */
606     var_Create (mp, "vout", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
607     var_Create (mp, "window", VLC_VAR_STRING);
608     var_Create (mp, "vmem-lock", VLC_VAR_ADDRESS);
609     var_Create (mp, "vmem-unlock", VLC_VAR_ADDRESS);
610     var_Create (mp, "vmem-display", VLC_VAR_ADDRESS);
611     var_Create (mp, "vmem-data", VLC_VAR_ADDRESS);
612     var_Create (mp, "vmem-setup", VLC_VAR_ADDRESS);
613     var_Create (mp, "vmem-cleanup", VLC_VAR_ADDRESS);
614     var_Create (mp, "vmem-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
615     var_Create (mp, "vmem-width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
616     var_Create (mp, "vmem-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
617     var_Create (mp, "vmem-pitch", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
618     var_Create (mp, "avcodec-hw", VLC_VAR_STRING);
619     var_Create (mp, "drawable-xid", VLC_VAR_INTEGER);
620 #if defined (_WIN32) || defined (__OS2__)
621     var_Create (mp, "drawable-hwnd", VLC_VAR_INTEGER);
622 #endif
623 #ifdef __APPLE__
624     var_Create (mp, "drawable-nsobject", VLC_VAR_ADDRESS);
625 #endif
626 #ifdef __ANDROID__
627     var_Create (mp, "drawable-androidwindow", VLC_VAR_ADDRESS);
628 #endif
629 #ifdef HAVE_EVAS
630     var_Create (mp, "drawable-evasobject", VLC_VAR_ADDRESS);
631 #endif
632
633     var_Create (mp, "keyboard-events", VLC_VAR_BOOL);
634     var_SetBool (mp, "keyboard-events", true);
635     var_Create (mp, "mouse-events", VLC_VAR_BOOL);
636     var_SetBool (mp, "mouse-events", true);
637
638     var_Create (mp, "fullscreen", VLC_VAR_BOOL);
639     var_Create (mp, "autoscale", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
640     var_Create (mp, "zoom", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
641     var_Create (mp, "aspect-ratio", VLC_VAR_STRING);
642     var_Create (mp, "crop", VLC_VAR_STRING);
643     var_Create (mp, "deinterlace", VLC_VAR_INTEGER);
644     var_Create (mp, "deinterlace-mode", VLC_VAR_STRING);
645
646     var_Create (mp, "vbi-page", VLC_VAR_INTEGER);
647     var_SetInteger (mp, "vbi-page", 100);
648
649     var_Create (mp, "marq-marquee", VLC_VAR_STRING);
650     var_Create (mp, "marq-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
651     var_Create (mp, "marq-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
652     var_Create (mp, "marq-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
653     var_Create (mp, "marq-refresh", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
654     var_Create (mp, "marq-size", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
655     var_Create (mp, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
656     var_Create (mp, "marq-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
657     var_Create (mp, "marq-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
658
659     var_Create (mp, "logo-file", VLC_VAR_STRING);
660     var_Create (mp, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
661     var_Create (mp, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
662     var_Create (mp, "logo-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
663     var_Create (mp, "logo-repeat", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
664     var_Create (mp, "logo-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
665     var_Create (mp, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
666
667     var_Create (mp, "contrast", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
668     var_Create (mp, "brightness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
669     var_Create (mp, "hue", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
670     var_Create (mp, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
671     var_Create (mp, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
672
673      /* Audio */
674     var_Create (mp, "aout", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
675     var_Create (mp, "audio-device", VLC_VAR_STRING);
676     var_Create (mp, "mute", VLC_VAR_BOOL);
677     var_Create (mp, "volume", VLC_VAR_FLOAT);
678     var_Create (mp, "corks", VLC_VAR_INTEGER);
679     var_Create (mp, "audio-filter", VLC_VAR_STRING);
680     var_Create (mp, "role", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
681     var_Create (mp, "amem-data", VLC_VAR_ADDRESS);
682     var_Create (mp, "amem-setup", VLC_VAR_ADDRESS);
683     var_Create (mp, "amem-cleanup", VLC_VAR_ADDRESS);
684     var_Create (mp, "amem-play", VLC_VAR_ADDRESS);
685     var_Create (mp, "amem-pause", VLC_VAR_ADDRESS);
686     var_Create (mp, "amem-resume", VLC_VAR_ADDRESS);
687     var_Create (mp, "amem-flush", VLC_VAR_ADDRESS);
688     var_Create (mp, "amem-drain", VLC_VAR_ADDRESS);
689     var_Create (mp, "amem-set-volume", VLC_VAR_ADDRESS);
690     var_Create (mp, "amem-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
691     var_Create (mp, "amem-rate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
692     var_Create (mp, "amem-channels", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
693
694     /* Video Title */
695     var_Create (mp, "video-title-show", VLC_VAR_BOOL);
696     var_Create (mp, "video-title-position", VLC_VAR_INTEGER);
697     var_Create (mp, "video-title-timeout", VLC_VAR_INTEGER);
698
699     /* Equalizer */
700     var_Create (mp, "equalizer-preamp", VLC_VAR_FLOAT);
701     var_Create (mp, "equalizer-vlcfreqs", VLC_VAR_BOOL);
702     var_Create (mp, "equalizer-bands", VLC_VAR_STRING);
703
704     mp->p_md = NULL;
705     mp->state = libvlc_NothingSpecial;
706     mp->p_libvlc_instance = instance;
707     mp->input.p_thread = NULL;
708     mp->input.p_resource = input_resource_New(VLC_OBJECT(mp));
709     if (unlikely(mp->input.p_resource == NULL))
710     {
711         vlc_object_release(mp);
712         return NULL;
713     }
714     audio_output_t *aout = input_resource_GetAout(mp->input.p_resource);
715     if( aout != NULL )
716         input_resource_PutAout(mp->input.p_resource, aout);
717
718     vlc_mutex_init (&mp->input.lock);
719     mp->i_refcount = 1;
720     mp->p_event_manager = libvlc_event_manager_new(mp);
721     if (unlikely(mp->p_event_manager == NULL))
722     {
723         input_resource_Release(mp->input.p_resource);
724         vlc_object_release(mp);
725         return NULL;
726     }
727     vlc_mutex_init(&mp->object_lock);
728
729     var_AddCallback(mp, "corks", corks_changed, NULL);
730     var_AddCallback(mp, "audio-device", audio_device_changed, NULL);
731     var_AddCallback(mp, "mute", mute_changed, NULL);
732     var_AddCallback(mp, "volume", volume_changed, NULL);
733
734     /* Snapshot initialization */
735     /* Attach a var callback to the global object to provide the glue between
736      * vout_thread that generates the event and media_player that re-emits it
737      * with its own event manager
738      *
739      * FIXME: It's unclear why we want to put this in public API, and why we
740      * want to expose it in such a limiting and ugly way.
741      */
742     var_AddCallback(mp->obj.libvlc, "snapshot-file", snapshot_was_taken, mp);
743
744     libvlc_retain(instance);
745     return mp;
746 }
747
748 /**************************************************************************
749  * Create a Media Instance object with a media descriptor.
750  **************************************************************************/
751 libvlc_media_player_t *
752 libvlc_media_player_new_from_media( libvlc_media_t * p_md )
753 {
754     libvlc_media_player_t * p_mi;
755
756     p_mi = libvlc_media_player_new( p_md->p_libvlc_instance );
757     if( !p_mi )
758         return NULL;
759
760     libvlc_media_retain( p_md );
761     p_mi->p_md = p_md;
762
763     return p_mi;
764 }
765
766 /**************************************************************************
767  * Destroy a Media Instance object (libvlc internal)
768  *
769  * Warning: No lock held here, but hey, this is internal. Caller must lock.
770  **************************************************************************/
771 static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
772 {
773     assert( p_mi );
774
775     /* Detach Callback from the main libvlc object */
776     var_DelCallback( p_mi->obj.libvlc,
777                      "snapshot-file", snapshot_was_taken, p_mi );
778
779     /* Detach callback from the media player / input manager object */
780     var_DelCallback( p_mi, "volume", volume_changed, NULL );
781     var_DelCallback( p_mi, "mute", mute_changed, NULL );
782     var_DelCallback( p_mi, "audio-device", audio_device_changed, NULL );
783     var_DelCallback( p_mi, "corks", corks_changed, NULL );
784
785     /* No need for lock_input() because no other threads knows us anymore */
786     if( p_mi->input.p_thread )
787         release_input_thread(p_mi);
788     input_resource_Terminate( p_mi->input.p_resource );
789     input_resource_Release( p_mi->input.p_resource );
790     vlc_mutex_destroy( &p_mi->input.lock );
791
792     libvlc_event_manager_release( p_mi->p_event_manager );
793     libvlc_media_release( p_mi->p_md );
794     vlc_mutex_destroy( &p_mi->object_lock );
795
796     libvlc_instance_t *instance = p_mi->p_libvlc_instance;
797     vlc_object_release( p_mi );
798     libvlc_release(instance);
799 }
800
801 /**************************************************************************
802  * Release a Media Instance object.
803  *
804  * Function does the locking.
805  **************************************************************************/
806 void libvlc_media_player_release( libvlc_media_player_t *p_mi )
807 {
808     bool destroy;
809
810     assert( p_mi );
811     lock(p_mi);
812     destroy = !--p_mi->i_refcount;
813     unlock(p_mi);
814
815     if( destroy )
816         libvlc_media_player_destroy( p_mi );
817 }
818
819 /**************************************************************************
820  * Retain a Media Instance object.
821  *
822  * Caller must hold the lock.
823  **************************************************************************/
824 void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
825 {
826     assert( p_mi );
827
828     lock(p_mi);
829     p_mi->i_refcount++;
830     unlock(p_mi);
831 }
832
833 /**************************************************************************
834  * Set the Media descriptor associated with the instance.
835  *
836  * Enter without lock -- function will lock the object.
837  **************************************************************************/
838 void libvlc_media_player_set_media(
839                             libvlc_media_player_t *p_mi,
840                             libvlc_media_t *p_md )
841 {
842     lock_input(p_mi);
843
844     release_input_thread( p_mi );
845
846     lock( p_mi );
847     set_state( p_mi, libvlc_NothingSpecial, true );
848     unlock_input( p_mi );
849
850     libvlc_media_release( p_mi->p_md );
851
852     if( !p_md )
853     {
854         p_mi->p_md = NULL;
855         unlock(p_mi);
856         return; /* It is ok to pass a NULL md */
857     }
858
859     libvlc_media_retain( p_md );
860     p_mi->p_md = p_md;
861
862     /* The policy here is to ignore that we were created using a different
863      * libvlc_instance, because we don't really care */
864     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
865
866     unlock(p_mi);
867
868     /* Send an event for the newly available media */
869     libvlc_event_t event;
870     event.type = libvlc_MediaPlayerMediaChanged;
871     event.u.media_player_media_changed.new_media = p_md;
872     libvlc_event_send( p_mi->p_event_manager, &event );
873
874 }
875
876 /**************************************************************************
877  * Get the Media descriptor associated with the instance.
878  **************************************************************************/
879 libvlc_media_t *
880 libvlc_media_player_get_media( libvlc_media_player_t *p_mi )
881 {
882     libvlc_media_t *p_m;
883
884     lock( p_mi );
885     p_m = p_mi->p_md;
886     if( p_m )
887         libvlc_media_retain( p_m );
888     unlock( p_mi );
889
890     return p_m;
891 }
892
893 /**************************************************************************
894  * Get the event Manager.
895  **************************************************************************/
896 libvlc_event_manager_t *
897 libvlc_media_player_event_manager( libvlc_media_player_t *p_mi )
898 {
899     return p_mi->p_event_manager;
900 }
901
902 static void add_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi )
903 {
904     var_AddListCallback( p_input_thread, "video-es", input_es_changed, p_mi );
905     var_AddListCallback( p_input_thread, "audio-es", input_es_changed, p_mi );
906     var_AddListCallback( p_input_thread, "spu-es", input_es_changed, p_mi );
907     var_AddCallback( p_input_thread, "video-es", input_es_selected, p_mi );
908     var_AddCallback( p_input_thread, "audio-es", input_es_selected, p_mi );
909     var_AddCallback( p_input_thread, "spu-es", input_es_selected, p_mi );
910 }
911
912 static void del_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi )
913 {
914     var_DelListCallback( p_input_thread, "video-es", input_es_changed, p_mi );
915     var_DelListCallback( p_input_thread, "audio-es", input_es_changed, p_mi );
916     var_DelListCallback( p_input_thread, "spu-es", input_es_changed, p_mi );
917     var_DelCallback( p_input_thread, "video-es", input_es_selected, p_mi );
918     var_DelCallback( p_input_thread, "audio-es", input_es_selected, p_mi );
919     var_DelCallback( p_input_thread, "spu-es", input_es_selected, p_mi );
920 }
921
922 /**************************************************************************
923  * Tell media player to start playing.
924  **************************************************************************/
925 int libvlc_media_player_play( libvlc_media_player_t *p_mi )
926 {
927     lock_input( p_mi );
928
929     input_thread_t *p_input_thread = p_mi->input.p_thread;
930     if( p_input_thread )
931     {
932         /* A thread already exists, send it a play message */
933         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
934         unlock_input( p_mi );
935         return 0;
936     }
937
938     /* Ignore previous exception */
939     lock(p_mi);
940
941     if( !p_mi->p_md )
942     {
943         unlock(p_mi);
944         unlock_input( p_mi );
945         libvlc_printerr( "No associated media descriptor" );
946         return -1;
947     }
948
949     media_attach_preparsed_event( p_mi->p_md );
950
951     p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL,
952                                    p_mi->input.p_resource );
953     unlock(p_mi);
954     if( !p_input_thread )
955     {
956         unlock_input(p_mi);
957         media_detach_preparsed_event( p_mi->p_md );
958         libvlc_printerr( "Not enough memory" );
959         return -1;
960     }
961
962     var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
963     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
964     var_AddCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
965     var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
966     add_es_callbacks( p_input_thread, p_mi );
967
968     if( input_Start( p_input_thread ) )
969     {
970         unlock_input(p_mi);
971         del_es_callbacks( p_input_thread, p_mi );
972         var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
973         var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
974         var_DelCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
975         var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
976         input_Close( p_input_thread );
977         media_detach_preparsed_event( p_mi->p_md );
978         libvlc_printerr( "Input initialization failure" );
979         return -1;
980     }
981     p_mi->input.p_thread = p_input_thread;
982     unlock_input(p_mi);
983     return 0;
984 }
985
986 void libvlc_media_player_set_pause( libvlc_media_player_t *p_mi, int paused )
987 {
988     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi );
989     if( !p_input_thread )
990         return;
991
992     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
993     if( state == libvlc_Playing )
994     {
995         if( paused )
996         {
997             if( libvlc_media_player_can_pause( p_mi ) )
998                 input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
999             else
1000                 input_Stop( p_input_thread );
1001         }
1002     }
1003     else
1004     {
1005         if( !paused )
1006             input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
1007     }
1008
1009     vlc_object_release( p_input_thread );
1010 }
1011
1012 /**************************************************************************
1013  * Toggle pause.
1014  **************************************************************************/
1015 void libvlc_media_player_pause( libvlc_media_player_t *p_mi )
1016 {
1017     libvlc_media_player_set_pause( p_mi, libvlc_media_player_is_playing( p_mi ) );
1018 }
1019
1020 /**************************************************************************
1021  * Tells whether the media player is currently playing.
1022  *
1023  * Enter with lock held.
1024  **************************************************************************/
1025 int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi )
1026 {
1027     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
1028     return libvlc_Playing == state;
1029 }
1030
1031 /**************************************************************************
1032  * Stop playing.
1033  **************************************************************************/
1034 void libvlc_media_player_stop( libvlc_media_player_t *p_mi )
1035 {
1036     lock_input(p_mi);
1037     release_input_thread( p_mi ); /* This will stop the input thread */
1038
1039     /* Force to go to stopped state, in case we were in Ended, or Error
1040      * state. */
1041     if( p_mi->state != libvlc_Stopped )
1042     {
1043         set_state( p_mi, libvlc_Stopped, false );
1044
1045         /* Construct and send the event */
1046         libvlc_event_t event;
1047         event.type = libvlc_MediaPlayerStopped;
1048         libvlc_event_send( p_mi->p_event_manager, &event );
1049     }
1050
1051     input_resource_Terminate( p_mi->input.p_resource );
1052     unlock_input(p_mi);
1053 }
1054
1055
1056 void libvlc_video_set_callbacks( libvlc_media_player_t *mp,
1057     void *(*lock_cb) (void *, void **),
1058     void (*unlock_cb) (void *, void *, void *const *),
1059     void (*display_cb) (void *, void *),
1060     void *opaque )
1061 {
1062     var_SetAddress( mp, "vmem-lock", lock_cb );
1063     var_SetAddress( mp, "vmem-unlock", unlock_cb );
1064     var_SetAddress( mp, "vmem-display", display_cb );
1065     var_SetAddress( mp, "vmem-data", opaque );
1066     var_SetString( mp, "avcodec-hw", "none" );
1067     var_SetString( mp, "vout", "vmem" );
1068     var_SetString( mp, "window", "none" );
1069 }
1070
1071 void libvlc_video_set_format_callbacks( libvlc_media_player_t *mp,
1072                                         libvlc_video_format_cb setup,
1073                                         libvlc_video_cleanup_cb cleanup )
1074 {
1075     var_SetAddress( mp, "vmem-setup", setup );
1076     var_SetAddress( mp, "vmem-cleanup", cleanup );
1077 }
1078
1079 void libvlc_video_set_format( libvlc_media_player_t *mp, const char *chroma,
1080                               unsigned width, unsigned height, unsigned pitch )
1081 {
1082     var_SetString( mp, "vmem-chroma", chroma );
1083     var_SetInteger( mp, "vmem-width", width );
1084     var_SetInteger( mp, "vmem-height", height );
1085     var_SetInteger( mp, "vmem-pitch", pitch );
1086 }
1087
1088 /**************************************************************************
1089  * set_nsobject
1090  **************************************************************************/
1091 void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
1092                                         void * drawable )
1093 {
1094     assert (p_mi != NULL);
1095 #ifdef __APPLE__
1096     var_SetString (p_mi, "avcodec-hw", "");
1097     var_SetString (p_mi, "vout", "");
1098     var_SetString (p_mi, "window", "");
1099     var_SetAddress (p_mi, "drawable-nsobject", drawable);
1100 #else
1101     (void)drawable;
1102     libvlc_printerr ("can't set nsobject: APPLE build required");
1103     assert(false);
1104     var_SetString (p_mi, "vout", "none");
1105     var_SetString (p_mi, "window", "none");
1106 #endif
1107 }
1108
1109 /**************************************************************************
1110  * get_nsobject
1111  **************************************************************************/
1112 void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi )
1113 {
1114     assert (p_mi != NULL);
1115 #ifdef __APPLE__
1116     return var_GetAddress (p_mi, "drawable-nsobject");
1117 #else
1118     (void) p_mi;
1119     return NULL;
1120 #endif
1121 }
1122
1123 /**************************************************************************
1124  * set_agl
1125  **************************************************************************/
1126 void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
1127                                   uint32_t drawable )
1128 {
1129     (void)drawable;
1130     libvlc_printerr ("can't set agl: use libvlc_media_player_set_nsobject instead");
1131     assert(false);
1132     var_SetString (p_mi, "vout", "none");
1133     var_SetString (p_mi, "window", "none");
1134 }
1135
1136 /**************************************************************************
1137  * get_agl
1138  **************************************************************************/
1139 uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
1140 {
1141     (void) p_mi;
1142     return 0;
1143 }
1144
1145 /**************************************************************************
1146  * set_xwindow
1147  **************************************************************************/
1148 void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
1149                                       uint32_t drawable )
1150 {
1151     assert (p_mi != NULL);
1152
1153     var_SetString (p_mi, "avcodec-hw", "");
1154     var_SetString (p_mi, "vout", drawable ? "xid" : "");
1155     var_SetString (p_mi, "window", drawable ? "embed-xid,any" : "");
1156     var_SetInteger (p_mi, "drawable-xid", drawable);
1157 }
1158
1159 /**************************************************************************
1160  * get_xwindow
1161  **************************************************************************/
1162 uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
1163 {
1164     return var_GetInteger (p_mi, "drawable-xid");
1165 }
1166
1167 /**************************************************************************
1168  * set_hwnd
1169  **************************************************************************/
1170 void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
1171                                    void *drawable )
1172 {
1173     assert (p_mi != NULL);
1174 #if defined (_WIN32) || defined (__OS2__)
1175     var_SetString (p_mi, "avcodec-hw", "");
1176     var_SetString (p_mi, "vout", "");
1177     var_SetString (p_mi, "window",
1178                    (drawable != NULL) ? "embed-hwnd,any" : "");
1179     var_SetInteger (p_mi, "drawable-hwnd", (uintptr_t)drawable);
1180 #else
1181     (void) drawable;
1182     libvlc_printerr ("can't set nsobject: WIN32 build required");
1183     assert(false);
1184     var_SetString (p_mi, "vout", "none");
1185     var_SetString (p_mi, "window", "none");
1186 #endif
1187 }
1188
1189 /**************************************************************************
1190  * get_hwnd
1191  **************************************************************************/
1192 void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
1193 {
1194     assert (p_mi != NULL);
1195 #if defined (_WIN32) || defined (__OS2__)
1196     return (void *)(uintptr_t)var_GetInteger (p_mi, "drawable-hwnd");
1197 #else
1198     (void) p_mi;
1199     return NULL;
1200 #endif
1201 }
1202
1203 /**************************************************************************
1204  * set_android_context
1205  **************************************************************************/
1206 void libvlc_media_player_set_android_context( libvlc_media_player_t *p_mi,
1207                                               void *p_awindow_handler )
1208 {
1209     assert (p_mi != NULL);
1210 #ifdef __ANDROID__
1211     var_SetAddress (p_mi, "drawable-androidwindow", p_awindow_handler);
1212 #else
1213     (void) p_awindow_handler;
1214     libvlc_printerr ("can't set android context: ANDROID build required");
1215     assert(false);
1216     var_SetString (p_mi, "vout", "none");
1217     var_SetString (p_mi, "window", "none");
1218 #endif
1219 }
1220
1221 /**************************************************************************
1222  * set_evas_object
1223  **************************************************************************/
1224 int libvlc_media_player_set_evas_object( libvlc_media_player_t *p_mi,
1225                                          void *p_evas_object )
1226 {
1227     assert (p_mi != NULL);
1228 #ifdef HAVE_EVAS
1229     var_SetString (p_mi, "vout", "evas");
1230     var_SetString (p_mi, "window", "none");
1231     var_SetAddress (p_mi, "drawable-evasobject", p_evas_object);
1232     return 0;
1233 #else
1234     (void) p_mi; (void) p_evas_object;
1235     return -1;
1236 #endif
1237 }
1238
1239 void libvlc_audio_set_callbacks( libvlc_media_player_t *mp,
1240                                  libvlc_audio_play_cb play_cb,
1241                                  libvlc_audio_pause_cb pause_cb,
1242                                  libvlc_audio_resume_cb resume_cb,
1243                                  libvlc_audio_flush_cb flush_cb,
1244                                  libvlc_audio_drain_cb drain_cb,
1245                                  void *opaque )
1246 {
1247     var_SetAddress( mp, "amem-play", play_cb );
1248     var_SetAddress( mp, "amem-pause", pause_cb );
1249     var_SetAddress( mp, "amem-resume", resume_cb );
1250     var_SetAddress( mp, "amem-flush", flush_cb );
1251     var_SetAddress( mp, "amem-drain", drain_cb );
1252     var_SetAddress( mp, "amem-data", opaque );
1253     var_SetString( mp, "aout", "amem,none" );
1254
1255     input_resource_ResetAout(mp->input.p_resource);
1256 }
1257
1258 void libvlc_audio_set_volume_callback( libvlc_media_player_t *mp,
1259                                        libvlc_audio_set_volume_cb cb )
1260 {
1261     var_SetAddress( mp, "amem-set-volume", cb );
1262
1263     input_resource_ResetAout(mp->input.p_resource);
1264 }
1265
1266 void libvlc_audio_set_format_callbacks( libvlc_media_player_t *mp,
1267                                         libvlc_audio_setup_cb setup,
1268                                         libvlc_audio_cleanup_cb cleanup )
1269 {
1270     var_SetAddress( mp, "amem-setup", setup );
1271     var_SetAddress( mp, "amem-cleanup", cleanup );
1272
1273     input_resource_ResetAout(mp->input.p_resource);
1274 }
1275
1276 void libvlc_audio_set_format( libvlc_media_player_t *mp, const char *format,
1277                               unsigned rate, unsigned channels )
1278 {
1279     var_SetString( mp, "amem-format", format );
1280     var_SetInteger( mp, "amem-rate", rate );
1281     var_SetInteger( mp, "amem-channels", channels );
1282
1283     input_resource_ResetAout(mp->input.p_resource);
1284 }
1285
1286
1287 /**************************************************************************
1288  * Getters for stream information
1289  **************************************************************************/
1290 libvlc_time_t libvlc_media_player_get_length(
1291                              libvlc_media_player_t *p_mi )
1292 {
1293     input_thread_t *p_input_thread;
1294     libvlc_time_t i_time;
1295
1296     p_input_thread = libvlc_get_input_thread ( p_mi );
1297     if( !p_input_thread )
1298         return -1;
1299
1300     i_time = from_mtime(var_GetInteger( p_input_thread, "length" ));
1301     vlc_object_release( p_input_thread );
1302
1303     return i_time;
1304 }
1305
1306 libvlc_time_t libvlc_media_player_get_time( libvlc_media_player_t *p_mi )
1307 {
1308     input_thread_t *p_input_thread;
1309     libvlc_time_t i_time;
1310
1311     p_input_thread = libvlc_get_input_thread ( p_mi );
1312     if( !p_input_thread )
1313         return -1;
1314
1315     i_time = from_mtime(var_GetInteger( p_input_thread , "time" ));
1316     vlc_object_release( p_input_thread );
1317     return i_time;
1318 }
1319
1320 void libvlc_media_player_set_time( libvlc_media_player_t *p_mi,
1321                                    libvlc_time_t i_time )
1322 {
1323     input_thread_t *p_input_thread;
1324
1325     p_input_thread = libvlc_get_input_thread ( p_mi );
1326     if( !p_input_thread )
1327         return;
1328
1329     var_SetInteger( p_input_thread, "time", to_mtime(i_time) );
1330     vlc_object_release( p_input_thread );
1331 }
1332
1333 void libvlc_media_player_set_position( libvlc_media_player_t *p_mi,
1334                                        float position )
1335 {
1336     input_thread_t *p_input_thread;
1337
1338     p_input_thread = libvlc_get_input_thread ( p_mi );
1339     if( !p_input_thread )
1340         return;
1341
1342     var_SetFloat( p_input_thread, "position", position );
1343     vlc_object_release( p_input_thread );
1344 }
1345
1346 float libvlc_media_player_get_position( libvlc_media_player_t *p_mi )
1347 {
1348     input_thread_t *p_input_thread;
1349     float f_position;
1350
1351     p_input_thread = libvlc_get_input_thread ( p_mi );
1352     if( !p_input_thread )
1353         return -1.0;
1354
1355     f_position = var_GetFloat( p_input_thread, "position" );
1356     vlc_object_release( p_input_thread );
1357
1358     return f_position;
1359 }
1360
1361 void libvlc_media_player_set_chapter( libvlc_media_player_t *p_mi,
1362                                       int chapter )
1363 {
1364     input_thread_t *p_input_thread;
1365
1366     p_input_thread = libvlc_get_input_thread ( p_mi );
1367     if( !p_input_thread )
1368         return;
1369
1370     var_SetInteger( p_input_thread, "chapter", chapter );
1371     vlc_object_release( p_input_thread );
1372 }
1373
1374 int libvlc_media_player_get_chapter( libvlc_media_player_t *p_mi )
1375 {
1376     input_thread_t *p_input_thread;
1377     int i_chapter;
1378
1379     p_input_thread = libvlc_get_input_thread ( p_mi );
1380     if( !p_input_thread )
1381         return -1;
1382
1383     i_chapter = var_GetInteger( p_input_thread, "chapter" );
1384     vlc_object_release( p_input_thread );
1385
1386     return i_chapter;
1387 }
1388
1389 int libvlc_media_player_get_chapter_count( libvlc_media_player_t *p_mi )
1390 {
1391     input_thread_t *p_input_thread;
1392     vlc_value_t val;
1393
1394     p_input_thread = libvlc_get_input_thread ( p_mi );
1395     if( !p_input_thread )
1396         return -1;
1397
1398     int i_ret = var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
1399     vlc_object_release( p_input_thread );
1400
1401     return i_ret == VLC_SUCCESS ? val.i_int : -1;
1402 }
1403
1404 int libvlc_media_player_get_chapter_count_for_title(
1405                                  libvlc_media_player_t *p_mi,
1406                                  int i_title )
1407 {
1408     vlc_value_t val;
1409
1410     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1411     if( !p_input_thread )
1412         return -1;
1413
1414     char psz_name[sizeof ("title ") + 3 * sizeof (int)];
1415     sprintf( psz_name, "title %2u", i_title );
1416
1417     int i_ret = var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
1418     vlc_object_release( p_input_thread );
1419
1420     return i_ret == VLC_SUCCESS ? val.i_int : -1;
1421 }
1422
1423 void libvlc_media_player_set_title( libvlc_media_player_t *p_mi,
1424                                     int i_title )
1425 {
1426     input_thread_t *p_input_thread;
1427
1428     p_input_thread = libvlc_get_input_thread ( p_mi );
1429     if( !p_input_thread )
1430         return;
1431
1432     var_SetInteger( p_input_thread, "title", i_title );
1433     vlc_object_release( p_input_thread );
1434
1435     //send event
1436     libvlc_event_t event;
1437     event.type = libvlc_MediaPlayerTitleChanged;
1438     event.u.media_player_title_changed.new_title = i_title;
1439     libvlc_event_send( p_mi->p_event_manager, &event );
1440 }
1441
1442 int libvlc_media_player_get_title( libvlc_media_player_t *p_mi )
1443 {
1444     input_thread_t *p_input_thread;
1445     int i_title;
1446
1447     p_input_thread = libvlc_get_input_thread ( p_mi );
1448     if( !p_input_thread )
1449         return -1;
1450
1451     i_title = var_GetInteger( p_input_thread, "title" );
1452     vlc_object_release( p_input_thread );
1453
1454     return i_title;
1455 }
1456
1457 int libvlc_media_player_get_title_count( libvlc_media_player_t *p_mi )
1458 {
1459     input_thread_t *p_input_thread;
1460     vlc_value_t val;
1461
1462     p_input_thread = libvlc_get_input_thread ( p_mi );
1463     if( !p_input_thread )
1464         return -1;
1465
1466     int i_ret = var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
1467     vlc_object_release( p_input_thread );
1468
1469     return i_ret == VLC_SUCCESS ? val.i_int : -1;
1470 }
1471
1472 int libvlc_media_player_get_full_title_descriptions( libvlc_media_player_t *p_mi,
1473                                                      libvlc_title_description_t *** pp_titles )
1474 {
1475     assert( p_mi );
1476
1477     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
1478
1479     if( !p_input_thread )
1480         return -1;
1481
1482     input_title_t **p_input_title;
1483     int count;
1484
1485     /* fetch data */
1486     int ret = input_Control( p_input_thread, INPUT_GET_FULL_TITLE_INFO,
1487                              &p_input_title, &count );
1488     vlc_object_release( p_input_thread );
1489     if( ret != VLC_SUCCESS )
1490         return -1;
1491
1492     libvlc_title_description_t **titles = malloc( count * sizeof (*titles) );
1493     if( count > 0 && unlikely(titles == NULL) )
1494         return -1;
1495
1496     /* fill array */
1497     for( int i = 0; i < count; i++)
1498     {
1499         libvlc_title_description_t *title = malloc( sizeof (*title) );
1500         if( unlikely(title == NULL) )
1501         {
1502             libvlc_title_descriptions_release( titles, i );
1503             return -1;
1504         }
1505         titles[i] = title;
1506
1507         /* we want to return milliseconds to match the rest of the API */
1508         title->i_duration = p_input_title[i]->i_length / 1000;
1509         title->i_flags = p_input_title[i]->i_flags;
1510         if( p_input_title[i]->psz_name )
1511             title->psz_name = strdup( p_input_title[i]->psz_name );
1512         else
1513             title->psz_name = NULL;
1514         vlc_input_title_Delete( p_input_title[i] );
1515     }
1516     free( p_input_title );
1517
1518     *pp_titles = titles;
1519     return count;
1520 }
1521
1522 void libvlc_title_descriptions_release( libvlc_title_description_t **p_titles,
1523                                         unsigned i_count )
1524 {
1525     for (unsigned i = 0; i < i_count; i++ )
1526     {
1527         if ( !p_titles[i] )
1528             continue;
1529
1530         free( p_titles[i]->psz_name );
1531         free( p_titles[i] );
1532     }
1533     free( p_titles );
1534 }
1535
1536 int libvlc_media_player_get_full_chapter_descriptions( libvlc_media_player_t *p_mi,
1537                                                       int i_chapters_of_title,
1538                                                       libvlc_chapter_description_t *** pp_chapters )
1539 {
1540     assert( p_mi );
1541
1542     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
1543
1544     if( !p_input_thread )
1545         return -1;
1546
1547     seekpoint_t **p_seekpoint = NULL;
1548
1549     /* fetch data */
1550     int ret = input_Control(p_input_thread, INPUT_GET_SEEKPOINTS, &p_seekpoint, &i_chapters_of_title);
1551     vlc_object_release( p_input_thread );
1552
1553     if( ret != VLC_SUCCESS)
1554     {
1555         return -1;
1556     }
1557
1558     if (i_chapters_of_title == 0 || p_seekpoint == NULL)
1559     {
1560         return 0;
1561     }
1562
1563     const int ci_chapter_count = (const int)i_chapters_of_title;
1564
1565     *pp_chapters = calloc( ci_chapter_count, sizeof(**pp_chapters) );
1566     if( !*pp_chapters )
1567     {
1568         return -1;
1569     }
1570
1571     /* fill array */
1572     for( int i = 0; i < ci_chapter_count; i++)
1573     {
1574         libvlc_chapter_description_t *p_chapter = malloc( sizeof(*p_chapter) );
1575         if( unlikely(p_chapter == NULL) )
1576         {
1577             libvlc_chapter_descriptions_release( *pp_chapters, ci_chapter_count );
1578             return -1;
1579         }
1580         (*pp_chapters)[i] = p_chapter;
1581
1582         p_chapter->i_time_offset = p_seekpoint[i]->i_time_offset / 1000;
1583
1584         if( i > 0 )
1585         {
1586             p_chapter->i_duration = p_chapter->i_time_offset - (*pp_chapters)[i-1]->i_time_offset;
1587         }
1588         else
1589         {
1590             p_chapter->i_duration = p_chapter->i_time_offset;
1591         }
1592
1593         if( p_seekpoint[i]->psz_name )
1594         {
1595             p_chapter->psz_name = strdup( p_seekpoint[i]->psz_name );
1596         }
1597         else
1598         {
1599             p_chapter->psz_name = NULL;
1600         }
1601         vlc_seekpoint_Delete( p_seekpoint[i] );
1602     }
1603
1604     return ci_chapter_count;
1605 }
1606
1607 void libvlc_chapter_descriptions_release( libvlc_chapter_description_t **p_chapters,
1608                                           unsigned i_count )
1609 {
1610     for (unsigned i = 0; i < i_count; i++ )
1611     {
1612         if ( !p_chapters[i] )
1613             continue;
1614
1615         free( p_chapters[i]->psz_name );
1616         free( p_chapters[i] );
1617     }
1618     free( p_chapters );
1619 }
1620
1621 void libvlc_media_player_next_chapter( libvlc_media_player_t *p_mi )
1622 {
1623     input_thread_t *p_input_thread;
1624
1625     p_input_thread = libvlc_get_input_thread ( p_mi );
1626     if( !p_input_thread )
1627         return;
1628
1629     int i_type = var_Type( p_input_thread, "next-chapter" );
1630     var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1631                             "next-chapter":"next-title" );
1632
1633     vlc_object_release( p_input_thread );
1634 }
1635
1636 void libvlc_media_player_previous_chapter( libvlc_media_player_t *p_mi )
1637 {
1638     input_thread_t *p_input_thread;
1639
1640     p_input_thread = libvlc_get_input_thread ( p_mi );
1641     if( !p_input_thread )
1642         return;
1643
1644     int i_type = var_Type( p_input_thread, "next-chapter" );
1645     var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1646                             "prev-chapter":"prev-title" );
1647
1648     vlc_object_release( p_input_thread );
1649 }
1650
1651 float libvlc_media_player_get_fps( libvlc_media_player_t *p_mi )
1652 {
1653     libvlc_media_t *media = libvlc_media_player_get_media( p_mi );
1654     if( media == NULL )
1655         return 0.f;
1656
1657     input_item_t *item = media->p_input_item;
1658     float fps = 0.f;
1659
1660     vlc_mutex_lock( &item->lock );
1661     for( int i = 0; i < item->i_es; i++ )
1662     {
1663         const es_format_t *fmt = item->es[i];
1664
1665         if( fmt->i_cat == VIDEO_ES && fmt->video.i_frame_rate_base > 0 )
1666             fps = (float)fmt->video.i_frame_rate
1667                   / (float)fmt->video.i_frame_rate_base;
1668     }
1669     vlc_mutex_unlock( &item->lock );
1670     libvlc_media_release( media );
1671
1672     return fps;
1673 }
1674
1675 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi )
1676 {
1677     input_thread_t *p_input_thread =
1678                             libvlc_get_input_thread ( p_mi );
1679     if ( !p_input_thread )
1680         return false;
1681
1682     int state = var_GetInteger( p_input_thread, "state" );
1683     vlc_object_release( p_input_thread );
1684
1685     return state != END_S && state != ERROR_S;
1686 }
1687
1688 int libvlc_media_player_set_rate( libvlc_media_player_t *p_mi, float rate )
1689 {
1690     var_SetFloat (p_mi, "rate", rate);
1691
1692     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1693     if( !p_input_thread )
1694         return 0;
1695     var_SetFloat( p_input_thread, "rate", rate );
1696     vlc_object_release( p_input_thread );
1697     return 0;
1698 }
1699
1700 float libvlc_media_player_get_rate( libvlc_media_player_t *p_mi )
1701 {
1702     return var_GetFloat (p_mi, "rate");
1703 }
1704
1705 libvlc_state_t libvlc_media_player_get_state( libvlc_media_player_t *p_mi )
1706 {
1707     lock(p_mi);
1708     libvlc_state_t state = p_mi->state;
1709     unlock(p_mi);
1710     return state;
1711 }
1712
1713 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi )
1714 {
1715     input_thread_t *p_input_thread;
1716     bool b_seekable;
1717
1718     p_input_thread = libvlc_get_input_thread ( p_mi );
1719     if ( !p_input_thread )
1720         return false;
1721     b_seekable = var_GetBool( p_input_thread, "can-seek" );
1722     vlc_object_release( p_input_thread );
1723
1724     return b_seekable;
1725 }
1726
1727 void libvlc_media_player_navigate( libvlc_media_player_t* p_mi,
1728                                    unsigned navigate )
1729 {
1730     static const vlc_action_t map[] =
1731     {
1732         INPUT_NAV_ACTIVATE, INPUT_NAV_UP, INPUT_NAV_DOWN,
1733         INPUT_NAV_LEFT, INPUT_NAV_RIGHT, INPUT_NAV_POPUP,
1734     };
1735
1736     if( navigate >= sizeof(map) / sizeof(map[0]) )
1737       return;
1738
1739     input_thread_t *p_input = libvlc_get_input_thread ( p_mi );
1740     if ( p_input == NULL )
1741       return;
1742
1743     input_Control( p_input, map[navigate], NULL );
1744     vlc_object_release( p_input );
1745 }
1746
1747 /* internal function, used by audio, video */
1748 libvlc_track_description_t *
1749         libvlc_get_track_description( libvlc_media_player_t *p_mi,
1750                                       const char *psz_variable )
1751 {
1752     input_thread_t *p_input = libvlc_get_input_thread( p_mi );
1753     libvlc_track_description_t *p_track_description = NULL,
1754                                *p_actual, *p_previous;
1755
1756     if( !p_input )
1757         return NULL;
1758
1759     vlc_value_t val_list, text_list;
1760     int i_ret = var_Change( p_input, psz_variable, VLC_VAR_GETCHOICES, &val_list, &text_list );
1761     if( i_ret != VLC_SUCCESS )
1762         return NULL;
1763
1764     /* no tracks */
1765     if( val_list.p_list->i_count <= 0 )
1766         goto end;
1767
1768     p_track_description = ( libvlc_track_description_t * )
1769         malloc( sizeof( libvlc_track_description_t ) );
1770     if ( !p_track_description )
1771     {
1772         libvlc_printerr( "Not enough memory" );
1773         goto end;
1774     }
1775     p_actual = p_track_description;
1776     p_previous = NULL;
1777     for( int i = 0; i < val_list.p_list->i_count; i++ )
1778     {
1779         if( !p_actual )
1780         {
1781             p_actual = ( libvlc_track_description_t * )
1782                 malloc( sizeof( libvlc_track_description_t ) );
1783             if ( !p_actual )
1784             {
1785                 libvlc_track_description_list_release( p_track_description );
1786                 libvlc_printerr( "Not enough memory" );
1787                 goto end;
1788             }
1789         }
1790         p_actual->i_id = val_list.p_list->p_values[i].i_int;
1791         p_actual->psz_name = strdup( text_list.p_list->p_values[i].psz_string );
1792         p_actual->p_next = NULL;
1793         if( p_previous )
1794             p_previous->p_next = p_actual;
1795         p_previous = p_actual;
1796         p_actual =  NULL;
1797     }
1798
1799 end:
1800     var_FreeList( &val_list, &text_list );
1801     vlc_object_release( p_input );
1802
1803     return p_track_description;
1804 }
1805
1806 // Deprecated alias for libvlc_track_description_list_release
1807 void libvlc_track_description_release( libvlc_track_description_t *p_td )
1808 {
1809     libvlc_track_description_list_release( p_td );
1810 }
1811
1812 void libvlc_track_description_list_release( libvlc_track_description_t *p_td )
1813 {
1814     libvlc_track_description_t *p_actual, *p_before;
1815     p_actual = p_td;
1816
1817     while ( p_actual )
1818     {
1819         free( p_actual->psz_name );
1820         p_before = p_actual;
1821         p_actual = p_before->p_next;
1822         free( p_before );
1823     }
1824 }
1825
1826 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi )
1827 {
1828     input_thread_t *p_input_thread;
1829     bool b_can_pause;
1830
1831     p_input_thread = libvlc_get_input_thread ( p_mi );
1832     if ( !p_input_thread )
1833         return false;
1834     b_can_pause = var_GetBool( p_input_thread, "can-pause" );
1835     vlc_object_release( p_input_thread );
1836
1837     return b_can_pause;
1838 }
1839
1840 int libvlc_media_player_program_scrambled( libvlc_media_player_t *p_mi )
1841 {
1842     input_thread_t *p_input_thread;
1843     bool b_program_scrambled;
1844
1845     p_input_thread = libvlc_get_input_thread ( p_mi );
1846     if ( !p_input_thread )
1847         return false;
1848     b_program_scrambled = var_GetBool( p_input_thread, "program-scrambled" );
1849     vlc_object_release( p_input_thread );
1850
1851     return b_program_scrambled;
1852 }
1853
1854 void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )
1855 {
1856     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1857     if( p_input_thread != NULL )
1858     {
1859         var_TriggerCallback( p_input_thread, "frame-next" );
1860         vlc_object_release( p_input_thread );
1861     }
1862 }
1863
1864 /**
1865  * Private lookup table to get subpicture alignment flag values corresponding
1866  * to a libvlc_position_t enumerated value.
1867  */
1868 static const unsigned char position_subpicture_alignment[] = {
1869     [libvlc_position_center]       = 0,
1870     [libvlc_position_left]         = SUBPICTURE_ALIGN_LEFT,
1871     [libvlc_position_right]        = SUBPICTURE_ALIGN_RIGHT,
1872     [libvlc_position_top]          = SUBPICTURE_ALIGN_TOP,
1873     [libvlc_position_top_left]     = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT,
1874     [libvlc_position_top_right]    = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_RIGHT,
1875     [libvlc_position_bottom]       = SUBPICTURE_ALIGN_BOTTOM,
1876     [libvlc_position_bottom_left]  = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_LEFT,
1877     [libvlc_position_bottom_right] = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_RIGHT
1878 };
1879
1880 void libvlc_media_player_set_video_title_display( libvlc_media_player_t *p_mi, libvlc_position_t position, unsigned timeout )
1881 {
1882     assert( position >= libvlc_position_disable && position <= libvlc_position_bottom_right );
1883
1884     if ( position != libvlc_position_disable )
1885     {
1886         var_SetBool( p_mi, "video-title-show", true );
1887         var_SetInteger( p_mi, "video-title-position", position_subpicture_alignment[position] );
1888         var_SetInteger( p_mi, "video-title-timeout", timeout );
1889     }
1890     else
1891     {
1892         var_SetBool( p_mi, "video-title-show", false );
1893     }
1894 }
1895
1896 int libvlc_media_player_add_slave( libvlc_media_player_t *p_mi,
1897                                    libvlc_media_slave_type_t i_type,
1898                                    const char *psz_uri, bool b_select )
1899 {
1900     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1901
1902     if( p_input_thread == NULL )
1903     {
1904         libvlc_media_t *p_media = libvlc_media_player_get_media( p_mi );
1905         if( p_media == NULL )
1906             return -1;
1907
1908         int i_ret = libvlc_media_slaves_add( p_media, i_type, 4, psz_uri );
1909         libvlc_media_release( p_media );
1910         return i_ret;
1911     }
1912     else
1913     {
1914         int i_ret = input_AddSlave( p_input_thread, i_type, psz_uri, b_select );
1915         vlc_object_release( p_input_thread );
1916
1917         return i_ret == VLC_SUCCESS ? 0 : -1;
1918     }
1919 }
1920
1921 /**
1922  * Maximum size of a formatted equalizer amplification band frequency value.
1923  *
1924  * The allowed value range is supposed to be constrained from -20.0 to 20.0.
1925  *
1926  * The format string " %.07f" with a minimum value of "-20" gives a maximum
1927  * string length of e.g. " -19.1234567", i.e. 12 bytes (not including the null
1928  * terminator).
1929  */
1930 #define EQZ_BAND_VALUE_SIZE 12
1931
1932 int libvlc_media_player_set_equalizer( libvlc_media_player_t *p_mi, libvlc_equalizer_t *p_equalizer )
1933 {
1934     char bands[EQZ_BANDS_MAX * EQZ_BAND_VALUE_SIZE + 1];
1935
1936     if( p_equalizer != NULL )
1937     {
1938         for( unsigned i = 0, c = 0; i < EQZ_BANDS_MAX; i++ )
1939         {
1940             c += snprintf( bands + c, sizeof(bands) - c, " %.07f",
1941                           p_equalizer->f_amp[i] );
1942             if( unlikely(c >= sizeof(bands)) )
1943                 return -1;
1944         }
1945
1946         var_SetFloat( p_mi, "equalizer-preamp", p_equalizer->f_preamp );
1947         var_SetString( p_mi, "equalizer-bands", bands );
1948     }
1949     var_SetString( p_mi, "audio-filter", p_equalizer ? "equalizer" : "" );
1950
1951     audio_output_t *p_aout = input_resource_HoldAout( p_mi->input.p_resource );
1952     if( p_aout != NULL )
1953     {
1954         if( p_equalizer != NULL )
1955         {
1956             var_SetFloat( p_aout, "equalizer-preamp", p_equalizer->f_preamp );
1957             var_SetString( p_aout, "equalizer-bands", bands );
1958         }
1959
1960         var_SetString( p_aout, "audio-filter", p_equalizer ? "equalizer" : "" );
1961         vlc_object_release( p_aout );
1962     }
1963
1964     return 0;
1965 }
1966
1967 static const char roles[][16] =
1968 {
1969     [libvlc_role_Music] =         "music",
1970     [libvlc_role_Video] =         "video",
1971     [libvlc_role_Communication] = "communication",
1972     [libvlc_role_Game] =          "game",
1973     [liblvc_role_Notification] =  "notification",
1974     [libvlc_role_Animation] =     "animation",
1975     [libvlc_role_Production] =    "production",
1976     [libvlc_role_Accessibility] = "accessibility",
1977     [libvlc_role_Test] =          "test",
1978 };
1979
1980 int libvlc_media_player_set_role(libvlc_media_player_t *mp, unsigned role)
1981 {
1982     if (role >= ARRAY_SIZE(roles)
1983      || var_SetString(mp, "role", roles[role]) != VLC_SUCCESS)
1984         return -1;
1985     return 0;
1986 }
1987
1988 int libvlc_media_player_get_role(libvlc_media_player_t *mp)
1989 {
1990     int ret = -1;
1991     char *str = var_GetString(mp, "role");
1992     if (str == NULL)
1993         return 0;
1994
1995     for (size_t i = 0; i < ARRAY_SIZE(roles); i++)
1996         if (!strcmp(roles[i], str))
1997         {
1998             ret = i;
1999             break;
2000         }
2001
2002     free(str);
2003     return ret;
2004 }