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