diff options
Diffstat (limited to 'src')
9 files changed, 86 insertions, 44 deletions
diff --git a/src/gsttools/qgstreamerplayersession.cpp b/src/gsttools/qgstreamerplayersession.cpp index 485556275..bd402fb3c 100644 --- a/src/gsttools/qgstreamerplayersession.cpp +++ b/src/gsttools/qgstreamerplayersession.cpp @@ -272,33 +272,6 @@ GstElement *QGstreamerPlayerSession::playbin() const return m_playbin; } -void QGstreamerPlayerSession::setPipeline(GstElement *pipeline) -{ - GstBus *bus = pipeline ? gst_element_get_bus(pipeline) : nullptr; - if (!bus) - return; - - gst_object_unref(GST_OBJECT(m_pipeline)); - m_pipeline = pipeline; - gst_object_unref(GST_OBJECT(m_bus)); - m_bus = bus; - delete m_busHelper; - m_busHelper = new QGstreamerBusHelper(m_bus, this); - m_busHelper->installMessageFilter(this); - - if (m_videoOutput) - m_busHelper->installMessageFilter(m_videoOutput); - - if (m_playbin) { - gst_element_set_state(m_playbin, GST_STATE_NULL); - gst_object_unref(GST_OBJECT(m_playbin)); - } - - m_playbin = nullptr; - m_volumeElement = nullptr; - m_videoIdentity = nullptr; -} - #if QT_CONFIG(gstreamer_app) void QGstreamerPlayerSession::configureAppSrcElement(GObject* object, GObject *orig, GParamSpec *pspec, QGstreamerPlayerSession* self) { @@ -364,6 +337,22 @@ void QGstreamerPlayerSession::loadFromUri(const QNetworkRequest &request) } #endif + if (m_request.url().scheme() == QLatin1String("gst-pipeline")) { + QString url = m_request.url().toString(QUrl::RemoveScheme); + QString pipeline = QUrl::fromPercentEncoding(url.toLatin1().constData()); + GError *err = nullptr; + GstElement *element = gst_parse_launch(pipeline.toLatin1().constData(), &err); + if (err) { + auto errstr = QLatin1String(err->message); + qWarning() << "Error:" << pipeline << ":" << errstr; + emit error(QMediaPlayer::FormatError, errstr); + g_clear_error(&err); + } + + setPipeline(element); + return; + } + if (m_playbin) { m_tags.clear(); emit tagsChanged(); @@ -379,6 +368,48 @@ void QGstreamerPlayerSession::loadFromUri(const QNetworkRequest &request) } } +void QGstreamerPlayerSession::setPipeline(GstElement *pipeline) +{ + GstBus *bus = pipeline ? gst_element_get_bus(pipeline) : nullptr; + if (!bus) + return; + + gst_object_unref(GST_OBJECT(m_pipeline)); + m_pipeline = pipeline; + gst_object_unref(GST_OBJECT(m_bus)); + m_bus = bus; + delete m_busHelper; + m_busHelper = new QGstreamerBusHelper(m_bus, this); + m_busHelper->installMessageFilter(this); + + if (m_videoOutput) + m_busHelper->installMessageFilter(m_videoOutput); + + if (m_playbin) { + gst_element_set_state(m_playbin, GST_STATE_NULL); + gst_object_unref(GST_OBJECT(m_playbin)); + } + + m_playbin = nullptr; + m_volumeElement = nullptr; + m_videoIdentity = nullptr; + + if (m_renderer) { + auto it = gst_bin_iterate_sinks(GST_BIN(pipeline)); + GValue data = { 0, 0 }; + while (gst_iterator_next (it, &data) == GST_ITERATOR_OK) { + auto child = static_cast<GstElement*>(g_value_get_object(&data)); + if (QLatin1String(GST_OBJECT_NAME(child)) == QLatin1String("qtvideosink")) { + m_renderer->setVideoSink(child); + break; + } + } + gst_iterator_free(it); + } + + emit pipelineChanged(); +} + qint64 QGstreamerPlayerSession::duration() const { return m_duration; @@ -581,9 +612,6 @@ void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput) QGstreamerVideoRendererInterface* renderer = qobject_cast<QGstreamerVideoRendererInterface*>(videoOutput); m_renderer = renderer; - - // If custom pipeline is considered to use video sink from the renderer - // need to create the pipeline when the renderer is ready. emit rendererChanged(); // No sense to continue if custom pipeline requested. diff --git a/src/gsttools/qgstreamerplayersession_p.h b/src/gsttools/qgstreamerplayersession_p.h index 447b9816a..b613793c4 100644 --- a/src/gsttools/qgstreamerplayersession_p.h +++ b/src/gsttools/qgstreamerplayersession_p.h @@ -94,7 +94,6 @@ public: virtual ~QGstreamerPlayerSession(); GstElement *playbin() const; - void setPipeline(GstElement *pipeline); GstElement *pipeline() const { return m_pipeline; } QGstreamerBusHelper *bus() const { return m_busHelper; } @@ -178,6 +177,7 @@ signals: void invalidMedia(); void playbackRateChanged(qreal); void rendererChanged(); + void pipelineChanged(); private slots: void getStreamsInfo(); @@ -208,6 +208,7 @@ private: void addAudioBufferProbe(); void flushVideoProbes(); void resumeVideoProbes(); + void setPipeline(GstElement *pipeline); QNetworkRequest m_request; QMediaPlayer::State m_state; diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp index eeaf70982..083ceff24 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.cpp +++ b/src/plugins/android/src/common/qandroidvideooutput.cpp @@ -82,6 +82,10 @@ void OpenGLResourcesDeleter::deleteShaderProgramHelper(void *prog) delete reinterpret_cast<QOpenGLShaderProgram *>(prog); } +void OpenGLResourcesDeleter::deleteThisHelper() +{ + delete this; +} class AndroidTextureVideoBuffer : public QAbstractVideoBuffer { @@ -170,6 +174,7 @@ QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent) , m_externalTex(0) , m_fbo(0) , m_program(0) + , m_glDeleter(0) , m_surfaceTextureCanAttachToContext(QtAndroidPrivate::androidSdkVersion() >= 16) { @@ -179,11 +184,11 @@ QAndroidTextureVideoOutput::~QAndroidTextureVideoOutput() { clearSurfaceTexture(); - if (!m_glDeleter.isNull()) { // Make sure all of these are deleted on the render thread. + if (m_glDeleter) { // Make sure all of these are deleted on the render thread. m_glDeleter->deleteFbo(m_fbo); m_glDeleter->deleteShaderProgram(m_program); m_glDeleter->deleteTexture(m_externalTex); - m_glDeleter->deleteLater(); + m_glDeleter->deleteThis(); } } @@ -231,7 +236,8 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture() // for the GL render thread to call us back to do it. if (QOpenGLContext::currentContext()) { glGenTextures(1, &m_externalTex); - m_glDeleter.reset(new OpenGLResourcesDeleter); + if (!m_glDeleter) + m_glDeleter = new OpenGLResourcesDeleter; } else if (!m_externalTex) { return false; } @@ -246,7 +252,7 @@ bool QAndroidTextureVideoOutput::initSurfaceTexture() } else { delete m_surfaceTexture; m_surfaceTexture = 0; - if (!m_glDeleter.isNull()) + if (m_glDeleter) m_glDeleter->deleteTexture(m_externalTex); m_externalTex = 0; } @@ -267,7 +273,7 @@ void QAndroidTextureVideoOutput::clearSurfaceTexture() // only if detachFromGLContext() called (API level >= 16), so we'll do it manually, // on the render thread. if (m_surfaceTextureCanAttachToContext) { - if (!m_glDeleter.isNull()) + if (m_glDeleter) m_glDeleter->deleteTexture(m_externalTex); m_externalTex = 0; } @@ -401,7 +407,7 @@ void QAndroidTextureVideoOutput::createGLResources() Q_ASSERT(QOpenGLContext::currentContext() != NULL); if (!m_glDeleter) - m_glDeleter.reset(new OpenGLResourcesDeleter); + m_glDeleter = new OpenGLResourcesDeleter; if (m_surfaceTextureCanAttachToContext && !m_externalTex) { m_surfaceTexture->detachFromGLContext(); @@ -451,7 +457,8 @@ void QAndroidTextureVideoOutput::customEvent(QEvent *e) // This is running in the render thread (OpenGL enabled) if (!m_surfaceTextureCanAttachToContext && !m_externalTex) { glGenTextures(1, &m_externalTex); - m_glDeleter.reset(new OpenGLResourcesDeleter); // We'll use this to cleanup GL resources in the correct thread + if (!m_glDeleter) // We'll use this to cleanup GL resources in the correct thread + m_glDeleter = new OpenGLResourcesDeleter; emit readyChanged(true); } } diff --git a/src/plugins/android/src/common/qandroidvideooutput.h b/src/plugins/android/src/common/qandroidvideooutput.h index 62a936881..2a35247e9 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.h +++ b/src/plugins/android/src/common/qandroidvideooutput.h @@ -81,11 +81,13 @@ public: void deleteTexture(quint32 id) { QMetaObject::invokeMethod(this, "deleteTextureHelper", Qt::AutoConnection, Q_ARG(quint32, id)); } void deleteFbo(QOpenGLFramebufferObject *fbo) { QMetaObject::invokeMethod(this, "deleteFboHelper", Qt::AutoConnection, Q_ARG(void *, fbo)); } void deleteShaderProgram(QOpenGLShaderProgram *prog) { QMetaObject::invokeMethod(this, "deleteShaderProgramHelper", Qt::AutoConnection, Q_ARG(void *, prog)); } + void deleteThis() { QMetaObject::invokeMethod(this, "deleteThisHelper"); } private: Q_INVOKABLE void deleteTextureHelper(quint32 id); Q_INVOKABLE void deleteFboHelper(void *fbo); Q_INVOKABLE void deleteShaderProgramHelper(void *prog); + Q_INVOKABLE void deleteThisHelper(); }; class QAndroidTextureVideoOutput : public QAndroidVideoOutput @@ -126,7 +128,7 @@ private: quint32 m_externalTex; QOpenGLFramebufferObject *m_fbo; QOpenGLShaderProgram *m_program; - QScopedPointer<OpenGLResourcesDeleter, QScopedPointerDeleteLater> m_glDeleter; + OpenGLResourcesDeleter *m_glDeleter; bool m_surfaceTextureCanAttachToContext; diff --git a/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp b/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp index 43cd5a2b2..8e4ea01a1 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_yuv.cpp @@ -388,8 +388,8 @@ void QSGVideoMaterial_YUV::bind() // In YUYV texture the UV plane appears with the 1/2 of image and Y width. m_planeWidth[1] = fw / 2; functions->glActiveTexture(GL_TEXTURE1); - // Either r,b (YUYV) or g,a (UYVY) values are used as source of YV. - // Additionally Y and V are set per 2 pixels hence only 1/2 of image with is used. + // Either r,b (YUYV) or g,a (UYVY) values are used as source of UV. + // Additionally U and V are set per 2 pixels hence only 1/2 of image width is used. // Interpreting this properly in shaders allows to not copy or not make conditionals inside shaders, // only interpretation of data changes. bindTexture(m_textureIds[1], m_planeWidth[1], m_frame.height(), m_frame.bits(), GL_RGBA); diff --git a/src/qtmultimediaquicktools/shaders/uyvyvideo.frag b/src/qtmultimediaquicktools/shaders/uyvyvideo.frag index 5c62441c2..244464e73 100644 --- a/src/qtmultimediaquicktools/shaders/uyvyvideo.frag +++ b/src/qtmultimediaquicktools/shaders/uyvyvideo.frag @@ -1,3 +1,4 @@ +// Reference: qgsvideonode_yuv.cpp:387 to 398 uniform sampler2D yTexture; // Y component passed as GL_LUMINANCE_ALPHA, in uyvy Y = a uniform sampler2D uvTexture; // UV component passed as RGBA macropixel, in uyvy U = r, V = b uniform mediump mat4 colorMatrix; diff --git a/src/qtmultimediaquicktools/shaders/uyvyvideo_core.frag b/src/qtmultimediaquicktools/shaders/uyvyvideo_core.frag index 75c7de5a6..b151a7c7f 100644 --- a/src/qtmultimediaquicktools/shaders/uyvyvideo_core.frag +++ b/src/qtmultimediaquicktools/shaders/uyvyvideo_core.frag @@ -1,5 +1,6 @@ #version 150 core -uniform sampler2D yTexture; // Y component passed as GL_LUMINANCE_ALPHA, in uyvy Y = a +// Reference: qgsvideonode_yuv.cpp:387 to 398 +uniform sampler2D yTexture; // Y component passed as GL_RG, in uyvy Y = a uniform sampler2D uvTexture; // UV component passed as RGBA macropixel, in uyvy U = r, V = b uniform mat4 colorMatrix; uniform float opacity; diff --git a/src/qtmultimediaquicktools/shaders/yuyvvideo.frag b/src/qtmultimediaquicktools/shaders/yuyvvideo.frag index 5ce8b7366..c2ad65b78 100644 --- a/src/qtmultimediaquicktools/shaders/yuyvvideo.frag +++ b/src/qtmultimediaquicktools/shaders/yuyvvideo.frag @@ -1,5 +1,6 @@ +// Reference: qgsvideonode_yuv.cpp:387 to 398 uniform sampler2D yTexture; // Y component passed as GL_LUMINANCE_ALPHA, in yuyv Y = r -uniform sampler2D uvTexture; // UV component passed as RGBA macropixel, in uyvy U = g, V = a +uniform sampler2D uvTexture; // UV component passed as RGBA macropixel, in yuyv U = g, V = a uniform mediump mat4 colorMatrix; uniform lowp float opacity; varying highp vec2 qt_TexCoord; diff --git a/src/qtmultimediaquicktools/shaders/yuyvvideo_core.frag b/src/qtmultimediaquicktools/shaders/yuyvvideo_core.frag index 010c4a5f2..a30d7818a 100644 --- a/src/qtmultimediaquicktools/shaders/yuyvvideo_core.frag +++ b/src/qtmultimediaquicktools/shaders/yuyvvideo_core.frag @@ -1,5 +1,6 @@ #version 150 core -uniform sampler2D yTexture; // Y component passed as GL_LUMINANCE_ALPHA, in yuyv Y = r +// Reference: qgsvideonode_yuv.cpp:387 to 398 +uniform sampler2D yTexture; // Y component passed as GL_RG, in yuyv Y = r uniform sampler2D uvTexture; // UV component passed as RGBA macropixel, in uyvy U = g, V = a uniform mat4 colorMatrix; uniform float opacity; |