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
.states
.current_video_track
!= -2 &&
448 input
->ml
.states
.current_video_track
== ev
->fmt
->i_id
)
449 vlc_player_SelectTrack(input
->player
, &trackpriv
->t
,
450 VLC_PLAYER_SELECT_EXCLUSIVE
);
453 if (input
->ml
.states
.current_audio_track
!= -2 &&
454 input
->ml
.states
.current_audio_track
== ev
->fmt
->i_id
)
455 vlc_player_SelectTrack(input
->player
, &trackpriv
->t
,
456 VLC_PLAYER_SELECT_EXCLUSIVE
);
459 if (input
->ml
.states
.current_subtitle_track
!= -2 &&
460 input
->ml
.states
.current_subtitle_track
== ev
->fmt
->i_id
)
461 vlc_player_SelectTrack(input
->player
, &trackpriv
->t
,
462 VLC_PLAYER_SELECT_EXCLUSIVE
);
467 case VLC_INPUT_ES_DELETED
:
470 trackpriv
= vlc_player_track_vector_FindById(vec
, ev
->id
, &idx
);
473 vlc_player_SendEvent(player
, on_track_list_changed
,
474 VLC_PLAYER_LIST_REMOVED
, &trackpriv
->t
);
475 vlc_vector_remove(vec
, idx
);
476 vlc_player_track_priv_Delete(trackpriv
);
480 case VLC_INPUT_ES_UPDATED
:
481 trackpriv
= vlc_player_track_vector_FindById(vec
, ev
->id
, NULL
);
484 if (vlc_player_track_priv_Update(trackpriv
, ev
->title
, ev
->fmt
) != 0)
486 vlc_player_SendEvent(player
, on_track_list_changed
,
487 VLC_PLAYER_LIST_UPDATED
, &trackpriv
->t
);
489 case VLC_INPUT_ES_SELECTED
:
490 trackpriv
= vlc_player_track_vector_FindById(vec
, ev
->id
, NULL
);
493 trackpriv
->t
.selected
= true;
494 vlc_player_SendEvent(player
, on_track_selection_changed
,
495 NULL
, trackpriv
->t
.es_id
);
497 switch (ev
->fmt
->i_cat
)
499 /* Save the default selected track to know if it changed
500 * when the playback stops, in order to save the user's
501 * explicitely selected track */
503 if (input
->ml
.default_video_track
== -2)
504 input
->ml
.default_video_track
= ev
->fmt
->i_id
;
507 if (input
->ml
.default_audio_track
== -2)
508 input
->ml
.default_audio_track
= ev
->fmt
->i_id
;
511 if (input
->ml
.default_subtitle_track
== -2)
512 input
->ml
.default_subtitle_track
= ev
->fmt
->i_id
;
518 case VLC_INPUT_ES_UNSELECTED
:
519 trackpriv
= vlc_player_track_vector_FindById(vec
, ev
->id
, NULL
);
522 vlc_player_RemoveTimerSource(player
, ev
->id
);
523 trackpriv
->t
.selected
= false;
524 vlc_player_SendEvent(player
, on_track_selection_changed
,
525 trackpriv
->t
.es_id
, NULL
);
529 vlc_assert_unreachable();
534 vlc_player_input_HandleTitleEvent(struct vlc_player_input
*input
,
535 const struct vlc_input_event_title
*ev
)
537 vlc_player_t
*player
= input
->player
;
540 case VLC_INPUT_TITLE_NEW_LIST
:
542 input_thread_private_t
*input_th
= input_priv(input
->thread
);
543 const int title_offset
= input_th
->i_title_offset
;
544 const int chapter_offset
= input_th
->i_seekpoint_offset
;
547 vlc_player_title_list_Release(input
->titles
);
548 input
->title_selected
= input
->chapter_selected
= 0;
550 vlc_player_title_list_Create(ev
->list
.array
, ev
->list
.count
,
551 title_offset
, chapter_offset
);
552 vlc_player_SendEvent(player
, on_titles_changed
, input
->titles
);
555 vlc_player_SendEvent(player
, on_title_selection_changed
,
556 &input
->titles
->array
[0], 0);
557 if (input
->ml
.states
.current_title
>= 0 &&
558 (size_t)input
->ml
.states
.current_title
< ev
->list
.count
)
560 vlc_player_SelectTitleIdx(player
, input
->ml
.states
.current_title
);
565 case VLC_INPUT_TITLE_SELECTED
:
567 return; /* a previous VLC_INPUT_TITLE_NEW_LIST failed */
568 assert(ev
->selected_idx
< input
->titles
->count
);
569 input
->title_selected
= ev
->selected_idx
;
570 vlc_player_SendEvent(player
, on_title_selection_changed
,
571 &input
->titles
->array
[input
->title_selected
],
572 input
->title_selected
);
573 if (input
->ml
.states
.current_title
>= 0 &&
574 (size_t)input
->ml
.states
.current_title
== ev
->selected_idx
&&
575 input
->ml
.states
.progress
> .0f
)
577 input_SetPosition(input
->thread
, input
->ml
.states
.progress
, false);
578 /* Reset the wanted title to avoid forcing it or the position
579 * again during the next title change
581 input
->ml
.states
.current_title
= 0;
585 vlc_assert_unreachable();
590 vlc_player_input_HandleChapterEvent(struct vlc_player_input
*input
,
591 const struct vlc_input_event_chapter
*ev
)
593 vlc_player_t
*player
= input
->player
;
594 if (!input
->titles
|| ev
->title
< 0 || ev
->seekpoint
< 0)
595 return; /* a previous VLC_INPUT_TITLE_NEW_LIST failed */
597 assert((size_t)ev
->title
< input
->titles
->count
);
598 const struct vlc_player_title
*title
= &input
->titles
->array
[ev
->title
];
599 if (!title
->chapter_count
)
602 assert(ev
->seekpoint
< (int)title
->chapter_count
);
603 input
->title_selected
= ev
->title
;
604 input
->chapter_selected
= ev
->seekpoint
;
606 const struct vlc_player_chapter
*chapter
= &title
->chapters
[ev
->seekpoint
];
607 vlc_player_SendEvent(player
, on_chapter_selection_changed
, title
, ev
->title
,
608 chapter
, ev
->seekpoint
);
612 vlc_player_input_HandleVoutEvent(struct vlc_player_input
*input
,
613 const struct vlc_input_event_vout
*ev
)
618 vlc_player_t
*player
= input
->player
;
620 struct vlc_player_track_priv
*trackpriv
=
621 vlc_player_input_FindTrackById(input
, ev
->id
, NULL
);
625 const bool is_video_es
= trackpriv
->t
.fmt
.i_cat
== VIDEO_ES
;
629 case VLC_INPUT_EVENT_VOUT_ADDED
:
630 trackpriv
->vout
= ev
->vout
;
631 vlc_player_SendEvent(player
, on_vout_changed
,
632 VLC_PLAYER_VOUT_STARTED
, ev
->vout
,
637 /* Register vout callbacks after the vout list event */
638 vlc_player_vout_AddCallbacks(player
, ev
->vout
);
641 case VLC_INPUT_EVENT_VOUT_DELETED
:
644 /* Un-register vout callbacks before the vout list event */
645 vlc_player_vout_DelCallbacks(player
, ev
->vout
);
648 trackpriv
->vout
= NULL
;
649 vlc_player_SendEvent(player
, on_vout_changed
,
650 VLC_PLAYER_VOUT_STOPPED
, ev
->vout
,
651 VLC_VOUT_ORDER_NONE
, ev
->id
);
654 vlc_assert_unreachable();
659 input_thread_Events(input_thread_t
*input_thread
,
660 const struct vlc_input_event
*event
, void *user_data
)
662 struct vlc_player_input
*input
= user_data
;
663 vlc_player_t
*player
= input
->player
;
665 assert(input_thread
== input
->thread
);
667 /* No player lock for this event */
668 if (event
->type
== INPUT_EVENT_OUTPUT_CLOCK
)
670 if (event
->output_clock
.system_ts
!= VLC_TICK_INVALID
)
672 const struct vlc_player_timer_point point
= {
674 .rate
= event
->output_clock
.rate
,
675 .ts
= event
->output_clock
.ts
,
676 .length
= VLC_TICK_INVALID
,
677 .system_date
= event
->output_clock
.system_ts
,
679 vlc_player_UpdateTimer(player
, event
->output_clock
.id
,
680 event
->output_clock
.master
, &point
,
682 event
->output_clock
.frame_rate
,
683 event
->output_clock
.frame_rate_base
);
687 vlc_player_UpdateTimerState(player
, event
->output_clock
.id
,
688 VLC_PLAYER_TIMER_STATE_DISCONTINUITY
,
694 vlc_mutex_lock(&player
->lock
);
698 case INPUT_EVENT_STATE
:
699 vlc_player_input_HandleStateEvent(input
, event
->state
.value
,
702 case INPUT_EVENT_RATE
:
703 input
->rate
= event
->rate
;
704 vlc_player_SendEvent(player
, on_rate_changed
, input
->rate
);
706 case INPUT_EVENT_CAPABILITIES
:
708 int old_caps
= input
->capabilities
;
709 input
->capabilities
= event
->capabilities
;
710 vlc_player_SendEvent(player
, on_capabilities_changed
,
711 old_caps
, input
->capabilities
);
714 case INPUT_EVENT_TIMES
:
716 bool changed
= false;
717 vlc_tick_t system_date
= VLC_TICK_INVALID
;
719 if (event
->times
.ms
!= VLC_TICK_INVALID
720 && (input
->time
!= event
->times
.ms
721 || input
->position
!= event
->times
.percentage
))
723 input
->time
= event
->times
.ms
;
724 input
->position
= event
->times
.percentage
;
725 system_date
= vlc_tick_now();
727 vlc_player_SendEvent(player
, on_position_changed
,
728 input
->time
, input
->position
);
730 vlc_player_input_UpdateTime(input
);
732 if (input
->length
!= event
->times
.length
)
734 input
->length
= event
->times
.length
;
735 input_item_SetDuration(input_GetItem(input
->thread
), event
->times
.length
);
736 vlc_player_SendEvent(player
, on_length_changed
, input
->length
);
740 if (input
->normal_time
!= event
->times
.normal_time
)
742 assert(event
->times
.normal_time
!= VLC_TICK_INVALID
);
743 input
->normal_time
= event
->times
.normal_time
;
749 const struct vlc_player_timer_point point
= {
750 .position
= input
->position
,
752 .ts
= input
->time
+ input
->normal_time
,
753 .length
= input
->length
,
754 .system_date
= system_date
,
756 vlc_player_UpdateTimer(player
, NULL
, false, &point
,
757 input
->normal_time
, 0, 0);
761 case INPUT_EVENT_PROGRAM
:
762 vlc_player_input_HandleProgramEvent(input
, &event
->program
);
765 vlc_player_input_HandleEsEvent(input
, &event
->es
);
767 case INPUT_EVENT_TITLE
:
768 vlc_player_input_HandleTitleEvent(input
, &event
->title
);
770 case INPUT_EVENT_CHAPTER
:
771 vlc_player_input_HandleChapterEvent(input
, &event
->chapter
);
773 case INPUT_EVENT_RECORD
:
774 input
->recording
= event
->record
;
775 vlc_player_SendEvent(player
, on_recording_changed
, input
->recording
);
777 case INPUT_EVENT_STATISTICS
:
778 input
->stats
= *event
->stats
;
779 vlc_player_SendEvent(player
, on_statistics_changed
, &input
->stats
);
781 case INPUT_EVENT_SIGNAL
:
782 input
->signal_quality
= event
->signal
.quality
;
783 input
->signal_strength
= event
->signal
.strength
;
784 vlc_player_SendEvent(player
, on_signal_changed
,
785 input
->signal_quality
, input
->signal_strength
);
787 case INPUT_EVENT_CACHE
:
788 input
->cache
= event
->cache
;
789 vlc_player_SendEvent(player
, on_buffering_changed
, event
->cache
);
791 case INPUT_EVENT_VOUT
:
792 vlc_player_input_HandleVoutEvent(input
, &event
->vout
);
794 case INPUT_EVENT_ITEM_META
:
795 vlc_player_SendEvent(player
, on_media_meta_changed
,
796 input_GetItem(input
->thread
));
798 case INPUT_EVENT_ITEM_EPG
:
799 vlc_player_SendEvent(player
, on_media_epg_changed
,
800 input_GetItem(input
->thread
));
802 case INPUT_EVENT_SUBITEMS
:
803 vlc_player_SendEvent(player
, on_media_subitems_changed
,
804 input_GetItem(input
->thread
), event
->subitems
);
806 case INPUT_EVENT_DEAD
:
807 if (input
->started
) /* Can happen with early input_thread fails */
808 vlc_player_input_HandleState(input
, VLC_PLAYER_STATE_STOPPING
,
810 vlc_player_destructor_AddJoinableInput(player
, input
);
812 case INPUT_EVENT_VBI_PAGE
:
813 input
->teletext_page
= event
->vbi_page
< 999 ? event
->vbi_page
: 100;
814 vlc_player_SendEvent(player
, on_teletext_page_changed
,
815 input
->teletext_page
);
817 case INPUT_EVENT_VBI_TRANSPARENCY
:
818 input
->teletext_transparent
= event
->vbi_transparent
;
819 vlc_player_SendEvent(player
, on_teletext_transparency_changed
,
820 input
->teletext_transparent
);
826 vlc_mutex_unlock(&player
->lock
);
829 struct vlc_player_input
*
830 vlc_player_input_New(vlc_player_t
*player
, input_item_t
*item
)
832 struct vlc_player_input
*input
= malloc(sizeof(*input
));
836 input
->player
= player
;
837 input
->started
= false;
839 input
->state
= VLC_PLAYER_STATE_STOPPED
;
840 input
->error
= VLC_PLAYER_ERROR_NONE
;
842 input
->capabilities
= 0;
843 input
->length
= input
->time
= VLC_TICK_INVALID
;
844 input
->normal_time
= VLC_TICK_0
;
845 input
->pause_date
= VLC_TICK_INVALID
;
846 input
->position
= 0.f
;
848 input
->recording
= false;
851 input
->signal_quality
= input
->signal_strength
= -1.f
;
853 memset(&input
->stats
, 0, sizeof(input
->stats
));
855 vlc_vector_init(&input
->program_vector
);
856 vlc_vector_init(&input
->video_track_vector
);
857 vlc_vector_init(&input
->audio_track_vector
);
858 vlc_vector_init(&input
->spu_track_vector
);
859 input
->teletext_menu
= NULL
;
861 input
->titles
= NULL
;
862 input
->title_selected
= input
->chapter_selected
= 0;
864 input
->teletext_enabled
= input
->teletext_transparent
= false;
865 input
->teletext_page
= 0;
867 input
->abloop_state
[0].set
= input
->abloop_state
[1].set
= false;
869 memset(&input
->ml
.states
, 0, sizeof(input
->ml
.states
));
870 input
->ml
.states
.aspect_ratio
= input
->ml
.states
.crop
=
871 input
->ml
.states
.deinterlace
= input
->ml
.states
.video_filter
= NULL
;
872 input
->ml
.states
.current_title
= -1;
873 input
->ml
.states
.current_video_track
=
874 input
->ml
.states
.current_audio_track
=
875 input
->ml
.states
.current_subtitle_track
=
876 input
->ml
.default_video_track
= input
->ml
.default_audio_track
=
877 input
->ml
.default_subtitle_track
= -2;
878 input
->ml
.states
.progress
= -1.f
;
880 input
->thread
= input_Create(player
, input_thread_Events
, input
, item
,
881 player
->resource
, player
->renderer
);
888 vlc_player_input_RestoreMlStates(input
, item
);
890 /* Initial sub/audio delay */
891 const vlc_tick_t cat_delays
[DATA_ES
] = {
893 VLC_TICK_FROM_MS(var_InheritInteger(player
, "audio-desync")),
895 vlc_tick_from_samples(var_InheritInteger(player
, "sub-delay"), 10),
898 for (enum es_format_category_e i
= UNKNOWN_ES
; i
< DATA_ES
; ++i
)
900 input
->cat_delays
[i
] = cat_delays
[i
];
901 if (cat_delays
[i
] != 0)
903 const input_control_param_t param
= {
904 .cat_delay
= { i
, cat_delays
[i
] }
906 int ret
= input_ControlPush(input
->thread
,
907 INPUT_CONTROL_SET_CATEGORY_DELAY
,
909 if (ret
== VLC_SUCCESS
)
910 vlc_player_SendEvent(player
, on_category_delay_changed
, i
,
918 vlc_player_input_Delete(struct vlc_player_input
*input
)
920 assert(input
->titles
== NULL
);
921 assert(input
->program_vector
.size
== 0);
922 assert(input
->video_track_vector
.size
== 0);
923 assert(input
->audio_track_vector
.size
== 0);
924 assert(input
->spu_track_vector
.size
== 0);
925 assert(input
->teletext_menu
== NULL
);
927 vlc_vector_destroy(&input
->program_vector
);
928 vlc_vector_destroy(&input
->video_track_vector
);
929 vlc_vector_destroy(&input
->audio_track_vector
);
930 vlc_vector_destroy(&input
->spu_track_vector
);
932 input_Close(input
->thread
);