// 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
{
const char* title;
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++;
}
if (scenario->wait_stopped)
assert(seek_count == scenario->seek_count);
else
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[] =
{
{
.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),
.a_time = VLC_TICK_FROM_MS(19800), .b_time = VLC_TICK_FROM_MS(30000),
.seek_count = 2,
},
{
.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),
.a_time = VLC_TICK_FROM_MS(19800), .b_time = VLC_TICK_FROM_MS(30000),
.seek_count = 2,
},
{
.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,
},
{
.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,
},
{
.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,
},
{
.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),
.a_pos = 0.9, .b_pos = 1.0f,
.seek_count = 2,
},
{
.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),
.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]: %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", ¶ms);
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;
}
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet am 2026-11-04)
¤
*© Formatika GbR, Deutschland
|
|