diff options
25 files changed, 249 insertions, 108 deletions
diff --git a/dist/changes-5.13.2 b/dist/changes-5.13.2 new file mode 100644 index 000000000..62dffcb02 --- /dev/null +++ b/dist/changes-5.13.2 @@ -0,0 +1,68 @@ +Qt 5.13.2 is a bug-fix release. It maintains both forward and backward +source compatibility with Qt 5.13.0 through 5.13.1. +In Qt 5.13.0, binary compatibility was broken due to the usage of the enum +QVideoFrame::PixelFormat, the break has been reverted, +thus introducing a binary compatibility break with earlier Qt 5.13.0 and 5.13.1. + +For more details, refer to the online documentation included in this +distribution. The documentation is also available online: + +https://doc.qt.io/qt-5/index.html + +The Qt version 5.13 series is binary compatible with the 5.12.x series. +Applications compiled for 5.12 will continue to run with 5.13. + +Some of the changes listed in this file include issue tracking numbers +corresponding to tasks in the Qt Bug Tracker: + +https://bugreports.qt.io/ + +Each of these identifiers can be entered in the bug tracker to obtain more +information about a particular change. + +**************************************************************************** +* Qt 5.13.2 Changes * +**************************************************************************** + + - In Qt 5.13.0 binary compatibility was broken + for usage of the enum QVideoFrame::PixelFormat by introducing + QVideoFrame::Format_ABGR32. + To minimize the impact of this, the break has been reverted, + thus introducing a binary compatibility break with earlier Qt 5.13.x + versions, but restoring compatibility with all earlier versions of Qt 5. + - Fixed crash when VideoOutput.sourceRect is requested but playback is stopped. + - [QTBUG-51588] Fixed leaking of QVideoFilterRunnable when window is closed. + - [QTBUG-45064] Introduced QGraphicsVideoItem::type(). + - Fixed camera.viewfinder to respect camera's media status + if the viewfinder is requested after the camera is loaded. + +**************************************************************************** +* Platform Specific Changes * +**************************************************************************** + + - GStreamer: + * CameraBin plugin now fetches supported viewfinder settings at status + higher or equal to LoadedStatus if it has not been fetched. + * Fixed duplicated entries in supported Camera's resolution/framerate if the + underlying element uses caps' features. + * Introduced audio/x-raw codec in QAudioRecorder. + * [QTBUG-65399] Fixed media player to show pre-rolled frame on new media + (means to seek to the beginning) only when pause() is called. + * [QTBUG-76135] Show image processing warnings only when the camera is loaded. + * [QTBUG-78079] Fixed media player to recreate playbin features after custom pipeline. + * [QTBUG-73084] Fixed mapping of VPU texture using real physical address of data + which prevents leaks in the kernel for iMX boards. + + - AVFoundation: + * [QTBUG-77270] Fixed black frames being shown if current OpenGL context has been changed. + * [QTBUG-49806] Fixed media player to send StalledMedia status when no enough data to play + and resume playback afterwards. + + - DirectShow: + * [QTBUG-77829] Fixed crash when there is no surface on flush(). + * [QTBUG-77849] Introduced startTime and endTime to QVideoFrame. + * [QTBUG-77163] Introduced support to use QMediaPlayer in secondary thread. + * [QTBUG-46368] Implemented QMediaVideoProbeControl->flush(). + * [QTBUG-46368] Fixed media player to send media status before errors. + * [QTBUG-68778] Fixed media player to postpone seeking if the playback is stopped. + * Fixed crash when qrc media resource is set twice to media player. diff --git a/src/gsttools/qgstreamerplayercontrol.cpp b/src/gsttools/qgstreamerplayercontrol.cpp index bd4c90ac5..165978288 100644 --- a/src/gsttools/qgstreamerplayercontrol.cpp +++ b/src/gsttools/qgstreamerplayercontrol.cpp @@ -450,6 +450,10 @@ void QGstreamerPlayerControl::updateSessionState(QMediaPlayer::State state) void QGstreamerPlayerControl::updateMediaStatus() { + //EndOfMedia status should be kept, until reset by pause, play or setMedia + if (m_mediaStatus == QMediaPlayer::EndOfMedia) + return; + pushState(); QMediaPlayer::MediaStatus oldStatus = m_mediaStatus; @@ -477,10 +481,6 @@ void QGstreamerPlayerControl::updateMediaStatus() if (m_currentState == QMediaPlayer::PlayingState && !m_resources->isGranted()) m_mediaStatus = QMediaPlayer::StalledMedia; - //EndOfMedia status should be kept, until reset by pause, play or setMedia - if (oldStatus == QMediaPlayer::EndOfMedia) - m_mediaStatus = QMediaPlayer::EndOfMedia; - popAndNotifyState(); } diff --git a/src/gsttools/qgstreamerplayersession.cpp b/src/gsttools/qgstreamerplayersession.cpp index b9e1c084f..ed3f16c5f 100644 --- a/src/gsttools/qgstreamerplayersession.cpp +++ b/src/gsttools/qgstreamerplayersession.cpp @@ -265,8 +265,11 @@ void QGstreamerPlayerSession::resetElements() resetGstObject(m_nullVideoSink); resetGstObject(m_videoOutputBin); + m_audioSink = nullptr; m_volumeElement = nullptr; m_videoIdentity = nullptr; + m_pendingVideoSink = nullptr; + m_videoSink = nullptr; } GstElement *QGstreamerPlayerSession::playbin() const diff --git a/src/multimedia/playback/qmediaplaylist.cpp b/src/multimedia/playback/qmediaplaylist.cpp index 7c21a599b..9539a1809 100644 --- a/src/multimedia/playback/qmediaplaylist.cpp +++ b/src/multimedia/playback/qmediaplaylist.cpp @@ -184,20 +184,20 @@ bool QMediaPlaylist::setMediaObject(QMediaObject *mediaObject) disconnect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)), this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString))); - disconnect(playlist, SIGNAL(mediaChanged(int,int)), this, SIGNAL(mediaChanged(int,int))); - disconnect(playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SIGNAL(mediaAboutToBeInserted(int,int))); - disconnect(playlist, SIGNAL(mediaInserted(int,int)), this, SIGNAL(mediaInserted(int,int))); - disconnect(playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SIGNAL(mediaAboutToBeRemoved(int,int))); - disconnect(playlist, SIGNAL(mediaRemoved(int,int)), this, SIGNAL(mediaRemoved(int,int))); + disconnect(playlist, &QMediaPlaylistProvider::mediaChanged, this, &QMediaPlaylist::mediaChanged); + disconnect(playlist, &QMediaPlaylistProvider::mediaAboutToBeInserted, this, &QMediaPlaylist::mediaAboutToBeInserted); + disconnect(playlist, &QMediaPlaylistProvider::mediaInserted, this, &QMediaPlaylist::mediaInserted); + disconnect(playlist, &QMediaPlaylistProvider::mediaAboutToBeRemoved, this, &QMediaPlaylist::mediaAboutToBeRemoved); + disconnect(playlist, &QMediaPlaylistProvider::mediaRemoved, this, &QMediaPlaylist::mediaRemoved); - disconnect(playlist, SIGNAL(loaded()), this, SIGNAL(loaded())); + disconnect(playlist, &QMediaPlaylistProvider::loaded, this, &QMediaPlaylist::loaded); - disconnect(d->control, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), - this, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); - disconnect(d->control, SIGNAL(currentIndexChanged(int)), - this, SIGNAL(currentIndexChanged(int))); - disconnect(d->control, SIGNAL(currentMediaChanged(QMediaContent)), - this, SIGNAL(currentMediaChanged(QMediaContent))); + disconnect(d->control, &QMediaPlaylistControl::playbackModeChanged, + this, &QMediaPlaylist::playbackModeChanged); + disconnect(d->control, &QMediaPlaylistControl::currentIndexChanged, + this, &QMediaPlaylist::currentIndexChanged); + disconnect(d->control, &QMediaPlaylistControl::currentMediaChanged, + this, &QMediaPlaylist::currentMediaChanged); // Copy playlist items, sync playback mode and sync current index between // old control and new control @@ -214,20 +214,20 @@ bool QMediaPlaylist::setMediaObject(QMediaObject *mediaObject) connect(playlist, SIGNAL(loadFailed(QMediaPlaylist::Error,QString)), this, SLOT(_q_loadFailed(QMediaPlaylist::Error,QString))); - connect(playlist, SIGNAL(mediaChanged(int,int)), this, SIGNAL(mediaChanged(int,int))); - connect(playlist, SIGNAL(mediaAboutToBeInserted(int,int)), this, SIGNAL(mediaAboutToBeInserted(int,int))); - connect(playlist, SIGNAL(mediaInserted(int,int)), this, SIGNAL(mediaInserted(int,int))); - connect(playlist, SIGNAL(mediaAboutToBeRemoved(int,int)), this, SIGNAL(mediaAboutToBeRemoved(int,int))); - connect(playlist, SIGNAL(mediaRemoved(int,int)), this, SIGNAL(mediaRemoved(int,int))); + connect(playlist, &QMediaPlaylistProvider::mediaChanged, this, &QMediaPlaylist::mediaChanged); + connect(playlist, &QMediaPlaylistProvider::mediaAboutToBeInserted, this, &QMediaPlaylist::mediaAboutToBeInserted); + connect(playlist, &QMediaPlaylistProvider::mediaInserted, this, &QMediaPlaylist::mediaInserted); + connect(playlist, &QMediaPlaylistProvider::mediaAboutToBeRemoved, this, &QMediaPlaylist::mediaAboutToBeRemoved); + connect(playlist, &QMediaPlaylistProvider::mediaRemoved, this, &QMediaPlaylist::mediaRemoved); - connect(playlist, SIGNAL(loaded()), this, SIGNAL(loaded())); + connect(playlist, &QMediaPlaylistProvider::loaded, this, &QMediaPlaylist::loaded); - connect(d->control, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode)), - this, SIGNAL(playbackModeChanged(QMediaPlaylist::PlaybackMode))); - connect(d->control, SIGNAL(currentIndexChanged(int)), - this, SIGNAL(currentIndexChanged(int))); - connect(d->control, SIGNAL(currentMediaChanged(QMediaContent)), - this, SIGNAL(currentMediaChanged(QMediaContent))); + connect(d->control, &QMediaPlaylistControl::playbackModeChanged, + this, &QMediaPlaylist::playbackModeChanged); + connect(d->control, &QMediaPlaylistControl::currentIndexChanged, + this, &QMediaPlaylist::currentIndexChanged); + connect(d->control, &QMediaPlaylistControl::currentMediaChanged, + this, &QMediaPlaylist::currentMediaChanged); if (removedStart != -1 && removedEnd != -1) { emit mediaAboutToBeRemoved(removedStart, removedEnd); diff --git a/src/multimedia/qmediaserviceprovider.cpp b/src/multimedia/qmediaserviceprovider.cpp index 5731cf5be..d8ffe42ae 100644 --- a/src/multimedia/qmediaserviceprovider.cpp +++ b/src/multimedia/qmediaserviceprovider.cpp @@ -682,6 +682,7 @@ Q_GLOBAL_STATIC(QPluginServiceProvider, pluginProvider); */ /*! + \internal \fn QMediaServiceProvider::requestService(const QByteArray &type, const QMediaServiceProviderHint &hint) Requests an instance of a \a type service which best matches the given \a @@ -695,12 +696,14 @@ Q_GLOBAL_STATIC(QPluginServiceProvider, pluginProvider); */ /*! + \internal \fn QMediaServiceProvider::releaseService(QMediaService *service) Releases a media \a service requested with requestService(). */ /*! + \internal \fn QMediaServiceProvider::supportedFeatures(const QMediaService *service) const Returns the features supported by a given \a service. @@ -713,6 +716,7 @@ QMediaServiceProviderHint::Features QMediaServiceProvider::supportedFeatures(con } /*! + \internal Returns how confident a media service provider is that is can provide a \a serviceType service that is able to play media of a specific \a mimeType that is encoded using the listed \a codecs while adhering to constraints @@ -732,6 +736,7 @@ QMultimedia::SupportEstimate QMediaServiceProvider::hasSupport(const QByteArray } /*! + \internal \fn QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceType, int flags) const Returns a list of MIME types supported by the service provider for the @@ -749,6 +754,7 @@ QStringList QMediaServiceProvider::supportedMimeTypes(const QByteArray &serviceT } /*! + \internal \since 5.3 Returns the default device for a \a service type. @@ -760,6 +766,7 @@ QByteArray QMediaServiceProvider::defaultDevice(const QByteArray &serviceType) c } /*! + \internal Returns the list of devices related to \a service type. */ QList<QByteArray> QMediaServiceProvider::devices(const QByteArray &service) const @@ -769,6 +776,7 @@ QList<QByteArray> QMediaServiceProvider::devices(const QByteArray &service) cons } /*! + \internal Returns the description of \a device related to \a serviceType, suitable for use by an application for display. */ @@ -780,6 +788,7 @@ QString QMediaServiceProvider::deviceDescription(const QByteArray &serviceType, } /*! + \internal \since 5.3 Returns the physical position of a camera \a device on the system hardware. @@ -791,6 +800,7 @@ QCamera::Position QMediaServiceProvider::cameraPosition(const QByteArray &device } /*! + \internal \since 5.3 Returns the physical orientation of the camera \a device. The value is the angle by which the @@ -818,6 +828,7 @@ void QMediaServiceProvider::setDefaultServiceProvider(QMediaServiceProvider *pro /*! + \internal Returns a default provider of media services. */ QMediaServiceProvider *QMediaServiceProvider::defaultServiceProvider() diff --git a/src/plugins/alsa/qalsaaudiooutput.cpp b/src/plugins/alsa/qalsaaudiooutput.cpp index ddbe04de9..5c8ae171c 100644 --- a/src/plugins/alsa/qalsaaudiooutput.cpp +++ b/src/plugins/alsa/qalsaaudiooutput.cpp @@ -53,9 +53,11 @@ #include <QtMultimedia/private/qaudiohelpers_p.h> #include "qalsaaudiooutput.h" #include "qalsaaudiodeviceinfo.h" +#include <QLoggingCategory> QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcAlsaOutput, "qt.multimedia.alsa.output") //#define DEBUG_AUDIO 1 QAlsaAudioOutput::QAlsaAudioOutput(const QByteArray &device) @@ -403,28 +405,22 @@ bool QAlsaAudioOutput::open() fatal = true; errMessage = QString::fromLatin1("QAudioOutput: buffer/period min and max: err = %1").arg(err); } else { - if (maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time) { -#ifdef DEBUG_AUDIO - qDebug()<<"defaults out of range"; - qDebug()<<"pmin="<<minPeriodTime<<", pmax="<<maxPeriodTime<<", bmin="<<minBufferTime<<", bmax="<<maxBufferTime; -#endif - period_time = minPeriodTime; - if (period_time*4 <= maxBufferTime) { - // Use 4 periods if possible - buffer_time = period_time*4; - chunks = 4; - } else if (period_time*2 <= maxBufferTime) { - // Use 2 periods if possible - buffer_time = period_time*2; - chunks = 2; + static unsigned user_buffer_time = qEnvironmentVariableIntValue("QT_ALSA_OUTPUT_BUFFER_TIME"); + static unsigned user_period_time = qEnvironmentVariableIntValue("QT_ALSA_OUTPUT_PERIOD_TIME"); + const bool outOfRange = maxBufferTime < buffer_time || buffer_time < minBufferTime || maxPeriodTime < period_time || minPeriodTime > period_time; + if (outOfRange || user_period_time || user_buffer_time) { + period_time = user_period_time ? user_period_time : minPeriodTime; + if (!user_buffer_time) { + chunks = maxBufferTime / period_time; + buffer_time = period_time * chunks; } else { - qWarning()<<"QAudioOutput: alsa only supports single period!"; - fatal = true; + buffer_time = user_buffer_time; + chunks = buffer_time / period_time; } -#ifdef DEBUG_AUDIO - qDebug()<<"used: buffer_time="<<buffer_time<<", period_time="<<period_time; -#endif } + qCDebug(lcAlsaOutput) << "buffer time: [" << minBufferTime << "-" << maxBufferTime << "] =" << buffer_time; + qCDebug(lcAlsaOutput) << "period time: [" << minPeriodTime << "-" << maxPeriodTime << "] =" << period_time; + qCDebug(lcAlsaOutput) << "chunks =" << chunks; } } if ( !fatal ) { diff --git a/src/plugins/android/src/common/qandroidmultimediautils.cpp b/src/plugins/android/src/common/qandroidmultimediautils.cpp index a4a7f773d..1f03d5d29 100644 --- a/src/plugins/android/src/common/qandroidmultimediautils.cpp +++ b/src/plugins/android/src/common/qandroidmultimediautils.cpp @@ -113,7 +113,7 @@ AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrame::Pix } } -bool qt_androidRequestPermission(const QString &key) +static bool androidRequestPermission(const QString &key) { using namespace QtAndroidPrivate; @@ -139,4 +139,14 @@ bool qt_androidRequestPermission(const QString &key) return true; } +bool qt_androidRequestCameraPermission() +{ + return androidRequestPermission(QLatin1String("android.permission.CAMERA")); +} + +bool qt_androidRequestRecordingPermission() +{ + return androidRequestPermission(QLatin1String("android.permission.RECORD_AUDIO")); +} + QT_END_NAMESPACE diff --git a/src/plugins/android/src/common/qandroidmultimediautils.h b/src/plugins/android/src/common/qandroidmultimediautils.h index 0a837ae3c..381671cb8 100644 --- a/src/plugins/android/src/common/qandroidmultimediautils.h +++ b/src/plugins/android/src/common/qandroidmultimediautils.h @@ -55,7 +55,8 @@ bool qt_sizeLessThan(const QSize &s1, const QSize &s2); QVideoFrame::PixelFormat qt_pixelFormatFromAndroidImageFormat(AndroidCamera::ImageFormat f); AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrame::PixelFormat f); -bool qt_androidRequestPermission(const QString &key); +bool qt_androidRequestCameraPermission(); +bool qt_androidRequestRecordingPermission(); QT_END_NAMESPACE diff --git a/src/plugins/android/src/common/qandroidvideooutput.cpp b/src/plugins/android/src/common/qandroidvideooutput.cpp index 25e67e865..fd6eb0e8b 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.cpp +++ b/src/plugins/android/src/common/qandroidvideooutput.cpp @@ -49,6 +49,8 @@ #include <qopenglshaderprogram.h> #include <qopenglframebufferobject.h> #include <QtCore/private/qjnihelpers_p.h> +#include <QtGui/QWindow> +#include <QtGui/QOffscreenSurface> QT_BEGIN_NAMESPACE @@ -182,6 +184,8 @@ QAndroidTextureVideoOutput::QAndroidTextureVideoOutput(QObject *parent) QAndroidTextureVideoOutput::~QAndroidTextureVideoOutput() { + delete m_offscreenSurface; + delete m_glContext; clearSurfaceTexture(); if (m_glDeleter) { // Make sure all of these are deleted on the render thread. @@ -345,6 +349,35 @@ bool QAndroidTextureVideoOutput::renderFrameToFbo() if (!m_nativeSize.isValid() || !m_surfaceTexture) return false; + // Make sure we have an OpenGL context to make current. + if (!QOpenGLContext::currentContext() && !m_glContext) { + // Create Hidden QWindow surface to create context in this thread. + m_offscreenSurface = new QWindow(); + m_offscreenSurface->setSurfaceType(QWindow::OpenGLSurface); + // Needs geometry to be a valid surface, but size is not important. + m_offscreenSurface->setGeometry(0, 0, 1, 1); + m_offscreenSurface->create(); + + // Create OpenGL context and set share context from surface. + m_glContext = new QOpenGLContext(); + m_glContext->setFormat(m_offscreenSurface->requestedFormat()); + + auto surface = qobject_cast<QAbstractVideoSurface *>(m_surface->property("videoSurface").value<QObject *>()); + if (!surface) + surface = m_surface; + auto shareContext = qobject_cast<QOpenGLContext *>(surface->property("GLContext").value<QObject *>()); + if (shareContext) + m_glContext->setShareContext(shareContext); + + if (!m_glContext->create()) { + qWarning("Failed to create QOpenGLContext"); + return false; + } + } + + if (m_glContext) + m_glContext->makeCurrent(m_offscreenSurface); + createGLResources(); m_surfaceTexture->updateTexImage(); diff --git a/src/plugins/android/src/common/qandroidvideooutput.h b/src/plugins/android/src/common/qandroidvideooutput.h index 2a35247e9..456fe8e22 100644 --- a/src/plugins/android/src/common/qandroidvideooutput.h +++ b/src/plugins/android/src/common/qandroidvideooutput.h @@ -51,6 +51,8 @@ class AndroidSurfaceHolder; class QOpenGLFramebufferObject; class QOpenGLShaderProgram; class QAbstractVideoSurface; +class QWindow; +class QOpenGLContext; class QAndroidVideoOutput : public QObject { @@ -132,6 +134,9 @@ private: bool m_surfaceTextureCanAttachToContext; + QWindow *m_offscreenSurface = nullptr; + QOpenGLContext *m_glContext = nullptr; + friend class AndroidTextureVideoBuffer; }; diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp index 5df8241e0..a0f809376 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.cpp @@ -77,6 +77,7 @@ QAndroidCameraSession::QAndroidCameraSession(QObject *parent) , m_captureCanceled(false) , m_currentImageCaptureId(-1) , m_previewCallback(0) + , m_keepActive(false) { m_mediaStorageLocation.addStorageLocation( QMediaStorageLocation::Pictures, @@ -182,7 +183,7 @@ bool QAndroidCameraSession::open() m_status = QCamera::LoadingStatus; emit statusChanged(m_status); - m_camera = AndroidCamera::requestCameraPermission() ? AndroidCamera::open(m_selectedCamera) : nullptr; + m_camera = AndroidCamera::open(m_selectedCamera); if (m_camera) { connect(m_camera, SIGNAL(pictureExposed()), this, SLOT(onCameraPictureExposed())); @@ -912,7 +913,7 @@ void QAndroidCameraSession::onApplicationStateChanged(Qt::ApplicationState state { switch (state) { case Qt::ApplicationInactive: - if (m_state != QCamera::UnloadedState) { + if (!m_keepActive && m_state != QCamera::UnloadedState) { m_savedState = m_state; close(); m_state = QCamera::UnloadedState; @@ -930,4 +931,12 @@ void QAndroidCameraSession::onApplicationStateChanged(Qt::ApplicationState state } } +bool QAndroidCameraSession::requestRecordingPermission() +{ + m_keepActive = true; + const bool result = qt_androidRequestRecordingPermission(); + m_keepActive = false; + return result; +} + QT_END_NAMESPACE diff --git a/src/plugins/android/src/mediacapture/qandroidcamerasession.h b/src/plugins/android/src/mediacapture/qandroidcamerasession.h index b51dcc628..728dc484e 100644 --- a/src/plugins/android/src/mediacapture/qandroidcamerasession.h +++ b/src/plugins/android/src/mediacapture/qandroidcamerasession.h @@ -112,6 +112,7 @@ public: virtual void onFrameAvailable(const QVideoFrame &frame) = 0; }; void setPreviewCallback(PreviewCallback *callback); + bool requestRecordingPermission(); Q_SIGNALS: void statusChanged(QCamera::Status status); @@ -196,6 +197,7 @@ private: QSet<QAndroidMediaVideoProbeControl *> m_videoProbes; QMutex m_videoProbesMutex; PreviewCallback *m_previewCallback; + bool m_keepActive; }; QT_END_NAMESPACE diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp index bc9bc983e..7cc3ad619 100644 --- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp @@ -206,8 +206,10 @@ void QAndroidCaptureSession::start() delete m_mediaRecorder; } - - if (!AndroidMediaRecorder::requestRecordingPermission()) { + const bool granted = m_cameraSession + ? m_cameraSession->requestRecordingPermission() + : qt_androidRequestRecordingPermission(); + if (!granted) { setStatus(QMediaRecorder::UnavailableStatus); Q_EMIT error(QMediaRecorder::ResourceError, QLatin1String("Permission denied.")); return; diff --git a/src/plugins/android/src/wrappers/jni/androidcamera.cpp b/src/plugins/android/src/wrappers/jni/androidcamera.cpp index 2f32fb742..3ea7bc773 100644 --- a/src/plugins/android/src/wrappers/jni/androidcamera.cpp +++ b/src/plugins/android/src/wrappers/jni/androidcamera.cpp @@ -58,11 +58,6 @@ QT_BEGIN_NAMESPACE static const char QtCameraListenerClassName[] = "org/qtproject/qt5/android/multimedia/QtCameraListener"; -static QString cameraPermissionKey() -{ - return QStringLiteral("android.permission.CAMERA"); -} - typedef QHash<int, AndroidCamera *> CameraMap; Q_GLOBAL_STATIC(CameraMap, cameras) Q_GLOBAL_STATIC(QReadWriteLock, rwLock) @@ -324,6 +319,9 @@ AndroidCamera::~AndroidCamera() AndroidCamera *AndroidCamera::open(int cameraId) { + if (!qt_androidRequestCameraPermission()) + return nullptr; + AndroidCameraPrivate *d = new AndroidCameraPrivate(); QThread *worker = new QThread; worker->start(); @@ -764,7 +762,7 @@ QJNIObjectPrivate AndroidCamera::getCameraObject() int AndroidCamera::getNumberOfCameras() { - if (!requestCameraPermission()) + if (!qt_androidRequestCameraPermission()) return 0; return QJNIObjectPrivate::callStaticMethod<jint>("android/hardware/Camera", @@ -801,11 +799,6 @@ void AndroidCamera::getCameraInfo(int id, AndroidCameraInfo *info) } } -bool AndroidCamera::requestCameraPermission() -{ - return qt_androidRequestPermission(cameraPermissionKey()); -} - void AndroidCamera::startPreview() { Q_D(AndroidCamera); diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp index d0101411b..d607ab806 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp +++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp @@ -383,11 +383,6 @@ void AndroidMediaRecorder::setSurfaceHolder(AndroidSurfaceHolder *holder) } } -bool AndroidMediaRecorder::requestRecordingPermission() -{ - return qt_androidRequestPermission(QLatin1String("android.permission.RECORD_AUDIO")); -} - bool AndroidMediaRecorder::initJNI(JNIEnv *env) { jclass clazz = QJNIEnvironmentPrivate::findClass(QtMediaRecorderListenerClassName, diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h index cd2d164d8..e4b3a80ea 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h +++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h @@ -160,7 +160,6 @@ public: void setSurfaceTexture(AndroidSurfaceTexture *texture); void setSurfaceHolder(AndroidSurfaceHolder *holder); - static bool requestRecordingPermission(); static bool initJNI(JNIEnv *env); Q_SIGNALS: diff --git a/src/plugins/avfoundation/camera/avfmediaassetwriter.h b/src/plugins/avfoundation/camera/avfmediaassetwriter.h index 9d61d5089..f063dab4b 100644 --- a/src/plugins/avfoundation/camera/avfmediaassetwriter.h +++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.h @@ -43,7 +43,6 @@ #include "avfcamerautility.h" #include <QtCore/qglobal.h> -#include <QtCore/qatomic.h> #include <AVFoundation/AVFoundation.h> @@ -52,17 +51,10 @@ QT_BEGIN_NAMESPACE class AVFMediaRecorderControlIOS; class AVFCameraService; -typedef QAtomicInteger<qint64> AVFAtomicInt64; - QT_END_NAMESPACE @interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) : NSObject<AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioDataOutputSampleBufferDelegate> -{ -@public - QT_PREPEND_NAMESPACE(AVFAtomicInt64) m_durationInMs; -} - - (id)initWithDelegate:(QT_PREPEND_NAMESPACE(AVFMediaRecorderControlIOS) *)delegate; - (bool)setupWithFileURL:(NSURL *)fileURL @@ -76,6 +68,7 @@ QT_END_NAMESPACE - (void)stop; // This to be called from the recorder control's dtor: - (void)abort; +- (qint64)durationInMs; @end diff --git a/src/plugins/avfoundation/camera/avfmediaassetwriter.mm b/src/plugins/avfoundation/camera/avfmediaassetwriter.mm index 318d66117..2d40b9087 100644 --- a/src/plugins/avfoundation/camera/avfmediaassetwriter.mm +++ b/src/plugins/avfoundation/camera/avfmediaassetwriter.mm @@ -47,6 +47,7 @@ #include "avfmediacontainercontrol.h" #include <QtCore/qmetaobject.h> +#include <QtCore/qatomic.h> QT_USE_NAMESPACE @@ -79,6 +80,8 @@ enum WriterState WriterStateAborted }; +using AVFAtomicInt64 = QAtomicInteger<qint64>; + } // unnamed namespace @interface QT_MANGLE_NAMESPACE(AVFMediaAssetWriter) (PrivateAPI) @@ -93,32 +96,35 @@ enum WriterState @private AVFCameraService *m_service; - QT_PREPEND_NAMESPACE(AVFScopedPointer)<AVAssetWriterInput> m_cameraWriterInput; - QT_PREPEND_NAMESPACE(AVFScopedPointer)<AVCaptureDeviceInput> m_audioInput; - QT_PREPEND_NAMESPACE(AVFScopedPointer)<AVCaptureAudioDataOutput> m_audioOutput; - QT_PREPEND_NAMESPACE(AVFScopedPointer)<AVAssetWriterInput> m_audioWriterInput; + AVFScopedPointer<AVAssetWriterInput> m_cameraWriterInput; + AVFScopedPointer<AVCaptureDeviceInput> m_audioInput; + AVFScopedPointer<AVCaptureAudioDataOutput> m_audioOutput; + AVFScopedPointer<AVAssetWriterInput> m_audioWriterInput; + AVCaptureDevice *m_audioCaptureDevice; // Queue to write sample buffers: - QT_PREPEND_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_writerQueue; + AVFScopedPointer<dispatch_queue_t> m_writerQueue; // High priority serial queue for video output: - QT_PREPEND_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_videoQueue; + AVFScopedPointer<dispatch_queue_t> m_videoQueue; // Serial queue for audio output: - QT_PREPEND_NAMESPACE(AVFScopedPointer)<dispatch_queue_t> m_audioQueue; + AVFScopedPointer<dispatch_queue_t> m_audioQueue; - QT_PREPEND_NAMESPACE(AVFScopedPointer)<AVAssetWriter> m_assetWriter; + AVFScopedPointer<AVAssetWriter> m_assetWriter; - QT_PREPEND_NAMESPACE(AVFMediaRecorderControlIOS) *m_delegate; + AVFMediaRecorderControlIOS *m_delegate; bool m_setStartTime; - QT_PREPEND_NAMESPACE(QAtomicInt) m_state; -@private + QAtomicInt m_state; + CMTime m_startTime; CMTime m_lastTimeStamp; NSDictionary *m_audioSettings; NSDictionary *m_videoSettings; + + AVFAtomicInt64 m_durationInMs; } - (id)initWithDelegate:(AVFMediaRecorderControlIOS *)delegate @@ -413,7 +419,7 @@ enum WriterState m_audioOutput.reset([[AVCaptureAudioDataOutput alloc] init]); - if (m_audioOutput && [captureSession canAddOutput:m_audioOutput]) { + if (m_audioOutput.data() && [captureSession canAddOutput:m_audioOutput]) { [captureSession addOutput:m_audioOutput]; } else { qDebugCamera() << Q_FUNC_INFO << "failed to add audio output"; @@ -431,7 +437,7 @@ enum WriterState { Q_ASSERT(m_service && m_service->videoOutput() && m_service->videoOutput()->videoDataOutput()); - Q_ASSERT(m_assetWriter); + Q_ASSERT(m_assetWriter.data()); m_cameraWriterInput.reset([[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:m_videoSettings @@ -451,7 +457,7 @@ enum WriterState m_cameraWriterInput.data().expectsMediaDataInRealTime = YES; - if (m_audioOutput) { + if (m_audioOutput.data()) { CMFormatDescriptionRef sourceFormat = m_audioCaptureDevice ? m_audioCaptureDevice.activeFormat.formatDescription : 0; m_audioWriterInput.reset([[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeAudio outputSettings:m_audioSettings @@ -479,7 +485,7 @@ enum WriterState [m_service->videoOutput()->videoDataOutput() setSampleBufferDelegate:self queue:m_videoQueue]; - if (m_audioOutput) { + if (m_audioOutput.data()) { Q_ASSERT(m_audioQueue); [m_audioOutput setSampleBufferDelegate:self queue:m_audioQueue]; } @@ -500,4 +506,9 @@ enum WriterState } } +- (qint64)durationInMs +{ + return m_durationInMs.loadAcquire(); +} + @end diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm index 0b31bd0bc..62197e900 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol_ios.mm @@ -144,7 +144,7 @@ QMediaRecorder::Status AVFMediaRecorderControlIOS::status() const qint64 AVFMediaRecorderControlIOS::duration() const { - return m_writer.data()->m_durationInMs.load(); + return m_writer.data().durationInMs; } bool AVFMediaRecorderControlIOS::isMuted() const diff --git a/src/plugins/opensles/qopenslesaudioinput.cpp b/src/plugins/opensles/qopenslesaudioinput.cpp index ad87cb057..54ed18ac1 100644 --- a/src/plugins/opensles/qopenslesaudioinput.cpp +++ b/src/plugins/opensles/qopenslesaudioinput.cpp @@ -117,6 +117,8 @@ QOpenSLESAudioInput::QOpenSLESAudioInput(const QByteArray &device) m_recorderPreset = SL_ANDROID_RECORDING_PRESET_CAMCORDER; else if (qstrcmp(device, QT_ANDROID_PRESET_VOICE_RECOGNITION) == 0) m_recorderPreset = SL_ANDROID_RECORDING_PRESET_VOICE_RECOGNITION; + else if (qstrcmp(device, QT_ANDROID_PRESET_VOICE_COMMUNICATION) == 0) + m_recorderPreset = SL_ANDROID_RECORDING_PRESET_VOICE_COMMUNICATION; else m_recorderPreset = SL_ANDROID_RECORDING_PRESET_GENERIC; #endif diff --git a/src/plugins/opensles/qopenslesaudioinput.h b/src/plugins/opensles/qopenslesaudioinput.h index ad84db0cd..35cc37959 100644 --- a/src/plugins/opensles/qopenslesaudioinput.h +++ b/src/plugins/opensles/qopenslesaudioinput.h @@ -50,6 +50,7 @@ #define QT_ANDROID_PRESET_MIC "mic" #define QT_ANDROID_PRESET_CAMCORDER "camcorder" #define QT_ANDROID_PRESET_VOICE_RECOGNITION "voicerecognition" +#define QT_ANDROID_PRESET_VOICE_COMMUNICATION "voicecommunication" #endif diff --git a/src/plugins/opensles/qopenslesengine.cpp b/src/plugins/opensles/qopenslesengine.cpp index 43cdcb276..36025dcfd 100644 --- a/src/plugins/opensles/qopenslesengine.cpp +++ b/src/plugins/opensles/qopenslesengine.cpp @@ -114,7 +114,8 @@ QList<QByteArray> QOpenSLESEngine::availableDevices(QAudio::Mode mode) const #ifdef ANDROID devices << QT_ANDROID_PRESET_MIC << QT_ANDROID_PRESET_CAMCORDER - << QT_ANDROID_PRESET_VOICE_RECOGNITION; + << QT_ANDROID_PRESET_VOICE_RECOGNITION + << QT_ANDROID_PRESET_VOICE_COMMUNICATION; #else devices << "default"; #endif diff --git a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp index 18cf0e927..32166502d 100644 --- a/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp +++ b/src/qtmultimediaquicktools/qdeclarativevideooutput.cpp @@ -57,7 +57,7 @@ Q_LOGGING_CATEGORY(qLcVideo, "qt.multimedia.video") /*! \qmltype VideoOutput - \instantiates QDeclarativeVideoOutput + //! \instantiates QDeclarativeVideoOutput \brief Render video or camera viewfinder. \ingroup multimedia_qml @@ -206,6 +206,7 @@ void QDeclarativeVideoOutput::setSource(QObject *source) } m_sourceType = MediaObjectSource; +#if QT_CONFIG(opengl) } else if (metaObject->indexOfProperty("videoSurface") != -1) { // Make sure our backend is a QDeclarativeVideoRendererBackend m_backend.reset(); @@ -219,6 +220,7 @@ void QDeclarativeVideoOutput::setSource(QObject *source) m_source.data()->setProperty("videoSurface", QVariant::fromValue<QAbstractVideoSurface*>(surface)); m_sourceType = VideoSurfaceSource; +#endif } else { m_sourceType = NoSource; } @@ -247,12 +249,13 @@ bool QDeclarativeVideoOutput::createBackend(QMediaService *service) } } } - +#if QT_CONFIG(opengl) if (!backendAvailable) { m_backend.reset(new QDeclarativeVideoRendererBackend(this)); if (m_backend->init(service)) backendAvailable = true; } +#endif // QDeclarativeVideoWindowBackend only works when there is a service with a QVideoWindowControl. // Without service, the QDeclarativeVideoRendererBackend should always work. diff --git a/src/qtmultimediaquicktools/qtmultimediaquicktools.pro b/src/qtmultimediaquicktools/qtmultimediaquicktools.pro index 7c8d07647..cb1f8106b 100644 --- a/src/qtmultimediaquicktools/qtmultimediaquicktools.pro +++ b/src/qtmultimediaquicktools/qtmultimediaquicktools.pro @@ -11,20 +11,23 @@ PRIVATE_HEADERS += \ HEADERS += \ $$PRIVATE_HEADERS \ - qdeclarativevideooutput_render_p.h \ - qdeclarativevideooutput_window_p.h \ - qsgvideonode_yuv_p.h \ - qsgvideonode_rgb_p.h \ - qsgvideonode_texture_p.h + qdeclarativevideooutput_window_p.h SOURCES += \ qsgvideonode_p.cpp \ qdeclarativevideooutput.cpp \ - qdeclarativevideooutput_render.cpp \ - qdeclarativevideooutput_window.cpp \ - qsgvideonode_yuv.cpp \ - qsgvideonode_rgb.cpp \ - qsgvideonode_texture.cpp + qdeclarativevideooutput_window.cpp + +qtConfig(opengl) { + SOURCES += qdeclarativevideooutput_render.cpp \ + qsgvideonode_rgb.cpp \ + qsgvideonode_yuv.cpp \ + qsgvideonode_texture.cpp + HEADERS += qdeclarativevideooutput_render_p.h \ + qsgvideonode_rgb_p.h \ + qsgvideonode_yuv_p.h \ + qsgvideonode_texture_p.h +} RESOURCES += \ qtmultimediaquicktools.qrc diff --git a/src/src.pro b/src/src.pro index 97a053379..1dc1015c6 100644 --- a/src/src.pro +++ b/src/src.pro @@ -16,7 +16,7 @@ src_plugins.subdir = plugins src_plugins.depends = multimedia -qtHaveModule(quick):qtConfig(opengl) { +qtHaveModule(quick) { src_qtmultimediaquicktools.subdir = qtmultimediaquicktools src_qtmultimediaquicktools.depends = multimedia |