1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qgstreamervideooverlay_p.h" |
41 | |
42 | #include <QtGui/qguiapplication.h> |
43 | #include "qgstutils_p.h" |
44 | |
45 | #if !GST_CHECK_VERSION(1,0,0) |
46 | #include <gst/interfaces/xoverlay.h> |
47 | #else |
48 | #include <gst/video/videooverlay.h> |
49 | #endif |
50 | |
51 | #include <QtMultimedia/private/qtmultimediaglobal_p.h> |
52 | |
53 | QT_BEGIN_NAMESPACE |
54 | |
55 | struct ElementMap |
56 | { |
57 | const char *qtPlatform; |
58 | const char *gstreamerElement; |
59 | }; |
60 | |
61 | // Ordered by descending priority |
62 | static const ElementMap elementMap[] = |
63 | { |
64 | #if QT_CONFIG(gstreamer_gl) |
65 | { .qtPlatform: "xcb" , .gstreamerElement: "glimagesink" }, |
66 | #endif |
67 | { .qtPlatform: "xcb" , .gstreamerElement: "vaapisink" }, |
68 | { .qtPlatform: "xcb" , .gstreamerElement: "xvimagesink" }, |
69 | { .qtPlatform: "xcb" , .gstreamerElement: "ximagesink" } |
70 | }; |
71 | |
72 | class QGstreamerSinkProperties |
73 | { |
74 | public: |
75 | virtual ~QGstreamerSinkProperties() |
76 | { |
77 | } |
78 | |
79 | virtual bool hasShowPrerollFrame() const = 0; |
80 | virtual void reset() = 0; |
81 | virtual int brightness() const = 0; |
82 | virtual bool setBrightness(int brightness) = 0; |
83 | virtual int contrast() const = 0; |
84 | virtual bool setContrast(int contrast) = 0; |
85 | virtual int hue() const = 0; |
86 | virtual bool setHue(int hue) = 0; |
87 | virtual int saturation() const = 0; |
88 | virtual bool setSaturation(int saturation) = 0; |
89 | virtual Qt::AspectRatioMode aspectRatioMode() const = 0; |
90 | virtual void setAspectRatioMode(Qt::AspectRatioMode mode) = 0; |
91 | }; |
92 | |
93 | class QXVImageSinkProperties : public QGstreamerSinkProperties |
94 | { |
95 | public: |
96 | QXVImageSinkProperties(GstElement *sink) |
97 | : m_videoSink(sink) |
98 | { |
99 | m_hasForceAspectRatio = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), property_name: "force-aspect-ratio" ); |
100 | m_hasBrightness = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), property_name: "brightness" ); |
101 | m_hasContrast = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), property_name: "contrast" ); |
102 | m_hasHue = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), property_name: "hue" ); |
103 | m_hasSaturation = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), property_name: "saturation" ); |
104 | m_hasShowPrerollFrame = g_object_class_find_property(G_OBJECT_GET_CLASS(m_videoSink), property_name: "show-preroll-frame" ); |
105 | } |
106 | |
107 | bool hasShowPrerollFrame() const override |
108 | { |
109 | return m_hasShowPrerollFrame; |
110 | } |
111 | |
112 | void reset() override |
113 | { |
114 | setAspectRatioMode(m_aspectRatioMode); |
115 | setBrightness(m_brightness); |
116 | setContrast(m_contrast); |
117 | setHue(m_hue); |
118 | setSaturation(m_saturation); |
119 | } |
120 | |
121 | int brightness() const override |
122 | { |
123 | int brightness = 0; |
124 | if (m_hasBrightness) |
125 | g_object_get(G_OBJECT(m_videoSink), first_property_name: "brightness" , &brightness, nullptr); |
126 | |
127 | return brightness / 10; |
128 | } |
129 | |
130 | bool setBrightness(int brightness) override |
131 | { |
132 | m_brightness = brightness; |
133 | if (m_hasBrightness) |
134 | g_object_set(G_OBJECT(m_videoSink), first_property_name: "brightness" , brightness * 10, nullptr); |
135 | |
136 | return m_hasBrightness; |
137 | } |
138 | |
139 | int contrast() const override |
140 | { |
141 | int contrast = 0; |
142 | if (m_hasContrast) |
143 | g_object_get(G_OBJECT(m_videoSink), first_property_name: "contrast" , &contrast, nullptr); |
144 | |
145 | return contrast / 10; |
146 | } |
147 | |
148 | bool setContrast(int contrast) override |
149 | { |
150 | m_contrast = contrast; |
151 | if (m_hasContrast) |
152 | g_object_set(G_OBJECT(m_videoSink), first_property_name: "contrast" , contrast * 10, nullptr); |
153 | |
154 | return m_hasContrast; |
155 | } |
156 | |
157 | int hue() const override |
158 | { |
159 | int hue = 0; |
160 | if (m_hasHue) |
161 | g_object_get(G_OBJECT(m_videoSink), first_property_name: "hue" , &hue, nullptr); |
162 | |
163 | return hue / 10; |
164 | } |
165 | |
166 | bool setHue(int hue) override |
167 | { |
168 | m_hue = hue; |
169 | if (m_hasHue) |
170 | g_object_set(G_OBJECT(m_videoSink), first_property_name: "hue" , hue * 10, nullptr); |
171 | |
172 | return m_hasHue; |
173 | } |
174 | |
175 | int saturation() const override |
176 | { |
177 | int saturation = 0; |
178 | if (m_hasSaturation) |
179 | g_object_get(G_OBJECT(m_videoSink), first_property_name: "saturation" , &saturation, nullptr); |
180 | |
181 | return saturation / 10; |
182 | } |
183 | |
184 | bool setSaturation(int saturation) override |
185 | { |
186 | m_saturation = saturation; |
187 | if (m_hasSaturation) |
188 | g_object_set(G_OBJECT(m_videoSink), first_property_name: "saturation" , saturation * 10, nullptr); |
189 | |
190 | return m_hasSaturation; |
191 | } |
192 | |
193 | Qt::AspectRatioMode aspectRatioMode() const override |
194 | { |
195 | Qt::AspectRatioMode mode = Qt::KeepAspectRatio; |
196 | if (m_hasForceAspectRatio) { |
197 | gboolean forceAR = false; |
198 | g_object_get(G_OBJECT(m_videoSink), first_property_name: "force-aspect-ratio" , &forceAR, nullptr); |
199 | if (!forceAR) |
200 | mode = Qt::IgnoreAspectRatio; |
201 | } |
202 | |
203 | return mode; |
204 | } |
205 | |
206 | void setAspectRatioMode(Qt::AspectRatioMode mode) override |
207 | { |
208 | m_aspectRatioMode = mode; |
209 | if (m_hasForceAspectRatio) { |
210 | g_object_set(G_OBJECT(m_videoSink), |
211 | first_property_name: "force-aspect-ratio" , |
212 | (mode == Qt::KeepAspectRatio), |
213 | nullptr); |
214 | } |
215 | } |
216 | |
217 | protected: |
218 | |
219 | GstElement *m_videoSink = nullptr; |
220 | bool m_hasForceAspectRatio = false; |
221 | bool m_hasBrightness = false; |
222 | bool m_hasContrast = false; |
223 | bool m_hasHue = false; |
224 | bool m_hasSaturation = false; |
225 | bool m_hasShowPrerollFrame = false; |
226 | Qt::AspectRatioMode m_aspectRatioMode = Qt::KeepAspectRatio; |
227 | int m_brightness = 0; |
228 | int m_contrast = 0; |
229 | int m_hue = 0; |
230 | int m_saturation = 0; |
231 | }; |
232 | |
233 | class QVaapiSinkProperties : public QXVImageSinkProperties |
234 | { |
235 | public: |
236 | QVaapiSinkProperties(GstElement *sink) |
237 | : QXVImageSinkProperties(sink) |
238 | { |
239 | // Set default values. |
240 | m_contrast = 1; |
241 | m_saturation = 1; |
242 | } |
243 | |
244 | int brightness() const override |
245 | { |
246 | gfloat brightness = 0; |
247 | if (m_hasBrightness) |
248 | g_object_get(G_OBJECT(m_videoSink), first_property_name: "brightness" , &brightness, nullptr); |
249 | |
250 | return brightness * 100; // [-1,1] -> [-100,100] |
251 | } |
252 | |
253 | bool setBrightness(int brightness) override |
254 | { |
255 | m_brightness = brightness; |
256 | if (m_hasBrightness) { |
257 | gfloat v = brightness / 100.0; // [-100,100] -> [-1,1] |
258 | g_object_set(G_OBJECT(m_videoSink), first_property_name: "brightness" , v, nullptr); |
259 | } |
260 | |
261 | return m_hasBrightness; |
262 | } |
263 | |
264 | int contrast() const override |
265 | { |
266 | gfloat contrast = 1; |
267 | if (m_hasContrast) |
268 | g_object_get(G_OBJECT(m_videoSink), first_property_name: "contrast" , &contrast, nullptr); |
269 | |
270 | return (contrast - 1) * 100; // [0,2] -> [-100,100] |
271 | } |
272 | |
273 | bool setContrast(int contrast) override |
274 | { |
275 | m_contrast = contrast; |
276 | if (m_hasContrast) { |
277 | gfloat v = (contrast / 100.0) + 1; // [-100,100] -> [0,2] |
278 | g_object_set(G_OBJECT(m_videoSink), first_property_name: "contrast" , v, nullptr); |
279 | } |
280 | |
281 | return m_hasContrast; |
282 | } |
283 | |
284 | int hue() const override |
285 | { |
286 | gfloat hue = 0; |
287 | if (m_hasHue) |
288 | g_object_get(G_OBJECT(m_videoSink), first_property_name: "hue" , &hue, nullptr); |
289 | |
290 | return hue / 180 * 100; // [-180,180] -> [-100,100] |
291 | } |
292 | |
293 | bool setHue(int hue) override |
294 | { |
295 | m_hue = hue; |
296 | if (m_hasHue) { |
297 | gfloat v = hue / 100.0 * 180; // [-100,100] -> [-180,180] |
298 | g_object_set(G_OBJECT(m_videoSink), first_property_name: "hue" , v, nullptr); |
299 | } |
300 | |
301 | return m_hasHue; |
302 | } |
303 | |
304 | int saturation() const override |
305 | { |
306 | gfloat saturation = 1; |
307 | if (m_hasSaturation) |
308 | g_object_get(G_OBJECT(m_videoSink), first_property_name: "saturation" , &saturation, nullptr); |
309 | |
310 | return (saturation - 1) * 100; // [0,2] -> [-100,100] |
311 | } |
312 | |
313 | bool setSaturation(int saturation) override |
314 | { |
315 | m_saturation = saturation; |
316 | if (m_hasSaturation) { |
317 | gfloat v = (saturation / 100.0) + 1; // [-100,100] -> [0,2] |
318 | g_object_set(G_OBJECT(m_videoSink), first_property_name: "saturation" , v, nullptr); |
319 | } |
320 | |
321 | return m_hasSaturation; |
322 | } |
323 | }; |
324 | |
325 | static bool qt_gst_element_is_functioning(GstElement *element) |
326 | { |
327 | GstStateChangeReturn ret = gst_element_set_state(element, state: GST_STATE_READY); |
328 | if (ret == GST_STATE_CHANGE_SUCCESS) { |
329 | gst_element_set_state(element, state: GST_STATE_NULL); |
330 | return true; |
331 | } |
332 | |
333 | return false; |
334 | } |
335 | |
336 | static GstElement *findBestVideoSink() |
337 | { |
338 | GstElement *choice = 0; |
339 | QString platform = QGuiApplication::platformName(); |
340 | |
341 | // We need a native window ID to use the GstVideoOverlay interface. |
342 | // Bail out if the Qt platform plugin in use cannot provide a sensible WId. |
343 | if (platform != QLatin1String("xcb" )) |
344 | return 0; |
345 | |
346 | // First, try some known video sinks, depending on the Qt platform plugin in use. |
347 | for (quint32 i = 0; i < (sizeof(elementMap) / sizeof(ElementMap)); ++i) { |
348 | #if QT_CONFIG(gstreamer_gl) |
349 | if (!QGstUtils::useOpenGL() && qstrcmp(str1: elementMap[i].gstreamerElement, str2: "glimagesink" ) == 0) |
350 | continue; |
351 | #endif |
352 | if (platform == QLatin1String(elementMap[i].qtPlatform) |
353 | && (choice = gst_element_factory_make(factoryname: elementMap[i].gstreamerElement, name: nullptr))) { |
354 | |
355 | if (qt_gst_element_is_functioning(element: choice)) |
356 | return choice; |
357 | |
358 | gst_object_unref(object: choice); |
359 | choice = 0; |
360 | } |
361 | } |
362 | |
363 | // If none of the known video sinks are available, try to find one that implements the |
364 | // GstVideoOverlay interface and has autoplugging rank. |
365 | GList *list = qt_gst_video_sinks(); |
366 | for (GList *item = list; item != nullptr; item = item->next) { |
367 | GstElementFactory *f = GST_ELEMENT_FACTORY(item->data); |
368 | |
369 | if (!gst_element_factory_has_interface(factory: f, QT_GSTREAMER_VIDEOOVERLAY_INTERFACE_NAME)) |
370 | continue; |
371 | |
372 | if (GstElement *el = gst_element_factory_create(factory: f, name: nullptr)) { |
373 | if (qt_gst_element_is_functioning(element: el)) { |
374 | choice = el; |
375 | break; |
376 | } |
377 | |
378 | gst_object_unref(object: el); |
379 | } |
380 | } |
381 | |
382 | gst_plugin_feature_list_free(list); |
383 | |
384 | return choice; |
385 | } |
386 | |
387 | QGstreamerVideoOverlay::QGstreamerVideoOverlay(QObject *parent, const QByteArray &elementName) |
388 | : QObject(parent) |
389 | , QGstreamerBufferProbe(QGstreamerBufferProbe::ProbeCaps) |
390 | { |
391 | GstElement *sink = nullptr; |
392 | if (!elementName.isEmpty()) |
393 | sink = gst_element_factory_make(factoryname: elementName.constData(), name: nullptr); |
394 | else |
395 | sink = findBestVideoSink(); |
396 | |
397 | setVideoSink(sink); |
398 | } |
399 | |
400 | QGstreamerVideoOverlay::~QGstreamerVideoOverlay() |
401 | { |
402 | if (m_videoSink) { |
403 | delete m_sinkProperties; |
404 | GstPad *pad = gst_element_get_static_pad(element: m_videoSink, name: "sink" ); |
405 | removeProbeFromPad(pad); |
406 | gst_object_unref(GST_OBJECT(pad)); |
407 | gst_object_unref(GST_OBJECT(m_videoSink)); |
408 | } |
409 | } |
410 | |
411 | GstElement *QGstreamerVideoOverlay::videoSink() const |
412 | { |
413 | return m_videoSink; |
414 | } |
415 | |
416 | void QGstreamerVideoOverlay::setVideoSink(GstElement *sink) |
417 | { |
418 | if (!sink) |
419 | return; |
420 | |
421 | if (m_videoSink) |
422 | gst_object_unref(GST_OBJECT(m_videoSink)); |
423 | |
424 | m_videoSink = sink; |
425 | qt_gst_object_ref_sink(GST_OBJECT(m_videoSink)); |
426 | |
427 | GstPad *pad = gst_element_get_static_pad(element: m_videoSink, name: "sink" ); |
428 | addProbeToPad(pad); |
429 | gst_object_unref(GST_OBJECT(pad)); |
430 | |
431 | QString sinkName(QLatin1String(GST_OBJECT_NAME(sink))); |
432 | bool isVaapi = sinkName.startsWith(s: QLatin1String("vaapisink" )); |
433 | delete m_sinkProperties; |
434 | m_sinkProperties = isVaapi ? new QVaapiSinkProperties(sink) : new QXVImageSinkProperties(sink); |
435 | |
436 | if (m_sinkProperties->hasShowPrerollFrame()) |
437 | g_signal_connect(m_videoSink, "notify::show-preroll-frame" , |
438 | G_CALLBACK(showPrerollFrameChanged), this); |
439 | } |
440 | |
441 | QSize QGstreamerVideoOverlay::nativeVideoSize() const |
442 | { |
443 | return m_nativeVideoSize; |
444 | } |
445 | |
446 | void QGstreamerVideoOverlay::setWindowHandle(WId id) |
447 | { |
448 | m_windowId = id; |
449 | |
450 | if (isActive()) |
451 | setWindowHandle_helper(id); |
452 | } |
453 | |
454 | void QGstreamerVideoOverlay::setWindowHandle_helper(WId id) |
455 | { |
456 | #if GST_CHECK_VERSION(1,0,0) |
457 | if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) { |
458 | gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(m_videoSink), handle: id); |
459 | #else |
460 | if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) { |
461 | # if GST_CHECK_VERSION(0,10,31) |
462 | gst_x_overlay_set_window_handle(GST_X_OVERLAY(m_videoSink), id); |
463 | # else |
464 | gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(m_videoSink), id); |
465 | # endif |
466 | #endif |
467 | |
468 | // Properties need to be reset when changing the winId. |
469 | m_sinkProperties->reset(); |
470 | } |
471 | } |
472 | |
473 | void QGstreamerVideoOverlay::expose() |
474 | { |
475 | if (!isActive()) |
476 | return; |
477 | |
478 | #if !GST_CHECK_VERSION(1,0,0) |
479 | if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) |
480 | gst_x_overlay_expose(GST_X_OVERLAY(m_videoSink)); |
481 | #else |
482 | if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) { |
483 | gst_video_overlay_expose(GST_VIDEO_OVERLAY(m_videoSink)); |
484 | } |
485 | #endif |
486 | } |
487 | |
488 | void QGstreamerVideoOverlay::setRenderRectangle(const QRect &rect) |
489 | { |
490 | int x = -1; |
491 | int y = -1; |
492 | int w = -1; |
493 | int h = -1; |
494 | |
495 | if (!rect.isEmpty()) { |
496 | x = rect.x(); |
497 | y = rect.y(); |
498 | w = rect.width(); |
499 | h = rect.height(); |
500 | } |
501 | |
502 | #if GST_CHECK_VERSION(1,0,0) |
503 | if (m_videoSink && GST_IS_VIDEO_OVERLAY(m_videoSink)) |
504 | gst_video_overlay_set_render_rectangle(GST_VIDEO_OVERLAY(m_videoSink), x, y, width: w, height: h); |
505 | #elif GST_CHECK_VERSION(0, 10, 29) |
506 | if (m_videoSink && GST_IS_X_OVERLAY(m_videoSink)) |
507 | gst_x_overlay_set_render_rectangle(GST_X_OVERLAY(m_videoSink), x, y , w , h); |
508 | #else |
509 | Q_UNUSED(x) |
510 | Q_UNUSED(y) |
511 | Q_UNUSED(w) |
512 | Q_UNUSED(h) |
513 | #endif |
514 | } |
515 | |
516 | bool QGstreamerVideoOverlay::processSyncMessage(const QGstreamerMessage &message) |
517 | { |
518 | GstMessage* gm = message.rawMessage(); |
519 | |
520 | #if !GST_CHECK_VERSION(1,0,0) |
521 | if (gm && (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) && |
522 | gst_structure_has_name(gm->structure, "prepare-xwindow-id" )) { |
523 | #else |
524 | if (gm && (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_ELEMENT) && |
525 | gst_structure_has_name(structure: gst_message_get_structure(message: gm), name: "prepare-window-handle" )) { |
526 | #endif |
527 | setWindowHandle_helper(m_windowId); |
528 | return true; |
529 | } |
530 | |
531 | return false; |
532 | } |
533 | |
534 | bool QGstreamerVideoOverlay::processBusMessage(const QGstreamerMessage &message) |
535 | { |
536 | GstMessage* gm = message.rawMessage(); |
537 | |
538 | if (GST_MESSAGE_TYPE(gm) == GST_MESSAGE_STATE_CHANGED && |
539 | GST_MESSAGE_SRC(gm) == GST_OBJECT_CAST(m_videoSink)) { |
540 | |
541 | updateIsActive(); |
542 | } |
543 | |
544 | return false; |
545 | } |
546 | |
547 | void QGstreamerVideoOverlay::probeCaps(GstCaps *caps) |
548 | { |
549 | QSize size = QGstUtils::capsCorrectedResolution(caps); |
550 | if (size != m_nativeVideoSize) { |
551 | m_nativeVideoSize = size; |
552 | emit nativeVideoSizeChanged(); |
553 | } |
554 | } |
555 | |
556 | bool QGstreamerVideoOverlay::isActive() const |
557 | { |
558 | return m_isActive; |
559 | } |
560 | |
561 | void QGstreamerVideoOverlay::updateIsActive() |
562 | { |
563 | if (!m_videoSink) |
564 | return; |
565 | |
566 | GstState state = GST_STATE(m_videoSink); |
567 | gboolean showPreroll = true; |
568 | |
569 | if (m_sinkProperties->hasShowPrerollFrame()) |
570 | g_object_get(G_OBJECT(m_videoSink), first_property_name: "show-preroll-frame" , &showPreroll, nullptr); |
571 | |
572 | bool newIsActive = (state == GST_STATE_PLAYING || (state == GST_STATE_PAUSED && showPreroll)); |
573 | |
574 | if (newIsActive != m_isActive) { |
575 | m_isActive = newIsActive; |
576 | emit activeChanged(); |
577 | } |
578 | } |
579 | |
580 | void QGstreamerVideoOverlay::showPrerollFrameChanged(GObject *, GParamSpec *, QGstreamerVideoOverlay *overlay) |
581 | { |
582 | overlay->updateIsActive(); |
583 | } |
584 | |
585 | Qt::AspectRatioMode QGstreamerVideoOverlay::aspectRatioMode() const |
586 | { |
587 | return m_sinkProperties->aspectRatioMode(); |
588 | } |
589 | |
590 | void QGstreamerVideoOverlay::setAspectRatioMode(Qt::AspectRatioMode mode) |
591 | { |
592 | m_sinkProperties->setAspectRatioMode(mode); |
593 | } |
594 | |
595 | int QGstreamerVideoOverlay::brightness() const |
596 | { |
597 | return m_sinkProperties->brightness(); |
598 | } |
599 | |
600 | void QGstreamerVideoOverlay::setBrightness(int brightness) |
601 | { |
602 | if (m_sinkProperties->setBrightness(brightness)) |
603 | emit brightnessChanged(brightness); |
604 | } |
605 | |
606 | int QGstreamerVideoOverlay::contrast() const |
607 | { |
608 | return m_sinkProperties->contrast(); |
609 | } |
610 | |
611 | void QGstreamerVideoOverlay::setContrast(int contrast) |
612 | { |
613 | if (m_sinkProperties->setContrast(contrast)) |
614 | emit contrastChanged(contrast); |
615 | } |
616 | |
617 | int QGstreamerVideoOverlay::hue() const |
618 | { |
619 | return m_sinkProperties->hue(); |
620 | } |
621 | |
622 | void QGstreamerVideoOverlay::setHue(int hue) |
623 | { |
624 | if (m_sinkProperties->setHue(hue)) |
625 | emit hueChanged(hue); |
626 | } |
627 | |
628 | int QGstreamerVideoOverlay::saturation() const |
629 | { |
630 | return m_sinkProperties->saturation(); |
631 | } |
632 | |
633 | void QGstreamerVideoOverlay::setSaturation(int saturation) |
634 | { |
635 | if (m_sinkProperties->setSaturation(saturation)) |
636 | emit saturationChanged(saturation); |
637 | } |
638 | |
639 | QT_END_NAMESPACE |
640 | |