Tizen 2.0 Release
[framework/multimedia/gst-plugins-bad0.10.git] / ext / gsettings / gstgsettingsvideosrc.c
1 /* 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
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
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  * |[
28  * gst-launch gsettingsvideosrc ! ffmpegcolorspace ! videoscale ! autovideosink
29  * ]| 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 <string.h>
39
40 #include "gstgsettingsvideosrc.h"
41 #include "gstgsettings.h"
42
43 GST_BOILERPLATE (GstGSettingsVideoSrc, gst_gsettings_video_src, GstSwitchSrc,
44     GST_TYPE_SWITCH_SRC);
45
46 static gboolean
47 gst_gsettings_video_src_change_child (GstGSettingsVideoSrc * src)
48 {
49   gchar *new_string;
50   GError *err = NULL;
51   GstElement *new_kid;
52
53   GST_OBJECT_LOCK (src);
54   new_string =
55       g_settings_get_string (src->settings, GST_GSETTINGS_KEY_VIDEOSRC);
56
57   if (new_string != NULL && src->gsettings_str != NULL &&
58       (strlen (new_string) == 0 ||
59           strcmp (src->gsettings_str, new_string) == 0)) {
60     g_free (new_string);
61     GST_DEBUG_OBJECT (src,
62         "GSettings key was updated, but it didn't change. Ignoring");
63     GST_OBJECT_UNLOCK (src);
64     return TRUE;
65   }
66   GST_OBJECT_UNLOCK (src);
67
68   GST_DEBUG_OBJECT (src, "GSettings key changed from '%s' to '%s'",
69       GST_STR_NULL (src->gsettings_str), GST_STR_NULL (new_string));
70
71   if (new_string) {
72     new_kid = gst_parse_bin_from_description (new_string, TRUE, &err);
73     if (err) {
74       GST_ERROR_OBJECT (src, "error creating bin '%s': %s", new_string,
75           err->message);
76       g_error_free (err);
77     }
78   } else {
79     new_kid = NULL;
80   }
81
82   if (new_kid == NULL) {
83     GST_ELEMENT_ERROR (src, LIBRARY, SETTINGS, (NULL),
84         ("Failed to render video src from GSettings"));
85     goto fail;
86   }
87
88   if (!gst_switch_src_set_child (GST_SWITCH_SRC (src), new_kid)) {
89     GST_WARNING_OBJECT (src, "Failed to update child element");
90     goto fail;
91   }
92
93   g_free (src->gsettings_str);
94   src->gsettings_str = new_string;
95
96   return TRUE;
97
98 fail:
99   g_free (new_string);
100   return FALSE;
101 }
102
103 static void
104 on_changed (GSettings * settings, gchar * key, GstGSettingsVideoSrc * src)
105 {
106   if (!g_str_equal (key, "videosrc"));
107   return;
108
109   gst_gsettings_video_src_change_child (src);
110 }
111
112 static gboolean
113 gst_gsettings_video_src_start (GstGSettingsVideoSrc * src)
114 {
115   GError *err = NULL;
116   GThread *thread;
117
118   src->loop = g_main_loop_new (src->context, FALSE);
119
120   thread =
121       g_thread_create ((GThreadFunc) g_main_loop_run, src->loop, FALSE, &err);
122   if (!thread) {
123     GST_ELEMENT_ERROR (src, CORE, STATE_CHANGE, (NULL),
124         ("Failed to create new thread: %s", err->message));
125     g_error_free (err);
126     g_main_loop_unref (src->loop);
127     src->loop = NULL;
128     return FALSE;
129   }
130
131   g_main_context_push_thread_default (src->context);
132   src->settings = g_settings_new (GST_GSETTINGS_SCHEMA);
133   src->changed_id =
134       g_signal_connect_data (G_OBJECT (src->settings), "changed",
135       G_CALLBACK (on_changed), gst_object_ref (src),
136       (GClosureNotify) gst_object_unref, 0);
137   g_main_context_pop_thread_default (src->context);
138
139   return TRUE;
140 }
141
142 static gboolean
143 gst_gsettings_video_src_reset (GstGSettingsVideoSrc * src)
144 {
145   gst_switch_src_set_child (GST_SWITCH_SRC (src), NULL);
146
147   if (src->changed_id) {
148     g_signal_handler_disconnect (src->settings, src->changed_id);
149     src->changed_id = 0;
150   }
151
152   if (src->loop) {
153     g_main_loop_quit (src->loop);
154     g_main_loop_unref (src->loop);
155     src->loop = NULL;
156   }
157
158   if (src->settings) {
159     g_object_unref (src->settings);
160     src->settings = NULL;
161   }
162
163   GST_OBJECT_LOCK (src);
164   g_free (src->gsettings_str);
165   src->gsettings_str = NULL;
166   GST_OBJECT_UNLOCK (src);
167
168   return TRUE;
169 }
170
171 static void
172 gst_gsettings_video_src_finalize (GObject * object)
173 {
174   GstGSettingsVideoSrc *src = GST_GSETTINGS_VIDEO_SRC (object);
175
176   g_free (src->gsettings_str);
177   g_main_context_unref (src->context);
178
179   GST_CALL_PARENT (G_OBJECT_CLASS, finalize, ((GObject *) (src)));
180 }
181
182 static GstStateChangeReturn
183 gst_gsettings_video_src_change_state (GstElement * element,
184     GstStateChange transition)
185 {
186   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
187   GstGSettingsVideoSrc *src = GST_GSETTINGS_VIDEO_SRC (element);
188
189   switch (transition) {
190     case GST_STATE_CHANGE_NULL_TO_READY:
191       if (!gst_gsettings_video_src_start (src))
192         return GST_STATE_CHANGE_FAILURE;
193
194       if (!gst_gsettings_video_src_change_child (src)) {
195         gst_gsettings_video_src_reset (src);
196         return GST_STATE_CHANGE_FAILURE;
197       }
198       break;
199     default:
200       break;
201   }
202
203   ret = GST_CALL_PARENT_WITH_DEFAULT (GST_ELEMENT_CLASS, change_state,
204       (element, transition), GST_STATE_CHANGE_SUCCESS);
205
206   switch (transition) {
207     case GST_STATE_CHANGE_READY_TO_NULL:
208       gst_gsettings_video_src_reset (src);
209       break;
210     default:
211       break;
212   }
213
214   return ret;
215 }
216
217 static void
218 gst_gsettings_video_src_init (GstGSettingsVideoSrc * src,
219     GstGSettingsVideoSrcClass * g_class)
220 {
221   src->context = g_main_context_new ();
222   gst_gsettings_video_src_reset (src);
223 }
224
225 static void
226 gst_gsettings_video_src_base_init (gpointer klass)
227 {
228   GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
229
230   gst_element_class_set_details_simple (eklass, "GSettings video src",
231       "Src/Video",
232       "Video src embedding the GSettings preferences for video input",
233       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
234 }
235
236 static void
237 gst_gsettings_video_src_class_init (GstGSettingsVideoSrcClass * klass)
238 {
239   GObjectClass *oklass = G_OBJECT_CLASS (klass);
240   GstElementClass *eklass = GST_ELEMENT_CLASS (klass);
241
242   oklass->finalize = gst_gsettings_video_src_finalize;
243
244   eklass->change_state = gst_gsettings_video_src_change_state;
245 }