player: add selected_by_user in tracks
[vlc.git] / src / player / input.c
blob7fccd70b91e07585e7ae82ed7d4f154813f41db3
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 *****************************************************************************/
21 #ifdef HAVE_CONFIG_H
22 # include "config.h"
23 #endif
25 #include <vlc_common.h>
26 #include <vlc_interface.h>
27 #include "player.h"
29 struct vlc_player_track_priv *
30 vlc_player_input_FindTrackById(struct vlc_player_input *input, vlc_es_id_t *id,
31 size_t *idx)
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;
38 static void
39 vlc_player_input_HandleAtoBLoop(struct vlc_player_input *input, vlc_tick_t time,
40 float pos)
42 vlc_player_t *player = input->player;
44 if (player->input != input)
45 return;
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);
60 vlc_tick_t
61 vlc_player_input_GetTime(struct vlc_player_input *input)
63 vlc_player_t *player = input->player;
64 vlc_tick_t ts;
66 if (input == player->input
67 && vlc_player_GetTimerPoint(player, vlc_tick_now(), &ts, NULL) == 0)
68 return ts;
69 return input->time;
72 float
73 vlc_player_input_GetPos(struct vlc_player_input *input)
75 vlc_player_t *player = input->player;
76 float pos;
78 if (input == player->input
79 && vlc_player_GetTimerPoint(player, vlc_tick_now(), NULL, &pos) == 0)
80 return pos;
81 return input->position;
84 static void
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));
92 int
93 vlc_player_input_Start(struct vlc_player_input *input)
95 int ret = input_Start(input->thread);
96 if (ret != VLC_SUCCESS)
97 return ret;
98 input->started = true;
99 return ret;
102 static bool
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,
118 delay) == 0);
119 if (player->error_count == 0)
120 return false; /* canceled */
122 return true;
125 void
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)
135 return;
137 input->state = state;
139 /* Override the global state if the player is still playing and has a next
140 * media to play */
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);
148 if (input->titles)
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++;
159 else
160 player->error_count = 0;
162 vlc_player_WaitRetryDelay(player);
164 if (!player->deleting)
165 vlc_player_OpenNextMedia(player);
166 if (!player->input)
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);
174 else
175 libvlc_Quit(vlc_object_instance(player));
176 break;
177 case VLC_PLAYER_MEDIA_STOPPED_CONTINUE:
178 if (player->input && player->started)
179 vlc_player_input_Start(player->input);
180 break;
181 default:
182 break;
185 send_event = !player->started;
186 break;
187 case VLC_PLAYER_STATE_STOPPING:
188 input->started = false;
190 vlc_player_UpdateTimerState(player, NULL,
191 VLC_PLAYER_TIMER_STATE_DISCONTINUITY,
192 VLC_TICK_INVALID);
194 if (input == player->input)
195 player->input = NULL;
197 if (player->started)
199 vlc_player_PrepareNextMedia(player);
200 if (!player->next_media)
201 player->started = false;
203 send_event = !player->started;
204 break;
205 case VLC_PLAYER_STATE_PLAYING:
206 input->pause_date = VLC_TICK_INVALID;
207 /* fallthrough */
208 case VLC_PLAYER_STATE_STARTED:
209 if (player->started &&
210 player->global_state == VLC_PLAYER_STATE_PLAYING)
211 send_event = false;
212 break;
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,
221 input->pause_date);
222 break;
223 default:
224 vlc_assert_unreachable();
227 if (send_event)
229 player->global_state = input->state;
230 vlc_player_SendEvent(player, on_state_changed, player->global_state);
234 static void
235 vlc_player_input_HandleStateEvent(struct vlc_player_input *input,
236 input_state_e state, vlc_tick_t state_date)
238 switch (state)
240 case OPENING_S:
241 vlc_player_input_HandleState(input, VLC_PLAYER_STATE_STARTED,
242 VLC_TICK_INVALID);
243 break;
244 case PLAYING_S:
245 vlc_player_input_HandleState(input, VLC_PLAYER_STATE_PLAYING,
246 state_date);
247 break;
248 case PAUSE_S:
249 vlc_player_input_HandleState(input, VLC_PLAYER_STATE_PAUSED,
250 state_date);
251 break;
252 case END_S:
253 vlc_player_input_HandleState(input, VLC_PLAYER_STATE_STOPPING,
254 VLC_TICK_INVALID);
255 vlc_player_destructor_AddStoppingInput(input->player, input);
256 break;
257 case ERROR_S:
258 /* Don't send errors if the input is stopped by the user */
259 if (input->started)
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);
265 break;
266 default:
267 vlc_assert_unreachable();
271 static void
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;
279 switch (ev->action)
281 case VLC_INPUT_PROGRAM_ADDED:
282 prgm = vlc_player_program_New(ev->id, ev->title);
283 if (!prgm)
284 break;
286 if (!vlc_vector_push(vec, prgm))
288 vlc_player_program_Delete(prgm);
289 break;
291 vlc_player_SendEvent(player, on_program_list_changed,
292 VLC_PLAYER_LIST_ADDED, prgm);
293 break;
294 case VLC_INPUT_PROGRAM_DELETED:
296 size_t idx;
297 prgm = vlc_player_program_vector_FindById(vec, ev->id, &idx);
298 if (prgm)
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);
305 break;
307 case VLC_INPUT_PROGRAM_UPDATED:
308 case VLC_INPUT_PROGRAM_SCRAMBLED:
309 prgm = vlc_player_program_vector_FindById(vec, ev->id, NULL);
310 if (!prgm)
311 break;
312 if (ev->action == VLC_INPUT_PROGRAM_UPDATED)
314 if (vlc_player_program_Update(prgm, ev->id, ev->title) != 0)
315 break;
317 else
318 prgm->scrambled = ev->scrambled;
319 vlc_player_SendEvent(player, on_program_list_changed,
320 VLC_PLAYER_LIST_UPDATED, prgm);
321 break;
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)
329 if (!prgm->selected)
331 assert(selected_id == -1);
332 prgm->selected = true;
333 selected_id = prgm->group_id;
336 else
338 if (prgm->selected)
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);
349 break;
351 default:
352 vlc_assert_unreachable();
356 static void
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;
361 switch (ev->action)
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,
371 ev->fmt);
372 if (!input->teletext_menu)
373 return;
375 vlc_player_SendEvent(player, on_teletext_menu_changed, true);
376 break;
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);
387 break;
389 case VLC_INPUT_ES_UPDATED:
390 break;
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);
399 break;
400 default:
401 vlc_assert_unreachable();
405 static void
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);
416 return;
419 vlc_player_track_vector *vec =
420 vlc_player_input_GetTrackVector(input, ev->fmt->i_cat);
421 if (!vec)
422 return; /* UNKNOWN_ES or DATA_ES not handled */
424 vlc_player_t *player = input->player;
425 struct vlc_player_track_priv *trackpriv;
426 switch (ev->action)
428 case VLC_INPUT_ES_ADDED:
429 trackpriv = vlc_player_track_priv_New(ev->id, ev->title, ev->fmt);
430 if (!trackpriv)
431 break;
433 if (!vlc_vector_push(vec, trackpriv))
435 vlc_player_track_priv_Delete(trackpriv);
436 break;
438 vlc_player_SendEvent(player, on_track_list_changed,
439 VLC_PLAYER_LIST_ADDED, &trackpriv->t);
440 switch (ev->fmt->i_cat)
442 case VIDEO_ES:
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
446 * gets selected */
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);
452 break;
453 case AUDIO_ES:
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);
459 break;
460 case SPU_ES:
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);
466 default:
467 break;
469 break;
470 case VLC_INPUT_ES_DELETED:
472 size_t idx;
473 trackpriv = vlc_player_track_vector_FindById(vec, ev->id, &idx);
474 if (trackpriv)
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);
481 break;
483 case VLC_INPUT_ES_UPDATED:
484 trackpriv = vlc_player_track_vector_FindById(vec, ev->id, NULL);
485 if (!trackpriv)
486 break;
487 if (vlc_player_track_priv_Update(trackpriv, ev->title, ev->fmt) != 0)
488 break;
489 vlc_player_SendEvent(player, on_track_list_changed,
490 VLC_PLAYER_LIST_UPDATED, &trackpriv->t);
491 break;
492 case VLC_INPUT_ES_SELECTED:
493 trackpriv = vlc_player_track_vector_FindById(vec, ev->id, NULL);
494 if (trackpriv)
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 */
506 case VIDEO_ES:
507 if (input->ml.default_video_track == -2)
508 input->ml.default_video_track = ev->fmt->i_id;
509 break;
510 case AUDIO_ES:
511 if (input->ml.default_audio_track == -2)
512 input->ml.default_audio_track = ev->fmt->i_id;
513 break;
514 case SPU_ES:
515 if (input->ml.default_subtitle_track == -2)
516 input->ml.default_subtitle_track = ev->fmt->i_id;
517 break;
518 default:
519 break;
521 break;
522 case VLC_INPUT_ES_UNSELECTED:
523 trackpriv = vlc_player_track_vector_FindById(vec, ev->id, NULL);
524 if (trackpriv)
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);
532 break;
533 default:
534 vlc_assert_unreachable();
538 static void
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;
543 switch (ev->action)
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;
551 if (input->titles)
552 vlc_player_title_list_Release(input->titles);
553 input->title_selected = input->chapter_selected = 0;
554 input->titles =
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);
558 if (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;
570 break;
572 case VLC_INPUT_TITLE_SELECTED:
573 if (!input->titles)
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;
591 break;
592 default:
593 vlc_assert_unreachable();
597 static void
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)
608 return;
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);
619 static void
620 vlc_player_input_HandleVoutEvent(struct vlc_player_input *input,
621 const struct vlc_input_event_vout *ev)
623 assert(ev->vout);
624 assert(ev->id);
626 vlc_player_t *player = input->player;
628 struct vlc_player_track_priv *trackpriv =
629 vlc_player_input_FindTrackById(input, ev->id, NULL);
630 if (!trackpriv)
631 return;
633 const bool is_video_es = trackpriv->t.fmt.i_cat == VIDEO_ES;
635 switch (ev->action)
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,
641 ev->order, ev->id);
643 if (is_video_es)
645 /* Register vout callbacks after the vout list event */
646 vlc_player_vout_AddCallbacks(player, ev->vout);
648 break;
649 case VLC_INPUT_EVENT_VOUT_STOPPED:
650 if (is_video_es)
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);
660 break;
661 default:
662 vlc_assert_unreachable();
666 static void
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 = {
681 .position = 0,
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,
689 VLC_TICK_INVALID,
690 event->output_clock.frame_rate,
691 event->output_clock.frame_rate_base);
693 else
695 vlc_player_UpdateTimerState(player, event->output_clock.id,
696 VLC_PLAYER_TIMER_STATE_DISCONTINUITY,
697 VLC_TICK_INVALID);
699 return;
702 vlc_mutex_lock(&player->lock);
704 switch (event->type)
706 case INPUT_EVENT_STATE:
707 vlc_player_input_HandleStateEvent(input, event->state.value,
708 event->state.date);
709 break;
710 case INPUT_EVENT_RATE:
711 input->rate = event->rate;
712 vlc_player_SendEvent(player, on_rate_changed, input->rate);
713 break;
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);
720 break;
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();
734 changed = true;
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);
745 changed = true;
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;
752 changed = true;
755 if (changed)
757 const struct vlc_player_timer_point point = {
758 .position = input->position,
759 .rate = input->rate,
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);
767 break;
769 case INPUT_EVENT_PROGRAM:
770 vlc_player_input_HandleProgramEvent(input, &event->program);
771 break;
772 case INPUT_EVENT_ES:
773 vlc_player_input_HandleEsEvent(input, &event->es);
774 break;
775 case INPUT_EVENT_TITLE:
776 vlc_player_input_HandleTitleEvent(input, &event->title);
777 break;
778 case INPUT_EVENT_CHAPTER:
779 vlc_player_input_HandleChapterEvent(input, &event->chapter);
780 break;
781 case INPUT_EVENT_RECORD:
782 input->recording = event->record;
783 vlc_player_SendEvent(player, on_recording_changed, input->recording);
784 break;
785 case INPUT_EVENT_STATISTICS:
786 input->stats = *event->stats;
787 vlc_player_SendEvent(player, on_statistics_changed, &input->stats);
788 break;
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);
794 break;
795 case INPUT_EVENT_CACHE:
796 input->cache = event->cache;
797 vlc_player_SendEvent(player, on_buffering_changed, event->cache);
798 break;
799 case INPUT_EVENT_VOUT:
800 vlc_player_input_HandleVoutEvent(input, &event->vout);
801 break;
802 case INPUT_EVENT_ITEM_META:
803 vlc_player_SendEvent(player, on_media_meta_changed,
804 input_GetItem(input->thread));
805 break;
806 case INPUT_EVENT_ITEM_EPG:
807 vlc_player_SendEvent(player, on_media_epg_changed,
808 input_GetItem(input->thread));
809 break;
810 case INPUT_EVENT_SUBITEMS:
811 vlc_player_SendEvent(player, on_media_subitems_changed,
812 input_GetItem(input->thread), event->subitems);
813 break;
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,
817 VLC_TICK_INVALID);
818 vlc_player_destructor_AddJoinableInput(player, input);
819 break;
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);
824 break;
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);
829 break;
830 default:
831 break;
834 vlc_mutex_unlock(&player->lock);
837 void
838 vlc_player_input_SelectTracksByStringIds(struct vlc_player_input *input,
839 enum es_format_category_e cat,
840 const char *str_ids)
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));
849 if (!input)
850 return NULL;
852 input->player = player;
853 input->started = false;
855 input->state = VLC_PLAYER_STATE_STOPPED;
856 input->error = VLC_PLAYER_ERROR_NONE;
857 input->rate = 1.f;
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;
866 input->cache = 0.f;
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);
901 if (!input->thread)
903 free(input);
904 return NULL;
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] = {
922 [AUDIO_ES] =
923 VLC_TICK_FROM_MS(var_InheritInteger(player, "audio-desync")),
924 [SPU_ES] =
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,
938 &param);
939 if (ret == VLC_SUCCESS)
940 vlc_player_SendEvent(player, on_category_delay_changed, i,
941 cat_delays[i]);
944 return input;
947 void
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);
963 free(input);