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