blob: 2b768675d85f01e5c5247e1728dfaffc2ae4fbb2 [file] [log] [blame]
Olivier Naudanb28313f2012-04-16 08:10:18 -04001/* GStreamer
2 * Copyright (C) 2010 Sebastian Dröge <sebastian.droege@collabora.co.uk>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
Sebastian Drögee6513c12013-07-14 12:12:42 +020016 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
Olivier Naudanb28313f2012-04-16 08:10:18 -040018 */
19/**
20 * SECTION:element-gsettingsvideosrc
21 *
22 * This element outputs sound to the videosrc that has been configured in
23 * GSettings by the user.
24 *
25 * <refsect2>
26 * <title>Example launch line</title>
27 * |[
Sebastian Dröge8aae4522012-09-18 10:21:31 +020028 * gst-launch gsettingsvideosrc ! videoconvert ! videoscale ! autovideosink
Olivier Naudanb28313f2012-04-16 08:10:18 -040029 * ]| Play from configured videosrc
30 * </refsect2>
31 */
32
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36
37#include <gst/gst.h>
38#include <gst/glib-compat-private.h>
39#include <string.h>
40
41#include "gstgsettingsvideosrc.h"
42#include "gstgsettings.h"
43
44GST_BOILERPLATE (GstGSettingsVideoSrc, gst_gsettings_video_src, GstSwitchSrc,
45 GST_TYPE_SWITCH_SRC);
46
47static gboolean
48gst_gsettings_video_src_change_child (GstGSettingsVideoSrc * src)
49{
50 gchar *new_string;
51 GError *err = NULL;
52 GstElement *new_kid;
53
54 GST_OBJECT_LOCK (src);
55 new_string =
56 g_settings_get_string (src->settings, GST_GSETTINGS_KEY_VIDEOSRC);
57
58 if (new_string != NULL && src->gsettings_str != NULL &&
59 (strlen (new_string) == 0 ||
60 strcmp (src->gsettings_str, new_string) == 0)) {
61 g_free (new_string);
62 GST_DEBUG_OBJECT (src,
63 "GSettings key was updated, but it didn't change. Ignoring");
64 GST_OBJECT_UNLOCK (src);
65 return TRUE;
66 }
67 GST_OBJECT_UNLOCK (src);
68
69 GST_DEBUG_OBJECT (src, "GSettings key changed from '%s' to '%s'",
70 GST_STR_NULL (src->gsettings_str), GST_STR_NULL (new_string));
71
72 if (new_string) {
73 new_kid = gst_parse_bin_from_description (new_string, TRUE, &err);
74 if (err) {
75 GST_ERROR_OBJECT (src, "error creating bin '%s': %s", new_string,
76 err->message);
77 g_error_free (err);
78 }
79 } else {
80 new_kid = NULL;
81 }
82
83 if (new_kid == NULL) {
84 GST_ELEMENT_ERROR (src, LIBRARY, SETTINGS, (NULL),
85 ("Failed to render video src from GSettings"));
86 goto fail;
87 }
88
89 if (!gst_switch_src_set_child (GST_SWITCH_SRC (src), new_kid)) {
90 GST_WARNING_OBJECT (src, "Failed to update child element");
91 goto fail;
92 }
93
94 g_free (src->gsettings_str);
95 src->gsettings_str = new_string;
96
97 return TRUE;
98
99fail:
100 g_free (new_string);
101 return FALSE;
102}
103
104static void
105on_changed (GSettings * settings, gchar * key, GstGSettingsVideoSrc * src)
106{
107 if (!g_str_equal (key, "videosrc"))
108 return;
109
110 gst_gsettings_video_src_change_child (src);
111}
112
113static gboolean
114gst_gsettings_video_src_start (GstGSettingsVideoSrc * src)
115{
116 GError *err = NULL;
117 GThread *thread;
118
119 src->loop = g_main_loop_new (src->context, FALSE);
120
121 thread =
122 g_thread_create ((GThreadFunc) g_main_loop_run, src->loop, FALSE, &err);
123 if (!thread) {
124 GST_ELEMENT_ERROR (src, CORE, STATE_CHANGE, (NULL),
125 ("Failed to create new thread: %s", err->message));
126 g_error_free (err);
127 g_main_loop_unref (src->loop);
128 src->loop = NULL;
129 return FALSE;
130 }
131
132 g_main_context_push_thread_default (src->context);
133 src->settings = g_settings_new (GST_GSETTINGS_SCHEMA);
134 src->changed_id =
135 g_signal_connect_data (G_OBJECT (src->settings), "changed",
136 G_CALLBACK (on_changed), gst_object_ref (src),
137 (GClosureNotify) gst_object_unref, 0);
138 g_main_context_pop_thread_default (src->context);
139
140 return TRUE;
141}
142
143static gboolean
144gst_gsettings_video_src_reset (GstGSettingsVideoSrc * src)
145{
146 gst_switch_src_set_child (GST_SWITCH_SRC (src), NULL);
147
148 if (src->changed_id) {
149 g_signal_handler_disconnect (src->settings, src->changed_id);
150 src->changed_id = 0;
151 }
152
153 if (src->loop) {
154 g_main_loop_quit (src->loop);
155 g_main_loop_unref (src->loop);
156 src->loop = NULL;
157 }
158
159 if (src->settings) {
160 g_object_unref (src->settings);
161 src->settings = NULL;
162 }
163
164 GST_OBJECT_LOCK (src);
165 g_free (src->gsettings_str);
166 src->gsettings_str = NULL;
167 GST_OBJECT_UNLOCK (src);
168
169 return TRUE;
170}
171
172static void
173gst_gsettings_video_src_finalize (GObject * object)
174{
175 GstGSettingsVideoSrc *src = GST_GSETTINGS_VIDEO_SRC (object);
176
177 g_free (src->gsettings_str);
178 g_main_context_unref (src->context);
179
180 GST_CALL_PARENT (G_OBJECT_CLASS, finalize, ((GObject *) (src)));
181}
182
183static GstStateChangeReturn
184gst_gsettings_video_src_change_state (GstElement * element,
185 GstStateChange transition)
186{
187 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
188 GstGSettingsVideoSrc *src = GST_GSETTINGS_VIDEO_SRC (element);
189
190 switch (transition) {
191 case GST_STATE_CHANGE_NULL_TO_READY:
192 if (!gst_gsettings_video_src_start (src))
193 return GST_STATE_CHANGE_FAILURE;
194
195 if (!gst_gsettings_video_src_change_child (src)) {
196 gst_gsettings_video_src_reset (src);
197 return GST_STATE_CHANGE_FAILURE;
198 }
199 break;
200 default:
201 break;
202 }
203
204 ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
205 (element, transition), GST_STATE_CHANGE_SUCCESS);
206
207 switch (transition) {
208 case GST_STATE_CHANGE_READY_TO_NULL:
209 gst_gsettings_video_src_reset (src);
210 break;
211 default:
212 break;
213 }
214
215 return ret;
216}
217
218static void
219gst_gsettings_video_src_init (GstGSettingsVideoSrc * src,
220 GstGSettingsVideoSrcClass * g_class)
221{
222 src->context = g_main_context_new ();
223 gst_gsettings_video_src_reset (src);
224}
225
226static void
227gst_gsettings_video_src_base_init (gpointer klass)
228{
229 GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
230
Sebastian Dröge6a5ec012012-10-25 14:10:09 +0200231 gst_element_class_set_static_metadata (eklass, "GSettings video src",
Olivier Naudanb28313f2012-04-16 08:10:18 -0400232 "Src/Video",
233 "Video src embedding the GSettings preferences for video input",
234 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
235}
236
237static void
238gst_gsettings_video_src_class_init (GstGSettingsVideoSrcClass * klass)
239{
240 GObjectClass *oklass = G_OBJECT_CLASS (klass);
241 GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
242
243 oklass->finalize = gst_gsettings_video_src_finalize;
244
245 eklass->change_state = gst_gsettings_video_src_change_state;
246}