• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2010 Thiago Santos <thiago.sousa.santos@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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 /**
20  * SECTION:element-viewfinderbin
21  * @title: gstviewfinderbin
22  *
23  * The gstviewfinderbin element is a displaying element for camerabin2.
24  *
25  * ## Example launch line
26  * |[
27  * gst-launch-1.0 -v videotestsrc ! viewfinderbin
28  * ]|
29  * Feeds the viewfinderbin with video test data.
30  *
31  */
32 
33 #ifdef HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 
37 #include "gstviewfinderbin.h"
38 #include "camerabingeneral.h"
39 #include <gst/pbutils/pbutils.h>
40 
41 #include <gst/gst-i18n-plugin.h>
42 
43 GST_DEBUG_CATEGORY_STATIC (gst_viewfinder_bin_debug);
44 #define GST_CAT_DEFAULT gst_viewfinder_bin_debug
45 
46 enum
47 {
48   PROP_0,
49   PROP_VIDEO_SINK,
50   PROP_DISABLE_CONVERTERS
51 };
52 
53 #define DEFAULT_DISABLE_CONVERTERS FALSE
54 
55 /* pad templates */
56 
57 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
58     GST_PAD_SINK,
59     GST_PAD_ALWAYS,
60     GST_STATIC_CAPS ("video/x-raw(ANY)")
61     );
62 
63 /* class initialization */
64 #define gst_viewfinder_bin_parent_class parent_class
65 G_DEFINE_TYPE (GstViewfinderBin, gst_viewfinder_bin, GST_TYPE_BIN);
66 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (viewfinderbin, "viewfinderbin",
67     GST_RANK_NONE, gst_viewfinder_bin_get_type (),
68     GST_DEBUG_CATEGORY_INIT (gst_viewfinder_bin_debug, "viewfinderbin", 0,
69         "ViewFinderBin");
70     );
71 
72 static void gst_viewfinder_bin_set_property (GObject * object, guint prop_id,
73     const GValue * value, GParamSpec * spec);
74 static void gst_viewfinder_bin_get_property (GObject * object, guint prop_id,
75     GValue * value, GParamSpec * spec);
76 
77 static void
78 gst_viewfinder_bin_set_video_sink (GstViewfinderBin * vfbin, GstElement * sink);
79 
80 
81 /* Element class functions */
82 static GstStateChangeReturn
83 gst_viewfinder_bin_change_state (GstElement * element, GstStateChange trans);
84 
85 static void
gst_viewfinder_bin_dispose(GObject * object)86 gst_viewfinder_bin_dispose (GObject * object)
87 {
88   GstViewfinderBin *viewfinderbin = GST_VIEWFINDER_BIN_CAST (object);
89 
90   if (viewfinderbin->user_video_sink) {
91     gst_object_unref (viewfinderbin->user_video_sink);
92     viewfinderbin->user_video_sink = NULL;
93   }
94 
95   if (viewfinderbin->video_sink) {
96     gst_object_unref (viewfinderbin->video_sink);
97     viewfinderbin->video_sink = NULL;
98   }
99 
100   G_OBJECT_CLASS (parent_class)->dispose ((GObject *) viewfinderbin);
101 }
102 
103 static void
gst_viewfinder_bin_class_init(GstViewfinderBinClass * klass)104 gst_viewfinder_bin_class_init (GstViewfinderBinClass * klass)
105 {
106   GObjectClass *gobject_klass;
107   GstElementClass *element_class;
108 
109   gobject_klass = (GObjectClass *) klass;
110   element_class = GST_ELEMENT_CLASS (klass);
111 
112   element_class->change_state =
113       GST_DEBUG_FUNCPTR (gst_viewfinder_bin_change_state);
114 
115   gobject_klass->dispose = gst_viewfinder_bin_dispose;
116   gobject_klass->set_property = gst_viewfinder_bin_set_property;
117   gobject_klass->get_property = gst_viewfinder_bin_get_property;
118 
119   g_object_class_install_property (gobject_klass, PROP_VIDEO_SINK,
120       g_param_spec_object ("video-sink", "Video Sink",
121           "the video output element to use (NULL = default)",
122           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
123 
124   g_object_class_install_property (gobject_klass, PROP_DISABLE_CONVERTERS,
125       g_param_spec_boolean ("disable-converters", "Disable conversion elements",
126           "If video converters should be disabled (must be set on NULL)",
127           DEFAULT_DISABLE_CONVERTERS,
128           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
129 
130   gst_element_class_add_static_pad_template (element_class, &sink_template);
131 
132   gst_element_class_set_static_metadata (element_class, "Viewfinder Bin",
133       "Sink/Video", "Viewfinder Bin used in camerabin2",
134       "Thiago Santos <thiago.sousa.santos@collabora.com>");
135 }
136 
137 static void
gst_viewfinder_bin_init(GstViewfinderBin * viewfinderbin)138 gst_viewfinder_bin_init (GstViewfinderBin * viewfinderbin)
139 {
140   GstPadTemplate *templ = gst_static_pad_template_get (&sink_template);
141   viewfinderbin->ghostpad = gst_ghost_pad_new_no_target_from_template ("sink",
142       templ);
143   gst_object_unref (templ);
144   gst_element_add_pad (GST_ELEMENT_CAST (viewfinderbin),
145       viewfinderbin->ghostpad);
146 
147   viewfinderbin->disable_converters = DEFAULT_DISABLE_CONVERTERS;
148 }
149 
150 static gboolean
gst_viewfinder_bin_create_elements(GstViewfinderBin * vfbin)151 gst_viewfinder_bin_create_elements (GstViewfinderBin * vfbin)
152 {
153   GstElement *csp = NULL;
154   GstElement *videoscale = NULL;
155   GstPad *firstpad = NULL;
156   const gchar *missing_element_name;
157   gboolean newsink = FALSE;
158   gboolean updated_converters = FALSE;
159 
160   GST_DEBUG_OBJECT (vfbin, "Creating internal elements");
161 
162   /* First check if we need to add/replace the internal sink */
163   if (vfbin->video_sink) {
164     if (vfbin->user_video_sink && vfbin->video_sink != vfbin->user_video_sink) {
165       gst_bin_remove (GST_BIN_CAST (vfbin), vfbin->video_sink);
166       gst_object_unref (vfbin->video_sink);
167       vfbin->video_sink = NULL;
168     }
169   }
170 
171   if (!vfbin->video_sink) {
172     if (vfbin->user_video_sink)
173       vfbin->video_sink = gst_object_ref (vfbin->user_video_sink);
174     else {
175       vfbin->video_sink = gst_element_factory_make ("autovideosink",
176           "vfbin-sink");
177       if (!vfbin->video_sink) {
178         missing_element_name = "autovideosink";
179         goto missing_element;
180       }
181     }
182 
183     gst_bin_add (GST_BIN_CAST (vfbin), gst_object_ref (vfbin->video_sink));
184     newsink = TRUE;
185   }
186 
187   /* check if we want add/remove the conversion elements */
188   if (vfbin->elements_created && vfbin->disable_converters) {
189     /* remove the elements, user doesn't want them */
190 
191     gst_ghost_pad_set_target (GST_GHOST_PAD (vfbin->ghostpad), NULL);
192     csp = gst_bin_get_by_name (GST_BIN_CAST (vfbin), "vfbin-csp");
193     videoscale = gst_bin_get_by_name (GST_BIN_CAST (vfbin), "vfbin-videoscale");
194 
195     gst_bin_remove (GST_BIN_CAST (vfbin), csp);
196     gst_bin_remove (GST_BIN_CAST (vfbin), videoscale);
197 
198     gst_object_unref (csp);
199     gst_object_unref (videoscale);
200 
201     updated_converters = TRUE;
202   } else if (!vfbin->elements_created && !vfbin->disable_converters) {
203     gst_ghost_pad_set_target (GST_GHOST_PAD (vfbin->ghostpad), NULL);
204 
205     /* add the elements, user wants them */
206     csp = gst_element_factory_make ("videoconvert", "vfbin-csp");
207     if (!csp) {
208       missing_element_name = "videoconvert";
209       goto missing_element;
210     }
211     gst_bin_add (GST_BIN_CAST (vfbin), csp);
212 
213     videoscale = gst_element_factory_make ("videoscale", "vfbin-videoscale");
214     if (!videoscale) {
215       missing_element_name = "videoscale";
216       goto missing_element;
217     }
218     gst_bin_add (GST_BIN_CAST (vfbin), videoscale);
219 
220     gst_element_link_pads_full (csp, "src", videoscale, "sink",
221         GST_PAD_LINK_CHECK_NOTHING);
222 
223     vfbin->elements_created = TRUE;
224     GST_DEBUG_OBJECT (vfbin, "Elements successfully created and linked");
225 
226     updated_converters = TRUE;
227   }
228   /* otherwise, just leave it as is */
229 
230   /* if sink was replaced -> link it to the internal converters */
231   if (newsink && !vfbin->disable_converters) {
232     gboolean unref = FALSE;
233     if (!videoscale) {
234       videoscale = gst_bin_get_by_name (GST_BIN_CAST (vfbin),
235           "vfbin-videoscale");
236       unref = TRUE;
237     }
238 
239     if (!gst_element_link_pads_full (videoscale, "src", vfbin->video_sink,
240             "sink", GST_PAD_LINK_CHECK_CAPS)) {
241       GST_ELEMENT_ERROR (vfbin, CORE, NEGOTIATION, (NULL),
242           ("linking videoscale and viewfindersink failed"));
243     }
244 
245     if (unref)
246       gst_object_unref (videoscale);
247     videoscale = NULL;
248   }
249 
250   /* Check if we need a new ghostpad target */
251   if (updated_converters || (newsink && vfbin->disable_converters)) {
252     if (vfbin->disable_converters) {
253       firstpad = gst_element_get_static_pad (vfbin->video_sink, "sink");
254     } else {
255       /* csp should always exist at this point */
256       firstpad = gst_element_get_static_pad (csp, "sink");
257     }
258   }
259 
260   /* need to change the ghostpad target if firstpad is set */
261   if (firstpad) {
262     if (!gst_ghost_pad_set_target (GST_GHOST_PAD (vfbin->ghostpad), firstpad))
263       goto error;
264     gst_object_unref (firstpad);
265     firstpad = NULL;
266   }
267 
268   return TRUE;
269 
270 missing_element:
271   gst_element_post_message (GST_ELEMENT_CAST (vfbin),
272       gst_missing_element_message_new (GST_ELEMENT_CAST (vfbin),
273           missing_element_name));
274   GST_ELEMENT_ERROR (vfbin, CORE, MISSING_PLUGIN,
275       (_("Missing element '%s' - check your GStreamer installation."),
276           missing_element_name), (NULL));
277   goto error;
278 
279 error:
280   GST_WARNING_OBJECT (vfbin, "Creating internal elements failed");
281   if (firstpad)
282     gst_object_unref (firstpad);
283   return FALSE;
284 }
285 
286 static GstStateChangeReturn
gst_viewfinder_bin_change_state(GstElement * element,GstStateChange trans)287 gst_viewfinder_bin_change_state (GstElement * element, GstStateChange trans)
288 {
289   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
290   GstViewfinderBin *vfbin = GST_VIEWFINDER_BIN_CAST (element);
291 
292   switch (trans) {
293     case GST_STATE_CHANGE_NULL_TO_READY:
294       if (!gst_viewfinder_bin_create_elements (vfbin)) {
295         return GST_STATE_CHANGE_FAILURE;
296       }
297       break;
298     default:
299       break;
300   }
301 
302   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, trans);
303 
304   switch (trans) {
305     case GST_STATE_CHANGE_READY_TO_NULL:
306       break;
307     default:
308       break;
309   }
310 
311   return ret;
312 }
313 
314 static void
gst_viewfinder_bin_set_video_sink(GstViewfinderBin * vfbin,GstElement * sink)315 gst_viewfinder_bin_set_video_sink (GstViewfinderBin * vfbin, GstElement * sink)
316 {
317   GST_INFO_OBJECT (vfbin, "Setting video sink to %" GST_PTR_FORMAT, sink);
318 
319   if (vfbin->user_video_sink != sink) {
320     if (vfbin->user_video_sink) {
321       gst_object_unref (vfbin->user_video_sink);
322     }
323     vfbin->user_video_sink = sink;
324     if (sink)
325       gst_object_ref (sink);
326   }
327 }
328 
329 static void
gst_viewfinder_bin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)330 gst_viewfinder_bin_set_property (GObject * object, guint prop_id,
331     const GValue * value, GParamSpec * pspec)
332 {
333   GstViewfinderBin *vfbin = GST_VIEWFINDER_BIN_CAST (object);
334 
335   switch (prop_id) {
336     case PROP_VIDEO_SINK:
337       gst_viewfinder_bin_set_video_sink (vfbin, g_value_get_object (value));
338       break;
339     case PROP_DISABLE_CONVERTERS:
340       vfbin->disable_converters = g_value_get_boolean (value);
341       break;
342     default:
343       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
344       break;
345   }
346 }
347 
348 static void
gst_viewfinder_bin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)349 gst_viewfinder_bin_get_property (GObject * object, guint prop_id,
350     GValue * value, GParamSpec * pspec)
351 {
352   GstViewfinderBin *vfbin = GST_VIEWFINDER_BIN_CAST (object);
353 
354   switch (prop_id) {
355     case PROP_VIDEO_SINK:
356       g_value_set_object (value, vfbin->video_sink);
357       break;
358     case PROP_DISABLE_CONVERTERS:
359       g_value_set_boolean (value, vfbin->disable_converters);
360       break;
361     default:
362       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
363       break;
364   }
365 }
366