diff options
author | Liang Qi <liang.qi@qt.io> | 2017-04-18 22:03:42 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2017-04-18 22:03:42 +0200 |
commit | 7caf543280bf8bdb0d3ea18d6c1a2537fdccfe6e (patch) | |
tree | 5c18b1ca8df1f39bb71cb1b579852f7b39894f1c /src/plugins | |
parent | 6de2c8aca6736550d87057b0a3f025464bf21246 (diff) | |
parent | d5d7dcfb15c0b5c5e9009b83fba922ea0b7e86f5 (diff) | |
download | qtmultimedia-7caf543280bf8bdb0d3ea18d6c1a2537fdccfe6e.tar.gz |
Merge remote-tracking branch 'origin/5.8' into 5.9
Change-Id: I7cd203eec77f3b5689c14b81b0862c5b70bab1a6
Diffstat (limited to 'src/plugins')
12 files changed, 278 insertions, 5 deletions
diff --git a/src/plugins/android/src/common/common.pri b/src/plugins/android/src/common/common.pri index 9c741bd94..1b02b99ea 100644 --- a/src/plugins/android/src/common/common.pri +++ b/src/plugins/android/src/common/common.pri @@ -1,6 +1,7 @@ INCLUDEPATH += $$PWD HEADERS += \ + $$PWD/qandroidglobal.h \ $$PWD/qandroidvideooutput.h \ $$PWD/qandroidmultimediautils.h diff --git a/src/plugins/android/src/common/qandroidglobal.h b/src/plugins/android/src/common/qandroidglobal.h new file mode 100644 index 000000000..e7342be97 --- /dev/null +++ b/src/plugins/android/src/common/qandroidglobal.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 QANDROIDGLOBAL_H +#define QANDROIDGLOBAL_H + +#include <QtCore/qglobal.h> +#include <QtCore/qloggingcategory.h> + +QT_BEGIN_NAMESPACE + +Q_DECLARE_LOGGING_CATEGORY(qtAndroidMediaPlugin) + +QT_END_NAMESPACE + +#endif // QANDROIDGLOBAL_H diff --git a/src/plugins/android/src/common/qandroidmultimediautils.cpp b/src/plugins/android/src/common/qandroidmultimediautils.cpp index c7a16dcf0..a4a7f773d 100644 --- a/src/plugins/android/src/common/qandroidmultimediautils.cpp +++ b/src/plugins/android/src/common/qandroidmultimediautils.cpp @@ -38,8 +38,11 @@ ****************************************************************************/ #include "qandroidmultimediautils.h" +#include "qandroidglobal.h" #include <qlist.h> +#include <QtCore/private/qjni_p.h> +#include <QtCore/private/qjnihelpers_p.h> QT_BEGIN_NAMESPACE @@ -110,4 +113,30 @@ AndroidCamera::ImageFormat qt_androidImageFormatFromPixelFormat(QVideoFrame::Pix } } +bool qt_androidRequestPermission(const QString &key) +{ + using namespace QtAndroidPrivate; + + if (androidSdkVersion() < 23) + return true; + + PermissionsResult res = checkPermission(key); + if (res == PermissionsResult::Granted) // Permission already granted? + return true; + + QJNIEnvironmentPrivate env; + const auto &results = requestPermissionsSync(env, QStringList() << key); + if (!results.contains(key)) { + qCWarning(qtAndroidMediaPlugin, "No permission found for key: %s", qPrintable(key)); + return false; + } + + if (results[key] == PermissionsResult::Denied) { + qCDebug(qtAndroidMediaPlugin, "%s - Permission denied by user!", qPrintable(key)); + return false; + } + + return true; +} + QT_END_NAMESPACE diff --git a/src/plugins/android/src/common/qandroidmultimediautils.h b/src/plugins/android/src/common/qandroidmultimediautils.h index 0e811ecb8..0a837ae3c 100644 --- a/src/plugins/android/src/common/qandroidmultimediautils.h +++ b/src/plugins/android/src/common/qandroidmultimediautils.h @@ -55,6 +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); + QT_END_NAMESPACE #endif // QANDROIDMULTIMEDIAUTILS_H diff --git a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp index 9e38c8539..a5aff51cd 100644 --- a/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp +++ b/src/plugins/android/src/mediacapture/qandroidcapturesession.cpp @@ -44,6 +44,7 @@ #include "androidmultimediautils.h" #include "qandroidmultimediautils.h" #include "qandroidvideooutput.h" +#include "qandroidglobal.h" QT_BEGIN_NAMESPACE @@ -177,6 +178,14 @@ void QAndroidCaptureSession::start() m_mediaRecorder->release(); delete m_mediaRecorder; } + + + if (!AndroidMediaRecorder::requestRecordingPermission()) { + setStatus(QMediaRecorder::UnavailableStatus); + Q_EMIT error(QMediaRecorder::ResourceError, QLatin1String("Permission denied.")); + return; + } + m_mediaRecorder = new AndroidMediaRecorder; connect(m_mediaRecorder, SIGNAL(error(int,int)), this, SLOT(onError(int,int))); connect(m_mediaRecorder, SIGNAL(info(int,int)), this, SLOT(onInfo(int,int))); diff --git a/src/plugins/android/src/qandroidmediaserviceplugin.cpp b/src/plugins/android/src/qandroidmediaserviceplugin.cpp index 0de231c9d..f441baf0a 100644 --- a/src/plugins/android/src/qandroidmediaserviceplugin.cpp +++ b/src/plugins/android/src/qandroidmediaserviceplugin.cpp @@ -50,10 +50,12 @@ #include "androidmultimediautils.h" #include "androidmediarecorder.h" #include "androidsurfaceview.h" -#include <qdebug.h> +#include "qandroidglobal.h" QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(qtAndroidMediaPlugin, "qt.multimedia.plugins.android") + QAndroidMediaServicePlugin::QAndroidMediaServicePlugin() { } @@ -72,7 +74,7 @@ QMediaService *QAndroidMediaServicePlugin::create(const QString &key) return new QAndroidCaptureService(key); } - qWarning() << "Android service plugin: unsupported key:" << key; + qCWarning(qtAndroidMediaPlugin) << "Android service plugin: unsupported key:" << key; return 0; } diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp index a707dd903..d0101411b 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp +++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.cpp @@ -42,6 +42,8 @@ #include "androidcamera.h" #include "androidsurfacetexture.h" #include "androidsurfaceview.h" +#include "qandroidglobal.h" +#include "qandroidmultimediautils.h" #include <QtCore/private/qjni_p.h> #include <qmap.h> @@ -381,6 +383,10 @@ void AndroidMediaRecorder::setSurfaceHolder(AndroidSurfaceHolder *holder) } } +bool AndroidMediaRecorder::requestRecordingPermission() +{ + return qt_androidRequestPermission(QLatin1String("android.permission.RECORD_AUDIO")); +} bool AndroidMediaRecorder::initJNI(JNIEnv *env) { diff --git a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h index e4b3a80ea..cd2d164d8 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediarecorder.h +++ b/src/plugins/android/src/wrappers/jni/androidmediarecorder.h @@ -160,6 +160,7 @@ public: void setSurfaceTexture(AndroidSurfaceTexture *texture); void setSurfaceHolder(AndroidSurfaceHolder *holder); + static bool requestRecordingPermission(); static bool initJNI(JNIEnv *env); Q_SIGNALS: diff --git a/src/plugins/directshow/player/directshowmetadatacontrol.cpp b/src/plugins/directshow/player/directshowmetadatacontrol.cpp index 45d3a958b..1f75e3340 100644 --- a/src/plugins/directshow/player/directshowmetadatacontrol.cpp +++ b/src/plugins/directshow/player/directshowmetadatacontrol.cpp @@ -87,6 +87,7 @@ DEFINE_PROPERTYKEY(PKEY_Media_AverageLevel, 0x09EDD5B6, 0xB301, 0x43C5, 0x99, 0x DEFINE_PROPERTYKEY(PKEY_Audio_ChannelCount, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 7); DEFINE_PROPERTYKEY(PKEY_Audio_PeakValue, 0x2579E5D0, 0x1116, 0x4084, 0xBD, 0x9A, 0x9B, 0x4F, 0x7C, 0xB4, 0xDF, 0x5E, 100); DEFINE_PROPERTYKEY(PKEY_Audio_SampleRate, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 5); +DEFINE_PROPERTYKEY(PKEY_Audio_Format, 0x64440490, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 2); DEFINE_PROPERTYKEY(PKEY_Music_AlbumTitle, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 4); DEFINE_PROPERTYKEY(PKEY_Music_AlbumArtist, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 13); DEFINE_PROPERTYKEY(PKEY_Music_Artist, 0x56A3372E, 0xCE9C, 0x11D2, 0x9F, 0x0E, 0x00, 0x60, 0x97, 0xC6, 0x86, 0xF6, 2); @@ -104,8 +105,111 @@ DEFINE_PROPERTYKEY(PKEY_Video_VerticalAspectRatio, 0x64440491, 0x4C8B, 0x11D1, 0 DEFINE_PROPERTYKEY(PKEY_Video_FrameRate, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 6); DEFINE_PROPERTYKEY(PKEY_Video_EncodingBitrate, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 8); DEFINE_PROPERTYKEY(PKEY_Video_Director, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 20); +DEFINE_PROPERTYKEY(PKEY_Video_Compression, 0x64440491, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 10); DEFINE_PROPERTYKEY(PKEY_Media_Writer, 0x64440492, 0x4C8B, 0x11D1, 0x8B, 0x70, 0x08, 0x00, 0x36, 0xB1, 0x1A, 0x03, 23); +static QString nameForGUIDString(const QString &guid) +{ + // Audio formats + if (guid == "{00001610-0000-0010-8000-00AA00389B71}" || guid == "{000000FF-0000-0010-8000-00AA00389B71}") + return QStringLiteral("MPEG AAC Audio"); + else if (guid == "{00001600-0000-0010-8000-00AA00389B71}") + return QStringLiteral("MPEG ADTS AAC Audio"); + else if (guid == "{00000092-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Dolby AC-3 SPDIF"); + else if (guid == "{E06D802C-DB46-11CF-B4D1-00805F6CBBEA}" || guid == "{00002000-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Dolby AC-3"); + else if (guid == "{A7FB87AF-2D02-42FB-A4D4-05CD93843BDD}") + return QStringLiteral("Dolby Digital Plus"); + else if (guid == "{00000009-0000-0010-8000-00AA00389B71}") + return QStringLiteral("DRM"); + else if (guid == "{00000008-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Digital Theater Systems Audio (DTS)"); + else if (guid == "{00000003-0000-0010-8000-00AA00389B71}") + return QStringLiteral("IEEE Float Audio"); + else if (guid == "{00000055-0000-0010-8000-00AA00389B71}") + return QStringLiteral("MPEG Audio Layer-3 (MP3)"); + else if (guid == "{00000050-0000-0010-8000-00AA00389B71}") + return QStringLiteral("MPEG-1 Audio"); + else if (guid == "{2E6D7033-767A-494D-B478-F29D25DC9037}") + return QStringLiteral("MPEG Audio Layer 1/2"); + else if (guid == "{0000000A-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Audio Voice"); + else if (guid == "{00000001-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Uncompressed PCM Audio"); + else if (guid == "{00000164-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Audio 9 SPDIF"); + else if (guid == "{00000161-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Audio 8 (WMA2)"); + else if (guid == "{00000162-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Audio 9 (WMA3"); + else if (guid == "{00000163-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Audio 9 Lossless"); + else if (guid == "{8D2FD10B-5841-4a6b-8905-588FEC1ADED9}") + return QStringLiteral("Vorbis"); + else if (guid == "{0000F1AC-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Free Lossless Audio Codec (FLAC)"); + else if (guid == "{00006C61-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Apple Lossless Audio Codec (ALAC)"); + + // Video formats + if (guid == "{35327664-0000-0010-8000-00AA00389B71}") + return QStringLiteral("DVCPRO 25 (DV25)"); + else if (guid == "{30357664-0000-0010-8000-00AA00389B71}") + return QStringLiteral("DVCPRO 50 (DV50)"); + else if (guid == "{20637664-0000-0010-8000-00AA00389B71}") + return QStringLiteral("DVC/DV Video"); + else if (guid == "{31687664-0000-0010-8000-00AA00389B71}") + return QStringLiteral("DVCPRO 100 (DVH1)"); + else if (guid == "{64687664-0000-0010-8000-00AA00389B71}") + return QStringLiteral("HD-DVCR (DVHD)"); + else if (guid == "{64737664-0000-0010-8000-00AA00389B71}") + return QStringLiteral("SDL-DVCR (DVSD)"); + else if (guid == "{6C737664-0000-0010-8000-00AA00389B71}") + return QStringLiteral("SD-DVCR (DVSL)"); + else if (guid == "{33363248-0000-0010-8000-00AA00389B71}") + return QStringLiteral("H.263 Video"); + else if (guid == "{34363248-0000-0010-8000-00AA00389B71}") + return QStringLiteral("H.264 Video"); + else if (guid == "{35363248-0000-0010-8000-00AA00389B71}") + return QStringLiteral("H.265 Video"); + else if (guid == "{43564548-0000-0010-8000-00AA00389B71}") + return QStringLiteral("High Efficiency Video Coding (HEVC)"); + else if (guid == "{3253344D-0000-0010-8000-00AA00389B71}") + return QStringLiteral("MPEG-4 part 2 Video (M4S2)"); + else if (guid == "{47504A4D-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Motion JPEG (MJPG)"); + else if (guid == "{3334504D-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Microsoft MPEG 4 version 3 (MP43)"); + else if (guid == "{5334504D-0000-0010-8000-00AA00389B71}") + return QStringLiteral("ISO MPEG 4 version 1 (MP4S)"); + else if (guid == "{5634504D-0000-0010-8000-00AA00389B71}") + return QStringLiteral("MPEG-4 part 2 Video (MP4V)"); + else if (guid == "{E06D8026-DB46-11CF-B4D1-00805F6CBBEA}") + return QStringLiteral("MPEG-2 Video"); + else if (guid == "{3147504D-0000-0010-8000-00AA00389B71}") + return QStringLiteral("MPEG-1 Video"); + else if (guid == "{3153534D-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Screen 1 (MSS1)"); + else if (guid == "{3253534D-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Video 9 Screen (MSS2)"); + else if (guid == "{31564D57-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Video 7 (WMV1)"); + else if (guid == "{32564D57-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Video 8 (WMV2)"); + else if (guid == "{33564D57-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Video 9 (WMV3)"); + else if (guid == "{31435657-0000-0010-8000-00AA00389B71}") + return QStringLiteral("Windows Media Video VC1 (WVC1)"); + else if (guid == "{30385056-0000-0010-8000-00AA00389B71}") + return QStringLiteral("VP8 Video"); + else if (guid == "{30395056-0000-0010-8000-00AA00389B71}") + return QStringLiteral("VP9 Video"); + + else + return QStringLiteral("Unknown codec"); +} + typedef HRESULT (WINAPI *q_SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); static q_SHCreateItemFromParsingName sHCreateItemFromParsingName = 0; #endif @@ -498,6 +602,10 @@ void DirectShowMetaDataControl::updateMetadata(IFilterGraph2 *graph, IBaseFilter m_metadata.insert(QMediaMetaData::Director, convertValue(var)); } else if (IsEqualPropertyKey(key, PKEY_Media_Writer)) { m_metadata.insert(QMediaMetaData::Writer, convertValue(var)); + } else if (IsEqualPropertyKey(key, PKEY_Video_Compression)) { + m_metadata.insert(QMediaMetaData::VideoCodec, nameForGUIDString(convertValue(var).toString())); + } else if (IsEqualPropertyKey(key, PKEY_Audio_Format)) { + m_metadata.insert(QMediaMetaData::AudioCodec, nameForGUIDString(convertValue(var).toString())); } PropVariantClear(&var); diff --git a/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp b/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp index e9e8e0f71..b3505231b 100644 --- a/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp @@ -153,12 +153,41 @@ void CameraBinRecorder::applySettings() videoEncoderControl->videoSettings().codec().isEmpty()) { QList<QStringList> candidates; + + // By order of preference + + // .mp4 (h264, AAC) + candidates.append(QStringList() << "video/quicktime, variant=(string)iso" << "video/x-h264" << "audio/mpeg, mpegversion=(int)4"); + + // .mp4 (h264, AC3) + candidates.append(QStringList() << "video/quicktime, variant=(string)iso" << "video/x-h264" << "audio/x-ac3"); + + // .mp4 (h264, MP3) + candidates.append(QStringList() << "video/quicktime, variant=(string)iso" << "video/x-h264" << "audio/mpeg, mpegversion=(int)1, layer=(int)3"); + + // .mkv (h264, AAC) candidates.append(QStringList() << "video/x-matroska" << "video/x-h264" << "audio/mpeg, mpegversion=(int)4"); + + // .mkv (h264, AC3) + candidates.append(QStringList() << "video/x-matroska" << "video/x-h264" << "audio/x-ac3"); + + // .mkv (h264, MP3) + candidates.append(QStringList() << "video/x-matroska" << "video/x-h264" << "audio/mpeg, mpegversion=(int)1, layer=(int)3"); + + // .mov (h264, AAC) + candidates.append(QStringList() << "video/quicktime" << "video/x-h264" << "audio/mpeg, mpegversion=(int)4"); + + // .mov (h264, MP3) + candidates.append(QStringList() << "video/quicktime" << "video/x-h264" << "audio/mpeg, mpegversion=(int)1, layer=(int)3"); + + // .webm (VP8, Vorbis) candidates.append(QStringList() << "video/webm" << "video/x-vp8" << "audio/x-vorbis"); + + // .ogg (Theora, Vorbis) candidates.append(QStringList() << "application/ogg" << "video/x-theora" << "audio/x-vorbis"); - candidates.append(QStringList() << "video/quicktime" << "video/x-h264" << "audio/mpeg, mpegversion=(int)4"); - candidates.append(QStringList() << "video/quicktime" << "video/x-h264" << "audio/mpeg"); - candidates.append(QStringList() << "video/x-msvideo" << "video/x-divx" << "audio/mpeg"); + + // .avi (DivX, MP3) + candidates.append(QStringList() << "video/x-msvideo" << "video/x-divx" << "audio/mpeg, mpegversion=(int)1, layer=(int)3"); for (const QStringList &candidate : qAsConst(candidates)) { if (containerControl->supportedContainers().contains(candidate[0]) && diff --git a/src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp b/src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp index 54b31627e..0bfe76f2f 100644 --- a/src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp +++ b/src/plugins/gstreamer/mediaplayer/qgstreamerplayercontrol.cpp @@ -119,6 +119,9 @@ QMediaPlayerResourceSetInterface* QGstreamerPlayerControl::resources() const qint64 QGstreamerPlayerControl::position() const { + if (m_mediaStatus == QMediaPlayer::EndOfMedia) + return m_session->duration(); + return m_pendingSeekPosition != -1 ? m_pendingSeekPosition : m_session->position(); } diff --git a/src/plugins/opensles/qopenslesaudioinput.cpp b/src/plugins/opensles/qopenslesaudioinput.cpp index 30860650b..c3f5ed422 100644 --- a/src/plugins/opensles/qopenslesaudioinput.cpp +++ b/src/plugins/opensles/qopenslesaudioinput.cpp @@ -46,6 +46,8 @@ #ifdef ANDROID #include <SLES/OpenSLES_AndroidConfiguration.h> +#include <QtCore/private/qjnihelpers_p.h> +#include <QtCore/private/qjni_p.h> #endif QT_BEGIN_NAMESPACE @@ -55,6 +57,32 @@ QT_BEGIN_NAMESPACE #define MINIMUM_PERIOD_TIME_MS 5 #ifdef ANDROID +static bool hasRecordingPermission() +{ + using namespace QtAndroidPrivate; + if (androidSdkVersion() < 23) + return true; + + const QString key(QLatin1String("android.permission.RECORD_AUDIO")); + PermissionsResult res = checkPermission(key); + if (res == PermissionsResult::Granted) // Permission already granted? + return true; + + QJNIEnvironmentPrivate env; + const auto &results = requestPermissionsSync(env, QStringList() << key); + if (!results.contains(key)) { + qWarning("No permission found for key: %s", qPrintable(key)); + return false; + } + + if (results[key] == PermissionsResult::Denied) { + qDebug("%s - Permission denied by user!", qPrintable(key)); + return false; + } + + return true; +} + static void bufferQueueCallback(SLAndroidSimpleBufferQueueItf, void *context) #else static void bufferQueueCallback(SLBufferQueueItf, void *context) @@ -179,6 +207,9 @@ QIODevice *QOpenSLESAudioInput::start() bool QOpenSLESAudioInput::startRecording() { + if (!hasRecordingPermission()) + return false; + m_processedBytes = 0; m_clockStamp.restart(); m_lastNotifyTime = 0; |