1 /*
2 Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). <qt-info@nokia.com>
3 Copyright (C) 2011-2012 Collabora Ltd. <info@collabora.com>
4
5 This library is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License version 2.1
7 as published by the Free Software Foundation.
8
9 This program 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
12 GNU Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "gstqtglvideosinkbase.h"
19 #include "painters/openglsurfacepainter.h"
20 #include "delegates/qtvideosinkdelegate.h"
21 #include <QCoreApplication>
22
23 #define CAPS_FORMATS "{ BGRA, BGRx, ARGB, xRGB, RGB, RGB16, BGR, v308, AYUV, YV12, I420 }"
24
25 const char * const GstQtGLVideoSinkBase::s_colorbalance_labels[] = {
26 "contrast", "brightness", "hue", "saturation"
27 };
28
29 GstQtVideoSinkBaseClass *GstQtGLVideoSinkBase::s_parent_class = 0;
30
31 //------------------------------
32
DEFINE_TYPE_WITH_CODE(GstQtGLVideoSinkBase,GST_TYPE_QT_VIDEO_SINK_BASE,init_interfaces)33 DEFINE_TYPE_WITH_CODE(GstQtGLVideoSinkBase, GST_TYPE_QT_VIDEO_SINK_BASE, init_interfaces)
34
35 void GstQtGLVideoSinkBase::init_interfaces(GType type)
36 {
37 static const GInterfaceInfo colorbalance_info = {
38 (GInterfaceInitFunc) &GstQtGLVideoSinkBase::colorbalance_init, NULL, NULL
39 };
40
41 g_type_add_interface_static(type, GST_TYPE_COLOR_BALANCE, &colorbalance_info);
42 }
43
44 //------------------------------
45
base_init(gpointer g_class)46 void GstQtGLVideoSinkBase::base_init(gpointer g_class)
47 {
48 GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
49 element_class->padtemplates = NULL; //get rid of the pad template of the base class
50
51 static GstStaticPadTemplate sink_pad_template =
52 GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
53 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE (CAPS_FORMATS))
54 );
55
56 gst_element_class_add_pad_template(
57 element_class, gst_static_pad_template_get(&sink_pad_template));
58 }
59
class_init(gpointer g_class,gpointer class_data)60 void GstQtGLVideoSinkBase::class_init(gpointer g_class, gpointer class_data)
61 {
62 Q_UNUSED(class_data);
63
64 s_parent_class = reinterpret_cast<GstQtVideoSinkBaseClass*>(g_type_class_peek_parent(g_class));
65
66 GObjectClass *object_class = G_OBJECT_CLASS(g_class);
67 object_class->finalize = GstQtGLVideoSinkBase::finalize;
68 object_class->set_property = GstQtGLVideoSinkBase::set_property;
69 object_class->get_property = GstQtGLVideoSinkBase::get_property;
70
71 GstBaseSinkClass *base_sink_class = GST_BASE_SINK_CLASS(g_class);
72 base_sink_class->start = GstQtGLVideoSinkBase::start;
73 base_sink_class->set_caps = GstQtGLVideoSinkBase::set_caps;
74
75 g_object_class_install_property(object_class, PROP_CONTRAST,
76 g_param_spec_int("contrast", "Contrast", "The contrast of the video",
77 -100, 100, 0, static_cast<GParamFlags>(G_PARAM_READWRITE)));
78 g_object_class_install_property(object_class, PROP_BRIGHTNESS,
79 g_param_spec_int("brightness", "Brightness", "The brightness of the video",
80 -100, 100, 0, static_cast<GParamFlags>(G_PARAM_READWRITE)));
81 g_object_class_install_property(object_class, PROP_HUE,
82 g_param_spec_int("hue", "Hue", "The hue of the video",
83 -100, 100, 0, static_cast<GParamFlags>(G_PARAM_READWRITE)));
84 g_object_class_install_property(object_class, PROP_SATURATION,
85 g_param_spec_int("saturation", "Saturation", "The saturation of the video",
86 -100, 100, 0, static_cast<GParamFlags>(G_PARAM_READWRITE)));
87 }
88
init(GTypeInstance * instance,gpointer g_class)89 void GstQtGLVideoSinkBase::init(GTypeInstance *instance, gpointer g_class)
90 {
91 Q_UNUSED(g_class);
92 GstQtGLVideoSinkBase *self = GST_QT_GL_VIDEO_SINK_BASE(instance);
93
94 GstColorBalanceChannel *channel;
95 self->m_channels_list = NULL;
96
97 for (int i=0; i < LABEL_LAST; i++) {
98 channel = GST_COLOR_BALANCE_CHANNEL(g_object_new(GST_TYPE_COLOR_BALANCE_CHANNEL, NULL));
99 channel->label = g_strdup(s_colorbalance_labels[i]);
100 channel->min_value = -100;
101 channel->max_value = 100;
102
103 self->m_channels_list = g_list_append(self->m_channels_list, channel);
104 }
105 }
106
finalize(GObject * object)107 void GstQtGLVideoSinkBase::finalize(GObject *object)
108 {
109 GstQtGLVideoSinkBase *self = GST_QT_GL_VIDEO_SINK_BASE(object);
110
111 while (self->m_channels_list) {
112 GstColorBalanceChannel *channel = GST_COLOR_BALANCE_CHANNEL(self->m_channels_list->data);
113 g_object_unref(channel);
114 self->m_channels_list = g_list_next(self->m_channels_list);
115 }
116
117 g_list_free(self->m_channels_list);
118
119 G_OBJECT_CLASS(s_parent_class)->finalize(object);
120 }
121
122 //------------------------------
123
124
colorbalance_init(GstColorBalanceInterface * interface,gpointer data)125 void GstQtGLVideoSinkBase::colorbalance_init(GstColorBalanceInterface *interface, gpointer data)
126 {
127 Q_UNUSED(data);
128 interface->list_channels = GstQtGLVideoSinkBase::colorbalance_list_channels;
129 interface->set_value = GstQtGLVideoSinkBase::colorbalance_set_value;
130 interface->get_value = GstQtGLVideoSinkBase::colorbalance_get_value;
131 interface->get_balance_type = GstQtGLVideoSinkBase::colorbalance_get_balance_type;
132 }
133
colorbalance_list_channels(GstColorBalance * balance)134 const GList *GstQtGLVideoSinkBase::colorbalance_list_channels(GstColorBalance *balance)
135 {
136 return GST_QT_GL_VIDEO_SINK_BASE(balance)->m_channels_list;
137 }
138
colorbalance_set_value(GstColorBalance * balance,GstColorBalanceChannel * channel,gint value)139 void GstQtGLVideoSinkBase::colorbalance_set_value(GstColorBalance *balance,
140 GstColorBalanceChannel *channel, gint value)
141 {
142 GstQtVideoSinkBase *sink = GST_QT_VIDEO_SINK_BASE(balance);
143
144 if (!qstrcmp(channel->label, s_colorbalance_labels[LABEL_CONTRAST])) {
145 sink->delegate->setContrast(value);
146 } else if (!qstrcmp(channel->label, s_colorbalance_labels[LABEL_BRIGHTNESS])) {
147 sink->delegate->setBrightness(value);
148 } else if (!qstrcmp(channel->label, s_colorbalance_labels[LABEL_HUE])) {
149 sink->delegate->setHue(value);
150 } else if (!qstrcmp(channel->label, s_colorbalance_labels[LABEL_SATURATION])) {
151 sink->delegate->setSaturation(value);
152 } else {
153 GST_WARNING_OBJECT(sink, "Unknown colorbalance channel %s", channel->label);
154 }
155 }
156
colorbalance_get_value(GstColorBalance * balance,GstColorBalanceChannel * channel)157 gint GstQtGLVideoSinkBase::colorbalance_get_value(GstColorBalance *balance,
158 GstColorBalanceChannel *channel)
159 {
160 GstQtVideoSinkBase *sink = GST_QT_VIDEO_SINK_BASE(balance);
161
162 if (!qstrcmp(channel->label, s_colorbalance_labels[LABEL_CONTRAST])) {
163 return sink->delegate->contrast();
164 } else if (!qstrcmp(channel->label, s_colorbalance_labels[LABEL_BRIGHTNESS])) {
165 return sink->delegate->brightness();
166 } else if (!qstrcmp(channel->label, s_colorbalance_labels[LABEL_HUE])) {
167 return sink->delegate->hue();
168 } else if (!qstrcmp(channel->label, s_colorbalance_labels[LABEL_SATURATION])) {
169 return sink->delegate->saturation();
170 } else {
171 GST_WARNING_OBJECT(sink, "Unknown colorbalance channel %s", channel->label);
172 }
173
174 return 0;
175 }
176
colorbalance_get_balance_type(GstColorBalance * balance)177 GstColorBalanceType GstQtGLVideoSinkBase::colorbalance_get_balance_type(GstColorBalance *balance)
178 {
179 Q_UNUSED(balance);
180 return GST_COLOR_BALANCE_HARDWARE;
181 }
182
183 //------------------------------
184
set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)185 void GstQtGLVideoSinkBase::set_property(GObject *object, guint prop_id,
186 const GValue *value, GParamSpec *pspec)
187 {
188 GstQtVideoSinkBase *sink = GST_QT_VIDEO_SINK_BASE(object);
189
190 switch (prop_id) {
191 case PROP_CONTRAST:
192 sink->delegate->setContrast(g_value_get_int(value));
193 break;
194 case PROP_BRIGHTNESS:
195 sink->delegate->setBrightness(g_value_get_int(value));
196 break;
197 case PROP_HUE:
198 sink->delegate->setHue(g_value_get_int(value));
199 break;
200 case PROP_SATURATION:
201 sink->delegate->setSaturation(g_value_get_int(value));
202 break;
203 default:
204 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
205 break;
206 }
207 }
208
get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)209 void GstQtGLVideoSinkBase::get_property(GObject *object, guint prop_id,
210 GValue *value, GParamSpec *pspec)
211 {
212 GstQtVideoSinkBase *sink = GST_QT_VIDEO_SINK_BASE(object);
213
214 switch (prop_id) {
215 case PROP_CONTRAST:
216 g_value_set_int(value, sink->delegate->contrast());
217 break;
218 case PROP_BRIGHTNESS:
219 g_value_set_int(value, sink->delegate->brightness());
220 break;
221 case PROP_HUE:
222 g_value_set_int(value, sink->delegate->hue());
223 break;
224 case PROP_SATURATION:
225 g_value_set_int(value, sink->delegate->saturation());
226 break;
227 default:
228 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
229 break;
230 }
231 }
232
233 //------------------------------
234
start(GstBaseSink * base)235 gboolean GstQtGLVideoSinkBase::start(GstBaseSink *base)
236 {
237 GstQtVideoSinkBase *sink = GST_QT_VIDEO_SINK_BASE(base);
238
239 //fail on purpose if the user hasn't set a context
240 if (sink->delegate->supportedPainterTypes() == QtVideoSinkDelegate::Generic) {
241 GST_WARNING_OBJECT(sink, "Neither GLSL nor ARB Fragment Program are supported "
242 "for painting. Did you forget to set a gl context?");
243 return FALSE;
244 } else {
245 return TRUE;
246 }
247 }
248
set_caps(GstBaseSink * base,GstCaps * caps)249 gboolean GstQtGLVideoSinkBase::set_caps(GstBaseSink *base, GstCaps *caps)
250 {
251 GstQtVideoSinkBase *sink = GST_QT_VIDEO_SINK_BASE(base);
252
253 GST_LOG_OBJECT(sink, "new caps %" GST_PTR_FORMAT, caps);
254 BufferFormat format = BufferFormat::fromCaps(caps);
255 if (OpenGLSurfacePainter::supportedPixelFormats().contains(format.videoFormat())) {
256 QCoreApplication::postEvent(sink->delegate,
257 new BaseDelegate::BufferFormatEvent(format));
258 return TRUE;
259 } else {
260 return FALSE;
261 }
262 }
263