qgstreamerplaybin.cpp 11.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
/****************************************************************************
**
** 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$
**
****************************************************************************/

Val Doroshchuk's avatar
Val Doroshchuk committed
40 41
#include "qgstreamerplaybin.h"
#include "qgstreamerpipeline_p.h"
42
#include <private/qgstreamervideorenderer_p.h>
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
#include <private/qgstreamerplayersession_p.h>
#include <QtMultimedia/qmediametadata.h>

QT_BEGIN_NAMESPACE

typedef enum {
    GST_PLAY_FLAG_VIDEO         = 0x00000001,
    GST_PLAY_FLAG_AUDIO         = 0x00000002,
    GST_PLAY_FLAG_TEXT          = 0x00000004,
    GST_PLAY_FLAG_VIS           = 0x00000008,
    GST_PLAY_FLAG_SOFT_VOLUME   = 0x00000010,
    GST_PLAY_FLAG_NATIVE_AUDIO  = 0x00000020,
    GST_PLAY_FLAG_NATIVE_VIDEO  = 0x00000040,
    GST_PLAY_FLAG_DOWNLOAD      = 0x00000080,
    GST_PLAY_FLAG_BUFFERING     = 0x000000100
} GstPlayFlags;

Val Doroshchuk's avatar
Val Doroshchuk committed
60
class QGstreamerPlaybinPrivate : public QGstreamerPipelinePrivate
61
{
Val Doroshchuk's avatar
Val Doroshchuk committed
62
    Q_DECLARE_PUBLIC(QGstreamerPlaybin)
63

64
public:
Val Doroshchuk's avatar
Val Doroshchuk committed
65 66
    QGstreamerPlaybinPrivate(QGstreamerPlaybin *q) 
        : QGstreamerPipelinePrivate(q)
67 68 69
    {
    }

70 71
public Q_SLOTS:
    void streamsChanged();
Val Doroshchuk's avatar
Val Doroshchuk committed
72
    void updatePlaybin();
73
    void mediaPlayerChanged();
74 75

protected:
76 77 78
    QString videoSinkDesc;
    QString pendingVideoSinkDesc;

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
    bool showText = false;
    bool pendingShowText = showText;
    QUrl textUri;
    QUrl pendingTextUri;
    QString textFont;
    QString pendingTextFont;
    int audioStreamsCount = 0;
    int pendingAudioStream = -1;
    int audioStream = -1;
    QList<QVariantMap> audioStreamProperties;
    int videoStreamsCount = 0;
    int pendingVideoStream = -1;
    int videoStream = -1;
    QList<QVariantMap> videoStreamProperties;
    int textStreamsCount = 0;
    int pendingTextStream = -1;
    int textStream = -1;
    QList<QVariantMap> textStreamProperties;
};

99
void QGstreamerPlaybinPrivate::mediaPlayerChanged()
100
{
Val Doroshchuk's avatar
Val Doroshchuk committed
101 102 103 104 105 106 107
    Q_Q(QGstreamerPlaybin);

    if (!session)
        return;

    connect(session, &QGstreamerPlayerSession::streamsChanged,
        this, &QGstreamerPlaybinPrivate::streamsChanged);
108

Val Doroshchuk's avatar
Val Doroshchuk committed
109
    connect(session, &QGstreamerPlayerSession::rendererIsReady,
Val Doroshchuk's avatar
Val Doroshchuk committed
110
        this, &QGstreamerPlaybinPrivate::updatePlaybin);
Val Doroshchuk's avatar
Val Doroshchuk committed
111 112 113 114 115 116 117 118 119 120

    // 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);

Val Doroshchuk's avatar
Val Doroshchuk committed
121
    updatePlaybin();
Val Doroshchuk's avatar
Val Doroshchuk committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135
}

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;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
136
void QGstreamerPlaybinPrivate::updatePlaybin()
Val Doroshchuk's avatar
Val Doroshchuk committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
{
    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();
        }
    }
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
}

static QVariantMap getStreamProperties(GstElement *pipeline, const char *name, int i)
{
    QVariantMap streamProperties;
    GstTagList *tags = 0;
    g_signal_emit_by_name(G_OBJECT(pipeline), name, i, &tags);

#if GST_CHECK_VERSION(1,0,0)
    if (tags && GST_IS_TAG_LIST(tags)) {
#else
    if (tags && gst_is_tag_list(tags)) {
#endif
        gchar *languageCode = 0;
        if (gst_tag_list_get_string(tags, GST_TAG_LANGUAGE_CODE, &languageCode))
            streamProperties[QMediaMetaData::Language] = QString::fromUtf8(languageCode);

        g_free (languageCode);
        gst_tag_list_free(tags);
    }

    return streamProperties;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
178
void QGstreamerPlaybinPrivate::streamsChanged()
179
{
Val Doroshchuk's avatar
Val Doroshchuk committed
180
    Q_Q(QGstreamerPlaybin);
181

Val Doroshchuk's avatar
Val Doroshchuk committed
182
    GstElement *playbin = session ? session->playbin() : nullptr;
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
    if (!playbin)
        return;

    gint audioCount = 0;
    gint videoCount = 0;
    gint textCount = 0;

    g_object_get(G_OBJECT(playbin), "n-audio", &audioCount, NULL);
    g_object_get(G_OBJECT(playbin), "n-video", &videoCount, NULL);
    g_object_get(G_OBJECT(playbin), "n-text", &textCount, NULL);

    QList<QVariantMap> audioProperties, videoProperties, textProperties;
    for (int i = 0; i < audioCount; ++i)
        audioProperties.append(getStreamProperties(playbin, "get-audio-tags", i));

    for (int i = 0; i < videoCount; ++i)
        videoProperties.append(getStreamProperties(playbin, "get-video-tags", i));

    for (int i = 0; i < textCount; ++i)
        textProperties.append(getStreamProperties(playbin, "get-text-tags", i));

    bool audioPropertiesChanged = audioStreamProperties != audioProperties;
    if (audioPropertiesChanged)
        audioStreamProperties = audioProperties;

    bool videoPropertiesChanged = videoStreamProperties != videoProperties;
    if (videoPropertiesChanged)
        videoStreamProperties = videoProperties;

    bool textPropertiesChanged = textStreamProperties != textProperties;
    if (textPropertiesChanged)
        textStreamProperties = textProperties;

    if (audioStreamsCount != audioCount) {
        audioStreamsCount = audioCount;
        emit q->audioStreamsCountChanged();
    }

    if (audioPropertiesChanged)
        emit q->audioStreamPropertiesChanged();

    if (videoStreamsCount != videoCount) {
        videoStreamsCount = videoCount;
        emit q->videoStreamsCountChanged();
    }

    if (videoPropertiesChanged)
        emit q->videoStreamPropertiesChanged();

    if (textStreamsCount != textCount) {
        textStreamsCount = textCount;
        emit q->textStreamsCountChanged();
    }

    if (textPropertiesChanged)
        emit q->textStreamPropertiesChanged();
}

241
QGstreamerPlaybin::QGstreamerPlaybin(QMediaPlayer *media, QObject *parent)
Val Doroshchuk's avatar
Val Doroshchuk committed
242
    : QGstreamerPipeline(new QGstreamerPlaybinPrivate(this), media, parent)
243
{
Val Doroshchuk's avatar
Val Doroshchuk committed
244
    Q_D(QGstreamerPlaybin);
Val Doroshchuk's avatar
Val Doroshchuk committed
245

246 247
    connect(this, &QGstreamerPipeline::mediaPlayerChanged,
        d, &QGstreamerPlaybinPrivate::mediaPlayerChanged);
Val Doroshchuk's avatar
Val Doroshchuk committed
248

249
    d->mediaPlayerChanged();
250 251
}

Val Doroshchuk's avatar
Val Doroshchuk committed
252 253
QGstreamerPlaybin::QGstreamerPlaybin(QObject *parent)
    : QGstreamerPlaybin(nullptr, parent)
254 255 256
{
}

Val Doroshchuk's avatar
Val Doroshchuk committed
257
QGstreamerPlaybin::~QGstreamerPlaybin()
258 259 260
{
}

Val Doroshchuk's avatar
Val Doroshchuk committed
261
QString QGstreamerPlaybin::videoSink() const
262 263 264 265
{
    return d_func()->videoSinkDesc;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
266
void QGstreamerPlaybin::setVideoSink(const QString &desc)
267
{
Val Doroshchuk's avatar
Val Doroshchuk committed
268
    Q_D(QGstreamerPlaybin);
269 270

    d->pendingVideoSinkDesc = desc;
Val Doroshchuk's avatar
Val Doroshchuk committed
271
    if (!d->session || d->videoSinkDesc == desc)
272 273
        return;

Val Doroshchuk's avatar
Val Doroshchuk committed
274
    d->updatePlaybin();
275 276
}

Val Doroshchuk's avatar
Val Doroshchuk committed
277
bool QGstreamerPlaybin::showText() const
278 279 280 281
{
    return d_func()->showText;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
282
void QGstreamerPlaybin::setShowText(bool show)
283
{
Val Doroshchuk's avatar
Val Doroshchuk committed
284
    Q_D(QGstreamerPlaybin);
285 286

    d->pendingShowText = show;
Val Doroshchuk's avatar
Val Doroshchuk committed
287 288
    GstElement *playbin = d->session ? d->session->playbin() : nullptr;
    if (!playbin || d->showText == show)
289 290 291 292
        return;

    d->showText = show;
    int flags = 0;
Val Doroshchuk's avatar
Val Doroshchuk committed
293
    g_object_get(G_OBJECT(playbin), "flags", &flags, NULL);
294 295 296 297 298 299

    if (show)
        flags |= GST_PLAY_FLAG_TEXT;
    else
        flags &= ~GST_PLAY_FLAG_TEXT;

Val Doroshchuk's avatar
Val Doroshchuk committed
300
    g_object_set(G_OBJECT(playbin), "flags", flags, NULL);
301 302 303
    emit showTextChanged();
}

Val Doroshchuk's avatar
Val Doroshchuk committed
304
QUrl QGstreamerPlaybin::textUri() const
305 306 307 308
{
    return d_func()->textUri;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
309
void QGstreamerPlaybin::setTextUri(const QUrl &uri)
310
{
Val Doroshchuk's avatar
Val Doroshchuk committed
311
    Q_D(QGstreamerPlaybin);
312 313

    d->pendingTextUri = uri;
Val Doroshchuk's avatar
Val Doroshchuk committed
314 315
    GstElement *playbin = d->session ? d->session->playbin() : nullptr;
    if (!playbin || d->textUri == uri)
316 317 318 319 320
        return;

    d->textUri = uri;
    setShowText(true);

Val Doroshchuk's avatar
Val Doroshchuk committed
321
    g_object_set(G_OBJECT(playbin), "suburi", uri.toEncoded().constData(), NULL);
322 323 324
    emit textUriChanged();
}

Val Doroshchuk's avatar
Val Doroshchuk committed
325
QString QGstreamerPlaybin::textFont() const
326 327 328 329
{
    return d_func()->textFont;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
330
void QGstreamerPlaybin::setTextFont(const QString &str)
331
{
Val Doroshchuk's avatar
Val Doroshchuk committed
332
    Q_D(QGstreamerPlaybin);
333 334

    d->pendingTextFont = str;
Val Doroshchuk's avatar
Val Doroshchuk committed
335 336
    GstElement *playbin = d->session ? d->session->playbin() : nullptr;
    if (!playbin || d->textFont == str)
337 338 339
        return;

    d->textFont = str;
Val Doroshchuk's avatar
Val Doroshchuk committed
340
    g_object_set(G_OBJECT(playbin), "subtitle-font-desc", str.toUtf8().constData(), NULL);
341 342 343
    emit textFontChanged();
}

Val Doroshchuk's avatar
Val Doroshchuk committed
344
int QGstreamerPlaybin::audioStreamsCount() const
345 346 347 348
{
    return d_func()->audioStreamsCount;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
349
int QGstreamerPlaybin::audioStream() const
350 351 352 353
{
    return d_func()->audioStream;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
354
void QGstreamerPlaybin::setAudioStream(int i)
355
{
Val Doroshchuk's avatar
Val Doroshchuk committed
356
    Q_D(QGstreamerPlaybin);
357 358

    d->pendingAudioStream = i;
Val Doroshchuk's avatar
Val Doroshchuk committed
359 360
    GstElement *playbin = d->session ? d->session->playbin() : nullptr;
    if (!playbin || d->audioStream == i)
361 362 363
        return;

    d->audioStream = i;
Val Doroshchuk's avatar
Val Doroshchuk committed
364
    g_object_set(G_OBJECT(playbin), "current-audio", i, NULL);
365 366 367
    emit audioStreamChanged();
}

Val Doroshchuk's avatar
Val Doroshchuk committed
368
QVariantMap QGstreamerPlaybin::audioStreamProperties(int i)
369 370 371 372
{
    return d_func()->audioStreamProperties[i];
}

Val Doroshchuk's avatar
Val Doroshchuk committed
373
int QGstreamerPlaybin::videoStreamsCount() const
374 375 376 377
{
    return d_func()->videoStreamsCount;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
378
int QGstreamerPlaybin::videoStream() const
379 380 381 382
{
    return d_func()->videoStream;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
383
void QGstreamerPlaybin::setVideoStream(int i)
384
{
Val Doroshchuk's avatar
Val Doroshchuk committed
385
    Q_D(QGstreamerPlaybin);
386 387

    d->pendingVideoStream = i;
Val Doroshchuk's avatar
Val Doroshchuk committed
388 389
    GstElement *playbin = d->session ? d->session->playbin() : nullptr;
    if (!playbin || d->videoStream == i)
390 391 392
        return;

    d->videoStream = i;
Val Doroshchuk's avatar
Val Doroshchuk committed
393
    g_object_set(G_OBJECT(playbin), "current-video", i, NULL);
394 395 396
    emit videoStreamChanged();
}

Val Doroshchuk's avatar
Val Doroshchuk committed
397
QVariantMap QGstreamerPlaybin::videoStreamProperties(int i)
398 399 400 401
{
    return d_func()->videoStreamProperties[i];
}

Val Doroshchuk's avatar
Val Doroshchuk committed
402
int QGstreamerPlaybin::textStreamsCount() const
403 404 405 406
{
    return d_func()->textStreamsCount;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
407
int QGstreamerPlaybin::textStream() const
408 409 410 411
{
    return d_func()->textStream;
}

Val Doroshchuk's avatar
Val Doroshchuk committed
412
void QGstreamerPlaybin::setTextStream(int i)
413
{
Val Doroshchuk's avatar
Val Doroshchuk committed
414
    Q_D(QGstreamerPlaybin);
415 416

    d->pendingTextStream = i;
Val Doroshchuk's avatar
Val Doroshchuk committed
417 418
    GstElement *playbin = d->session ? d->session->playbin() : nullptr;
    if (!playbin || d->textStream == i)
419 420 421
        return;

    d->textStream = i;
Val Doroshchuk's avatar
Val Doroshchuk committed
422
    g_object_set(G_OBJECT(playbin), "current-text", i, NULL);
423 424 425
    emit textStreamChanged();
}

Val Doroshchuk's avatar
Val Doroshchuk committed
426
QVariantMap QGstreamerPlaybin::textStreamProperties(int i)
427 428 429 430
{
    return d_func()->textStreamProperties[i];
}

Val Doroshchuk's avatar
Val Doroshchuk committed
431
#include "moc_qgstreamerplaybin.cpp"
432 433

QT_END_NAMESPACE