1 /* GStreamer
2 * Copyright (C) <2011> 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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "gstplaysinkvideoconvert.h"
25
26 #include <gst/pbutils/pbutils.h>
27 #include <gst/gst-i18n-plugin.h>
28
29 GST_DEBUG_CATEGORY_STATIC (gst_play_sink_video_convert_debug);
30 #define GST_CAT_DEFAULT gst_play_sink_video_convert_debug
31
32 #define parent_class gst_play_sink_video_convert_parent_class
33
34 G_DEFINE_TYPE (GstPlaySinkVideoConvert, gst_play_sink_video_convert,
35 GST_TYPE_PLAY_SINK_CONVERT_BIN);
36
37 enum
38 {
39 PROP_0,
40 PROP_USE_CONVERTERS,
41 PROP_USE_BALANCE,
42 };
43
44 static gboolean
gst_play_sink_video_convert_add_conversion_elements(GstPlaySinkVideoConvert * self)45 gst_play_sink_video_convert_add_conversion_elements (GstPlaySinkVideoConvert *
46 self)
47 {
48 GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self);
49 GstElement *el, *prev = NULL;
50
51 g_assert (cbin->conversion_elements == NULL);
52
53 GST_DEBUG_OBJECT (self,
54 "Building video conversion with use-converters %d, use-balance %d",
55 self->use_converters, self->use_balance);
56
57 if (self->use_converters) {
58 el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin,
59 COLORSPACE, "conv");
60 if (el)
61 prev = el;
62
63 el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin,
64 "videoscale", "scale");
65 if (el) {
66 /* Add black borders if necessary to keep the DAR */
67 g_object_set (el, "add-borders", TRUE, NULL);
68 if (prev) {
69 if (!gst_element_link_pads_full (prev, "src", el, "sink",
70 GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
71 goto link_failed;
72 }
73 prev = el;
74 }
75 }
76
77 if (self->use_balance && self->balance) {
78 el = self->balance;
79 gst_play_sink_convert_bin_add_conversion_element (cbin, el);
80 if (prev) {
81 if (!gst_element_link_pads_full (prev, "src", el, "sink",
82 GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
83 goto link_failed;
84 }
85 prev = el;
86
87 el = gst_play_sink_convert_bin_add_conversion_element_factory (cbin,
88 COLORSPACE, "conv2");
89 if (prev) {
90 if (!gst_element_link_pads_full (prev, "src", el, "sink",
91 GST_PAD_LINK_CHECK_TEMPLATE_CAPS))
92 goto link_failed;
93 }
94 if (el)
95 prev = el;
96 }
97
98 return TRUE;
99
100 link_failed:
101 return FALSE;
102 }
103
104 static void
gst_play_sink_video_convert_finalize(GObject * object)105 gst_play_sink_video_convert_finalize (GObject * object)
106 {
107 GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (object);
108
109 if (self->balance)
110 gst_object_unref (self->balance);
111
112 G_OBJECT_CLASS (parent_class)->finalize (object);
113 }
114
115 static void
gst_play_sink_video_convert_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)116 gst_play_sink_video_convert_set_property (GObject * object, guint prop_id,
117 const GValue * value, GParamSpec * pspec)
118 {
119 GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (object);
120 gboolean v, changed = FALSE;
121
122 GST_PLAY_SINK_CONVERT_BIN_LOCK (self);
123 switch (prop_id) {
124 case PROP_USE_CONVERTERS:
125 v = g_value_get_boolean (value);
126 if (v != self->use_converters) {
127 self->use_converters = v;
128 changed = TRUE;
129 }
130 break;
131 case PROP_USE_BALANCE:
132 v = g_value_get_boolean (value);
133 if (v != self->use_balance) {
134 self->use_balance = v;
135 changed = TRUE;
136 }
137 break;
138 default:
139 break;
140 }
141
142 if (changed) {
143 GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self);
144 GST_DEBUG_OBJECT (self, "Rebuilding converter bin");
145 gst_play_sink_convert_bin_remove_elements (cbin);
146 gst_play_sink_video_convert_add_conversion_elements (self);
147 gst_play_sink_convert_bin_add_identity (cbin);
148 gst_play_sink_convert_bin_cache_converter_caps (cbin);
149 }
150 GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self);
151 }
152
153 static void
gst_play_sink_video_convert_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)154 gst_play_sink_video_convert_get_property (GObject * object, guint prop_id,
155 GValue * value, GParamSpec * pspec)
156 {
157 GstPlaySinkVideoConvert *self = GST_PLAY_SINK_VIDEO_CONVERT_CAST (object);
158
159 GST_PLAY_SINK_CONVERT_BIN_LOCK (self);
160 switch (prop_id) {
161 case PROP_USE_CONVERTERS:
162 g_value_set_boolean (value, self->use_converters);
163 break;
164 case PROP_USE_BALANCE:
165 g_value_set_boolean (value, self->use_balance);
166 break;
167 default:
168 break;
169 }
170 GST_PLAY_SINK_CONVERT_BIN_UNLOCK (self);
171 }
172
173 static void
gst_play_sink_video_convert_class_init(GstPlaySinkVideoConvertClass * klass)174 gst_play_sink_video_convert_class_init (GstPlaySinkVideoConvertClass * klass)
175 {
176 GObjectClass *gobject_class;
177 GstElementClass *gstelement_class;
178
179 GST_DEBUG_CATEGORY_INIT (gst_play_sink_video_convert_debug,
180 "playsinkvideoconvert", 0, "play bin");
181
182 gobject_class = (GObjectClass *) klass;
183 gstelement_class = (GstElementClass *) klass;
184
185 gobject_class->finalize = gst_play_sink_video_convert_finalize;
186 gobject_class->set_property = gst_play_sink_video_convert_set_property;
187 gobject_class->get_property = gst_play_sink_video_convert_get_property;
188
189 g_object_class_install_property (gobject_class, PROP_USE_CONVERTERS,
190 g_param_spec_boolean ("use-converters", "Use converters",
191 "Whether to use conversion elements", FALSE,
192 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
193
194 g_object_class_install_property (gobject_class, PROP_USE_BALANCE,
195 g_param_spec_boolean ("use-balance", "Use balance",
196 "Whether to use a videobalance element", FALSE,
197 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
198
199 gst_element_class_set_static_metadata (gstelement_class,
200 "Player Sink Video Converter", "Video/Bin/Converter",
201 "Convenience bin for video conversion",
202 "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
203 }
204
205 static void
gst_play_sink_video_convert_init(GstPlaySinkVideoConvert * self)206 gst_play_sink_video_convert_init (GstPlaySinkVideoConvert * self)
207 {
208 GstPlaySinkConvertBin *cbin = GST_PLAY_SINK_CONVERT_BIN (self);
209 cbin->audio = FALSE;
210
211 /* FIXME: Only create this on demand but for now we need
212 * it to always exist because of playsink's color balance
213 * proxying logic.
214 */
215 self->balance = gst_element_factory_make ("videobalance", "videobalance");
216 if (self->balance)
217 gst_object_ref_sink (self->balance);
218
219 gst_play_sink_video_convert_add_conversion_elements (self);
220 gst_play_sink_convert_bin_cache_converter_caps (cbin);
221 }
222