1 /* GStreamer
2  *
3  * Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
4  * Copyright (C) 2015 Brijesh Singh <brijesh.ksingh@gmail.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21 
22 /**
23  * SECTION:gstplayer-visualization
24  * @title: GstPlayerVisualization
25  * @short_description: Player Visualization
26  *
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 
33 #include "gstplayer-visualization.h"
34 
35 #include <string.h>
36 
37 static GMutex vis_lock;
38 static GQueue vis_list = G_QUEUE_INIT;
39 static guint32 vis_cookie;
40 
41 G_DEFINE_BOXED_TYPE (GstPlayerVisualization, gst_player_visualization,
42     (GBoxedCopyFunc) gst_player_visualization_copy,
43     (GBoxedFreeFunc) gst_player_visualization_free);
44 
45 /**
46  * gst_player_visualization_free:
47  * @vis: #GstPlayerVisualization instance
48  *
49  * Frees a #GstPlayerVisualization.
50  */
51 void
gst_player_visualization_free(GstPlayerVisualization * vis)52 gst_player_visualization_free (GstPlayerVisualization * vis)
53 {
54   g_return_if_fail (vis != NULL);
55 
56   g_free (vis->name);
57   g_free (vis->description);
58   g_free (vis);
59 }
60 
61 /**
62  * gst_player_visualization_copy:
63  * @vis: #GstPlayerVisualization instance
64  *
65  * Makes a copy of the #GstPlayerVisualization. The result must be
66  * freed using gst_player_visualization_free().
67  *
68  * Returns: (transfer full): an allocated copy of @vis.
69  */
70 GstPlayerVisualization *
gst_player_visualization_copy(const GstPlayerVisualization * vis)71 gst_player_visualization_copy (const GstPlayerVisualization * vis)
72 {
73   GstPlayerVisualization *ret;
74 
75   g_return_val_if_fail (vis != NULL, NULL);
76 
77   ret = g_new0 (GstPlayerVisualization, 1);
78   ret->name = vis->name ? g_strdup (vis->name) : NULL;
79   ret->description = vis->description ? g_strdup (vis->description) : NULL;
80 
81   return ret;
82 }
83 
84 /**
85  * gst_player_visualizations_free:
86  * @viss: a %NULL terminated array of #GstPlayerVisualization to free
87  *
88  * Frees a %NULL terminated array of #GstPlayerVisualization.
89  */
90 void
gst_player_visualizations_free(GstPlayerVisualization ** viss)91 gst_player_visualizations_free (GstPlayerVisualization ** viss)
92 {
93   GstPlayerVisualization **p;
94 
95   g_return_if_fail (viss != NULL);
96 
97   p = viss;
98   while (*p) {
99     g_free ((*p)->name);
100     g_free ((*p)->description);
101     g_free (*p);
102     p++;
103   }
104   g_free (viss);
105 }
106 
107 static void
gst_player_update_visualization_list(void)108 gst_player_update_visualization_list (void)
109 {
110   GList *features;
111   GList *l;
112   guint32 cookie;
113   GstPlayerVisualization *vis;
114 
115   g_mutex_lock (&vis_lock);
116 
117   /* check if we need to update the list */
118   cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
119   if (vis_cookie == cookie) {
120     g_mutex_unlock (&vis_lock);
121     return;
122   }
123 
124   /* if update is needed then first free the existing list */
125   while ((vis = g_queue_pop_head (&vis_list)))
126     gst_player_visualization_free (vis);
127 
128   features = gst_registry_get_feature_list (gst_registry_get (),
129       GST_TYPE_ELEMENT_FACTORY);
130 
131   for (l = features; l; l = l->next) {
132     GstPluginFeature *feature = l->data;
133     const gchar *klass;
134 
135     klass = gst_element_factory_get_metadata (GST_ELEMENT_FACTORY (feature),
136         GST_ELEMENT_METADATA_KLASS);
137 
138     if (strstr (klass, "Visualization")) {
139       vis = g_new0 (GstPlayerVisualization, 1);
140 
141       vis->name = g_strdup (gst_plugin_feature_get_name (feature));
142       vis->description =
143           g_strdup (gst_element_factory_get_metadata (GST_ELEMENT_FACTORY
144               (feature), GST_ELEMENT_METADATA_DESCRIPTION));
145       g_queue_push_tail (&vis_list, vis);
146     }
147   }
148   gst_plugin_feature_list_free (features);
149 
150   vis_cookie = cookie;
151 
152   g_mutex_unlock (&vis_lock);
153 }
154 
155 /**
156  * gst_player_visualizations_get:
157  *
158  * Returns: (transfer full) (array zero-terminated=1) (element-type GstPlayerVisualization):
159  *  a %NULL terminated array containing all available
160  *  visualizations. Use gst_player_visualizations_free() after
161  *  usage.
162  */
163 GstPlayerVisualization **
gst_player_visualizations_get(void)164 gst_player_visualizations_get (void)
165 {
166   gint i = 0;
167   GList *l;
168   GstPlayerVisualization **ret;
169 
170   gst_player_update_visualization_list ();
171 
172   g_mutex_lock (&vis_lock);
173   ret = g_new0 (GstPlayerVisualization *, g_queue_get_length (&vis_list) + 1);
174   for (l = vis_list.head; l; l = l->next)
175     ret[i++] = gst_player_visualization_copy (l->data);
176   g_mutex_unlock (&vis_lock);
177 
178   return ret;
179 }
180