26
27
#include <gst/gst.h>
27
28
#include <gst/interfaces/navigation.h>
28
29
#include <gst/interfaces/propertyprobe.h>
30
#include <gst/video/video.h>
29
31
#include "abstractrenderer.h"
30
32
#include "backend.h"
31
33
#include "devicemanager.h"
32
34
#include "mediaobject.h"
35
#include "x11renderer.h"
34
37
#include "widgetrenderer.h"
77
void VideoWidget::updateWindowID()
79
X11Renderer *render = dynamic_cast<X11Renderer*>(m_renderer);
84
void VideoWidget::finalizeLink()
86
connect(root()->pipeline(), SIGNAL(mouseOverActive(bool)), this, SLOT(mouseOverActive(bool)));
87
connect(root()->pipeline(), SIGNAL(windowIDNeeded()), this, SLOT(updateWindowID()));
90
void VideoWidget::prepareToUnlink()
92
disconnect(root()->pipeline());
75
95
void VideoWidget::setupVideoBin()
78
98
m_renderer = m_backend->deviceManager()->createVideoRenderer(this);
79
99
GstElement *videoSink = m_renderer->videoSink();
100
GstPad *videoPad = gst_element_get_static_pad(videoSink, "sink");
101
g_signal_connect(videoPad, "notify::caps", G_CALLBACK(cb_capsChanged), this);
81
103
m_videoBin = gst_bin_new (NULL);
82
104
Q_ASSERT(m_videoBin);
99
121
if (queue && m_videoBin && videoScale && m_colorspace && videoSink && m_videoplug) {
100
122
//Ensure that the bare essentials are prepared
101
gst_bin_add_many (GST_BIN (m_videoBin), queue, m_colorspace, m_videoplug, videoScale, videoSink, (const char*)NULL);
123
gst_bin_add_many (GST_BIN (m_videoBin), queue, m_colorspace, m_videoplug, videoScale, videoSink, NULL);
102
124
bool success = false;
103
125
//Video balance controls color/sat/hue in the YUV colorspace
104
126
m_videoBalance = gst_element_factory_make ("videobalance", NULL);
107
129
// then hand it off to the videobalance filter before finally converting it back to RGB.
108
130
// Hence we nede a videoFilter to convert the colorspace before and after videobalance
109
131
GstElement *m_colorspace2 = gst_element_factory_make ("ffmpegcolorspace", NULL);
110
gst_bin_add_many(GST_BIN(m_videoBin), m_videoBalance, m_colorspace2, (const char*)NULL);
111
success = gst_element_link_many(queue, m_colorspace, m_videoBalance, m_colorspace2, videoScale, m_videoplug, videoSink, (const char*)NULL);
132
gst_bin_add_many(GST_BIN(m_videoBin), m_videoBalance, m_colorspace2, NULL);
133
success = gst_element_link_many(queue, m_colorspace, m_videoBalance, m_colorspace2, videoScale, m_videoplug, videoSink, NULL);
113
135
//If video balance is not available, just connect to sink directly
114
success = gst_element_link_many(queue, m_colorspace, videoScale, m_videoplug, videoSink, (const char*)NULL);
136
success = gst_element_link_many(queue, m_colorspace, videoScale, m_videoplug, videoSink, NULL);
117
GstPad *videopad = gst_element_get_pad (queue, "sink");
139
GstPad *videopad = gst_element_get_static_pad (queue, "sink");
118
140
gst_element_add_pad (m_videoBin, gst_ghost_pad_new ("sink", videopad));
119
141
gst_object_unref (videopad);
120
142
QWidget *parentWidget = qobject_cast<QWidget*>(parent());
128
150
gst_bin_add_many (GST_BIN (m_videoBin), videoSink, NULL);
129
GstPad *videopad = gst_element_get_pad (videoSink,"sink");
151
GstPad *videopad = gst_element_get_static_pad (videoSink,"sink");
130
152
gst_element_add_pad (m_videoBin, gst_ghost_pad_new ("sink", videopad));
131
153
gst_object_unref (videopad);
132
154
QWidget *parentWidget = qobject_cast<QWidget*>(parent());
160
182
// Use widgetRenderer as a fallback
161
183
m_renderer = new WidgetRenderer(this);
162
184
videoSink = m_renderer->videoSink();
185
GstPad *videoPad = gst_element_get_static_pad(videoSink, "sink");
186
g_signal_connect(videoPad, "notify::caps", G_CALLBACK(cb_capsChanged), this);
163
187
gst_bin_add(GST_BIN(m_videoBin), videoSink);
164
188
gst_element_link(m_videoplug, videoSink);
165
189
gst_element_set_state (videoSink, GST_STATE_PAUSED);
167
// Request return to current state
168
root()->invalidateGraph();
169
root()->setState(root()->state());
171
192
QWidget::setVisible(val);
307
328
QByteArray tegraEnv = qgetenv("TEGRA_GST_OPENMAX");
308
329
if (tegraEnv.isEmpty()) {
309
330
if (m_videoBalance)
310
g_object_set(G_OBJECT(m_videoBalance), "brightness", newValue, (const char*)NULL); //gstreamer range is [-1, 1]
331
g_object_set(G_OBJECT(m_videoBalance), "brightness", newValue, NULL); //gstreamer range is [-1, 1]
313
g_object_set(G_OBJECT(videoSink), "brightness", newValue, (const char*)NULL); //gstreamer range is [-1, 1]
334
g_object_set(G_OBJECT(videoSink), "brightness", newValue, NULL); //gstreamer range is [-1, 1]
335
356
if (tegraEnv.isEmpty()) {
336
357
if (m_videoBalance)
337
g_object_set(G_OBJECT(m_videoBalance), "contrast", (newValue + 1.0), (const char*)NULL); //gstreamer range is [0-2]
358
g_object_set(G_OBJECT(m_videoBalance), "contrast", (newValue + 1.0), NULL); //gstreamer range is [0-2]
340
g_object_set(G_OBJECT(videoSink), "contrast", (newValue + 1.0), (const char*)NULL); //gstreamer range is [0-2]
361
g_object_set(G_OBJECT(videoSink), "contrast", (newValue + 1.0), NULL); //gstreamer range is [0-2]
356
377
m_hue = newValue;
358
379
if (m_videoBalance)
359
g_object_set(G_OBJECT(m_videoBalance), "hue", newValue, (const char*)NULL); //gstreamer range is [-1, 1]
380
g_object_set(G_OBJECT(m_videoBalance), "hue", newValue, NULL); //gstreamer range is [-1, 1]
362
383
qreal VideoWidget::saturation() const
379
400
QByteArray tegraEnv = qgetenv("TEGRA_GST_OPENMAX");
380
401
if (tegraEnv.isEmpty()) {
381
402
if (m_videoBalance)
382
g_object_set(G_OBJECT(m_videoBalance), "saturation", newValue + 1.0, (const char*)NULL); //gstreamer range is [0, 2]
403
g_object_set(G_OBJECT(m_videoBalance), "saturation", newValue + 1.0, NULL); //gstreamer range is [0, 2]
385
g_object_set(G_OBJECT(videoSink), "saturation", newValue + 1.0, (const char*)NULL); //gstreamer range is [0, 2]
406
g_object_set(G_OBJECT(videoSink), "saturation", newValue + 1.0, NULL); //gstreamer range is [0, 2]
400
421
m_renderer->movieSizeChanged(m_movieSize);
403
void VideoWidget::mediaNodeEvent(const MediaNodeEvent *event)
405
switch (event->type()) {
406
case MediaNodeEvent::VideoSizeChanged: {
407
const QSize *size = static_cast<const QSize*>(event->data());
411
case MediaNodeEvent::VideoMouseOver: {
412
const gboolean active = *static_cast<const gboolean*>(event->data());
414
setCursor(Qt::PointingHandCursor);
416
setCursor(Qt::ArrowCursor);
424
// Forward events to renderer
426
m_renderer->handleMediaNodeEvent(event);
429
424
void VideoWidget::keyPressEvent(QKeyEvent *event)
431
426
GstElement *videosink = m_renderer->videoSink();
502
497
QWidget::mouseReleaseEvent(event);
500
void VideoWidget::cb_capsChanged(GstPad *pad, GParamSpec *spec, gpointer data)
503
//TODO: Original code disconnected the signal until source was changed again. Is that needed?
504
//Also, it used a signal ID, which isn't needed since we can just disconnect based on the data
505
//value (see Pipeline destructor for example)
506
//g_signal_handler_disconnect(pad, media->capsHandler());
507
VideoWidget *that = static_cast<VideoWidget*>(data);
508
if (!GST_PAD_IS_LINKED(pad))
511
gst_element_get_state(that->videoElement(), &videoState, NULL, 1000);
515
//FIXME: This sometimes gives a gstreamer warning. Feels like GStreamer shouldn't, and instead
516
//just quietly return false, probably a bug.
517
if (gst_video_get_size(pad, &width, &height)) {
518
QMetaObject::invokeMethod(that, "setMovieSize", Q_ARG(QSize, QSize(width, height)));
522
void VideoWidget::mouseOverActive(bool active)
525
setCursor(Qt::PointingHandCursor);
527
setCursor(Qt::ArrowCursor);
506
531
} //namespace Phonon::Gstreamer