diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-10-05 14:02:02 +0200 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2018-10-05 14:02:02 +0200 |
commit | 51c15a0f0f8ba127b667c4700e4e055c681077d3 (patch) | |
tree | cd972bad814f685aba05e6dc6f596603875bd6f8 /src | |
parent | 704e120042a504cfe5ff76f6f35133f47d067028 (diff) | |
parent | 83c49ab485026f35fbd9b5f8242be967a0a24e8b (diff) |
Merge remote-tracking branch 'origin/5.12' into dev
Change-Id: I600b0532f154dc885913f14a5d24261c0de93893
Diffstat (limited to 'src')
20 files changed, 383 insertions, 65 deletions
diff --git a/src/gsttools/qgstreamervideorenderer.cpp b/src/gsttools/qgstreamervideorenderer.cpp index 1b5cc8caf..25fc33cb3 100644 --- a/src/gsttools/qgstreamervideorenderer.cpp +++ b/src/gsttools/qgstreamervideorenderer.cpp @@ -113,7 +113,7 @@ void QGstreamerVideoRenderer::setSurface(QAbstractVideoSurface *surface) if (m_surface) { connect(m_surface.data(), SIGNAL(supportedFormatsChanged()), this, SLOT(handleFormatChange())); - QGstVideoRendererSink::setSurface(m_surface); + QVideoSurfaceGstSink::setSurface(m_surface); } if (wasReady != isReady()) diff --git a/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h b/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h index 034af39fc..961cf91d2 100644 --- a/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h +++ b/src/multimedia/gsttools_headers/qvideosurfacegstsink_p.h @@ -139,6 +139,7 @@ public: GstVideoSink parent; static QVideoSurfaceGstSink *createSink(QAbstractVideoSurface *surface); + static void setSurface(QAbstractVideoSurface *surface) { Q_UNUSED(surface); } private: static GType get_type(); diff --git a/src/multimediawidgets/qpaintervideosurface.cpp b/src/multimediawidgets/qpaintervideosurface.cpp index 0396f9fc0..e4762a7e1 100644 --- a/src/multimediawidgets/qpaintervideosurface.cpp +++ b/src/multimediawidgets/qpaintervideosurface.cpp @@ -143,6 +143,11 @@ QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::start(const QVideoSurf { m_frame = QVideoFrame(); m_imageFormat = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()); + // Do not render into ARGB32 images using QPainter. + // Using QImage::Format_ARGB32_Premultiplied is significantly faster. + if (m_imageFormat == QImage::Format_ARGB32) + m_imageFormat = QImage::Format_ARGB32_Premultiplied; + m_imageSize = format.frameSize(); m_scanLineDirection = format.scanLineDirection(); m_mirrored = format.property("mirrored").toBool(); @@ -191,10 +196,6 @@ QAbstractVideoSurface::Error QVideoSurfaceGenericPainter::paint( m_imageSize.height(), m_frame.bytesPerLine(), m_imageFormat); - // Do not render into ARGB32 images using QPainter. - // Using QImage::Format_ARGB32_Premultiplied is significantly faster. - if (m_imageFormat == QImage::Format_ARGB32) - image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied); const QTransform oldTransform = painter->transform(); QTransform transform = oldTransform; diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java index 7fb4a8690..b1da2f1fa 100644 --- a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java +++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java @@ -212,6 +212,11 @@ public class QtAndroidMediaPlayer mContext = context; } + public MediaPlayer getMediaPlayerHandle() + { + return mMediaPlayer; + } + private void setState(int state) { if (mState == state) diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp index 9631a6ba7..df1463a87 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp +++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp @@ -93,7 +93,9 @@ QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent) mPendingVolume(-1), mPendingMute(-1), mReloadingMedia(false), - mActiveStateChangeNotifiers(0) + mActiveStateChangeNotifiers(0), + mPendingPlaybackRate(1.0), + mHasPendingPlaybackRate(false) { connect(mMediaPlayer,SIGNAL(bufferingChanged(qint32)), this,SLOT(onBufferingChanged(qint32))); @@ -290,12 +292,45 @@ void QAndroidMediaPlayerControl::updateAvailablePlaybackRanges() qreal QAndroidMediaPlayerControl::playbackRate() const { - return 1.0f; + if (mHasPendingPlaybackRate || + (mState & (AndroidMediaPlayer::Initialized + | AndroidMediaPlayer::Prepared + | AndroidMediaPlayer::Started + | AndroidMediaPlayer::Paused + | AndroidMediaPlayer::PlaybackCompleted + | AndroidMediaPlayer::Error)) == 0) { + return mPendingPlaybackRate; + } + + return mMediaPlayer->playbackRate(); } void QAndroidMediaPlayerControl::setPlaybackRate(qreal rate) { - Q_UNUSED(rate); + if ((mState & (AndroidMediaPlayer::Initialized + | AndroidMediaPlayer::Prepared + | AndroidMediaPlayer::Started + | AndroidMediaPlayer::Paused + | AndroidMediaPlayer::PlaybackCompleted + | AndroidMediaPlayer::Error)) == 0) { + if (mPendingPlaybackRate != rate) { + mPendingPlaybackRate = rate; + mHasPendingPlaybackRate = true; + Q_EMIT playbackRateChanged(rate); + } + return; + } + + bool succeeded = mMediaPlayer->setPlaybackRate(rate); + + if (mHasPendingPlaybackRate) { + mHasPendingPlaybackRate = false; + mPendingPlaybackRate = qreal(1.0); + if (!succeeded) + Q_EMIT playbackRateChanged(playbackRate()); + } else if (succeeded) { + Q_EMIT playbackRateChanged(rate); + } } QMediaContent QAndroidMediaPlayerControl::media() const @@ -379,6 +414,9 @@ void QAndroidMediaPlayerControl::play() setMedia(mMediaContent, mMediaStream); } + if (!mMediaContent.isNull()) + setState(QMediaPlayer::PlayingState); + if ((mState & (AndroidMediaPlayer::Prepared | AndroidMediaPlayer::Started | AndroidMediaPlayer::Paused @@ -387,7 +425,6 @@ void QAndroidMediaPlayerControl::play() return; } - setState(QMediaPlayer::PlayingState); mMediaPlayer->play(); } @@ -718,6 +755,8 @@ void QAndroidMediaPlayerControl::flushPendingStates() setVolume(mPendingVolume); if (mPendingMute != -1) setMuted((mPendingMute == 1)); + if (mHasPendingPlaybackRate) + setPlaybackRate(mPendingPlaybackRate); switch (newState) { case QMediaPlayer::PlayingState: diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h index 04f728a59..119add7f8 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h +++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h @@ -117,6 +117,8 @@ private: int mPendingMute; bool mReloadingMedia; int mActiveStateChangeNotifiers; + qreal mPendingPlaybackRate; + bool mHasPendingPlaybackRate; // we need this because the rate can theoretically be negative void setState(QMediaPlayer::State state); void setMediaStatus(QMediaPlayer::MediaStatus status); diff --git a/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp b/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp index 582d8aa9d..b81f98cbd 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp +++ b/src/plugins/android/src/wrappers/jni/androidmediaplayer.cpp @@ -109,6 +109,33 @@ bool AndroidMediaPlayer::isMuted() return mMediaPlayer.callMethod<jboolean>("isMuted"); } +qreal AndroidMediaPlayer::playbackRate() +{ + qreal rate(1.0); + + if (QtAndroidPrivate::androidSdkVersion() < 23) + return rate; + + QJNIObjectPrivate player = mMediaPlayer.callObjectMethod("getMediaPlayerHandle", "()Landroid/media/MediaPlayer;"); + if (player.isValid()) { + QJNIObjectPrivate playbackParams = player.callObjectMethod("getPlaybackParams", "()Landroid/media/PlaybackParams;"); + if (playbackParams.isValid()) { + const qreal speed = playbackParams.callMethod<jfloat>("getSpeed", "()F"); + QJNIEnvironmentPrivate env; + if (env->ExceptionCheck()) { +#ifdef QT_DEBUG + env->ExceptionDescribe(); +#endif // QT_DEBUG + env->ExceptionClear(); + } else { + rate = speed; + } + } + } + + return rate; +} + jobject AndroidMediaPlayer::display() { return mMediaPlayer.callObjectMethod("display", "()Landroid/view/SurfaceHolder;").object(); @@ -155,6 +182,40 @@ void AndroidMediaPlayer::setVolume(int volume) mMediaPlayer.callMethod<void>("setVolume", "(I)V", jint(volume)); } +bool AndroidMediaPlayer::setPlaybackRate(qreal rate) +{ + if (QtAndroidPrivate::androidSdkVersion() < 23) { + qWarning("Setting the playback rate on a media player requires Android 6.0 (API level 23) or later"); + return false; + } + + QJNIEnvironmentPrivate env; + + QJNIObjectPrivate player = mMediaPlayer.callObjectMethod("getMediaPlayerHandle", "()Landroid/media/MediaPlayer;"); + if (player.isValid()) { + QJNIObjectPrivate playbackParams = player.callObjectMethod("getPlaybackParams", "()Landroid/media/PlaybackParams;"); + if (playbackParams.isValid()) { + playbackParams.callObjectMethod("setSpeed", "(F)Landroid/media/PlaybackParams;", jfloat(rate)); + // pitch can only be > 0 + if (!qFuzzyIsNull(rate)) + playbackParams.callObjectMethod("setPitch", "(F)Landroid/media/PlaybackParams;", jfloat(qAbs(rate))); + player.callMethod<void>("setPlaybackParams", "(Landroid/media/PlaybackParams;)V", playbackParams.object()); + if (Q_UNLIKELY(env->ExceptionCheck())) { +#ifdef QT_DEBUG + env->ExceptionDescribe(); +#endif // QT_DEBUG + env->ExceptionClear(); + qWarning() << "Invalid playback rate" << rate; + return false; + } else { + return true; + } + } + } + + return false; +} + void AndroidMediaPlayer::setDisplay(AndroidSurfaceTexture *surfaceTexture) { mMediaPlayer.callMethod<void>("setDisplay", diff --git a/src/plugins/android/src/wrappers/jni/androidmediaplayer.h b/src/plugins/android/src/wrappers/jni/androidmediaplayer.h index 28bfa3662..a7284bb0c 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediaplayer.h +++ b/src/plugins/android/src/wrappers/jni/androidmediaplayer.h @@ -103,6 +103,7 @@ public: bool isPlaying(); int volume(); bool isMuted(); + qreal playbackRate(); jobject display(); void play(); @@ -113,6 +114,7 @@ public: void setDataSource(const QString &path); void prepareAsync(); void setVolume(int volume); + bool setPlaybackRate(qreal rate); void setDisplay(AndroidSurfaceTexture *surfaceTexture); static bool initJNI(JNIEnv *env); diff --git a/src/plugins/directshow/camera/camera.pri b/src/plugins/directshow/camera/camera.pri index 0e1c1e895..3be1acc49 100644 --- a/src/plugins/directshow/camera/camera.pri +++ b/src/plugins/directshow/camera/camera.pri @@ -15,7 +15,8 @@ HEADERS += \ $$PWD/directshowcameraexposurecontrol.h \ $$PWD/directshowcameracapturedestinationcontrol.h \ $$PWD/directshowcameracapturebufferformatcontrol.h \ - $$PWD/directshowcamerazoomcontrol.h + $$PWD/directshowcamerazoomcontrol.h \ + $$PWD/directshowcameraimageencodercontrol.h SOURCES += \ $$PWD/dscameraservice.cpp \ @@ -29,7 +30,8 @@ SOURCES += \ $$PWD/directshowcameraexposurecontrol.cpp \ $$PWD/directshowcameracapturedestinationcontrol.cpp \ $$PWD/directshowcameracapturebufferformatcontrol.cpp \ - $$PWD/directshowcamerazoomcontrol.cpp + $$PWD/directshowcamerazoomcontrol.cpp \ + $$PWD/directshowcameraimageencodercontrol.cpp *-msvc*:INCLUDEPATH += $$(DXSDK_DIR)/include QMAKE_USE += directshow diff --git a/src/plugins/directshow/camera/directshowcameraimageencodercontrol.cpp b/src/plugins/directshow/camera/directshowcameraimageencodercontrol.cpp new file mode 100644 index 000000000..912f67a2d --- /dev/null +++ b/src/plugins/directshow/camera/directshowcameraimageencodercontrol.cpp @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "directshowcameraimageencodercontrol.h" +#include "dscamerasession.h" +#include <QImageWriter> + +QT_BEGIN_NAMESPACE + +DirectShowCameraImageEncoderControl::DirectShowCameraImageEncoderControl(DSCameraSession *session) + : QImageEncoderControl(session) + , m_session(session) +{ +} + +QList<QSize> DirectShowCameraImageEncoderControl::supportedResolutions(const QImageEncoderSettings &settings, bool *continuous) const +{ + QList<QSize> res; + if (!settings.codec().isEmpty() && !supportedImageCodecs().contains(settings.codec(), Qt::CaseInsensitive)) + return res; + + QList<QSize> resolutions = m_session->supportedResolutions(continuous); + QSize r = settings.resolution(); + if (!r.isValid()) + return resolutions; + + if (resolutions.contains(r)) + res << settings.resolution(); + + return res; +} + +QStringList DirectShowCameraImageEncoderControl::supportedImageCodecs() const +{ + QStringList supportedCodecs; + for (const QByteArray &type: QImageWriter::supportedImageFormats()) { + supportedCodecs << type; + } + + return supportedCodecs; +} + +QString DirectShowCameraImageEncoderControl::imageCodecDescription(const QString &codecName) const +{ + Q_UNUSED(codecName); + return QString(); +} + +QImageEncoderSettings DirectShowCameraImageEncoderControl::imageSettings() const +{ + return m_session->imageEncoderSettings(); +} + +void DirectShowCameraImageEncoderControl::setImageSettings(const QImageEncoderSettings &settings) +{ + m_session->setImageEncoderSettings(settings); +} + +QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/directshowcameraimageencodercontrol.h b/src/plugins/directshow/camera/directshowcameraimageencodercontrol.h new file mode 100644 index 000000000..6891bea77 --- /dev/null +++ b/src/plugins/directshow/camera/directshowcameraimageencodercontrol.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef DIRECTSHOWCAMERAIMAGEENCODERCONTROL_H +#define DIRECTSHOWCAMERAIMAGEENCODERCONTROL_H + +#include <qimageencodercontrol.h> + +QT_BEGIN_NAMESPACE + +class DSCameraSession; +class DirectShowCameraImageEncoderControl : public QImageEncoderControl +{ + Q_OBJECT +public: + DirectShowCameraImageEncoderControl(DSCameraSession *session); + + QList<QSize> supportedResolutions( + const QImageEncoderSettings &settings = QImageEncoderSettings(), + bool *continuous = nullptr) const override; + + QStringList supportedImageCodecs() const override; + QString imageCodecDescription(const QString &formatName) const override; + + QImageEncoderSettings imageSettings() const override; + void setImageSettings(const QImageEncoderSettings &settings) override; + +private: + DSCameraSession *m_session; +}; + +QT_END_NAMESPACE + +#endif // DIRECTSHOWCAMERAIMAGEENCODERCONTROL_H diff --git a/src/plugins/directshow/camera/dscameraservice.cpp b/src/plugins/directshow/camera/dscameraservice.cpp index a806cabe3..8115ef385 100644 --- a/src/plugins/directshow/camera/dscameraservice.cpp +++ b/src/plugins/directshow/camera/dscameraservice.cpp @@ -53,6 +53,7 @@ #include "directshowcameracapturebufferformatcontrol.h" #include "directshowvideoprobecontrol.h" #include "directshowcamerazoomcontrol.h" +#include "directshowcameraimageencodercontrol.h" QT_BEGIN_NAMESPACE @@ -70,6 +71,7 @@ DSCameraService::DSCameraService(QObject *parent): , m_captureBufferFormatControl(new DirectShowCameraCaptureBufferFormatControl) , m_videoProbeControl(nullptr) , m_zoomControl(new DirectShowCameraZoomControl(m_session)) + , m_imageEncoderControl(new DirectShowCameraImageEncoderControl(m_session)) { } @@ -81,6 +83,7 @@ DSCameraService::~DSCameraService() delete m_videoDevice; delete m_videoRenderer; delete m_imageCapture; + delete m_imageEncoderControl; delete m_session; delete m_exposureControl; delete m_captureDestinationControl; @@ -134,6 +137,9 @@ QMediaControl* DSCameraService::requestControl(const char *name) if (qstrcmp(name, QCameraZoomControl_iid) == 0) return m_zoomControl; + if (qstrcmp(name, QImageEncoderControl_iid) == 0) + return m_imageEncoderControl; + return 0; } diff --git a/src/plugins/directshow/camera/dscameraservice.h b/src/plugins/directshow/camera/dscameraservice.h index 2e45edcce..9a8f745f6 100644 --- a/src/plugins/directshow/camera/dscameraservice.h +++ b/src/plugins/directshow/camera/dscameraservice.h @@ -57,6 +57,7 @@ class DirectShowCameraCaptureDestinationControl; class DirectShowCameraCaptureBufferFormatControl; class DirectShowVideoProbeControl; class DirectShowCameraZoomControl; +class DirectShowCameraImageEncoderControl; class DSCameraService : public QMediaService { @@ -82,6 +83,7 @@ private: DirectShowCameraCaptureBufferFormatControl *m_captureBufferFormatControl; DirectShowVideoProbeControl *m_videoProbeControl; DirectShowCameraZoomControl *m_zoomControl; + DirectShowCameraImageEncoderControl *m_imageEncoderControl; }; QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscamerasession.cpp b/src/plugins/directshow/camera/dscamerasession.cpp index bf81262d6..8d0c72057 100644 --- a/src/plugins/directshow/camera/dscamerasession.cpp +++ b/src/plugins/directshow/camera/dscamerasession.cpp @@ -584,10 +584,13 @@ int DSCameraSession::captureImage(const QString &fileName) return m_imageIdCounter; } + const QString ext = !m_imageEncoderSettings.codec().isEmpty() + ? m_imageEncoderSettings.codec().toLower() + : QLatin1String("jpg"); m_imageCaptureFileName = m_fileNameGenerator.generateFileName(fileName, QMediaStorageLocation::Pictures, QLatin1String("IMG_"), - QLatin1String("jpg")); + ext); updateReadyForCapture(); @@ -687,8 +690,9 @@ void DSCameraSession::processCapturedImage(int id, const QImage &image, const QString &path) { + const QString format = m_imageEncoderSettings.codec(); if (captureDestinations & QCameraImageCapture::CaptureToFile) { - if (image.save(path, "JPG")) { + if (image.save(path, !format.isEmpty() ? format.toUtf8().constData() : "JPG")) { Q_EMIT imageSaved(id, path); } else { Q_EMIT captureError(id, QCameraImageCapture::ResourceError, @@ -713,7 +717,7 @@ bool DSCameraSession::createFilterGraph() // Create the filter graph hr = CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC, - IID_IGraphBuilder, reinterpret_cast<void**>(*&m_filterGraph)); + IID_IGraphBuilder, reinterpret_cast<void**>(&m_filterGraph)); if (FAILED(hr)) { errorString = tr("Failed to create filter graph"); goto failed; @@ -844,9 +848,11 @@ bool DSCameraSession::configurePreviewFormat() { // Resolve viewfinder settings int settingsIndex = 0; + const QSize captureResolution = m_imageEncoderSettings.resolution(); + const QSize resolution = captureResolution.isValid() ? captureResolution : m_viewfinderSettings.resolution(); QCameraViewfinderSettings resolvedViewfinderSettings; for (const QCameraViewfinderSettings &s : qAsConst(m_supportedViewfinderSettings)) { - if ((m_viewfinderSettings.resolution().isEmpty() || m_viewfinderSettings.resolution() == s.resolution()) + if ((resolution.isEmpty() || resolution == s.resolution()) && (qFuzzyIsNull(m_viewfinderSettings.minimumFrameRate()) || qFuzzyCompare((float)m_viewfinderSettings.minimumFrameRate(), (float)s.minimumFrameRate())) && (qFuzzyIsNull(m_viewfinderSettings.maximumFrameRate()) || qFuzzyCompare((float)m_viewfinderSettings.maximumFrameRate(), (float)s.maximumFrameRate())) && (m_viewfinderSettings.pixelFormat() == QVideoFrame::Format_Invalid || m_viewfinderSettings.pixelFormat() == s.pixelFormat()) @@ -1171,4 +1177,23 @@ void DSCameraSession::updateSourceCapabilities() updateImageProcessingParametersInfos(); } +QList<QSize> DSCameraSession::supportedResolutions(bool *continuous) const +{ + if (continuous) + *continuous = false; + + QList<QSize> res; + for (auto &settings : m_supportedViewfinderSettings) { + auto size = settings.resolution(); + if (!res.contains(size)) + res << size; + } + + std::sort(res.begin(), res.end(), [](const QSize &r1, const QSize &r2) { + return qlonglong(r1.width()) * r1.height() < qlonglong(r2.width()) * r2.height(); + }); + + return res; +} + QT_END_NAMESPACE diff --git a/src/plugins/directshow/camera/dscamerasession.h b/src/plugins/directshow/camera/dscamerasession.h index ac861ae58..361a0220e 100644 --- a/src/plugins/directshow/camera/dscamerasession.h +++ b/src/plugins/directshow/camera/dscamerasession.h @@ -51,6 +51,7 @@ #include <QtMultimedia/qvideosurfaceformat.h> #include <QtMultimedia/qcameraimageprocessingcontrol.h> #include <QtMultimedia/qcameraimagecapture.h> +#include <QtMultimedia/qmediaencodersettings.h> #include <private/qmediastoragelocation_p.h> #include <tchar.h> @@ -129,6 +130,11 @@ public: void addVideoProbe(DirectShowVideoProbeControl *probe); void removeVideoProbe(DirectShowVideoProbeControl *probe); + QList<QSize> supportedResolutions(bool *continuous) const; + QImageEncoderSettings imageEncoderSettings() const { return m_imageEncoderSettings; } + void setImageEncoderSettings(const QImageEncoderSettings &settings) + { m_imageEncoderSettings = settings; } + Q_SIGNALS: void statusChanged(QCamera::Status); void imageExposed(int id); @@ -217,6 +223,8 @@ private: QMutex m_probeMutex; DirectShowVideoProbeControl *m_videoProbeControl; + QImageEncoderSettings m_imageEncoderSettings; + // Internal state QCamera::Status m_status; QTimer m_deviceLostEventTimer; diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp index b268592c6..c83e467a6 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp +++ b/src/plugins/gstreamer/mediacapture/qgstreamercapturesession.cpp @@ -107,8 +107,6 @@ QGstreamerCaptureSession::QGstreamerCaptureSession(QGstreamerCaptureSession::Cap qWarning() << QMediaRecorder::Error(e) << ":" << str.toLatin1().constData(); }); m_mediaContainerControl = new QGstreamerMediaContainerControl(this); - - setState(StoppedState); } QGstreamerCaptureSession::~QGstreamerCaptureSession() diff --git a/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp b/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp index 958204803..ba26d8df8 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp +++ b/src/plugins/gstreamer/mediacapture/qgstreamerrecordercontrol.cpp @@ -115,6 +115,9 @@ void QGstreamerRecorderControl::updateStatus() if (m_status != newStatus) { m_status = newStatus; emit statusChanged(m_status); + // If stop has been called and session state became stopped. + if (m_status == QMediaRecorder::LoadedStatus) + emit stateChanged(m_state); } } @@ -204,7 +207,6 @@ void QGstreamerRecorderControl::stop() m_session->setState(QGstreamerCaptureSession::PreviewState); } - emit stateChanged(m_state); updateStatus(); } diff --git a/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp b/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp index 9930dd2e1..fbd698eea 100644 --- a/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp +++ b/src/plugins/qnx/mediaplayer/mmrenderervideowindowcontrol.cpp @@ -205,18 +205,11 @@ void MmRendererVideoWindowControl::attachDisplay(mmr_context_t *context) return; } - QWindow *windowForGroup = window; - - //According to mmr_output_attach() documentation, the window group name of the - //application's top-level window is expected. - while (windowForGroup->parent()) - windowForGroup = windowForGroup->parent(); - const char * const groupNameData = static_cast<const char *>( - nativeInterface->nativeResourceForWindow("windowGroup", windowForGroup)); + nativeInterface->nativeResourceForWindow("windowGroup", window)); if (!groupNameData) { qDebug() << "MmRendererVideoWindowControl: Unable to find window group for window" - << windowForGroup; + << window; return; } @@ -250,9 +243,7 @@ void MmRendererVideoWindowControl::updateVideoPosition() { QWindow * const window = findWindow(m_winId); if (m_context && m_videoId != -1 && window) { - QPoint topLeft = m_fullscreen ? - QPoint(0,0) : - window->mapToGlobal(m_displayRect.topLeft()); + QPoint topLeft = m_displayRect.topLeft(); QScreen * const screen = window->screen(); int width = m_fullscreen ? @@ -262,7 +253,8 @@ void MmRendererVideoWindowControl::updateVideoPosition() screen->size().height() : m_displayRect.height(); - if (m_metaData.hasVideo()) { // We need the source size to do aspect ratio scaling + if (m_metaData.hasVideo() && m_metaData.width() > 0 && m_metaData.height() > 0) { + // We need the source size to do aspect ratio scaling const qreal sourceRatio = m_metaData.width() / static_cast<float>(m_metaData.height()); const qreal targetRatio = width / static_cast<float>(height); diff --git a/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp b/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp index 465ccfa7d..4b68f47a4 100644 --- a/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp +++ b/src/plugins/videonode/imx6/qsgvivantevideomaterial.cpp @@ -103,7 +103,7 @@ void QSGVivanteVideoMaterial::setCurrentFrame(const QVideoFrame &frame, QSGVideo { QMutexLocker lock(&mFrameMutex); mNextFrame = frame; - mMappable = !flags.testFlag(QSGVideoNode::FrameFiltered); + mMappable = mMapError == GL_NO_ERROR && !flags.testFlag(QSGVideoNode::FrameFiltered); #ifdef QT_VIVANTE_VIDEO_DEBUG qDebug() << Q_FUNC_INFO << " new frame: " << frame; @@ -172,6 +172,7 @@ GLuint QSGVivanteVideoMaterial::vivanteMapping(QVideoFrame vF) mWidth = vF.width(); mHeight = vF.height(); mFormat = vF.pixelFormat(); + mMapError = GL_NO_ERROR; clearTextures(); } @@ -236,7 +237,12 @@ GLuint QSGVivanteVideoMaterial::vivanteMapping(QVideoFrame vF) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexDirectInvalidateVIV_LOCAL(GL_TEXTURE_2D); - return tmpTexId; + mMapError = glGetError(); + if (mMapError == GL_NO_ERROR) + return tmpTexId; + + // Error occurred. + // Fallback to copying data. } else { // Fastest path: already seen this logical address. Just // indicate that the data belonging to the texture has changed. @@ -244,40 +250,40 @@ GLuint QSGVivanteVideoMaterial::vivanteMapping(QVideoFrame vF) glTexDirectInvalidateVIV_LOCAL(GL_TEXTURE_2D); return mBitsToTextureMap.value(vF.bits()); } + } + + // Cannot map. So copy. + if (!mTexDirectTexture) { + glGenTextures(1, &mTexDirectTexture); + glBindTexture(GL_TEXTURE_2D, mTexDirectTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexDirectVIV_LOCAL(GL_TEXTURE_2D, mCurrentFrame.width(), mCurrentFrame.height(), + QSGVivanteVideoNode::getVideoFormat2GLFormatMap().value(mCurrentFrame.pixelFormat()), + (GLvoid **) &mTexDirectPlanes); } else { - // Cannot map. So copy. - if (!mTexDirectTexture) { - glGenTextures(1, &mTexDirectTexture); - glBindTexture(GL_TEXTURE_2D, mTexDirectTexture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexDirectVIV_LOCAL(GL_TEXTURE_2D, mCurrentFrame.width(), mCurrentFrame.height(), - QSGVivanteVideoNode::getVideoFormat2GLFormatMap().value(mCurrentFrame.pixelFormat()), - (GLvoid **) &mTexDirectPlanes); - } else { - glBindTexture(GL_TEXTURE_2D, mTexDirectTexture); - } - switch (mCurrentFrame.pixelFormat()) { - case QVideoFrame::Format_YUV420P: - case QVideoFrame::Format_YV12: - memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(0), mCurrentFrame.height() * mCurrentFrame.bytesPerLine(0)); - memcpy(mTexDirectPlanes[1], mCurrentFrame.bits(1), mCurrentFrame.height() * mCurrentFrame.bytesPerLine(1)); - memcpy(mTexDirectPlanes[2], mCurrentFrame.bits(2), mCurrentFrame.height() * mCurrentFrame.bytesPerLine(2)); - break; - case QVideoFrame::Format_NV12: - case QVideoFrame::Format_NV21: - memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(0), mCurrentFrame.height() * mCurrentFrame.bytesPerLine(0)); - memcpy(mTexDirectPlanes[1], mCurrentFrame.bits(1), mCurrentFrame.height() / 2 * mCurrentFrame.bytesPerLine(1)); - break; - default: - memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(), mCurrentFrame.height() * mCurrentFrame.bytesPerLine()); - break; - } - glTexDirectInvalidateVIV_LOCAL(GL_TEXTURE_2D); - return mTexDirectTexture; + glBindTexture(GL_TEXTURE_2D, mTexDirectTexture); + } + switch (mCurrentFrame.pixelFormat()) { + case QVideoFrame::Format_YUV420P: + case QVideoFrame::Format_YV12: + memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(0), mCurrentFrame.height() * mCurrentFrame.bytesPerLine(0)); + memcpy(mTexDirectPlanes[1], mCurrentFrame.bits(1), mCurrentFrame.height() / 2 * mCurrentFrame.bytesPerLine(1)); + memcpy(mTexDirectPlanes[2], mCurrentFrame.bits(2), mCurrentFrame.height() / 2 * mCurrentFrame.bytesPerLine(2)); + break; + case QVideoFrame::Format_NV12: + case QVideoFrame::Format_NV21: + memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(0), mCurrentFrame.height() * mCurrentFrame.bytesPerLine(0)); + memcpy(mTexDirectPlanes[1], mCurrentFrame.bits(1), mCurrentFrame.height() / 2 * mCurrentFrame.bytesPerLine(1)); + break; + default: + memcpy(mTexDirectPlanes[0], mCurrentFrame.bits(), mCurrentFrame.height() * mCurrentFrame.bytesPerLine()); + break; } + glTexDirectInvalidateVIV_LOCAL(GL_TEXTURE_2D); + return mTexDirectTexture; } else { #ifdef QT_VIVANTE_VIDEO_DEBUG diff --git a/src/plugins/videonode/imx6/qsgvivantevideomaterial.h b/src/plugins/videonode/imx6/qsgvivantevideomaterial.h index 862747f27..adbd960a4 100644 --- a/src/plugins/videonode/imx6/qsgvivantevideomaterial.h +++ b/src/plugins/videonode/imx6/qsgvivantevideomaterial.h @@ -81,6 +81,7 @@ private: QVideoFrame mCurrentFrame, mNextFrame; GLuint mCurrentTexture; bool mMappable; + GLenum mMapError = GL_NO_ERROR; QMutex mFrameMutex; |