Felix Paul Kühne pushed to branch master at VideoLAN / VLC


Commits:
f573990e by Pierre Lamot at 2026-01-20T15:24:08+01:00
player: fix initial seeking in AB loop policy

When setting AB loop, if the player is already in the interval, we shouldn't
seek to the A point

- - - - -
608b85a6 by Pierre Lamot at 2026-01-20T15:24:08+01:00
test: player: abloop: display test purpose in the logs

- - - - -
b5928fa3 by Pierre Lamot at 2026-01-20T15:24:08+01:00
test: player: abloop: add tests to check initial after setting ABLoop

- - - - -
0ab833bf by Pierre Lamot at 2026-01-20T15:24:08+01:00
player: fix player seeking to AB loop start while paused

- - - - -


3 changed files:

- src/player/input.c
- src/player/player.c
- test/src/player/abloop.c


Changes:

=====================================
src/player/input.c
=====================================
@@ -296,6 +296,7 @@ vlc_player_input_HandleState(struct vlc_player_input *input,
             break;
         case VLC_PLAYER_STATE_PLAYING:
             input->pause_date = VLC_TICK_INVALID;
+            vlc_player_SignalAtoBLoop(player);
             vlc_player_UpdateTimerEvent(player, NULL,
                                         VLC_PLAYER_TIMER_EVENT_PLAYING,
                                         input->pause_date);
@@ -311,6 +312,7 @@ vlc_player_input_HandleState(struct vlc_player_input *input,
             assert(state_date != VLC_TICK_INVALID);
             input->pause_date = state_date;
 
+            vlc_player_SignalAtoBLoop(player);
             vlc_player_UpdateTimerEvent(player, NULL,
                                         VLC_PLAYER_TIMER_EVENT_PAUSED,
                                         input->pause_date);


=====================================
src/player/player.c
=====================================
@@ -195,7 +195,7 @@ 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)
+    if (!input || input->pause_date != VLC_TICK_INVALID || 
!input->abloop_state[0].set || !input->abloop_state[1].set)
         return VLC_TICK_MIN;
 
     vlc_tick_t now = vlc_tick_now();
@@ -1609,7 +1609,9 @@ vlc_player_SetAtoBLoopTime(vlc_player_t *player, 
vlc_tick_t a_time, vlc_tick_t b
     input->abloop_state[1].pos = 0;
     input->abloop_state[1].set = true;
 
-    vlc_player_SetTime(player, a_time);
+    vlc_tick_t current = vlc_player_input_GetTime(input, false, 
vlc_tick_now());
+    if (current == VLC_TICK_INVALID || current < a_time || current > b_time)
+        vlc_player_SetTime(player, a_time);
 
     vlc_player_SendEvent(player, on_atobloop_changed, VLC_PLAYER_ABLOOP_A, 
a_time, 0);
     vlc_player_SendEvent(player, on_atobloop_changed, VLC_PLAYER_ABLOOP_B, 
b_time, 0);
@@ -1637,7 +1639,9 @@ vlc_player_SetAtoBLoopPosition(vlc_player_t *player, 
double a_pos, double b_pos)
     input->abloop_state[1].pos = b_pos;
     input->abloop_state[1].set = true;
 
-    vlc_player_SetPosition(player, a_pos);
+    double current = vlc_player_input_GetPos(input, false, vlc_tick_now());
+    if (current < a_pos || current > b_pos)
+        vlc_player_SetPosition(player, a_pos);
 
     vlc_player_SendEvent(player, on_atobloop_changed, VLC_PLAYER_ABLOOP_A, 
VLC_TICK_INVALID, a_pos);
     vlc_player_SendEvent(player, on_atobloop_changed, VLC_PLAYER_ABLOOP_B, 
VLC_TICK_INVALID, b_pos);


=====================================
test/src/player/abloop.c
=====================================
@@ -10,6 +10,7 @@
 
 struct abloop_scenario
 {
+    const char* title;
     bool can_seek;
     bool after_1st_buferring;
     bool nolength_report;
@@ -131,7 +132,7 @@ test_abloop(struct ctx *ctx)
     const struct abloop_scenario scenarios[] =
     {
         {
-            /* Check that b_time past length is handled */
+            .title = "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),
@@ -139,7 +140,7 @@ test_abloop(struct ctx *ctx)
             .seek_count = 2,
         },
         {
-            /* Check we have the same result if called after buffering */
+            .title  = "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),
@@ -147,28 +148,28 @@ test_abloop(struct ctx *ctx)
             .seek_count = 2,
         },
         {
-            /* Check small A->B loop values */
+            .title = "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 */
+            .title = "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 */
+            .title = "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) */
+            .title = "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),
@@ -176,7 +177,7 @@ test_abloop(struct ctx *ctx)
             .seek_count = 2,
         },
         {
-            /* Check that A->B loop is not triggered */
+            .title= "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),
@@ -187,17 +188,171 @@ test_abloop(struct ctx *ctx)
 
     for (size_t i = 0; i < ARRAY_SIZE(scenarios); ++i)
     {
-        test_log("abloop[%zu]\n", i);
+        test_log("abloop[%zu]: %s\n", i, scenarios[i].title);
         test_abloop_scenario(ctx, &scenarios[i]);
     }
 }
 
+struct abloop_initial_position_scenario
+{
+    const char* title;
+    bool can_seek;
+    bool nolength_report;
+    vlc_tick_t initial_time;
+    vlc_tick_t expected_initial_time;
+    vlc_tick_t length;
+    vlc_tick_t a_time;
+    vlc_tick_t b_time;
+    double initial_pos;
+    double expected_initial_pos;
+    double a_pos;
+    double b_pos;
+
+};
+
+static void
+test_abloop_initial_position_scenario(struct ctx *ctx, const struct 
abloop_initial_position_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", &params);
+
+    player_start(ctx);
+
+    while (get_buffering_count(ctx) < 1)
+        vlc_player_CondWait(player, &ctx->wait);
+
+    if (scenario->initial_time != VLC_TICK_INVALID)
+    {
+        vlc_player_SetTime(player, scenario->initial_time);
+
+        vec_on_position_changed *vec = &ctx->report.on_position_changed;
+        while (vec->size == 0)
+            vlc_player_CondWait(player, &ctx->wait);
+
+        vlc_tick_t current_time = VEC_LAST(vec).time;
+
+        assert(current_time >= scenario->initial_time);
+        assert(current_time - scenario->initial_time < VLC_TICK_FROM_MS(1000));
+
+        assert(scenario->b_time != VLC_TICK_INVALID);
+        int ret = vlc_player_SetAtoBLoopTime(player, scenario->a_time,
+                                             scenario->b_time);
+        assert(ret == VLC_SUCCESS);
+
+
+        //wait for the next position report
+        while (vec->size == 1)
+            vlc_player_CondWait(player, &ctx->wait);
+
+
+        current_time = VEC_LAST(vec).time;
+
+        assert(current_time >= scenario->expected_initial_time);
+        assert(current_time - scenario->expected_initial_time < 
VLC_TICK_FROM_MS(1000));
+    }
+    else
+    {
+        vlc_player_SetPosition(player, scenario->initial_pos);
+
+        vec_on_position_changed *vec = &ctx->report.on_position_changed;
+        while (vec->size == 0)
+            vlc_player_CondWait(player, &ctx->wait);
+
+        double current_pos = VEC_LAST(vec).pos;
+
+        assert(current_pos >= scenario->initial_pos);
+        assert((current_pos - scenario->initial_pos) < 0.1);
+
+        int ret = vlc_player_SetAtoBLoopPosition(player, scenario->a_pos,
+                                                 scenario->b_pos);
+        assert(ret == VLC_SUCCESS);
+
+
+        //wait for the next position report
+        while (vec->size == 1)
+            vlc_player_CondWait(player, &ctx->wait);
+
+
+        current_pos = VEC_LAST(vec).pos;
+
+        assert(current_pos >= scenario->expected_initial_pos);
+        assert((current_pos - scenario->expected_initial_pos) < 0.1);
+    }
+
+    test_end(ctx);
+}
+
+static void
+test_abloop_initial_position(struct ctx *ctx)
+{
+    const struct abloop_initial_position_scenario scenarios[] =
+    {
+        {
+            .title = "Current time before the interval should seek to 
beginning",
+            .can_seek = true,
+            .length = VLC_TICK_FROM_MS(30000),
+            .initial_time = VLC_TICK_FROM_MS(5000), .expected_initial_time = 
VLC_TICK_FROM_MS(10000),
+            .a_time = VLC_TICK_FROM_MS(10000), .b_time = 
VLC_TICK_FROM_MS(20000),
+        },
+        {
+            .title = "Current time in the interval should not seek",
+            .can_seek = true,
+            .length = VLC_TICK_FROM_MS(30000),
+            .initial_time = VLC_TICK_FROM_MS(15000), .expected_initial_time = 
VLC_TICK_FROM_MS(15000),
+            .a_time = VLC_TICK_FROM_MS(10000), .b_time = 
VLC_TICK_FROM_MS(20000),
+        },
+        {
+            .title = "Current time after the interval should seek to 
beginning",
+            .can_seek = true,
+            .length = VLC_TICK_FROM_MS(30000),
+            .initial_time = VLC_TICK_FROM_MS(25000), .expected_initial_time = 
VLC_TICK_FROM_MS(10000),
+            .a_time = VLC_TICK_FROM_MS(10000), .b_time = 
VLC_TICK_FROM_MS(20000),
+        },
+        {
+            .title = "Current pos before the interval should seek to 
beginning",
+            .can_seek = true,
+            .length = VLC_TICK_FROM_MS(30000),
+            .initial_pos = 0.1, .expected_initial_pos = 0.3,
+            .a_pos = 0.3, .b_pos = 0.6,
+        },
+        {
+            .title = "Current pos in the interval should not seek",
+            .can_seek = true,
+            .length = VLC_TICK_FROM_MS(30000),
+            .initial_pos = 0.4, .expected_initial_pos = 0.4,
+            .a_pos = 0.3, .b_pos = 0.6,
+        },
+        {
+            .title = "Current pos after the interval should seek to beginning",
+            .can_seek = true,
+            .length = VLC_TICK_FROM_MS(30000),
+            .initial_pos = 0.8, .expected_initial_pos = 0.3,
+            .a_pos = 0.3, .b_pos = 0.6,
+        },
+
+    };
+
+    for (size_t i = 0; i < ARRAY_SIZE(scenarios); ++i)
+    {
+        test_log("abloop_initial_position[%zu]: %s\n", i, scenarios[i].title);
+        test_abloop_initial_position_scenario(ctx, &scenarios[i]);
+    }
+}
+
 int
 main(void)
 {
     struct ctx ctx;
     ctx_init(&ctx, 0);
     test_abloop(&ctx);
+    test_abloop_initial_position(&ctx);
     ctx_destroy(&ctx);
     return 0;
 }



View it on GitLab: 
https://code.videolan.org/videolan/vlc/-/compare/abd5e50fefc35d29f143155b2916d0c4965f1a67...0ab833bfbb2012fabfa9f2e308261b8abaed3647

-- 
View it on GitLab: 
https://code.videolan.org/videolan/vlc/-/compare/abd5e50fefc35d29f143155b2916d0c4965f1a67...0ab833bfbb2012fabfa9f2e308261b8abaed3647
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance
_______________________________________________
vlc-commits mailing list
[email protected]
https://mailman.videolan.org/listinfo/vlc-commits

Reply via email to