From 370c48039bfa0fe4325852358d603cf4438c3f47 Mon Sep 17 00:00:00 2001 From: James McDonnell Date: Thu, 15 Mar 2018 10:39:07 -0400 Subject: Switch WindowGrabber to a private parent window The code that it was using to retrieve a parent window didn't always get the right window. Using a private window prevents any confusion. Change-Id: Ic368460c6bf150891ff51f1f3b00bbe93c6cf780 Reviewed-by: Rafael Roquetto --- src/plugins/qnx/common/windowgrabber.cpp | 42 ++++++++++++++++++-------------- src/plugins/qnx/common/windowgrabber.h | 1 + 2 files changed, 25 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/plugins/qnx/common/windowgrabber.cpp b/src/plugins/qnx/common/windowgrabber.cpp index ca7224a4f..9a65ad3a0 100644 --- a/src/plugins/qnx/common/windowgrabber.cpp +++ b/src/plugins/qnx/common/windowgrabber.cpp @@ -58,6 +58,7 @@ static PFNEGLDESTROYIMAGEKHRPROC s_eglDestroyImageKHR; WindowGrabber::WindowGrabber(QObject *parent) : QObject(parent), + m_windowParent(nullptr), m_screenContext(0), m_active(false), m_currentFrame(0), @@ -81,10 +82,26 @@ WindowGrabber::WindowGrabber(QObject *parent) s_eglCreateImageKHR = reinterpret_cast(eglGetProcAddress("eglCreateImageKHR")); s_eglDestroyImageKHR = reinterpret_cast(eglGetProcAddress("eglDestroyImageKHR")); } + + QPlatformNativeInterface *const nativeInterface = QGuiApplication::platformNativeInterface(); + if (nativeInterface) { + m_screenContext = static_cast( + nativeInterface->nativeResourceForIntegration("screenContext")); + } + + // Create a parent window for the window whose content will be grabbed. Since the + // window is only a buffer conduit, the characteristics of the parent window are + // irrelevant. The contents of the window can be grabbed so long as the window + // joins the parent window's group and the parent window is in this process. + // Using the window that displays this content isn't possible because there's no + // way to reliably retrieve it from this code or any calling code. + screen_create_window(&m_windowParent, m_screenContext); + screen_create_window_group(m_windowParent, nullptr); } WindowGrabber::~WindowGrabber() { + screen_destroy_window(m_windowParent); QCoreApplication::eventDispatcher()->removeNativeEventFilter(this); cleanup(); } @@ -184,24 +201,13 @@ bool WindowGrabber::nativeEventFilter(const QByteArray &eventType, void *message QByteArray WindowGrabber::windowGroupId() const { - QWindow *window = QGuiApplication::allWindows().isEmpty() ? 0 : QGuiApplication::allWindows().first(); - if (!window) - return QByteArray(); - - QPlatformNativeInterface * const nativeInterface = QGuiApplication::platformNativeInterface(); - if (!nativeInterface) { - qWarning() << "WindowGrabber: Unable to get platform native interface"; - return QByteArray(); - } - - const char * const groupIdData = static_cast( - nativeInterface->nativeResourceForWindow("windowGroup", window)); - if (!groupIdData) { - qWarning() << "WindowGrabber: Unable to find window group for window" << window; - return QByteArray(); - } - - return QByteArray(groupIdData); + char groupName[256]; + memset(groupName, 0, sizeof(groupName)); + screen_get_window_property_cv(m_windowParent, + SCREEN_PROPERTY_GROUP, + sizeof(groupName) - 1, + groupName); + return QByteArray(groupName); } bool WindowGrabber::eglImageSupported() diff --git a/src/plugins/qnx/common/windowgrabber.h b/src/plugins/qnx/common/windowgrabber.h index 4b2217f74..3ebd0e8a6 100644 --- a/src/plugins/qnx/common/windowgrabber.h +++ b/src/plugins/qnx/common/windowgrabber.h @@ -126,6 +126,7 @@ private: QByteArray m_windowId; + screen_window_t m_windowParent; screen_window_t m_window; screen_context_t m_screenContext; -- cgit v1.2.3 From 24664700b3162bb67ff2e28a1de2505fb76c3e0b Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Tue, 2 Jan 2018 17:27:33 +0100 Subject: DirectShow: Fix crackling when playing custom sample rate Seems waveOutWrite() requires WAVEHDR->dwBufferLength to be even number otherwise some crackling might be heard while playing. And looks like it is not related to QAudioFormat, any of it produces the issue. Task-number: QTBUG-64931 Change-Id: I87dbe165611325d9c0291a3bffdc091397b42741 Reviewed-by: Maurice Kalinowski --- src/plugins/windowsaudio/qwindowsaudiooutput.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp index eb4caf128..d1c0b475f 100644 --- a/src/plugins/windowsaudio/qwindowsaudiooutput.cpp +++ b/src/plugins/windowsaudio/qwindowsaudiooutput.cpp @@ -241,6 +241,10 @@ bool QWindowsAudioOutput::open() period_size = buffer_size / 5; } + // Make even size of wave block to prevent crackling + // due to waveOutWrite() does not like odd buffer length + period_size &= ~1; + if (period_size == 0) { errorState = QAudio::OpenError; deviceState = QAudio::StoppedState; -- cgit v1.2.3 From 5096d40486a86ec05dca539bcb82d05c795aab6f Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Wed, 10 Jan 2018 16:12:36 +0100 Subject: Set geometry for recreated video renderer backend If video renderer backend has been recreated, then it needs to update its geometry. Which previously didn't happen and as a result no content was shown. The geometry is now updated from within the video node. Task-number: QTBUG-54680 Change-Id: Iadbf324f4734c9ac6c487eaedd014629ca330599 Reviewed-by: Christian Stromme --- src/qtmultimediaquicktools/qdeclarativevideooutput.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp index 4fc768438..3c6a6f9c5 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp @@ -263,17 +263,16 @@ bool QDeclarativeVideoOutput::createBackend(QMediaService *service) backendAvailable = true; } - if (!backendAvailable) { - qWarning() << Q_FUNC_INFO << "Media service has neither renderer nor window control available."; - m_backend.reset(); - } else if (!m_geometryDirty) { - m_backend->updateGeometry(); - } + if (backendAvailable) { + // Since new backend has been created needs to update its geometry. + m_geometryDirty = true; - if (m_backend) { m_backend->clearFilters(); for (int i = 0; i < m_filters.count(); ++i) m_backend->appendFilter(m_filters[i]); + } else { + qWarning() << Q_FUNC_INFO << "Media service has neither renderer nor window control available."; + m_backend.reset(); } return backendAvailable; -- cgit v1.2.3 From 84d0d87699a2a92b3207beae30a52f25e23acb65 Mon Sep 17 00:00:00 2001 From: VaL Doroshchuk Date: Mon, 7 May 2018 12:47:02 +0200 Subject: CameraBin: Postpone fetching supported viewfinder settings Fetching caps from video source might take sometime and hang ui thread. Currently the caps are fetched when the camera gets ready which produces a hang. Proposed a fix to postpone fetching caps when requested and not when camera loaded. Task-number: QTBUG-67920 Change-Id: I7734ef96c98b2c425714eacc1fd1222fd7ee5c44 Reviewed-by: Christian Stromme --- .../gstreamer/camerabin/camerabinsession.cpp | 80 ++++++++++++---------- src/plugins/gstreamer/camerabin/camerabinsession.h | 3 +- 2 files changed, 43 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.cpp b/src/plugins/gstreamer/camerabin/camerabinsession.cpp index 3bb6ebffb..d7a96d333 100644 --- a/src/plugins/gstreamer/camerabin/camerabinsession.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinsession.cpp @@ -363,9 +363,9 @@ void CameraBinSession::setupCaptureResolution() Both = 0x4 }; quint8 found = Nothing; - - for (int i = 0; i < m_supportedViewfinderSettings.count() && !(found & Both); ++i) { - const QCameraViewfinderSettings &s = m_supportedViewfinderSettings.at(i); + auto viewfinderSettings = supportedViewfinderSettings(); + for (int i = 0; i < viewfinderSettings.count() && !(found & Both); ++i) { + const QCameraViewfinderSettings &s = viewfinderSettings.at(i); if (s.resolution() == viewfinderResolution) { if ((qFuzzyIsNull(viewfinderFrameRate) || s.maximumFrameRate() == viewfinderFrameRate) && (viewfinderPixelFormat == QVideoFrame::Format_Invalid || s.pixelFormat() == viewfinderPixelFormat)) @@ -676,8 +676,46 @@ void CameraBinSession::setViewfinder(QObject *viewfinder) } } +static QList capsToViewfinderSettings(GstCaps *supportedCaps) +{ + QList settings; + + if (!supportedCaps) + return settings; + + supportedCaps = qt_gst_caps_normalize(supportedCaps); + + // Convert caps to QCameraViewfinderSettings + for (uint i = 0; i < gst_caps_get_size(supportedCaps); ++i) { + const GstStructure *structure = gst_caps_get_structure(supportedCaps, i); + + QCameraViewfinderSettings s; + s.setResolution(QGstUtils::structureResolution(structure)); + s.setPixelFormat(QGstUtils::structurePixelFormat(structure)); + s.setPixelAspectRatio(QGstUtils::structurePixelAspectRatio(structure)); + + QPair frameRateRange = QGstUtils::structureFrameRateRange(structure); + s.setMinimumFrameRate(frameRateRange.first); + s.setMaximumFrameRate(frameRateRange.second); + + if (!s.resolution().isEmpty() + && s.pixelFormat() != QVideoFrame::Format_Invalid + && !settings.contains(s)) { + settings.append(s); + } + } + + gst_caps_unref(supportedCaps); + return settings; +} + QList CameraBinSession::supportedViewfinderSettings() const { + if (m_status == QCamera::LoadedStatus && m_supportedViewfinderSettings.isEmpty()) { + m_supportedViewfinderSettings = + capsToViewfinderSettings(supportedCaps(QCamera::CaptureViewfinder)); + } + return m_supportedViewfinderSettings; } @@ -1075,7 +1113,7 @@ bool CameraBinSession::processBusMessage(const QGstreamerMessage &message) break; case GST_STATE_READY: if (oldState == GST_STATE_NULL) - updateSupportedViewfinderSettings(); + m_supportedViewfinderSettings.clear(); setMetaData(m_metaData); setStatus(QCamera::LoadedStatus); @@ -1453,40 +1491,6 @@ QList CameraBinSession::supportedResolutions(QPair rate, return res; } -void CameraBinSession::updateSupportedViewfinderSettings() -{ - m_supportedViewfinderSettings.clear(); - - GstCaps *supportedCaps = this->supportedCaps(QCamera::CaptureViewfinder); - - // Convert caps to QCameraViewfinderSettings - if (supportedCaps) { - supportedCaps = qt_gst_caps_normalize(supportedCaps); - - for (uint i = 0; i < gst_caps_get_size(supportedCaps); i++) { - const GstStructure *structure = gst_caps_get_structure(supportedCaps, i); - - QCameraViewfinderSettings s; - s.setResolution(QGstUtils::structureResolution(structure)); - s.setPixelFormat(QGstUtils::structurePixelFormat(structure)); - s.setPixelAspectRatio(QGstUtils::structurePixelAspectRatio(structure)); - - QPair frameRateRange = QGstUtils::structureFrameRateRange(structure); - s.setMinimumFrameRate(frameRateRange.first); - s.setMaximumFrameRate(frameRateRange.second); - - if (!s.resolution().isEmpty() - && s.pixelFormat() != QVideoFrame::Format_Invalid - && !m_supportedViewfinderSettings.contains(s)) { - - m_supportedViewfinderSettings.append(s); - } - } - - gst_caps_unref(supportedCaps); - } -} - void CameraBinSession::elementAdded(GstBin *, GstElement *element, CameraBinSession *session) { GstElementFactory *factory = gst_element_get_factory(element); diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.h b/src/plugins/gstreamer/camerabin/camerabinsession.h index d5c2d7822..999398fa4 100644 --- a/src/plugins/gstreamer/camerabin/camerabinsession.h +++ b/src/plugins/gstreamer/camerabin/camerabinsession.h @@ -203,7 +203,6 @@ private: bool setupCameraBin(); void setAudioCaptureCaps(); GstCaps *supportedCaps(QCamera::CaptureModes mode) const; - void updateSupportedViewfinderSettings(); static void updateBusyStatus(GObject *o, GParamSpec *p, gpointer d); QString currentContainerFormat() const; @@ -229,7 +228,7 @@ private: QGstreamerElementFactory *m_videoInputFactory; QObject *m_viewfinder; QGstreamerVideoRendererInterface *m_viewfinderInterface; - QList m_supportedViewfinderSettings; + mutable QList m_supportedViewfinderSettings; QCameraViewfinderSettings m_viewfinderSettings; QCameraViewfinderSettings m_actualViewfinderSettings; -- cgit v1.2.3 From 0675d111de8bb1b96bfceeaa13448595b06b9e7c Mon Sep 17 00:00:00 2001 From: VaL Doroshchuk Date: Mon, 7 May 2018 09:58:54 +0200 Subject: Gstreamer: Show warning on error from QGstreamerRecorderControl Need to show errors returned from QGstreamerRecorderControl. Also if QGstreamerCaptureSession emits an error this error will be proxied to QGstreamerRecorderControl and back to QGstreamerCaptureSession to show it. Task-number: QTBUG-67706 Change-Id: I285a968b15a4cc8ab1e8e99e83f8dd7e2659a1d1 Reviewed-by: Christian Stromme --- src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp index 609670b81..b268592c6 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp +++ b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp @@ -103,6 +103,9 @@ QGstreamerCaptureSession::QGstreamerCaptureSession(QGstreamerCaptureSession::Cap m_videoEncodeControl = new QGstreamerVideoEncode(this); m_imageEncodeControl = new QGstreamerImageEncode(this); m_recorderControl = new QGstreamerRecorderControl(this); + connect(m_recorderControl, &QGstreamerRecorderControl::error, [](int e, const QString &str) { + qWarning() << QMediaRecorder::Error(e) << ":" << str.toLatin1().constData(); + }); m_mediaContainerControl = new QGstreamerMediaContainerControl(this); setState(StoppedState); -- cgit v1.2.3 From a0049de16d9e2a92b8d31b1ee6943c994ffdf7d2 Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Tue, 10 Oct 2017 13:24:27 +0200 Subject: Fix adjusting volume for default device Using WAVE_MAPPER device id (which points to default device) is not possible to get and initialize a mixer object to set volume. Function mixerGetID() does not support WAVE_MAPPER as a device id yet. Since we do not know device number anymore needs to call waveInOpen() first and after that initialize mixer controls using hWaveIn handler. - Fixed default volume from 0.0f -> 1.0f. - Before QWindowsAudioInput::start() is called, use cached volume. - After QWindowsAudioInput::start(), mixer controls are initialized. - QWindowsAudioInput::stop() deinitializes mixer controls. Task-number: QTBUG-61920 Change-Id: I5a94dad282618fb4a2e0f75c34008ca002bd1aeb Reviewed-by: Maurice Kalinowski --- src/plugins/windowsaudio/qwindowsaudioinput.cpp | 25 ++++++++++--------------- src/plugins/windowsaudio/qwindowsaudioinput.h | 1 + 2 files changed, 11 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/plugins/windowsaudio/qwindowsaudioinput.cpp b/src/plugins/windowsaudio/qwindowsaudioinput.cpp index 4771fe1cc..00b36cfe4 100644 --- a/src/plugins/windowsaudio/qwindowsaudioinput.cpp +++ b/src/plugins/windowsaudio/qwindowsaudioinput.cpp @@ -74,14 +74,13 @@ QWindowsAudioInput::QWindowsAudioInput(const QByteArray &device) waveBlockOffset = 0; mixerID = 0; + cachedVolume = 1.0f; memset(&mixerLineControls, 0, sizeof(mixerLineControls)); - initMixer(); } QWindowsAudioInput::~QWindowsAudioInput() { stop(); - closeMixer(); } void QT_WIN_CALLBACK QWindowsAudioInput::waveInProc( HWAVEIN hWaveIn, UINT uMsg, @@ -183,6 +182,7 @@ QAudio::State QWindowsAudioInput::state() const void QWindowsAudioInput::setVolume(qreal volume) { + cachedVolume = volume; for (DWORD i = 0; i < mixerLineControls.cControls; i++) { MIXERCONTROLDETAILS controlDetails; @@ -204,7 +204,6 @@ void QWindowsAudioInput::setVolume(qreal volume) qreal QWindowsAudioInput::volume() const { - DWORD volume = 0; for (DWORD i = 0; i < mixerLineControls.cControls; i++) { if ((mixerLineControls.pamxctrl[i].dwControlType != MIXERCONTROL_CONTROLTYPE_FADER) && (mixerLineControls.pamxctrl[i].dwControlType != MIXERCONTROL_CONTROLTYPE_VOLUME)) { @@ -226,11 +225,10 @@ qreal QWindowsAudioInput::volume() const continue; if (controlDetails.cbDetails < sizeof(MIXERCONTROLDETAILS_UNSIGNED)) continue; - volume = detailsUnsigned.dwValue; - break; + return detailsUnsigned.dwValue / 65535.0; } - return volume / 65535.0; + return cachedVolume; } void QWindowsAudioInput::setFormat(const QAudioFormat& fmt) @@ -378,6 +376,7 @@ bool QWindowsAudioInput::open() elapsedTimeOffset = 0; totalTimeValue = 0; errorState = QAudio::NoError; + initMixer(); return true; } @@ -396,6 +395,7 @@ void QWindowsAudioInput::close() mutex.unlock(); waveInClose(hWaveIn); + closeMixer(); int count = 0; while(!finished && count < 500) { @@ -406,17 +406,10 @@ void QWindowsAudioInput::close() void QWindowsAudioInput::initMixer() { - QDataStream ds(&m_device, QIODevice::ReadOnly); - quint32 inputDevice; - ds >> inputDevice; - - if (int(inputDevice) < 0) - return; - // Get the Mixer ID from the Sound Device ID UINT mixerIntID = 0; - if (mixerGetID(reinterpret_cast(quintptr(inputDevice)), - &mixerIntID, MIXER_OBJECTF_WAVEIN) != MMSYSERR_NOERROR) + if (mixerGetID(reinterpret_cast(hWaveIn), + &mixerIntID, MIXER_OBJECTF_HWAVEIN) != MMSYSERR_NOERROR) return; mixerID = reinterpret_cast(quintptr(mixerIntID)); @@ -436,6 +429,8 @@ void QWindowsAudioInput::initMixer() mixerLineControls.pamxctrl = new MIXERCONTROL[mixerLineControls.cControls]; if (mixerGetLineControls(mixerID, &mixerLineControls, MIXER_GETLINECONTROLSF_ALL) != MMSYSERR_NOERROR) closeMixer(); + else + setVolume(cachedVolume); } } diff --git a/src/plugins/windowsaudio/qwindowsaudioinput.h b/src/plugins/windowsaudio/qwindowsaudioinput.h index e61a50a89..a0feae257 100644 --- a/src/plugins/windowsaudio/qwindowsaudioinput.h +++ b/src/plugins/windowsaudio/qwindowsaudioinput.h @@ -147,6 +147,7 @@ private: void closeMixer(); HMIXEROBJ mixerID; MIXERLINECONTROLS mixerLineControls; + qreal cachedVolume; private slots: void feedback(); -- cgit v1.2.3 From 83542fd6b134b1fb70b085e62819c3e742a9e31f Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Mon, 15 Jan 2018 12:16:37 +0100 Subject: QSoundEffect: Release QAudioOutput when new source url applied When sample is ready QAudioOutput is created with sample's format. In case when new source url is applied old format is reused in QAudioOutput instance which might lead incorrect playback. Task-number: QTBUG-54262 Change-Id: I84af167412cb53726593a3bfd4193fc7cd71f332 Reviewed-by: Andy Shaw Reviewed-by: Christian Stromme --- src/multimedia/audio/qsoundeffect_qaudio_p.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src') diff --git a/src/multimedia/audio/qsoundeffect_qaudio_p.cpp b/src/multimedia/audio/qsoundeffect_qaudio_p.cpp index 388f84d91..3f315fa28 100644 --- a/src/multimedia/audio/qsoundeffect_qaudio_p.cpp +++ b/src/multimedia/audio/qsoundeffect_qaudio_p.cpp @@ -132,6 +132,13 @@ void QSoundEffectPrivate::setSource(const QUrl &url) d->m_sample = nullptr; } + if (d->m_audioOutput) { + disconnect(d->m_audioOutput, &QAudioOutput::stateChanged, d, &PrivateSoundSource::stateChanged); + d->m_audioOutput->stop(); + d->m_audioOutput->deleteLater(); + d->m_audioOutput = nullptr; + } + setStatus(QSoundEffect::Loading); d->m_sample = sampleCache()->requestSample(url); connect(d->m_sample, &QSample::error, d, &PrivateSoundSource::decoderError); -- cgit v1.2.3 From 14a77698a01782f27e395bbc8694b808455d4ba1 Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Fri, 11 May 2018 13:46:15 +0200 Subject: QSoundEffect: Check if network access manager is already released In case if network access manager is already released need to prevent using it in dtor. Task-number: QTBUG-66754 Change-Id: I9f61e284b39e920dadf771d807a4b7dce2a353f7 Reviewed-by: Christian Stromme --- src/multimedia/audio/qsamplecache_p.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/multimedia/audio/qsamplecache_p.cpp b/src/multimedia/audio/qsamplecache_p.cpp index c76f51899..93010c182 100644 --- a/src/multimedia/audio/qsamplecache_p.cpp +++ b/src/multimedia/audio/qsamplecache_p.cpp @@ -132,7 +132,8 @@ QSampleCache::~QSampleCache() for (QSample* sample : copyStaleSamples) delete sample; - m_networkAccessManager->deleteLater(); + if (m_networkAccessManager) + m_networkAccessManager->deleteLater(); } void QSampleCache::loadingRelease() -- cgit v1.2.3