a9a22fee155068d08ce7b1457ecf677b4f331f26
[vlc.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_renderer_discoverer.h>
31 #include <vlc/libvlc_media.h>
32 #include <vlc/libvlc_events.h>
33
34 #include <vlc_demux.h>
35 #include <vlc_input.h>
36 #include <vlc_vout.h>
37 #include <vlc_aout.h>
38 #include <vlc_actions.h>
39 #include <vlc_http.h>
40
41 #include "libvlc_internal.h"
42 #include "media_internal.h" // libvlc_media_set_state()
43 #include "media_player_internal.h"
44 #include "renderer_discoverer_internal.h"
45
46 #define ES_INIT (-2) /* -1 is reserved for ES deselect */
47
48 static int
49 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
50                         vlc_value_t oldval, vlc_value_t newval,
51                         void * p_userdata );
52 static int
53 input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
54                         vlc_value_t oldval, vlc_value_t newval,
55                         void * p_userdata );
56 static int
57 input_scrambled_changed( vlc_object_t * p_this, char const * psz_cmd,
58                         vlc_value_t oldval, vlc_value_t newval,
59                         void * p_userdata );
60 static int
61 input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
62                      vlc_value_t oldval, vlc_value_t newval,
63                      void * p_userdata );
64
65 static int
66 input_es_changed( vlc_object_t * p_this, char const * psz_cmd,
67                   int action, vlc_value_t *p_val,
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->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->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->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->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->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->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->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->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->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 = (100 *
378             var_GetFloat( p_input, "cache" ));
379         libvlc_event_send( &p_mi->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->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->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->event_manager, &event );
411     }
412     else if ( newval.i_int == INPUT_EVENT_ES )
413     {
414         /* Send ESSelected events from this callback ("intf-event") and not
415          * from "audio-es", "video-es", "spu-es" callbacks. Indeed, these
416          * callbacks are not triggered when the input_thread changes an ES
417          * while this callback is. */
418         struct {
419             const char *psz_name;
420             const libvlc_track_type_t type;
421             int new_es;
422         } es_list[] = {
423             { "audio-es", libvlc_track_audio, ES_INIT },
424             { "video-es", libvlc_track_video, ES_INIT },
425             { "spu-es", libvlc_track_text, ES_INIT },
426         };
427         /* Check if an ES selection changed */
428         lock( p_mi );
429         for( size_t i = 0; i < ARRAY_SIZE( es_list ); ++i )
430         {
431             int current_es = var_GetInteger( p_input, es_list[i].psz_name );
432             if( current_es != p_mi->selected_es[i] )
433                 es_list[i].new_es = p_mi->selected_es[i] = current_es;
434         }
435         unlock( p_mi );
436
437         /* Send the ESSelected event for each ES that were newly selected */
438         for( size_t i = 0; i < ARRAY_SIZE( es_list ); ++i )
439         {
440             if( es_list[i].new_es != ES_INIT )
441             {
442                 event.type = libvlc_MediaPlayerESSelected;
443                 event.u.media_player_es_changed.i_type = es_list[i].type;
444                 event.u.media_player_es_changed.i_id = es_list[i].new_es;
445                 libvlc_event_send( &p_mi->event_manager, &event );
446             }
447         }
448     }
449
450     return VLC_SUCCESS;
451 }
452
453 static int track_type_from_name(const char *psz_name)
454 {
455    if( !strcmp( psz_name, "video-es" ) )
456        return libvlc_track_video;
457     else if( !strcmp( psz_name, "audio-es" ) )
458         return libvlc_track_audio;
459     else if( !strcmp( psz_name, "spu-es" ) )
460         return libvlc_track_text;
461     else
462         return libvlc_track_unknown;
463 }
464
465 static int input_es_changed( vlc_object_t *p_this,
466                              char const *psz_cmd,
467                              int action,
468                              vlc_value_t *p_val,
469                              void *p_userdata )
470 {
471     VLC_UNUSED(p_this);
472     libvlc_media_player_t *mp = p_userdata;
473     libvlc_event_t event;
474
475     /* Ignore the "Disable" element */
476     if (p_val && p_val->i_int < 0)
477         return VLC_EGENERIC;
478
479     switch (action)
480     {
481     case VLC_VAR_ADDCHOICE:
482         event.type = libvlc_MediaPlayerESAdded;
483         break;
484     case VLC_VAR_DELCHOICE:
485     case VLC_VAR_CLEARCHOICES:
486         event.type = libvlc_MediaPlayerESDeleted;
487         break;
488     default:
489         return VLC_EGENERIC;
490     }
491
492     event.u.media_player_es_changed.i_type = track_type_from_name(psz_cmd);
493
494     int i_id;
495     if (action != VLC_VAR_CLEARCHOICES)
496     {
497         if (!p_val)
498             return VLC_EGENERIC;
499         i_id = p_val->i_int;
500     }
501     else
502     {
503         /* -1 means all ES tracks of this type were deleted. */
504         i_id = -1;
505     }
506     event.u.media_player_es_changed.i_id = i_id;
507
508     libvlc_event_send(&mp->event_manager, &event);
509
510     return VLC_SUCCESS;
511 }
512
513 /**************************************************************************
514  * Snapshot Taken Event.
515  *
516  * FIXME: This snapshot API interface makes no sense in media_player.
517  *************************************************************************/
518 static int snapshot_was_taken(vlc_object_t *p_this, char const *psz_cmd,
519                               vlc_value_t oldval, vlc_value_t newval, void *p_data )
520 {
521     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_this);
522
523     libvlc_media_player_t *mp = p_data;
524     libvlc_event_t event;
525     event.type = libvlc_MediaPlayerSnapshotTaken;
526     event.u.media_player_snapshot_taken.psz_filename = newval.psz_string;
527     libvlc_event_send(&mp->event_manager, &event);
528
529     return VLC_SUCCESS;
530 }
531
532 static int corks_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
533                          vlc_value_t cur, void *opaque)
534 {
535     libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
536
537     if (!old.i_int != !cur.i_int)
538     {
539         libvlc_event_t event;
540
541         event.type = cur.i_int ? libvlc_MediaPlayerCorked
542                                : libvlc_MediaPlayerUncorked;
543         libvlc_event_send(&mp->event_manager, &event);
544     }
545     VLC_UNUSED(name); VLC_UNUSED(opaque);
546     return VLC_SUCCESS;
547 }
548
549 static int audio_device_changed(vlc_object_t *obj, const char *name,
550                                 vlc_value_t old, vlc_value_t cur, void *opaque)
551 {
552     libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
553     libvlc_event_t event;
554
555     event.type = libvlc_MediaPlayerAudioDevice;
556     event.u.media_player_audio_device.device = cur.psz_string;
557     libvlc_event_send(&mp->event_manager, &event);
558     VLC_UNUSED(name); VLC_UNUSED(old); VLC_UNUSED(opaque);
559     return VLC_SUCCESS;
560 }
561
562 static int mute_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
563                         vlc_value_t cur, void *opaque)
564 {
565     libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
566
567     if (old.b_bool != cur.b_bool)
568     {
569         libvlc_event_t event;
570
571         event.type = cur.b_bool ? libvlc_MediaPlayerMuted
572                                 : libvlc_MediaPlayerUnmuted;
573         libvlc_event_send(&mp->event_manager, &event);
574     }
575     VLC_UNUSED(name); VLC_UNUSED(opaque);
576     return VLC_SUCCESS;
577 }
578
579 static int volume_changed(vlc_object_t *obj, const char *name, vlc_value_t old,
580                           vlc_value_t cur, void *opaque)
581 {
582     libvlc_media_player_t *mp = (libvlc_media_player_t *)obj;
583     libvlc_event_t event;
584
585     event.type = libvlc_MediaPlayerAudioVolume;
586     event.u.media_player_audio_volume.volume = cur.f_float;
587     libvlc_event_send(&mp->event_manager, &event);
588     VLC_UNUSED(name); VLC_UNUSED(old); VLC_UNUSED(opaque);
589     return VLC_SUCCESS;
590 }
591
592 /**************************************************************************
593  * Create a Media Instance object.
594  *
595  * Refcount strategy:
596  * - All items created by _new start with a refcount set to 1.
597  * - Accessor _release decrease the refcount by 1, if after that
598  *   operation the refcount is 0, the object is destroyed.
599  * - Accessor _retain increase the refcount by 1 (XXX: to implement)
600  *
601  * Object locking strategy:
602  * - No lock held while in constructor.
603  * - When accessing any member variable this lock is held. (XXX who locks?)
604  * - When attempting to destroy the object the lock is also held.
605  **************************************************************************/
606 libvlc_media_player_t *
607 libvlc_media_player_new( libvlc_instance_t *instance )
608 {
609     libvlc_media_player_t * mp;
610
611     assert(instance);
612
613     mp = vlc_object_create (instance->p_libvlc_int, sizeof(*mp));
614     if (unlikely(mp == NULL))
615     {
616         libvlc_printerr("Not enough memory");
617         return NULL;
618     }
619
620     /* Input */
621     var_Create (mp, "rate", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT);
622     var_Create (mp, "sout", VLC_VAR_STRING);
623     var_Create (mp, "demux-filter", VLC_VAR_STRING);
624
625     /* Video */
626     var_Create (mp, "vout", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
627     var_Create (mp, "window", VLC_VAR_STRING);
628     var_Create (mp, "vmem-lock", VLC_VAR_ADDRESS);
629     var_Create (mp, "vmem-unlock", VLC_VAR_ADDRESS);
630     var_Create (mp, "vmem-display", VLC_VAR_ADDRESS);
631     var_Create (mp, "vmem-data", VLC_VAR_ADDRESS);
632     var_Create (mp, "vmem-setup", VLC_VAR_ADDRESS);
633     var_Create (mp, "vmem-cleanup", VLC_VAR_ADDRESS);
634     var_Create (mp, "vmem-chroma", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
635     var_Create (mp, "vmem-width", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
636     var_Create (mp, "vmem-height", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
637     var_Create (mp, "vmem-pitch", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
638     var_Create (mp, "avcodec-hw", VLC_VAR_STRING);
639     var_Create (mp, "drawable-xid", VLC_VAR_INTEGER);
640 #if defined (_WIN32) || defined (__OS2__)
641     var_Create (mp, "drawable-hwnd", VLC_VAR_INTEGER);
642 #endif
643 #ifdef __APPLE__
644     var_Create (mp, "drawable-nsobject", VLC_VAR_ADDRESS);
645 #endif
646 #ifdef __ANDROID__
647     var_Create (mp, "drawable-androidwindow", VLC_VAR_ADDRESS);
648 #endif
649 #ifdef HAVE_EVAS
650     var_Create (mp, "drawable-evasobject", VLC_VAR_ADDRESS);
651 #endif
652
653     var_Create (mp, "keyboard-events", VLC_VAR_BOOL);
654     var_SetBool (mp, "keyboard-events", true);
655     var_Create (mp, "mouse-events", VLC_VAR_BOOL);
656     var_SetBool (mp, "mouse-events", true);
657
658     var_Create (mp, "fullscreen", VLC_VAR_BOOL);
659     var_Create (mp, "autoscale", VLC_VAR_BOOL | VLC_VAR_DOINHERIT);
660     var_Create (mp, "zoom", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
661     var_Create (mp, "aspect-ratio", VLC_VAR_STRING);
662     var_Create (mp, "crop", VLC_VAR_STRING);
663     var_Create (mp, "deinterlace", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
664     var_Create (mp, "deinterlace-mode", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
665
666     var_Create (mp, "vbi-page", VLC_VAR_INTEGER);
667     var_SetInteger (mp, "vbi-page", 100);
668
669     var_Create (mp, "video-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
670     var_Create (mp, "sub-source", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
671     var_Create (mp, "sub-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
672
673     var_Create (mp, "marq-marquee", VLC_VAR_STRING);
674     var_Create (mp, "marq-color", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
675     var_Create (mp, "marq-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
676     var_Create (mp, "marq-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
677     var_Create (mp, "marq-refresh", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
678     var_Create (mp, "marq-size", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
679     var_Create (mp, "marq-timeout", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
680     var_Create (mp, "marq-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
681     var_Create (mp, "marq-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
682
683     var_Create (mp, "logo-file", VLC_VAR_STRING);
684     var_Create (mp, "logo-x", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
685     var_Create (mp, "logo-y", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
686     var_Create (mp, "logo-delay", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
687     var_Create (mp, "logo-repeat", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
688     var_Create (mp, "logo-opacity", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
689     var_Create (mp, "logo-position", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
690
691     var_Create (mp, "contrast", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
692     var_Create (mp, "brightness", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
693     var_Create (mp, "hue", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
694     var_Create (mp, "saturation", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
695     var_Create (mp, "gamma", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT);
696
697      /* Audio */
698     var_Create (mp, "aout", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
699     var_Create (mp, "audio-device", VLC_VAR_STRING);
700     var_Create (mp, "mute", VLC_VAR_BOOL);
701     var_Create (mp, "volume", VLC_VAR_FLOAT);
702     var_Create (mp, "corks", VLC_VAR_INTEGER);
703     var_Create (mp, "audio-filter", VLC_VAR_STRING);
704     var_Create (mp, "role", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
705     var_Create (mp, "amem-data", VLC_VAR_ADDRESS);
706     var_Create (mp, "amem-setup", VLC_VAR_ADDRESS);
707     var_Create (mp, "amem-cleanup", VLC_VAR_ADDRESS);
708     var_Create (mp, "amem-play", VLC_VAR_ADDRESS);
709     var_Create (mp, "amem-pause", VLC_VAR_ADDRESS);
710     var_Create (mp, "amem-resume", VLC_VAR_ADDRESS);
711     var_Create (mp, "amem-flush", VLC_VAR_ADDRESS);
712     var_Create (mp, "amem-drain", VLC_VAR_ADDRESS);
713     var_Create (mp, "amem-set-volume", VLC_VAR_ADDRESS);
714     var_Create (mp, "amem-format", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
715     var_Create (mp, "amem-rate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
716     var_Create (mp, "amem-channels", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
717
718     /* Video Title */
719     var_Create (mp, "video-title-show", VLC_VAR_BOOL);
720     var_Create (mp, "video-title-position", VLC_VAR_INTEGER);
721     var_Create (mp, "video-title-timeout", VLC_VAR_INTEGER);
722
723     /* Equalizer */
724     var_Create (mp, "equalizer-preamp", VLC_VAR_FLOAT);
725     var_Create (mp, "equalizer-vlcfreqs", VLC_VAR_BOOL);
726     var_Create (mp, "equalizer-bands", VLC_VAR_STRING);
727
728     /* Initialize the shared HTTP cookie jar */
729     vlc_value_t cookies;
730     cookies.p_address = vlc_http_cookies_new();
731     if ( likely(cookies.p_address) )
732     {
733         var_Create(mp, "http-cookies", VLC_VAR_ADDRESS);
734         var_SetChecked(mp, "http-cookies", VLC_VAR_ADDRESS, cookies);
735     }
736
737     mp->p_md = NULL;
738     mp->state = libvlc_NothingSpecial;
739     mp->p_libvlc_instance = instance;
740     mp->input.p_thread = NULL;
741     mp->input.p_renderer = NULL;
742     mp->input.p_resource = input_resource_New(VLC_OBJECT(mp));
743     if (unlikely(mp->input.p_resource == NULL))
744     {
745         vlc_object_release(mp);
746         return NULL;
747     }
748     audio_output_t *aout = input_resource_GetAout(mp->input.p_resource);
749     if( aout != NULL )
750         input_resource_PutAout(mp->input.p_resource, aout);
751
752     vlc_viewpoint_init(&mp->viewpoint);
753
754     var_Create (mp, "viewpoint", VLC_VAR_ADDRESS);
755     var_SetAddress( mp, "viewpoint", &mp->viewpoint );
756     vlc_mutex_init (&mp->input.lock);
757     mp->i_refcount = 1;
758     libvlc_event_manager_init(&mp->event_manager, mp);
759     vlc_mutex_init(&mp->object_lock);
760
761     var_AddCallback(mp, "corks", corks_changed, NULL);
762     var_AddCallback(mp, "audio-device", audio_device_changed, NULL);
763     var_AddCallback(mp, "mute", mute_changed, NULL);
764     var_AddCallback(mp, "volume", volume_changed, NULL);
765
766     /* Snapshot initialization */
767     /* Attach a var callback to the global object to provide the glue between
768      * vout_thread that generates the event and media_player that re-emits it
769      * with its own event manager
770      *
771      * FIXME: It's unclear why we want to put this in public API, and why we
772      * want to expose it in such a limiting and ugly way.
773      */
774     var_AddCallback(mp->obj.libvlc, "snapshot-file", snapshot_was_taken, mp);
775
776     libvlc_retain(instance);
777     return mp;
778 }
779
780 /**************************************************************************
781  * Create a Media Instance object with a media descriptor.
782  **************************************************************************/
783 libvlc_media_player_t *
784 libvlc_media_player_new_from_media( libvlc_media_t * p_md )
785 {
786     libvlc_media_player_t * p_mi;
787
788     p_mi = libvlc_media_player_new( p_md->p_libvlc_instance );
789     if( !p_mi )
790         return NULL;
791
792     libvlc_media_retain( p_md );
793     p_mi->p_md = p_md;
794
795     return p_mi;
796 }
797
798 /**************************************************************************
799  * Destroy a Media Instance object (libvlc internal)
800  *
801  * Warning: No lock held here, but hey, this is internal. Caller must lock.
802  **************************************************************************/
803 static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
804 {
805     assert( p_mi );
806
807     /* Detach Callback from the main libvlc object */
808     var_DelCallback( p_mi->obj.libvlc,
809                      "snapshot-file", snapshot_was_taken, p_mi );
810
811     /* Detach callback from the media player / input manager object */
812     var_DelCallback( p_mi, "volume", volume_changed, NULL );
813     var_DelCallback( p_mi, "mute", mute_changed, NULL );
814     var_DelCallback( p_mi, "audio-device", audio_device_changed, NULL );
815     var_DelCallback( p_mi, "corks", corks_changed, NULL );
816
817     /* No need for lock_input() because no other threads knows us anymore */
818     if( p_mi->input.p_thread )
819         release_input_thread(p_mi);
820     input_resource_Terminate( p_mi->input.p_resource );
821     input_resource_Release( p_mi->input.p_resource );
822     if( p_mi->input.p_renderer )
823         vlc_renderer_item_release( p_mi->input.p_renderer );
824
825     vlc_mutex_destroy( &p_mi->input.lock );
826
827     libvlc_event_manager_destroy(&p_mi->event_manager);
828     libvlc_media_release( p_mi->p_md );
829     vlc_mutex_destroy( &p_mi->object_lock );
830
831     vlc_http_cookie_jar_t *cookies = var_GetAddress( p_mi, "http-cookies" );
832     if ( cookies )
833     {
834         var_Destroy( p_mi, "http-cookies" );
835         vlc_http_cookies_destroy( cookies );
836     }
837
838     libvlc_instance_t *instance = p_mi->p_libvlc_instance;
839     vlc_object_release( p_mi );
840     libvlc_release(instance);
841 }
842
843 /**************************************************************************
844  * Release a Media Instance object.
845  *
846  * Function does the locking.
847  **************************************************************************/
848 void libvlc_media_player_release( libvlc_media_player_t *p_mi )
849 {
850     bool destroy;
851
852     assert( p_mi );
853     lock(p_mi);
854     destroy = !--p_mi->i_refcount;
855     unlock(p_mi);
856
857     if( destroy )
858         libvlc_media_player_destroy( p_mi );
859 }
860
861 /**************************************************************************
862  * Retain a Media Instance object.
863  *
864  * Caller must hold the lock.
865  **************************************************************************/
866 void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
867 {
868     assert( p_mi );
869
870     lock(p_mi);
871     p_mi->i_refcount++;
872     unlock(p_mi);
873 }
874
875 /**************************************************************************
876  * Set the Media descriptor associated with the instance.
877  *
878  * Enter without lock -- function will lock the object.
879  **************************************************************************/
880 void libvlc_media_player_set_media(
881                             libvlc_media_player_t *p_mi,
882                             libvlc_media_t *p_md )
883 {
884     lock_input(p_mi);
885
886     release_input_thread( p_mi );
887
888     lock( p_mi );
889     set_state( p_mi, libvlc_NothingSpecial, true );
890     unlock_input( p_mi );
891
892     libvlc_media_release( p_mi->p_md );
893
894     if( !p_md )
895     {
896         p_mi->p_md = NULL;
897         unlock(p_mi);
898         return; /* It is ok to pass a NULL md */
899     }
900
901     libvlc_media_retain( p_md );
902     p_mi->p_md = p_md;
903
904     /* The policy here is to ignore that we were created using a different
905      * libvlc_instance, because we don't really care */
906     p_mi->p_libvlc_instance = p_md->p_libvlc_instance;
907
908     unlock(p_mi);
909
910     /* Send an event for the newly available media */
911     libvlc_event_t event;
912     event.type = libvlc_MediaPlayerMediaChanged;
913     event.u.media_player_media_changed.new_media = p_md;
914     libvlc_event_send( &p_mi->event_manager, &event );
915
916 }
917
918 /**************************************************************************
919  * Get the Media descriptor associated with the instance.
920  **************************************************************************/
921 libvlc_media_t *
922 libvlc_media_player_get_media( libvlc_media_player_t *p_mi )
923 {
924     libvlc_media_t *p_m;
925
926     lock( p_mi );
927     p_m = p_mi->p_md;
928     if( p_m )
929         libvlc_media_retain( p_m );
930     unlock( p_mi );
931
932     return p_m;
933 }
934
935 /**************************************************************************
936  * Get the event Manager.
937  **************************************************************************/
938 libvlc_event_manager_t *
939 libvlc_media_player_event_manager( libvlc_media_player_t *p_mi )
940 {
941     return &p_mi->event_manager;
942 }
943
944 static void add_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi )
945 {
946     var_AddListCallback( p_input_thread, "video-es", input_es_changed, p_mi );
947     var_AddListCallback( p_input_thread, "audio-es", input_es_changed, p_mi );
948     var_AddListCallback( p_input_thread, "spu-es", input_es_changed, p_mi );
949 }
950
951 static void del_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi )
952 {
953     var_DelListCallback( p_input_thread, "video-es", input_es_changed, p_mi );
954     var_DelListCallback( p_input_thread, "audio-es", input_es_changed, p_mi );
955     var_DelListCallback( p_input_thread, "spu-es", input_es_changed, p_mi );
956 }
957
958 /**************************************************************************
959  * Tell media player to start playing.
960  **************************************************************************/
961 int libvlc_media_player_play( libvlc_media_player_t *p_mi )
962 {
963     lock_input( p_mi );
964
965     input_thread_t *p_input_thread = p_mi->input.p_thread;
966     if( p_input_thread )
967     {
968         /* A thread already exists, send it a play message */
969         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
970         unlock_input( p_mi );
971         return 0;
972     }
973
974     /* Ignore previous exception */
975     lock(p_mi);
976
977     if( !p_mi->p_md )
978     {
979         unlock(p_mi);
980         unlock_input( p_mi );
981         libvlc_printerr( "No associated media descriptor" );
982         return -1;
983     }
984
985     for( size_t i = 0; i < ARRAY_SIZE( p_mi->selected_es ); ++i )
986         p_mi->selected_es[i] = ES_INIT;
987
988     media_attach_preparsed_event( p_mi->p_md );
989
990     p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL,
991                                    p_mi->input.p_resource,
992                                    p_mi->input.p_renderer );
993     unlock(p_mi);
994     if( !p_input_thread )
995     {
996         unlock_input(p_mi);
997         media_detach_preparsed_event( p_mi->p_md );
998         libvlc_printerr( "Not enough memory" );
999         return -1;
1000     }
1001
1002     var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
1003     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
1004     var_AddCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
1005     var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
1006     add_es_callbacks( p_input_thread, p_mi );
1007
1008     if( input_Start( p_input_thread ) )
1009     {
1010         unlock_input(p_mi);
1011         del_es_callbacks( p_input_thread, p_mi );
1012         var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
1013         var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
1014         var_DelCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
1015         var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
1016         input_Close( p_input_thread );
1017         media_detach_preparsed_event( p_mi->p_md );
1018         libvlc_printerr( "Input initialization failure" );
1019         return -1;
1020     }
1021     p_mi->input.p_thread = p_input_thread;
1022     unlock_input(p_mi);
1023     return 0;
1024 }
1025
1026 void libvlc_media_player_set_pause( libvlc_media_player_t *p_mi, int paused )
1027 {
1028     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi );
1029     if( !p_input_thread )
1030         return;
1031
1032     if( paused )
1033     {
1034         if( libvlc_media_player_can_pause( p_mi ) )
1035             input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
1036         else
1037             input_Stop( p_input_thread );
1038     }
1039     else
1040     {
1041         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
1042     }
1043
1044     vlc_object_release( p_input_thread );
1045 }
1046
1047 /**************************************************************************
1048  * Toggle pause.
1049  **************************************************************************/
1050 void libvlc_media_player_pause( libvlc_media_player_t *p_mi )
1051 {
1052     libvlc_media_player_set_pause( p_mi, libvlc_media_player_is_playing( p_mi ) );
1053 }
1054
1055 /**************************************************************************
1056  * Tells whether the media player is currently playing.
1057  **************************************************************************/
1058 int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi )
1059 {
1060     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
1061     return libvlc_Playing == state;
1062 }
1063
1064 /**************************************************************************
1065  * Stop playing.
1066  **************************************************************************/
1067 void libvlc_media_player_stop( libvlc_media_player_t *p_mi )
1068 {
1069     lock_input(p_mi);
1070     release_input_thread( p_mi ); /* This will stop the input thread */
1071
1072     /* Force to go to stopped state, in case we were in Ended, or Error
1073      * state. */
1074     if( p_mi->state != libvlc_Stopped )
1075     {
1076         set_state( p_mi, libvlc_Stopped, false );
1077
1078         /* Construct and send the event */
1079         libvlc_event_t event;
1080         event.type = libvlc_MediaPlayerStopped;
1081         libvlc_event_send( &p_mi->event_manager, &event );
1082     }
1083
1084     input_resource_Terminate( p_mi->input.p_resource );
1085     unlock_input(p_mi);
1086 }
1087
1088 int libvlc_media_player_set_renderer( libvlc_media_player_t *p_mi,
1089                                       libvlc_renderer_item_t *p_litem )
1090 {
1091     vlc_renderer_item_t *p_item =
1092         p_litem ? libvlc_renderer_item_to_vlc( p_litem ) : NULL;
1093
1094     lock_input( p_mi );
1095     input_thread_t *p_input_thread = p_mi->input.p_thread;
1096     if( p_input_thread )
1097         input_Control( p_input_thread, INPUT_SET_RENDERER, p_item );
1098
1099     if( p_mi->input.p_renderer )
1100         vlc_renderer_item_release( p_mi->input.p_renderer );
1101     p_mi->input.p_renderer = p_item ? vlc_renderer_item_hold( p_item ) : NULL;
1102     unlock_input( p_mi );
1103
1104     return 0;
1105 }
1106
1107 void libvlc_video_set_callbacks( libvlc_media_player_t *mp,
1108     void *(*lock_cb) (void *, void **),
1109     void (*unlock_cb) (void *, void *, void *const *),
1110     void (*display_cb) (void *, void *),
1111     void *opaque )
1112 {
1113     var_SetAddress( mp, "vmem-lock", lock_cb );
1114     var_SetAddress( mp, "vmem-unlock", unlock_cb );
1115     var_SetAddress( mp, "vmem-display", display_cb );
1116     var_SetAddress( mp, "vmem-data", opaque );
1117     var_SetString( mp, "avcodec-hw", "none" );
1118     var_SetString( mp, "vout", "vmem" );
1119     var_SetString( mp, "window", "none" );
1120 }
1121
1122 void libvlc_video_set_format_callbacks( libvlc_media_player_t *mp,
1123                                         libvlc_video_format_cb setup,
1124                                         libvlc_video_cleanup_cb cleanup )
1125 {
1126     var_SetAddress( mp, "vmem-setup", setup );
1127     var_SetAddress( mp, "vmem-cleanup", cleanup );
1128 }
1129
1130 void libvlc_video_set_format( libvlc_media_player_t *mp, const char *chroma,
1131                               unsigned width, unsigned height, unsigned pitch )
1132 {
1133     var_SetString( mp, "vmem-chroma", chroma );
1134     var_SetInteger( mp, "vmem-width", width );
1135     var_SetInteger( mp, "vmem-height", height );
1136     var_SetInteger( mp, "vmem-pitch", pitch );
1137 }
1138
1139 /**************************************************************************
1140  * set_nsobject
1141  **************************************************************************/
1142 void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
1143                                         void * drawable )
1144 {
1145     assert (p_mi != NULL);
1146 #ifdef __APPLE__
1147     var_SetString (p_mi, "avcodec-hw", "");
1148     var_SetString (p_mi, "vout", "");
1149     var_SetString (p_mi, "window", "");
1150     var_SetAddress (p_mi, "drawable-nsobject", drawable);
1151 #else
1152     (void)drawable;
1153     libvlc_printerr ("can't set nsobject: APPLE build required");
1154     assert(false);
1155     var_SetString (p_mi, "vout", "none");
1156     var_SetString (p_mi, "window", "none");
1157 #endif
1158 }
1159
1160 /**************************************************************************
1161  * get_nsobject
1162  **************************************************************************/
1163 void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi )
1164 {
1165     assert (p_mi != NULL);
1166 #ifdef __APPLE__
1167     return var_GetAddress (p_mi, "drawable-nsobject");
1168 #else
1169     (void) p_mi;
1170     return NULL;
1171 #endif
1172 }
1173
1174 /**************************************************************************
1175  * set_agl
1176  **************************************************************************/
1177 void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
1178                                   uint32_t drawable )
1179 {
1180     (void)drawable;
1181     libvlc_printerr ("can't set agl: use libvlc_media_player_set_nsobject instead");
1182     assert(false);
1183     var_SetString (p_mi, "vout", "none");
1184     var_SetString (p_mi, "window", "none");
1185 }
1186
1187 /**************************************************************************
1188  * get_agl
1189  **************************************************************************/
1190 uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
1191 {
1192     (void) p_mi;
1193     return 0;
1194 }
1195
1196 /**************************************************************************
1197  * set_xwindow
1198  **************************************************************************/
1199 void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
1200                                       uint32_t drawable )
1201 {
1202     assert (p_mi != NULL);
1203
1204     var_SetString (p_mi, "avcodec-hw", "");
1205     var_SetString (p_mi, "vout", "");
1206     var_SetString (p_mi, "window", drawable ? "embed-xid,any" : "");
1207     var_SetInteger (p_mi, "drawable-xid", drawable);
1208 }
1209
1210 /**************************************************************************
1211  * get_xwindow
1212  **************************************************************************/
1213 uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
1214 {
1215     return var_GetInteger (p_mi, "drawable-xid");
1216 }
1217
1218 /**************************************************************************
1219  * set_hwnd
1220  **************************************************************************/
1221 void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
1222                                    void *drawable )
1223 {
1224     assert (p_mi != NULL);
1225 #if defined (_WIN32) || defined (__OS2__)
1226     var_SetString (p_mi, "avcodec-hw", "");
1227     var_SetString (p_mi, "vout", "");
1228     var_SetString (p_mi, "window",
1229                    (drawable != NULL) ? "embed-hwnd,any" : "");
1230     var_SetInteger (p_mi, "drawable-hwnd", (uintptr_t)drawable);
1231 #else
1232     (void) drawable;
1233     libvlc_printerr ("can't set nsobject: WIN32 build required");
1234     assert(false);
1235     var_SetString (p_mi, "vout", "none");
1236     var_SetString (p_mi, "window", "none");
1237 #endif
1238 }
1239
1240 /**************************************************************************
1241  * get_hwnd
1242  **************************************************************************/
1243 void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
1244 {
1245     assert (p_mi != NULL);
1246 #if defined (_WIN32) || defined (__OS2__)
1247     return (void *)(uintptr_t)var_GetInteger (p_mi, "drawable-hwnd");
1248 #else
1249     (void) p_mi;
1250     return NULL;
1251 #endif
1252 }
1253
1254 /**************************************************************************
1255  * set_android_context
1256  **************************************************************************/
1257 void libvlc_media_player_set_android_context( libvlc_media_player_t *p_mi,
1258                                               void *p_awindow_handler )
1259 {
1260     assert (p_mi != NULL);
1261 #ifdef __ANDROID__
1262     var_SetAddress (p_mi, "drawable-androidwindow", p_awindow_handler);
1263 #else
1264     (void) p_awindow_handler;
1265     libvlc_printerr ("can't set android context: ANDROID build required");
1266     assert(false);
1267     var_SetString (p_mi, "vout", "none");
1268     var_SetString (p_mi, "window", "none");
1269 #endif
1270 }
1271
1272 /**************************************************************************
1273  * set_evas_object
1274  **************************************************************************/
1275 int libvlc_media_player_set_evas_object( libvlc_media_player_t *p_mi,
1276                                          void *p_evas_object )
1277 {
1278     assert (p_mi != NULL);
1279 #ifdef HAVE_EVAS
1280     var_SetString (p_mi, "vout", "evas");
1281     var_SetString (p_mi, "window", "none");
1282     var_SetAddress (p_mi, "drawable-evasobject", p_evas_object);
1283     return 0;
1284 #else
1285     (void) p_mi; (void) p_evas_object;
1286     return -1;
1287 #endif
1288 }
1289
1290 void libvlc_audio_set_callbacks( libvlc_media_player_t *mp,
1291                                  libvlc_audio_play_cb play_cb,
1292                                  libvlc_audio_pause_cb pause_cb,
1293                                  libvlc_audio_resume_cb resume_cb,
1294                                  libvlc_audio_flush_cb flush_cb,
1295                                  libvlc_audio_drain_cb drain_cb,
1296                                  void *opaque )
1297 {
1298     var_SetAddress( mp, "amem-play", play_cb );
1299     var_SetAddress( mp, "amem-pause", pause_cb );
1300     var_SetAddress( mp, "amem-resume", resume_cb );
1301     var_SetAddress( mp, "amem-flush", flush_cb );
1302     var_SetAddress( mp, "amem-drain", drain_cb );
1303     var_SetAddress( mp, "amem-data", opaque );
1304     var_SetString( mp, "aout", "amem,none" );
1305
1306     input_resource_ResetAout(mp->input.p_resource);
1307 }
1308
1309 void libvlc_audio_set_volume_callback( libvlc_media_player_t *mp,
1310                                        libvlc_audio_set_volume_cb cb )
1311 {
1312     var_SetAddress( mp, "amem-set-volume", cb );
1313
1314     input_resource_ResetAout(mp->input.p_resource);
1315 }
1316
1317 void libvlc_audio_set_format_callbacks( libvlc_media_player_t *mp,
1318                                         libvlc_audio_setup_cb setup,
1319                                         libvlc_audio_cleanup_cb cleanup )
1320 {
1321     var_SetAddress( mp, "amem-setup", setup );
1322     var_SetAddress( mp, "amem-cleanup", cleanup );
1323
1324     input_resource_ResetAout(mp->input.p_resource);
1325 }
1326
1327 void libvlc_audio_set_format( libvlc_media_player_t *mp, const char *format,
1328                               unsigned rate, unsigned channels )
1329 {
1330     var_SetString( mp, "amem-format", format );
1331     var_SetInteger( mp, "amem-rate", rate );
1332     var_SetInteger( mp, "amem-channels", channels );
1333
1334     input_resource_ResetAout(mp->input.p_resource);
1335 }
1336
1337
1338 /**************************************************************************
1339  * Getters for stream information
1340  **************************************************************************/
1341 libvlc_time_t libvlc_media_player_get_length(
1342                              libvlc_media_player_t *p_mi )
1343 {
1344     input_thread_t *p_input_thread;
1345     libvlc_time_t i_time;
1346
1347     p_input_thread = libvlc_get_input_thread ( p_mi );
1348     if( !p_input_thread )
1349         return -1;
1350
1351     i_time = from_mtime(var_GetInteger( p_input_thread, "length" ));
1352     vlc_object_release( p_input_thread );
1353
1354     return i_time;
1355 }
1356
1357 libvlc_time_t libvlc_media_player_get_time( libvlc_media_player_t *p_mi )
1358 {
1359     input_thread_t *p_input_thread;
1360     libvlc_time_t i_time;
1361
1362     p_input_thread = libvlc_get_input_thread ( p_mi );
1363     if( !p_input_thread )
1364         return -1;
1365
1366     i_time = from_mtime(var_GetInteger( p_input_thread , "time" ));
1367     vlc_object_release( p_input_thread );
1368     return i_time;
1369 }
1370
1371 void libvlc_media_player_set_time( libvlc_media_player_t *p_mi,
1372                                    libvlc_time_t i_time )
1373 {
1374     input_thread_t *p_input_thread;
1375
1376     p_input_thread = libvlc_get_input_thread ( p_mi );
1377     if( !p_input_thread )
1378         return;
1379
1380     var_SetInteger( p_input_thread, "time", to_mtime(i_time) );
1381     vlc_object_release( p_input_thread );
1382 }
1383
1384 void libvlc_media_player_set_position( libvlc_media_player_t *p_mi,
1385                                        float position )
1386 {
1387     input_thread_t *p_input_thread;
1388
1389     p_input_thread = libvlc_get_input_thread ( p_mi );
1390     if( !p_input_thread )
1391         return;
1392
1393     var_SetFloat( p_input_thread, "position", position );
1394     vlc_object_release( p_input_thread );
1395 }
1396
1397 float libvlc_media_player_get_position( libvlc_media_player_t *p_mi )
1398 {
1399     input_thread_t *p_input_thread;
1400     float f_position;
1401
1402     p_input_thread = libvlc_get_input_thread ( p_mi );
1403     if( !p_input_thread )
1404         return -1.0;
1405
1406     f_position = var_GetFloat( p_input_thread, "position" );
1407     vlc_object_release( p_input_thread );
1408
1409     return f_position;
1410 }
1411
1412 void libvlc_media_player_set_chapter( libvlc_media_player_t *p_mi,
1413                                       int chapter )
1414 {
1415     input_thread_t *p_input_thread;
1416
1417     p_input_thread = libvlc_get_input_thread ( p_mi );
1418     if( !p_input_thread )
1419         return;
1420
1421     var_SetInteger( p_input_thread, "chapter", chapter );
1422     vlc_object_release( p_input_thread );
1423 }
1424
1425 int libvlc_media_player_get_chapter( libvlc_media_player_t *p_mi )
1426 {
1427     input_thread_t *p_input_thread;
1428     int i_chapter;
1429
1430     p_input_thread = libvlc_get_input_thread ( p_mi );
1431     if( !p_input_thread )
1432         return -1;
1433
1434     i_chapter = var_GetInteger( p_input_thread, "chapter" );
1435     vlc_object_release( p_input_thread );
1436
1437     return i_chapter;
1438 }
1439
1440 int libvlc_media_player_get_chapter_count( libvlc_media_player_t *p_mi )
1441 {
1442     input_thread_t *p_input_thread;
1443     vlc_value_t val;
1444
1445     p_input_thread = libvlc_get_input_thread ( p_mi );
1446     if( !p_input_thread )
1447         return -1;
1448
1449     int i_ret = var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
1450     vlc_object_release( p_input_thread );
1451
1452     return i_ret == VLC_SUCCESS ? val.i_int : -1;
1453 }
1454
1455 int libvlc_media_player_get_chapter_count_for_title(
1456                                  libvlc_media_player_t *p_mi,
1457                                  int i_title )
1458 {
1459     vlc_value_t val;
1460
1461     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1462     if( !p_input_thread )
1463         return -1;
1464
1465     char psz_name[sizeof ("title ") + 3 * sizeof (int)];
1466     sprintf( psz_name, "title %2u", i_title );
1467
1468     int i_ret = var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
1469     vlc_object_release( p_input_thread );
1470
1471     return i_ret == VLC_SUCCESS ? val.i_int : -1;
1472 }
1473
1474 void libvlc_media_player_set_title( libvlc_media_player_t *p_mi,
1475                                     int i_title )
1476 {
1477     input_thread_t *p_input_thread;
1478
1479     p_input_thread = libvlc_get_input_thread ( p_mi );
1480     if( !p_input_thread )
1481         return;
1482
1483     var_SetInteger( p_input_thread, "title", i_title );
1484     vlc_object_release( p_input_thread );
1485
1486     //send event
1487     libvlc_event_t event;
1488     event.type = libvlc_MediaPlayerTitleChanged;
1489     event.u.media_player_title_changed.new_title = i_title;
1490     libvlc_event_send( &p_mi->event_manager, &event );
1491 }
1492
1493 int libvlc_media_player_get_title( libvlc_media_player_t *p_mi )
1494 {
1495     input_thread_t *p_input_thread;
1496     int i_title;
1497
1498     p_input_thread = libvlc_get_input_thread ( p_mi );
1499     if( !p_input_thread )
1500         return -1;
1501
1502     i_title = var_GetInteger( p_input_thread, "title" );
1503     vlc_object_release( p_input_thread );
1504
1505     return i_title;
1506 }
1507
1508 int libvlc_media_player_get_title_count( libvlc_media_player_t *p_mi )
1509 {
1510     input_thread_t *p_input_thread;
1511     vlc_value_t val;
1512
1513     p_input_thread = libvlc_get_input_thread ( p_mi );
1514     if( !p_input_thread )
1515         return -1;
1516
1517     int i_ret = var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
1518     vlc_object_release( p_input_thread );
1519
1520     return i_ret == VLC_SUCCESS ? val.i_int : -1;
1521 }
1522
1523 int libvlc_media_player_get_full_title_descriptions( libvlc_media_player_t *p_mi,
1524                                                      libvlc_title_description_t *** pp_titles )
1525 {
1526     assert( p_mi );
1527
1528     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
1529
1530     if( !p_input_thread )
1531         return -1;
1532
1533     input_title_t **p_input_title;
1534     int count;
1535
1536     /* fetch data */
1537     int ret = input_Control( p_input_thread, INPUT_GET_FULL_TITLE_INFO,
1538                              &p_input_title, &count );
1539     vlc_object_release( p_input_thread );
1540     if( ret != VLC_SUCCESS )
1541         return -1;
1542
1543     libvlc_title_description_t **titles = vlc_alloc( count, sizeof (*titles) );
1544     if( count > 0 && unlikely(titles == NULL) )
1545         return -1;
1546
1547     /* fill array */
1548     for( int i = 0; i < count; i++)
1549     {
1550         libvlc_title_description_t *title = malloc( sizeof (*title) );
1551         if( unlikely(title == NULL) )
1552         {
1553             libvlc_title_descriptions_release( titles, i );
1554             return -1;
1555         }
1556         titles[i] = title;
1557
1558         /* we want to return milliseconds to match the rest of the API */
1559         title->i_duration = p_input_title[i]->i_length / 1000;
1560         title->i_flags = p_input_title[i]->i_flags;
1561         if( p_input_title[i]->psz_name )
1562             title->psz_name = strdup( p_input_title[i]->psz_name );
1563         else
1564             title->psz_name = NULL;
1565         vlc_input_title_Delete( p_input_title[i] );
1566     }
1567     free( p_input_title );
1568
1569     *pp_titles = titles;
1570     return count;
1571 }
1572
1573 void libvlc_title_descriptions_release( libvlc_title_description_t **p_titles,
1574                                         unsigned i_count )
1575 {
1576     for (unsigned i = 0; i < i_count; i++ )
1577     {
1578         if ( !p_titles[i] )
1579             continue;
1580
1581         free( p_titles[i]->psz_name );
1582         free( p_titles[i] );
1583     }
1584     free( p_titles );
1585 }
1586
1587 int libvlc_media_player_get_full_chapter_descriptions( libvlc_media_player_t *p_mi,
1588                                                       int i_chapters_of_title,
1589                                                       libvlc_chapter_description_t *** pp_chapters )
1590 {
1591     assert( p_mi );
1592
1593     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
1594
1595     if( !p_input_thread )
1596         return -1;
1597
1598     seekpoint_t **p_seekpoint = NULL;
1599
1600     /* fetch data */
1601     int ci_chapter_count = i_chapters_of_title;
1602
1603     int ret = input_Control(p_input_thread, INPUT_GET_SEEKPOINTS, &p_seekpoint, &ci_chapter_count);
1604     if( ret != VLC_SUCCESS)
1605     {
1606         vlc_object_release( p_input_thread );
1607         return -1;
1608     }
1609
1610     if (ci_chapter_count == 0 || p_seekpoint == NULL)
1611     {
1612         vlc_object_release( p_input_thread );
1613         return 0;
1614     }
1615
1616     input_title_t *p_title;
1617     ret = input_Control( p_input_thread, INPUT_GET_TITLE_INFO, &p_title,
1618                          &i_chapters_of_title );
1619     vlc_object_release( p_input_thread );
1620     if( ret != VLC_SUCCESS )
1621     {
1622         goto error;
1623     }
1624     int64_t i_title_duration = p_title->i_length / 1000;
1625     vlc_input_title_Delete( p_title );
1626
1627     *pp_chapters = calloc( ci_chapter_count, sizeof(**pp_chapters) );
1628     if( !*pp_chapters )
1629     {
1630         goto error;
1631     }
1632
1633     /* fill array */
1634     for( int i = 0; i < ci_chapter_count; ++i )
1635     {
1636         libvlc_chapter_description_t *p_chapter = malloc( sizeof(*p_chapter) );
1637         if( unlikely(p_chapter == NULL) )
1638         {
1639             goto error;
1640         }
1641         (*pp_chapters)[i] = p_chapter;
1642
1643         p_chapter->i_time_offset = p_seekpoint[i]->i_time_offset / 1000;
1644
1645         if( i < ci_chapter_count - 1 )
1646         {
1647             p_chapter->i_duration = p_seekpoint[i + 1]->i_time_offset / 1000 -
1648                                     p_chapter->i_time_offset;
1649         }
1650         else
1651         {
1652             if ( i_title_duration )
1653                 p_chapter->i_duration = i_title_duration - p_chapter->i_time_offset;
1654             else
1655                 p_chapter->i_duration = 0;
1656         }
1657
1658         if( p_seekpoint[i]->psz_name )
1659         {
1660             p_chapter->psz_name = strdup( p_seekpoint[i]->psz_name );
1661         }
1662         else
1663         {
1664             p_chapter->psz_name = NULL;
1665         }
1666         vlc_seekpoint_Delete( p_seekpoint[i] );
1667         p_seekpoint[i] = NULL;
1668     }
1669
1670     free( p_seekpoint );
1671     return ci_chapter_count;
1672
1673 error:
1674     if( *pp_chapters )
1675         libvlc_chapter_descriptions_release( *pp_chapters, ci_chapter_count );
1676     for ( int i = 0; i < ci_chapter_count; ++i )
1677         vlc_seekpoint_Delete( p_seekpoint[i] );
1678     free( p_seekpoint );
1679     return -1;
1680 }
1681
1682 void libvlc_chapter_descriptions_release( libvlc_chapter_description_t **p_chapters,
1683                                           unsigned i_count )
1684 {
1685     for (unsigned i = 0; i < i_count; i++ )
1686     {
1687         if ( !p_chapters[i] )
1688             continue;
1689
1690         free( p_chapters[i]->psz_name );
1691         free( p_chapters[i] );
1692     }
1693     free( p_chapters );
1694 }
1695
1696 void libvlc_media_player_next_chapter( libvlc_media_player_t *p_mi )
1697 {
1698     input_thread_t *p_input_thread;
1699
1700     p_input_thread = libvlc_get_input_thread ( p_mi );
1701     if( !p_input_thread )
1702         return;
1703
1704     int i_type = var_Type( p_input_thread, "next-chapter" );
1705     var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1706                             "next-chapter":"next-title" );
1707
1708     vlc_object_release( p_input_thread );
1709 }
1710
1711 void libvlc_media_player_previous_chapter( libvlc_media_player_t *p_mi )
1712 {
1713     input_thread_t *p_input_thread;
1714
1715     p_input_thread = libvlc_get_input_thread ( p_mi );
1716     if( !p_input_thread )
1717         return;
1718
1719     int i_type = var_Type( p_input_thread, "next-chapter" );
1720     var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1721                             "prev-chapter":"prev-title" );
1722
1723     vlc_object_release( p_input_thread );
1724 }
1725
1726 float libvlc_media_player_get_fps( libvlc_media_player_t *p_mi )
1727 {
1728     libvlc_media_t *media = libvlc_media_player_get_media( p_mi );
1729     if( media == NULL )
1730         return 0.f;
1731
1732     input_item_t *item = media->p_input_item;
1733     float fps = 0.f;
1734
1735     vlc_mutex_lock( &item->lock );
1736     for( int i = 0; i < item->i_es; i++ )
1737     {
1738         const es_format_t *fmt = item->es[i];
1739
1740         if( fmt->i_cat == VIDEO_ES && fmt->video.i_frame_rate_base > 0 )
1741             fps = (float)fmt->video.i_frame_rate
1742                   / (float)fmt->video.i_frame_rate_base;
1743     }
1744     vlc_mutex_unlock( &item->lock );
1745     libvlc_media_release( media );
1746
1747     return fps;
1748 }
1749
1750 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi )
1751 {
1752     input_thread_t *p_input_thread =
1753                             libvlc_get_input_thread ( p_mi );
1754     if ( !p_input_thread )
1755         return false;
1756
1757     int state = var_GetInteger( p_input_thread, "state" );
1758     vlc_object_release( p_input_thread );
1759
1760     return state != END_S && state != ERROR_S;
1761 }
1762
1763 int libvlc_media_player_set_rate( libvlc_media_player_t *p_mi, float rate )
1764 {
1765     var_SetFloat (p_mi, "rate", rate);
1766
1767     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1768     if( !p_input_thread )
1769         return 0;
1770     var_SetFloat( p_input_thread, "rate", rate );
1771     vlc_object_release( p_input_thread );
1772     return 0;
1773 }
1774
1775 float libvlc_media_player_get_rate( libvlc_media_player_t *p_mi )
1776 {
1777     return var_GetFloat (p_mi, "rate");
1778 }
1779
1780 libvlc_state_t libvlc_media_player_get_state( libvlc_media_player_t *p_mi )
1781 {
1782     lock(p_mi);
1783     libvlc_state_t state = p_mi->state;
1784     unlock(p_mi);
1785     return state;
1786 }
1787
1788 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi )
1789 {
1790     input_thread_t *p_input_thread;
1791     bool b_seekable;
1792
1793     p_input_thread = libvlc_get_input_thread ( p_mi );
1794     if ( !p_input_thread )
1795         return false;
1796     b_seekable = var_GetBool( p_input_thread, "can-seek" );
1797     vlc_object_release( p_input_thread );
1798
1799     return b_seekable;
1800 }
1801
1802 void libvlc_media_player_navigate( libvlc_media_player_t* p_mi,
1803                                    unsigned navigate )
1804 {
1805     static const int map[] =
1806     {
1807         INPUT_NAV_ACTIVATE, INPUT_NAV_UP, INPUT_NAV_DOWN,
1808         INPUT_NAV_LEFT, INPUT_NAV_RIGHT, INPUT_NAV_POPUP,
1809     };
1810
1811     if( navigate >= sizeof(map) / sizeof(map[0]) )
1812       return;
1813
1814     input_thread_t *p_input = libvlc_get_input_thread ( p_mi );
1815     if ( p_input == NULL )
1816       return;
1817
1818     input_Control( p_input, map[navigate], NULL );
1819     vlc_object_release( p_input );
1820 }
1821
1822 /* internal function, used by audio, video */
1823 libvlc_track_description_t *
1824         libvlc_get_track_description( libvlc_media_player_t *p_mi,
1825                                       const char *psz_variable )
1826 {
1827     input_thread_t *p_input = libvlc_get_input_thread( p_mi );
1828     libvlc_track_description_t *p_track_description = NULL,
1829                                *p_actual, *p_previous;
1830
1831     if( !p_input )
1832         return NULL;
1833
1834     vlc_value_t val_list, text_list;
1835     int i_ret = var_Change( p_input, psz_variable, VLC_VAR_GETCHOICES, &val_list, &text_list );
1836     if( i_ret != VLC_SUCCESS )
1837         return NULL;
1838
1839     /* no tracks */
1840     if( val_list.p_list->i_count <= 0 )
1841         goto end;
1842
1843     p_track_description = malloc( sizeof *p_track_description );
1844     if ( !p_track_description )
1845     {
1846         libvlc_printerr( "Not enough memory" );
1847         goto end;
1848     }
1849     p_actual = p_track_description;
1850     p_previous = NULL;
1851     for( int i = 0; i < val_list.p_list->i_count; i++ )
1852     {
1853         if( !p_actual )
1854         {
1855             p_actual = malloc( sizeof *p_actual );
1856             if ( !p_actual )
1857             {
1858                 libvlc_track_description_list_release( p_track_description );
1859                 libvlc_printerr( "Not enough memory" );
1860
1861                 p_track_description = NULL;
1862                 goto end;
1863             }
1864         }
1865         p_actual->i_id = val_list.p_list->p_values[i].i_int;
1866         p_actual->psz_name = strdup( text_list.p_list->p_values[i].psz_string );
1867         p_actual->p_next = NULL;
1868         if( p_previous )
1869             p_previous->p_next = p_actual;
1870         p_previous = p_actual;
1871         p_actual =  NULL;
1872     }
1873
1874 end:
1875     var_FreeList( &val_list, &text_list );
1876     vlc_object_release( p_input );
1877
1878     return p_track_description;
1879 }
1880
1881 // Deprecated alias for libvlc_track_description_list_release
1882 void libvlc_track_description_release( libvlc_track_description_t *p_td )
1883 {
1884     libvlc_track_description_list_release( p_td );
1885 }
1886
1887 void libvlc_track_description_list_release( libvlc_track_description_t *p_td )
1888 {
1889     libvlc_track_description_t *p_actual, *p_before;
1890     p_actual = p_td;
1891
1892     while ( p_actual )
1893     {
1894         free( p_actual->psz_name );
1895         p_before = p_actual;
1896         p_actual = p_before->p_next;
1897         free( p_before );
1898     }
1899 }
1900
1901 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi )
1902 {
1903     input_thread_t *p_input_thread;
1904     bool b_can_pause;
1905
1906     p_input_thread = libvlc_get_input_thread ( p_mi );
1907     if ( !p_input_thread )
1908         return false;
1909     b_can_pause = var_GetBool( p_input_thread, "can-pause" );
1910     vlc_object_release( p_input_thread );
1911
1912     return b_can_pause;
1913 }
1914
1915 int libvlc_media_player_program_scrambled( libvlc_media_player_t *p_mi )
1916 {
1917     input_thread_t *p_input_thread;
1918     bool b_program_scrambled;
1919
1920     p_input_thread = libvlc_get_input_thread ( p_mi );
1921     if ( !p_input_thread )
1922         return false;
1923     b_program_scrambled = var_GetBool( p_input_thread, "program-scrambled" );
1924     vlc_object_release( p_input_thread );
1925
1926     return b_program_scrambled;
1927 }
1928
1929 void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )
1930 {
1931     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1932     if( p_input_thread != NULL )
1933     {
1934         var_TriggerCallback( p_input_thread, "frame-next" );
1935         vlc_object_release( p_input_thread );
1936     }
1937 }
1938
1939 /**
1940  * Private lookup table to get subpicture alignment flag values corresponding
1941  * to a libvlc_position_t enumerated value.
1942  */
1943 static const unsigned char position_subpicture_alignment[] = {
1944     [libvlc_position_center]       = 0,
1945     [libvlc_position_left]         = SUBPICTURE_ALIGN_LEFT,
1946     [libvlc_position_right]        = SUBPICTURE_ALIGN_RIGHT,
1947     [libvlc_position_top]          = SUBPICTURE_ALIGN_TOP,
1948     [libvlc_position_top_left]     = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT,
1949     [libvlc_position_top_right]    = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_RIGHT,
1950     [libvlc_position_bottom]       = SUBPICTURE_ALIGN_BOTTOM,
1951     [libvlc_position_bottom_left]  = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_LEFT,
1952     [libvlc_position_bottom_right] = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_RIGHT
1953 };
1954
1955 void libvlc_media_player_set_video_title_display( libvlc_media_player_t *p_mi, libvlc_position_t position, unsigned timeout )
1956 {
1957     assert( position >= libvlc_position_disable && position <= libvlc_position_bottom_right );
1958
1959     if ( position != libvlc_position_disable )
1960     {
1961         var_SetBool( p_mi, "video-title-show", true );
1962         var_SetInteger( p_mi, "video-title-position", position_subpicture_alignment[position] );
1963         var_SetInteger( p_mi, "video-title-timeout", timeout );
1964     }
1965     else
1966     {
1967         var_SetBool( p_mi, "video-title-show", false );
1968     }
1969 }
1970
1971 int libvlc_media_player_add_slave( libvlc_media_player_t *p_mi,
1972                                    libvlc_media_slave_type_t i_type,
1973                                    const char *psz_uri, bool b_select )
1974 {
1975     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1976
1977     if( p_input_thread == NULL )
1978     {
1979         libvlc_media_t *p_media = libvlc_media_player_get_media( p_mi );
1980         if( p_media == NULL )
1981             return -1;
1982
1983         int i_ret = libvlc_media_slaves_add( p_media, i_type, 4, psz_uri );
1984         libvlc_media_release( p_media );
1985         return i_ret;
1986     }
1987     else
1988     {
1989         int i_ret = input_AddSlave( p_input_thread, (enum slave_type) i_type,
1990                                     psz_uri, b_select, false, false );
1991         vlc_object_release( p_input_thread );
1992
1993         return i_ret == VLC_SUCCESS ? 0 : -1;
1994     }
1995 }
1996
1997 /**
1998  * Maximum size of a formatted equalizer amplification band frequency value.
1999  *
2000  * The allowed value range is supposed to be constrained from -20.0 to 20.0.
2001  *
2002  * The format string " %.07f" with a minimum value of "-20" gives a maximum
2003  * string length of e.g. " -19.1234567", i.e. 12 bytes (not including the null
2004  * terminator).
2005  */
2006 #define EQZ_BAND_VALUE_SIZE 12
2007
2008 int libvlc_media_player_set_equalizer( libvlc_media_player_t *p_mi, libvlc_equalizer_t *p_equalizer )
2009 {
2010     char bands[EQZ_BANDS_MAX * EQZ_BAND_VALUE_SIZE + 1];
2011
2012     if( p_equalizer != NULL )
2013     {
2014         for( unsigned i = 0, c = 0; i < EQZ_BANDS_MAX; i++ )
2015         {
2016             c += snprintf( bands + c, sizeof(bands) - c, " %.07f",
2017                           p_equalizer->f_amp[i] );
2018             if( unlikely(c >= sizeof(bands)) )
2019                 return -1;
2020         }
2021
2022         var_SetFloat( p_mi, "equalizer-preamp", p_equalizer->f_preamp );
2023         var_SetString( p_mi, "equalizer-bands", bands );
2024     }
2025     var_SetString( p_mi, "audio-filter", p_equalizer ? "equalizer" : "" );
2026
2027     audio_output_t *p_aout = input_resource_HoldAout( p_mi->input.p_resource );
2028     if( p_aout != NULL )
2029     {
2030         if( p_equalizer != NULL )
2031         {
2032             var_SetFloat( p_aout, "equalizer-preamp", p_equalizer->f_preamp );
2033             var_SetString( p_aout, "equalizer-bands", bands );
2034         }
2035
2036         var_SetString( p_aout, "audio-filter", p_equalizer ? "equalizer" : "" );
2037         vlc_object_release( p_aout );
2038     }
2039
2040     return 0;
2041 }
2042
2043 static const char roles[][16] =
2044 {
2045     [libvlc_role_Music] =         "music",
2046     [libvlc_role_Video] =         "video",
2047     [libvlc_role_Communication] = "communication",
2048     [libvlc_role_Game] =          "game",
2049     [libvlc_role_Notification] =  "notification",
2050     [libvlc_role_Animation] =     "animation",
2051     [libvlc_role_Production] =    "production",
2052     [libvlc_role_Accessibility] = "accessibility",
2053     [libvlc_role_Test] =          "test",
2054 };
2055
2056 int libvlc_media_player_set_role(libvlc_media_player_t *mp, unsigned role)
2057 {
2058     if (role >= ARRAY_SIZE(roles)
2059      || var_SetString(mp, "role", roles[role]) != VLC_SUCCESS)
2060         return -1;
2061     return 0;
2062 }
2063
2064 int libvlc_media_player_get_role(libvlc_media_player_t *mp)
2065 {
2066     int ret = -1;
2067     char *str = var_GetString(mp, "role");
2068     if (str == NULL)
2069         return 0;
2070
2071     for (size_t i = 0; i < ARRAY_SIZE(roles); i++)
2072         if (!strcmp(roles[i], str))
2073         {
2074             ret = i;
2075             break;
2076         }
2077
2078     free(str);
2079     return ret;
2080 }