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  */
lock(libvlc_media_player_t * mp)107 static inline void lock(libvlc_media_player_t *mp)
108 {
109     vlc_mutex_lock(&mp->object_lock);
110 }
111 
unlock(libvlc_media_player_t * mp)112 static inline void unlock(libvlc_media_player_t *mp)
113 {
114     vlc_mutex_unlock(&mp->object_lock);
115 }
116 
lock_input(libvlc_media_player_t * mp)117 static inline void lock_input(libvlc_media_player_t *mp)
118 {
119     vlc_mutex_lock(&mp->input.lock);
120 }
121 
unlock_input(libvlc_media_player_t * mp)122 static inline void unlock_input(libvlc_media_player_t *mp)
123 {
124     vlc_mutex_unlock(&mp->input.lock);
125 }
126 
input_item_preparsed_changed(const vlc_event_t * p_event,void * user_data)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 
media_attach_preparsed_event(libvlc_media_t * p_md)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 
media_detach_preparsed_event(libvlc_media_t * p_md)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  */
release_input_thread(libvlc_media_player_t * p_mi)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  */
libvlc_get_input_thread(libvlc_media_player_t * p_mi)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  */
set_state(libvlc_media_player_t * p_mi,libvlc_state_t state,bool b_locked)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
input_seekable_changed(vlc_object_t * p_this,char const * psz_cmd,vlc_value_t oldval,vlc_value_t newval,void * p_userdata)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
input_pausable_changed(vlc_object_t * p_this,char const * psz_cmd,vlc_value_t oldval,vlc_value_t newval,void * p_userdata)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
input_scrambled_changed(vlc_object_t * p_this,char const * psz_cmd,vlc_value_t oldval,vlc_value_t newval,void * p_userdata)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
input_event_changed(vlc_object_t * p_this,char const * psz_cmd,vlc_value_t oldval,vlc_value_t newval,void * p_userdata)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 
track_type_from_name(const char * psz_name)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 
input_es_changed(vlc_object_t * p_this,char const * psz_cmd,int action,vlc_value_t * p_val,void * p_userdata)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  *************************************************************************/
snapshot_was_taken(vlc_object_t * p_this,char const * psz_cmd,vlc_value_t oldval,vlc_value_t newval,void * p_data)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 
corks_changed(vlc_object_t * obj,const char * name,vlc_value_t old,vlc_value_t cur,void * opaque)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 
audio_device_changed(vlc_object_t * obj,const char * name,vlc_value_t old,vlc_value_t cur,void * opaque)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 
mute_changed(vlc_object_t * obj,const char * name,vlc_value_t old,vlc_value_t cur,void * opaque)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 
volume_changed(vlc_object_t * obj,const char * name,vlc_value_t old,vlc_value_t cur,void * opaque)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 *
libvlc_media_player_new(libvlc_instance_t * instance)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 *
libvlc_media_player_new_from_media(libvlc_media_t * p_md)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  **************************************************************************/
libvlc_media_player_destroy(libvlc_media_player_t * p_mi)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  **************************************************************************/
libvlc_media_player_release(libvlc_media_player_t * p_mi)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  **************************************************************************/
libvlc_media_player_retain(libvlc_media_player_t * p_mi)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  **************************************************************************/
libvlc_media_player_set_media(libvlc_media_player_t * p_mi,libvlc_media_t * p_md)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     unlock(p_mi);
905 
906     /* Send an event for the newly available media */
907     libvlc_event_t event;
908     event.type = libvlc_MediaPlayerMediaChanged;
909     event.u.media_player_media_changed.new_media = p_md;
910     libvlc_event_send( &p_mi->event_manager, &event );
911 
912 }
913 
914 /**************************************************************************
915  * Get the Media descriptor associated with the instance.
916  **************************************************************************/
917 libvlc_media_t *
libvlc_media_player_get_media(libvlc_media_player_t * p_mi)918 libvlc_media_player_get_media( libvlc_media_player_t *p_mi )
919 {
920     libvlc_media_t *p_m;
921 
922     lock( p_mi );
923     p_m = p_mi->p_md;
924     if( p_m )
925         libvlc_media_retain( p_m );
926     unlock( p_mi );
927 
928     return p_m;
929 }
930 
931 /**************************************************************************
932  * Get the event Manager.
933  **************************************************************************/
934 libvlc_event_manager_t *
libvlc_media_player_event_manager(libvlc_media_player_t * p_mi)935 libvlc_media_player_event_manager( libvlc_media_player_t *p_mi )
936 {
937     return &p_mi->event_manager;
938 }
939 
add_es_callbacks(input_thread_t * p_input_thread,libvlc_media_player_t * p_mi)940 static void add_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi )
941 {
942     var_AddListCallback( p_input_thread, "video-es", input_es_changed, p_mi );
943     var_AddListCallback( p_input_thread, "audio-es", input_es_changed, p_mi );
944     var_AddListCallback( p_input_thread, "spu-es", input_es_changed, p_mi );
945 }
946 
del_es_callbacks(input_thread_t * p_input_thread,libvlc_media_player_t * p_mi)947 static void del_es_callbacks( input_thread_t *p_input_thread, libvlc_media_player_t *p_mi )
948 {
949     var_DelListCallback( p_input_thread, "video-es", input_es_changed, p_mi );
950     var_DelListCallback( p_input_thread, "audio-es", input_es_changed, p_mi );
951     var_DelListCallback( p_input_thread, "spu-es", input_es_changed, p_mi );
952 }
953 
954 /**************************************************************************
955  * Tell media player to start playing.
956  **************************************************************************/
libvlc_media_player_play(libvlc_media_player_t * p_mi)957 int libvlc_media_player_play( libvlc_media_player_t *p_mi )
958 {
959     lock_input( p_mi );
960 
961     input_thread_t *p_input_thread = p_mi->input.p_thread;
962     if( p_input_thread )
963     {
964         /* A thread already exists, send it a play message */
965         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
966         unlock_input( p_mi );
967         return 0;
968     }
969 
970     /* Ignore previous exception */
971     lock(p_mi);
972 
973     if( !p_mi->p_md )
974     {
975         unlock(p_mi);
976         unlock_input( p_mi );
977         libvlc_printerr( "No associated media descriptor" );
978         return -1;
979     }
980 
981     for( size_t i = 0; i < ARRAY_SIZE( p_mi->selected_es ); ++i )
982         p_mi->selected_es[i] = ES_INIT;
983 
984     media_attach_preparsed_event( p_mi->p_md );
985 
986     p_input_thread = input_Create( p_mi, p_mi->p_md->p_input_item, NULL,
987                                    p_mi->input.p_resource,
988                                    p_mi->input.p_renderer );
989     unlock(p_mi);
990     if( !p_input_thread )
991     {
992         unlock_input(p_mi);
993         media_detach_preparsed_event( p_mi->p_md );
994         libvlc_printerr( "Not enough memory" );
995         return -1;
996     }
997 
998     var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
999     var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
1000     var_AddCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
1001     var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
1002     add_es_callbacks( p_input_thread, p_mi );
1003 
1004     if( input_Start( p_input_thread ) )
1005     {
1006         unlock_input(p_mi);
1007         del_es_callbacks( p_input_thread, p_mi );
1008         var_DelCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
1009         var_DelCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
1010         var_DelCallback( p_input_thread, "program-scrambled", input_scrambled_changed, p_mi );
1011         var_DelCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
1012         input_Close( p_input_thread );
1013         media_detach_preparsed_event( p_mi->p_md );
1014         libvlc_printerr( "Input initialization failure" );
1015         return -1;
1016     }
1017     p_mi->input.p_thread = p_input_thread;
1018     unlock_input(p_mi);
1019     return 0;
1020 }
1021 
libvlc_media_player_set_pause(libvlc_media_player_t * p_mi,int paused)1022 void libvlc_media_player_set_pause( libvlc_media_player_t *p_mi, int paused )
1023 {
1024     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi );
1025     if( !p_input_thread )
1026         return;
1027 
1028     if( paused )
1029     {
1030         if( libvlc_media_player_can_pause( p_mi ) )
1031             input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
1032         else
1033             input_Stop( p_input_thread );
1034     }
1035     else
1036     {
1037         input_Control( p_input_thread, INPUT_SET_STATE, PLAYING_S );
1038     }
1039 
1040     vlc_object_release( p_input_thread );
1041 }
1042 
1043 /**************************************************************************
1044  * Toggle pause.
1045  **************************************************************************/
libvlc_media_player_pause(libvlc_media_player_t * p_mi)1046 void libvlc_media_player_pause( libvlc_media_player_t *p_mi )
1047 {
1048     libvlc_media_player_set_pause( p_mi, libvlc_media_player_is_playing( p_mi ) );
1049 }
1050 
1051 /**************************************************************************
1052  * Tells whether the media player is currently playing.
1053  **************************************************************************/
libvlc_media_player_is_playing(libvlc_media_player_t * p_mi)1054 int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi )
1055 {
1056     libvlc_state_t state = libvlc_media_player_get_state( p_mi );
1057     return libvlc_Playing == state;
1058 }
1059 
1060 /**************************************************************************
1061  * Stop playing.
1062  **************************************************************************/
libvlc_media_player_stop(libvlc_media_player_t * p_mi)1063 void libvlc_media_player_stop( libvlc_media_player_t *p_mi )
1064 {
1065     lock_input(p_mi);
1066     release_input_thread( p_mi ); /* This will stop the input thread */
1067 
1068     /* Force to go to stopped state, in case we were in Ended, or Error
1069      * state. */
1070     if( p_mi->state != libvlc_Stopped )
1071     {
1072         set_state( p_mi, libvlc_Stopped, false );
1073 
1074         /* Construct and send the event */
1075         libvlc_event_t event;
1076         event.type = libvlc_MediaPlayerStopped;
1077         libvlc_event_send( &p_mi->event_manager, &event );
1078     }
1079 
1080     input_resource_Terminate( p_mi->input.p_resource );
1081     unlock_input(p_mi);
1082 }
1083 
libvlc_media_player_set_renderer(libvlc_media_player_t * p_mi,libvlc_renderer_item_t * p_litem)1084 int libvlc_media_player_set_renderer( libvlc_media_player_t *p_mi,
1085                                       libvlc_renderer_item_t *p_litem )
1086 {
1087     vlc_renderer_item_t *p_item =
1088         p_litem ? libvlc_renderer_item_to_vlc( p_litem ) : NULL;
1089 
1090     lock_input( p_mi );
1091     input_thread_t *p_input_thread = p_mi->input.p_thread;
1092     if( p_input_thread )
1093         input_Control( p_input_thread, INPUT_SET_RENDERER, p_item );
1094 
1095     if( p_mi->input.p_renderer )
1096         vlc_renderer_item_release( p_mi->input.p_renderer );
1097     p_mi->input.p_renderer = p_item ? vlc_renderer_item_hold( p_item ) : NULL;
1098     unlock_input( p_mi );
1099 
1100     return 0;
1101 }
1102 
libvlc_video_set_callbacks(libvlc_media_player_t * mp,void * (* lock_cb)(void *,void **),void (* unlock_cb)(void *,void *,void * const *),void (* display_cb)(void *,void *),void * opaque)1103 void libvlc_video_set_callbacks( libvlc_media_player_t *mp,
1104     void *(*lock_cb) (void *, void **),
1105     void (*unlock_cb) (void *, void *, void *const *),
1106     void (*display_cb) (void *, void *),
1107     void *opaque )
1108 {
1109     var_SetAddress( mp, "vmem-lock", lock_cb );
1110     var_SetAddress( mp, "vmem-unlock", unlock_cb );
1111     var_SetAddress( mp, "vmem-display", display_cb );
1112     var_SetAddress( mp, "vmem-data", opaque );
1113     var_SetString( mp, "avcodec-hw", "none" );
1114     var_SetString( mp, "vout", "vmem" );
1115     var_SetString( mp, "window", "none" );
1116 }
1117 
libvlc_video_set_format_callbacks(libvlc_media_player_t * mp,libvlc_video_format_cb setup,libvlc_video_cleanup_cb cleanup)1118 void libvlc_video_set_format_callbacks( libvlc_media_player_t *mp,
1119                                         libvlc_video_format_cb setup,
1120                                         libvlc_video_cleanup_cb cleanup )
1121 {
1122     var_SetAddress( mp, "vmem-setup", setup );
1123     var_SetAddress( mp, "vmem-cleanup", cleanup );
1124 }
1125 
libvlc_video_set_format(libvlc_media_player_t * mp,const char * chroma,unsigned width,unsigned height,unsigned pitch)1126 void libvlc_video_set_format( libvlc_media_player_t *mp, const char *chroma,
1127                               unsigned width, unsigned height, unsigned pitch )
1128 {
1129     var_SetString( mp, "vmem-chroma", chroma );
1130     var_SetInteger( mp, "vmem-width", width );
1131     var_SetInteger( mp, "vmem-height", height );
1132     var_SetInteger( mp, "vmem-pitch", pitch );
1133 }
1134 
1135 /**************************************************************************
1136  * set_nsobject
1137  **************************************************************************/
libvlc_media_player_set_nsobject(libvlc_media_player_t * p_mi,void * drawable)1138 void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
1139                                         void * drawable )
1140 {
1141     assert (p_mi != NULL);
1142 #ifdef __APPLE__
1143     var_SetString (p_mi, "avcodec-hw", "");
1144     var_SetString (p_mi, "vout", "");
1145     var_SetString (p_mi, "window", "");
1146     var_SetAddress (p_mi, "drawable-nsobject", drawable);
1147 #else
1148     (void)drawable;
1149     libvlc_printerr ("can't set nsobject: APPLE build required");
1150     assert(false);
1151     var_SetString (p_mi, "vout", "none");
1152     var_SetString (p_mi, "window", "none");
1153 #endif
1154 }
1155 
1156 /**************************************************************************
1157  * get_nsobject
1158  **************************************************************************/
libvlc_media_player_get_nsobject(libvlc_media_player_t * p_mi)1159 void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi )
1160 {
1161     assert (p_mi != NULL);
1162 #ifdef __APPLE__
1163     return var_GetAddress (p_mi, "drawable-nsobject");
1164 #else
1165     (void) p_mi;
1166     return NULL;
1167 #endif
1168 }
1169 
1170 /**************************************************************************
1171  * set_agl
1172  **************************************************************************/
libvlc_media_player_set_agl(libvlc_media_player_t * p_mi,uint32_t drawable)1173 void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
1174                                   uint32_t drawable )
1175 {
1176     (void)drawable;
1177     libvlc_printerr ("can't set agl: use libvlc_media_player_set_nsobject instead");
1178     assert(false);
1179     var_SetString (p_mi, "vout", "none");
1180     var_SetString (p_mi, "window", "none");
1181 }
1182 
1183 /**************************************************************************
1184  * get_agl
1185  **************************************************************************/
libvlc_media_player_get_agl(libvlc_media_player_t * p_mi)1186 uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
1187 {
1188     (void) p_mi;
1189     return 0;
1190 }
1191 
1192 /**************************************************************************
1193  * set_xwindow
1194  **************************************************************************/
libvlc_media_player_set_xwindow(libvlc_media_player_t * p_mi,uint32_t drawable)1195 void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
1196                                       uint32_t drawable )
1197 {
1198     assert (p_mi != NULL);
1199 
1200     var_SetString (p_mi, "avcodec-hw", "");
1201     var_SetString (p_mi, "vout", "");
1202     var_SetString (p_mi, "window", drawable ? "embed-xid,any" : "");
1203     var_SetInteger (p_mi, "drawable-xid", drawable);
1204 }
1205 
1206 /**************************************************************************
1207  * get_xwindow
1208  **************************************************************************/
libvlc_media_player_get_xwindow(libvlc_media_player_t * p_mi)1209 uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
1210 {
1211     return var_GetInteger (p_mi, "drawable-xid");
1212 }
1213 
1214 /**************************************************************************
1215  * set_hwnd
1216  **************************************************************************/
libvlc_media_player_set_hwnd(libvlc_media_player_t * p_mi,void * drawable)1217 void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
1218                                    void *drawable )
1219 {
1220     assert (p_mi != NULL);
1221 #if defined (_WIN32) || defined (__OS2__)
1222     var_SetString (p_mi, "avcodec-hw", "");
1223     var_SetString (p_mi, "vout", "");
1224     var_SetString (p_mi, "window",
1225                    (drawable != NULL) ? "embed-hwnd,any" : "");
1226     var_SetInteger (p_mi, "drawable-hwnd", (uintptr_t)drawable);
1227 #else
1228     (void) drawable;
1229     libvlc_printerr ("can't set nsobject: WIN32 build required");
1230     assert(false);
1231     var_SetString (p_mi, "vout", "none");
1232     var_SetString (p_mi, "window", "none");
1233 #endif
1234 }
1235 
1236 /**************************************************************************
1237  * get_hwnd
1238  **************************************************************************/
libvlc_media_player_get_hwnd(libvlc_media_player_t * p_mi)1239 void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
1240 {
1241     assert (p_mi != NULL);
1242 #if defined (_WIN32) || defined (__OS2__)
1243     return (void *)(uintptr_t)var_GetInteger (p_mi, "drawable-hwnd");
1244 #else
1245     (void) p_mi;
1246     return NULL;
1247 #endif
1248 }
1249 
1250 /**************************************************************************
1251  * set_android_context
1252  **************************************************************************/
libvlc_media_player_set_android_context(libvlc_media_player_t * p_mi,void * p_awindow_handler)1253 void libvlc_media_player_set_android_context( libvlc_media_player_t *p_mi,
1254                                               void *p_awindow_handler )
1255 {
1256     assert (p_mi != NULL);
1257 #ifdef __ANDROID__
1258     var_SetAddress (p_mi, "drawable-androidwindow", p_awindow_handler);
1259 #else
1260     (void) p_awindow_handler;
1261     libvlc_printerr ("can't set android context: ANDROID build required");
1262     assert(false);
1263     var_SetString (p_mi, "vout", "none");
1264     var_SetString (p_mi, "window", "none");
1265 #endif
1266 }
1267 
1268 /**************************************************************************
1269  * set_evas_object
1270  **************************************************************************/
libvlc_media_player_set_evas_object(libvlc_media_player_t * p_mi,void * p_evas_object)1271 int libvlc_media_player_set_evas_object( libvlc_media_player_t *p_mi,
1272                                          void *p_evas_object )
1273 {
1274     assert (p_mi != NULL);
1275 #ifdef HAVE_EVAS
1276     var_SetString (p_mi, "vout", "evas");
1277     var_SetString (p_mi, "window", "none");
1278     var_SetAddress (p_mi, "drawable-evasobject", p_evas_object);
1279     return 0;
1280 #else
1281     (void) p_mi; (void) p_evas_object;
1282     return -1;
1283 #endif
1284 }
1285 
libvlc_audio_set_callbacks(libvlc_media_player_t * mp,libvlc_audio_play_cb play_cb,libvlc_audio_pause_cb pause_cb,libvlc_audio_resume_cb resume_cb,libvlc_audio_flush_cb flush_cb,libvlc_audio_drain_cb drain_cb,void * opaque)1286 void libvlc_audio_set_callbacks( libvlc_media_player_t *mp,
1287                                  libvlc_audio_play_cb play_cb,
1288                                  libvlc_audio_pause_cb pause_cb,
1289                                  libvlc_audio_resume_cb resume_cb,
1290                                  libvlc_audio_flush_cb flush_cb,
1291                                  libvlc_audio_drain_cb drain_cb,
1292                                  void *opaque )
1293 {
1294     var_SetAddress( mp, "amem-play", play_cb );
1295     var_SetAddress( mp, "amem-pause", pause_cb );
1296     var_SetAddress( mp, "amem-resume", resume_cb );
1297     var_SetAddress( mp, "amem-flush", flush_cb );
1298     var_SetAddress( mp, "amem-drain", drain_cb );
1299     var_SetAddress( mp, "amem-data", opaque );
1300     var_SetString( mp, "aout", "amem,none" );
1301 
1302     input_resource_ResetAout(mp->input.p_resource);
1303 }
1304 
libvlc_audio_set_volume_callback(libvlc_media_player_t * mp,libvlc_audio_set_volume_cb cb)1305 void libvlc_audio_set_volume_callback( libvlc_media_player_t *mp,
1306                                        libvlc_audio_set_volume_cb cb )
1307 {
1308     var_SetAddress( mp, "amem-set-volume", cb );
1309 
1310     input_resource_ResetAout(mp->input.p_resource);
1311 }
1312 
libvlc_audio_set_format_callbacks(libvlc_media_player_t * mp,libvlc_audio_setup_cb setup,libvlc_audio_cleanup_cb cleanup)1313 void libvlc_audio_set_format_callbacks( libvlc_media_player_t *mp,
1314                                         libvlc_audio_setup_cb setup,
1315                                         libvlc_audio_cleanup_cb cleanup )
1316 {
1317     var_SetAddress( mp, "amem-setup", setup );
1318     var_SetAddress( mp, "amem-cleanup", cleanup );
1319 
1320     input_resource_ResetAout(mp->input.p_resource);
1321 }
1322 
libvlc_audio_set_format(libvlc_media_player_t * mp,const char * format,unsigned rate,unsigned channels)1323 void libvlc_audio_set_format( libvlc_media_player_t *mp, const char *format,
1324                               unsigned rate, unsigned channels )
1325 {
1326     var_SetString( mp, "amem-format", format );
1327     var_SetInteger( mp, "amem-rate", rate );
1328     var_SetInteger( mp, "amem-channels", channels );
1329 
1330     input_resource_ResetAout(mp->input.p_resource);
1331 }
1332 
1333 
1334 /**************************************************************************
1335  * Getters for stream information
1336  **************************************************************************/
libvlc_media_player_get_length(libvlc_media_player_t * p_mi)1337 libvlc_time_t libvlc_media_player_get_length(
1338                              libvlc_media_player_t *p_mi )
1339 {
1340     input_thread_t *p_input_thread;
1341     libvlc_time_t i_time;
1342 
1343     p_input_thread = libvlc_get_input_thread ( p_mi );
1344     if( !p_input_thread )
1345         return -1;
1346 
1347     i_time = from_mtime(var_GetInteger( p_input_thread, "length" ));
1348     vlc_object_release( p_input_thread );
1349 
1350     return i_time;
1351 }
1352 
libvlc_media_player_get_time(libvlc_media_player_t * p_mi)1353 libvlc_time_t libvlc_media_player_get_time( libvlc_media_player_t *p_mi )
1354 {
1355     input_thread_t *p_input_thread;
1356     libvlc_time_t i_time;
1357 
1358     p_input_thread = libvlc_get_input_thread ( p_mi );
1359     if( !p_input_thread )
1360         return -1;
1361 
1362     i_time = from_mtime(var_GetInteger( p_input_thread , "time" ));
1363     vlc_object_release( p_input_thread );
1364     return i_time;
1365 }
1366 
libvlc_media_player_set_time(libvlc_media_player_t * p_mi,libvlc_time_t i_time)1367 void libvlc_media_player_set_time( libvlc_media_player_t *p_mi,
1368                                    libvlc_time_t i_time )
1369 {
1370     input_thread_t *p_input_thread;
1371 
1372     p_input_thread = libvlc_get_input_thread ( p_mi );
1373     if( !p_input_thread )
1374         return;
1375 
1376     var_SetInteger( p_input_thread, "time", to_mtime(i_time) );
1377     vlc_object_release( p_input_thread );
1378 }
1379 
libvlc_media_player_set_position(libvlc_media_player_t * p_mi,float position)1380 void libvlc_media_player_set_position( libvlc_media_player_t *p_mi,
1381                                        float position )
1382 {
1383     input_thread_t *p_input_thread;
1384 
1385     p_input_thread = libvlc_get_input_thread ( p_mi );
1386     if( !p_input_thread )
1387         return;
1388 
1389     var_SetFloat( p_input_thread, "position", position );
1390     vlc_object_release( p_input_thread );
1391 }
1392 
libvlc_media_player_get_position(libvlc_media_player_t * p_mi)1393 float libvlc_media_player_get_position( libvlc_media_player_t *p_mi )
1394 {
1395     input_thread_t *p_input_thread;
1396     float f_position;
1397 
1398     p_input_thread = libvlc_get_input_thread ( p_mi );
1399     if( !p_input_thread )
1400         return -1.0;
1401 
1402     f_position = var_GetFloat( p_input_thread, "position" );
1403     vlc_object_release( p_input_thread );
1404 
1405     return f_position;
1406 }
1407 
libvlc_media_player_set_chapter(libvlc_media_player_t * p_mi,int chapter)1408 void libvlc_media_player_set_chapter( libvlc_media_player_t *p_mi,
1409                                       int chapter )
1410 {
1411     input_thread_t *p_input_thread;
1412 
1413     p_input_thread = libvlc_get_input_thread ( p_mi );
1414     if( !p_input_thread )
1415         return;
1416 
1417     var_SetInteger( p_input_thread, "chapter", chapter );
1418     vlc_object_release( p_input_thread );
1419 }
1420 
libvlc_media_player_get_chapter(libvlc_media_player_t * p_mi)1421 int libvlc_media_player_get_chapter( libvlc_media_player_t *p_mi )
1422 {
1423     input_thread_t *p_input_thread;
1424     int i_chapter;
1425 
1426     p_input_thread = libvlc_get_input_thread ( p_mi );
1427     if( !p_input_thread )
1428         return -1;
1429 
1430     i_chapter = var_GetInteger( p_input_thread, "chapter" );
1431     vlc_object_release( p_input_thread );
1432 
1433     return i_chapter;
1434 }
1435 
libvlc_media_player_get_chapter_count(libvlc_media_player_t * p_mi)1436 int libvlc_media_player_get_chapter_count( libvlc_media_player_t *p_mi )
1437 {
1438     input_thread_t *p_input_thread;
1439     vlc_value_t val;
1440 
1441     p_input_thread = libvlc_get_input_thread ( p_mi );
1442     if( !p_input_thread )
1443         return -1;
1444 
1445     int i_ret = var_Change( p_input_thread, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL );
1446     vlc_object_release( p_input_thread );
1447 
1448     return i_ret == VLC_SUCCESS ? val.i_int : -1;
1449 }
1450 
libvlc_media_player_get_chapter_count_for_title(libvlc_media_player_t * p_mi,int i_title)1451 int libvlc_media_player_get_chapter_count_for_title(
1452                                  libvlc_media_player_t *p_mi,
1453                                  int i_title )
1454 {
1455     vlc_value_t val;
1456 
1457     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1458     if( !p_input_thread )
1459         return -1;
1460 
1461     char psz_name[sizeof ("title ") + 3 * sizeof (int)];
1462     sprintf( psz_name, "title %2u", i_title );
1463 
1464     int i_ret = var_Change( p_input_thread, psz_name, VLC_VAR_CHOICESCOUNT, &val, NULL );
1465     vlc_object_release( p_input_thread );
1466 
1467     return i_ret == VLC_SUCCESS ? val.i_int : -1;
1468 }
1469 
libvlc_media_player_set_title(libvlc_media_player_t * p_mi,int i_title)1470 void libvlc_media_player_set_title( libvlc_media_player_t *p_mi,
1471                                     int i_title )
1472 {
1473     input_thread_t *p_input_thread;
1474 
1475     p_input_thread = libvlc_get_input_thread ( p_mi );
1476     if( !p_input_thread )
1477         return;
1478 
1479     var_SetInteger( p_input_thread, "title", i_title );
1480     vlc_object_release( p_input_thread );
1481 
1482     //send event
1483     libvlc_event_t event;
1484     event.type = libvlc_MediaPlayerTitleChanged;
1485     event.u.media_player_title_changed.new_title = i_title;
1486     libvlc_event_send( &p_mi->event_manager, &event );
1487 }
1488 
libvlc_media_player_get_title(libvlc_media_player_t * p_mi)1489 int libvlc_media_player_get_title( libvlc_media_player_t *p_mi )
1490 {
1491     input_thread_t *p_input_thread;
1492     int i_title;
1493 
1494     p_input_thread = libvlc_get_input_thread ( p_mi );
1495     if( !p_input_thread )
1496         return -1;
1497 
1498     i_title = var_GetInteger( p_input_thread, "title" );
1499     vlc_object_release( p_input_thread );
1500 
1501     return i_title;
1502 }
1503 
libvlc_media_player_get_title_count(libvlc_media_player_t * p_mi)1504 int libvlc_media_player_get_title_count( libvlc_media_player_t *p_mi )
1505 {
1506     input_thread_t *p_input_thread;
1507     vlc_value_t val;
1508 
1509     p_input_thread = libvlc_get_input_thread ( p_mi );
1510     if( !p_input_thread )
1511         return -1;
1512 
1513     int i_ret = var_Change( p_input_thread, "title", VLC_VAR_CHOICESCOUNT, &val, NULL );
1514     vlc_object_release( p_input_thread );
1515 
1516     return i_ret == VLC_SUCCESS ? val.i_int : -1;
1517 }
1518 
libvlc_media_player_get_full_title_descriptions(libvlc_media_player_t * p_mi,libvlc_title_description_t *** pp_titles)1519 int libvlc_media_player_get_full_title_descriptions( libvlc_media_player_t *p_mi,
1520                                                      libvlc_title_description_t *** pp_titles )
1521 {
1522     assert( p_mi );
1523 
1524     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
1525 
1526     if( !p_input_thread )
1527         return -1;
1528 
1529     input_title_t **p_input_title;
1530     int count;
1531 
1532     /* fetch data */
1533     int ret = input_Control( p_input_thread, INPUT_GET_FULL_TITLE_INFO,
1534                              &p_input_title, &count );
1535     vlc_object_release( p_input_thread );
1536     if( ret != VLC_SUCCESS )
1537         return -1;
1538 
1539     libvlc_title_description_t **titles = vlc_alloc( count, sizeof (*titles) );
1540     if( count > 0 && unlikely(titles == NULL) )
1541         return -1;
1542 
1543     /* fill array */
1544     for( int i = 0; i < count; i++)
1545     {
1546         libvlc_title_description_t *title = malloc( sizeof (*title) );
1547         if( unlikely(title == NULL) )
1548         {
1549             libvlc_title_descriptions_release( titles, i );
1550             return -1;
1551         }
1552         titles[i] = title;
1553 
1554         /* we want to return milliseconds to match the rest of the API */
1555         title->i_duration = p_input_title[i]->i_length / 1000;
1556         title->i_flags = p_input_title[i]->i_flags;
1557         if( p_input_title[i]->psz_name )
1558             title->psz_name = strdup( p_input_title[i]->psz_name );
1559         else
1560             title->psz_name = NULL;
1561         vlc_input_title_Delete( p_input_title[i] );
1562     }
1563     free( p_input_title );
1564 
1565     *pp_titles = titles;
1566     return count;
1567 }
1568 
libvlc_title_descriptions_release(libvlc_title_description_t ** p_titles,unsigned i_count)1569 void libvlc_title_descriptions_release( libvlc_title_description_t **p_titles,
1570                                         unsigned i_count )
1571 {
1572     for (unsigned i = 0; i < i_count; i++ )
1573     {
1574         if ( !p_titles[i] )
1575             continue;
1576 
1577         free( p_titles[i]->psz_name );
1578         free( p_titles[i] );
1579     }
1580     free( p_titles );
1581 }
1582 
libvlc_media_player_get_full_chapter_descriptions(libvlc_media_player_t * p_mi,int i_chapters_of_title,libvlc_chapter_description_t *** pp_chapters)1583 int libvlc_media_player_get_full_chapter_descriptions( libvlc_media_player_t *p_mi,
1584                                                       int i_chapters_of_title,
1585                                                       libvlc_chapter_description_t *** pp_chapters )
1586 {
1587     assert( p_mi );
1588 
1589     input_thread_t *p_input_thread = libvlc_get_input_thread( p_mi );
1590 
1591     if( !p_input_thread )
1592         return -1;
1593 
1594     seekpoint_t **p_seekpoint = NULL;
1595 
1596     /* fetch data */
1597     int ci_chapter_count = i_chapters_of_title;
1598 
1599     int ret = input_Control(p_input_thread, INPUT_GET_SEEKPOINTS, &p_seekpoint, &ci_chapter_count);
1600     if( ret != VLC_SUCCESS)
1601     {
1602         vlc_object_release( p_input_thread );
1603         return -1;
1604     }
1605 
1606     if (ci_chapter_count == 0 || p_seekpoint == NULL)
1607     {
1608         vlc_object_release( p_input_thread );
1609         return 0;
1610     }
1611 
1612     input_title_t *p_title;
1613     ret = input_Control( p_input_thread, INPUT_GET_TITLE_INFO, &p_title,
1614                          &i_chapters_of_title );
1615     vlc_object_release( p_input_thread );
1616     if( ret != VLC_SUCCESS )
1617     {
1618         goto error;
1619     }
1620     int64_t i_title_duration = p_title->i_length / 1000;
1621     vlc_input_title_Delete( p_title );
1622 
1623     *pp_chapters = calloc( ci_chapter_count, sizeof(**pp_chapters) );
1624     if( !*pp_chapters )
1625     {
1626         goto error;
1627     }
1628 
1629     /* fill array */
1630     for( int i = 0; i < ci_chapter_count; ++i )
1631     {
1632         libvlc_chapter_description_t *p_chapter = malloc( sizeof(*p_chapter) );
1633         if( unlikely(p_chapter == NULL) )
1634         {
1635             goto error;
1636         }
1637         (*pp_chapters)[i] = p_chapter;
1638 
1639         p_chapter->i_time_offset = p_seekpoint[i]->i_time_offset / 1000;
1640 
1641         if( i < ci_chapter_count - 1 )
1642         {
1643             p_chapter->i_duration = p_seekpoint[i + 1]->i_time_offset / 1000 -
1644                                     p_chapter->i_time_offset;
1645         }
1646         else
1647         {
1648             if ( i_title_duration )
1649                 p_chapter->i_duration = i_title_duration - p_chapter->i_time_offset;
1650             else
1651                 p_chapter->i_duration = 0;
1652         }
1653 
1654         if( p_seekpoint[i]->psz_name )
1655         {
1656             p_chapter->psz_name = strdup( p_seekpoint[i]->psz_name );
1657         }
1658         else
1659         {
1660             p_chapter->psz_name = NULL;
1661         }
1662         vlc_seekpoint_Delete( p_seekpoint[i] );
1663         p_seekpoint[i] = NULL;
1664     }
1665 
1666     free( p_seekpoint );
1667     return ci_chapter_count;
1668 
1669 error:
1670     if( *pp_chapters )
1671         libvlc_chapter_descriptions_release( *pp_chapters, ci_chapter_count );
1672     for ( int i = 0; i < ci_chapter_count; ++i )
1673         vlc_seekpoint_Delete( p_seekpoint[i] );
1674     free( p_seekpoint );
1675     return -1;
1676 }
1677 
libvlc_chapter_descriptions_release(libvlc_chapter_description_t ** p_chapters,unsigned i_count)1678 void libvlc_chapter_descriptions_release( libvlc_chapter_description_t **p_chapters,
1679                                           unsigned i_count )
1680 {
1681     for (unsigned i = 0; i < i_count; i++ )
1682     {
1683         if ( !p_chapters[i] )
1684             continue;
1685 
1686         free( p_chapters[i]->psz_name );
1687         free( p_chapters[i] );
1688     }
1689     free( p_chapters );
1690 }
1691 
libvlc_media_player_next_chapter(libvlc_media_player_t * p_mi)1692 void libvlc_media_player_next_chapter( libvlc_media_player_t *p_mi )
1693 {
1694     input_thread_t *p_input_thread;
1695 
1696     p_input_thread = libvlc_get_input_thread ( p_mi );
1697     if( !p_input_thread )
1698         return;
1699 
1700     int i_type = var_Type( p_input_thread, "next-chapter" );
1701     var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1702                             "next-chapter":"next-title" );
1703 
1704     vlc_object_release( p_input_thread );
1705 }
1706 
libvlc_media_player_previous_chapter(libvlc_media_player_t * p_mi)1707 void libvlc_media_player_previous_chapter( libvlc_media_player_t *p_mi )
1708 {
1709     input_thread_t *p_input_thread;
1710 
1711     p_input_thread = libvlc_get_input_thread ( p_mi );
1712     if( !p_input_thread )
1713         return;
1714 
1715     int i_type = var_Type( p_input_thread, "next-chapter" );
1716     var_TriggerCallback( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
1717                             "prev-chapter":"prev-title" );
1718 
1719     vlc_object_release( p_input_thread );
1720 }
1721 
libvlc_media_player_get_fps(libvlc_media_player_t * p_mi)1722 float libvlc_media_player_get_fps( libvlc_media_player_t *p_mi )
1723 {
1724     libvlc_media_t *media = libvlc_media_player_get_media( p_mi );
1725     if( media == NULL )
1726         return 0.f;
1727 
1728     input_item_t *item = media->p_input_item;
1729     float fps = 0.f;
1730 
1731     vlc_mutex_lock( &item->lock );
1732     for( int i = 0; i < item->i_es; i++ )
1733     {
1734         const es_format_t *fmt = item->es[i];
1735 
1736         if( fmt->i_cat == VIDEO_ES && fmt->video.i_frame_rate_base > 0 )
1737             fps = (float)fmt->video.i_frame_rate
1738                   / (float)fmt->video.i_frame_rate_base;
1739     }
1740     vlc_mutex_unlock( &item->lock );
1741     libvlc_media_release( media );
1742 
1743     return fps;
1744 }
1745 
libvlc_media_player_will_play(libvlc_media_player_t * p_mi)1746 int libvlc_media_player_will_play( libvlc_media_player_t *p_mi )
1747 {
1748     input_thread_t *p_input_thread =
1749                             libvlc_get_input_thread ( p_mi );
1750     if ( !p_input_thread )
1751         return false;
1752 
1753     int state = var_GetInteger( p_input_thread, "state" );
1754     vlc_object_release( p_input_thread );
1755 
1756     return state != END_S && state != ERROR_S;
1757 }
1758 
libvlc_media_player_set_rate(libvlc_media_player_t * p_mi,float rate)1759 int libvlc_media_player_set_rate( libvlc_media_player_t *p_mi, float rate )
1760 {
1761     var_SetFloat (p_mi, "rate", rate);
1762 
1763     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1764     if( !p_input_thread )
1765         return 0;
1766     var_SetFloat( p_input_thread, "rate", rate );
1767     vlc_object_release( p_input_thread );
1768     return 0;
1769 }
1770 
libvlc_media_player_get_rate(libvlc_media_player_t * p_mi)1771 float libvlc_media_player_get_rate( libvlc_media_player_t *p_mi )
1772 {
1773     return var_GetFloat (p_mi, "rate");
1774 }
1775 
libvlc_media_player_get_state(libvlc_media_player_t * p_mi)1776 libvlc_state_t libvlc_media_player_get_state( libvlc_media_player_t *p_mi )
1777 {
1778     lock(p_mi);
1779     libvlc_state_t state = p_mi->state;
1780     unlock(p_mi);
1781     return state;
1782 }
1783 
libvlc_media_player_is_seekable(libvlc_media_player_t * p_mi)1784 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi )
1785 {
1786     input_thread_t *p_input_thread;
1787     bool b_seekable;
1788 
1789     p_input_thread = libvlc_get_input_thread ( p_mi );
1790     if ( !p_input_thread )
1791         return false;
1792     b_seekable = var_GetBool( p_input_thread, "can-seek" );
1793     vlc_object_release( p_input_thread );
1794 
1795     return b_seekable;
1796 }
1797 
libvlc_media_player_navigate(libvlc_media_player_t * p_mi,unsigned navigate)1798 void libvlc_media_player_navigate( libvlc_media_player_t* p_mi,
1799                                    unsigned navigate )
1800 {
1801     static const int map[] =
1802     {
1803         INPUT_NAV_ACTIVATE, INPUT_NAV_UP, INPUT_NAV_DOWN,
1804         INPUT_NAV_LEFT, INPUT_NAV_RIGHT, INPUT_NAV_POPUP,
1805     };
1806 
1807     if( navigate >= sizeof(map) / sizeof(map[0]) )
1808       return;
1809 
1810     input_thread_t *p_input = libvlc_get_input_thread ( p_mi );
1811     if ( p_input == NULL )
1812       return;
1813 
1814     input_Control( p_input, map[navigate], NULL );
1815     vlc_object_release( p_input );
1816 }
1817 
1818 /* internal function, used by audio, video */
1819 libvlc_track_description_t *
libvlc_get_track_description(libvlc_media_player_t * p_mi,const char * psz_variable)1820         libvlc_get_track_description( libvlc_media_player_t *p_mi,
1821                                       const char *psz_variable )
1822 {
1823     input_thread_t *p_input = libvlc_get_input_thread( p_mi );
1824     libvlc_track_description_t *p_track_description = NULL,
1825                                *p_actual, *p_previous;
1826 
1827     if( !p_input )
1828         return NULL;
1829 
1830     vlc_value_t val_list, text_list;
1831     int i_ret = var_Change( p_input, psz_variable, VLC_VAR_GETCHOICES, &val_list, &text_list );
1832     if( i_ret != VLC_SUCCESS )
1833         return NULL;
1834 
1835     /* no tracks */
1836     if( val_list.p_list->i_count <= 0 )
1837         goto end;
1838 
1839     p_track_description = malloc( sizeof *p_track_description );
1840     if ( !p_track_description )
1841     {
1842         libvlc_printerr( "Not enough memory" );
1843         goto end;
1844     }
1845     p_actual = p_track_description;
1846     p_previous = NULL;
1847     for( int i = 0; i < val_list.p_list->i_count; i++ )
1848     {
1849         if( !p_actual )
1850         {
1851             p_actual = malloc( sizeof *p_actual );
1852             if ( !p_actual )
1853             {
1854                 libvlc_track_description_list_release( p_track_description );
1855                 libvlc_printerr( "Not enough memory" );
1856 
1857                 p_track_description = NULL;
1858                 goto end;
1859             }
1860         }
1861         p_actual->i_id = val_list.p_list->p_values[i].i_int;
1862         p_actual->psz_name = strdup( text_list.p_list->p_values[i].psz_string );
1863         p_actual->p_next = NULL;
1864         if( p_previous )
1865             p_previous->p_next = p_actual;
1866         p_previous = p_actual;
1867         p_actual =  NULL;
1868     }
1869 
1870 end:
1871     var_FreeList( &val_list, &text_list );
1872     vlc_object_release( p_input );
1873 
1874     return p_track_description;
1875 }
1876 
1877 // Deprecated alias for libvlc_track_description_list_release
libvlc_track_description_release(libvlc_track_description_t * p_td)1878 void libvlc_track_description_release( libvlc_track_description_t *p_td )
1879 {
1880     libvlc_track_description_list_release( p_td );
1881 }
1882 
libvlc_track_description_list_release(libvlc_track_description_t * p_td)1883 void libvlc_track_description_list_release( libvlc_track_description_t *p_td )
1884 {
1885     libvlc_track_description_t *p_actual, *p_before;
1886     p_actual = p_td;
1887 
1888     while ( p_actual )
1889     {
1890         free( p_actual->psz_name );
1891         p_before = p_actual;
1892         p_actual = p_before->p_next;
1893         free( p_before );
1894     }
1895 }
1896 
libvlc_media_player_can_pause(libvlc_media_player_t * p_mi)1897 int libvlc_media_player_can_pause( libvlc_media_player_t *p_mi )
1898 {
1899     input_thread_t *p_input_thread;
1900     bool b_can_pause;
1901 
1902     p_input_thread = libvlc_get_input_thread ( p_mi );
1903     if ( !p_input_thread )
1904         return false;
1905     b_can_pause = var_GetBool( p_input_thread, "can-pause" );
1906     vlc_object_release( p_input_thread );
1907 
1908     return b_can_pause;
1909 }
1910 
libvlc_media_player_program_scrambled(libvlc_media_player_t * p_mi)1911 int libvlc_media_player_program_scrambled( libvlc_media_player_t *p_mi )
1912 {
1913     input_thread_t *p_input_thread;
1914     bool b_program_scrambled;
1915 
1916     p_input_thread = libvlc_get_input_thread ( p_mi );
1917     if ( !p_input_thread )
1918         return false;
1919     b_program_scrambled = var_GetBool( p_input_thread, "program-scrambled" );
1920     vlc_object_release( p_input_thread );
1921 
1922     return b_program_scrambled;
1923 }
1924 
libvlc_media_player_next_frame(libvlc_media_player_t * p_mi)1925 void libvlc_media_player_next_frame( libvlc_media_player_t *p_mi )
1926 {
1927     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1928     if( p_input_thread != NULL )
1929     {
1930         var_TriggerCallback( p_input_thread, "frame-next" );
1931         vlc_object_release( p_input_thread );
1932     }
1933 }
1934 
1935 /**
1936  * Private lookup table to get subpicture alignment flag values corresponding
1937  * to a libvlc_position_t enumerated value.
1938  */
1939 static const unsigned char position_subpicture_alignment[] = {
1940     [libvlc_position_center]       = 0,
1941     [libvlc_position_left]         = SUBPICTURE_ALIGN_LEFT,
1942     [libvlc_position_right]        = SUBPICTURE_ALIGN_RIGHT,
1943     [libvlc_position_top]          = SUBPICTURE_ALIGN_TOP,
1944     [libvlc_position_top_left]     = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_LEFT,
1945     [libvlc_position_top_right]    = SUBPICTURE_ALIGN_TOP | SUBPICTURE_ALIGN_RIGHT,
1946     [libvlc_position_bottom]       = SUBPICTURE_ALIGN_BOTTOM,
1947     [libvlc_position_bottom_left]  = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_LEFT,
1948     [libvlc_position_bottom_right] = SUBPICTURE_ALIGN_BOTTOM | SUBPICTURE_ALIGN_RIGHT
1949 };
1950 
libvlc_media_player_set_video_title_display(libvlc_media_player_t * p_mi,libvlc_position_t position,unsigned timeout)1951 void libvlc_media_player_set_video_title_display( libvlc_media_player_t *p_mi, libvlc_position_t position, unsigned timeout )
1952 {
1953     assert( position >= libvlc_position_disable && position <= libvlc_position_bottom_right );
1954 
1955     if ( position != libvlc_position_disable )
1956     {
1957         var_SetBool( p_mi, "video-title-show", true );
1958         var_SetInteger( p_mi, "video-title-position", position_subpicture_alignment[position] );
1959         var_SetInteger( p_mi, "video-title-timeout", timeout );
1960     }
1961     else
1962     {
1963         var_SetBool( p_mi, "video-title-show", false );
1964     }
1965 }
1966 
libvlc_media_player_add_slave(libvlc_media_player_t * p_mi,libvlc_media_slave_type_t i_type,const char * psz_uri,bool b_select)1967 int libvlc_media_player_add_slave( libvlc_media_player_t *p_mi,
1968                                    libvlc_media_slave_type_t i_type,
1969                                    const char *psz_uri, bool b_select )
1970 {
1971     input_thread_t *p_input_thread = libvlc_get_input_thread ( p_mi );
1972 
1973     if( p_input_thread == NULL )
1974     {
1975         libvlc_media_t *p_media = libvlc_media_player_get_media( p_mi );
1976         if( p_media == NULL )
1977             return -1;
1978 
1979         int i_ret = libvlc_media_slaves_add( p_media, i_type, 4, psz_uri );
1980         libvlc_media_release( p_media );
1981         return i_ret;
1982     }
1983     else
1984     {
1985         int i_ret = input_AddSlave( p_input_thread, (enum slave_type) i_type,
1986                                     psz_uri, b_select, false, false );
1987         vlc_object_release( p_input_thread );
1988 
1989         return i_ret == VLC_SUCCESS ? 0 : -1;
1990     }
1991 }
1992 
1993 /**
1994  * Maximum size of a formatted equalizer amplification band frequency value.
1995  *
1996  * The allowed value range is supposed to be constrained from -20.0 to 20.0.
1997  *
1998  * The format string " %.07f" with a minimum value of "-20" gives a maximum
1999  * string length of e.g. " -19.1234567", i.e. 12 bytes (not including the null
2000  * terminator).
2001  */
2002 #define EQZ_BAND_VALUE_SIZE 12
2003 
libvlc_media_player_set_equalizer(libvlc_media_player_t * p_mi,libvlc_equalizer_t * p_equalizer)2004 int libvlc_media_player_set_equalizer( libvlc_media_player_t *p_mi, libvlc_equalizer_t *p_equalizer )
2005 {
2006     char bands[EQZ_BANDS_MAX * EQZ_BAND_VALUE_SIZE + 1];
2007 
2008     if( p_equalizer != NULL )
2009     {
2010         for( unsigned i = 0, c = 0; i < EQZ_BANDS_MAX; i++ )
2011         {
2012             c += snprintf( bands + c, sizeof(bands) - c, " %.07f",
2013                           p_equalizer->f_amp[i] );
2014             if( unlikely(c >= sizeof(bands)) )
2015                 return -1;
2016         }
2017 
2018         var_SetFloat( p_mi, "equalizer-preamp", p_equalizer->f_preamp );
2019         var_SetString( p_mi, "equalizer-bands", bands );
2020     }
2021     var_SetString( p_mi, "audio-filter", p_equalizer ? "equalizer" : "" );
2022 
2023     audio_output_t *p_aout = input_resource_HoldAout( p_mi->input.p_resource );
2024     if( p_aout != NULL )
2025     {
2026         if( p_equalizer != NULL )
2027         {
2028             var_SetFloat( p_aout, "equalizer-preamp", p_equalizer->f_preamp );
2029             var_SetString( p_aout, "equalizer-bands", bands );
2030         }
2031 
2032         var_SetString( p_aout, "audio-filter", p_equalizer ? "equalizer" : "" );
2033         vlc_object_release( p_aout );
2034     }
2035 
2036     return 0;
2037 }
2038 
2039 static const char roles[][16] =
2040 {
2041     [libvlc_role_Music] =         "music",
2042     [libvlc_role_Video] =         "video",
2043     [libvlc_role_Communication] = "communication",
2044     [libvlc_role_Game] =          "game",
2045     [libvlc_role_Notification] =  "notification",
2046     [libvlc_role_Animation] =     "animation",
2047     [libvlc_role_Production] =    "production",
2048     [libvlc_role_Accessibility] = "accessibility",
2049     [libvlc_role_Test] =          "test",
2050 };
2051 
libvlc_media_player_set_role(libvlc_media_player_t * mp,unsigned role)2052 int libvlc_media_player_set_role(libvlc_media_player_t *mp, unsigned role)
2053 {
2054     if (role >= ARRAY_SIZE(roles)
2055      || var_SetString(mp, "role", roles[role]) != VLC_SUCCESS)
2056         return -1;
2057     return 0;
2058 }
2059 
libvlc_media_player_get_role(libvlc_media_player_t * mp)2060 int libvlc_media_player_get_role(libvlc_media_player_t *mp)
2061 {
2062     int ret = -1;
2063     char *str = var_GetString(mp, "role");
2064     if (str == NULL)
2065         return 0;
2066 
2067     for (size_t i = 0; i < ARRAY_SIZE(roles); i++)
2068         if (!strcmp(roles[i], str))
2069         {
2070             ret = i;
2071             break;
2072         }
2073 
2074     free(str);
2075     return ret;
2076 }
2077