Commit 9fffe22d authored by Val Doroshchuk's avatar Val Doroshchuk

Rename to Playbin

parent 32d64263
......@@ -2,7 +2,16 @@ TARGET = QtGstreamerExtras
QT = multimediagsttools_private
include(playback/playback.pri)
PUBLIC_HEADERS += \
qgstreamerpipeline.h \
qgstreamerplaybin.h
PRIVATE_HEADERS += \
qgstreamerpipeline_p.h
SOURCES += \
qgstreamerplaybin.cpp \
qgstreamerpipeline.cpp
CONFIG += simd optimize_full
......
INCLUDEPATH += playback
PUBLIC_HEADERS += \
playback/qgstreamermediaplayer.h
SOURCES += \
playback/qgstreamermediaplayer.cpp
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qgstreamerpipeline.h"
#include "qgstreamerpipeline_p.h"
#include <private/qgstreamervideorenderer_p.h>
#include <private/qgstreamerplayersession_p.h>
#include <QMediaService>
QT_BEGIN_NAMESPACE
void QGstreamerPipelinePrivate::updateMediaObject()
{
Q_Q(QGstreamerPipeline);
QMediaObject *obj = qobject_cast<QMediaObject*>(source->property("mediaObject").value<QObject*>());
q->setMediaObject(obj);
}
QGstreamerPipeline::QGstreamerPipeline(QGstreamerPipelinePrivate *d, QMediaObject *media, QObject *parent)
: QObject(parent)
, d_ptr(d)
{
setMediaObject(media);
}
QGstreamerPipeline::~QGstreamerPipeline()
{
delete d_ptr;
}
QObject *QGstreamerPipeline::source() const
{
return d_func()->source.data();
}
void QGstreamerPipeline::setSource(QObject *src)
{
Q_D(QGstreamerPipeline);
if (d->source == src)
return;
if (d->source)
disconnect(d->source.data(), 0, d, SLOT(updateMediaObject()));
d->source = src;
if (d->source) {
const QMetaObject *metaObject = d->source->metaObject();
int mediaObjectPropertyIndex = metaObject->indexOfProperty("mediaObject");
if (mediaObjectPropertyIndex != -1) {
const QMetaProperty mediaObjectProperty = metaObject->property(mediaObjectPropertyIndex);
if (mediaObjectProperty.hasNotifySignal()) {
QMetaMethod method = mediaObjectProperty.notifySignal();
QMetaObject::connect(d->source.data(), method.methodIndex(),
d, d->metaObject()->indexOfSlot("updateMediaObject()"),
Qt::DirectConnection, 0);
}
}
}
d->updateMediaObject();
emit sourceChanged();
}
QMediaObject *QGstreamerPipeline::mediaObject() const
{
return d_func()->mediaObject.data();
}
void QGstreamerPipeline::setMediaObject(QMediaObject *src)
{
Q_D(QGstreamerPipeline);
auto service = src ? src->service() : nullptr;
if (!service)
return;
auto control = qobject_cast<QGstreamerPlayerControl *>(service->requestControl(QMediaPlayerControl_iid));
d->session = control ? control->session() : nullptr;
d->mediaObject = src;
emit mediaObjectChanged();
}
template <class T>
static void setGstProperty(GstElement *element, const QString &name, T v)
{
g_object_set(G_OBJECT(element), name.toLatin1().constData(), v, NULL);
}
bool QGstreamerPipeline::set(const QString &elementName, const QVariantMap& map)
{
Q_D(QGstreamerPipeline);
GstElement *element = nullptr;
if (elementName == QLatin1String("videoSink"))
element = (d->session && d->session->renderer()) ? d->session->renderer()->videoSink() : nullptr;
else if (d->session->pipeline())
element = gst_bin_get_by_name(GST_BIN(d->session->pipeline()), elementName.toLatin1().constData());
if (!element) {
qWarning() << "Could not find element by name:" << elementName;
if (d->session->pipeline()) {
qWarning() << "Available elements:";
qWarning() << " " << "videoSink";
GstIterator *children = gst_bin_iterate_recurse(GST_BIN(d->session->pipeline()));
gst_iterator_foreach(children, [](const GValue *item, gpointer) {
GstElement *element = GST_ELEMENT(g_value_get_object(item));
qWarning() << " " << GST_ELEMENT_NAME(element);
}, nullptr);
gst_iterator_free(children);
} else {
qWarning() << "No pipeline available";
}
return false;
}
for (auto it = map.begin(); it != map.end(); ++it) {
QString name = it.key();
QVariant value = it.value();
switch (value.type()) {
case QMetaType::Int:
setGstProperty(element, name, value.toInt());
break;
case QMetaType::Bool:
setGstProperty(element, name, value.toBool());
break;
case QMetaType::Double:
setGstProperty(element, name, value.toDouble());
break;
case QMetaType::QString:
setGstProperty(element, name, value.toString().toUtf8().constData());
break;
default:
break;
}
}
return true;
}
#include "moc_qgstreamerpipeline.cpp"
QT_END_NAMESPACE
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QGSTREAMERPIPELINE_H
#define QGSTREAMERPIPELINE_H
#include <QtMultimedia/qtmultimediaglobal.h>
#include <QVariantMap>
#include <QUrl>
QT_BEGIN_NAMESPACE
class QMediaObject;
class QGstreamerPipelinePrivate;
class Q_MULTIMEDIA_EXPORT QGstreamerPipeline : public QObject
{
Q_OBJECT
Q_PROPERTY(QObject* source READ source WRITE setSource NOTIFY sourceChanged)
Q_PROPERTY(QMediaObject* mediaObject READ mediaObject NOTIFY mediaObjectChanged SCRIPTABLE false DESIGNABLE false)
public:
~QGstreamerPipeline();
QObject *source() const;
void setSource(QObject *source);
QMediaObject *mediaObject() const;
void setMediaObject(QMediaObject *source);
Q_INVOKABLE bool set(const QString &elementName, const QVariantMap& map);
Q_SIGNALS:
void sourceChanged();
void mediaObjectChanged();
protected:
QGstreamerPipeline(QGstreamerPipelinePrivate *d,
QMediaObject *player = nullptr, QObject *parent = nullptr);
QGstreamerPipelinePrivate *d_ptr = nullptr;
private:
Q_DISABLE_COPY(QGstreamerPipeline)
Q_DECLARE_PRIVATE(QGstreamerPipeline)
};
QT_END_NAMESPACE
#endif // QGSTREAMERPIPELINE_H
/****************************************************************************
**
** Copyright (C) 2018 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QGSTREAMERPIPELINE_P_H
#define QGSTREAMERPIPELINE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QPointer>
QT_BEGIN_NAMESPACE
class QMediaObject;
class QGstreamerPlayerSession;
class QGstreamerPipeline;
class QGstreamerPipelinePrivate : public QObject
{
Q_OBJECT
Q_DECLARE_PUBLIC(QGstreamerPipeline)
public:
QGstreamerPipelinePrivate(QGstreamerPipeline *q) : q_ptr(q) { }
~QGstreamerPipelinePrivate() { }
public Q_SLOTS:
void updateMediaObject();
protected:
QPointer<QObject> source;
QPointer<QMediaObject> mediaObject;
QGstreamerPlayerSession *session = nullptr;
QGstreamerPipeline *q_ptr = nullptr;
};
QT_END_NAMESPACE
#endif // QGSTREAMERPIPELINE_P_H
......@@ -37,10 +37,10 @@
**
****************************************************************************/
#include "qgstreamermediaplayer.h"
#include "qgstreamerplaybin.h"
#include "qgstreamerpipeline_p.h"
#include <private/qgstreamervideorenderer_p.h>
#include <private/qgstreamerplayersession_p.h>
#include <QMediaService>
#include <QtMultimedia/qmediametadata.h>
QT_BEGIN_NAMESPACE
......@@ -57,28 +57,22 @@ typedef enum {
GST_PLAY_FLAG_BUFFERING = 0x000000100
} GstPlayFlags;
class QGstreamerMediaPlayerPrivate : public QObject
class QGstreamerPlaybinPrivate : public QGstreamerPipelinePrivate
{
Q_DECLARE_PUBLIC(QGstreamerMediaPlayer)
Q_DECLARE_PUBLIC(QGstreamerPlaybin)
public:
QGstreamerMediaPlayerPrivate(QGstreamerMediaPlayer *q)
: q_ptr(q)
QGstreamerPlaybinPrivate(QGstreamerPlaybin *q)
: QGstreamerPipelinePrivate(q)
{
}
public Q_SLOTS:
void updateMediaObject();
void streamsChanged();
void updatePipeline();
void mediaObjectChanged();
protected:
QPointer<QObject> source;
QPointer<QMediaObject> mediaObject;
QGstreamerPlayerSession *session = nullptr;
QString pipelineDesc;
QString pendingPipelineDesc;
QString videoSinkDesc;
QString pendingVideoSinkDesc;
......@@ -100,16 +94,64 @@ protected:
int pendingTextStream = -1;
int textStream = -1;
QList<QVariantMap> textStreamProperties;
QGstreamerMediaPlayer *q_ptr = nullptr;
};
void QGstreamerMediaPlayerPrivate::updateMediaObject()
void QGstreamerPlaybinPrivate::mediaObjectChanged()
{
Q_Q(QGstreamerMediaPlayer);
Q_Q(QGstreamerPlaybin);
if (!session)
return;
connect(session, &QGstreamerPlayerSession::streamsChanged,
this, &QGstreamerPlaybinPrivate::streamsChanged);
QMediaObject *obj = qobject_cast<QMediaObject*>(source->property("mediaObject").value<QObject*>());
q->setMediaObject(obj);
// Create pipeline when renderer is ready.
connect(session, &QGstreamerPlayerSession::rendererIsReady,
this, &QGstreamerPlaybinPrivate::updatePipeline);
// In case if these values've been applied
// before mediaObject is available.
q->setShowText(pendingShowText);
q->setTextUri(pendingTextUri);
q->setTextFont(pendingTextFont);
q->setAudioStream(pendingAudioStream);
q->setVideoStream(pendingVideoStream);
q->setTextStream(pendingTextStream);
updatePipeline();
}
static GstElement *parseDesc(const QString &name)
{
GError *error = NULL;
GstElement *element = gst_parse_launch(name.toLatin1().constData(), &error);
if (error) {
g_printerr("ERROR: %s: %s\n", name.toLatin1().constData(), GST_STR_NULL(error->message));
g_clear_error(&error);
}
return element;
}
void QGstreamerPlaybinPrivate::updatePipeline()
{
Q_Q(QGstreamerPlaybin);
auto renderer = session->renderer();
if (!renderer || !renderer->isReady())
return;
if (!pendingVideoSinkDesc.isEmpty()) {
GstElement *videoSink = parseDesc(pendingVideoSinkDesc);
if (videoSink) {
videoSinkDesc = pendingVideoSinkDesc;
pendingVideoSinkDesc.clear();
renderer->setVideoSink(videoSink);
emit q->videoSinkChanged();
}
}
}
static QVariantMap getStreamProperties(GstElement *pipeline, const char *name, int i)
......@@ -134,9 +176,9 @@ static QVariantMap getStreamProperties(GstElement *pipeline, const char *name, i
return streamProperties;
}
void QGstreamerMediaPlayerPrivate::streamsChanged()
void QGstreamerPlaybinPrivate::streamsChanged()
{
Q_Q(QGstreamerMediaPlayer);
Q_Q(QGstreamerPlaybin);
GstElement *playbin = session ? session->playbin() : nullptr;
if (!playbin)
......@@ -197,176 +239,34 @@ void QGstreamerMediaPlayerPrivate::streamsChanged()
emit q->textStreamPropertiesChanged();
}
static GstElement *parseDesc(const QString &name)
{
GError *error = NULL;
GstElement *element = gst_parse_launch(name.toLatin1().constData(), &error);
if (error) {
g_printerr("ERROR: %s: %s\n", name.toLatin1().constData(), GST_STR_NULL(error->message));
g_clear_error(&error);
}
return element;
}
void QGstreamerMediaPlayerPrivate::updatePipeline()
QGstreamerPlaybin::QGstreamerPlaybin(QMediaObject *media, QObject *parent)
: QGstreamerPipeline(new QGstreamerPlaybinPrivate(this), media, parent)
{
Q_Q(QGstreamerMediaPlayer);
auto renderer = session->renderer();
if (!renderer || !renderer->isReady())
return;
Q_D(QGstreamerPlaybin);
if (!pendingVideoSinkDesc.isEmpty()) {
GstElement *videoSink = parseDesc(pendingVideoSinkDesc);
if (videoSink) {
videoSinkDesc = pendingVideoSinkDesc;
pendingVideoSinkDesc.clear();
renderer->setVideoSink(videoSink);
connect((QGstreamerPipeline*)this, &QGstreamerPipeline::mediaObjectChanged,
d, QOverload<>::of(&QGstreamerPlaybinPrivate::mediaObjectChanged));
emit q->videoSinkChanged();
}
}
if (!pendingPipelineDesc.isEmpty()) {
GstElement *pipeline = parseDesc(pendingPipelineDesc);
if (pipeline) {
pipelineDesc = pendingPipelineDesc;
pendingPipelineDesc.clear();
session->setPipeline(pipeline);
emit q->pipelineChanged();
auto it = gst_bin_iterate_sinks(GST_BIN(pipeline));
GValue data = { 0, 0 };
while (gst_iterator_next (it, &data) == GST_ITERATOR_OK) {
auto child = (GstElement*) g_value_get_object(&data);
if (QLatin1String(GST_OBJECT_NAME(child)) == QLatin1String("qtvideosink")) {
renderer->setVideoSink(child);
break;
}
}
gst_iterator_free(it);
}
}
}
QGstreamerMediaPlayer::QGstreamerMediaPlayer(QMediaObject *media, QObject *parent)
: QGstreamerMediaPlayer(parent)
{
setMediaObject(media);
}
QGstreamerMediaPlayer::QGstreamerMediaPlayer(QObject *parent)
: QObject(parent)
, d_ptr(new QGstreamerMediaPlayerPrivate(this))
{
}
QGstreamerMediaPlayer::~QGstreamerMediaPlayer()
{
delete d_ptr;
}
QObject *QGstreamerMediaPlayer::source() const
{
return d_func()->source.data();
}
void QGstreamerMediaPlayer::setSource(QObject *src)
{
Q_D(QGstreamerMediaPlayer);
if (d->source == src)
return;
if (d->source)
disconnect(d->source.data(), 0, d, SLOT(updateMediaObject()));
d->source = src;
if (d->source) {
const QMetaObject *metaObject = d->source->metaObject();
int mediaObjectPropertyIndex = metaObject->indexOfProperty("mediaObject");
if (mediaObjectPropertyIndex != -1) {
const QMetaProperty mediaObjectProperty = metaObject->property(mediaObjectPropertyIndex);
if (mediaObjectProperty.hasNotifySignal()) {
QMetaMethod method = mediaObjectProperty.notifySignal();
QMetaObject::connect(d->source.data(), method.methodIndex(),
d, d->metaObject()->indexOfSlot("updateMediaObject()"),
Qt::DirectConnection, 0);
}
}
}
d->updateMediaObject();
emit sourceChanged();
}
QMediaObject *QGstreamerMediaPlayer::mediaObject() const
{
return d_func()->mediaObject.data();
}
void QGstreamerMediaPlayer::setMediaObject(QMediaObject *src)
{
Q_D(QGstreamerMediaPlayer);
auto service = src ? src->service() : nullptr;
if (!service)
return;
auto control = qobject_cast<QGstreamerPlayerControl *>(service->requestControl(QMediaPlayerControl_iid));
d->session = control ? control->session() : nullptr;
if (!d->session)
return;
connect(d->session, &QGstreamerPlayerSession::streamsChanged,
d, &QGstreamerMediaPlayerPrivate::streamsChanged);
// Create pipeline when renderer is ready.
connect(d->session, &QGstreamerPlayerSession::rendererChanged,
d, &QGstreamerMediaPlayerPrivate::updatePipeline);
// In case if these values've been applied
// before mediaObject is available.
setShowText(d->pendingShowText);
setTextUri(d->pendingTextUri);
setTextFont(d->pendingTextFont);
setAudioStream(d->pendingAudioStream);
setVideoStream(d->pendingVideoStream);
setTextStream(d->pendingTextStream);
d->updatePipeline();
d->mediaObjectChanged();
}
QString QGstreamerMediaPlayer::pipeline() const
QGstreamerPlaybin::QGstreamerPlaybin(QObject *parent)
: QGstreamerPlaybin(nullptr, parent)
{
return d_func()->pipelineDesc;
}
void QGstreamerMediaPlayer::setPipeline(const QString &desc)
QGstreamerPlaybin::~QGstreamerPlaybin()
{
Q_D(QGstreamerMediaPlayer);
d->pendingPipelineDesc = desc;
if (!d->session || d->pipelineDesc == desc)
return;
d->updatePipeline();
}
QString QGstreamerMediaPlayer::videoSink() const
QString QGstreamerPlaybin::videoSink() const
{
return d_func()->videoSinkDesc;
}
void QGstreamerMediaPlayer::setVideoSink(const QString &desc)
void QGstreamerPlaybin::setVideoSink(const QString &desc)
{
Q_D(QGstreamerMediaPlayer);
Q_D(QGstreamerPlaybin);
d->pendingVideoSinkDesc = desc;
if (!d->session || d