input: Propagate duration updates to the input_item_t
[vlc.git] / src / player / input.c
blobbe1544d4d9ac15179d9531ccf121573a8c37407b
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.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);
451 break;
452 case AUDIO_ES:
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);
457 break;
458 case SPU_ES:
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);
463 default:
464 break;
466 break;
467 case VLC_INPUT_ES_DELETED:
469 size_t idx;
470 trackpriv = vlc_player_track_vector_FindById(vec, ev->id, &idx);
471 if (trackpriv)
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);
478 break;
480 case VLC_INPUT_ES_UPDATED:
481 trackpriv = vlc_player_track_vector_FindById(vec, ev->id, NULL);
482 if (!trackpriv)
483 break;
484 if (vlc_player_track_priv_Update(trackpriv, ev->title, ev->fmt) != 0)
485 break;
486 vlc_player_SendEvent(player, on_track_list_changed,
487 VLC_PLAYER_LIST_UPDATED, &trackpriv->t);
488 break;
489 case VLC_INPUT_ES_SELECTED:
490 trackpriv = vlc_player_track_vector_FindById(vec, ev->id, NULL);
491 if (trackpriv)
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 */
502 case VIDEO_ES:
503 if (input->ml.default_video_track == -2)
504 input->ml.default_video_track = ev->fmt->i_id;
505 break;
506 case AUDIO_ES:
507 if (input->ml.default_audio_track == -2)
508 input->ml.default_audio_track = ev->fmt->i_id;
509 break;
510 case SPU_ES:
511 if (input->ml.default_subtitle_track == -2)
512 input->ml.default_subtitle_track = ev->fmt->i_id;
513 break;
514 default:
515 break;
517 break;
518 case VLC_INPUT_ES_UNSELECTED:
519 trackpriv = vlc_player_track_vector_FindById(vec, ev->id, NULL);
520 if (trackpriv)
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);
527 break;
528 default:
529 vlc_assert_unreachable();
533 static void
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;
538 switch (ev->action)
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;
546 if (input->titles)
547 vlc_player_title_list_Release(input->titles);
548 input->title_selected = input->chapter_selected = 0;
549 input->titles =
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);
553 if (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);
563 break;
565 case VLC_INPUT_TITLE_SELECTED:
566 if (!input->titles)
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;
583 break;
584 default:
585 vlc_assert_unreachable();
589 static void
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)
600 return;
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);
611 static void
612 vlc_player_input_HandleVoutEvent(struct vlc_player_input *input,
613 const struct vlc_input_event_vout *ev)
615 assert(ev->vout);
616 assert(ev->id);
618 vlc_player_t *player = input->player;
620 struct vlc_player_track_priv *trackpriv =
621 vlc_player_input_FindTrackById(input, ev->id, NULL);
622 if (!trackpriv)
623 return;
625 const bool is_video_es = trackpriv->t.fmt.i_cat == VIDEO_ES;
627 switch (ev->action)
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,
633 ev->order, ev->id);
635 if (is_video_es)
637 /* Register vout callbacks after the vout list event */
638 vlc_player_vout_AddCallbacks(player, ev->vout);
640 break;
641 case VLC_INPUT_EVENT_VOUT_DELETED:
642 if (is_video_es)
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);
652 break;
653 default:
654 vlc_assert_unreachable();
658 static void
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 = {
673 .position = 0,
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,
681 VLC_TICK_INVALID,
682 event->output_clock.frame_rate,
683 event->output_clock.frame_rate_base);
685 else
687 vlc_player_UpdateTimerState(player, event->output_clock.id,
688 VLC_PLAYER_TIMER_STATE_DISCONTINUITY,
689 VLC_TICK_INVALID);
691 return;
694 vlc_mutex_lock(&player->lock);
696 switch (event->type)
698 case INPUT_EVENT_STATE:
699 vlc_player_input_HandleStateEvent(input, event->state.value,
700 event->state.date);
701 break;
702 case INPUT_EVENT_RATE:
703 input->rate = event->rate;
704 vlc_player_SendEvent(player, on_rate_changed, input->rate);
705 break;
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);
712 break;
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();
726 changed = true;
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);
737 changed = true;
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;
744 changed = true;
747 if (changed)
749 const struct vlc_player_timer_point point = {
750 .position = input->position,
751 .rate = input->rate,
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);
759 break;
761 case INPUT_EVENT_PROGRAM:
762 vlc_player_input_HandleProgramEvent(input, &event->program);
763 break;
764 case INPUT_EVENT_ES:
765 vlc_player_input_HandleEsEvent(input, &event->es);
766 break;
767 case INPUT_EVENT_TITLE:
768 vlc_player_input_HandleTitleEvent(input, &event->title);
769 break;
770 case INPUT_EVENT_CHAPTER:
771 vlc_player_input_HandleChapterEvent(input, &event->chapter);
772 break;
773 case INPUT_EVENT_RECORD:
774 input->recording = event->record;
775 vlc_player_SendEvent(player, on_recording_changed, input->recording);
776 break;
777 case INPUT_EVENT_STATISTICS:
778 input->stats = *event->stats;
779 vlc_player_SendEvent(player, on_statistics_changed, &input->stats);
780 break;
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);
786 break;
787 case INPUT_EVENT_CACHE:
788 input->cache = event->cache;
789 vlc_player_SendEvent(player, on_buffering_changed, event->cache);
790 break;
791 case INPUT_EVENT_VOUT:
792 vlc_player_input_HandleVoutEvent(input, &event->vout);
793 break;
794 case INPUT_EVENT_ITEM_META:
795 vlc_player_SendEvent(player, on_media_meta_changed,
796 input_GetItem(input->thread));
797 break;
798 case INPUT_EVENT_ITEM_EPG:
799 vlc_player_SendEvent(player, on_media_epg_changed,
800 input_GetItem(input->thread));
801 break;
802 case INPUT_EVENT_SUBITEMS:
803 vlc_player_SendEvent(player, on_media_subitems_changed,
804 input_GetItem(input->thread), event->subitems);
805 break;
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,
809 VLC_TICK_INVALID);
810 vlc_player_destructor_AddJoinableInput(player, input);
811 break;
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);
816 break;
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);
821 break;
822 default:
823 break;
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));
833 if (!input)
834 return NULL;
836 input->player = player;
837 input->started = false;
839 input->state = VLC_PLAYER_STATE_STOPPED;
840 input->error = VLC_PLAYER_ERROR_NONE;
841 input->rate = 1.f;
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;
850 input->cache = 0.f;
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);
882 if (!input->thread)
884 free(input);
885 return NULL;
888 vlc_player_input_RestoreMlStates(input, item);
890 /* Initial sub/audio delay */
891 const vlc_tick_t cat_delays[DATA_ES] = {
892 [AUDIO_ES] =
893 VLC_TICK_FROM_MS(var_InheritInteger(player, "audio-desync")),
894 [SPU_ES] =
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,
908 &param);
909 if (ret == VLC_SUCCESS)
910 vlc_player_SendEvent(player, on_category_delay_changed, i,
911 cat_delays[i]);
914 return input;
917 void
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);
933 free(input);