[vlc-commits] [Git][videolan/vlc][master] 15 commits: player: rename destructor to mainloop
Thomas Guillem (@tguillem)
gitlab at videolan.org
Tue Dec 2 15:32:41 UTC 2025
Thomas Guillem pushed to branch master at VideoLAN / VLC
Commits:
84c6f631 by Thomas Guillem at 2025-12-02T14:57:10+00:00
player: rename destructor to mainloop
This thread could be used for something else than stopping inputs.
- - - - -
e60ef1ad by Thomas Guillem at 2025-12-02T14:57:10+00:00
player: refactor, merge vlc_player_input_HandleAtoBLoop()
No functional changes.
- - - - -
bece5b79 by Thomas Guillem at 2025-12-02T14:57:10+00:00
player: expose vlc_player_input_HandleAtoBLoop()
- - - - -
02adcc43 by Thomas Guillem at 2025-12-02T14:57:10+00:00
player: reorder calls in vlc_player_input_HandleAtoBLoop()
Avoid initializing variables if not needed.
- - - - -
993ae382 by Thomas Guillem at 2025-12-02T14:57:10+00:00
player: return the seeking state from GetTimerPoint()
- - - - -
1c1cfcf5 by Thomas Guillem at 2025-12-02T14:57:10+00:00
player: rework vlc_player_input_HandleAtoBLoop()
Can be forced to force the seek to the a position (not used for now)
Returns true if it caused a seek.
- - - - -
8b71cb69 by Thomas Guillem at 2025-12-02T14:57:10+00:00
player: check can_seek later on AtoBLoop requests
So that vlc_player_SetAtoBLoop() can be called when not started.
- - - - -
624afb64 by Thomas Guillem at 2025-12-02T14:57:10+00:00
player: finer AtoBLoop handling
Use the player timer to wait for the accurate B deadline.
- - - - -
f893fa24 by Thomas Guillem at 2025-12-02T14:57:10+00:00
player: also handle AtoBLoop on EOF
The deadline (from the previous commit) can still be missed if the B
position is very close to the end (or past the end).
This also fixes AtoBLoop when the length is not known, and near EOF
(when only using positions).
- - - - -
5534270f by Thomas Guillem at 2025-12-02T14:57:10+00:00
mock: add report_length
Can be used to test a stream without a known (or exposed) length.
- - - - -
f6234960 by Thomas Guillem at 2025-12-02T14:57:10+00:00
test: player: handle timer on_seek events
- - - - -
d7d8e95e by Thomas Guillem at 2025-12-02T14:57:10+00:00
test: player: common: handle report_length
- - - - -
07b397ea by Thomas Guillem at 2025-12-02T14:57:10+00:00
test: player: add more timers helpers
Helper to create and listen to timer events.
- - - - -
34795f64 by Thomas Guillem at 2025-12-02T14:57:10+00:00
test: player: timers: use helpers
- - - - -
170bd5d7 by Thomas Guillem at 2025-12-02T14:57:10+00:00
test: player: check AtoBLoop
- - - - -
11 changed files:
- modules/demux/mock.c
- src/player/input.c
- src/player/player.c
- src/player/player.h
- src/player/timer.c
- test/Makefile.am
- test/src/meson.build
- + test/src/player/abloop.c
- test/src/player/common.h
- test/src/player/timers.c
- test/src/player/timers.h
Changes:
=====================================
modules/demux/mock.c
=====================================
@@ -219,6 +219,7 @@ var_Read_float(const char *psz)
#define OPTIONS_GLOBAL(X) \
X(node_count, ssize_t, add_integer, Ssize, 0, NO_FREE) \
X(length, vlc_tick_t, add_integer, Integer, VLC_TICK_FROM_MS(5000), NO_FREE) \
+ X(report_length, bool, add_bool, Bool, true, NO_FREE) \
X(audio_track_count, ssize_t, add_integer, Ssize, 0, NO_FREE) \
X(video_track_count, ssize_t, add_integer, Ssize, 0, NO_FREE) \
X(sub_track_count, ssize_t, add_integer, Ssize, 0, NO_FREE) \
@@ -557,6 +558,8 @@ Control(demux_t *demux, int query, va_list args)
VLC_TICK_0 + sys->pts_offset + va_arg(args, double) * sys->length;
return VLC_SUCCESS;
case DEMUX_GET_LENGTH:
+ if (!sys->report_length)
+ return VLC_EGENERIC;
*va_arg(args, vlc_tick_t *) = sys->length;
return VLC_SUCCESS;
case DEMUX_GET_NORMAL_TIME:
=====================================
src/player/input.c
=====================================
@@ -35,28 +35,6 @@ vlc_player_input_FindTrackById(struct vlc_player_input *input, vlc_es_id_t *id,
return vec ? vlc_player_track_vector_FindById(vec, id, idx) : NULL;
}
-static void
-vlc_player_input_HandleAtoBLoop(struct vlc_player_input *input, vlc_tick_t time,
- double pos)
-{
- vlc_player_t *player = input->player;
-
- if (player->input != input)
- return;
-
- assert(input->abloop_state[0].set && input->abloop_state[1].set);
-
- if (time != VLC_TICK_INVALID
- && input->abloop_state[0].time != VLC_TICK_INVALID
- && input->abloop_state[1].time != VLC_TICK_INVALID)
- {
- if (time >= input->abloop_state[1].time)
- vlc_player_SetTime(player, input->abloop_state[0].time);
- }
- else if (pos >= input->abloop_state[1].pos)
- vlc_player_SetPosition(player, input->abloop_state[0].pos);
-}
-
vlc_tick_t
vlc_player_input_GetTime(struct vlc_player_input *input, bool seeking,
vlc_tick_t system_now)
@@ -65,7 +43,7 @@ vlc_player_input_GetTime(struct vlc_player_input *input, bool seeking,
vlc_tick_t ts;
if (input == player->input
- && vlc_player_GetTimerPoint(player, seeking, system_now, &ts, NULL) == 0)
+ && vlc_player_GetTimerPoint(player, &seeking, system_now, &ts, NULL) == 0)
return ts;
return input->time;
}
@@ -78,21 +56,42 @@ vlc_player_input_GetPos(struct vlc_player_input *input, bool seeking,
double pos;
if (input == player->input
- && vlc_player_GetTimerPoint(player, seeking, system_now, NULL, &pos) == 0)
+ && vlc_player_GetTimerPoint(player, &seeking, system_now, NULL, &pos) == 0)
return pos;
return input->position;
}
-static void
-vlc_player_input_UpdateTime(struct vlc_player_input *input)
+bool
+vlc_player_input_HandleAtoBLoop(struct vlc_player_input *input, bool forced)
{
- if (input->abloop_state[0].set && input->abloop_state[1].set)
+ if (!input->abloop_state[0].set || !input->abloop_state[1].set
+ || (input->capabilities & VLC_PLAYER_CAP_SEEK) == 0)
+ return false;
+
+ vlc_player_t *player = input->player;
+
+ if (player->input != input)
+ return false;
+
+ vlc_tick_t now = vlc_tick_now();
+ if (input->abloop_state[0].time != VLC_TICK_INVALID
+ && input->abloop_state[1].time != VLC_TICK_INVALID)
{
- vlc_tick_t now = vlc_tick_now();
- vlc_player_input_HandleAtoBLoop(input,
- vlc_player_input_GetTime(input, false, now),
- vlc_player_input_GetPos(input, false, now));
+ vlc_tick_t time = vlc_player_input_GetTime(input, false, now);
+ if (forced
+ || (time != VLC_TICK_INVALID && time >= input->abloop_state[1].time))
+ vlc_player_SetTime(player, input->abloop_state[0].time);
+ return true;
}
+
+ double pos = vlc_player_input_GetPos(input, false, now);
+ if (forced || pos >= input->abloop_state[1].pos)
+ {
+ vlc_player_SetPosition(player, input->abloop_state[0].pos);
+ return true;
+ }
+
+ return false;
}
int
@@ -927,6 +926,9 @@ input_thread_Events(input_thread_t *input_thread,
event->state.date);
break;
case INPUT_EVENT_EOF:
+ handled = vlc_player_input_HandleAtoBLoop(input, true);
+ if (handled)
+ break;
if (player->play_and_pause)
{
vlc_player_Pause(player);
@@ -944,6 +946,7 @@ input_thread_Events(input_thread_t *input_thread,
break;
case INPUT_EVENT_RATE:
input->rate = event->rate;
+ vlc_player_SignalAtoBLoop(player);
vlc_player_SendEvent(player, on_rate_changed, input->rate);
break;
case INPUT_EVENT_CAPABILITIES:
@@ -971,7 +974,7 @@ input_thread_Events(input_thread_t *input_thread,
vlc_player_SendEvent(player, on_position_changed,
input->time, input->position);
- vlc_player_input_UpdateTime(input);
+ vlc_player_input_HandleAtoBLoop(input, false);
}
if (input->length != duration)
{
@@ -1005,6 +1008,7 @@ input_thread_Events(input_thread_t *input_thread,
};
vlc_player_UpdateTimer(player, NULL, false, &point,
input->normal_time, 0, 0, priv->i_start);
+ vlc_player_SignalAtoBLoop(player);
}
break;
}
=====================================
src/player/player.c
=====================================
@@ -131,20 +131,20 @@ vlc_player_destructor_AddInput(vlc_player_t *player,
input->started = false;
/* Add this input to the stop list: it will be stopped by the
* destructor thread */
- assert(!vlc_list_HasInput(&player->destructor.stopping_inputs, input));
- assert(!vlc_list_HasInput(&player->destructor.joinable_inputs, input));
- vlc_list_append(&input->node, &player->destructor.inputs);
+ assert(!vlc_list_HasInput(&player->mainloop.stopping_inputs, input));
+ assert(!vlc_list_HasInput(&player->mainloop.joinable_inputs, input));
+ vlc_list_append(&input->node, &player->mainloop.stop_inputs);
}
else
{
/* Add this input to the joinable list: it will be deleted by the
* destructor thread */
- assert(!vlc_list_HasInput(&player->destructor.inputs, input));
- assert(!vlc_list_HasInput(&player->destructor.joinable_inputs, input));
- vlc_list_append(&input->node, &player->destructor.joinable_inputs);
+ assert(!vlc_list_HasInput(&player->mainloop.stop_inputs, input));
+ assert(!vlc_list_HasInput(&player->mainloop.joinable_inputs, input));
+ vlc_list_append(&input->node, &player->mainloop.joinable_inputs);
}
- vlc_cond_signal(&input->player->destructor.wait);
+ vlc_cond_signal(&input->player->mainloop.wait);
}
void
@@ -152,12 +152,12 @@ vlc_player_destructor_AddStoppingInput(vlc_player_t *player,
struct vlc_player_input *input)
{
/* Add this input to the stopping list */
- if (vlc_list_HasInput(&player->destructor.inputs, input))
+ if (vlc_list_HasInput(&player->mainloop.stop_inputs, input))
vlc_list_remove(&input->node);
- if (!vlc_list_HasInput(&player->destructor.stopping_inputs, input))
+ if (!vlc_list_HasInput(&player->mainloop.stopping_inputs, input))
{
- vlc_list_append(&input->node, &player->destructor.stopping_inputs);
- vlc_cond_signal(&input->player->destructor.wait);
+ vlc_list_append(&input->node, &player->mainloop.stopping_inputs);
+ vlc_cond_signal(&input->player->mainloop.wait);
}
}
@@ -165,7 +165,7 @@ void
vlc_player_destructor_AddJoinableInput(vlc_player_t *player,
struct vlc_player_input *input)
{
- if (vlc_list_HasInput(&player->destructor.stopping_inputs, input))
+ if (vlc_list_HasInput(&player->mainloop.stopping_inputs, input))
vlc_list_remove(&input->node);
assert(!input->started);
@@ -174,13 +174,50 @@ vlc_player_destructor_AddJoinableInput(vlc_player_t *player,
static bool vlc_player_destructor_IsEmpty(vlc_player_t *player)
{
- return vlc_list_is_empty(&player->destructor.inputs)
- && vlc_list_is_empty(&player->destructor.stopping_inputs)
- && vlc_list_is_empty(&player->destructor.joinable_inputs);
+ return vlc_list_is_empty(&player->mainloop.stop_inputs)
+ && vlc_list_is_empty(&player->mainloop.stopping_inputs)
+ && vlc_list_is_empty(&player->mainloop.joinable_inputs);
+}
+
+void
+vlc_player_SignalAtoBLoop(vlc_player_t *player)
+{
+ struct vlc_player_input *input = vlc_player_get_input_locked(player);
+
+ if (!input || !input->abloop_state[0].set || !input->abloop_state[1].set)
+ return;
+
+ vlc_cond_signal(&player->mainloop.wait);
+}
+
+static vlc_tick_t
+vlc_player_GetAtoBLoopDeadline(vlc_player_t *player)
+{
+ struct vlc_player_input *input = vlc_player_get_input_locked(player);
+
+ if (!input || !input->abloop_state[0].set || !input->abloop_state[1].set)
+ return VLC_TICK_MIN;
+
+ vlc_tick_t now = vlc_tick_now();
+ vlc_tick_t ts;
+ bool seeking = false;
+ if (vlc_player_GetTimerPoint(player, &seeking, now, &ts, NULL) != 0)
+ return VLC_TICK_MIN;
+ if (seeking)
+ return VLC_TICK_MIN;
+
+ vlc_tick_t b_time = input->abloop_state[1].time;
+ if (b_time == VLC_TICK_INVALID)
+ {
+ if (input->length == VLC_TICK_INVALID)
+ return VLC_TICK_MIN;
+ b_time = input->abloop_state[1].pos * input->length;
+ }
+ return now + (b_time - ts) * input->rate;
}
static void *
-vlc_player_destructor_Thread(void *data)
+vlc_player_mainloop_Thread(void *data)
{
vlc_player_t *player = data;
@@ -195,12 +232,23 @@ vlc_player_destructor_Thread(void *data)
{
/* Wait for an input to stop or close. No while loop here since we want
* to leave this code path when the player is deleting. */
- if (vlc_list_is_empty(&player->destructor.inputs)
- && vlc_list_is_empty(&player->destructor.joinable_inputs))
- vlc_cond_wait(&player->destructor.wait, &player->lock);
+ vlc_tick_t deadline = vlc_player_GetAtoBLoopDeadline(player);
+ bool timeout = false;
+ if (vlc_list_is_empty(&player->mainloop.stop_inputs)
+ && vlc_list_is_empty(&player->mainloop.joinable_inputs))
+ {
+ if (deadline == VLC_TICK_MIN)
+ vlc_cond_wait(&player->mainloop.wait, &player->lock);
+ else
+ timeout = vlc_cond_timedwait(&player->mainloop.wait,
+ &player->lock, deadline) != 0;
+ }
+
+ if (timeout && player->input != NULL)
+ vlc_player_input_HandleAtoBLoop(player->input, true);
struct vlc_player_input *input;
- vlc_list_foreach(input, &player->destructor.inputs, node)
+ vlc_list_foreach(input, &player->mainloop.stop_inputs, node)
{
input_Stop(input->thread);
input->stopping_reason = VLC_PLAYER_MEDIA_STOPPING_USER;
@@ -211,8 +259,8 @@ vlc_player_destructor_Thread(void *data)
bool keep_sout = true;
const bool inputs_changed =
- !vlc_list_is_empty(&player->destructor.joinable_inputs);
- vlc_list_foreach(input, &player->destructor.joinable_inputs, node)
+ !vlc_list_is_empty(&player->mainloop.joinable_inputs);
+ vlc_list_foreach(input, &player->mainloop.joinable_inputs, node)
{
vlc_player_UpdateMLStates(player, input);
@@ -1471,8 +1519,8 @@ vlc_player_SetAtoBLoop(vlc_player_t *player, enum vlc_player_abloop abloop)
{
struct vlc_player_input *input = vlc_player_get_input_locked(player);
- if (!input || !vlc_player_CanSeek(player))
- return VLC_EGENERIC;
+ if (!input )
+ return VLC_EINVAL;
vlc_tick_t time = vlc_player_GetTime(player);
float pos = vlc_player_GetPosition(player);
@@ -1487,6 +1535,12 @@ vlc_player_SetAtoBLoop(vlc_player_t *player, enum vlc_player_abloop abloop)
input->abloop_state[0].set = true;
break;
case VLC_PLAYER_ABLOOP_B:
+ if (!vlc_player_CanSeek(player))
+ {
+ input->abloop_state[0].set = false;
+ return VLC_EGENERIC;
+ }
+
if (!input->abloop_state[0].set)
return VLC_EGENERIC;
input->abloop_state[1].time = time;
@@ -1537,8 +1591,8 @@ vlc_player_SetAtoBLoopTime(vlc_player_t *player, vlc_tick_t a_time, vlc_tick_t b
struct vlc_player_input *input = vlc_player_get_input_locked(player);
- if (!input || !vlc_player_CanSeek(player))
- return VLC_EGENERIC;
+ if (!input)
+ return VLC_EINVAL;
input->abloop_state[0].time = a_time;
input->abloop_state[0].pos = 0;
@@ -1565,8 +1619,8 @@ vlc_player_SetAtoBLoopPosition(vlc_player_t *player, double a_pos, double b_pos)
struct vlc_player_input *input = vlc_player_get_input_locked(player);
- if (!input || !vlc_player_CanSeek(player))
- return VLC_EGENERIC;
+ if (!input)
+ return VLC_EINVAL;
input->abloop_state[0].time = VLC_TICK_INVALID;
input->abloop_state[0].pos = a_pos;
@@ -1940,7 +1994,7 @@ vlc_player_InitLocks(vlc_player_t *player, enum vlc_player_lock_type lock_type)
vlc_mutex_init(&player->vout_listeners_lock);
vlc_mutex_init(&player->aout_listeners_lock);
vlc_cond_init(&player->start_delay_cond);
- vlc_cond_init(&player->destructor.wait);
+ vlc_cond_init(&player->mainloop.wait);
}
void
@@ -1955,7 +2009,7 @@ vlc_player_Delete(vlc_player_t *player)
}
player->deleting = true;
- vlc_cond_signal(&player->destructor.wait);
+ vlc_cond_signal(&player->mainloop.wait);
assert(vlc_list_is_empty(&player->listeners));
assert(vlc_list_is_empty(&player->metadata_listeners));
@@ -1964,7 +2018,7 @@ vlc_player_Delete(vlc_player_t *player)
vlc_mutex_unlock(&player->lock);
- vlc_join(player->destructor.thread, NULL);
+ vlc_join(player->mainloop.thread, NULL);
if (player->media)
input_item_Release(player->media);
@@ -2008,9 +2062,9 @@ vlc_player_New(vlc_object_t *parent, enum vlc_player_lock_type lock_type)
vlc_list_init(&player->metadata_listeners);
vlc_list_init(&player->vout_listeners);
vlc_list_init(&player->aout_listeners);
- vlc_list_init(&player->destructor.inputs);
- vlc_list_init(&player->destructor.stopping_inputs);
- vlc_list_init(&player->destructor.joinable_inputs);
+ vlc_list_init(&player->mainloop.stop_inputs);
+ vlc_list_init(&player->mainloop.stopping_inputs);
+ vlc_list_init(&player->mainloop.joinable_inputs);
player->start_paused = false;
player->pause_on_cork = false;
player->corked = false;
@@ -2086,7 +2140,7 @@ vlc_player_New(vlc_object_t *parent, enum vlc_player_lock_type lock_type)
vlc_player_InitLocks(player, lock_type);
vlc_player_InitTimer(player);
- if (vlc_clone(&player->destructor.thread, vlc_player_destructor_Thread,
+ if (vlc_clone(&player->mainloop.thread, vlc_player_mainloop_Thread,
player) != 0)
{
vlc_player_DestroyTimer(player);
=====================================
src/player/player.h
=====================================
@@ -290,10 +290,10 @@ struct vlc_player_t
vlc_thread_t thread;
vlc_cond_t wait;
vlc_cond_t notify;
- struct vlc_list inputs;
+ struct vlc_list stop_inputs;
struct vlc_list stopping_inputs;
struct vlc_list joinable_inputs;
- } destructor;
+ } mainloop;
struct vlc_player_timer timer;
};
@@ -361,6 +361,9 @@ void
vlc_player_destructor_AddJoinableInput(vlc_player_t *player,
struct vlc_player_input *input);
+void
+vlc_player_SignalAtoBLoop(vlc_player_t *player);
+
/*
* player_track.c
*/
@@ -471,6 +474,9 @@ void
vlc_player_input_HandleState(struct vlc_player_input *, enum vlc_player_state,
vlc_tick_t state_date);
+bool
+vlc_player_input_HandleAtoBLoop(struct vlc_player_input *input, bool forced);
+
/*
* player_timer.c
*/
@@ -505,7 +511,7 @@ void
vlc_player_RemoveTimerSource(vlc_player_t *player, vlc_es_id_t *es_source);
int
-vlc_player_GetTimerPoint(vlc_player_t *player, bool seeking,
+vlc_player_GetTimerPoint(vlc_player_t *player, bool *seeking,
vlc_tick_t system_now,
vlc_tick_t *out_ts, double *out_pos);
=====================================
src/player/timer.c
=====================================
@@ -527,14 +527,15 @@ vlc_player_RemoveTimerSource(vlc_player_t *player, vlc_es_id_t *es_source)
}
int
-vlc_player_GetTimerPoint(vlc_player_t *player, bool seeking,
+vlc_player_GetTimerPoint(vlc_player_t *player, bool *seeking,
vlc_tick_t system_now,
vlc_tick_t *out_ts, double *out_pos)
{
int ret = VLC_EGENERIC;
vlc_mutex_lock(&player->timer.lock);
- if (seeking
- && (player->timer.seek_ts != VLC_TICK_INVALID || player->timer.seek_position >= 0.0f))
+ bool timer_seeking = player->timer.seek_ts != VLC_TICK_INVALID
+ || player->timer.seek_position >= 0.0f;
+ if (*seeking && timer_seeking)
{
if (out_ts != NULL)
{
@@ -569,6 +570,8 @@ vlc_player_GetTimerPoint(vlc_player_t *player, bool seeking,
ret = VLC_SUCCESS;
}
+ if (ret == VLC_SUCCESS)
+ *seeking = timer_seeking;
end:
vlc_mutex_unlock(&player->timer.lock);
return ret;
=====================================
test/Makefile.am
=====================================
@@ -8,6 +8,7 @@ AUTOMAKE_OPTIONS = subdir-objects
# Unit/regression test
###############################################################################
player_programs = \
+ test_src_player_abloop \
test_src_player_attachments \
test_src_player_capabilities \
test_src_player_discontinuities \
@@ -216,6 +217,9 @@ test_src_preparser_thumbnail_SOURCES = src/preparser/thumbnail.c
test_src_preparser_thumbnail_LDADD = $(LIBVLCCORE) $(LIBVLC)
test_src_preparser_thumbnail_to_files_SOURCES = src/preparser/thumbnail_to_files.c
test_src_preparser_thumbnail_to_files_LDADD = $(LIBVLCCORE) $(LIBVLC)
+test_src_player_abloop_SOURCES = src/player/common.h src/player/modules.c \
+ src/player/abloop.c src/player/timers.h
+test_src_player_abloop_LDADD = $(LIBVLCCORE) $(LIBVLC) $(LIBM)
test_src_player_attachments_SOURCES = src/player/common.h src/player/modules.c \
src/player/attachments.c
test_src_player_attachments_LDADD = $(LIBVLCCORE) $(LIBVLC) $(LIBM)
=====================================
test/src/meson.build
=====================================
@@ -105,6 +105,18 @@ vlc_tests += {
'module_depends' : ['demux_mock', 'rawvideo']
}
+vlc_tests += {
+ 'name' : 'test_src_player_abloop',
+ 'sources' : files(
+ 'player/common.h',
+ 'player/modules.c',
+ 'player/timers.h',
+ 'player/abloop.c'),
+ 'suite' : ['src', 'test_src'],
+ 'link_with' : [libvlc, libvlccore],
+ 'module_depends' : vlc_plugins_targets.keys()
+}
+
vlc_tests += {
'name' : 'test_src_player_attachments',
'sources' : files(
=====================================
test/src/player/abloop.c
=====================================
@@ -0,0 +1,199 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*****************************************************************************
+ * abloop.c: abloop player test
+ *****************************************************************************
+ * Copyright (C) 2018-2025 VLC authors and VideoLAN
+ *****************************************************************************/
+
+#include "common.h"
+#include "timers.h"
+
+struct abloop_scenario
+{
+ bool can_seek;
+ bool after_1st_buferring;
+ bool nolength_report;
+ bool wait_stopped;
+ bool check_prev_ts;
+ vlc_tick_t length;
+ vlc_tick_t a_time;
+ vlc_tick_t b_time;
+ double a_pos;
+ double b_pos;
+ size_t seek_count;
+};
+
+static void
+test_abloop_scenario(struct ctx *ctx, const struct abloop_scenario *scenario)
+{
+ vlc_player_t *player = ctx->player;
+
+ struct media_params params = DEFAULT_MEDIA_PARAMS(scenario->length);
+ params.can_seek = scenario->can_seek;
+ params.track_count[AUDIO_ES] = 1;
+ params.track_count[VIDEO_ES] = 0;
+ params.track_count[SPU_ES] = 0;
+ params.report_length = !scenario->nolength_report;
+ player_set_next_mock_media(ctx, "media1", ¶ms);
+
+ struct timer_state timer;
+ player_add_timer(player, &timer, false, VLC_TICK_INVALID);
+
+ player_start(ctx);
+
+ size_t expected_buffering_count = scenario->seek_count;
+ if (scenario->after_1st_buferring)
+ {
+ /* Wait for 1st buffering */
+ while (get_buffering_count(ctx) < 1)
+ vlc_player_CondWait(ctx->player, &ctx->wait);
+ expected_buffering_count++;
+ }
+
+ if (scenario->a_time != VLC_TICK_INVALID)
+ {
+ assert(scenario->b_time != VLC_TICK_INVALID);
+ int ret = vlc_player_SetAtoBLoopTime(ctx->player, scenario->a_time,
+ scenario->b_time);
+ assert(ret == VLC_SUCCESS);
+ }
+ else
+ {
+ int ret = vlc_player_SetAtoBLoopPosition(ctx->player, scenario->a_pos,
+ scenario->b_pos);
+ assert(ret == VLC_SUCCESS);
+ }
+
+ if (!scenario->wait_stopped)
+ {
+ /* Wait all seek request */
+ while (get_buffering_count(ctx) < expected_buffering_count)
+ vlc_player_CondWait(ctx->player, &ctx->wait);
+
+ vlc_player_Stop(player);
+ }
+ wait_state(ctx, VLC_PLAYER_STATE_STOPPED);
+
+ vec_report_timer *vec = &timer.vec;
+ size_t seek_count = 0;
+ for (size_t i = 0; i < vec->size; ++i)
+ {
+ struct report_timer *report = &vec->data[i];
+ if (report->type != REPORT_TIMER_SEEK)
+ continue;
+ if (report->seek.finished)
+ continue;
+ struct vlc_player_timer_point *point = &report->seek.point;
+
+ if (scenario->a_time != VLC_TICK_INVALID)
+ assert(point->ts == scenario->a_time);
+ else
+ assert(point->position == scenario->a_pos);
+
+ if (seek_count > 0 && scenario->check_prev_ts)
+ {
+ assert(scenario->a_time != VLC_TICK_INVALID);
+ assert(i > 0);
+ bool checked = false;
+ for (size_t j = i - 1; j > 0; --j)
+ {
+ struct report_timer *time_report = &vec->data[j];
+ if (time_report->type != REPORT_TIMER_POINT)
+ continue;
+ struct vlc_player_timer_point *time_point = &time_report->point;
+
+ vlc_tick_t end_ts = scenario->b_time;
+ if (end_ts > params.length)
+ end_ts = params.length;
+ assert(time_point->ts >= scenario->a_time);
+ assert(time_point->ts <= end_ts);
+ assert(time_point->ts + params.audio_sample_length >= end_ts);
+ checked = true;
+ break;
+ }
+ assert(checked);
+ }
+ seek_count++;
+ }
+ assert(seek_count == scenario->seek_count);
+
+ test_end(ctx);
+ player_remove_timer(player, &timer);
+}
+
+static void
+test_abloop(struct ctx *ctx)
+{
+ const struct abloop_scenario scenarios[] =
+ {
+ {
+ /* Check that b_time past length is handled */
+ .can_seek = true, .after_1st_buferring = false,
+ .check_prev_ts = true,
+ .length = VLC_TICK_FROM_MS(20000),
+ .a_time = VLC_TICK_FROM_MS(19800), .b_time = VLC_TICK_FROM_MS(30000),
+ .seek_count = 2,
+ },
+ {
+ /* Check we have the same result if called after buffering */
+ .can_seek = true, .after_1st_buferring = true,
+ .check_prev_ts = true,
+ .length = VLC_TICK_FROM_MS(20000),
+ .a_time = VLC_TICK_FROM_MS(19800), .b_time = VLC_TICK_FROM_MS(30000),
+ .seek_count = 2,
+ },
+ {
+ /* Check small A->B loop values */
+ .can_seek = true, .after_1st_buferring = true,
+ .length = VLC_TICK_FROM_MS(3000),
+ .a_time = VLC_TICK_FROM_MS(1), .b_time = VLC_TICK_FROM_MS(2),
+ .seek_count = 4,
+ },
+ {
+ /* Check with positions */
+ .can_seek = true, .after_1st_buferring = true,
+ .length = VLC_TICK_FROM_MS(3000),
+ .a_pos = 0.9, .b_pos = 1.0f,
+ .seek_count = 1,
+ },
+ {
+ /* Check we have the same result if called after buffering */
+ .can_seek = true, .after_1st_buferring = false,
+ .length = VLC_TICK_FROM_MS(3000),
+ .a_pos = 0.9, .b_pos = 1.0f,
+ .seek_count = 2,
+ },
+ {
+ /* Check that seek is triggered by EOF (no reported length) */
+ .can_seek = true, .after_1st_buferring = false,
+ .nolength_report = true,
+ .length = VLC_TICK_FROM_MS(1000),
+ .a_pos = 0.9, .b_pos = 1.0f,
+ .seek_count = 2,
+ },
+ {
+ /* Check that A->B loop is not triggered */
+ .can_seek = false, .after_1st_buferring = false,
+ .nolength_report = true, .wait_stopped = true,
+ .length = VLC_TICK_FROM_MS(100),
+ .a_pos = 0.1, .b_pos = 1.0f,
+ .seek_count = 1, /* Caused by the A seek request that fails */
+ },
+ };
+
+ for (size_t i = 0; i < ARRAY_SIZE(scenarios); ++i)
+ {
+ test_log("abloop[%zu]\n", i);
+ test_abloop_scenario(ctx, &scenarios[i]);
+ }
+}
+
+int
+main(void)
+{
+ struct ctx ctx;
+ ctx_init(&ctx, 0);
+ test_abloop(&ctx);
+ ctx_destroy(&ctx);
+ return 0;
+}
=====================================
test/src/player/common.h
=====================================
@@ -189,6 +189,7 @@ struct media_params
bool can_pause;
bool error;
bool null_names;
+ bool report_length;
vlc_tick_t pts_delay;
const char *config;
@@ -214,6 +215,7 @@ struct media_params
.can_pause = true, \
.error = false, \
.null_names = false, \
+ .report_length = true, \
.pts_delay = DEFAULT_PTS_DELAY, \
.config = NULL, \
.discontinuities = NULL, \
@@ -781,7 +783,8 @@ create_mock_media(const char *name, const struct media_params *params)
"sub_packetized=%d;length=%"PRId64";audio_sample_length=%"PRId64";"
"video_frame_rate=%u;video_frame_rate_base=%u;"
"title_count=%zu;chapter_count=%zu;"
- "can_seek=%d;can_pause=%d;error=%d;null_names=%d;pts_delay=%"PRId64";"
+ "can_seek=%d;can_pause=%d;error=%d;null_names=%d;"
+ "report_length=%d;ts_delay=%"PRId64";"
"config=%s;discontinuities=%s;attachment_count=%zu",
params->track_count[VIDEO_ES], params->track_count[AUDIO_ES],
params->track_count[SPU_ES], params->program_count,
@@ -790,7 +793,7 @@ create_mock_media(const char *name, const struct media_params *params)
params->video_frame_rate, params->video_frame_rate_base,
params->title_count, params->chapter_count,
params->can_seek, params->can_pause, params->error, params->null_names,
- params->pts_delay,
+ params->report_length, params->pts_delay,
params->config ? params->config : "",
params->discontinuities ? params->discontinuities : "",
params->attachment_count);
=====================================
test/src/player/timers.c
=====================================
@@ -251,16 +251,6 @@ test_timers(struct ctx *ctx)
vlc_player_t *player = ctx->player;
- static const struct vlc_player_timer_cbs cbs =
- {
- .on_update = timers_on_update,
- .on_paused = timers_on_paused,
- };
- static const struct vlc_player_timer_smpte_cbs smpte_cbs =
- {
- .on_update = timers_smpte_on_update,
- };
-
/* Configure timers */
struct timer_state timers[TIMER_COUNT];
@@ -269,18 +259,14 @@ test_timers(struct ctx *ctx)
/* Filter some points in order to not be flooded */
timers[REGULAR_DELAY_TIMER_IDX].delay = SOURCE_DELAY_TIMER_VALUE;
+ timers[SMPTE_TIMER_IDX].delay = VLC_TICK_INVALID;
/* Create all timers */
for (size_t i = 0; i < ARRAY_SIZE(timers); ++i)
{
vlc_vector_init(&timers[i].vec);
- if (i == SMPTE_TIMER_IDX)
- timers[i].id = vlc_player_AddSmpteTimer(player, &smpte_cbs,
- &timers[i]);
- else
- timers[i].id = vlc_player_AddTimer(player, timers[i].delay, &cbs,
- &timers[i]);
- assert(timers[i].id);
+ bool smpte = i == SMPTE_TIMER_IDX;
+ player_add_timer(player, &timers[i], smpte, timers[i].delay);
}
/* Test all timers using valid tracks */
@@ -337,8 +323,7 @@ test_timers(struct ctx *ctx)
for (size_t i = 0; i < ARRAY_SIZE(timers); ++i)
{
struct timer_state *timer = &timers[i];
- vlc_vector_clear(&timer->vec);
- vlc_player_RemoveTimer(player, timer->id);
+ player_remove_timer(player, timer);
}
}
=====================================
test/src/player/timers.h
=====================================
@@ -15,12 +15,17 @@ struct report_timer
REPORT_TIMER_POINT,
REPORT_TIMER_TC,
REPORT_TIMER_PAUSED,
+ REPORT_TIMER_SEEK,
} type;
union
{
struct vlc_player_timer_point point;
struct vlc_player_timer_smpte_timecode tc;
vlc_tick_t paused_date;
+ struct {
+ struct vlc_player_timer_point point;
+ bool finished;
+ } seek;
};
};
typedef struct VLC_VECTOR(struct report_timer) vec_report_timer;
@@ -58,6 +63,21 @@ timers_on_paused(vlc_tick_t system_date, void *data)
assert(success);
}
+static inline void
+timers_on_seek(const struct vlc_player_timer_point *point, void *data)
+{
+ struct timer_state *timer = data;
+ struct report_timer report =
+ {
+ .type = REPORT_TIMER_SEEK,
+ };
+ report.seek.finished = point == NULL;
+ if (!report.seek.finished)
+ report.seek.point = *point;
+ bool success = vlc_vector_push(&timer->vec, report);
+ assert(success);
+}
+
static inline void
timers_smpte_on_update(const struct vlc_player_timer_smpte_timecode *tc,
void *data)
@@ -70,4 +90,36 @@ timers_smpte_on_update(const struct vlc_player_timer_smpte_timecode *tc,
};
bool success = vlc_vector_push(&timer->vec, report);
assert(success);
+}
+
+static inline void
+player_add_timer(vlc_player_t *player, struct timer_state *timer, bool smpte,
+ vlc_tick_t delay)
+{
+ static const struct vlc_player_timer_cbs cbs =
+ {
+ .on_update = timers_on_update,
+ .on_paused = timers_on_paused,
+ .on_seek = timers_on_seek,
+ };
+
+ static const struct vlc_player_timer_smpte_cbs smpte_cbs =
+ {
+ .on_update = timers_smpte_on_update,
+ };
+
+ vlc_vector_init(&timer->vec);
+ timer->delay = delay;
+ if (smpte)
+ timer->id = vlc_player_AddSmpteTimer(player, &smpte_cbs, timer);
+ else
+ timer->id = vlc_player_AddTimer(player, timer->delay, &cbs, timer);
+ assert(timer->id);
+}
+
+static inline void
+player_remove_timer(vlc_player_t *player, struct timer_state *timer)
+{
+ vlc_vector_clear(&timer->vec);
+ vlc_player_RemoveTimer(player, timer->id);
}
\ No newline at end of file
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/e48a61a6fb74322db8e841a8321bff298f00a0bf...170bd5d7850ffde19511a8b948c84a6b6a5a45cb
--
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/e48a61a6fb74322db8e841a8321bff298f00a0bf...170bd5d7850ffde19511a8b948c84a6b6a5a45cb
You're receiving this email because of your account on code.videolan.org.
VideoLAN code repository instance
More information about the vlc-commits
mailing list