Revision control

Copy as Markdown

// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QGSTREAMERMEDIAPLAYER_P_H
#define QGSTREAMERMEDIAPLAYER_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 <QtMultimedia/private/qplatformmediaplayer_p.h>
#include <QtMultimedia/private/qtmultimediaglobal_p.h>
#include <QtMultimedia/private/qmultimediautils_p.h>
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qtimer.h>
#include <QtCore/qurl.h>
#include <QtCore/qfuture.h>
#include <common/qgst_bus_observer_p.h>
#include <common/qgst_discoverer_p.h>
#include <common/qgst_p.h>
#include <common/qgstpipeline_p.h>
#include <common/qgstreamervideosink_p.h>
#include <gst/play/gstplay.h>
#include <array>
QT_BEGIN_NAMESPACE
class QGstreamerMessage;
class QGstreamerAudioOutput;
class QGstreamerVideoOutput;
class QGstreamerMediaPlayer : public QObject,
public QPlatformMediaPlayer,
public QGstreamerBusMessageFilter
{
using QGstPlayHandle = QGstImpl::QGstHandleHelper<GstPlay>::SharedHandle;
public:
static q23::expected<QPlatformMediaPlayer *, QString> create(QMediaPlayer *parent = nullptr);
~QGstreamerMediaPlayer() override;
qint64 duration() const override;
float bufferProgress() const override;
QMediaTimeRange availablePlaybackRanges() const override;
qreal playbackRate() const override;
void setPlaybackRate(qreal rate) override;
QUrl media() const override;
const QIODevice *mediaStream() const override;
void setMedia(const QUrl &, QIODevice *) override;
bool streamPlaybackSupported() const override { return true; }
void setAudioOutput(QPlatformAudioOutput *output) override;
QMediaMetaData metaData() const override;
void setVideoSink(QVideoSink *sink) override;
int trackCount(TrackType) override;
QMediaMetaData trackMetaData(TrackType /*type*/, int /*streamNumber*/) override;
int activeTrack(TrackType) override;
void setActiveTrack(TrackType, int /*streamNumber*/) override;
void setPosition(qint64 pos) override;
void setPosition(std::chrono::milliseconds pos);
void play() override;
void pause() override;
void stop() override;
const QGstPipeline &pipeline() const;
bool canPlayQrc() const override;
PitchCompensationAvailability pitchCompensationAvailability() const override;
bool pitchCompensation() const override;
private:
QGstreamerMediaPlayer(QGstreamerVideoOutput *videoOutput, QMediaPlayer *parent);
static void sourceSetupCallback(GstElement *uridecodebin, GstElement *source,
QGstreamerMediaPlayer *);
bool hasMedia() const;
bool hasValidMedia() const;
void updatePositionFromPipeline();
void updateBufferProgress(float);
QUrl m_url;
QIODevice *m_stream = nullptr;
enum class ResourceErrorState : uint8_t {
NoError,
ErrorOccurred,
ErrorReported,
};
ResourceErrorState m_resourceErrorState = ResourceErrorState::NoError;
float m_bufferProgress = 0.f;
std::chrono::milliseconds m_duration{};
QGstreamerAudioOutput *gstAudioOutput = nullptr;
QGstreamerVideoOutput *gstVideoOutput = nullptr;
// // Message handler
bool processBusMessage(const QGstreamerMessage &message) override;
bool processBusMessageApplication(const QGstreamerMessage &message);
// decoder connections
void disconnectDecoderHandlers();
QGObjectHandlerScopedConnection sourceSetup;
// custom sources
void decoderPadAddedCustomSource(const QGstElement &src, const QGstPad &pad);
void decoderPadRemovedCustomSource(const QGstElement &src, const QGstPad &pad);
bool isCustomSource() const { return m_url.scheme() == QStringLiteral(u"gstreamer-pipeline"); }
void setMediaCustomSource(const QUrl &content);
void cleanupCustomPipeline();
QGstElement decoder;
QGstPipeline customPipeline;
QGObjectHandlerScopedConnection padAdded;
QGObjectHandlerScopedConnection padRemoved;
std::unique_ptr<QTimer> positionUpdateTimer;
TrackTypeMap<QGstElement> customPipelineSinks;
TrackTypeMap<QGstPad> customPipelinePads;
// play
QGstPlayHandle m_gstPlay;
QGstPipeline m_playbin;
QGstBusObserver m_gstPlayBus;
// GstPlay bus message counting to achieve STOPPED state before destruction
int m_expectedStoppedMessages = 0; // from gst_play_stop calls and after reaching EOS
bool m_playOrPauseCalledSinceLastStateChangedOrEosMessage = false; // handles EOS edge case
bool m_callStopInDestructor = false; // true after gst_play_play/pause calls, false when stopped
// metadata
QMediaMetaData m_metaData;
TrackTypeMap<std::vector<QMediaMetaData>> m_trackMetaData;
TrackTypeMap<std::vector<QByteArray>> m_trackIDs;
TrackTypeMap<int> m_activeTrack{};
QList<QSize> m_nativeSize;
void resetStateForEmptyOrInvalidMedia();
void updateNativeSizeOnVideoOutput();
void seekToCurrentPosition();
std::optional<std::chrono::nanoseconds> m_pendingSeek;
int stateChangeToSkip = 0;
void updateVideoTrackEnabled();
void updateAudioTrackEnabled();
void updateSubtitleTrackEnabled();
QGstreamerRelayVideoSink *m_gstVideoSink = nullptr;
// asynchronous discovery
using DiscoverResult = q23::expected<QGst::QGstDiscovererInfo, QUniqueGErrorHandle>;
QFuture<DiscoverResult> discover(QUrl);
void handleDiscoverResult(const DiscoverResult &, const QUrl &playerUrl);
QFuture<DiscoverResult> m_discoverFuture;
QFuture<void> m_discoveryHandler;
bool m_hasPendingMedia = false;
std::optional<QMediaPlayer::PlaybackState> m_requestedPlaybackState = std::nullopt;
};
QT_END_NAMESPACE
#endif