[vlc-devel] [PATCH 1/2] libvlc: add media_player metadata listener API

Thomas Guillem thomas at gllm.fr
Mon Jan 18 16:32:14 UTC 2021


For now, it is only used for propagating loudness measurements.
---
 include/vlc/libvlc_media_player.h | 133 ++++++++++++++++++++++++++++++
 lib/libvlc.sym                    |   2 +
 lib/media_player.c                | 103 +++++++++++++++++++++++
 3 files changed, 238 insertions(+)

diff --git a/include/vlc/libvlc_media_player.h b/include/vlc/libvlc_media_player.h
index 8dd85d16049..a0398883c88 100644
--- a/include/vlc/libvlc_media_player.h
+++ b/include/vlc/libvlc_media_player.h
@@ -2608,6 +2608,139 @@ LIBVLC_API int libvlc_media_player_set_role(libvlc_media_player_t *p_mi,
 
 /** @} audio */
 
+/** \defgroup libvlc_media_player_metadata_cbs LibVLC media player metadata callbacks
+ * @{
+ */
+
+/**
+ * Media player metadata listener opaque structure.
+ *
+ * This opaque structure is returned by
+ * libvlc_media_player_add_metadata_listener() and can be used to remove the
+ * listener via libvlc_media_player_remove_metadata_listener().
+ */
+typedef struct libvlc_media_player_metadata_listener_id
+    libvlc_media_player_metadata_listener_id;
+
+/**
+ * Audio loudness measurement
+ */
+struct libvlc_audio_loudness
+{
+    /** Momentary loudness (last 400 ms), in LUFS */
+    double loudness_momentary;
+    /** Short term loudness (last 3seconds), in LUFS */
+    double loudness_shortterm;
+    /** Integrated loudness (global), in LUFS */
+    double loudness_integrated;
+    /** Loudness range, in LU */
+    double loudness_range;
+    /** True Peak, in dBTP */
+    double truepeak;
+};
+
+/**
+ * Player metadata option
+ */
+enum libvlc_media_player_metadata_option
+{
+    /**
+     * Ask for momentary loudness measurement
+     *
+     * Very low CPU usage.
+     * @see libvlc_media_player_metadata_cbs.on_momentary_loudness_changed
+     */
+    LIBVLC_MEDIA_PLAYER_METADATA_LOUDNESS_MOMENTARY,
+
+    /**
+     * Ask for all loudness measurements
+     *
+     * High CPU usage.
+     * @see libvlc_media_player_metadata_cbs.on_loudness_changed
+     */
+    LIBVLC_MEDIA_PLAYER_METADATA_LOUDNESS_FULL,
+};
+
+/**
+ * Player metadata callbacks
+ *
+ * Can be registered with libvlc_media_player_add_metadata_listener().
+ *
+ * @warning To avoid deadlocks, users should never call libvlc_media_player_t
+ * functions from these callbacks.
+ */
+union libvlc_media_player_metadata_cbs
+{
+    /**
+     * Called when the momentary loudness measurement have changed
+     *
+     * @see VLC_PLAYER_METADATA_LOUDNESS_MOMEMTARY
+     *
+     * Only sent when audio is playing, approximately every 400ms (but can be
+     * higher, depending on the input sample size).
+     *
+     * @param date Absolute date of the measurement. It is most likely in the
+     * future (0 to 2seconds) depending on the audio output buffer size. Use
+     * \ref libvlc_delay to get the relative delay until this date is reached.
+     * @param momentary_loudness Momentary loudness
+     * @param data opaque pointer set by
+     * libvlc_media_player_add_metadata_listener()
+     */
+    void (*on_momentary_loudness_changed)(libvlc_time_t date,
+                                          double momentary_loudness,
+                                          void *data);
+
+    /**
+     * Called when loudness measurements have changed
+     *
+     * @see VLC_PLAYER_METADATA_LOUDNESS_FULL
+     *
+     * Only sent when audio is playing, approximately every 400ms (but can be
+     * higher, depending on the input sample size).
+     *
+     * @param date Absolute date of the measurement. It is most likely in the
+     * future (0 to 2seconds) depending on the audio output buffer size. Use
+     * \ref libvlc_delay to get the relative delay until this date is reached.
+     * @param loudness loudness measurement
+     * @param data opaque pointer set by
+     * libvlc_media_player_add_metadata_listener()
+     */
+    void (*on_loudness_changed)(libvlc_time_t date,
+                                const struct libvlc_audio_loudness *loudness,
+                                void *data);
+};
+
+/**
+ * Add a metadata listener
+ *
+ * @note Every registered loudness meter need to be removed by the caller with
+ * libvlc_media_player_remove_metadata_listener().
+ *
+ * @param mp media player
+ * @param cbs pointer to a libvlc_media_player_metadata_cbs union, the
+ * structure must be valid during the lifetime of the player
+ * @param cbs_data opaque pointer used by the callbacks
+ * @return a valid listener id, or NULL in case of error (plugin missing)
+ */
+LIBVLC_API libvlc_media_player_metadata_listener_id *
+libvlc_media_player_add_metadata_listener(libvlc_media_player_t *mp,
+                                          enum libvlc_media_player_metadata_option option,
+                                          const union libvlc_media_player_metadata_cbs *cbs,
+                                          void *cbs_data);
+
+/**
+ * Remove a metadata listener
+ *
+ * @param mp media player
+ * @param id listener id returned by libvlc_media_player_add_metadata_listener()
+ */
+LIBVLC_API void
+libvlc_media_player_remove_metadata_listener(libvlc_media_player_t *mp,
+                                             libvlc_media_player_metadata_listener_id *id);
+
+
+/** @} libvlc_media_player_metadata_cbs */
+
 /** @} media_player */
 
 # ifdef __cplusplus
diff --git a/lib/libvlc.sym b/lib/libvlc.sym
index f30d67f3a9e..db476bda970 100644
--- a/lib/libvlc.sym
+++ b/lib/libvlc.sym
@@ -198,6 +198,8 @@ 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_add_metadata_listener
+libvlc_media_player_remove_metadata_listener
 libvlc_media_release
 libvlc_media_retain
 libvlc_media_save_meta
diff --git a/lib/media_player.c b/lib/media_player.c
index 58dfbc39fb6..7ed306ece2b 100644
--- a/lib/media_player.c
+++ b/lib/media_player.c
@@ -2188,6 +2188,109 @@ int libvlc_media_player_get_role(libvlc_media_player_t *mp)
     return ret;
 }
 
+struct libvlc_media_player_metadata_listener_id
+{
+    vlc_player_metadata_listener_id *id;
+    union libvlc_media_player_metadata_cbs cbs;
+    void *cbs_data;
+};
+
+static void
+metadata_wrapper_on_momentary_loudness_changed(vlc_tick_t date,
+                                               double momentary_loudness,
+                                               void *data)
+{
+
+    libvlc_media_player_metadata_listener_id *wrapper = data;
+    wrapper->cbs.on_momentary_loudness_changed(date, momentary_loudness,
+                                               wrapper->cbs_data);
+}
+
+static void
+metadata_wrapper_on_loudness_changed(vlc_tick_t date,
+                                     const struct vlc_audio_loudness *vlc_loudness,
+                                     void *data)
+{
+
+    libvlc_media_player_metadata_listener_id *wrapper = data;
+
+    const struct libvlc_audio_loudness loudness = {
+        .loudness_momentary = vlc_loudness->loudness_momentary,
+        .loudness_shortterm = vlc_loudness->loudness_shortterm,
+        .loudness_integrated = vlc_loudness->loudness_integrated,
+        .loudness_range = vlc_loudness->loudness_range,
+        .truepeak = vlc_loudness->truepeak,
+    };
+    wrapper->cbs.on_loudness_changed(date, &loudness, wrapper->cbs_data);
+}
+
+libvlc_media_player_metadata_listener_id *
+libvlc_media_player_add_metadata_listener(libvlc_media_player_t *mp,
+                                          enum libvlc_media_player_metadata_option option,
+                                          const union libvlc_media_player_metadata_cbs *cbs,
+                                          void *cbs_data)
+{
+    vlc_player_t *player = mp->player;
+
+    libvlc_media_player_metadata_listener_id *wrapper = malloc(sizeof(*wrapper));
+    if (wrapper == NULL)
+        return NULL;
+
+    wrapper->cbs = *cbs;
+    wrapper->cbs_data = cbs_data;
+
+    enum vlc_player_metadata_option vlc_option;
+    union vlc_player_metadata_cbs *vlc_cbs;
+
+    switch (option)
+    {
+        case LIBVLC_MEDIA_PLAYER_METADATA_LOUDNESS_MOMENTARY:
+        {
+            vlc_option = VLC_PLAYER_METADATA_LOUDNESS_MOMENTARY;
+            static union vlc_player_metadata_cbs cbs_momentary_loudness = {
+                .on_momentary_loudness_changed = metadata_wrapper_on_momentary_loudness_changed,
+            };
+            vlc_cbs = &cbs_momentary_loudness;
+            break;
+        }
+        case LIBVLC_MEDIA_PLAYER_METADATA_LOUDNESS_FULL:
+        {
+            vlc_option = VLC_PLAYER_METADATA_LOUDNESS_FULL;
+            static union vlc_player_metadata_cbs cbs_loudness = {
+                .on_loudness_changed = metadata_wrapper_on_loudness_changed,
+            };
+            vlc_cbs = &cbs_loudness;
+            break;
+        }
+        default: vlc_assert_unreachable();
+    }
+
+    vlc_player_Lock(player);
+    vlc_player_metadata_listener_id *id =
+        vlc_player_AddMetadataListener(player, vlc_option, vlc_cbs, wrapper);
+    vlc_player_Unlock(player);
+
+    if (id != NULL)
+        wrapper->id = id;
+    else
+        free(wrapper);
+
+    return wrapper;
+}
+
+void
+libvlc_media_player_remove_metadata_listener(libvlc_media_player_t *mp,
+                                             libvlc_media_player_metadata_listener_id *wrapper)
+{
+    vlc_player_t *player = mp->player;
+
+    vlc_player_Lock(player);
+    vlc_player_RemoveMetadataListener(player, wrapper->id);
+    vlc_player_Unlock(player);
+    free(wrapper);
+}
+
+
 #include <vlc_vout_display.h>
 
 /* make sure surface structures from libvlc can be passed as such to vlc
-- 
2.29.2



More information about the vlc-devel mailing list