diff options
12 files changed, 176 insertions, 232 deletions
diff --git a/examples/multimedia/audiodecoder/audiodecoder.cpp b/examples/multimedia/audiodecoder/audiodecoder.cpp index 09f40c711..36bbb2919 100644 --- a/examples/multimedia/audiodecoder/audiodecoder.cpp +++ b/examples/multimedia/audiodecoder/audiodecoder.cpp @@ -66,7 +66,7 @@ AudioDecoder::AudioDecoder(bool isPlayback, bool isDelete, const QString &target format.setSampleRate(48000); m_decoder.setAudioFormat(format); - QIODevice* target = new QFile(targetFileName); + QIODevice* target = new QFile(targetFileName, this); if (target->open(QIODevice::WriteOnly)) m_waveDecoder = new QWaveDecoder(target, format); diff --git a/src/multimedia/platform/gstreamer/audio/qaudioinput_gstreamer.cpp b/src/multimedia/platform/gstreamer/audio/qaudioinput_gstreamer.cpp index 3a0d0c4a0..93d6a87d3 100644 --- a/src/multimedia/platform/gstreamer/audio/qaudioinput_gstreamer.cpp +++ b/src/multimedia/platform/gstreamer/audio/qaudioinput_gstreamer.cpp @@ -165,9 +165,9 @@ bool QGStreamerAudioInput::open() return false; } - auto *gstCaps = QGstUtils::capsForAudioFormat(m_format); + auto gstCaps = QGstUtils::capsForAudioFormat(m_format); - if (!gstCaps) { + if (gstCaps.isNull()) { setError(QAudio::OpenError); setState(QAudio::StoppedState); return false; @@ -186,7 +186,7 @@ bool QGStreamerAudioInput::open() gst_object_unref (gstBus); gstAppSink = createAppSink(); - g_object_set(gstAppSink.object(), "caps", gstCaps, nullptr); + gstAppSink.set("caps", gstCaps); QGstElement conv("audioconvert", "conv"); gstVolume = QGstElement("volume", "volume"); diff --git a/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer.cpp b/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer.cpp index 0ce1c8d60..6996bc1dd 100644 --- a/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer.cpp +++ b/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer.cpp @@ -56,8 +56,11 @@ QT_BEGIN_NAMESPACE QGStreamerAudioOutput::QGStreamerAudioOutput(const QByteArray &device) - : m_device(device) + : m_device(device), + gstPipeline("pipeline") { + gstPipeline.installMessageFilter(this); + QGStreamerAudioDeviceInfo audioInfo(device, QAudio::AudioOutput); gstOutput = gst_device_create_element(audioInfo.gstDevice, nullptr); } @@ -199,24 +202,14 @@ bool QGStreamerAudioOutput::open() return false; } - gstPipeline = QGstPipeline("pipeline"); - gstPipeline.installMessageFilter(this); - - gstAppSrc = gst_element_factory_make("appsrc", "appsrc"); - - m_bufferSize = gst_app_src_get_max_bytes(GST_APP_SRC(gstAppSrc.element())); - // qDebug() << "GST caps:" << gst_caps_to_string(caps); m_appSrc = new QGstAppSrc; + m_appSrc->setup(m_audioSource, QGstAppSrc::ForceSequential); + m_appSrc->setAudioFormat(m_format); + connect(m_appSrc, &QGstAppSrc::bytesProcessed, this, &QGStreamerAudioOutput::bytesProcessedByAppSrc); connect(m_appSrc, &QGstAppSrc::noMoreData, this, &QGStreamerAudioOutput::needData); - if (m_audioSource) { - m_appSrc->setStream(m_audioSource); - } else { - m_appSrc->setBuffer(&m_buffer); - } - m_appSrc->setAudioFormat(m_format); - m_appSrc->setup(gstAppSrc.element()); + gstAppSrc = m_appSrc->element(); // gstDecodeBin = gst_element_factory_make ("decodebin", "dec"); QGstElement conv("audioconvert", "conv"); @@ -256,13 +249,11 @@ void QGStreamerAudioOutput::close() m_audioSource = nullptr; } m_opened = false; - m_buffer.clear(); } qint64 QGStreamerAudioOutput::write(const char *data, qint64 len) { - m_buffer.append(data, len); - m_appSrc->newDataAvailable(); + m_appSrc->write(data, len); return len; } @@ -282,7 +273,7 @@ int QGStreamerAudioOutput::bytesFree() const if (m_deviceState != QAudio::ActiveState && m_deviceState != QAudio::IdleState) return 0; - return qMax(0, 4096*4 - m_buffer.size()); + return m_appSrc->canAcceptMoreData() ? 4096*4 : 0; } int QGStreamerAudioOutput::periodSize() const diff --git a/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer_p.h b/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer_p.h index 71e266a2c..532792c1c 100644 --- a/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer_p.h +++ b/src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer_p.h @@ -125,7 +125,6 @@ private: bool m_pullMode = true; bool m_opened = false; QIODevice *m_audioSource = nullptr; - QRingBuffer m_buffer; QTimer m_periodTimer; int m_bufferSize = 0; qint64 m_bytesProcessed = 0; diff --git a/src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder.cpp b/src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder.cpp index ec518ca60..50675c30f 100644 --- a/src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder.cpp +++ b/src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder.cpp @@ -129,8 +129,9 @@ void QGstreamerAudioDecoder::configureAppSrcElement(GObject* object, GObject *or GstElement *appsrc; g_object_get(orig, "source", &appsrc, NULL); - if (!self->appsrc()->setup(appsrc)) - qWarning()<<"Could not setup appsrc element"; + auto *qAppSrc = self->appsrc(); + qAppSrc->setExternalAppSrc(appsrc); + qAppSrc->setup(self->mDevice); g_object_unref(G_OBJECT(appsrc)); } @@ -285,11 +286,8 @@ void QGstreamerAudioDecoder::setSourceFilename(const QString &fileName) { stop(); mDevice = nullptr; -#if QT_CONFIG(gstreamer_app) - if (m_appSrc) - m_appSrc->deleteLater(); + delete m_appSrc; m_appSrc = nullptr; -#endif bool isSignalRequired = (mSource != fileName); mSource = fileName; @@ -324,7 +322,6 @@ void QGstreamerAudioDecoder::start() if (!mSource.isEmpty()) { m_playbin.set("uri", QUrl::fromLocalFile(mSource).toEncoded().constData()); } else if (mDevice) { -#if QT_CONFIG(gstreamer_app) // make sure we can read from device if (!mDevice->isOpen() || !mDevice->isReadable()) { processInvalidMedia(QAudioDecoder::AccessDeniedError, QLatin1String("Unable to read from specified device")); @@ -333,10 +330,8 @@ void QGstreamerAudioDecoder::start() if (!m_appSrc) m_appSrc = new QGstAppSrc(this); - m_appSrc->setStream(mDevice); m_playbin.set("uri", "appsrc://"); -#endif } else { return; } @@ -345,9 +340,8 @@ void QGstreamerAudioDecoder::start() if (m_appSink) { if (mFormat.isValid()) { setAudioFlags(false); - GstCaps *caps = QGstUtils::capsForAudioFormat(mFormat); - gst_app_sink_set_caps(m_appSink, caps); - gst_caps_unref(caps); + QGstMutableCaps caps = QGstUtils::capsForAudioFormat(mFormat); + gst_app_sink_set_caps(m_appSink, caps.get()); } else { // We want whatever the native audio format is setAudioFlags(true); diff --git a/src/multimedia/platform/gstreamer/common/qgst_p.h b/src/multimedia/platform/gstreamer/common/qgst_p.h index e44419026..0cbef3c85 100644 --- a/src/multimedia/platform/gstreamer/common/qgst_p.h +++ b/src/multimedia/platform/gstreamer/common/qgst_p.h @@ -243,7 +243,7 @@ public: int size() const { return gst_caps_get_size(caps); } QGstStructure at(int index) { return gst_caps_get_structure(caps, index); } - GstCaps *get() { return caps; } + GstCaps *get() const { return caps; } QByteArray toString() const { gchar *c = gst_caps_to_string(caps); @@ -303,6 +303,7 @@ public: void set(const char *property, quint64 i) { g_object_set(m_object, property, guint64(i), nullptr); } void set(const char *property, double d) { g_object_set(m_object, property, gdouble(d), nullptr); } void set(const char *property, const QGstObject &o) { g_object_set(m_object, property, o.object(), nullptr); } + void set(const char *property, const QGstMutableCaps &c) { g_object_set(m_object, property, c.get(), nullptr); } QGString getString(const char *property) const { char *s = nullptr; g_object_get(m_object, property, &s, nullptr); return s; } diff --git a/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp b/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp index ed4c57926..9b4419e34 100644 --- a/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstappsrc.cpp @@ -49,55 +49,62 @@ Q_LOGGING_CATEGORY(qLcAppSrc, "qt.multimedia.appsrc") QGstAppSrc::QGstAppSrc(QObject *parent) : QObject(parent) { - m_callbacks.need_data = &QGstAppSrc::on_need_data; - m_callbacks.enough_data = &QGstAppSrc::on_enough_data; - m_callbacks.seek_data = &QGstAppSrc::on_seek_data; + m_appSrc = QGstElement("appsrc", "appsrc"); + if (m_appSrc.isNull()) + qWarning() << "Could not create GstAppSrc."; } QGstAppSrc::~QGstAppSrc() { - if (m_appSrc) - gst_object_unref(G_OBJECT(m_appSrc)); } -bool QGstAppSrc::setup(GstElement* appsrc) +bool QGstAppSrc::setup(QIODevice *stream, Flags flags) { - if (m_appSrc) { - gst_object_unref(G_OBJECT(m_appSrc)); - m_appSrc = nullptr; - } + if (m_appSrc.isNull()) + return false; - if (!appsrc || (!m_stream && !m_buffer)) + if (!setStream(stream, flags)) return false; - m_appSrc = GST_APP_SRC(appsrc); - gst_object_ref(appsrc); - gst_app_src_set_callbacks(m_appSrc, (GstAppSrcCallbacks*)&m_callbacks, this, (GDestroyNotify)&QGstAppSrc::destroy_notify); + auto *appSrc = GST_APP_SRC(m_appSrc.element()); + GstAppSrcCallbacks m_callbacks; + m_callbacks.need_data = &QGstAppSrc::on_need_data; + m_callbacks.enough_data = &QGstAppSrc::on_enough_data; + m_callbacks.seek_data = &QGstAppSrc::on_seek_data; + gst_app_src_set_callbacks(appSrc, (GstAppSrcCallbacks*)&m_callbacks, this, nullptr); - m_maxBytes = gst_app_src_get_max_bytes(m_appSrc); + m_maxBytes = gst_app_src_get_max_bytes(appSrc); if (m_sequential) m_streamType = GST_APP_STREAM_TYPE_STREAM; else m_streamType = GST_APP_STREAM_TYPE_RANDOM_ACCESS; - gst_app_src_set_stream_type(m_appSrc, m_streamType); - gst_app_src_set_size(m_appSrc, (m_sequential) ? -1 : (m_stream->bytesAvailable())); - if (m_format.isValid()) { - GstCaps *caps = QGstUtils::capsForAudioFormat(m_format); - if (caps) { - g_object_set(m_appSrc, "caps", caps, nullptr); - g_object_set(m_appSrc, "format", GST_FORMAT_TIME, nullptr); - } else { - qCWarning(qLcAppSrc) << "Invalid caps"; - } - } + gst_app_src_set_stream_type(appSrc, m_streamType); + gst_app_src_set_size(appSrc, m_sequential ? -1 : m_stream->size()); m_networkReply = qobject_cast<QNetworkReply *>(m_stream); return true; } -void QGstAppSrc::setStream(QIODevice *stream) +void QGstAppSrc::setAudioFormat(const QAudioFormat &f) +{ + m_format = f; + if (!m_format.isValid()) + return; + + auto caps = QGstUtils::capsForAudioFormat(m_format); + Q_ASSERT(!caps.isNull()); + m_appSrc.set("caps", caps); + m_appSrc.set("format", GST_FORMAT_TIME); +} + +void QGstAppSrc::setExternalAppSrc(const QGstElement &appsrc) +{ + m_appSrc = appsrc; +} + +bool QGstAppSrc::setStream(QIODevice *stream, Flags flags) { if (m_stream) { disconnect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady())); @@ -105,188 +112,169 @@ void QGstAppSrc::setStream(QIODevice *stream) m_stream = nullptr; } - if (m_appSrc) { - gst_object_unref(G_OBJECT(m_appSrc)); - m_appSrc = nullptr; - } - - m_dataRequestSize = ~0; - m_dataRequested = false; - m_enoughData = false; - m_forceData = false; - m_sequential = false; + m_dataRequestSize = 0; + m_sequential = true; m_maxBytes = 0; if (stream) { + if (!stream->isOpen() && !stream->open(QIODevice::ReadOnly)) + return false; m_stream = stream; connect(m_stream, SIGNAL(destroyed()), SLOT(streamDestroyed())); connect(m_stream, SIGNAL(readyRead()), this, SLOT(onDataReady())); - m_sequential = m_stream->isSequential(); + m_sequential = (flags == ForceSequential) || m_stream->isSequential(); } - initialPosition = m_stream->pos(); + return true; } -QIODevice *QGstAppSrc::stream() const +QGstElement QGstAppSrc::element() { - return m_stream; + return m_appSrc; } -GstAppSrc *QGstAppSrc::element() +void QGstAppSrc::write(const char *data, qsizetype size) { - return m_appSrc; + qCDebug(qLcAppSrc) << "write" << size << m_noMoreData << m_dataRequestSize; + if (!size) + return; + Q_ASSERT(!m_stream); + m_buffer.append(data, size); + m_noMoreData = false; + if (m_dataRequestSize) + pushData(); } void QGstAppSrc::onDataReady() { qCDebug(qLcAppSrc) << "onDataReady" << m_stream->bytesAvailable() << m_stream->size(); - if (!m_enoughData) { - m_dataRequested = true; - pushDataToAppSrc(); - } + if (m_dataRequestSize) + pushData(); } void QGstAppSrc::streamDestroyed() { - if (sender() == m_stream) { - m_stream = nullptr; - sendEOS(); - } + m_stream = nullptr; + sendEOS(); } -void QGstAppSrc::pushDataToAppSrc() +void QGstAppSrc::pushData() { - qCDebug(qLcAppSrc) << "pushData" << m_stream << m_buffer; - if ((!isStreamValid() && !m_buffer) || !m_appSrc) + if (m_appSrc.isNull() || !m_dataRequestSize) return; - if ((m_stream && m_stream->atEnd() && (!m_networkReply || !m_networkReply->isRunning())) || - (m_buffer && !m_buffer->size())) { + qCDebug(qLcAppSrc) << "pushData" << m_stream << m_buffer.size(); + if ((m_stream && m_stream->atEnd())) { eosOrIdle(); return; } m_noMoreData = false; - Q_ASSERT(m_stream || m_buffer); - - if (m_dataRequested && !m_enoughData) { - qint64 size; - if (m_stream) - size = m_stream->bytesAvailable(); - else - size = m_buffer->size(); - - if (m_dataRequestSize == ~0u) - size = qMin(size, queueSize()); - else - size = qMin(size, (qint64)m_dataRequestSize); - - GstBuffer* buffer = gst_buffer_new_and_alloc(size); - - if (m_format.isValid()) { - uint nSamples = size/4; - - GST_BUFFER_TIMESTAMP(buffer) = gst_util_uint64_scale(streamedSamples, GST_SECOND, 48000); - GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale(nSamples, GST_SECOND, 48000); - streamedSamples += nSamples; - } - - GstMapInfo mapInfo; - gst_buffer_map(buffer, &mapInfo, GST_MAP_WRITE); - void* bufferData = mapInfo.data; - - if (m_sequential) - buffer->offset = bytesReadSoFar; - else - buffer->offset = m_stream->pos(); - qint64 bytesRead; - if (m_buffer) - bytesRead = m_buffer->read((char*)bufferData, size); - else - bytesRead = m_stream->read((char*)bufferData, size); - buffer->offset_end = buffer->offset + bytesRead - 1; - bytesReadSoFar += bytesRead; - - gst_buffer_unmap(buffer, &mapInfo); - qCDebug(qLcAppSrc) << "pushing bytes into gstreamer" << buffer->offset << bytesRead; - emit bytesProcessed(bytesRead); - - if (bytesRead > 0) { - m_dataRequested = false; - m_enoughData = false; - GstFlowReturn ret = gst_app_src_push_buffer (GST_APP_SRC (element()), buffer); - if (ret == GST_FLOW_ERROR) { - qWarning()<<"appsrc: push buffer error"; - } else if (ret == GST_FLOW_FLUSHING) { - qWarning()<<"appsrc: push buffer wrong state"; - } - } + + qint64 size; + if (m_stream) + size = m_stream->bytesAvailable(); + else + size = m_buffer.size(); + + size = qMin(size, (qint64)m_dataRequestSize); + + GstBuffer* buffer = gst_buffer_new_and_alloc(size); + + if (m_sequential) + buffer->offset = bytesReadSoFar; + else + buffer->offset = m_stream->pos(); + + if (m_format.isValid()) { + // timestamp raw audio data + uint nSamples = size/m_format.bytesPerSample(); + + GST_BUFFER_TIMESTAMP(buffer) = gst_util_uint64_scale(streamedSamples, GST_SECOND, m_format.sampleRate()); + GST_BUFFER_DURATION(buffer) = gst_util_uint64_scale(nSamples, GST_SECOND, m_format.sampleRate()); + streamedSamples += nSamples; + } + + GstMapInfo mapInfo; + gst_buffer_map(buffer, &mapInfo, GST_MAP_WRITE); + void* bufferData = mapInfo.data; + + qint64 bytesRead; + if (m_stream) + bytesRead = m_stream->read((char*)bufferData, size); + else + bytesRead = m_buffer.read((char*)bufferData, size); + buffer->offset_end = buffer->offset + bytesRead - 1; + bytesReadSoFar += bytesRead; + + gst_buffer_unmap(buffer, &mapInfo); + qCDebug(qLcAppSrc) << "pushing bytes into gstreamer" << buffer->offset << bytesRead; + if (bytesRead == 0) { + gst_buffer_unref(buffer); + eosOrIdle(); + return; + } + emit bytesProcessed(bytesRead); + + GstFlowReturn ret = gst_app_src_push_buffer(GST_APP_SRC(m_appSrc.element()), buffer); + if (ret == GST_FLOW_ERROR) { + qWarning() << "QGstAppSrc: push buffer error"; + } else if (ret == GST_FLOW_FLUSHING) { + qWarning() << "QGstAppSrc: push buffer wrong state"; } } bool QGstAppSrc::doSeek(qint64 value) { if (isStreamValid()) - return stream()->seek(value + initialPosition); + return m_stream->seek(value); return false; } -gboolean QGstAppSrc::on_seek_data(GstAppSrc *element, guint64 arg0, gpointer userdata) +gboolean QGstAppSrc::on_seek_data(GstAppSrc *, guint64 arg0, gpointer userdata) { // we do get some spurious seeks to INT_MAX, ignore those if (arg0 == std::numeric_limits<quint64>::max()) return true; - Q_UNUSED(element); + QGstAppSrc *self = reinterpret_cast<QGstAppSrc*>(userdata); - if (self && self->isStreamValid()) { - if (!self->stream()->isSequential()) - QMetaObject::invokeMethod(self, "doSeek", Qt::AutoConnection, Q_ARG(qint64, arg0)); - } - else + Q_ASSERT(self); + if (self->m_sequential) return false; + QMetaObject::invokeMethod(self, "doSeek", Qt::AutoConnection, Q_ARG(qint64, arg0)); return true; } -void QGstAppSrc::on_enough_data(GstAppSrc *element, gpointer userdata) +void QGstAppSrc::on_enough_data(GstAppSrc *, gpointer userdata) { qCDebug(qLcAppSrc) << "on_enough_data"; - Q_UNUSED(element); QGstAppSrc *self = static_cast<QGstAppSrc*>(userdata); - if (self) - self->m_enoughData = true; + Q_ASSERT(self); + self->m_dataRequestSize = 0; } -void QGstAppSrc::on_need_data(GstAppSrc *element, guint arg0, gpointer userdata) +void QGstAppSrc::on_need_data(GstAppSrc *, guint arg0, gpointer userdata) { qCDebug(qLcAppSrc) << "on_need_data requesting bytes" << arg0; - Q_UNUSED(element); QGstAppSrc *self = static_cast<QGstAppSrc*>(userdata); - if (self) { - self->m_dataRequested = true; - self->m_enoughData = false; - self->m_dataRequestSize = arg0; - QMetaObject::invokeMethod(self, "pushDataToAppSrc", Qt::AutoConnection); - } -} - -void QGstAppSrc::destroy_notify(gpointer data) -{ - Q_UNUSED(data); + Q_ASSERT(self); + self->m_dataRequestSize = arg0; + QMetaObject::invokeMethod(self, "pushData", Qt::AutoConnection); } void QGstAppSrc::sendEOS() { qCDebug(qLcAppSrc) << "sending EOS"; - if (!m_appSrc) + if (m_appSrc.isNull()) return; - gst_app_src_end_of_stream(GST_APP_SRC(m_appSrc)); + gst_app_src_end_of_stream(GST_APP_SRC(m_appSrc.element())); } void QGstAppSrc::eosOrIdle() { qCDebug(qLcAppSrc) << "eosOrIdle"; - if (!m_appSrc) + if (m_appSrc.isNull()) return; if (!m_sequential) { diff --git a/src/multimedia/platform/gstreamer/common/qgstappsrc_p.h b/src/multimedia/platform/gstreamer/common/qgstappsrc_p.h index 8a703f2ca..c72d0e06e 100644 --- a/src/multimedia/platform/gstreamer/common/qgstappsrc_p.h +++ b/src/multimedia/platform/gstreamer/common/qgstappsrc_p.h @@ -58,7 +58,7 @@ #include <QtCore/qiodevice.h> #include <QtCore/private/qringbuffer_p.h> -#include <gst/gst.h> +#include <private/qgst_p.h> #include <gst/app/gstappsrc.h> QT_BEGIN_NAMESPACE @@ -72,84 +72,57 @@ public: QGstAppSrc(QObject *parent = 0); ~QGstAppSrc(); - bool setup(GstElement *); + enum Flags { + NoFlags = 0, + ForceSequential = 1 + }; - void setStream(QIODevice *); - QIODevice *stream() const; + bool setup(QIODevice *stream = nullptr, Flags = NoFlags); + void setAudioFormat(const QAudioFormat &f); - void setBuffer(QRingBuffer *buffer) - { - Q_ASSERT(!m_stream); - m_buffer = buffer; - m_sequential = true; - } - QRingBuffer *buffer() const - { - return m_buffer; - } - - GstAppSrc *element(); - - qint64 queueSize() const { return m_maxBytes; } - - bool isStreamValid() const - { - return m_stream != nullptr && m_stream->isOpen(); - } + void setExternalAppSrc(const QGstElement &appsrc); + QGstElement element(); - void setAudioFormat(const QAudioFormat &f) - { - m_format = f; - } - QAudioFormat audioFormat() const - { - return m_format; - } + void write(const char *data, qsizetype size); - void newDataAvailable() - { - if (m_noMoreData) { - m_noMoreData = false; - pushDataToAppSrc(); - } - } + bool canAcceptMoreData() { return !m_noMoreData; } Q_SIGNALS: void bytesProcessed(int bytes); void noMoreData(); private Q_SLOTS: - void pushDataToAppSrc(); + void pushData(); bool doSeek(qint64); void onDataReady(); void streamDestroyed(); private: + bool setStream(QIODevice *, Flags flags); + bool isStreamValid() const + { + return m_stream != nullptr && m_stream->isOpen(); + } + static gboolean on_seek_data(GstAppSrc *element, guint64 arg0, gpointer userdata); static void on_enough_data(GstAppSrc *element, gpointer userdata); static void on_need_data(GstAppSrc *element, uint arg0, gpointer userdata); - static void destroy_notify(gpointer data); void sendEOS(); void eosOrIdle(); QIODevice *m_stream = nullptr; QNetworkReply *m_networkReply = nullptr; - QRingBuffer *m_buffer = nullptr; + QRingBuffer m_buffer; QAudioFormat m_format; - GstAppSrc *m_appSrc = nullptr; - bool m_sequential = false; + QGstElement m_appSrc; + bool m_sequential = true; bool m_noMoreData = false; GstAppStreamType m_streamType = GST_APP_STREAM_TYPE_RANDOM_ACCESS; - GstAppSrcCallbacks m_callbacks; - qint64 initialPosition = 0; qint64 m_maxBytes = 0; qint64 bytesReadSoFar = 0; - unsigned int m_dataRequestSize = ~0; - bool m_dataRequested = false; - bool m_enoughData = false; - bool m_forceData = false; + unsigned int m_dataRequestSize = 0; int streamedSamples = 0; }; diff --git a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp index 438b7576d..34bd2f8db 100644 --- a/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp @@ -582,14 +582,13 @@ void QGstreamerMediaPlayer::setMedia(const QUrl &content, QIODevice *stream) if (m_stream) { if (!m_appSrc) m_appSrc = new QGstAppSrc(this); - src = QGstElement("appsrc", "appsrc"); + src = m_appSrc->element(); decoder = QGstElement("decodebin", "decoder"); decoder.set("post-stream-topology", true); playerPipeline.add(src, decoder); src.link(decoder); - m_appSrc->setStream(m_stream); - m_appSrc->setup(src.element()); + m_appSrc->setup(m_stream); } else { // use uridecodebin decoder = QGstElement("uridecodebin", "uridecoder"); diff --git a/src/multimedia/platform/gstreamer/common/qgstutils.cpp b/src/multimedia/platform/gstreamer/common/qgstutils.cpp index 0ed867bf9..76b027f12 100644 --- a/src/multimedia/platform/gstreamer/common/qgstutils.cpp +++ b/src/multimedia/platform/gstreamer/common/qgstutils.cpp @@ -128,10 +128,10 @@ QAudioFormat QGstUtils::audioFormatForSample(GstSample *sample) Caller must unref GstCaps. */ -GstCaps *QGstUtils::capsForAudioFormat(const QAudioFormat &format) +QGstMutableCaps QGstUtils::capsForAudioFormat(const QAudioFormat &format) { if (!format.isValid()) - return nullptr; + return {}; auto sampleFormat = format.sampleFormat(); return gst_caps_new_simple( diff --git a/src/multimedia/platform/gstreamer/common/qgstutils_p.h b/src/multimedia/platform/gstreamer/common/qgstutils_p.h index e2bc35531..651152950 100644 --- a/src/multimedia/platform/gstreamer/common/qgstutils_p.h +++ b/src/multimedia/platform/gstreamer/common/qgstutils_p.h @@ -72,7 +72,7 @@ class QVideoFrameFormat; namespace QGstUtils { Q_MULTIMEDIA_EXPORT QAudioFormat audioFormatForSample(GstSample *sample); - Q_MULTIMEDIA_EXPORT GstCaps *capsForAudioFormat(const QAudioFormat &format); + Q_MULTIMEDIA_EXPORT QGstMutableCaps capsForAudioFormat(const QAudioFormat &format); Q_MULTIMEDIA_EXPORT QVideoFrameFormat formatForCaps( GstCaps *caps, diff --git a/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp b/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp index 5a6a0ded7..29a596df7 100644 --- a/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp +++ b/tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp @@ -424,8 +424,7 @@ void tst_QAudioOutput::pull() QString("didn't emit StoppedState signal after stop(), got %1 signals instead").arg(stateSignal.count()).toUtf8().constData()); QVERIFY2((audioOutput.state() == QAudio::StoppedState), "didn't transitions to StoppedState after stop()"); - QVERIFY2((processedUs == 1000000), - QString("processedUSecs() doesn't equal file duration in us (%1)").arg(processedUs).toUtf8().constData()); + QCOMPARE(processedUs, 1000000); QVERIFY2((audioOutput.error() == QAudio::NoError), "error() is not QAudio::NoError after stop()"); QVERIFY2((audioOutput.elapsedUSecs() == (qint64)0), "elapsedUSecs() not equal to zero in StoppedState"); |