[vlc-commits] [Git][videolan/vlc][master] lib/media_player: add the vlc_player Timer API

Hugo Beauzée-Luyssen (@chouquette) gitlab at videolan.org
Wed Aug 10 11:29:51 UTC 2022



Hugo Beauzée-Luyssen pushed to branch master at VideoLAN / VLC


Commits:
52cda837 by Thomas Guillem at 2022-08-10T10:52:27+00:00
lib/media_player: add the vlc_player Timer API

Any LibVLC users could request a timer from the player. This Media Player
timer has its own event API since:

 - It is only used to receive time update points:

 - The timer is not locked by the player lock. Indeed the player lock can be
   too "slow" (it can be recursive, it is used by the playlist, and is it held
   when sending all events). So it's not a good idea to hold this lock for
   every frame/sample updates.

 - The minimum delay between each updates can be configured: it avoids to flood
   the UI when playing a media file with very high fps or very low audio sample
   size.

The libvlc_media_player_time_point struct is used by timer update
callbacks. This public struct hold all the informations to interpolate a
time at a given date. It can be done with the
libvlc_media_player_time_point_interpolate() helper. That way, it is
now possible to get the last player time without holding any locks.

There is only one type of timer (for now):

libvlc_media_player_watch_time(): update are sent only when a frame or a
sample is outputted. Users of this timer should take into account that
the delay between each updates is not regular and can be up to 1seconds
(depending of the input). In that case, they should use their own timer
(from their mainloop) and use
libvlc_media_player_time_point_interpolate() to get the last time.

- - - - -


4 changed files:

- include/vlc/libvlc_media_player.h
- lib/libvlc.sym
- lib/media_player.c
- lib/media_player_internal.h


Changes:

=====================================
include/vlc/libvlc_media_player.h
=====================================
@@ -2652,6 +2652,158 @@ LIBVLC_API int libvlc_media_player_set_role(libvlc_media_player_t *p_mi,
 
 /** @} audio */
 
+/** \defgroup libvlc_media_player_watch_time LibVLC media player time watch API
+ * @{
+ */
+
+/**
+ * Media Player timer point
+ *
+ * \note ts and system_date values should not be used directly by the user.
+ * libvlc_media_player_time_point_interpolate() will read these values and
+ * return an interpolated ts.
+ *
+ * @see libvlc_media_player_watch_time_on_update
+ */
+typedef struct libvlc_media_player_time_point_t
+{
+    /** Position in the range [0.0f;1.0] */
+    double position;
+    /** Rate of the player */
+    double rate;
+    /** Valid time >= 0 or -1 */
+    libvlc_time_t ts;
+    /** Valid length >= 1 or 0 */
+    libvlc_time_t length;
+    /**
+     * System date of this record (always valid).
+     * Based on libvlc_clock(). This date can be in the future or in the past.
+     * The special value of INT64_MAX mean that the clock was paused when this
+     * point was updated. In that case,
+     * libvlc_media_player_time_point_interpolate() will return the current
+     * ts/pos of this point (there is nothing to interpolate).
+     * */
+    libvlc_time_t system_date;
+} libvlc_media_player_time_point_t;
+
+/**
+ * Callback prototype that notify when the player state or time changed.
+ *
+ * Get notified when the time is updated by the input or output source. The
+ * input source is the 'demux' or the 'access_demux'. The output source are
+ * audio and video outputs: an update is received each time a video frame is
+ * displayed or an audio sample is written. The delay between each updates may
+ * depend on the input and source type (it can be every 5ms, 30ms, 1s or
+ * 10s...). Users of this timer may need to update the position at a higher
+ * frequency from their own mainloop via
+ * libvlc_media_player_time_point_interpolate().
+ *
+ * \warning It is forbidden to call any Media Player functions from here..
+ *
+ * \param value always valid, the time corresponding to the state
+ * \param data opaque pointer set by libvlc_media_player_watch_time()
+ */
+typedef void (*libvlc_media_player_watch_time_on_update)(
+        const libvlc_media_player_time_point_t *value, void *data);
+
+/**
+ * Callback prototype that notify when the player is paused or a discontinuity
+ * occurred.
+ *
+ * Likely caused by seek from the user or because the playback is stopped. The
+ * player user should stop its "interpolate" timer.
+ *
+ * \warning It is forbidden to call any Media Player functions from here..
+ *
+ * \param system_date system date of this event, only valid (> 0) when paused. It
+ * can be used to interpolate the last updated point to this date in order
+ * to get the last paused ts/position.
+ * \param data opaque pointer set by libvlc_media_player_watch_time()
+ */
+typedef void (*libvlc_media_player_watch_time_on_discontinuity)(
+        libvlc_time_t system_date, void *data);
+
+/**
+ * Watch for times updates
+ *
+ * \warning Only one watcher can be registered at a time. Calling this function
+ * a second time (if libvlc_media_player_unwatch_time() was not called
+ * in-between) will fail.
+ *
+ * \param p_mi the media player
+ * \param min_period corresponds to the minimum period between each updates,
+ * use it to avoid flood from too many source updates, set it to 0 to receive
+ * all updates.
+ * \param on_update callback to listen to update events (must not be NULL)
+ * \param on_discontinuity callback to listen to discontinuity events (can be
+ * be NULL)
+ * \param cbs_data opaque pointer used by the callbacks
+ * \return 0 on success, -1 on error (allocation error, or if already watching)
+ * \version LibVLC 4.0.0 or later
+ */
+LIBVLC_API int
+libvlc_media_player_watch_time(libvlc_media_player_t *p_mi,
+                               libvlc_time_t min_period,
+                               libvlc_media_player_watch_time_on_update on_update,
+                               libvlc_media_player_watch_time_on_discontinuity on_discontinuity,
+                               void *cbs_data);
+
+/**
+ * Unwatch time updates
+ *
+ * \param p_mi the media player
+ * \version LibVLC 4.0.0 or later
+ */
+LIBVLC_API void
+libvlc_media_player_unwatch_time(libvlc_media_player_t *p_mi);
+
+/**
+ * Interpolate a timer value to now
+
+ * \param point time update obtained via the
+ * libvlc_media_player_watch_time_on_update() callback
+ * \param system_now current system date, returned by libvlc_clock()
+ * \param out_ts pointer where to set the interpolated ts, subtract this time
+ * with VLC_TICK_0 to get the original value.
+ * \param out_pos pointer where to set the interpolated position
+ * \return 0 in case of success, -1 if the interpolated ts is negative (could
+ * happen during the buffering step)
+ * \version LibVLC 4.0.0 or later
+ */
+LIBVLC_API int
+libvlc_media_player_time_point_interpolate(const libvlc_media_player_time_point_t *point,
+                                           libvlc_time_t system_now,
+                                           libvlc_time_t *out_ts, double *out_pos);
+
+/**
+ * Get the date of the next interval
+ *
+ * Can be used to setup an UI timer in order to update some widgets at specific
+ * interval. A next_interval of VLC_TICK_FROM_SEC(1) can be used to update a
+ * time widget when the media reaches a new second.
+ *
+ * \note The media time doesn't necessarily correspond to the system time, that
+ * is why this function is needed and uses the rate of the current point..
+ *
+ * \param point time update obtained via the
+ * libvlc_media_player_watch_time_on_update()
+ * \param system_now same system date used by
+ * libvlc_media_player_time_point_interpolate()
+ * \param interpolated_ts ts returned by
+ * libvlc_media_player_time_point_interpolate()
+ * \param next_interval next interval
+ * \return the absolute system date of the next interval, use libvlc_delay() to
+ * get a relative delay.
+ * \version LibVLC 4.0.0 or later
+ */
+LIBVLC_API libvlc_time_t
+libvlc_media_player_time_point_get_next_date(const libvlc_media_player_time_point_t *point,
+                                             libvlc_time_t system_now,
+                                             libvlc_time_t interpolated_ts,
+                                             libvlc_time_t next_interval);
+
+/** @} libvlc_media_player_watch_time */
+
 /** @} media_player */
 
 # ifdef __cplusplus


=====================================
lib/libvlc.sym
=====================================
@@ -193,6 +193,10 @@ libvlc_media_player_select_program_id
 libvlc_media_player_get_selected_program
 libvlc_media_player_get_program_from_id
 libvlc_media_player_get_programlist
+libvlc_media_player_watch_time
+libvlc_media_player_unwatch_time
+libvlc_media_player_time_point_interpolate
+libvlc_media_player_time_point_get_next_date
 libvlc_media_release
 libvlc_media_retain
 libvlc_media_save_meta


=====================================
lib/media_player.c
=====================================
@@ -717,6 +717,8 @@ libvlc_media_player_new( libvlc_instance_t *instance )
     var_Create (mp, "equalizer-vlcfreqs", VLC_VAR_BOOL);
     var_Create (mp, "equalizer-bands", VLC_VAR_STRING);
 
+    mp->timer.id = NULL;
+
     mp->p_md = NULL;
     mp->p_libvlc_instance = instance;
     /* use a reentrant lock to allow calling libvlc functions from callbacks */
@@ -2207,6 +2209,116 @@ int libvlc_media_player_get_role(libvlc_media_player_t *mp)
     return ret;
 }
 
+#define PLAYER_TIME_CORE_TO_LIB(point) { \
+    .position = point->position, \
+    .rate = point->rate, \
+    .ts = US_FROM_VLC_TICK(point->ts), \
+    .length = US_FROM_VLC_TICK(point->length), \
+    .system_date = US_FROM_VLC_TICK(point->system_date), \
+}
+
+#define PLAYER_TIME_LIB_TO_CORE(point) { \
+    .position = point->position, \
+    .rate = point->rate, \
+    .ts = VLC_TICK_FROM_US(point->ts), \
+    .length = VLC_TICK_FROM_US(point->length), \
+    .system_date = VLC_TICK_FROM_US(point->system_date), \
+}
+
+static void player_timer_on_update(const struct vlc_player_timer_point *point,
+                                   void *data)
+{
+    libvlc_media_player_t *p_mi = data;
+
+    const libvlc_media_player_time_point_t libpoint = PLAYER_TIME_CORE_TO_LIB(point);
+
+    p_mi->timer.on_update(&libpoint, p_mi->timer.cbs_data);
+}
+
+static void player_timer_on_discontinuity(vlc_tick_t system_date, void *data)
+{
+    libvlc_media_player_t *p_mi = data;
+
+    if (p_mi->timer.on_discontinuity == NULL)
+        return;
+
+    p_mi->timer.on_discontinuity(system_date, p_mi->timer.cbs_data);
+}
+
+int
+libvlc_media_player_watch_time(libvlc_media_player_t *p_mi,
+                               libvlc_time_t min_period,
+                               libvlc_media_player_watch_time_on_update on_update,
+                               libvlc_media_player_watch_time_on_discontinuity on_discontinuity,
+                               void *cbs_data)
+{
+    assert(on_update != NULL);
+
+    static const struct vlc_player_timer_cbs player_timer_cbs = {
+        .on_update = player_timer_on_update,
+        .on_discontinuity = player_timer_on_discontinuity,
+    };
+
+    vlc_player_t *player = p_mi->player;
+    vlc_player_Lock(player);
+
+    if (p_mi->timer.id != NULL)
+    {
+        libvlc_printerr("libvlc_media_player_watch_time error:"
+                        "already watching for events");
+        vlc_player_Unlock(player);
+        return -1;
+    }
+
+    p_mi->timer.on_update = on_update;
+    p_mi->timer.on_discontinuity = on_discontinuity;
+    p_mi->timer.cbs_data = cbs_data;
+
+    p_mi->timer.id = vlc_player_AddTimer(player, min_period, &player_timer_cbs, p_mi);
+    vlc_player_Unlock(player);
+
+    if (unlikely(p_mi->timer.id == NULL))
+        return -1;
+
+    return 0;
+}
+
+void
+libvlc_media_player_unwatch_time(libvlc_media_player_t *p_mi)
+{
+    vlc_player_t *player = p_mi->player;
+
+    vlc_player_Lock(player);
+
+    assert(p_mi->timer.id != NULL);
+    vlc_player_RemoveTimer(player, p_mi->timer.id);
+    p_mi->timer.id = NULL;
+
+    vlc_player_Unlock(player);
+}
+
+int
+libvlc_media_player_time_point_interpolate(const libvlc_media_player_time_point_t *libpoint,
+                                           libvlc_time_t system_now,
+                                           libvlc_time_t *out_ts, double *out_pos)
+{
+    const struct vlc_player_timer_point point = PLAYER_TIME_LIB_TO_CORE(libpoint);
+
+    return vlc_player_timer_point_Interpolate(&point, system_now, out_ts, out_pos);
+}
+
+libvlc_time_t
+libvlc_media_player_time_point_get_next_date(const libvlc_media_player_time_point_t *libpoint,
+                                             libvlc_time_t system_now,
+                                             libvlc_time_t interpolated_ts,
+                                             libvlc_time_t next_interval)
+{
+    const struct vlc_player_timer_point point = PLAYER_TIME_LIB_TO_CORE(libpoint);
+
+    return vlc_player_timer_point_GetNextIntervalDate(&point, system_now,
+                                                      interpolated_ts, next_interval);
+}
+
 #include <vlc_vout_display.h>
 
 /* make sure surface structures from libvlc can be passed as such to vlc


=====================================
lib/media_player_internal.h
=====================================
@@ -49,6 +49,13 @@ struct libvlc_media_player_t
     struct libvlc_instance_t * p_libvlc_instance; /* Parent instance */
     libvlc_media_t * p_md; /* current media descriptor */
     libvlc_event_manager_t event_manager;
+
+    struct {
+        vlc_player_timer_id *id;
+        libvlc_media_player_watch_time_on_update on_update;
+        libvlc_media_player_watch_time_on_discontinuity on_discontinuity;
+        void *cbs_data;
+    } timer;
 };
 
 libvlc_track_description_t * libvlc_get_track_description(



View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/52cda8377ebcccd70a5af409b68ab5b39b79d1ce

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/commit/52cda8377ebcccd70a5af409b68ab5b39b79d1ce
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