From b1430b9e60c51b326fd6eaf1b001916b3b8471f5 Mon Sep 17 00:00:00 2001 From: Ihor Dutchak Date: Thu, 27 Feb 2020 02:55:09 +0200 Subject: Fix AVFVideoWindowControl/AVFVideoWidget content flick on resize When AVPlayerLayer as a backend for AVFVideoWindowControl being resized, macOS adds animation that interferes with Qt resize routines. Disabling animation fixes visual flicks. Task-number: QTBUG-82542 Change-Id: I20a5699431369bcc2da8719b8c4a0151273f9973 Reviewed-by: VaL Doroshchuk --- src/plugins/avfoundation/mediaplayer/avfvideowidget.mm | 17 +++++++++++------ .../avfoundation/mediaplayer/avfvideowindowcontrol.mm | 9 +++++---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm index be349710c..0987342b4 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm @@ -38,12 +38,9 @@ ****************************************************************************/ #include "avfvideowidget.h" -#include -#include -#include -#include -#include +#import +#import #if defined(Q_OS_MACOS) #import @@ -51,6 +48,11 @@ #import #endif +#include +#include +#include +#include + QT_USE_NAMESPACE AVFVideoWidget::AVFVideoWidget(QWidget *parent) @@ -178,5 +180,8 @@ void AVFVideoWidget::updateAspectRatio() void AVFVideoWidget::updatePlayerLayerBounds(const QSize &size) { - m_playerLayer.bounds = CGRectMake(0.0f, 0.0f, (float)size.width(), (float)size.height()); + [CATransaction begin]; + [CATransaction setDisableActions: YES]; // disable animation/flicks + m_playerLayer.bounds = QRect(QPoint(0, 0), size).toCGRect(); + [CATransaction commit]; } diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm b/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm index 7fa41fdc2..d61129ec9 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm @@ -40,6 +40,7 @@ #include "avfvideowindowcontrol.h" #include +#import #if QT_HAS_INCLUDE() #include @@ -244,10 +245,10 @@ void AVFVideoWindowControl::updateAspectRatio() void AVFVideoWindowControl::updatePlayerLayerBounds() { if (m_playerLayer) { - CGRect newBounds = CGRectMake(0, 0, - m_displayRect.width(), m_displayRect.height()); - m_playerLayer.bounds = newBounds; - m_playerLayer.position = CGPointMake(m_displayRect.x(), m_displayRect.y()); + [CATransaction begin]; + [CATransaction setDisableActions: YES]; // disable animation/flicks + m_playerLayer.frame = m_displayRect.toCGRect(); + [CATransaction commit]; } } -- cgit v1.2.3 From cdb568606b9eab946c2cacff374a911dc4cfd2f0 Mon Sep 17 00:00:00 2001 From: Val Doroshchuk Date: Wed, 19 Feb 2020 14:38:17 +0100 Subject: AVF: Use supported pixel formats from video surface in Camera QAbstractVideoSurface is waiting for the video frames in supported pixel formats. See QAbstractVideoSurface::supportedPixelFormats(). If the surface does not support device's pixel format, don't show the camera's viewfinder and don't return video frames in unsupported formats. Task-number: QTBUG-82264 Change-Id: I084674f4b093a751bc4f4941047b979766880963 Reviewed-by: Andy Shaw --- .../camera/avfcamerarenderercontrol.mm | 4 +- .../camera/avfcameraviewfindersettingscontrol.mm | 43 ++++++++++++---------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm index 0359f5d0a..9e1bf3f84 100644 --- a/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm +++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm @@ -297,11 +297,9 @@ void AVFCameraRendererControl::setSurface(QAbstractVideoSurface *surface) { if (m_surface != surface) { m_surface = surface; -#ifdef Q_OS_IOS m_supportsTextures = m_surface - ? m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGRA32) + ? !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).isEmpty() : false; -#endif Q_EMIT surfaceChanged(surface); } } diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm index 0f7a0560b..dd0393f96 100644 --- a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm @@ -341,7 +341,10 @@ bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFr if (m_service->videoOutput()->surface()) { const QAbstractVideoSurface *surface = m_service->videoOutput()->surface(); - if (!surface->supportedPixelFormats().contains(qtFormat)) + QAbstractVideoBuffer::HandleType h = m_service->videoOutput()->supportsTextures() + ? QAbstractVideoBuffer::GLTextureHandle + : QAbstractVideoBuffer::NoHandle; + if (!surface->supportedPixelFormats(h).contains(qtFormat)) return false; } @@ -389,21 +392,19 @@ bool AVFCameraViewfinderSettingsControl2::applySettings(const QCameraViewfinderS // format, or if no surface is set, the preferred capture device format const QVector deviceFormats = viewfinderPixelFormats(); - QVideoFrame::PixelFormat pickedFormat = deviceFormats.first(); - QAbstractVideoSurface *surface = m_service->videoOutput()->surface(); + QVideoFrame::PixelFormat pickedFormat = deviceFormats.first(); if (surface) { - if (m_service->videoOutput()->supportsTextures()) { - pickedFormat = QVideoFrame::Format_ARGB32; - } else { - QList surfaceFormats = surface->supportedPixelFormats(); - - for (int i = 0; i < surfaceFormats.count(); ++i) { - const QVideoFrame::PixelFormat surfaceFormat = surfaceFormats.at(i); - if (deviceFormats.contains(surfaceFormat)) { - pickedFormat = surfaceFormat; - break; - } + pickedFormat = QVideoFrame::Format_Invalid; + QAbstractVideoBuffer::HandleType h = m_service->videoOutput()->supportsTextures() + ? QAbstractVideoBuffer::GLTextureHandle + : QAbstractVideoBuffer::NoHandle; + QList surfaceFormats = surface->supportedPixelFormats(h); + for (int i = 0; i < surfaceFormats.count(); ++i) { + const QVideoFrame::PixelFormat surfaceFormat = surfaceFormats.at(i); + if (deviceFormats.contains(surfaceFormat)) { + pickedFormat = surfaceFormat; + break; } } } @@ -411,13 +412,15 @@ bool AVFCameraViewfinderSettingsControl2::applySettings(const QCameraViewfinderS CVPixelFormatFromQtFormat(pickedFormat, avfPixelFormat); } - if (avfPixelFormat != 0) { - NSMutableDictionary *videoSettings = [NSMutableDictionary dictionaryWithCapacity:1]; - [videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat] - forKey:(id)kCVPixelBufferPixelFormatTypeKey]; + NSMutableDictionary *videoSettings = [NSMutableDictionary dictionaryWithCapacity:1]; + [videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat] + forKey:(id)kCVPixelBufferPixelFormatTypeKey]; - videoOutput.videoSettings = videoSettings; - } + const AVFConfigurationLock lock(captureDevice); + if (!lock) + qWarning("Failed to set active format (lock failed)"); + + videoOutput.videoSettings = videoSettings; } qt_set_framerate_limits(captureDevice, videoConnection(), settings.minimumFrameRate(), settings.maximumFrameRate()); -- cgit v1.2.3 From 89dc35385037339072159d1e5fc8e325010b2dc0 Mon Sep 17 00:00:00 2001 From: VaL Doroshchuk Date: Fri, 31 Jan 2020 16:20:10 +0100 Subject: GStreamer: Allow using different resolution for capture and viewfinder Currently viewfinder resolution is overridden by image resolution. Fixed to keep it separate. Note, it might be not fully supported by gst camera implementation. Change-Id: Ia04c7819da1410f41aee458d347408f94053170b Reviewed-by: Andy Shaw --- src/plugins/gstreamer/camerabin/camerabinsession.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.cpp b/src/plugins/gstreamer/camerabin/camerabinsession.cpp index 3e505a413..9445bd9d0 100644 --- a/src/plugins/gstreamer/camerabin/camerabinsession.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinsession.cpp @@ -347,10 +347,12 @@ void CameraBinSession::setupCaptureResolution() // If capture resolution is specified, use it also for the viewfinder to avoid caps negotiation // to fail. if (m_usingWrapperCameraBinSrc) { - if (m_captureMode == QCamera::CaptureStillImage && !imageResolution.isEmpty()) - viewfinderResolution = imageResolution; - else if (m_captureMode == QCamera::CaptureVideo && !videoResolution.isEmpty()) - viewfinderResolution = videoResolution; + if (viewfinderResolution.isEmpty()) { + if (m_captureMode == QCamera::CaptureStillImage && !imageResolution.isEmpty()) + viewfinderResolution = imageResolution; + else if (m_captureMode == QCamera::CaptureVideo && !videoResolution.isEmpty()) + viewfinderResolution = videoResolution; + } // Make sure we don't use incompatible frame rate and pixel format with the new resolution if (viewfinderResolution != m_viewfinderSettings.resolution() && -- cgit v1.2.3 From 6e21318ca9748e6ddaf9f38052b7896e63ebb81f Mon Sep 17 00:00:00 2001 From: VaL Doroshchuk Date: Wed, 4 Mar 2020 10:57:42 +0100 Subject: QMediaPlayer: Update gst-pipeline docs Added docs for using QAbstractVideoSurface and example how to use QVideoWidget. Change-Id: I27a105a3859086e6fa5d8a19672ef791ce9e5cca Reviewed-by: Andy Shaw Reviewed-by: Paul Wicking --- .../doc/snippets/multimedia-snippets/media.cpp | 31 ++++++++++++++++++++++ src/multimedia/playback/qmediaplayer.cpp | 13 +++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/multimedia/doc/snippets/multimedia-snippets/media.cpp b/src/multimedia/doc/snippets/multimedia-snippets/media.cpp index 8ec7cb072..7fd6259ea 100644 --- a/src/multimedia/doc/snippets/multimedia-snippets/media.cpp +++ b/src/multimedia/doc/snippets/multimedia-snippets/media.cpp @@ -56,6 +56,7 @@ #include "qaudioprobe.h" #include "qaudiorecorder.h" #include "qvideoprobe.h" +#include class MediaExample : public QObject { Q_OBJECT @@ -197,6 +198,36 @@ void MediaExample::MediaPlayer() player->play(); //! [Pipeline] + //! [Pipeline Surface] + class Surface : public QAbstractVideoSurface + { + public: + Surface(QObject *p) : QAbstractVideoSurface(p) { } + QList supportedPixelFormats(QAbstractVideoBuffer::HandleType) const override + { + // Make sure that the driver supports this pixel format. + return QList() << QVideoFrame::Format_YUYV; + } + + // Video frames are handled here. + bool present(const QVideoFrame &) override { return true; } + }; + + player = new QMediaPlayer; + player->setVideoOutput(new Surface(player)); + player->setMedia(QUrl("gst-pipeline: videotestsrc ! qtvideosink")); + player->play(); + //! [Pipeline Surface] + + //! [Pipeline Widget] + player = new QMediaPlayer; + videoWidget = new QVideoWidget; + videoWidget->show(); + player->setVideoOutput(videoWidget); + player->setMedia(QUrl("gst-pipeline: videotestsrc ! xvimagesink name=\"qtvideosink\"")); + player->play(); + //! [Pipeline Widget] + //! [Pipeline appsrc] QImage img("images/qt-logo.png"); img = img.convertToFormat(QImage::Format_ARGB32); diff --git a/src/multimedia/playback/qmediaplayer.cpp b/src/multimedia/playback/qmediaplayer.cpp index 44e91912b..2c66ad06a 100644 --- a/src/multimedia/playback/qmediaplayer.cpp +++ b/src/multimedia/playback/qmediaplayer.cpp @@ -1022,8 +1022,17 @@ void QMediaPlayer::setPlaybackRate(qreal rate) \snippet multimedia-snippets/media.cpp Pipeline - If the pipeline contains a video sink element named \c qtvideosink, - current QVideoWidget can be used to render the video. + If QAbstractVideoSurface is used as the video output, + \c qtvideosink can be used as a video sink element directly in the pipeline. + After that the surface will receive the video frames in QAbstractVideoSurface::present(). + + \snippet multimedia-snippets/media.cpp Pipeline Surface + + If QVideoWidget is used as the video output + and the pipeline contains a video sink element named \c qtvideosink, + current QVideoWidget will be used to render the video. + + \snippet multimedia-snippets/media.cpp Pipeline Widget If the pipeline contains appsrc element, it will be used to push data from \a stream. -- cgit v1.2.3 From bc42a549a309603ab4afe28b87406a663702aa24 Mon Sep 17 00:00:00 2001 From: Cheng Sun Date: Wed, 20 Nov 2019 11:23:09 +0000 Subject: QAlsaAudioOutput: leave IdleState as soon as there is data in the source This fixes two bugs: - Once IdleState is entered (due to underflow), one would have to bring the state to ActiveState manually before the backend would start sending new data to ALSA. This behavior is unlike that of QPulseAudioOutput, for example, which will automatically transition out of IdleState once there is data present in the source device. - Whilst in IdleState the audio output would would mark bytes as being consumed from the source device, even though they were not actually being sent to ALSA. Change-Id: If5b4835df0f58b7b15f1800d3a0a1041f1ab845a Reviewed-by: VaL Doroshchuk --- src/plugins/alsa/qalsaaudiooutput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/alsa/qalsaaudiooutput.cpp b/src/plugins/alsa/qalsaaudiooutput.cpp index 5c8ae171c..ee5aee989 100644 --- a/src/plugins/alsa/qalsaaudiooutput.cpp +++ b/src/plugins/alsa/qalsaaudiooutput.cpp @@ -707,7 +707,7 @@ bool QAlsaAudioOutput::deviceReady() if(l > 0) { // Got some data to output - if(deviceState != QAudio::ActiveState) + if (deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState) return true; qint64 bytesWritten = write(audioBuffer,l); if (bytesWritten != l) -- cgit v1.2.3 From 7f0a20ad066020d913faff636b8a0c5f61d2dfe0 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Sat, 22 Feb 2020 15:50:40 -0600 Subject: Document usage of QT_MULTIMEDIA_PREFERRED_PLUGINS on Windows Task-number: QTBUG-82300 Change-Id: Ibbd960ef69b59e535af30ac10a238ddcf7634b66 Reviewed-by: Andy Shaw --- src/multimedia/doc/src/platform-notes-windows.qdoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/multimedia/doc/src/platform-notes-windows.qdoc b/src/multimedia/doc/src/platform-notes-windows.qdoc index e86d6a276..a69e96d99 100644 --- a/src/multimedia/doc/src/platform-notes-windows.qdoc +++ b/src/multimedia/doc/src/platform-notes-windows.qdoc @@ -42,6 +42,11 @@ was introduced in Windows Vista as a replacement for DirectShow and other multimedia APIs. Consequently, WMF plugin in Qt is supported only for Windows Vista and later versions of the operating system. +The environment variable \c QT_MULTIMEDIA_PREFERRED_PLUGINS can be used to +control the priority of the plugins. For example, setting it to +"windowsmediafoundation" or "directshow" will cause the corresponding plugin +to be the preferred one. + \section1 Limitations The WMF plugin in Qt does not currently provide a camera backend. Instead, -- cgit v1.2.3