1 /*****************************************************************************
2 * player.c: Player interface
3 *****************************************************************************
4 * Copyright © 2018 VLC authors and VideoLAN
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19 *****************************************************************************/
25 #include <vlc_common.h>
28 #include <vlc_interface.h>
29 #include <vlc_renderer_discovery.h>
31 #include <vlc_vector.h>
32 #include <vlc_atomic.h>
36 #include "input_internal.h"
38 #include "../audio_output/aout_internal.h"
40 #define RETRY_TIMEOUT_BASE VLC_TICK_FROM_MS(100)
41 #define RETRY_TIMEOUT_MAX VLC_TICK_FROM_MS(3200)
43 static_assert(VLC_PLAYER_CAP_SEEK
== VLC_INPUT_CAPABILITIES_SEEKABLE
&&
44 VLC_PLAYER_CAP_PAUSE
== VLC_INPUT_CAPABILITIES_PAUSEABLE
&&
45 VLC_PLAYER_CAP_CHANGE_RATE
== VLC_INPUT_CAPABILITIES_CHANGE_RATE
&&
46 VLC_PLAYER_CAP_REWIND
== VLC_INPUT_CAPABILITIES_REWINDABLE
,
47 "player/input capabilities mismatch");
49 static_assert(VLC_PLAYER_TITLE_MENU
== INPUT_TITLE_MENU
&&
50 VLC_PLAYER_TITLE_INTERACTIVE
== INPUT_TITLE_INTERACTIVE
,
51 "player/input title flag mismatch");
53 #define GAPLESS 0 /* TODO */
55 typedef struct VLC_VECTOR(struct vlc_player_program
*)
56 vlc_player_program_vector
;
58 typedef struct VLC_VECTOR(struct vlc_player_track
*)
59 vlc_player_track_vector
;
61 struct vlc_player_listener_id
63 const struct vlc_player_cbs
*cbs
;
68 struct vlc_player_vout_listener_id
70 const struct vlc_player_vout_cbs
*cbs
;
75 struct vlc_player_aout_listener_id
77 const struct vlc_player_aout_cbs
*cbs
;
82 struct vlc_player_title_list
86 struct vlc_player_title array
[];
89 struct vlc_player_input
91 input_thread_t
*thread
;
95 enum vlc_player_state state
;
96 enum vlc_player_error error
;
106 float signal_quality
;
107 float signal_strength
;
110 struct input_stats_t stats
;
112 vlc_tick_t audio_delay
;
113 vlc_tick_t subtitle_delay
;
117 vlc_tick_t audio_time
;
118 vlc_tick_t subtitle_time
;
121 vlc_player_program_vector program_vector
;
122 vlc_player_track_vector video_track_vector
;
123 vlc_player_track_vector audio_track_vector
;
124 vlc_player_track_vector spu_track_vector
;
125 struct vlc_player_track
*teletext_menu
;
127 struct vlc_player_title_list
*titles
;
129 size_t title_selected
;
130 size_t chapter_selected
;
132 struct vlc_list node
;
134 bool teletext_enabled
;
135 bool teletext_transparent
;
136 unsigned teletext_page
;
148 struct vlc_common_members obj
;
150 vlc_mutex_t aout_listeners_lock
;
151 vlc_mutex_t vout_listeners_lock
;
152 vlc_cond_t start_delay_cond
;
154 enum vlc_player_media_stopped_action media_stopped_action
;
157 const struct vlc_player_media_provider
*media_provider
;
158 void *media_provider_data
;
163 struct vlc_list listeners
;
164 struct vlc_list aout_listeners
;
165 struct vlc_list vout_listeners
;
167 input_resource_t
*resource
;
168 vlc_renderer_item_t
*renderer
;
171 struct vlc_player_input
*input
;
173 bool releasing_media
;
175 input_item_t
*next_media
;
177 struct vlc_player_input
*next_input
;
180 enum vlc_player_state global_state
;
183 unsigned error_count
;
191 struct vlc_list inputs
;
192 struct vlc_list stopping_inputs
;
193 struct vlc_list joinable_inputs
;
197 #define vlc_player_SendEvent(player, event, ...) do { \
198 vlc_player_listener_id *listener; \
199 vlc_list_foreach(listener, &player->listeners, node) \
201 if (listener->cbs->event) \
202 listener->cbs->event(player, ##__VA_ARGS__, listener->cbs_data); \
206 #define vlc_player_aout_SendEvent(player, event, ...) do { \
207 vlc_mutex_lock(&player->aout_listeners_lock); \
208 vlc_player_aout_listener_id *listener; \
209 vlc_list_foreach(listener, &player->aout_listeners, node) \
211 if (listener->cbs->event) \
212 listener->cbs->event(player, ##__VA_ARGS__, listener->cbs_data); \
214 vlc_mutex_unlock(&player->aout_listeners_lock); \
217 #define vlc_player_vout_SendEvent(player, event, ...) do { \
218 vlc_mutex_lock(&player->vout_listeners_lock); \
219 vlc_player_vout_listener_id *listener; \
220 vlc_list_foreach(listener, &player->vout_listeners, node) \
222 if (listener->cbs->event) \
223 listener->cbs->event(player, ##__VA_ARGS__, listener->cbs_data); \
225 vlc_mutex_unlock(&player->vout_listeners_lock); \
229 #define vlc_player_foreach_inputs(it) \
230 for (struct vlc_player_input *it = player->input; \
232 it = (it == player->input ? player->next_input : NULL))
234 #define vlc_player_foreach_inputs(it) \
235 for (struct vlc_player_input *it = player->input; it != NULL; it = NULL)
239 input_thread_Events(input_thread_t
*, const struct vlc_input_event
*, void *);
241 vlc_player_input_HandleState(struct vlc_player_input
*, enum vlc_player_state
);
243 vlc_player_VoutCallback(vlc_object_t
*this, const char *var
,
244 vlc_value_t oldval
, vlc_value_t newval
, void *data
);
246 vlc_player_VoutOSDCallback(vlc_object_t
*this, const char *var
,
247 vlc_value_t oldval
, vlc_value_t newval
, void *data
);
250 vlc_player_assert_locked(vlc_player_t
*player
)
253 vlc_mutex_assert(&player
->lock
);
256 static inline struct vlc_player_input
*
257 vlc_player_get_input_locked(vlc_player_t
*player
)
259 vlc_player_assert_locked(player
);
260 return player
->input
;
263 static vout_thread_t
**
264 vlc_player_vout_OSDHoldAll(vlc_player_t
*player
, size_t *count
)
266 vout_thread_t
**vouts
= vlc_player_vout_HoldAll(player
, count
);
268 for (size_t i
= 0; i
< *count
; ++i
)
270 vout_FlushSubpictureChannel(vouts
[i
], VOUT_SPU_CHANNEL_OSD
);
271 vout_FlushSubpictureChannel(vouts
[i
], VOUT_SPU_CHANNEL_OSD_HSLIDER
);
272 vout_FlushSubpictureChannel(vouts
[i
], VOUT_SPU_CHANNEL_OSD_HSLIDER
);
278 vlc_player_vout_OSDReleaseAll(vlc_player_t
*player
, vout_thread_t
**vouts
,
281 for (size_t i
= 0; i
< count
; ++i
)
282 vlc_object_release(vouts
[i
]);
288 vouts_osd_Message(vout_thread_t
**vouts
, size_t count
, const char *fmt
, ...)
292 for (size_t i
= 0; i
< count
; ++i
)
293 vout_OSDMessageVa(vouts
[i
], VOUT_SPU_CHANNEL_OSD
, fmt
, args
);
298 vouts_osd_Icon(vout_thread_t
**vouts
, size_t count
, short type
)
300 for (size_t i
= 0; i
< count
; ++i
)
301 vout_OSDIcon(vouts
[i
], VOUT_SPU_CHANNEL_OSD
, type
);
305 vouts_osd_Slider(vout_thread_t
**vouts
, size_t count
, int position
, short type
)
307 int channel
= type
== OSD_HOR_SLIDER
?
308 VOUT_SPU_CHANNEL_OSD_HSLIDER
: VOUT_SPU_CHANNEL_OSD_VSLIDER
;
309 for (size_t i
= 0; i
< count
; ++i
)
310 vout_OSDSlider(vouts
[i
], channel
, position
, type
);
314 vlc_player_vout_OSDMessage(vlc_player_t
*player
, const char *fmt
, ...)
317 vout_thread_t
**vouts
= vlc_player_vout_OSDHoldAll(player
, &count
);
321 for (size_t i
= 0; i
< count
; ++i
)
322 vout_OSDMessageVa(vouts
[i
], VOUT_SPU_CHANNEL_OSD
, fmt
, args
);
325 vlc_player_vout_OSDReleaseAll(player
, vouts
, count
);
329 vlc_player_vout_OSDIcon(vlc_player_t
*player
, short type
)
332 vout_thread_t
**vouts
= vlc_player_vout_OSDHoldAll(player
, &count
);
334 vouts_osd_Icon(vouts
, count
, type
);
336 vlc_player_vout_OSDReleaseAll(player
, vouts
, count
);
340 vlc_player_program_DupTitle(int id
, const char *title
)
345 else if (asprintf(&dup
, "%d", id
) == -1)
350 static struct vlc_player_program
*
351 vlc_player_program_New(int id
, const char *name
)
353 struct vlc_player_program
*prgm
= malloc(sizeof(*prgm
));
356 prgm
->name
= vlc_player_program_DupTitle(id
, name
);
363 prgm
->selected
= prgm
->scrambled
= false;
369 vlc_player_program_Update(struct vlc_player_program
*prgm
, int id
,
372 free((char *)prgm
->name
);
373 prgm
->name
= vlc_player_program_DupTitle(id
, name
);
374 return prgm
->name
!= NULL
? VLC_SUCCESS
: VLC_ENOMEM
;
377 struct vlc_player_program
*
378 vlc_player_program_Dup(const struct vlc_player_program
*src
)
380 struct vlc_player_program
*dup
=
381 vlc_player_program_New(src
->group_id
, src
->name
);
385 dup
->selected
= src
->selected
;
386 dup
->scrambled
= src
->scrambled
;
391 vlc_player_program_Delete(struct vlc_player_program
*prgm
)
393 free((char *)prgm
->name
);
397 static struct vlc_player_program
*
398 vlc_player_program_vector_FindById(vlc_player_program_vector
*vec
, int id
,
401 for (size_t i
= 0; i
< vec
->size
; ++i
)
403 struct vlc_player_program
*prgm
= vec
->data
[i
];
404 if (prgm
->group_id
== id
)
414 static struct vlc_player_track
*
415 vlc_player_track_New(vlc_es_id_t
*id
, const char *name
, const es_format_t
*fmt
)
417 struct vlc_player_track
*track
= malloc(sizeof(*track
));
420 track
->name
= strdup(name
);
427 int ret
= es_format_Copy(&track
->fmt
, fmt
);
428 if (ret
!= VLC_SUCCESS
)
430 free((char *)track
->name
);
434 track
->es_id
= vlc_es_id_Hold(id
);
435 track
->selected
= false;
440 struct vlc_player_track
*
441 vlc_player_track_Dup(const struct vlc_player_track
*src
)
443 struct vlc_player_track
*dup
=
444 vlc_player_track_New(src
->es_id
, src
->name
, &src
->fmt
);
448 dup
->selected
= src
->selected
;
453 vlc_player_track_Delete(struct vlc_player_track
*track
)
455 es_format_Clean(&track
->fmt
);
456 free((char *)track
->name
);
457 vlc_es_id_Release(track
->es_id
);
462 vlc_player_track_Update(struct vlc_player_track
*track
,
463 const char *name
, const es_format_t
*fmt
)
465 if (strcmp(name
, track
->name
) != 0)
467 char *dup
= strdup(name
);
470 free((char *)track
->name
);
475 int ret
= es_format_Copy(&fmtdup
, fmt
);
476 if (ret
!= VLC_SUCCESS
)
479 es_format_Clean(&track
->fmt
);
484 struct vlc_player_title_list
*
485 vlc_player_title_list_Hold(struct vlc_player_title_list
*titles
)
487 vlc_atomic_rc_inc(&titles
->rc
);
492 vlc_player_title_list_Release(struct vlc_player_title_list
*titles
)
494 if (!vlc_atomic_rc_dec(&titles
->rc
))
496 for (size_t title_idx
= 0; title_idx
< titles
->count
; ++title_idx
)
498 struct vlc_player_title
*title
= &titles
->array
[title_idx
];
499 free((char *)title
->name
);
500 for (size_t chapter_idx
= 0; chapter_idx
< title
->chapter_count
;
503 const struct vlc_player_chapter
*chapter
=
504 &title
->chapters
[chapter_idx
];
505 free((char *)chapter
->name
);
507 free((void *)title
->chapters
);
513 input_title_GetName(const struct input_title_t
*input_title
, int idx
,
517 char length_str
[MSTRTIME_MAX_SIZE
+ sizeof(" []")];
519 if (input_title
->i_length
> 0)
521 strcpy(length_str
, " [");
522 secstotimestr(&length_str
[2], SEC_FROM_VLC_TICK(input_title
->i_length
));
523 strcat(length_str
, "]");
526 length_str
[0] = '\0';
529 if (input_title
->psz_name
&& input_title
->psz_name
[0] != '\0')
530 ret
= asprintf(&dup
, "%s%s", input_title
->psz_name
, length_str
);
532 ret
= asprintf(&dup
, _("Title %i%s"), idx
+ title_offset
, length_str
);
539 seekpoint_GetName(seekpoint_t
*seekpoint
, int idx
, int chapter_offset
)
541 if (seekpoint
->psz_name
&& seekpoint
->psz_name
[0] != '\0' )
542 return strdup(seekpoint
->psz_name
);
545 int ret
= asprintf(&dup
, _("Chapter %i"), idx
+ chapter_offset
);
551 static struct vlc_player_title_list
*
552 vlc_player_title_list_Create(input_title_t
*const *array
, size_t count
,
553 int title_offset
, int chapter_offset
)
558 /* Allocate the struct + the whole list */
560 if (mul_overflow(count
, sizeof(struct vlc_player_title
), &size
))
562 if (add_overflow(size
, sizeof(struct vlc_player_title_list
), &size
))
564 struct vlc_player_title_list
*titles
= malloc(size
);
568 vlc_atomic_rc_init(&titles
->rc
);
569 titles
->count
= count
;
571 for (size_t title_idx
= 0; title_idx
< titles
->count
; ++title_idx
)
573 const struct input_title_t
*input_title
= array
[title_idx
];
574 struct vlc_player_title
*title
= &titles
->array
[title_idx
];
576 title
->name
= input_title_GetName(input_title
, title_idx
, title_offset
);
577 title
->length
= input_title
->i_length
;
578 title
->flags
= input_title
->i_flags
;
579 const size_t seekpoint_count
= input_title
->i_seekpoint
> 0 ?
580 input_title
->i_seekpoint
: 0;
581 title
->chapter_count
= seekpoint_count
;
583 struct vlc_player_chapter
*chapters
= title
->chapter_count
== 0 ? NULL
:
584 vlc_alloc(title
->chapter_count
, sizeof(*chapters
));
588 for (size_t chapter_idx
= 0; chapter_idx
< title
->chapter_count
;
591 struct vlc_player_chapter
*chapter
= &chapters
[chapter_idx
];
592 seekpoint_t
*seekpoint
= input_title
->seekpoint
[chapter_idx
];
594 chapter
->name
= seekpoint_GetName(seekpoint
, chapter_idx
,
596 chapter
->time
= seekpoint
->i_time_offset
;
597 if (!chapter
->name
) /* Will trigger the error path */
598 title
->chapter_count
= chapter_idx
;
601 else if (seekpoint_count
> 0) /* Will trigger the error path */
602 title
->chapter_count
= 0;
604 title
->chapters
= chapters
;
606 if (!title
->name
|| seekpoint_count
!= title
->chapter_count
)
608 /* Release titles up to title_idx */
609 titles
->count
= title_idx
;
610 vlc_player_title_list_Release(titles
);
617 const struct vlc_player_title
*
618 vlc_player_title_list_GetAt(struct vlc_player_title_list
*titles
, size_t idx
)
620 assert(idx
< titles
->count
);
621 return &titles
->array
[idx
];
625 vlc_player_title_list_GetCount(struct vlc_player_title_list
*titles
)
627 return titles
->count
;
630 static struct vlc_player_input
*
631 vlc_player_input_New(vlc_player_t
*player
, input_item_t
*item
)
633 struct vlc_player_input
*input
= malloc(sizeof(*input
));
637 input
->player
= player
;
638 input
->started
= false;
640 input
->state
= VLC_PLAYER_STATE_STOPPED
;
641 input
->error
= VLC_PLAYER_ERROR_NONE
;
643 input
->capabilities
= 0;
644 input
->length
= input
->time
= VLC_TICK_INVALID
;
645 input
->position
= 0.f
;
647 input
->recording
= false;
650 input
->signal_quality
= input
->signal_strength
= -1.f
;
652 memset(&input
->stats
, 0, sizeof(input
->stats
));
654 input
->audio_delay
= input
->subtitle_delay
= 0;
656 input
->subsync
.audio_time
=
657 input
->subsync
.subtitle_time
= VLC_TICK_INVALID
;
659 vlc_vector_init(&input
->program_vector
);
660 vlc_vector_init(&input
->video_track_vector
);
661 vlc_vector_init(&input
->audio_track_vector
);
662 vlc_vector_init(&input
->spu_track_vector
);
663 input
->teletext_menu
= NULL
;
665 input
->titles
= NULL
;
666 input
->title_selected
= input
->chapter_selected
= 0;
668 input
->teletext_enabled
= input
->teletext_transparent
= false;
669 input
->teletext_page
= 0;
671 input
->abloop_state
[0].set
= input
->abloop_state
[1].set
= false;
673 input
->thread
= input_Create(player
, input_thread_Events
, input
, item
,
674 NULL
, player
->resource
, player
->renderer
);
684 vlc_player_input_Delete(struct vlc_player_input
*input
)
686 assert(input
->titles
== NULL
);
687 assert(input
->program_vector
.size
== 0);
688 assert(input
->video_track_vector
.size
== 0);
689 assert(input
->audio_track_vector
.size
== 0);
690 assert(input
->spu_track_vector
.size
== 0);
691 assert(input
->teletext_menu
== NULL
);
693 vlc_vector_destroy(&input
->program_vector
);
694 vlc_vector_destroy(&input
->video_track_vector
);
695 vlc_vector_destroy(&input
->audio_track_vector
);
696 vlc_vector_destroy(&input
->spu_track_vector
);
698 input_Close(input
->thread
);
703 vlc_player_input_Start(struct vlc_player_input
*input
)
705 int ret
= input_Start(input
->thread
);
706 if (ret
!= VLC_SUCCESS
)
708 input
->started
= true;
713 vlc_player_PrepareNextMedia(vlc_player_t
*player
)
715 vlc_player_assert_locked(player
);
717 if (!player
->media_provider
718 || player
->media_stopped_action
!= VLC_PLAYER_MEDIA_STOPPED_CONTINUE
719 || player
->has_next_media
)
722 assert(player
->next_media
== NULL
);
724 player
->media_provider
->get_next(player
, player
->media_provider_data
);
725 player
->has_next_media
= true;
729 vlc_player_OpenNextMedia(vlc_player_t
*player
)
731 assert(player
->input
== NULL
);
733 player
->has_next_media
= false;
735 int ret
= VLC_SUCCESS
;
736 if (player
->releasing_media
)
738 assert(player
->media
);
739 input_item_Release(player
->media
);
740 player
->media
= NULL
;
741 player
->releasing_media
= false;
745 if (!player
->next_media
)
749 input_item_Release(player
->media
);
750 player
->media
= player
->next_media
;
751 player
->next_media
= NULL
;
753 player
->input
= vlc_player_input_New(player
, player
->media
);
756 input_item_Release(player
->media
);
757 player
->media
= NULL
;
761 vlc_player_SendEvent(player
, on_current_media_changed
, player
->media
);
766 vlc_player_CancelWaitError(vlc_player_t
*player
)
768 if (player
->error_count
!= 0)
770 player
->error_count
= 0;
771 vlc_cond_signal(&player
->start_delay_cond
);
776 vlc_list_HasInput(struct vlc_list
*list
, struct vlc_player_input
*input
)
778 struct vlc_player_input
*other_input
;
779 vlc_list_foreach(other_input
, list
, node
)
781 if (other_input
== input
)
788 vlc_player_destructor_AddInput(vlc_player_t
*player
,
789 struct vlc_player_input
*input
)
793 input
->started
= false;
794 /* Add this input to the stop list: it will be stopped by the
795 * destructor thread */
796 assert(!vlc_list_HasInput(&player
->destructor
.stopping_inputs
, input
));
797 assert(!vlc_list_HasInput(&player
->destructor
.joinable_inputs
, input
));
798 vlc_list_append(&input
->node
, &player
->destructor
.inputs
);
802 /* Add this input to the joinable list: it will be deleted by the
803 * destructor thread */
804 assert(!vlc_list_HasInput(&player
->destructor
.inputs
, input
));
805 assert(!vlc_list_HasInput(&player
->destructor
.joinable_inputs
, input
));
806 vlc_list_append(&input
->node
, &player
->destructor
.joinable_inputs
);
809 vlc_cond_signal(&input
->player
->destructor
.wait
);
813 vlc_player_destructor_AddStoppingInput(vlc_player_t
*player
,
814 struct vlc_player_input
*input
)
816 /* Add this input to the stopping list */
817 if (vlc_list_HasInput(&player
->destructor
.inputs
, input
))
818 vlc_list_remove(&input
->node
);
819 if (!vlc_list_HasInput(&player
->destructor
.stopping_inputs
, input
))
821 vlc_list_append(&input
->node
, &player
->destructor
.stopping_inputs
);
822 vlc_cond_signal(&input
->player
->destructor
.wait
);
827 vlc_player_destructor_AddJoinableInput(vlc_player_t
*player
,
828 struct vlc_player_input
*input
)
830 if (vlc_list_HasInput(&player
->destructor
.stopping_inputs
, input
))
831 vlc_list_remove(&input
->node
);
833 assert(!input
->started
);
834 vlc_player_destructor_AddInput(player
, input
);
837 static bool vlc_player_destructor_IsEmpty(vlc_player_t
*player
)
839 return vlc_list_is_empty(&player
->destructor
.inputs
)
840 && vlc_list_is_empty(&player
->destructor
.stopping_inputs
)
841 && vlc_list_is_empty(&player
->destructor
.joinable_inputs
);
845 vlc_player_destructor_Thread(void *data
)
847 vlc_player_t
*player
= data
;
849 vlc_mutex_lock(&player
->lock
);
851 /* Terminate this thread when the player is deleting (vlc_player_Delete()
852 * was called) and when all input_thread_t all stopped and released. */
853 while (!player
->deleting
854 || !vlc_player_destructor_IsEmpty(player
))
856 /* Wait for an input to stop or close. No while loop here since we want
857 * to leave this code path when the player is deleting. */
858 if (vlc_list_is_empty(&player
->destructor
.inputs
)
859 && vlc_list_is_empty(&player
->destructor
.joinable_inputs
))
860 vlc_cond_wait(&player
->destructor
.wait
, &player
->lock
);
862 struct vlc_player_input
*input
;
863 vlc_list_foreach(input
, &player
->destructor
.inputs
, node
)
865 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_STOPPING
);
866 vlc_player_destructor_AddStoppingInput(player
, input
);
868 input_Stop(input
->thread
);
871 bool keep_sout
= true;
872 const bool inputs_changed
=
873 !vlc_list_is_empty(&player
->destructor
.joinable_inputs
);
874 vlc_list_foreach(input
, &player
->destructor
.joinable_inputs
, node
)
876 keep_sout
= var_GetBool(input
->thread
, "sout-keep");
878 if (input
->state
== VLC_PLAYER_STATE_STOPPING
)
879 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_STOPPED
);
881 vlc_list_remove(&input
->node
);
882 vlc_player_input_Delete(input
);
887 const bool started
= player
->started
;
888 vlc_player_Unlock(player
);
890 input_resource_TerminateVout(player
->resource
);
892 input_resource_TerminateSout(player
->resource
);
893 vlc_player_Lock(player
);
896 vlc_mutex_unlock(&player
->lock
);
901 vlc_player_WaitRetryDelay(vlc_player_t
*player
)
903 if (player
->error_count
)
905 /* Delay the next opening in case of error to avoid busy loops */
906 vlc_tick_t delay
= RETRY_TIMEOUT_BASE
;
907 for (unsigned i
= 1; i
< player
->error_count
908 && delay
< RETRY_TIMEOUT_MAX
; ++i
)
909 delay
*= 2; /* Wait 100, 200, 400, 800, 1600 and finally 3200ms */
910 delay
+= vlc_tick_now();
912 while (player
->error_count
> 0
913 && vlc_cond_timedwait(&player
->start_delay_cond
, &player
->lock
,
915 if (player
->error_count
== 0)
916 return false; /* canceled */
922 vlc_player_input_HandleState(struct vlc_player_input
*input
,
923 enum vlc_player_state state
)
925 vlc_player_t
*player
= input
->player
;
927 /* The STOPPING state can be set earlier by the player. In that case,
928 * ignore all future events except the STOPPED one */
929 if (input
->state
== VLC_PLAYER_STATE_STOPPING
930 && state
!= VLC_PLAYER_STATE_STOPPED
)
933 input
->state
= state
;
935 /* Override the global state if the player is still playing and has a next
937 bool send_event
= player
->global_state
!= state
;
938 switch (input
->state
)
940 case VLC_PLAYER_STATE_STOPPED
:
941 assert(!input
->started
);
942 assert(input
!= player
->input
);
946 vlc_player_title_list_Release(input
->titles
);
947 input
->titles
= NULL
;
948 vlc_player_SendEvent(player
, on_titles_changed
, NULL
);
951 if (input
->error
!= VLC_PLAYER_ERROR_NONE
)
952 player
->error_count
++;
954 player
->error_count
= 0;
956 vlc_player_WaitRetryDelay(player
);
958 if (!player
->deleting
)
959 vlc_player_OpenNextMedia(player
);
961 player
->started
= false;
963 switch (player
->media_stopped_action
)
965 case VLC_PLAYER_MEDIA_STOPPED_EXIT
:
966 if (player
->input
&& player
->started
)
967 vlc_player_input_Start(player
->input
);
969 libvlc_Quit(player
->obj
.libvlc
);
971 case VLC_PLAYER_MEDIA_STOPPED_CONTINUE
:
972 if (player
->input
&& player
->started
)
973 vlc_player_input_Start(player
->input
);
979 send_event
= !player
->started
;
981 case VLC_PLAYER_STATE_STOPPING
:
982 input
->started
= false;
983 if (input
== player
->input
)
984 player
->input
= NULL
;
988 vlc_player_PrepareNextMedia(player
);
989 if (!player
->next_media
)
990 player
->started
= false;
992 send_event
= !player
->started
;
994 case VLC_PLAYER_STATE_STARTED
:
995 case VLC_PLAYER_STATE_PLAYING
:
996 if (player
->started
&&
997 player
->global_state
== VLC_PLAYER_STATE_PLAYING
)
1001 case VLC_PLAYER_STATE_PAUSED
:
1002 assert(player
->started
&& input
->started
);
1005 vlc_assert_unreachable();
1010 player
->global_state
= input
->state
;
1011 vlc_player_SendEvent(player
, on_state_changed
, player
->global_state
);
1016 vlc_player_GetProgramCount(vlc_player_t
*player
)
1018 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1020 return input
? input
->program_vector
.size
: 0;
1023 const struct vlc_player_program
*
1024 vlc_player_GetProgramAt(vlc_player_t
*player
, size_t index
)
1026 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1031 assert(index
< input
->program_vector
.size
);
1032 return input
->program_vector
.data
[index
];
1035 const struct vlc_player_program
*
1036 vlc_player_GetProgram(vlc_player_t
*player
, int id
)
1038 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1043 struct vlc_player_program
*prgm
=
1044 vlc_player_program_vector_FindById(&input
->program_vector
, id
, NULL
);
1049 vlc_player_vout_OSDProgram(vlc_player_t
*player
, const char *name
)
1051 vlc_player_vout_OSDMessage(player
, _("Program Service ID: %s"), name
);
1055 vlc_player_SelectProgram(vlc_player_t
*player
, int id
)
1057 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1061 const struct vlc_player_program
*prgm
=
1062 vlc_player_program_vector_FindById(&input
->program_vector
,
1066 input_ControlPushHelper(input
->thread
, INPUT_CONTROL_SET_PROGRAM
,
1067 &(vlc_value_t
) { .i_int
= id
});
1068 vlc_player_vout_OSDProgram(player
, prgm
->name
);
1073 vlc_player_CycleProgram(vlc_player_t
*player
, bool next
)
1075 size_t count
= vlc_player_GetProgramCount(player
);
1079 bool selected
= false;
1080 for (size_t i
= 0; i
< count
; ++i
)
1082 const struct vlc_player_program
*prgm
=
1083 vlc_player_GetProgramAt(player
, i
);
1086 /* Only one program can be selected at a time */
1093 if (next
&& index
+ 1 == count
) /* First program */
1095 else if (!next
&& index
== 0) /* Last program */
1097 else /* Next or Previous program */
1098 index
= index
+ (next
? 1 : -1);
1100 const struct vlc_player_program
*prgm
=
1101 vlc_player_GetProgramAt(player
, index
);
1103 vlc_player_SelectProgram(player
, prgm
->group_id
);
1107 vlc_player_SelectNextProgram(vlc_player_t
*player
)
1109 vlc_player_CycleProgram(player
, true);
1113 vlc_player_SelectPrevProgram(vlc_player_t
*player
)
1115 vlc_player_CycleProgram(player
, false);
1119 vlc_player_input_HandleProgramEvent(struct vlc_player_input
*input
,
1120 const struct vlc_input_event_program
*ev
)
1122 vlc_player_t
*player
= input
->player
;
1123 struct vlc_player_program
*prgm
;
1124 vlc_player_program_vector
*vec
= &input
->program_vector
;
1128 case VLC_INPUT_PROGRAM_ADDED
:
1129 prgm
= vlc_player_program_New(ev
->id
, ev
->title
);
1133 if (!vlc_vector_push(vec
, prgm
))
1135 vlc_player_program_Delete(prgm
);
1138 vlc_player_SendEvent(player
, on_program_list_changed
,
1139 VLC_PLAYER_LIST_ADDED
, prgm
);
1141 case VLC_INPUT_PROGRAM_DELETED
:
1144 prgm
= vlc_player_program_vector_FindById(vec
, ev
->id
, &idx
);
1147 vlc_player_SendEvent(player
, on_program_list_changed
,
1148 VLC_PLAYER_LIST_REMOVED
, prgm
);
1149 vlc_vector_remove(vec
, idx
);
1150 vlc_player_program_Delete(prgm
);
1154 case VLC_INPUT_PROGRAM_UPDATED
:
1155 case VLC_INPUT_PROGRAM_SCRAMBLED
:
1156 prgm
= vlc_player_program_vector_FindById(vec
, ev
->id
, NULL
);
1159 if (ev
->action
== VLC_INPUT_PROGRAM_UPDATED
)
1161 if (vlc_player_program_Update(prgm
, ev
->id
, ev
->title
) != 0)
1165 prgm
->scrambled
= ev
->scrambled
;
1166 vlc_player_SendEvent(player
, on_program_list_changed
,
1167 VLC_PLAYER_LIST_UPDATED
, prgm
);
1169 case VLC_INPUT_PROGRAM_SELECTED
:
1171 int unselected_id
= -1, selected_id
= -1;
1172 vlc_vector_foreach(prgm
, vec
)
1174 if (prgm
->group_id
== ev
->id
)
1176 if (!prgm
->selected
)
1178 assert(selected_id
== -1);
1179 prgm
->selected
= true;
1180 selected_id
= prgm
->group_id
;
1187 assert(unselected_id
== -1);
1188 prgm
->selected
= false;
1189 unselected_id
= prgm
->group_id
;
1193 if (unselected_id
!= -1 || selected_id
!= -1)
1194 vlc_player_SendEvent(player
, on_program_selection_changed
,
1195 unselected_id
, selected_id
);
1199 vlc_assert_unreachable();
1203 static inline vlc_player_track_vector
*
1204 vlc_player_input_GetTrackVector(struct vlc_player_input
*input
,
1205 enum es_format_category_e cat
)
1210 return &input
->video_track_vector
;
1212 return &input
->audio_track_vector
;
1214 return &input
->spu_track_vector
;
1220 static struct vlc_player_track
*
1221 vlc_player_track_vector_FindById(vlc_player_track_vector
*vec
, vlc_es_id_t
*id
,
1224 for (size_t i
= 0; i
< vec
->size
; ++i
)
1226 struct vlc_player_track
*track
= vec
->data
[i
];
1227 if (track
->es_id
== id
)
1238 vlc_player_GetTrackCount(vlc_player_t
*player
, enum es_format_category_e cat
)
1240 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1244 vlc_player_track_vector
*vec
= vlc_player_input_GetTrackVector(input
, cat
);
1250 const struct vlc_player_track
*
1251 vlc_player_GetTrackAt(vlc_player_t
*player
, enum es_format_category_e cat
,
1254 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1258 vlc_player_track_vector
*vec
= vlc_player_input_GetTrackVector(input
, cat
);
1261 assert(index
< vec
->size
);
1262 return vec
->data
[index
];
1265 const struct vlc_player_track
*
1266 vlc_player_GetTrack(vlc_player_t
*player
, vlc_es_id_t
*id
)
1268 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1272 vlc_player_track_vector
*vec
=
1273 vlc_player_input_GetTrackVector(input
, vlc_es_id_GetCat(id
));
1276 return vlc_player_track_vector_FindById(vec
, id
, NULL
);
1279 static inline const char *
1280 es_format_category_to_string(enum es_format_category_e cat
)
1284 case VIDEO_ES
: return "Video";
1285 case AUDIO_ES
: return "Audio";
1286 case SPU_ES
: return "Subtitle";
1287 default: return NULL
;
1292 vlc_player_vout_OSDTrack(vlc_player_t
*player
, vlc_es_id_t
*id
, bool select
)
1294 enum es_format_category_e cat
= vlc_es_id_GetCat(id
);
1295 const struct vlc_player_track
*track
= vlc_player_GetTrack(player
, id
);
1296 if (!track
&& select
)
1299 const char *cat_name
= es_format_category_to_string(cat
);
1301 const char *track_name
= select
? track
->name
: _("N/A");
1302 vlc_player_vout_OSDMessage(player
, _("%s track: %s"), cat_name
, track_name
);
1306 vlc_player_SelectTrack(vlc_player_t
*player
, vlc_es_id_t
*id
)
1308 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1312 input_ControlPushEsHelper(input
->thread
, INPUT_CONTROL_SET_ES
, id
);
1313 vlc_player_vout_OSDTrack(player
, id
, true);
1317 vlc_player_CycleTrack(vlc_player_t
*player
, enum es_format_category_e cat
,
1320 size_t count
= vlc_player_GetTrackCount(player
, cat
);
1325 bool selected
= false;
1326 for (size_t i
= 0; i
< count
; ++i
)
1328 const struct vlc_player_track
*track
=
1329 vlc_player_GetTrackAt(player
, cat
, i
);
1331 if (track
->selected
)
1335 /* Can't cycle through tracks if there are more than one
1346 /* No track selected: select the first or the last track */
1347 index
= next
? 0 : count
- 1;
1352 /* Unselect if we reach the end of the cycle */
1353 if ((next
&& index
+ 1 == count
) || (!next
&& index
== 0))
1355 else /* Switch to the next or previous track */
1356 index
= index
+ (next
? 1 : -1);
1359 const struct vlc_player_track
*track
=
1360 vlc_player_GetTrackAt(player
, cat
, index
);
1362 vlc_player_SelectTrack(player
, track
->es_id
);
1364 vlc_player_UnselectTrack(player
, track
->es_id
);
1368 vlc_player_SelectNextTrack(vlc_player_t
*player
,
1369 enum es_format_category_e cat
)
1371 vlc_player_CycleTrack(player
, cat
, true);
1375 vlc_player_SelectPrevTrack(vlc_player_t
*player
,
1376 enum es_format_category_e cat
)
1378 vlc_player_CycleTrack(player
, cat
, false);
1382 vlc_player_UnselectTrack(vlc_player_t
*player
, vlc_es_id_t
*id
)
1384 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1388 input_ControlPushEsHelper(input
->thread
, INPUT_CONTROL_UNSET_ES
, id
);
1389 vlc_player_vout_OSDTrack(player
, id
, false);
1393 vlc_player_RestartTrack(vlc_player_t
*player
, vlc_es_id_t
*id
)
1395 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1398 input_ControlPushEsHelper(input
->thread
, INPUT_CONTROL_RESTART_ES
, id
);
1402 vlc_player_SelectDefaultTrack(vlc_player_t
*player
,
1403 enum es_format_category_e cat
, const char *lang
)
1405 vlc_player_assert_locked(player
);
1406 /* TODO */ (void) cat
; (void) lang
;
1410 vlc_player_input_HandleTeletextMenu(struct vlc_player_input
*input
,
1411 const struct vlc_input_event_es
*ev
)
1413 vlc_player_t
*player
= input
->player
;
1416 case VLC_INPUT_ES_ADDED
:
1417 if (input
->teletext_menu
)
1419 msg_Warn(player
, "Can't handle more than one teletext menu "
1420 "track. Using the last one.");
1421 vlc_player_track_Delete(input
->teletext_menu
);
1423 input
->teletext_menu
= vlc_player_track_New(ev
->id
, ev
->title
,
1425 if (!input
->teletext_menu
)
1428 vlc_player_SendEvent(player
, on_teletext_menu_changed
, true);
1430 case VLC_INPUT_ES_DELETED
:
1432 if (input
->teletext_menu
&& input
->teletext_menu
->es_id
== ev
->id
)
1434 assert(!input
->teletext_enabled
);
1436 vlc_player_track_Delete(input
->teletext_menu
);
1437 input
->teletext_menu
= NULL
;
1438 vlc_player_SendEvent(player
, on_teletext_menu_changed
, false);
1442 case VLC_INPUT_ES_UPDATED
:
1444 case VLC_INPUT_ES_SELECTED
:
1445 case VLC_INPUT_ES_UNSELECTED
:
1446 if (input
->teletext_menu
->es_id
== ev
->id
)
1448 input
->teletext_enabled
= ev
->action
== VLC_INPUT_ES_SELECTED
;
1449 vlc_player_SendEvent(player
, on_teletext_enabled_changed
,
1450 input
->teletext_enabled
);
1454 vlc_assert_unreachable();
1459 vlc_player_SetTeletextEnabled(vlc_player_t
*player
, bool enabled
)
1461 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1462 if (!input
|| !input
->teletext_menu
)
1465 vlc_player_SelectTrack(player
, input
->teletext_menu
->es_id
);
1467 vlc_player_UnselectTrack(player
, input
->teletext_menu
->es_id
);
1471 vlc_player_SelectTeletextPage(vlc_player_t
*player
, unsigned page
)
1473 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1474 if (!input
|| !input
->teletext_menu
)
1477 input_ControlPush(input
->thread
, INPUT_CONTROL_SET_VBI_PAGE
,
1478 &(input_control_param_t
) {
1479 .vbi_page
.id
= input
->teletext_menu
->es_id
,
1480 .vbi_page
.page
= page
,
1485 vlc_player_SetTeletextTransparency(vlc_player_t
*player
, bool enabled
)
1487 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1488 if (!input
|| !input
->teletext_menu
)
1491 input_ControlPush(input
->thread
, INPUT_CONTROL_SET_VBI_TRANSPARENCY
,
1492 &(input_control_param_t
) {
1493 .vbi_transparency
.id
= input
->teletext_menu
->es_id
,
1494 .vbi_transparency
.enabled
= enabled
,
1499 vlc_player_HasTeletextMenu(vlc_player_t
*player
)
1501 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1502 return input
&& input
->teletext_menu
;
1506 vlc_player_IsTeletextEnabled(vlc_player_t
*player
)
1508 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1509 if (input
&& input
->teletext_enabled
)
1511 assert(input
->teletext_menu
);
1518 vlc_player_GetTeletextPage(vlc_player_t
*player
)
1520 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1521 return vlc_player_IsTeletextEnabled(player
) ? input
->teletext_page
: 0;
1525 vlc_player_IsTeletextTransparent(vlc_player_t
*player
)
1527 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1528 return vlc_player_IsTeletextEnabled(player
) && input
->teletext_transparent
;
1532 vlc_player_input_HandleEsEvent(struct vlc_player_input
*input
,
1533 const struct vlc_input_event_es
*ev
)
1535 assert(ev
->id
&& ev
->title
&& ev
->fmt
);
1537 if (ev
->fmt
->i_cat
== SPU_ES
&& ev
->fmt
->i_codec
== VLC_CODEC_TELETEXT
1538 && (ev
->fmt
->subs
.teletext
.i_magazine
== 1
1539 || ev
->fmt
->subs
.teletext
.i_magazine
== -1))
1541 vlc_player_input_HandleTeletextMenu(input
, ev
);
1545 vlc_player_track_vector
*vec
=
1546 vlc_player_input_GetTrackVector(input
, ev
->fmt
->i_cat
);
1548 return; /* UNKNOWN_ES or DATA_ES not handled */
1550 vlc_player_t
*player
= input
->player
;
1551 struct vlc_player_track
*track
;
1554 case VLC_INPUT_ES_ADDED
:
1555 track
= vlc_player_track_New(ev
->id
, ev
->title
, ev
->fmt
);
1559 if (!vlc_vector_push(vec
, track
))
1561 vlc_player_track_Delete(track
);
1564 vlc_player_SendEvent(player
, on_track_list_changed
,
1565 VLC_PLAYER_LIST_ADDED
, track
);
1567 case VLC_INPUT_ES_DELETED
:
1570 track
= vlc_player_track_vector_FindById(vec
, ev
->id
, &idx
);
1573 vlc_player_SendEvent(player
, on_track_list_changed
,
1574 VLC_PLAYER_LIST_REMOVED
, track
);
1575 vlc_vector_remove(vec
, idx
);
1576 vlc_player_track_Delete(track
);
1580 case VLC_INPUT_ES_UPDATED
:
1581 track
= vlc_player_track_vector_FindById(vec
, ev
->id
, NULL
);
1584 if (vlc_player_track_Update(track
, ev
->title
, ev
->fmt
) != 0)
1586 vlc_player_SendEvent(player
, on_track_list_changed
,
1587 VLC_PLAYER_LIST_UPDATED
, track
);
1589 case VLC_INPUT_ES_SELECTED
:
1590 track
= vlc_player_track_vector_FindById(vec
, ev
->id
, NULL
);
1593 track
->selected
= true;
1594 vlc_player_SendEvent(player
, on_track_selection_changed
,
1595 NULL
, track
->es_id
);
1598 case VLC_INPUT_ES_UNSELECTED
:
1599 track
= vlc_player_track_vector_FindById(vec
, ev
->id
, NULL
);
1602 track
->selected
= false;
1603 vlc_player_SendEvent(player
, on_track_selection_changed
,
1604 track
->es_id
, NULL
);
1608 vlc_assert_unreachable();
1613 vlc_player_input_HandleTitleEvent(struct vlc_player_input
*input
,
1614 const struct vlc_input_event_title
*ev
)
1616 vlc_player_t
*player
= input
->player
;
1619 case VLC_INPUT_TITLE_NEW_LIST
:
1621 input_thread_private_t
*input_th
= input_priv(input
->thread
);
1622 const int title_offset
= input_th
->i_title_offset
;
1623 const int chapter_offset
= input_th
->i_seekpoint_offset
;
1626 vlc_player_title_list_Release(input
->titles
);
1627 input
->title_selected
= input
->chapter_selected
= 0;
1629 vlc_player_title_list_Create(ev
->list
.array
, ev
->list
.count
,
1630 title_offset
, chapter_offset
);
1631 vlc_player_SendEvent(player
, on_titles_changed
, input
->titles
);
1633 vlc_player_SendEvent(player
, on_title_selection_changed
,
1634 &input
->titles
->array
[0], 0);
1637 case VLC_INPUT_TITLE_SELECTED
:
1639 return; /* a previous VLC_INPUT_TITLE_NEW_LIST failed */
1640 assert(ev
->selected_idx
< input
->titles
->count
);
1641 input
->title_selected
= ev
->selected_idx
;
1642 vlc_player_SendEvent(player
, on_title_selection_changed
,
1643 &input
->titles
->array
[input
->title_selected
],
1644 input
->title_selected
);
1647 vlc_assert_unreachable();
1652 vlc_player_input_HandleChapterEvent(struct vlc_player_input
*input
,
1653 const struct vlc_input_event_chapter
*ev
)
1655 vlc_player_t
*player
= input
->player
;
1656 if (!input
->titles
|| ev
->title
< 0 || ev
->seekpoint
< 0)
1657 return; /* a previous VLC_INPUT_TITLE_NEW_LIST failed */
1659 assert((size_t)ev
->title
< input
->titles
->count
);
1660 const struct vlc_player_title
*title
= &input
->titles
->array
[ev
->title
];
1661 if (!title
->chapter_count
)
1664 assert(ev
->seekpoint
< (int)title
->chapter_count
);
1665 input
->title_selected
= ev
->title
;
1666 input
->chapter_selected
= ev
->seekpoint
;
1668 const struct vlc_player_chapter
*chapter
= &title
->chapters
[ev
->seekpoint
];
1669 vlc_player_SendEvent(player
, on_chapter_selection_changed
, title
, ev
->title
,
1670 chapter
, ev
->seekpoint
);
1673 struct vlc_player_title_list
*
1674 vlc_player_GetTitleList(vlc_player_t
*player
)
1676 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1677 return input
? input
->titles
: NULL
;
1681 vlc_player_GetSelectedTitleIdx(vlc_player_t
*player
)
1683 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1687 return input
->title_selected
;
1691 vlc_player_GetTitleIdx(vlc_player_t
*player
,
1692 const struct vlc_player_title
*title
)
1694 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1695 if (input
&& input
->titles
)
1696 for (size_t i
= 0; i
< input
->titles
->count
; ++i
)
1697 if (&input
->titles
->array
[i
] == title
)
1703 vlc_player_SelectTitleIdx(vlc_player_t
*player
, size_t index
)
1705 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1707 input_ControlPushHelper(input
->thread
, INPUT_CONTROL_SET_TITLE
,
1708 &(vlc_value_t
){ .i_int
= index
});
1712 vlc_player_SelectTitle(vlc_player_t
*player
,
1713 const struct vlc_player_title
*title
)
1715 ssize_t idx
= vlc_player_GetTitleIdx(player
, title
);
1717 vlc_player_SelectTitleIdx(player
, idx
);
1721 vlc_player_SelectChapter(vlc_player_t
*player
,
1722 const struct vlc_player_title
*title
,
1725 ssize_t idx
= vlc_player_GetTitleIdx(player
, title
);
1726 if (idx
!= -1 && idx
== vlc_player_GetSelectedTitleIdx(player
))
1727 vlc_player_SelectChapterIdx(player
, chapter_idx
);
1731 vlc_player_SelectNextTitle(vlc_player_t
*player
)
1733 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1736 input_ControlPush(input
->thread
, INPUT_CONTROL_SET_TITLE_NEXT
, NULL
);
1737 vlc_player_vout_OSDMessage(player
, _("Next title"));
1741 vlc_player_SelectPrevTitle(vlc_player_t
*player
)
1743 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1746 input_ControlPush(input
->thread
, INPUT_CONTROL_SET_TITLE_PREV
, NULL
);
1747 vlc_player_vout_OSDMessage(player
, _("Previous title"));
1751 vlc_player_GetSelectedChapterIdx(vlc_player_t
*player
)
1753 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1757 return input
->chapter_selected
;
1761 vlc_player_SelectChapterIdx(vlc_player_t
*player
, size_t index
)
1763 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1766 input_ControlPushHelper(input
->thread
, INPUT_CONTROL_SET_SEEKPOINT
,
1767 &(vlc_value_t
){ .i_int
= index
});
1768 vlc_player_vout_OSDMessage(player
, _("Chapter %ld"), index
);
1772 vlc_player_SelectNextChapter(vlc_player_t
*player
)
1774 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1777 input_ControlPush(input
->thread
, INPUT_CONTROL_SET_SEEKPOINT_NEXT
, NULL
);
1778 vlc_player_vout_OSDMessage(player
, _("Next chapter"));
1782 vlc_player_SelectPrevChapter(vlc_player_t
*player
)
1784 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1787 input_ControlPush(input
->thread
, INPUT_CONTROL_SET_SEEKPOINT_PREV
, NULL
);
1788 vlc_player_vout_OSDMessage(player
, _("Previous chapter"));
1792 vlc_player_input_HandleVoutEvent(struct vlc_player_input
*input
,
1793 const struct vlc_input_event_vout
*ev
)
1797 static const char osd_vars
[][sizeof("deinterlace-mode")] = {
1798 "aspect-ratio", "autoscale", "crop", "crop-bottom",
1799 "crop-top", "crop-left", "crop-right", "deinterlace",
1800 "deinterlace-mode", "sub-margin", "zoom"
1803 vlc_player_t
*player
= input
->player
;
1806 case VLC_INPUT_EVENT_VOUT_ADDED
:
1807 vlc_player_SendEvent(player
, on_vout_list_changed
,
1808 VLC_PLAYER_LIST_ADDED
, ev
->vout
);
1810 /* Register vout callbacks after the vout list event */
1811 var_AddCallback(ev
->vout
, "fullscreen",
1812 vlc_player_VoutCallback
, player
);
1813 var_AddCallback(ev
->vout
, "video-wallpaper",
1814 vlc_player_VoutCallback
, player
);
1815 for (size_t i
= 0; i
< ARRAY_SIZE(osd_vars
); ++i
)
1816 var_AddCallback(ev
->vout
, osd_vars
[i
],
1817 vlc_player_VoutOSDCallback
, player
);
1819 case VLC_INPUT_EVENT_VOUT_DELETED
:
1820 /* Un-register vout callbacks before the vout list event */
1821 var_DelCallback(ev
->vout
, "fullscreen",
1822 vlc_player_VoutCallback
, player
);
1823 var_DelCallback(ev
->vout
, "video-wallpaper",
1824 vlc_player_VoutCallback
, player
);
1825 for (size_t i
= 0; i
< ARRAY_SIZE(osd_vars
); ++i
)
1826 var_DelCallback(ev
->vout
, osd_vars
[i
],
1827 vlc_player_VoutOSDCallback
, player
);
1829 vlc_player_SendEvent(player
, on_vout_list_changed
,
1830 VLC_PLAYER_LIST_REMOVED
, ev
->vout
);
1833 vlc_assert_unreachable();
1838 vlc_player_input_HandleStateEvent(struct vlc_player_input
*input
,
1839 input_state_e state
)
1844 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_STARTED
);
1847 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_PLAYING
);
1850 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_PAUSED
);
1853 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_STOPPING
);
1854 vlc_player_destructor_AddStoppingInput(input
->player
, input
);
1857 /* Don't send errors if the input is stopped by the user */
1860 /* Contrary to the input_thead_t, an error is not a state */
1861 input
->error
= VLC_PLAYER_ERROR_GENERIC
;
1862 vlc_player_SendEvent(input
->player
, on_error_changed
, input
->error
);
1866 vlc_assert_unreachable();
1871 vlc_player_HandleAtoBLoop(vlc_player_t
*player
)
1873 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
1875 assert(input
->abloop_state
[0].set
&& input
->abloop_state
[1].set
);
1877 if (input
->time
!= VLC_TICK_INVALID
1878 && input
->abloop_state
[0].time
!= VLC_TICK_INVALID
1879 && input
->abloop_state
[1].time
!= VLC_TICK_INVALID
)
1881 if (input
->time
>= input
->abloop_state
[1].time
)
1882 vlc_player_SetTime(player
, input
->abloop_state
[0].time
);
1884 else if (input
->position
>= input
->abloop_state
[1].pos
)
1885 vlc_player_SetPosition(player
, input
->abloop_state
[0].pos
);
1889 input_thread_Events(input_thread_t
*input_thread
,
1890 const struct vlc_input_event
*event
, void *user_data
)
1892 struct vlc_player_input
*input
= user_data
;
1893 vlc_player_t
*player
= input
->player
;
1895 assert(input_thread
== input
->thread
);
1897 vlc_mutex_lock(&player
->lock
);
1899 switch (event
->type
)
1901 case INPUT_EVENT_STATE
:
1902 vlc_player_input_HandleStateEvent(input
, event
->state
);
1904 case INPUT_EVENT_RATE
:
1905 input
->rate
= event
->rate
;
1906 vlc_player_SendEvent(player
, on_rate_changed
, input
->rate
);
1908 case INPUT_EVENT_CAPABILITIES
:
1909 input
->capabilities
= event
->capabilities
;
1910 vlc_player_SendEvent(player
, on_capabilities_changed
,
1911 input
->capabilities
);
1913 case INPUT_EVENT_POSITION
:
1915 /* XXX case INPUT_EVENT_EOF: */
1916 if (player
->next_input
== NULL
)
1918 vlc_tick_t length
= input
->length
;
1919 vlc_tick_t time
= event
->position
.ms
;
1920 if (length
> 0 && time
> 0
1921 && length
- time
<= AOUT_MAX_PREPARE_TIME
)
1922 vlc_player_OpenNextMedia(player
);
1924 if (input
->time
!= event
->position
.ms
||
1925 input
->position
!= event
->position
.percentage
)
1927 input
->time
= event
->position
.ms
;
1928 input
->position
= event
->position
.percentage
;
1929 vlc_player_SendEvent(player
, on_position_changed
,
1933 if (input
->abloop_state
[0].set
&& input
->abloop_state
[1].set
1934 && input
== player
->input
)
1935 vlc_player_HandleAtoBLoop(player
);
1938 case INPUT_EVENT_LENGTH
:
1939 if (input
->length
!= event
->length
)
1941 input
->length
= event
->length
;
1942 vlc_player_SendEvent(player
, on_length_changed
, input
->length
);
1945 case INPUT_EVENT_PROGRAM
:
1946 vlc_player_input_HandleProgramEvent(input
, &event
->program
);
1948 case INPUT_EVENT_ES
:
1949 vlc_player_input_HandleEsEvent(input
, &event
->es
);
1951 case INPUT_EVENT_TITLE
:
1952 vlc_player_input_HandleTitleEvent(input
, &event
->title
);
1954 case INPUT_EVENT_CHAPTER
:
1955 vlc_player_input_HandleChapterEvent(input
, &event
->chapter
);
1957 case INPUT_EVENT_RECORD
:
1958 input
->recording
= event
->record
;
1959 vlc_player_SendEvent(player
, on_recording_changed
, input
->recording
);
1961 case INPUT_EVENT_STATISTICS
:
1962 input
->stats
= *event
->stats
;
1963 vlc_player_SendEvent(player
, on_statistics_changed
, &input
->stats
);
1965 case INPUT_EVENT_SIGNAL
:
1966 input
->signal_quality
= event
->signal
.quality
;
1967 input
->signal_strength
= event
->signal
.strength
;
1968 vlc_player_SendEvent(player
, on_signal_changed
,
1969 input
->signal_quality
, input
->signal_strength
);
1971 case INPUT_EVENT_AUDIO_DELAY
:
1972 input
->audio_delay
= event
->audio_delay
;
1973 vlc_player_SendEvent(player
, on_audio_delay_changed
,
1974 input
->audio_delay
);
1976 case INPUT_EVENT_SUBTITLE_DELAY
:
1977 input
->subtitle_delay
= event
->subtitle_delay
;
1978 vlc_player_SendEvent(player
, on_subtitle_delay_changed
,
1979 input
->subtitle_delay
);
1981 case INPUT_EVENT_CACHE
:
1982 input
->cache
= event
->cache
;
1983 vlc_player_SendEvent(player
, on_buffering_changed
, event
->cache
);
1985 case INPUT_EVENT_VOUT
:
1986 vlc_player_input_HandleVoutEvent(input
, &event
->vout
);
1988 case INPUT_EVENT_ITEM_META
:
1989 vlc_player_SendEvent(player
, on_media_meta_changed
,
1990 input_GetItem(input
->thread
));
1992 case INPUT_EVENT_ITEM_EPG
:
1993 vlc_player_SendEvent(player
, on_media_epg_changed
,
1994 input_GetItem(input
->thread
));
1996 case INPUT_EVENT_SUBITEMS
:
1997 vlc_player_SendEvent(player
, on_media_subitems_changed
,
1998 input_GetItem(input
->thread
), event
->subitems
);
2000 case INPUT_EVENT_DEAD
:
2001 if (input
->started
) /* Can happen with early input_thread fails */
2002 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_STOPPING
);
2003 vlc_player_destructor_AddJoinableInput(player
, input
);
2005 case INPUT_EVENT_VBI_PAGE
:
2006 input
->teletext_page
= event
->vbi_page
< 999 ? event
->vbi_page
: 100;
2007 vlc_player_SendEvent(player
, on_teletext_page_changed
,
2008 input
->teletext_page
);
2010 case INPUT_EVENT_VBI_TRANSPARENCY
:
2011 input
->teletext_transparent
= event
->vbi_transparent
;
2012 vlc_player_SendEvent(player
, on_teletext_transparency_changed
,
2013 input
->teletext_transparent
);
2019 vlc_mutex_unlock(&player
->lock
);
2023 vlc_player_Lock(vlc_player_t
*player
)
2025 vlc_mutex_lock(&player
->lock
);
2029 vlc_player_Unlock(vlc_player_t
*player
)
2031 vlc_mutex_unlock(&player
->lock
);
2035 vlc_player_CondWait(vlc_player_t
*player
, vlc_cond_t
*cond
)
2037 vlc_player_assert_locked(player
);
2038 vlc_cond_wait(cond
, &player
->lock
);
2041 vlc_player_listener_id
*
2042 vlc_player_AddListener(vlc_player_t
*player
,
2043 const struct vlc_player_cbs
*cbs
, void *cbs_data
)
2046 vlc_player_assert_locked(player
);
2048 vlc_player_listener_id
*listener
= malloc(sizeof(*listener
));
2052 listener
->cbs
= cbs
;
2053 listener
->cbs_data
= cbs_data
;
2055 vlc_list_append(&listener
->node
, &player
->listeners
);
2061 vlc_player_RemoveListener(vlc_player_t
*player
,
2062 vlc_player_listener_id
*id
)
2065 vlc_player_assert_locked(player
);
2067 vlc_list_remove(&id
->node
);
2072 vlc_player_SetCurrentMedia(vlc_player_t
*player
, input_item_t
*media
)
2074 vlc_player_assert_locked(player
);
2076 vlc_player_CancelWaitError(player
);
2078 vlc_player_InvalidateNextMedia(player
);
2082 /* Switch to this new media when the current input is stopped */
2083 player
->next_media
= input_item_Hold(media
);
2084 player
->releasing_media
= false;
2085 player
->has_next_media
= true;
2087 else if (player
->media
)
2089 /* The current media will be set to NULL once the current input is
2091 player
->releasing_media
= true;
2092 player
->has_next_media
= false;
2099 vlc_player_destructor_AddInput(player
, player
->input
);
2100 player
->input
= NULL
;
2103 assert(media
== player
->next_media
);
2104 if (!vlc_player_destructor_IsEmpty(player
))
2106 /* This media will be opened when the input is finally stopped */
2110 /* We can switch to the next media directly */
2111 return vlc_player_OpenNextMedia(player
);
2115 vlc_player_GetCurrentMedia(vlc_player_t
*player
)
2117 vlc_player_assert_locked(player
);
2119 return player
->media
;
2123 vlc_player_AddAssociatedMedia(vlc_player_t
*player
,
2124 enum es_format_category_e cat
, const char *uri
,
2125 bool select
, bool notify
, bool check_ext
)
2127 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2130 return VLC_EGENERIC
;
2132 enum slave_type type
;
2136 type
= SLAVE_TYPE_AUDIO
;
2139 type
= SLAVE_TYPE_SPU
;
2142 return VLC_EGENERIC
;
2144 return input_AddSlave(input
->thread
, type
, uri
, select
, notify
, check_ext
);
2148 vlc_player_SetAssociatedSubsFPS(vlc_player_t
*player
, float fps
)
2150 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2152 var_SetFloat(player
, "sub-fps", fps
);
2154 input_ControlPushHelper(input
->thread
, INPUT_CONTROL_SET_SUBS_FPS
,
2155 &(vlc_value_t
) { .f_float
= fps
});
2156 vlc_player_SendEvent(player
, on_associated_subs_fps_changed
, fps
);
2160 vlc_player_GetAssociatedSubsFPS(vlc_player_t
*player
)
2162 vlc_player_assert_locked(player
);
2163 return var_GetFloat(player
, "sub-fps");
2167 vlc_player_InvalidateNextMedia(vlc_player_t
*player
)
2169 vlc_player_assert_locked(player
);
2170 if (player
->next_media
)
2172 input_item_Release(player
->next_media
);
2173 player
->next_media
= NULL
;
2175 player
->has_next_media
= false;
2178 if (player
->next_input
)
2180 /* Cause the get_next callback to be called when this input is
2182 vlc_player_destructor_AddInput(player
, player
->next_input
);
2183 player
->next_input
= NULL
;
2189 vlc_player_Start(vlc_player_t
*player
)
2191 vlc_player_assert_locked(player
);
2193 vlc_player_CancelWaitError(player
);
2195 if (player
->started
)
2198 if (!vlc_player_destructor_IsEmpty(player
))
2200 if (player
->next_media
)
2202 player
->started
= true;
2206 return VLC_EGENERIC
;
2210 return VLC_EGENERIC
;
2214 /* Possible if the player was stopped by the user */
2215 player
->input
= vlc_player_input_New(player
, player
->media
);
2220 assert(!player
->input
->started
);
2222 if (player
->start_paused
)
2224 var_Create(player
->input
->thread
, "start-paused", VLC_VAR_BOOL
);
2225 var_SetBool(player
->input
->thread
, "start-paused", true);
2228 int ret
= vlc_player_input_Start(player
->input
);
2229 if (ret
== VLC_SUCCESS
)
2230 player
->started
= true;
2232 vlc_player_vout_OSDIcon(player
, OSD_PLAY_ICON
);
2237 vlc_player_Stop(vlc_player_t
*player
)
2239 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2241 vlc_player_CancelWaitError(player
);
2243 vlc_player_InvalidateNextMedia(player
);
2245 if (!input
|| !player
->started
)
2247 player
->started
= false;
2249 vlc_player_destructor_AddInput(player
, input
);
2250 player
->input
= NULL
;
2253 if (player
->next_input
)
2255 vlc_player_destructor_AddInput(player
, next_input
);
2256 player
->next_input
= NULL
;
2262 vlc_player_SetMediaStoppedAction(vlc_player_t
*player
,
2263 enum vlc_player_media_stopped_action action
)
2265 vlc_player_assert_locked(player
);
2266 player
->media_stopped_action
= action
;
2267 var_SetBool(player
, "play-and-pause",
2268 action
== VLC_PLAYER_MEDIA_STOPPED_PAUSE
);
2269 vlc_player_SendEvent(player
, on_media_stopped_action_changed
, action
);
2273 vlc_player_SetStartPaused(vlc_player_t
*player
, bool start_paused
)
2275 vlc_player_assert_locked(player
);
2276 player
->start_paused
= start_paused
;
2280 vlc_player_SetPause(vlc_player_t
*player
, bool pause
)
2282 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2284 if (!input
|| !input
->started
)
2287 vlc_value_t val
= { .i_int
= pause
? PAUSE_S
: PLAYING_S
};
2288 input_ControlPushHelper(input
->thread
, INPUT_CONTROL_SET_STATE
, &val
);
2290 vlc_player_vout_OSDIcon(player
, pause
? OSD_PAUSE_ICON
: OSD_PLAY_ICON
);
2294 vlc_player_Pause(vlc_player_t
*player
)
2296 vlc_player_SetPause(player
, true);
2300 vlc_player_Resume(vlc_player_t
*player
)
2302 vlc_player_SetPause(player
, false);
2306 vlc_player_NextVideoFrame(vlc_player_t
*player
)
2308 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2311 input_ControlPushHelper(input
->thread
, INPUT_CONTROL_SET_FRAME_NEXT
, NULL
);
2312 vlc_player_vout_OSDMessage(player
, _("Next frame"));
2315 enum vlc_player_state
2316 vlc_player_GetState(vlc_player_t
*player
)
2318 vlc_player_assert_locked(player
);
2319 return player
->global_state
;
2322 enum vlc_player_error
2323 vlc_player_GetError(vlc_player_t
*player
)
2325 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2326 return input
? input
->error
: VLC_PLAYER_ERROR_NONE
;
2330 vlc_player_GetCapabilities(vlc_player_t
*player
)
2332 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2333 return input
? input
->capabilities
: 0;
2337 vlc_player_GetRate(vlc_player_t
*player
)
2339 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2343 return var_GetFloat(player
, "rate");
2347 vlc_player_ChangeRate(vlc_player_t
*player
, float rate
)
2349 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2354 /* Save rate accross inputs */
2355 var_SetFloat(player
, "rate", rate
);
2359 input_ControlPushHelper(input
->thread
, INPUT_CONTROL_SET_RATE
,
2360 &(vlc_value_t
) { .f_float
= rate
});
2363 vlc_player_SendEvent(player
, on_rate_changed
, rate
);
2365 vlc_player_vout_OSDMessage(player
, ("Speed: %.2fx"), rate
);
2369 vlc_player_ChangeRateOffset(vlc_player_t
*player
, bool increment
)
2371 static const float rates
[] = {
2372 1.0/64, 1.0/32, 1.0/16, 1.0/8, 1.0/4, 1.0/3, 1.0/2, 2.0/3,
2374 3.0/2, 2.0/1, 3.0/1, 4.0/1, 8.0/1, 16.0/1, 32.0/1, 64.0/1,
2376 float rate
= vlc_player_GetRate(player
) * (increment
? 1.1f
: 0.9f
);
2378 /* find closest rate (if any) in the desired direction */
2379 for (size_t i
= 0; i
< ARRAY_SIZE(rates
); ++i
)
2381 if ((increment
&& rates
[i
] > rate
) ||
2382 (!increment
&& rates
[i
] >= rate
&& i
))
2384 rate
= increment
? rates
[i
] : rates
[i
-1];
2389 vlc_player_ChangeRate(player
, rate
);
2393 vlc_player_IncrementRate(vlc_player_t
*player
)
2395 vlc_player_ChangeRateOffset(player
, true);
2399 vlc_player_DecrementRate(vlc_player_t
*player
)
2401 vlc_player_ChangeRateOffset(player
, false);
2405 vlc_player_GetLength(vlc_player_t
*player
)
2407 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2408 return input
? input
->length
: VLC_TICK_INVALID
;
2412 vlc_player_GetTime(vlc_player_t
*player
)
2414 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2416 if (!input
|| input
->time
== VLC_TICK_INVALID
)
2417 return VLC_TICK_INVALID
;
2423 vlc_player_GetPosition(vlc_player_t
*player
)
2425 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2427 return input
? input
->position
: -1.f
;
2431 vlc_player_assert_seek_params(enum vlc_player_seek_speed speed
,
2432 enum vlc_player_whence whence
)
2434 assert(speed
== VLC_PLAYER_SEEK_PRECISE
2435 || speed
== VLC_PLAYER_SEEK_FAST
);
2436 assert(whence
== VLC_PLAYER_WHENCE_ABSOLUTE
2437 || whence
== VLC_PLAYER_WHENCE_RELATIVE
);
2438 (void) speed
; (void) whence
;
2442 vlc_player_vout_OSDPosition(vlc_player_t
*player
,
2443 struct vlc_player_input
*input
, vlc_tick_t time
,
2444 float position
, enum vlc_player_whence whence
)
2446 if (input
->length
!= VLC_TICK_INVALID
)
2448 if (time
== VLC_TICK_INVALID
)
2449 time
= position
* input
->length
;
2451 position
= time
/ (float) input
->length
;
2455 vout_thread_t
**vouts
= vlc_player_vout_OSDHoldAll(player
, &count
);
2457 if (time
!= VLC_TICK_INVALID
)
2459 if (whence
== VLC_PLAYER_WHENCE_RELATIVE
)
2461 time
+= input
->time
; /* XXX: TOCTOU */
2466 char time_text
[MSTRTIME_MAX_SIZE
];
2467 secstotimestr(time_text
, SEC_FROM_VLC_TICK(time
));
2468 if (input
->length
!= VLC_TICK_INVALID
)
2470 char len_text
[MSTRTIME_MAX_SIZE
];
2471 secstotimestr(len_text
, SEC_FROM_VLC_TICK(input
->length
));
2472 vouts_osd_Message(vouts
, count
, "%s / %s", time_text
, len_text
);
2475 vouts_osd_Message(vouts
, count
, "%s", time_text
);
2478 if (vlc_player_vout_IsFullscreen(player
))
2480 if (whence
== VLC_PLAYER_WHENCE_RELATIVE
)
2482 position
+= input
->position
; /* XXX: TOCTOU */
2486 vouts_osd_Slider(vouts
, count
, position
* 100, OSD_HOR_SLIDER
);
2488 vlc_player_vout_OSDReleaseAll(player
, vouts
, count
);
2492 vlc_player_DisplayPosition(vlc_player_t
*player
)
2494 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2497 vlc_player_vout_OSDPosition(player
, input
, input
->time
, input
->position
,
2498 VLC_PLAYER_WHENCE_ABSOLUTE
);
2502 vlc_player_SeekByPos(vlc_player_t
*player
, float position
,
2503 enum vlc_player_seek_speed speed
,
2504 enum vlc_player_whence whence
)
2506 vlc_player_assert_seek_params(speed
, whence
);
2508 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2513 whence
== VLC_PLAYER_WHENCE_ABSOLUTE
? INPUT_CONTROL_SET_POSITION
2514 : INPUT_CONTROL_JUMP_POSITION
;
2515 input_ControlPush(input
->thread
, type
,
2516 &(input_control_param_t
) {
2517 .pos
.f_val
= position
,
2518 .pos
.b_fast_seek
= speed
== VLC_PLAYER_SEEK_FAST
,
2521 vlc_player_vout_OSDPosition(player
, input
, VLC_TICK_INVALID
, position
,
2526 vlc_player_SeekByTime(vlc_player_t
*player
, vlc_tick_t time
,
2527 enum vlc_player_seek_speed speed
,
2528 enum vlc_player_whence whence
)
2530 vlc_player_assert_seek_params(speed
, whence
);
2532 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2537 whence
== VLC_PLAYER_WHENCE_ABSOLUTE
? INPUT_CONTROL_SET_TIME
2538 : INPUT_CONTROL_JUMP_TIME
;
2539 input_ControlPush(input
->thread
, type
,
2540 &(input_control_param_t
) {
2542 .time
.b_fast_seek
= speed
== VLC_PLAYER_SEEK_FAST
,
2545 vlc_player_vout_OSDPosition(player
, input
, time
, -1, whence
);
2549 vlc_player_SetRenderer(vlc_player_t
*player
, vlc_renderer_item_t
*renderer
)
2551 vlc_player_assert_locked(player
);
2553 if (player
->renderer
)
2554 vlc_renderer_item_release(player
->renderer
);
2555 player
->renderer
= renderer
? vlc_renderer_item_hold(renderer
) : NULL
;
2557 vlc_player_foreach_inputs(input
)
2560 .p_address
= renderer
? vlc_renderer_item_hold(renderer
) : NULL
2562 input_ControlPushHelper(input
->thread
, INPUT_CONTROL_SET_RENDERER
,
2565 vlc_player_SendEvent(player
, on_renderer_changed
, player
->renderer
);
2568 vlc_renderer_item_t
*
2569 vlc_player_GetRenderer(vlc_player_t
*player
)
2571 vlc_player_assert_locked(player
);
2572 return player
->renderer
;
2576 vlc_player_SetAtoBLoop(vlc_player_t
*player
, enum vlc_player_abloop abloop
)
2578 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2580 if (!input
|| !vlc_player_CanSeek(player
))
2581 return VLC_EGENERIC
;
2583 vlc_tick_t time
= vlc_player_GetTime(player
);
2584 float pos
= vlc_player_GetPosition(player
);
2585 int ret
= VLC_SUCCESS
;
2588 case VLC_PLAYER_ABLOOP_A
:
2589 if (input
->abloop_state
[1].set
)
2590 return VLC_EGENERIC
;
2591 input
->abloop_state
[0].time
= time
;
2592 input
->abloop_state
[0].pos
= pos
;
2593 input
->abloop_state
[0].set
= true;
2595 case VLC_PLAYER_ABLOOP_B
:
2596 if (!input
->abloop_state
[0].set
)
2597 return VLC_EGENERIC
;
2598 input
->abloop_state
[1].time
= time
;
2599 input
->abloop_state
[1].pos
= pos
;
2600 input
->abloop_state
[1].set
= true;
2601 if (input
->abloop_state
[0].time
!= VLC_TICK_INVALID
2602 && time
!= VLC_TICK_INVALID
)
2604 if (time
> input
->abloop_state
[0].time
)
2606 vlc_player_SetTime(player
, input
->abloop_state
[0].time
);
2610 else if (pos
> input
->abloop_state
[0].pos
)
2612 vlc_player_SetPosition(player
, input
->abloop_state
[0].pos
);
2616 /* Error: A time is superior to B time. */
2617 abloop
= VLC_PLAYER_ABLOOP_NONE
;
2620 case VLC_PLAYER_ABLOOP_NONE
:
2621 input
->abloop_state
[0].set
= input
->abloop_state
[1].set
= false;
2622 time
= VLC_TICK_INVALID
;
2626 vlc_assert_unreachable();
2628 vlc_player_SendEvent(player
, on_atobloop_changed
, abloop
, time
, pos
);
2632 enum vlc_player_abloop
2633 vlc_player_GetAtoBLoop(vlc_player_t
*player
, vlc_tick_t
*a_time
, float *a_pos
,
2634 vlc_tick_t
*b_time
, float *b_pos
)
2636 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2638 if (!input
|| !vlc_player_CanSeek(player
) || !input
->abloop_state
[0].set
)
2639 return VLC_PLAYER_ABLOOP_NONE
;
2642 *a_time
= input
->abloop_state
[0].time
;
2644 *a_pos
= input
->abloop_state
[0].pos
;
2645 if (!input
->abloop_state
[1].set
)
2646 return VLC_PLAYER_ABLOOP_A
;
2649 *b_time
= input
->abloop_state
[1].time
;
2651 *b_pos
= input
->abloop_state
[1].pos
;
2652 return VLC_PLAYER_ABLOOP_B
;
2656 vlc_player_Navigate(vlc_player_t
*player
, enum vlc_player_nav nav
)
2658 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2663 enum input_control_e control
;
2666 case VLC_PLAYER_NAV_ACTIVATE
:
2667 control
= INPUT_CONTROL_NAV_ACTIVATE
;
2669 case VLC_PLAYER_NAV_UP
:
2670 control
= INPUT_CONTROL_NAV_UP
;
2672 case VLC_PLAYER_NAV_DOWN
:
2673 control
= INPUT_CONTROL_NAV_DOWN
;
2675 case VLC_PLAYER_NAV_LEFT
:
2676 control
= INPUT_CONTROL_NAV_LEFT
;
2678 case VLC_PLAYER_NAV_RIGHT
:
2679 control
= INPUT_CONTROL_NAV_RIGHT
;
2681 case VLC_PLAYER_NAV_POPUP
:
2682 control
= INPUT_CONTROL_NAV_POPUP
;
2684 case VLC_PLAYER_NAV_MENU
:
2685 control
= INPUT_CONTROL_NAV_MENU
;
2688 vlc_assert_unreachable();
2690 input_ControlPushHelper(input
->thread
, control
, NULL
);
2694 vlc_player_UpdateViewpoint(vlc_player_t
*player
,
2695 const vlc_viewpoint_t
*viewpoint
,
2696 enum vlc_player_whence whence
)
2698 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2700 input_UpdateViewpoint(input
->thread
, viewpoint
,
2701 whence
== VLC_PLAYER_WHENCE_ABSOLUTE
);
2705 vlc_player_IsRecording(vlc_player_t
*player
)
2707 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2709 return input
? input
->recording
: false;
2713 vlc_player_SetRecordingEnabled(vlc_player_t
*player
, bool enable
)
2715 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2718 input_ControlPushHelper(input
->thread
, INPUT_CONTROL_SET_RECORD_STATE
,
2719 &(vlc_value_t
) { .b_bool
= enable
});
2721 vlc_player_vout_OSDMessage(player
, enable
?
2722 _("Recording") : _("Recording done"));
2726 vlc_player_SetAudioDelay(vlc_player_t
*player
, vlc_tick_t delay
,
2727 enum vlc_player_whence whence
)
2729 bool absolute
= whence
== VLC_PLAYER_WHENCE_ABSOLUTE
;
2730 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2734 input_ControlPush(input
->thread
, INPUT_CONTROL_SET_AUDIO_DELAY
,
2735 &(input_control_param_t
) {
2737 .b_absolute
= whence
== VLC_PLAYER_WHENCE_ABSOLUTE
,
2743 delay
+= input
->audio_delay
;
2744 vlc_player_vout_OSDMessage(player
, _("Audio delay: %i ms"),
2745 (int)MS_FROM_VLC_TICK(delay
));
2749 vlc_player_GetAudioDelay(vlc_player_t
*player
)
2751 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2752 return input
? input
->audio_delay
: 0;
2756 vlc_player_SetSubtitleDelayInternal(vlc_player_t
*player
, vlc_tick_t delay
,
2757 enum vlc_player_whence whence
)
2759 bool absolute
= whence
== VLC_PLAYER_WHENCE_ABSOLUTE
;
2760 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2764 input_ControlPush(input
->thread
, INPUT_CONTROL_SET_SPU_DELAY
,
2765 &(input_control_param_t
) {
2767 .b_absolute
= absolute
,
2774 vlc_player_SetSubtitleDelay(vlc_player_t
*player
, vlc_tick_t delay
,
2775 enum vlc_player_whence whence
)
2777 vlc_player_SetSubtitleDelayInternal(player
, delay
, whence
);
2778 vlc_player_vout_OSDMessage(player
, _("Subtitle delay: %s%i ms"),
2779 whence
== VLC_PLAYER_WHENCE_ABSOLUTE
? "" : "+",
2780 (int)MS_FROM_VLC_TICK(delay
));
2784 const char var
[sizeof("video")];
2785 const char sout_var
[sizeof("sout-video")];
2787 [VIDEO_ES
] = { "video", "sout-video" },
2788 [AUDIO_ES
] = { "audio", "sout-audio" },
2789 [SPU_ES
] = { "spu", "sout-spu" },
2793 vlc_player_SetTrackCategoryEnabled(vlc_player_t
*player
,
2794 enum es_format_category_e cat
, bool enabled
)
2796 assert(cat
>= UNKNOWN_ES
&& cat
<= DATA_ES
);
2797 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2799 var_SetBool(player
, cat2vars
[cat
].var
, enabled
);
2800 var_SetBool(player
, cat2vars
[cat
].sout_var
, enabled
);
2804 var_SetBool(input
->thread
, cat2vars
[cat
].var
, enabled
);
2805 var_SetBool(input
->thread
, cat2vars
[cat
].sout_var
, enabled
);
2808 vlc_player_UnselectTrackCategory(player
, cat
);
2813 vlc_player_IsTrackCategoryEnabled(vlc_player_t
*player
,
2814 enum es_format_category_e cat
)
2816 assert(cat
>= UNKNOWN_ES
&& cat
<= DATA_ES
);
2817 return var_GetBool(player
, cat2vars
[cat
].var
);
2821 vlc_player_SetSubtitleTextScale(vlc_player_t
*player
, unsigned scale
)
2823 assert(scale
>= 10 && scale
<= 500);
2824 var_SetInteger(player
, "sub-text-scale", scale
);
2828 vlc_player_GetSubtitleTextScale(vlc_player_t
*player
)
2830 return var_GetInteger(player
, "sub-text-scale");
2834 vlc_player_SubtitleSyncMarkAudio(vlc_player_t
*player
)
2836 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2839 input
->subsync
.audio_time
= vlc_tick_now();
2840 vlc_player_vout_OSDMessage(player
, _("Sub sync: bookmarked audio time"));
2844 vlc_player_SubtitleSyncMarkSubtitle(vlc_player_t
*player
)
2846 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2849 input
->subsync
.subtitle_time
= vlc_tick_now();
2850 vlc_player_vout_OSDMessage(player
, _("Sub sync: bookmarked subtitle time"));
2854 vlc_player_SubtitleSyncApply(vlc_player_t
*player
)
2856 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2859 if (input
->subsync
.audio_time
== VLC_TICK_INVALID
||
2860 input
->subsync
.subtitle_time
== VLC_TICK_INVALID
)
2862 vlc_player_vout_OSDMessage(player
, _("Sub sync: set bookmarks first!"));
2866 input
->subsync
.audio_time
- input
->subsync
.subtitle_time
;
2867 input
->subsync
.audio_time
= VLC_TICK_INVALID
;
2868 input
->subsync
.subtitle_time
= VLC_TICK_INVALID
;
2869 vlc_player_SetSubtitleDelayInternal(player
, delay
,
2870 VLC_PLAYER_WHENCE_RELATIVE
);
2872 long long delay_ms
= MS_FROM_VLC_TICK(delay
);
2873 long long totdelay_ms
= MS_FROM_VLC_TICK(input
->subtitle_delay
+ delay
);
2874 vlc_player_vout_OSDMessage(player
, _("Sub sync: corrected %"PRId64
2875 " ms (total delay = %"PRId64
" ms)"),
2876 delay_ms
, totdelay_ms
);
2880 vlc_player_SubtitleSyncReset(vlc_player_t
*player
)
2882 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2885 vlc_player_SetSubtitleDelayInternal(player
, 0, VLC_PLAYER_WHENCE_ABSOLUTE
);
2886 input
->subsync
.audio_time
= VLC_TICK_INVALID
;
2887 input
->subsync
.subtitle_time
= VLC_TICK_INVALID
;
2888 vlc_player_vout_OSDMessage(player
, _("Sub sync: delay reset"));
2892 vlc_player_SetSubtitleSync(vlc_player_t
*player
,
2893 enum vlc_player_subtitle_sync sync
)
2897 case VLC_PLAYER_SUBTITLE_SYNC_RESET
:
2898 vlc_player_SubtitleSyncReset(player
);
2900 case VLC_PLAYER_SUBTITLE_SYNC_MARK_AUDIO
:
2901 vlc_player_SubtitleSyncMarkAudio(player
);
2903 case VLC_PLAYER_SUBTITLE_SYNC_MARK_SUBTITLE
:
2904 vlc_player_SubtitleSyncMarkSubtitle(player
);
2906 case VLC_PLAYER_SUBTITLE_SYNC_APPLY
:
2907 vlc_player_SubtitleSyncApply(player
);
2910 vlc_assert_unreachable();
2915 vlc_player_GetSubtitleDelay(vlc_player_t
*player
)
2917 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2918 return input
? input
->subtitle_delay
: 0;
2922 vlc_player_GetSignal(vlc_player_t
*player
, float *quality
, float *strength
)
2924 assert(quality
&& strength
);
2925 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2927 if (input
&& input
->signal_quality
>= 0 && input
->signal_strength
>= 0)
2929 *quality
= input
->signal_quality
;
2930 *strength
= input
->signal_strength
;
2933 return VLC_EGENERIC
;
2936 const struct input_stats_t
*
2937 vlc_player_GetStatistics(vlc_player_t
*player
)
2939 struct vlc_player_input
*input
= vlc_player_get_input_locked(player
);
2941 return input
? &input
->stats
: NULL
;
2945 vlc_player_SetPauseOnCork(vlc_player_t
*player
, bool enabled
)
2947 vlc_player_assert_locked(player
);
2948 player
->pause_on_cork
= enabled
;
2952 vlc_player_CorkCallback(vlc_object_t
*this, const char *var
,
2953 vlc_value_t oldval
, vlc_value_t newval
, void *data
)
2955 vlc_player_t
*player
= data
;
2957 if (oldval
.i_int
== newval
.i_int
)
2960 vlc_player_Lock(player
);
2962 if (player
->pause_on_cork
)
2966 player
->corked
= player
->global_state
== VLC_PLAYER_STATE_PLAYING
2967 || player
->global_state
== VLC_PLAYER_STATE_STARTED
;
2969 vlc_player_Pause(player
);
2975 vlc_player_Resume(player
);
2976 player
->corked
= false;
2981 vlc_player_SendEvent(player
, on_cork_changed
, newval
.i_int
);
2983 vlc_player_Unlock(player
);
2986 (void) this; (void) var
;
2990 vlc_player_aout_Hold(vlc_player_t
*player
)
2992 return input_resource_HoldAout(player
->resource
);
2995 vlc_player_aout_listener_id
*
2996 vlc_player_aout_AddListener(vlc_player_t
*player
,
2997 const struct vlc_player_aout_cbs
*cbs
,
3002 vlc_player_aout_listener_id
*listener
= malloc(sizeof(*listener
));
3006 listener
->cbs
= cbs
;
3007 listener
->cbs_data
= cbs_data
;
3009 vlc_mutex_lock(&player
->aout_listeners_lock
);
3010 vlc_list_append(&listener
->node
, &player
->aout_listeners
);
3011 vlc_mutex_unlock(&player
->aout_listeners_lock
);
3017 vlc_player_aout_RemoveListener(vlc_player_t
*player
,
3018 vlc_player_aout_listener_id
*id
)
3022 vlc_mutex_lock(&player
->aout_listeners_lock
);
3023 vlc_list_remove(&id
->node
);
3024 vlc_mutex_unlock(&player
->aout_listeners_lock
);
3029 vlc_player_vout_OSDVolume(vlc_player_t
*player
, bool mute_action
)
3032 vout_thread_t
**vouts
= vlc_player_vout_OSDHoldAll(player
, &count
);
3034 bool mute
= vlc_player_aout_IsMuted(player
);
3035 int volume
= lroundf(vlc_player_aout_GetVolume(player
) * 100.f
);
3036 if (mute_action
&& mute
)
3037 vouts_osd_Icon(vouts
, count
, OSD_MUTE_ICON
);
3040 if (vlc_player_vout_IsFullscreen(player
))
3041 vouts_osd_Slider(vouts
, count
, volume
, OSD_VERT_SLIDER
);
3042 vouts_osd_Message(vouts
, count
, _("Volume: %ld%%"), volume
);
3045 vlc_player_vout_OSDReleaseAll(player
, vouts
, count
);
3049 vlc_player_AoutCallback(vlc_object_t
*this, const char *var
,
3050 vlc_value_t oldval
, vlc_value_t newval
, void *data
)
3052 vlc_player_t
*player
= data
;
3054 if (strcmp(var
, "volume") == 0)
3056 if (oldval
.f_float
!= newval
.f_float
)
3058 vlc_player_aout_SendEvent(player
, on_volume_changed
, newval
.f_float
);
3059 vlc_player_vout_OSDVolume(player
, false);
3062 else if (strcmp(var
, "mute") == 0)
3064 if (oldval
.b_bool
!= newval
.b_bool
)
3066 vlc_player_aout_SendEvent(player
, on_mute_changed
, newval
.b_bool
);
3067 vlc_player_vout_OSDVolume(player
, true);
3071 vlc_assert_unreachable();
3078 vlc_player_aout_GetVolume(vlc_player_t
*player
)
3080 audio_output_t
*aout
= vlc_player_aout_Hold(player
);
3083 float vol
= aout_VolumeGet(aout
);
3084 vlc_object_release(aout
);
3090 vlc_player_aout_SetVolume(vlc_player_t
*player
, float volume
)
3092 audio_output_t
*aout
= vlc_player_aout_Hold(player
);
3095 int ret
= aout_VolumeSet(aout
, volume
);
3096 vlc_object_release(aout
);
3102 vlc_player_aout_IncrementVolume(vlc_player_t
*player
, int steps
, float *result
)
3104 audio_output_t
*aout
= vlc_player_aout_Hold(player
);
3107 int ret
= aout_VolumeUpdate(aout
, steps
, result
);
3108 vlc_object_release(aout
);
3114 vlc_player_aout_IsMuted(vlc_player_t
*player
)
3116 audio_output_t
*aout
= vlc_player_aout_Hold(player
);
3119 int ret
= aout_MuteGet(aout
);
3120 vlc_object_release(aout
);
3126 vlc_player_aout_Mute(vlc_player_t
*player
, bool mute
)
3128 audio_output_t
*aout
= vlc_player_aout_Hold(player
);
3131 int ret
= aout_MuteSet (aout
, mute
);
3132 vlc_object_release(aout
);
3139 vlc_player_aout_EnableFilter(vlc_player_t
*player
, const char *name
, bool add
)
3141 audio_output_t
*aout
= vlc_player_aout_Hold(player
);
3144 aout_EnableFilter(aout
, name
, add
);
3145 vlc_object_release(aout
);
3151 vlc_player_vout_Hold(vlc_player_t
*player
)
3153 return input_resource_HoldVout(player
->resource
);
3157 vlc_player_vout_HoldAll(vlc_player_t
*player
, size_t *count
)
3159 vout_thread_t
**vouts
;
3160 input_resource_HoldVouts(player
->resource
, &vouts
, count
);
3164 vlc_player_vout_listener_id
*
3165 vlc_player_vout_AddListener(vlc_player_t
*player
,
3166 const struct vlc_player_vout_cbs
*cbs
,
3171 vlc_player_vout_listener_id
*listener
= malloc(sizeof(*listener
));
3175 listener
->cbs
= cbs
;
3176 listener
->cbs_data
= cbs_data
;
3178 vlc_mutex_lock(&player
->vout_listeners_lock
);
3179 vlc_list_append(&listener
->node
, &player
->vout_listeners
);
3180 vlc_mutex_unlock(&player
->vout_listeners_lock
);
3186 vlc_player_vout_RemoveListener(vlc_player_t
*player
,
3187 vlc_player_vout_listener_id
*id
)
3191 vlc_mutex_lock(&player
->vout_listeners_lock
);
3192 vlc_list_remove(&id
->node
);
3193 vlc_mutex_unlock(&player
->vout_listeners_lock
);
3198 vlc_player_vout_IsFullscreen(vlc_player_t
*player
)
3200 return var_GetBool(player
, "fullscreen");
3204 vlc_player_VoutCallback(vlc_object_t
*this, const char *var
,
3205 vlc_value_t oldval
, vlc_value_t newval
, void *data
)
3207 vlc_player_t
*player
= data
;
3209 if (strcmp(var
, "fullscreen") == 0)
3211 if (oldval
.b_bool
!= newval
.b_bool
)
3212 vlc_player_vout_SendEvent(player
, on_fullscreen_changed
,
3213 (vout_thread_t
*)this, newval
.b_bool
);
3215 else if (strcmp(var
, "video-wallpaper") == 0)
3217 if (oldval
.b_bool
!= newval
.b_bool
)
3218 vlc_player_vout_SendEvent(player
, on_wallpaper_mode_changed
,
3219 (vout_thread_t
*)this, newval
.b_bool
);
3222 vlc_assert_unreachable();
3228 vout_osd_PrintVariableText(vout_thread_t
*vout
, const char *varname
, int vartype
,
3229 vlc_value_t varval
, const char *osdfmt
)
3232 bool isvarstring
= vartype
== VLC_VAR_STRING
;
3234 vlc_value_t
*choices
;
3235 char **choices_text
;
3236 var_Change(vout
, varname
, VLC_VAR_GETCHOICES
,
3237 &num_choices
, &choices
, &choices_text
);
3238 for (size_t i
= 0; i
< num_choices
; ++i
)
3242 strcmp(choices
[i
].psz_string
, varval
.psz_string
) == 0) ||
3243 (!isvarstring
&& choices
[i
].f_float
== varval
.f_float
))
3245 vouts_osd_Message(&vout
, 1, osdfmt
, choices_text
[i
]);
3249 free(choices
[i
].psz_string
);
3250 free(choices_text
[i
]);
3258 vlc_player_VoutOSDCallback(vlc_object_t
*this, const char *var
,
3259 vlc_value_t oldval
, vlc_value_t newval
, void *data
)
3263 vout_thread_t
*vout
= (vout_thread_t
*)this;
3265 if (strcmp(var
, "aspect-ratio") == 0)
3266 vout_osd_PrintVariableText(vout
, var
, VLC_VAR_STRING
,
3267 newval
, _("Aspect ratio: %s"));
3269 else if (strcmp(var
, "autoscale") == 0)
3270 vouts_osd_Message(&vout
, 1, newval
.b_bool
?
3271 _("Scaled to screen") : _("Original size"));
3273 else if (strcmp(var
, "crop") == 0)
3274 vout_osd_PrintVariableText(vout
, var
, VLC_VAR_STRING
, newval
,
3277 else if (strcmp(var
, "crop-bottom") == 0)
3278 vouts_osd_Message(&vout
, 1, _("Bottom crop: %d px"), newval
.i_int
);
3280 else if (strcmp(var
, "crop-top") == 0)
3281 vouts_osd_Message(&vout
, 1, _("Top crop: %d px"), newval
.i_int
);
3283 else if (strcmp(var
, "crop-left") == 0)
3284 vouts_osd_Message(&vout
, 1, _("Left crop: %d px"), newval
.i_int
);
3286 else if (strcmp(var
, "crop-right") == 0)
3287 vouts_osd_Message(&vout
, 1, _("Right crop: %d px"), newval
.i_int
);
3289 else if (strcmp(var
, "deinterlace") == 0 ||
3290 strcmp(var
, "deinterlace-mode") == 0)
3292 bool varmode
= strcmp(var
, "deinterlace-mode") == 0;
3294 newval
.i_int
: var_GetInteger(vout
, "deinterlace");
3295 char *mode
= varmode
?
3296 newval
.psz_string
: var_GetString(vout
, "deinterlace-mode");
3297 vouts_osd_Message(&vout
, 1, _("Deinterlace %s (%s)"),
3298 on
== 1 ? _("On") : _("Off"), mode
);
3302 else if (strcmp(var
, "sub-margin") == 0)
3303 vouts_osd_Message(&vout
, 1, _("Subtitle position %d px"), newval
.i_int
);
3305 else if (strcmp(var
, "sub-text-scale") == 0)
3306 vouts_osd_Message(&vout
, 1, _("Subtitle text scale %d%%"), newval
.i_int
);
3308 else if (strcmp(var
, "zoom") == 0)
3310 if (newval
.f_float
== 1.f
)
3311 vouts_osd_Message(&vout
, 1, _("Zooming reset"));
3314 bool found
= vout_osd_PrintVariableText(vout
, var
, VLC_VAR_FLOAT
,
3315 newval
, _("Zoom mode: %s"));
3317 vouts_osd_Message(&vout
, 1, _("Zoom: x%f"), newval
.f_float
);
3326 vlc_player_vout_SetVar(vlc_player_t
*player
, const char *name
, int type
,
3329 var_SetChecked(player
, name
, type
, val
);
3332 vout_thread_t
**vouts
= vlc_player_vout_HoldAll(player
, &count
);
3333 for (size_t i
= 0; i
< count
; i
++)
3335 var_SetChecked(vouts
[i
], name
, type
, val
);
3336 vlc_object_release(vouts
[i
]);
3343 vlc_player_vout_TriggerOption(vlc_player_t
*player
, const char *option
)
3346 vout_thread_t
**vouts
= vlc_player_vout_HoldAll(player
, &count
);
3347 for (size_t i
= 0; i
< count
; ++i
)
3349 var_TriggerCallback(vouts
[i
], option
);
3350 vlc_object_release(vouts
[i
]);
3356 vlc_player_vout_SetFullscreen(vlc_player_t
*player
, bool enabled
)
3358 vlc_player_vout_SetVar(player
, "fullscreen", VLC_VAR_BOOL
,
3359 (vlc_value_t
) { .b_bool
= enabled
});
3360 vlc_player_vout_SendEvent(player
, on_fullscreen_changed
, NULL
, enabled
);
3364 vlc_player_vout_IsWallpaperModeEnabled(vlc_player_t
*player
)
3366 return var_GetBool(player
, "video-wallpaper");
3370 vlc_player_vout_SetWallpaperModeEnabled(vlc_player_t
*player
, bool enabled
)
3372 vlc_player_vout_SetVar(player
, "video-wallpaper", VLC_VAR_BOOL
,
3373 (vlc_value_t
) { .b_bool
= enabled
});
3374 vlc_player_vout_SendEvent(player
, on_wallpaper_mode_changed
, NULL
, enabled
);
3378 vlc_vout_filter_type_to_varname(enum vlc_vout_filter_type type
)
3382 case VLC_VOUT_FILTER_VIDEO_SPLITTER
:
3383 return "video-splitter";
3384 case VLC_VOUT_FILTER_VIDEO_FILTER
:
3385 return "video-filter";
3386 case VLC_VOUT_FILTER_SUB_SOURCE
:
3387 return "sub-source";
3388 case VLC_VOUT_FILTER_SUB_FILTER
:
3389 return "sub-filter";
3391 vlc_assert_unreachable();
3396 vlc_player_vout_SetFilter(vlc_player_t
*player
, enum vlc_vout_filter_type type
,
3399 const char *varname
= vlc_vout_filter_type_to_varname(type
);
3400 vlc_player_vout_SetVar(player
, varname
, VLC_VAR_STRING
,
3401 (vlc_value_t
) { .psz_string
= (char *) value
});
3405 vlc_player_vout_GetFilter(vlc_player_t
*player
, enum vlc_vout_filter_type type
)
3407 const char *varname
= vlc_vout_filter_type_to_varname(type
);
3408 return var_GetString(player
, varname
);
3412 vlc_player_vout_Snapshot(vlc_player_t
*player
)
3414 vlc_player_vout_TriggerOption(player
, "video-snapshot");
3418 vlc_player_InitLocks(vlc_player_t
*player
)
3420 vlc_mutex_init(&player
->lock
);
3421 vlc_mutex_init(&player
->vout_listeners_lock
);
3422 vlc_mutex_init(&player
->aout_listeners_lock
);
3423 vlc_cond_init(&player
->start_delay_cond
);
3424 vlc_cond_init(&player
->destructor
.wait
);
3428 vlc_player_DestroyLocks(vlc_player_t
*player
)
3430 vlc_mutex_destroy(&player
->lock
);
3431 vlc_mutex_destroy(&player
->vout_listeners_lock
);
3432 vlc_mutex_destroy(&player
->aout_listeners_lock
);
3433 vlc_cond_destroy(&player
->start_delay_cond
);
3434 vlc_cond_destroy(&player
->destructor
.wait
);
3438 vlc_player_Delete(vlc_player_t
*player
)
3440 vlc_mutex_lock(&player
->lock
);
3443 vlc_player_destructor_AddInput(player
, player
->input
);
3445 if (player
->next_input
)
3446 vlc_player_destructor_AddInput(player
, player
->next_inpu
);
3449 player
->deleting
= true;
3450 vlc_cond_signal(&player
->destructor
.wait
);
3452 assert(vlc_list_is_empty(&player
->listeners
));
3454 vlc_mutex_unlock(&player
->lock
);
3456 vlc_join(player
->destructor
.thread
, NULL
);
3459 input_item_Release(player
->media
);
3460 if (player
->next_media
)
3461 input_item_Release(player
->next_media
);
3463 vlc_player_DestroyLocks(player
);
3465 audio_output_t
*aout
= vlc_player_aout_Hold(player
);
3468 var_DelCallback(aout
, "volume", vlc_player_AoutCallback
, player
);
3469 var_DelCallback(aout
, "mute", vlc_player_AoutCallback
, player
);
3470 var_DelCallback(player
, "corks", vlc_player_CorkCallback
, NULL
);
3471 vlc_object_release(aout
);
3473 input_resource_Release(player
->resource
);
3474 if (player
->renderer
)
3475 vlc_renderer_item_release(player
->renderer
);
3477 vlc_object_release(player
);
3481 vlc_player_New(vlc_object_t
*parent
,
3482 const struct vlc_player_media_provider
*media_provider
,
3483 void *media_provider_data
)
3485 audio_output_t
*aout
= NULL
;
3486 vlc_player_t
*player
= vlc_custom_create(parent
, sizeof(*player
), "player");
3490 assert(!media_provider
|| media_provider
->get_next
);
3492 vlc_list_init(&player
->listeners
);
3493 vlc_list_init(&player
->vout_listeners
);
3494 vlc_list_init(&player
->aout_listeners
);
3495 vlc_list_init(&player
->destructor
.inputs
);
3496 vlc_list_init(&player
->destructor
.stopping_inputs
);
3497 vlc_list_init(&player
->destructor
.joinable_inputs
);
3498 player
->media_stopped_action
= VLC_PLAYER_MEDIA_STOPPED_CONTINUE
;
3499 player
->start_paused
= false;
3500 player
->pause_on_cork
= false;
3501 player
->corked
= false;
3502 player
->renderer
= NULL
;
3503 player
->media_provider
= media_provider
;
3504 player
->media_provider_data
= media_provider_data
;
3505 player
->media
= NULL
;
3506 player
->input
= NULL
;
3507 player
->global_state
= VLC_PLAYER_STATE_STOPPED
;
3508 player
->started
= false;
3510 player
->error_count
= 0;
3512 player
->releasing_media
= false;
3513 player
->has_next_media
= false;
3514 player
->next_media
= NULL
;
3516 player
->next_input
= NULL
;
3519 #define VAR_CREATE(var, flag) do { \
3520 if (var_Create(player, var, flag) != VLC_SUCCESS) \
3524 /* player variables */
3525 VAR_CREATE("rate", VLC_VAR_FLOAT
| VLC_VAR_DOINHERIT
);
3526 VAR_CREATE("sub-fps", VLC_VAR_FLOAT
| VLC_VAR_DOINHERIT
);
3527 VAR_CREATE("sub-text-scale", VLC_VAR_INTEGER
| VLC_VAR_DOINHERIT
);
3528 VAR_CREATE("demux-filter", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
3530 /* vout variables */
3531 VAR_CREATE("video-splitter", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
3532 VAR_CREATE("video-filter", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
3533 VAR_CREATE("sub-source", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
3534 VAR_CREATE("sub-filter", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
3535 VAR_CREATE("fullscreen", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
3536 VAR_CREATE("video-on-top", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
3537 VAR_CREATE("video-wallpaper", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
3539 /* aout variables */
3540 VAR_CREATE("audio-filter", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
3541 VAR_CREATE("mute", VLC_VAR_BOOL
);
3542 VAR_CREATE("corks", VLC_VAR_INTEGER
);
3544 /* es_out variables */
3545 VAR_CREATE("sout", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
3546 VAR_CREATE("video", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
3547 VAR_CREATE("sout-video", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
3548 VAR_CREATE("audio", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
3549 VAR_CREATE("sout-audio", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
3550 VAR_CREATE("spu", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
3551 VAR_CREATE("sout-spu", VLC_VAR_BOOL
| VLC_VAR_DOINHERIT
);
3553 /* TODO: Override these variables since the player handle media ended
3555 VAR_CREATE("start-paused", VLC_VAR_BOOL
);
3556 VAR_CREATE("play-and-pause", VLC_VAR_BOOL
);
3560 player
->resource
= input_resource_New(VLC_OBJECT(player
));
3562 if (!player
->resource
)
3566 aout
= input_resource_GetAout(player
->resource
);
3569 var_AddCallback(aout
, "volume", vlc_player_AoutCallback
, player
);
3570 var_AddCallback(aout
, "mute", vlc_player_AoutCallback
, player
);
3571 var_AddCallback(player
, "corks", vlc_player_CorkCallback
, NULL
);
3572 input_resource_PutAout(player
->resource
, aout
);
3575 player
->deleting
= false;
3576 vlc_player_InitLocks(player
);
3578 if (vlc_clone(&player
->destructor
.thread
, vlc_player_destructor_Thread
,
3579 player
, VLC_THREAD_PRIORITY_LOW
) != 0)
3581 vlc_player_DestroyLocks(player
);
3590 var_DelCallback(aout
, "volume", vlc_player_AoutCallback
, player
);
3591 var_DelCallback(aout
, "mute", vlc_player_AoutCallback
, player
);
3592 var_DelCallback(player
, "corks", vlc_player_AoutCallback
, NULL
);
3594 if (player
->resource
)
3595 input_resource_Release(player
->resource
);
3597 vlc_object_release(player
);