1 /*****************************************************************************
2 * player_input.c: Player input implementation
3 *****************************************************************************
4 * Copyright © 2018-2019 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>
26 #include <vlc_interface.h>
29 struct vlc_player_track_priv
*
30 vlc_player_input_FindTrackById(struct vlc_player_input
*input
, vlc_es_id_t
*id
,
33 vlc_player_track_vector
*vec
=
34 vlc_player_input_GetTrackVector(input
, vlc_es_id_GetCat(id
));
35 return vec
? vlc_player_track_vector_FindById(vec
, id
, idx
) : NULL
;
39 vlc_player_input_HandleAtoBLoop(struct vlc_player_input
*input
, vlc_tick_t time
,
42 vlc_player_t
*player
= input
->player
;
44 if (player
->input
!= input
)
47 assert(input
->abloop_state
[0].set
&& input
->abloop_state
[1].set
);
49 if (time
!= VLC_TICK_INVALID
50 && input
->abloop_state
[0].time
!= VLC_TICK_INVALID
51 && input
->abloop_state
[1].time
!= VLC_TICK_INVALID
)
53 if (time
>= input
->abloop_state
[1].time
)
54 vlc_player_SetTime(player
, input
->abloop_state
[0].time
);
56 else if (pos
>= input
->abloop_state
[1].pos
)
57 vlc_player_SetPosition(player
, input
->abloop_state
[0].pos
);
61 vlc_player_input_GetTime(struct vlc_player_input
*input
)
63 vlc_player_t
*player
= input
->player
;
66 if (input
== player
->input
67 && vlc_player_GetTimerPoint(player
, vlc_tick_now(), &ts
, NULL
) == 0)
73 vlc_player_input_GetPos(struct vlc_player_input
*input
)
75 vlc_player_t
*player
= input
->player
;
78 if (input
== player
->input
79 && vlc_player_GetTimerPoint(player
, vlc_tick_now(), NULL
, &pos
) == 0)
81 return input
->position
;
85 vlc_player_input_UpdateTime(struct vlc_player_input
*input
)
87 if (input
->abloop_state
[0].set
&& input
->abloop_state
[1].set
)
88 vlc_player_input_HandleAtoBLoop(input
, vlc_player_input_GetTime(input
),
89 vlc_player_input_GetPos(input
));
93 vlc_player_input_Start(struct vlc_player_input
*input
)
95 int ret
= input_Start(input
->thread
);
96 if (ret
!= VLC_SUCCESS
)
98 input
->started
= true;
103 vlc_player_WaitRetryDelay(vlc_player_t
*player
)
105 #define RETRY_TIMEOUT_BASE VLC_TICK_FROM_MS(100)
106 #define RETRY_TIMEOUT_MAX VLC_TICK_FROM_MS(3200)
107 if (player
->error_count
)
109 /* Delay the next opening in case of error to avoid busy loops */
110 vlc_tick_t delay
= RETRY_TIMEOUT_BASE
;
111 for (unsigned i
= 1; i
< player
->error_count
112 && delay
< RETRY_TIMEOUT_MAX
; ++i
)
113 delay
*= 2; /* Wait 100, 200, 400, 800, 1600 and finally 3200ms */
114 delay
+= vlc_tick_now();
116 while (player
->error_count
> 0
117 && vlc_cond_timedwait(&player
->start_delay_cond
, &player
->lock
,
119 if (player
->error_count
== 0)
120 return false; /* canceled */
126 vlc_player_input_HandleState(struct vlc_player_input
*input
,
127 enum vlc_player_state state
, vlc_tick_t state_date
)
129 vlc_player_t
*player
= input
->player
;
131 /* The STOPPING state can be set earlier by the player. In that case,
132 * ignore all future events except the STOPPED one */
133 if (input
->state
== VLC_PLAYER_STATE_STOPPING
134 && state
!= VLC_PLAYER_STATE_STOPPED
)
137 input
->state
= state
;
139 /* Override the global state if the player is still playing and has a next
141 bool send_event
= player
->global_state
!= state
;
142 switch (input
->state
)
144 case VLC_PLAYER_STATE_STOPPED
:
145 assert(!input
->started
);
146 assert(input
!= player
->input
);
150 vlc_player_title_list_Release(input
->titles
);
151 input
->titles
= NULL
;
152 vlc_player_SendEvent(player
, on_titles_changed
, NULL
);
155 vlc_player_ResetTimer(player
);
157 if (input
->error
!= VLC_PLAYER_ERROR_NONE
)
158 player
->error_count
++;
160 player
->error_count
= 0;
162 vlc_player_WaitRetryDelay(player
);
164 if (!player
->deleting
)
165 vlc_player_OpenNextMedia(player
);
167 player
->started
= false;
169 switch (player
->media_stopped_action
)
171 case VLC_PLAYER_MEDIA_STOPPED_EXIT
:
172 if (player
->input
&& player
->started
)
173 vlc_player_input_Start(player
->input
);
175 libvlc_Quit(vlc_object_instance(player
));
177 case VLC_PLAYER_MEDIA_STOPPED_CONTINUE
:
178 if (player
->input
&& player
->started
)
179 vlc_player_input_Start(player
->input
);
185 send_event
= !player
->started
;
187 case VLC_PLAYER_STATE_STOPPING
:
188 input
->started
= false;
190 vlc_player_UpdateTimerState(player
, NULL
,
191 VLC_PLAYER_TIMER_STATE_DISCONTINUITY
,
194 if (input
== player
->input
)
195 player
->input
= NULL
;
199 vlc_player_PrepareNextMedia(player
);
200 if (!player
->next_media
)
201 player
->started
= false;
203 send_event
= !player
->started
;
205 case VLC_PLAYER_STATE_PLAYING
:
206 input
->pause_date
= VLC_TICK_INVALID
;
208 case VLC_PLAYER_STATE_STARTED
:
209 if (player
->started
&&
210 player
->global_state
== VLC_PLAYER_STATE_PLAYING
)
214 case VLC_PLAYER_STATE_PAUSED
:
215 assert(player
->started
&& input
->started
);
216 assert(state_date
!= VLC_TICK_INVALID
);
217 input
->pause_date
= state_date
;
219 vlc_player_UpdateTimerState(player
, NULL
,
220 VLC_PLAYER_TIMER_STATE_PAUSED
,
224 vlc_assert_unreachable();
229 player
->global_state
= input
->state
;
230 vlc_player_SendEvent(player
, on_state_changed
, player
->global_state
);
235 vlc_player_input_HandleStateEvent(struct vlc_player_input
*input
,
236 input_state_e state
, vlc_tick_t state_date
)
241 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_STARTED
,
245 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_PLAYING
,
249 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_PAUSED
,
253 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_STOPPING
,
255 vlc_player_destructor_AddStoppingInput(input
->player
, input
);
258 /* Don't send errors if the input is stopped by the user */
261 /* Contrary to the input_thead_t, an error is not a state */
262 input
->error
= VLC_PLAYER_ERROR_GENERIC
;
263 vlc_player_SendEvent(input
->player
, on_error_changed
, input
->error
);
267 vlc_assert_unreachable();
272 vlc_player_input_HandleProgramEvent(struct vlc_player_input
*input
,
273 const struct vlc_input_event_program
*ev
)
275 vlc_player_t
*player
= input
->player
;
276 struct vlc_player_program
*prgm
;
277 vlc_player_program_vector
*vec
= &input
->program_vector
;
281 case VLC_INPUT_PROGRAM_ADDED
:
282 prgm
= vlc_player_program_New(ev
->id
, ev
->title
);
286 if (!vlc_vector_push(vec
, prgm
))
288 vlc_player_program_Delete(prgm
);
291 vlc_player_SendEvent(player
, on_program_list_changed
,
292 VLC_PLAYER_LIST_ADDED
, prgm
);
294 case VLC_INPUT_PROGRAM_DELETED
:
297 prgm
= vlc_player_program_vector_FindById(vec
, ev
->id
, &idx
);
300 vlc_player_SendEvent(player
, on_program_list_changed
,
301 VLC_PLAYER_LIST_REMOVED
, prgm
);
302 vlc_vector_remove(vec
, idx
);
303 vlc_player_program_Delete(prgm
);
307 case VLC_INPUT_PROGRAM_UPDATED
:
308 case VLC_INPUT_PROGRAM_SCRAMBLED
:
309 prgm
= vlc_player_program_vector_FindById(vec
, ev
->id
, NULL
);
312 if (ev
->action
== VLC_INPUT_PROGRAM_UPDATED
)
314 if (vlc_player_program_Update(prgm
, ev
->id
, ev
->title
) != 0)
318 prgm
->scrambled
= ev
->scrambled
;
319 vlc_player_SendEvent(player
, on_program_list_changed
,
320 VLC_PLAYER_LIST_UPDATED
, prgm
);
322 case VLC_INPUT_PROGRAM_SELECTED
:
324 int unselected_id
= -1, selected_id
= -1;
325 vlc_vector_foreach(prgm
, vec
)
327 if (prgm
->group_id
== ev
->id
)
331 assert(selected_id
== -1);
332 prgm
->selected
= true;
333 selected_id
= prgm
->group_id
;
340 assert(unselected_id
== -1);
341 prgm
->selected
= false;
342 unselected_id
= prgm
->group_id
;
346 if (unselected_id
!= -1 || selected_id
!= -1)
347 vlc_player_SendEvent(player
, on_program_selection_changed
,
348 unselected_id
, selected_id
);
352 vlc_assert_unreachable();
357 vlc_player_input_HandleTeletextMenu(struct vlc_player_input
*input
,
358 const struct vlc_input_event_es
*ev
)
360 vlc_player_t
*player
= input
->player
;
363 case VLC_INPUT_ES_ADDED
:
364 if (input
->teletext_menu
)
366 msg_Warn(player
, "Can't handle more than one teletext menu "
367 "track. Using the last one.");
368 vlc_player_track_priv_Delete(input
->teletext_menu
);
370 input
->teletext_menu
= vlc_player_track_priv_New(ev
->id
, ev
->title
,
372 if (!input
->teletext_menu
)
375 vlc_player_SendEvent(player
, on_teletext_menu_changed
, true);
377 case VLC_INPUT_ES_DELETED
:
379 if (input
->teletext_menu
&& input
->teletext_menu
->t
.es_id
== ev
->id
)
381 assert(!input
->teletext_enabled
);
383 vlc_player_track_priv_Delete(input
->teletext_menu
);
384 input
->teletext_menu
= NULL
;
385 vlc_player_SendEvent(player
, on_teletext_menu_changed
, false);
389 case VLC_INPUT_ES_UPDATED
:
391 case VLC_INPUT_ES_SELECTED
:
392 case VLC_INPUT_ES_UNSELECTED
:
393 if (input
->teletext_menu
->t
.es_id
== ev
->id
)
395 input
->teletext_enabled
= ev
->action
== VLC_INPUT_ES_SELECTED
;
396 vlc_player_SendEvent(player
, on_teletext_enabled_changed
,
397 input
->teletext_enabled
);
401 vlc_assert_unreachable();
406 vlc_player_input_HandleEsEvent(struct vlc_player_input
*input
,
407 const struct vlc_input_event_es
*ev
)
409 assert(ev
->id
&& ev
->title
&& ev
->fmt
);
411 if (ev
->fmt
->i_cat
== SPU_ES
&& ev
->fmt
->i_codec
== VLC_CODEC_TELETEXT
412 && (ev
->fmt
->subs
.teletext
.i_magazine
== 1
413 || ev
->fmt
->subs
.teletext
.i_magazine
> 8))
415 vlc_player_input_HandleTeletextMenu(input
, ev
);
419 vlc_player_track_vector
*vec
=
420 vlc_player_input_GetTrackVector(input
, ev
->fmt
->i_cat
);
422 return; /* UNKNOWN_ES or DATA_ES not handled */
424 vlc_player_t
*player
= input
->player
;
425 struct vlc_player_track_priv
*trackpriv
;
428 case VLC_INPUT_ES_ADDED
:
429 trackpriv
= vlc_player_track_priv_New(ev
->id
, ev
->title
, ev
->fmt
);
433 if (!vlc_vector_push(vec
, trackpriv
))
435 vlc_player_track_priv_Delete(trackpriv
);
438 vlc_player_SendEvent(player
, on_track_list_changed
,
439 VLC_PLAYER_LIST_ADDED
, &trackpriv
->t
);
440 switch (ev
->fmt
->i_cat
)
443 /* If we need to restore a specific track, let's do it upon
444 * insertion. The initialization of the default track when
445 * we don't have a value will be done when the first track
447 if (input
->ml
.restore_states
&&
448 input
->ml
.states
.current_video_track
!= -2 &&
449 input
->ml
.states
.current_video_track
== ev
->fmt
->i_id
)
450 vlc_player_SelectTrack(input
->player
, &trackpriv
->t
,
451 VLC_PLAYER_SELECT_EXCLUSIVE
);
454 if (input
->ml
.restore_states
&&
455 input
->ml
.states
.current_audio_track
!= -2 &&
456 input
->ml
.states
.current_audio_track
== ev
->fmt
->i_id
)
457 vlc_player_SelectTrack(input
->player
, &trackpriv
->t
,
458 VLC_PLAYER_SELECT_EXCLUSIVE
);
461 if (input
->ml
.restore_states
&&
462 input
->ml
.states
.current_subtitle_track
!= -2 &&
463 input
->ml
.states
.current_subtitle_track
== ev
->fmt
->i_id
)
464 vlc_player_SelectTrack(input
->player
, &trackpriv
->t
,
465 VLC_PLAYER_SELECT_EXCLUSIVE
);
470 case VLC_INPUT_ES_DELETED
:
473 trackpriv
= vlc_player_track_vector_FindById(vec
, ev
->id
, &idx
);
476 vlc_player_SendEvent(player
, on_track_list_changed
,
477 VLC_PLAYER_LIST_REMOVED
, &trackpriv
->t
);
478 vlc_vector_remove(vec
, idx
);
479 vlc_player_track_priv_Delete(trackpriv
);
483 case VLC_INPUT_ES_UPDATED
:
484 trackpriv
= vlc_player_track_vector_FindById(vec
, ev
->id
, NULL
);
487 if (vlc_player_track_priv_Update(trackpriv
, ev
->title
, ev
->fmt
) != 0)
489 vlc_player_SendEvent(player
, on_track_list_changed
,
490 VLC_PLAYER_LIST_UPDATED
, &trackpriv
->t
);
492 case VLC_INPUT_ES_SELECTED
:
493 trackpriv
= vlc_player_track_vector_FindById(vec
, ev
->id
, NULL
);
496 trackpriv
->t
.selected
= true;
497 trackpriv
->selected_by_user
= ev
->forced
;
498 vlc_player_SendEvent(player
, on_track_selection_changed
,
499 NULL
, trackpriv
->t
.es_id
);
501 switch (ev
->fmt
->i_cat
)
503 /* Save the default selected track to know if it changed
504 * when the playback stops, in order to save the user's
505 * explicitely selected track */
507 if (input
->ml
.default_video_track
== -2)
508 input
->ml
.default_video_track
= ev
->fmt
->i_id
;
511 if (input
->ml
.default_audio_track
== -2)
512 input
->ml
.default_audio_track
= ev
->fmt
->i_id
;
515 if (input
->ml
.default_subtitle_track
== -2)
516 input
->ml
.default_subtitle_track
= ev
->fmt
->i_id
;
522 case VLC_INPUT_ES_UNSELECTED
:
523 trackpriv
= vlc_player_track_vector_FindById(vec
, ev
->id
, NULL
);
526 vlc_player_RemoveTimerSource(player
, ev
->id
);
527 trackpriv
->t
.selected
= false;
528 trackpriv
->selected_by_user
= false;
529 vlc_player_SendEvent(player
, on_track_selection_changed
,
530 trackpriv
->t
.es_id
, NULL
);
534 vlc_assert_unreachable();
539 vlc_player_input_HandleTitleEvent(struct vlc_player_input
*input
,
540 const struct vlc_input_event_title
*ev
)
542 vlc_player_t
*player
= input
->player
;
545 case VLC_INPUT_TITLE_NEW_LIST
:
547 input_thread_private_t
*input_th
= input_priv(input
->thread
);
548 const int title_offset
= input_th
->i_title_offset
;
549 const int chapter_offset
= input_th
->i_seekpoint_offset
;
552 vlc_player_title_list_Release(input
->titles
);
553 input
->title_selected
= input
->chapter_selected
= 0;
555 vlc_player_title_list_Create(ev
->list
.array
, ev
->list
.count
,
556 title_offset
, chapter_offset
);
557 vlc_player_SendEvent(player
, on_titles_changed
, input
->titles
);
560 vlc_player_SendEvent(player
, on_title_selection_changed
,
561 &input
->titles
->array
[0], 0);
562 if (input
->ml
.restore
== VLC_RESTOREPOINT_TITLE
&&
563 (size_t)input
->ml
.states
.current_title
< ev
->list
.count
)
565 vlc_player_SelectTitleIdx(player
, input
->ml
.states
.current_title
);
567 input
->ml
.restore
= VLC_RESTOREPOINT_POSITION
;
569 else input
->ml
.restore
= VLC_RESTOREPOINT_NONE
;
572 case VLC_INPUT_TITLE_SELECTED
:
574 return; /* a previous VLC_INPUT_TITLE_NEW_LIST failed */
575 assert(ev
->selected_idx
< input
->titles
->count
);
576 input
->title_selected
= ev
->selected_idx
;
577 vlc_player_SendEvent(player
, on_title_selection_changed
,
578 &input
->titles
->array
[input
->title_selected
],
579 input
->title_selected
);
580 if (input
->ml
.restore
== VLC_RESTOREPOINT_POSITION
&&
581 input
->ml
.states
.current_title
>= 0 &&
582 (size_t)input
->ml
.states
.current_title
== ev
->selected_idx
&&
583 input
->ml
.states
.progress
> .0f
)
585 input_SetPosition(input
->thread
, input
->ml
.states
.progress
, false);
587 /* Reset the wanted title to avoid forcing it or the position
588 * again during the next title change
590 input
->ml
.restore
= VLC_RESTOREPOINT_NONE
;
593 vlc_assert_unreachable();
598 vlc_player_input_HandleChapterEvent(struct vlc_player_input
*input
,
599 const struct vlc_input_event_chapter
*ev
)
601 vlc_player_t
*player
= input
->player
;
602 if (!input
->titles
|| ev
->title
< 0 || ev
->seekpoint
< 0)
603 return; /* a previous VLC_INPUT_TITLE_NEW_LIST failed */
605 assert((size_t)ev
->title
< input
->titles
->count
);
606 const struct vlc_player_title
*title
= &input
->titles
->array
[ev
->title
];
607 if (!title
->chapter_count
)
610 assert(ev
->seekpoint
< (int)title
->chapter_count
);
611 input
->title_selected
= ev
->title
;
612 input
->chapter_selected
= ev
->seekpoint
;
614 const struct vlc_player_chapter
*chapter
= &title
->chapters
[ev
->seekpoint
];
615 vlc_player_SendEvent(player
, on_chapter_selection_changed
, title
, ev
->title
,
616 chapter
, ev
->seekpoint
);
620 vlc_player_input_HandleVoutEvent(struct vlc_player_input
*input
,
621 const struct vlc_input_event_vout
*ev
)
626 vlc_player_t
*player
= input
->player
;
628 struct vlc_player_track_priv
*trackpriv
=
629 vlc_player_input_FindTrackById(input
, ev
->id
, NULL
);
633 const bool is_video_es
= trackpriv
->t
.fmt
.i_cat
== VIDEO_ES
;
637 case VLC_INPUT_EVENT_VOUT_STARTED
:
638 trackpriv
->vout
= ev
->vout
;
639 vlc_player_SendEvent(player
, on_vout_changed
,
640 VLC_PLAYER_VOUT_STARTED
, ev
->vout
,
645 /* Register vout callbacks after the vout list event */
646 vlc_player_vout_AddCallbacks(player
, ev
->vout
);
649 case VLC_INPUT_EVENT_VOUT_STOPPED
:
652 /* Un-register vout callbacks before the vout list event */
653 vlc_player_vout_DelCallbacks(player
, ev
->vout
);
656 trackpriv
->vout
= NULL
;
657 vlc_player_SendEvent(player
, on_vout_changed
,
658 VLC_PLAYER_VOUT_STOPPED
, ev
->vout
,
659 VLC_VOUT_ORDER_NONE
, ev
->id
);
662 vlc_assert_unreachable();
667 input_thread_Events(input_thread_t
*input_thread
,
668 const struct vlc_input_event
*event
, void *user_data
)
670 struct vlc_player_input
*input
= user_data
;
671 vlc_player_t
*player
= input
->player
;
673 assert(input_thread
== input
->thread
);
675 /* No player lock for this event */
676 if (event
->type
== INPUT_EVENT_OUTPUT_CLOCK
)
678 if (event
->output_clock
.system_ts
!= VLC_TICK_INVALID
)
680 const struct vlc_player_timer_point point
= {
682 .rate
= event
->output_clock
.rate
,
683 .ts
= event
->output_clock
.ts
,
684 .length
= VLC_TICK_INVALID
,
685 .system_date
= event
->output_clock
.system_ts
,
687 vlc_player_UpdateTimer(player
, event
->output_clock
.id
,
688 event
->output_clock
.master
, &point
,
690 event
->output_clock
.frame_rate
,
691 event
->output_clock
.frame_rate_base
);
695 vlc_player_UpdateTimerState(player
, event
->output_clock
.id
,
696 VLC_PLAYER_TIMER_STATE_DISCONTINUITY
,
702 vlc_mutex_lock(&player
->lock
);
706 case INPUT_EVENT_STATE
:
707 vlc_player_input_HandleStateEvent(input
, event
->state
.value
,
710 case INPUT_EVENT_RATE
:
711 input
->rate
= event
->rate
;
712 vlc_player_SendEvent(player
, on_rate_changed
, input
->rate
);
714 case INPUT_EVENT_CAPABILITIES
:
716 int old_caps
= input
->capabilities
;
717 input
->capabilities
= event
->capabilities
;
718 vlc_player_SendEvent(player
, on_capabilities_changed
,
719 old_caps
, input
->capabilities
);
722 case INPUT_EVENT_TIMES
:
724 bool changed
= false;
725 vlc_tick_t system_date
= VLC_TICK_INVALID
;
727 if (event
->times
.ms
!= VLC_TICK_INVALID
728 && (input
->time
!= event
->times
.ms
729 || input
->position
!= event
->times
.percentage
))
731 input
->time
= event
->times
.ms
;
732 input
->position
= event
->times
.percentage
;
733 system_date
= vlc_tick_now();
735 vlc_player_SendEvent(player
, on_position_changed
,
736 input
->time
, input
->position
);
738 vlc_player_input_UpdateTime(input
);
740 if (input
->length
!= event
->times
.length
)
742 input
->length
= event
->times
.length
;
743 input_item_SetDuration(input_GetItem(input
->thread
), event
->times
.length
);
744 vlc_player_SendEvent(player
, on_length_changed
, input
->length
);
748 if (input
->normal_time
!= event
->times
.normal_time
)
750 assert(event
->times
.normal_time
!= VLC_TICK_INVALID
);
751 input
->normal_time
= event
->times
.normal_time
;
757 const struct vlc_player_timer_point point
= {
758 .position
= input
->position
,
760 .ts
= input
->time
+ input
->normal_time
,
761 .length
= input
->length
,
762 .system_date
= system_date
,
764 vlc_player_UpdateTimer(player
, NULL
, false, &point
,
765 input
->normal_time
, 0, 0);
769 case INPUT_EVENT_PROGRAM
:
770 vlc_player_input_HandleProgramEvent(input
, &event
->program
);
773 vlc_player_input_HandleEsEvent(input
, &event
->es
);
775 case INPUT_EVENT_TITLE
:
776 vlc_player_input_HandleTitleEvent(input
, &event
->title
);
778 case INPUT_EVENT_CHAPTER
:
779 vlc_player_input_HandleChapterEvent(input
, &event
->chapter
);
781 case INPUT_EVENT_RECORD
:
782 input
->recording
= event
->record
;
783 vlc_player_SendEvent(player
, on_recording_changed
, input
->recording
);
785 case INPUT_EVENT_STATISTICS
:
786 input
->stats
= *event
->stats
;
787 vlc_player_SendEvent(player
, on_statistics_changed
, &input
->stats
);
789 case INPUT_EVENT_SIGNAL
:
790 input
->signal_quality
= event
->signal
.quality
;
791 input
->signal_strength
= event
->signal
.strength
;
792 vlc_player_SendEvent(player
, on_signal_changed
,
793 input
->signal_quality
, input
->signal_strength
);
795 case INPUT_EVENT_CACHE
:
796 input
->cache
= event
->cache
;
797 vlc_player_SendEvent(player
, on_buffering_changed
, event
->cache
);
799 case INPUT_EVENT_VOUT
:
800 vlc_player_input_HandleVoutEvent(input
, &event
->vout
);
802 case INPUT_EVENT_ITEM_META
:
803 vlc_player_SendEvent(player
, on_media_meta_changed
,
804 input_GetItem(input
->thread
));
806 case INPUT_EVENT_ITEM_EPG
:
807 vlc_player_SendEvent(player
, on_media_epg_changed
,
808 input_GetItem(input
->thread
));
810 case INPUT_EVENT_SUBITEMS
:
811 vlc_player_SendEvent(player
, on_media_subitems_changed
,
812 input_GetItem(input
->thread
), event
->subitems
);
814 case INPUT_EVENT_DEAD
:
815 if (input
->started
) /* Can happen with early input_thread fails */
816 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_STOPPING
,
818 vlc_player_destructor_AddJoinableInput(player
, input
);
820 case INPUT_EVENT_VBI_PAGE
:
821 input
->teletext_page
= event
->vbi_page
< 999 ? event
->vbi_page
: 100;
822 vlc_player_SendEvent(player
, on_teletext_page_changed
,
823 input
->teletext_page
);
825 case INPUT_EVENT_VBI_TRANSPARENCY
:
826 input
->teletext_transparent
= event
->vbi_transparent
;
827 vlc_player_SendEvent(player
, on_teletext_transparency_changed
,
828 input
->teletext_transparent
);
834 vlc_mutex_unlock(&player
->lock
);
838 vlc_player_input_SelectTracksByStringIds(struct vlc_player_input
*input
,
839 enum es_format_category_e cat
,
842 input_SetEsCatIds(input
->thread
, cat
, str_ids
);
845 struct vlc_player_input
*
846 vlc_player_input_New(vlc_player_t
*player
, input_item_t
*item
)
848 struct vlc_player_input
*input
= malloc(sizeof(*input
));
852 input
->player
= player
;
853 input
->started
= false;
855 input
->state
= VLC_PLAYER_STATE_STOPPED
;
856 input
->error
= VLC_PLAYER_ERROR_NONE
;
858 input
->capabilities
= 0;
859 input
->length
= input
->time
= VLC_TICK_INVALID
;
860 input
->normal_time
= VLC_TICK_0
;
861 input
->pause_date
= VLC_TICK_INVALID
;
862 input
->position
= 0.f
;
864 input
->recording
= false;
867 input
->signal_quality
= input
->signal_strength
= -1.f
;
869 memset(&input
->stats
, 0, sizeof(input
->stats
));
871 vlc_vector_init(&input
->program_vector
);
872 vlc_vector_init(&input
->video_track_vector
);
873 vlc_vector_init(&input
->audio_track_vector
);
874 vlc_vector_init(&input
->spu_track_vector
);
875 input
->teletext_menu
= NULL
;
877 input
->titles
= NULL
;
878 input
->title_selected
= input
->chapter_selected
= 0;
880 input
->teletext_enabled
= input
->teletext_transparent
= false;
881 input
->teletext_page
= 0;
883 input
->abloop_state
[0].set
= input
->abloop_state
[1].set
= false;
885 memset(&input
->ml
.states
, 0, sizeof(input
->ml
.states
));
886 input
->ml
.states
.aspect_ratio
= input
->ml
.states
.crop
=
887 input
->ml
.states
.deinterlace
= input
->ml
.states
.video_filter
= NULL
;
888 input
->ml
.states
.current_title
= -1;
889 input
->ml
.states
.current_video_track
=
890 input
->ml
.states
.current_audio_track
=
891 input
->ml
.states
.current_subtitle_track
=
892 input
->ml
.default_video_track
= input
->ml
.default_audio_track
=
893 input
->ml
.default_subtitle_track
= -2;
894 input
->ml
.states
.progress
= -1.f
;
895 input
->ml
.restore
= VLC_RESTOREPOINT_NONE
;
896 input
->ml
.restore_states
= false;
897 input
->ml
.delay_restore
= false;
899 input
->thread
= input_Create(player
, input_thread_Events
, input
, item
,
900 player
->resource
, player
->renderer
);
906 vlc_player_input_RestoreMlStates(input
, false);
908 if (player
->video_string_ids
)
909 vlc_player_input_SelectTracksByStringIds(input
, VIDEO_ES
,
910 player
->video_string_ids
);
912 if (player
->audio_string_ids
)
913 vlc_player_input_SelectTracksByStringIds(input
, AUDIO_ES
,
914 player
->audio_string_ids
);
916 if (player
->sub_string_ids
)
917 vlc_player_input_SelectTracksByStringIds(input
, SPU_ES
,
918 player
->sub_string_ids
);
920 /* Initial sub/audio delay */
921 const vlc_tick_t cat_delays
[DATA_ES
] = {
923 VLC_TICK_FROM_MS(var_InheritInteger(player
, "audio-desync")),
925 vlc_tick_from_samples(var_InheritInteger(player
, "sub-delay"), 10),
928 for (enum es_format_category_e i
= UNKNOWN_ES
; i
< DATA_ES
; ++i
)
930 input
->cat_delays
[i
] = cat_delays
[i
];
931 if (cat_delays
[i
] != 0)
933 const input_control_param_t param
= {
934 .cat_delay
= { i
, cat_delays
[i
] }
936 int ret
= input_ControlPush(input
->thread
,
937 INPUT_CONTROL_SET_CATEGORY_DELAY
,
939 if (ret
== VLC_SUCCESS
)
940 vlc_player_SendEvent(player
, on_category_delay_changed
, i
,
948 vlc_player_input_Delete(struct vlc_player_input
*input
)
950 assert(input
->titles
== NULL
);
951 assert(input
->program_vector
.size
== 0);
952 assert(input
->video_track_vector
.size
== 0);
953 assert(input
->audio_track_vector
.size
== 0);
954 assert(input
->spu_track_vector
.size
== 0);
955 assert(input
->teletext_menu
== NULL
);
957 vlc_vector_destroy(&input
->program_vector
);
958 vlc_vector_destroy(&input
->video_track_vector
);
959 vlc_vector_destroy(&input
->audio_track_vector
);
960 vlc_vector_destroy(&input
->spu_track_vector
);
962 input_Close(input
->thread
);