[vlc-devel] [PATCH V3 16/19] test: player: test the timer API
Thomas Guillem
thomas at gllm.fr
Fri Sep 6 17:20:46 CEST 2019
---
test/src/player/player.c | 251 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 249 insertions(+), 2 deletions(-)
diff --git a/test/src/player/player.c b/test/src/player/player.c
index ceeb10bc44..0e7b7f3294 100644
--- a/test/src/player/player.c
+++ b/test/src/player/player.c
@@ -120,6 +120,24 @@ struct report_media_subitems
X(input_item_t *, on_media_epg_changed) \
X(struct report_media_subitems, on_media_subitems_changed) \
+struct report_timer
+{
+ enum vlc_player_timer_state state;
+ union
+ {
+ struct vlc_player_timer_point point;
+ struct vlc_player_timer_smpte_timecode tc;
+ };
+};
+typedef struct VLC_VECTOR(struct report_timer) vec_report_timer;
+
+struct timer_state
+{
+ vlc_player_timer_id *id;
+ vlc_tick_t delay;
+ vec_report_timer vec;
+};
+
#define X(type, name) typedef struct VLC_VECTOR(type) vec_##name;
REPORT_LIST
#undef X
@@ -148,6 +166,9 @@ struct media_params
bool video_packetized, audio_packetized, sub_packetized;
+ unsigned video_frame_rate;
+ unsigned video_frame_rate_base;
+
size_t title_count;
size_t chapter_count;
@@ -167,6 +188,8 @@ struct media_params
}, \
.program_count = 0, \
.video_packetized = true, .audio_packetized = true, .sub_packetized = true,\
+ .video_frame_rate = 25, \
+ .video_frame_rate_base = 1, \
.title_count = 0, \
.chapter_count = 0, \
.can_seek = true, \
@@ -630,14 +653,16 @@ create_mock_media(const char *name, const struct media_params *params)
"mock://video_track_count=%zu;audio_track_count=%zu;sub_track_count=%zu;"
"program_count=%zu;video_packetized=%d;audio_packetized=%d;"
"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",
params->track_count[VIDEO_ES], params->track_count[AUDIO_ES],
params->track_count[SPU_ES], params->program_count,
params->video_packetized, params->audio_packetized,
params->sub_packetized, params->length, params->audio_sample_length,
- params->title_count, params->chapter_count, params->can_seek,
- params->can_pause, params->error, params->null_names);
+ 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);
assert(ret != -1);
input_item_t *item = input_item_New(url, name);
@@ -1839,6 +1864,227 @@ REPORT_LIST
assert(ctx->listener);
}
+static void
+timers_on_update(enum vlc_player_timer_state state,
+ const struct vlc_player_timer_point *point, void *data)
+{
+ struct timer_state *timer = data;
+ struct report_timer report =
+ {
+ .state = state,
+ .point = *point,
+ };
+ bool success = vlc_vector_push(&timer->vec, report);
+ assert(success);
+}
+
+static void
+timers_smpte_on_update(const struct vlc_player_timer_smpte_timecode *tc,
+ void *data)
+{
+ struct timer_state *timer = data;
+ struct report_timer report =
+ {
+ .state = VLC_PLAYER_TIMER_STATE_PLAYING,
+ .tc = *tc,
+ };
+ bool success = vlc_vector_push(&timer->vec, report);
+ assert(success);
+}
+
+static void
+test_timers_assert_smpte(struct timer_state *timer,
+ vlc_tick_t duration, unsigned fps, bool drop_frame,
+ unsigned frame_resolution)
+{
+ /* TODO: Test that 4 frames are dropped every minutes except every 10
+ * minutes, should be easier to implement with a real seek notification
+ * support. */
+ assert(duration < VLC_TICK_FROM_SEC(60));
+
+ /* Assertions for the smpte timer */
+ vec_report_timer *vec = &timer->vec;
+
+ /* Check that we didn't miss any update points */
+ assert(vec->data[0].tc.frames == 0);
+ for (size_t i = 0; i < vec->size; ++i)
+ {
+ struct report_timer *prev_report = i > 0 ? &vec->data[i - 1] : NULL;
+ struct report_timer *report = &vec->data[i];
+
+ assert(report->tc.seconds == (i / fps));
+ if (prev_report)
+ {
+ assert(prev_report->tc.seconds == 0);
+ if (i % fps == 0)
+ {
+ assert(prev_report->tc.frames == fps - 1);
+ assert(report->tc.frames == 0);
+ }
+ else
+ assert(report->tc.frames == prev_report->tc.frames + 1);
+ }
+
+ assert(report->tc.drop_frame == drop_frame);
+ assert(report->tc.frame_resolution == frame_resolution);
+ }
+ assert(VEC_LAST(vec).tc.frames + 1 == fps * duration / VLC_TICK_FROM_SEC(1));
+}
+
+static void
+test_timers(struct ctx *ctx)
+{
+ test_log("timers\n");
+
+#define MEDIA_DURATION VLC_TICK_FROM_MS(100)
+#define MEDIA_FPS 120
+#define SAMPLE_LENGTH VLC_TICK_FROM_MS(1)
+#define MAX_UPDATE_COUNT (MEDIA_DURATION / SAMPLE_LENGTH)
+
+#define REGULAR_TIMER_IDX 0
+#define REGULAR_DELAY_TIMER_IDX 1
+#define SMPTE_TIMER_IDX 2
+#define TIMER_COUNT 3
+
+#define SOURCE_DELAY_TIMER_VALUE (VLC_TICK_FROM_MS(2))
+
+ vlc_player_t *player = ctx->player;
+ struct media_params params = DEFAULT_MEDIA_PARAMS(MEDIA_DURATION);
+
+ params.track_count[VIDEO_ES] = 1;
+ params.track_count[AUDIO_ES] = 1;
+ params.track_count[SPU_ES] = 1;
+ params.audio_sample_length = SAMPLE_LENGTH;
+ params.video_frame_rate = MEDIA_FPS;
+ params.video_frame_rate_base = 1;
+
+ static const struct vlc_player_timer_cbs cbs =
+ {
+ .on_update = timers_on_update,
+ };
+ static const struct vlc_player_timer_smpte_cbs smpte_cbs =
+ {
+ .on_update = timers_smpte_on_update,
+ };
+
+ /* Configure timers */
+ struct timer_state timers[TIMER_COUNT];
+
+ /* Receive all clock update points */
+ timers[REGULAR_TIMER_IDX].delay = VLC_TICK_INVALID;
+
+ /* Filter some points in order to not be flooded */
+ timers[REGULAR_DELAY_TIMER_IDX].delay = SOURCE_DELAY_TIMER_VALUE;
+
+ /* 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);
+ }
+
+ player_set_current_mock_media(ctx, "media1", ¶ms, false);
+ player_start(ctx);
+
+ wait_state(ctx, VLC_PLAYER_STATE_STARTED);
+ wait_state(ctx, VLC_PLAYER_STATE_STOPPED);
+
+ /* Common for regular timers */
+ for (size_t timer_idx = 0; timer_idx < SMPTE_TIMER_IDX; ++timer_idx)
+ {
+ struct timer_state *timer = &timers[timer_idx];
+ vec_report_timer *vec = &timer->vec;
+
+ for (size_t i = 1; i < vec->size; ++i)
+ {
+ struct report_timer *prev_report = &vec->data[i - 1];
+ struct report_timer *report = &vec->data[i];
+
+ /* ts/position should increase, rate should stay to 1.f */
+ assert(report->point.ts >= prev_report->point.ts);
+ assert(report->point.position >= prev_report->point.position);
+ assert(report->point.rate == 1.f);
+ assert(report->point.length == MEDIA_DURATION);
+
+ /* Only the last event should be a discontinuity. We can assume
+ * that since we are not seeking and playing a fake content */
+ if (i < vec->size - 1)
+ assert(report->state == VLC_PLAYER_TIMER_STATE_PLAYING);
+ else
+ assert(report->state == VLC_PLAYER_TIMER_STATE_DISCONTINUITY);
+ }
+
+ /* The last point should be the media duration */
+ assert(VEC_LAST(vec).point.ts == MEDIA_DURATION);
+ }
+
+ /* Assertions for the regular timer that received all update points */
+ {
+ struct timer_state *timer = &timers[REGULAR_TIMER_IDX];
+ vec_report_timer *vec = &timer->vec;
+
+ /* Check that we didn't miss any update points */
+ assert(vec->data[vec->size - 2].point.ts
+ == MEDIA_DURATION - SAMPLE_LENGTH + VLC_TICK_0);
+ assert(vec->size == MAX_UPDATE_COUNT + 1);
+ }
+
+ /* Assertions for the regular filtered timer */
+ {
+ struct timer_state *timer = &timers[REGULAR_DELAY_TIMER_IDX];
+ vec_report_timer *vec = &timer->vec;
+
+ /* It should not receive all update points */
+ assert(vec->size < MAX_UPDATE_COUNT);
+
+ for (size_t i = 1; i < vec->size; ++i)
+ {
+ struct report_timer *prev_report = &vec->data[i - 1];
+ struct report_timer *report = &vec->data[i];
+ if (i < vec->size - 1)
+ assert(report->point.system_date - prev_report->point.system_date
+ >= timer->delay);
+ }
+ }
+
+ test_timers_assert_smpte(&timers[SMPTE_TIMER_IDX], MEDIA_DURATION,
+ MEDIA_FPS, false, 3);
+ test_end(ctx);
+
+ for (size_t i = 0; i < ARRAY_SIZE(timers); ++i)
+ vlc_vector_clear(&timers[i].vec);
+
+ /* Test only the SMPTE timer with a longer media */
+#undef MEDIA_FPS
+#define MEDIA_FPS 60
+ params.video_frame_rate = 60000;
+ params.video_frame_rate_base = 1001;
+
+ player_set_current_mock_media(ctx, "media1", ¶ms, false);
+
+ player_start(ctx);
+
+ wait_state(ctx, VLC_PLAYER_STATE_STARTED);
+ wait_state(ctx, VLC_PLAYER_STATE_STOPPED);
+
+ test_timers_assert_smpte(&timers[SMPTE_TIMER_IDX],
+ MEDIA_DURATION, MEDIA_FPS, true, 2);
+
+ 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);
+ }
+
+ test_end(ctx);
+}
int
main(void)
@@ -1869,6 +2115,7 @@ main(void)
test_tracks(&ctx, true);
test_tracks(&ctx, false);
test_programs(&ctx);
+ test_timers(&ctx);
test_delete_while_playback(VLC_OBJECT(ctx.vlc->p_libvlc_int), true);
test_delete_while_playback(VLC_OBJECT(ctx.vlc->p_libvlc_int), false);
--
2.20.1
More information about the vlc-devel
mailing list