summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@qt.io>2019-06-03 11:18:47 +0200
committerLiang Qi <liang.qi@qt.io>2019-06-03 11:18:47 +0200
commitdfc0ee4975958f7144f04957b6d5856a28e99361 (patch)
tree249cc992e09e208c29369830af8cce6b0456a9bf /src
parent7ef21f7ed206749252fbd03f673a8588890828b1 (diff)
parent3bbeae539854c1474844c65025d40b813cec286c (diff)
Merge remote-tracking branch 'origin/5.12' into 5.13
Conflicts: src/plugins/directshow/player/directshowplayerservice.cpp Change-Id: I6b7edc312ecfadf84653ce24321ec55da41e131a
Diffstat (limited to 'src')
-rw-r--r--src/gsttools/qgstreamerplayersession.cpp136
-rw-r--r--src/gsttools/qgstreamerplayersession_p.h3
-rw-r--r--src/gsttools/qgstvideorenderersink.cpp3
-rw-r--r--src/multimediawidgets/qpaintervideosurface.cpp25
-rw-r--r--src/plugins/common/evr/evrd3dpresentengine.cpp10
-rw-r--r--src/plugins/directshow/player/directshowplayercontrol.cpp3
-rw-r--r--src/plugins/directshow/player/directshowplayerservice.cpp25
-rw-r--r--src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp5
8 files changed, 130 insertions, 80 deletions
diff --git a/src/gsttools/qgstreamerplayersession.cpp b/src/gsttools/qgstreamerplayersession.cpp
index 1e099fc89..5ede8a1c9 100644
--- a/src/gsttools/qgstreamerplayersession.cpp
+++ b/src/gsttools/qgstreamerplayersession.cpp
@@ -61,9 +61,9 @@
#include <QtCore/qdir.h>
#include <QtCore/qstandardpaths.h>
#include <qvideorenderercontrol.h>
+#include <QUrlQuery>
//#define DEBUG_PLAYBIN
-//#define DEBUG_VO_BIN_DUMP
QT_BEGIN_NAMESPACE
@@ -306,7 +306,7 @@ void QGstreamerPlayerSession::loadFromStream(const QNetworkRequest &request, QIO
m_appSrc = new QGstAppSrc(this);
m_appSrc->setStream(appSrcStream);
- if (m_playbin) {
+ if (!parsePipeline() && m_playbin) {
m_tags.clear();
emit tagsChanged();
@@ -338,28 +338,7 @@ void QGstreamerPlayerSession::loadFromUri(const QNetworkRequest &request)
}
#endif
- if (m_request.url().scheme() == QLatin1String("gst-pipeline")) {
- // Set current surface to video sink before creating a pipeline.
- auto renderer = qobject_cast<QVideoRendererControl*>(m_videoOutput);
- if (renderer)
- QVideoSurfaceGstSink::setSurface(renderer->surface());
-
- QString url = m_request.url().toString(QUrl::RemoveScheme);
- QString pipeline = QUrl::fromPercentEncoding(url.toLatin1().constData());
- GError *err = nullptr;
- GstElement *element = gst_parse_launch(pipeline.toLatin1().constData(), &err);
- if (err) {
- auto errstr = QLatin1String(err->message);
- qWarning() << "Error:" << pipeline << ":" << errstr;
- emit error(QMediaPlayer::FormatError, errstr);
- g_clear_error(&err);
- }
-
- setPipeline(element);
- return;
- }
-
- if (m_playbin) {
+ if (!parsePipeline() && m_playbin) {
m_tags.clear();
emit tagsChanged();
@@ -374,17 +353,61 @@ void QGstreamerPlayerSession::loadFromUri(const QNetworkRequest &request)
}
}
-void QGstreamerPlayerSession::setPipeline(GstElement *pipeline)
+bool QGstreamerPlayerSession::parsePipeline()
+{
+ if (m_request.url().scheme() != QLatin1String("gst-pipeline"))
+ return false;
+
+ // Set current surface to video sink before creating a pipeline.
+ auto renderer = qobject_cast<QVideoRendererControl *>(m_videoOutput);
+ if (renderer)
+ QVideoSurfaceGstSink::setSurface(renderer->surface());
+
+ QString url = m_request.url().toString(QUrl::RemoveScheme);
+ QString desc = QUrl::fromPercentEncoding(url.toLatin1().constData());
+ GError *err = nullptr;
+ GstElement *pipeline = gst_parse_launch(desc.toLatin1().constData(), &err);
+ if (err) {
+ auto errstr = QLatin1String(err->message);
+ qWarning() << "Error:" << desc << ":" << errstr;
+ emit error(QMediaPlayer::FormatError, errstr);
+ g_clear_error(&err);
+ }
+
+ return setPipeline(pipeline);
+}
+
+static void gst_foreach(GstIterator *it, const std::function<bool(GstElement *)> &cmp)
+{
+#if GST_CHECK_VERSION(1,0,0)
+ GValue value = G_VALUE_INIT;
+ while (gst_iterator_next (it, &value) == GST_ITERATOR_OK) {
+ auto child = static_cast<GstElement*>(g_value_get_object(&value));
+#else
+ GstElement *child = nullptr;
+ while (gst_iterator_next(it, reinterpret_cast<gpointer *>(&child)) == GST_ITERATOR_OK) {
+#endif
+ if (cmp(child))
+ break;
+ }
+
+ gst_iterator_free(it);
+#if GST_CHECK_VERSION(1,0,0)
+ g_value_unset(&value);
+#endif
+}
+
+bool QGstreamerPlayerSession::setPipeline(GstElement *pipeline)
{
GstBus *bus = pipeline ? gst_element_get_bus(pipeline) : nullptr;
if (!bus)
- return;
+ return false;
gst_object_unref(GST_OBJECT(m_pipeline));
m_pipeline = pipeline;
gst_object_unref(GST_OBJECT(m_bus));
m_bus = bus;
- delete m_busHelper;
+ m_busHelper->deleteLater();
m_busHelper = new QGstreamerBusHelper(m_bus, this);
m_busHelper->installMessageFilter(this);
@@ -401,24 +424,31 @@ void QGstreamerPlayerSession::setPipeline(GstElement *pipeline)
m_videoIdentity = nullptr;
if (m_renderer) {
- auto it = gst_bin_iterate_sinks(GST_BIN(pipeline));
-#if GST_CHECK_VERSION(1,0,0)
- GValue data = { 0, 0 };
- while (gst_iterator_next (it, &data) == GST_ITERATOR_OK) {
- auto child = static_cast<GstElement*>(g_value_get_object(&data));
-#else
- GstElement *child = nullptr;
- while (gst_iterator_next(it, reinterpret_cast<gpointer *>(&child)) == GST_ITERATOR_OK) {
-#endif
- if (QLatin1String(GST_OBJECT_NAME(child)) == QLatin1String("qtvideosink")) {
- m_renderer->setVideoSink(child);
- break;
- }
- }
- gst_iterator_free(it);
+ gst_foreach(gst_bin_iterate_sinks(GST_BIN(pipeline)),
+ [this](GstElement *child) {
+ if (qstrcmp(GST_OBJECT_NAME(child), "qtvideosink") == 0) {
+ m_renderer->setVideoSink(child);
+ return true;
+ }
+ return false;
+ });
}
+#if QT_CONFIG(gstreamer_app)
+ if (m_appSrc) {
+ gst_foreach(gst_bin_iterate_sources(GST_BIN(pipeline)),
+ [this](GstElement *child) {
+ if (qstrcmp(qt_gst_element_get_factory_name(child), "appsrc") == 0) {
+ m_appSrc->setup(child);
+ return true;
+ }
+ return false;
+ });
+ }
+#endif
+
emit pipelineChanged();
+ return true;
}
qint64 QGstreamerPlayerSession::duration() const
@@ -629,12 +659,6 @@ void QGstreamerPlayerSession::setVideoRenderer(QObject *videoOutput)
if (!m_playbin)
return;
-#ifdef DEBUG_VO_BIN_DUMP
- gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_playbin),
- GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /* GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES*/),
- "playbin_set");
-#endif
-
GstElement *videoSink = 0;
if (m_renderer && m_renderer->isReady())
videoSink = m_renderer->videoSink();
@@ -895,11 +919,6 @@ void QGstreamerPlayerSession::finishVideoOutputChange()
gst_object_unref(GST_OBJECT(srcPad));
-#ifdef DEBUG_VO_BIN_DUMP
- gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_playbin),
- GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL /* | GST_DEBUG_GRAPH_SHOW_MEDIA_TYPE | GST_DEBUG_GRAPH_SHOW_NON_DEFAULT_PARAMS | GST_DEBUG_GRAPH_SHOW_STATES */),
- "playbin_finish");
-#endif
}
#if !GST_CHECK_VERSION(1,0,0)
@@ -962,6 +981,9 @@ bool QGstreamerPlayerSession::isSeekable() const
bool QGstreamerPlayerSession::play()
{
+ static bool dumpDot = qEnvironmentVariableIsSet("GST_DEBUG_DUMP_DOT_DIR");
+ if (dumpDot)
+ gst_debug_bin_to_dot_file_with_ts(GST_BIN(m_pipeline), GstDebugGraphDetails(GST_DEBUG_GRAPH_SHOW_ALL), "session.play");
#ifdef DEBUG_PLAYBIN
qDebug() << Q_FUNC_INFO;
#endif
@@ -1637,6 +1659,14 @@ void QGstreamerPlayerSession::playbinNotifySource(GObject *o, GParamSpec *p, gpo
self->m_sourceType = UDPSrc;
//The udpsrc is always a live source.
self->m_isLiveSource = true;
+
+ QUrlQuery query(self->m_request.url());
+ const QString var = QLatin1String("udpsrc.caps");
+ if (query.hasQueryItem(var)) {
+ GstCaps *caps = gst_caps_from_string(query.queryItemValue(var).toLatin1().constData());
+ g_object_set(G_OBJECT(source), "caps", caps, NULL);
+ gst_caps_unref(caps);
+ }
} else if (qstrcmp(G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(source)), "GstSoupHTTPSrc") == 0) {
//souphttpsrc timeout unit = second
g_object_set(G_OBJECT(source), "timeout", guint(timeout), NULL);
diff --git a/src/gsttools/qgstreamerplayersession_p.h b/src/gsttools/qgstreamerplayersession_p.h
index b613793c4..d4b050272 100644
--- a/src/gsttools/qgstreamerplayersession_p.h
+++ b/src/gsttools/qgstreamerplayersession_p.h
@@ -208,7 +208,8 @@ private:
void addAudioBufferProbe();
void flushVideoProbes();
void resumeVideoProbes();
- void setPipeline(GstElement *pipeline);
+ bool parsePipeline();
+ bool setPipeline(GstElement *pipeline);
QNetworkRequest m_request;
QMediaPlayer::State m_state;
diff --git a/src/gsttools/qgstvideorenderersink.cpp b/src/gsttools/qgstvideorenderersink.cpp
index 09fdd42a6..c3a7a5988 100644
--- a/src/gsttools/qgstvideorenderersink.cpp
+++ b/src/gsttools/qgstvideorenderersink.cpp
@@ -516,7 +516,8 @@ void QGstVideoRendererSink::handleShowPrerollChange(GObject *o, GParamSpec *p, g
if (!showPrerollFrame) {
GstState state = GST_STATE_VOID_PENDING;
- gst_element_get_state(GST_ELEMENT(sink), &state, NULL, GST_CLOCK_TIME_NONE);
+ GstClockTime timeout = 10000000; // 10 ms
+ gst_element_get_state(GST_ELEMENT(sink), &state, NULL, timeout);
// show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means
// the QMediaPlayer was stopped from the paused state.
// We need to flush the current frame.
diff --git a/src/multimediawidgets/qpaintervideosurface.cpp b/src/multimediawidgets/qpaintervideosurface.cpp
index e4762a7e1..440d5c858 100644
--- a/src/multimediawidgets/qpaintervideosurface.cpp
+++ b/src/multimediawidgets/qpaintervideosurface.cpp
@@ -62,6 +62,15 @@
#include <QtDebug>
QT_BEGIN_NAMESPACE
+static void makeCurrent(QGLContext *context)
+{
+ context->makeCurrent();
+
+ auto handle = context->contextHandle();
+ if (handle && QOpenGLContext::currentContext() != handle)
+ handle->makeCurrent(handle->surface());
+}
+
QVideoSurfacePainter::~QVideoSurfacePainter()
{
}
@@ -395,7 +404,7 @@ QAbstractVideoSurface::Error QVideoSurfaceGLPainter::setCurrentFrame(const QVide
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
} else if (m_frame.map(QAbstractVideoBuffer::ReadOnly)) {
- m_context->makeCurrent();
+ makeCurrent(m_context);
for (int i = 0; i < m_textureCount; ++i) {
glBindTexture(GL_TEXTURE_2D, m_textureIds[i]);
@@ -737,7 +746,7 @@ QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::start(const QVideoSurfac
QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError;
- m_context->makeCurrent();
+ makeCurrent(m_context);
const char *program = 0;
@@ -862,7 +871,7 @@ QAbstractVideoSurface::Error QVideoSurfaceArbFpPainter::start(const QVideoSurfac
void QVideoSurfaceArbFpPainter::stop()
{
if (m_context) {
- m_context->makeCurrent();
+ makeCurrent(m_context);
if (m_handleType != QAbstractVideoBuffer::GLTextureHandle)
glDeleteTextures(m_textureCount, m_textureIds);
@@ -1115,7 +1124,7 @@ QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::start(const QVideoSurface
QAbstractVideoSurface::Error error = QAbstractVideoSurface::NoError;
- m_context->makeCurrent();
+ makeCurrent(m_context);
const char *fragmentProgram = 0;
@@ -1222,7 +1231,7 @@ QAbstractVideoSurface::Error QVideoSurfaceGlslPainter::start(const QVideoSurface
void QVideoSurfaceGlslPainter::stop()
{
if (m_context) {
- m_context->makeCurrent();
+ makeCurrent(m_context);
if (m_handleType != QAbstractVideoBuffer::GLTextureHandle)
glDeleteTextures(m_textureCount, m_textureIds);
@@ -1623,7 +1632,7 @@ void QPainterVideoSurface::setGLContext(QGLContext *context)
//Set a dynamic property to access the OpenGL context
this->setProperty("GLContext", QVariant::fromValue<QObject*>(m_glContext->contextHandle()));
- m_glContext->makeCurrent();
+ makeCurrent(m_glContext);
const QByteArray extensions(reinterpret_cast<const char *>(
context->contextHandle()->functions()->glGetString(GL_EXTENSIONS)));
@@ -1734,13 +1743,13 @@ void QPainterVideoSurface::createPainter()
#if !defined(QT_OPENGL_ES) && !defined(QT_OPENGL_DYNAMIC)
case FragmentProgramShader:
Q_ASSERT(m_glContext);
- m_glContext->makeCurrent();
+ makeCurrent(m_glContext);
m_painter = new QVideoSurfaceArbFpPainter(m_glContext);
break;
#endif // !QT_OPENGL_ES && !QT_OPENGL_DYNAMIC
case GlslShader:
Q_ASSERT(m_glContext);
- m_glContext->makeCurrent();
+ makeCurrent(m_glContext);
m_painter = new QVideoSurfaceGlslPainter(m_glContext);
break;
default:
diff --git a/src/plugins/common/evr/evrd3dpresentengine.cpp b/src/plugins/common/evr/evrd3dpresentengine.cpp
index ab694b795..4ce5a99d7 100644
--- a/src/plugins/common/evr/evrd3dpresentengine.cpp
+++ b/src/plugins/common/evr/evrd3dpresentengine.cpp
@@ -593,16 +593,6 @@ QVideoFrame D3DPresentEngine::makeVideoFrame(IMFSample *sample)
m_surfaceFormat.frameSize(),
m_surfaceFormat.pixelFormat());
- // WMF uses 100-nanosecond units, Qt uses microseconds
- LONGLONG startTime = -1;
- if (SUCCEEDED(sample->GetSampleTime(&startTime))) {
- frame.setStartTime(startTime * 0.1);
-
- LONGLONG duration = -1;
- if (SUCCEEDED(sample->GetSampleDuration(&duration)))
- frame.setEndTime((startTime + duration) * 0.1);
- }
-
return frame;
}
diff --git a/src/plugins/directshow/player/directshowplayercontrol.cpp b/src/plugins/directshow/player/directshowplayercontrol.cpp
index 2d0ee2d59..7de0a686f 100644
--- a/src/plugins/directshow/player/directshowplayercontrol.cpp
+++ b/src/plugins/directshow/player/directshowplayercontrol.cpp
@@ -219,6 +219,9 @@ const QIODevice *DirectShowPlayerControl::mediaStream() const
void DirectShowPlayerControl::setMedia(const QMediaContent &media, QIODevice *stream)
{
+ if (m_media == media)
+ return;
+
m_pendingPosition = -1;
m_emitPosition = -1;
diff --git a/src/plugins/directshow/player/directshowplayerservice.cpp b/src/plugins/directshow/player/directshowplayerservice.cpp
index 3f7346227..5f7c65ad0 100644
--- a/src/plugins/directshow/player/directshowplayerservice.cpp
+++ b/src/plugins/directshow/player/directshowplayerservice.cpp
@@ -408,8 +408,6 @@ void DirectShowPlayerService::doSetUrlSource(QMutexLocker *locker)
m_pendingTasks |= SetRate;
m_source = source;
- } else if (!m_url.isEmpty()) {
- m_pendingTasks |= SetUrlSource;
} else {
m_graphStatus = InvalidMedia;
@@ -531,9 +529,16 @@ void DirectShowPlayerService::doRender(QMutexLocker *locker)
} else {
locker->unlock();
HRESULT hr = graph->RenderEx(pin, /*AM_RENDEREX_RENDERTOEXISTINGRENDERERS*/ 1, 0);
- // Do not return an error if no video output is set yet.
- if (SUCCEEDED(hr) || !(m_executedTasks & SetVideoOutput)) {
+ if (SUCCEEDED(hr)) {
rendered = true;
+ m_error = QMediaPlayer::NoError;
+ } else if (!(m_executedTasks & SetVideoOutput)) {
+ // Do not return an error if no video output is set yet.
+ rendered = true;
+ // Remember the error in this case.
+ // Handle it when playing is requested and no video output has been provided.
+ m_error = QMediaPlayer::ResourceError;
+ m_errorString = QString("%1: %2").arg(__FUNCTION__).arg(qt_error_string(hr));
} else if (renderHr == S_OK || renderHr == VFW_E_NO_DECOMPRESSOR){
renderHr = hr;
}
@@ -914,6 +919,16 @@ void DirectShowPlayerService::play()
void DirectShowPlayerService::doPlay(QMutexLocker *locker)
{
+ // Invalidate if there is an error while loading.
+ if (m_error != QMediaPlayer::NoError) {
+ m_graphStatus = InvalidMedia;
+ if (!m_errorString.isEmpty())
+ qWarning("%s", qPrintable(m_errorString));
+ m_errorString = QString();
+ QCoreApplication::postEvent(this, new QEvent(QEvent::Type(Error)));
+ return;
+ }
+
if (IMediaControl *control = com_cast<IMediaControl>(m_graph, IID_IMediaControl)) {
locker->unlock();
HRESULT hr = control->Run();
@@ -1615,7 +1630,7 @@ void DirectShowPlayerService::updateStatus()
m_playerControl->updateStatus(QMediaPlayer::LoadingMedia);
break;
case Loaded:
- if ((m_pendingTasks | m_executingTask | m_executedTasks) & (Play | Pause)) {
+ if ((m_executingTask | m_executedTasks) & (Play | Pause)) {
if (m_buffering)
m_playerControl->updateStatus(QMediaPlayer::BufferingMedia);
else
diff --git a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp
index c054c0f76..70e7fbce5 100644
--- a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp
+++ b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp
@@ -396,7 +396,7 @@ QList<QByteArray> QWindowsAudioDeviceInfo::availableDevices(QAudio::Mode mode)
QList<QByteArray> devices;
//enumerate device fullnames through directshow api
- CoInitialize(NULL);
+ auto hrCoInit = CoInitialize(nullptr);
ICreateDevEnum *pDevEnum = NULL;
IEnumMoniker *pEnum = NULL;
// Create the System device enumerator
@@ -447,7 +447,8 @@ QList<QByteArray> QWindowsAudioDeviceInfo::availableDevices(QAudio::Mode mode)
}
pDevEnum->Release();
}
- CoUninitialize();
+ if (SUCCEEDED(hrCoInit))
+ CoUninitialize();
return devices;
}