summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--examples/multimedia/audiodecoder/audiodecoder.cpp2
-rw-r--r--src/multimedia/platform/gstreamer/audio/qaudioinput_gstreamer.cpp6
-rw-r--r--src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer.cpp29
-rw-r--r--src/multimedia/platform/gstreamer/audio/qaudiooutput_gstreamer_p.h1
-rw-r--r--src/multimedia/platform/gstreamer/audio/qgstreameraudiodecoder.cpp18
-rw-r--r--src/multimedia/platform/gstreamer/common/qgst_p.h3
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstappsrc.cpp264
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstappsrc_p.h71
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstreamermediaplayer.cpp5
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstutils.cpp4
-rw-r--r--src/multimedia/platform/gstreamer/common/qgstutils_p.h2
-rw-r--r--tests/auto/integration/qaudiooutput/tst_qaudiooutput.cpp3
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");