From ff527de0133d597293459cc7d0f03f6203995cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lisandro=20Dami=C3=A1n=20Nicanor=20P=C3=A9rez=20Meyer?= Date: Thu, 10 Jul 2014 19:19:37 -0300 Subject: Detect V4L availability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not build related stuff if not found. Makes GStreamer support available on Hurd. Task-number: QTBUG-39762 Change-Id: I1f70b6975e5bef99ab2441aac4d90508bc8b64bd Reviewed-by: Lisandro Damián Nicanor Pérez Meyer Reviewed-by: Yoann Lopes --- src/gsttools/gsttools.pro | 2 ++ src/gsttools/qgstreamervideoinputdevicecontrol.cpp | 5 +++++ src/plugins/gstreamer/camerabin/camerabin.pro | 2 ++ .../gstreamer/camerabin/camerabinserviceplugin.cpp | 5 +++++ src/plugins/gstreamer/mediacapture/mediacapture.pro | 21 ++++++++++++--------- .../mediacapture/qgstreamercaptureservice.cpp | 9 ++++++++- .../mediacapture/qgstreamercaptureservice.h | 2 ++ .../mediacapture/qgstreamercaptureserviceplugin.cpp | 3 +++ src/plugins/plugins.pro | 4 +++- 9 files changed, 42 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/gsttools/gsttools.pro b/src/gsttools/gsttools.pro index 15edd04d2..7c809a777 100644 --- a/src/gsttools/gsttools.pro +++ b/src/gsttools/gsttools.pro @@ -100,6 +100,8 @@ config_gstreamer_appsrc { LIBS_PRIVATE += -lgstapp-0.10 } +config_linux_v4l: DEFINES += USE_V4L + HEADERS += $$PRIVATE_HEADERS DESTDIR = $$QT.multimedia.libs diff --git a/src/gsttools/qgstreamervideoinputdevicecontrol.cpp b/src/gsttools/qgstreamervideoinputdevicecontrol.cpp index e4e202caf..dc008712e 100644 --- a/src/gsttools/qgstreamervideoinputdevicecontrol.cpp +++ b/src/gsttools/qgstreamervideoinputdevicecontrol.cpp @@ -45,7 +45,10 @@ #include #include + +#if defined(USE_V4L) #include +#endif QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl(QObject *parent) :QVideoDeviceSelectorControl(parent), m_source(0), m_selectedDevice(0) @@ -118,6 +121,7 @@ void QGstreamerVideoInputDeviceControl::update() return; } +#if defined(USE_V4L) QDir devDir("/dev"); devDir.setFilter(QDir::System); @@ -158,4 +162,5 @@ void QGstreamerVideoInputDeviceControl::update() } qt_safe_close(fd); } +#endif } diff --git a/src/plugins/gstreamer/camerabin/camerabin.pro b/src/plugins/gstreamer/camerabin/camerabin.pro index 9efa0812a..9ed821cb9 100644 --- a/src/plugins/gstreamer/camerabin/camerabin.pro +++ b/src/plugins/gstreamer/camerabin/camerabin.pro @@ -81,6 +81,8 @@ config_gstreamer_photography { DEFINES += GST_USE_UNSTABLE_API #prevents warnings because of unstable photography API } +config_linux_v4l: DEFINES += USE_V4L + OTHER_FILES += \ camerabin.json diff --git a/src/plugins/gstreamer/camerabin/camerabinserviceplugin.cpp b/src/plugins/gstreamer/camerabin/camerabinserviceplugin.cpp index 3decd6070..5fb419aae 100644 --- a/src/plugins/gstreamer/camerabin/camerabinserviceplugin.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinserviceplugin.cpp @@ -51,7 +51,10 @@ #include #include + +#if defined(USE_V4L) #include +#endif QT_BEGIN_NAMESPACE @@ -132,6 +135,7 @@ void CameraBinServicePlugin::updateDevices() const m_cameraDevices.clear(); m_cameraDescriptions.clear(); +#if defined(USE_V4L) QDir devDir("/dev"); devDir.setFilter(QDir::System); @@ -173,6 +177,7 @@ void CameraBinServicePlugin::updateDevices() const if (!m_cameraDevices.isEmpty()) m_defaultCameraDevice = m_cameraDevices.first(); +#endif } QT_END_NAMESPACE diff --git a/src/plugins/gstreamer/mediacapture/mediacapture.pro b/src/plugins/gstreamer/mediacapture/mediacapture.pro index e8d039f8d..5baa0fd8f 100644 --- a/src/plugins/gstreamer/mediacapture/mediacapture.pro +++ b/src/plugins/gstreamer/mediacapture/mediacapture.pro @@ -15,7 +15,6 @@ HEADERS += $$PWD/qgstreamercaptureservice.h \ $$PWD/qgstreamerrecordercontrol.h \ $$PWD/qgstreamermediacontainercontrol.h \ $$PWD/qgstreamercameracontrol.h \ - $$PWD/qgstreamerv4l2input.h \ $$PWD/qgstreamercapturemetadatacontrol.h \ $$PWD/qgstreamerimagecapturecontrol.h \ $$PWD/qgstreamerimageencode.h \ @@ -28,7 +27,6 @@ SOURCES += $$PWD/qgstreamercaptureservice.cpp \ $$PWD/qgstreamerrecordercontrol.cpp \ $$PWD/qgstreamermediacontainercontrol.cpp \ $$PWD/qgstreamercameracontrol.cpp \ - $$PWD/qgstreamerv4l2input.cpp \ $$PWD/qgstreamercapturemetadatacontrol.cpp \ $$PWD/qgstreamerimagecapturecontrol.cpp \ $$PWD/qgstreamerimageencode.cpp \ @@ -37,13 +35,18 @@ SOURCES += $$PWD/qgstreamercaptureservice.cpp \ # Camera usage with gstreamer needs to have #CONFIG += use_gstreamer_camera -use_gstreamer_camera { -DEFINES += USE_GSTREAMER_CAMERA +use_gstreamer_camera:config_linux_v4l { + DEFINES += USE_GSTREAMER_CAMERA + + OTHER_FILES += \ + mediacapturecamera.json + + HEADERS += \ + $$PWD/qgstreamerv4l2input.h + SOURCES += \ + $$PWD/qgstreamerv4l2input.cpp -OTHER_FILES += \ - mediacapturecamera.json } else { -OTHER_FILES += \ - mediacapture.json + OTHER_FILES += \ + mediacapture.json } - diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp index 92b362fb8..2278f926f 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp +++ b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.cpp @@ -48,9 +48,12 @@ #include "qgstreamerimageencode.h" #include "qgstreamercameracontrol.h" #include -#include "qgstreamerv4l2input.h" #include "qgstreamercapturemetadatacontrol.h" +#if defined(USE_GSTREAMER_CAMERA) +#include "qgstreamerv4l2input.h" +#endif + #include "qgstreamerimagecapturecontrol.h" #include #include @@ -74,7 +77,9 @@ QGstreamerCaptureService::QGstreamerCaptureService(const QString &service, QObje m_cameraControl = 0; m_metaDataControl = 0; +#if defined(USE_GSTREAMER_CAMERA) m_videoInput = 0; +#endif m_audioInputSelector = 0; m_videoInputDevice = 0; @@ -90,6 +95,7 @@ QGstreamerCaptureService::QGstreamerCaptureService(const QString &service, QObje m_captureSession = new QGstreamerCaptureSession(QGstreamerCaptureSession::Audio, this); } +#if defined(USE_GSTREAMER_CAMERA) if (service == Q_MEDIASERVICE_CAMERA) { m_captureSession = new QGstreamerCaptureSession(QGstreamerCaptureSession::AudioAndVideo, this); m_cameraControl = new QGstreamerCameraControl(m_captureSession); @@ -111,6 +117,7 @@ QGstreamerCaptureService::QGstreamerCaptureService(const QString &service, QObje #endif m_imageCaptureControl = new QGstreamerImageCaptureControl(m_captureSession); } +#endif m_audioInputSelector = new QGstreamerAudioInputSelector(this); connect(m_audioInputSelector, SIGNAL(activeInputChanged(QString)), m_captureSession, SLOT(setCaptureDevice(QString))); diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h index fc29b4f34..563c48c28 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h +++ b/src/plugins/gstreamer/mediacapture/qgstreamercaptureservice.h @@ -78,7 +78,9 @@ private: QGstreamerCaptureSession *m_captureSession; QGstreamerCameraControl *m_cameraControl; +#if defined(USE_GSTREAMER_CAMERA) QGstreamerV4L2Input *m_videoInput; +#endif QGstreamerCaptureMetaDataControl *m_metaDataControl; QAudioInputSelectorControl *m_audioInputSelector; diff --git a/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp b/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp index 8b88fbb71..77a6c3650 100644 --- a/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp +++ b/src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp @@ -52,7 +52,10 @@ #include #include + +#if defined(USE_GSTREAMER_CAMERA) #include +#endif QMediaService* QGstreamerCaptureServicePlugin::create(const QString &key) { diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 2677e269b..6a23fd2a3 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -43,7 +43,9 @@ unix:!mac:!android { } # v4l is turned off because it is not supported in Qt 5 - # !maemo*:SUBDIRS += v4l + # config_linux_v4l { + # !maemo*:SUBDIRS += v4l + # } } mac:!simulator { -- cgit v1.2.3 From c93c1d1dc30884b2c13bffdbc701efb5401b58b7 Mon Sep 17 00:00:00 2001 From: Dyami Caliri Date: Tue, 22 Jul 2014 11:19:14 -0700 Subject: CoreAudioOutput use timeout when waiting for render thread On Snow Leopard (at least), changing the default audio device while audio is playing can cause CoreAudioOutput to freeze in audioThreadStop(). It seems that the OS stops calling renderCallback when the device changes, so audioThreadStop() waits forever. Change-Id: If7244cc50f12295ff91a979ef50e3bee1273affd Reviewed-by: Andy Nichols --- src/plugins/coreaudio/coreaudiooutput.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/plugins/coreaudio/coreaudiooutput.mm b/src/plugins/coreaudio/coreaudiooutput.mm index e5e1c65e5..812d9dfe2 100644 --- a/src/plugins/coreaudio/coreaudiooutput.mm +++ b/src/plugins/coreaudio/coreaudiooutput.mm @@ -698,14 +698,14 @@ void CoreAudioOutput::audioThreadStop() { stopTimers(); if (m_audioThreadState.testAndSetAcquire(Running, Stopped)) - m_threadFinished.wait(&m_mutex); + m_threadFinished.wait(&m_mutex, 500); } void CoreAudioOutput::audioThreadDrain() { stopTimers(); if (m_audioThreadState.testAndSetAcquire(Running, Draining)) - m_threadFinished.wait(&m_mutex); + m_threadFinished.wait(&m_mutex, 500); } void CoreAudioOutput::audioDeviceStop() -- cgit v1.2.3 From 5195520a5a87ef8b5afdb980a808a5a95dad4e67 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Tue, 12 Aug 2014 15:07:23 +0200 Subject: Fix QSGVideoNode rendering of rgb frames with padding. Change-Id: I6870cfa51b01b648494e2068be06e52b67403739 Reviewed-by: Andrew den Exter Reviewed-by: Yoann Lopes --- src/qtmultimediaquicktools/qsgvideonode_rgb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp index ad01a08ae..1316be928 100644 --- a/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp +++ b/src/qtmultimediaquicktools/qsgvideonode_rgb.cpp @@ -220,7 +220,7 @@ public: stride /= 4; } - m_width = qreal(m_frame.width() / stride); + m_width = qreal(m_frame.width()) / stride; textureSize.setWidth(stride); if (m_textureSize != textureSize) { -- cgit v1.2.3 From fb35f025e320ef1639adf9a5d7bee73faa44e442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Str=C3=B8mme?= Date: Tue, 12 Aug 2014 16:46:50 +0200 Subject: OpenSL: Fix QAudioOutput::setNotifyInterval(). It was not possible to change the notify interval after calling start(). Task-number: QTBUG-40208 Change-Id: I82a626003e3bdfe7b7fc88b2f97da492c788877e Reviewed-by: Yoann Lopes --- src/plugins/opensles/qopenslesaudiooutput.cpp | 36 +++++++++++++++++++++++---- src/plugins/opensles/qopenslesaudiooutput.h | 1 + 2 files changed, 32 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/plugins/opensles/qopenslesaudiooutput.cpp b/src/plugins/opensles/qopenslesaudiooutput.cpp index 49bea0b36..9c62852de 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.cpp +++ b/src/plugins/opensles/qopenslesaudiooutput.cpp @@ -78,7 +78,8 @@ QOpenSLESAudioOutput::QOpenSLESAudioOutput(const QByteArray &device) m_periodSize(0), m_elapsedTime(0), m_processedBytes(0), - m_availableBuffers(BUFFER_COUNT) + m_availableBuffers(BUFFER_COUNT), + m_eventMask(SL_PLAYEVENT_HEADATEND) { #ifndef ANDROID m_streamType = -1; @@ -198,7 +199,33 @@ int QOpenSLESAudioOutput::bufferSize() const void QOpenSLESAudioOutput::setNotifyInterval(int ms) { - m_notifyInterval = ms > 0 ? ms : 0; + const int newInterval = ms > 0 ? ms : 0; + + if (newInterval == m_notifyInterval) + return; + + const SLuint32 newEvenMask = newInterval == 0 ? m_eventMask & ~SL_PLAYEVENT_HEADATNEWPOS + : m_eventMask & SL_PLAYEVENT_HEADATNEWPOS; + + if (m_state == QAudio::StoppedState) { + m_eventMask = newEvenMask; + m_notifyInterval = newInterval; + return; + } + + if (newEvenMask != m_eventMask + && SL_RESULT_SUCCESS != (*m_playItf)->SetCallbackEventsMask(m_playItf, newEvenMask)) { + return; + } + + m_eventMask = newEvenMask; + + if (newInterval && SL_RESULT_SUCCESS != (*m_playItf)->SetPositionUpdatePeriod(m_playItf, + newInterval)) { + return; + } + + m_notifyInterval = newInterval; } int QOpenSLESAudioOutput::notifyInterval() const @@ -488,13 +515,12 @@ bool QOpenSLESAudioOutput::preparePlayer() return false; } - SLuint32 mask = SL_PLAYEVENT_HEADATEND; if (m_notifyInterval && SL_RESULT_SUCCESS == (*m_playItf)->SetPositionUpdatePeriod(m_playItf, m_notifyInterval)) { - mask |= SL_PLAYEVENT_HEADATNEWPOS; + m_eventMask |= SL_PLAYEVENT_HEADATNEWPOS; } - if (SL_RESULT_SUCCESS != (*m_playItf)->SetCallbackEventsMask(m_playItf, mask)) { + if (SL_RESULT_SUCCESS != (*m_playItf)->SetCallbackEventsMask(m_playItf, m_eventMask)) { setError(QAudio::FatalError); return false; } diff --git a/src/plugins/opensles/qopenslesaudiooutput.h b/src/plugins/opensles/qopenslesaudiooutput.h index b0f01fa22..16cbc50d0 100644 --- a/src/plugins/opensles/qopenslesaudiooutput.h +++ b/src/plugins/opensles/qopenslesaudiooutput.h @@ -120,6 +120,7 @@ private: qint64 m_elapsedTime; qint64 m_processedBytes; QAtomicInt m_availableBuffers; + SLuint32 m_eventMask; qint32 m_streamType; QTime m_clockStamp; -- cgit v1.2.3 From 341b86c63fbe9e9f284e2d6547cb639f487a2ec4 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 17 Jul 2014 18:41:44 +0200 Subject: Android: fix retrieving metadata from assets, qrc and remote files. We need the same logic as for the media player: local files and assets must be loaded with a FileDescriptor. Because of a bug in Android API level >= 14, remote files have to be loaded in different ways depending on the version. Task-number: QTBUG-40274 Change-Id: I6411b959064d22219cf981a4dc8f4f26cf16f65f Reviewed-by: Christian Stromme --- .../src/mediaplayer/qandroidmediaplayercontrol.cpp | 4 +- .../src/mediaplayer/qandroidmediaplayercontrol.h | 1 + .../src/mediaplayer/qandroidmediaservice.cpp | 4 +- .../mediaplayer/qandroidmetadatareadercontrol.cpp | 10 +- .../mediaplayer/qandroidmetadatareadercontrol.h | 4 +- .../wrappers/jni/androidmediametadataretriever.cpp | 133 +++++++++++++++------ .../wrappers/jni/androidmediametadataretriever.h | 4 +- 7 files changed, 113 insertions(+), 47 deletions(-) (limited to 'src') diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp index 6817d65b0..90efcc503 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp +++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp @@ -325,8 +325,10 @@ void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent, mMediaPlayer->setDataSource(mediaPath); mMediaPlayer->prepareAsync(); - if (!reloading) + if (!reloading) { Q_EMIT mediaChanged(mMediaContent); + Q_EMIT actualMediaLocationChanged(mediaPath); + } resetBufferingProgress(); } diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h index 5744c11b8..1f61809cd 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h +++ b/src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h @@ -80,6 +80,7 @@ public: Q_SIGNALS: void metaDataUpdated(); + void actualMediaLocationChanged(const QString &url); public Q_SLOTS: void setPosition(qint64 position) Q_DECL_OVERRIDE; diff --git a/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp b/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp index 175958676..c6a7d3c39 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp +++ b/src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp @@ -53,8 +53,8 @@ QAndroidMediaService::QAndroidMediaService(QObject *parent) { mMediaControl = new QAndroidMediaPlayerControl; mMetadataControl = new QAndroidMetaDataReaderControl; - connect(mMediaControl, SIGNAL(mediaChanged(QMediaContent)), - mMetadataControl, SLOT(onMediaChanged(QMediaContent))); + connect(mMediaControl, SIGNAL(actualMediaLocationChanged(QString)), + mMetadataControl, SLOT(onMediaChanged(QString))); connect(mMediaControl, SIGNAL(metaDataUpdated()), mMetadataControl, SLOT(onUpdateMetaData())); } diff --git a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp index 82bd74997..7f68bc13c 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp +++ b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp @@ -101,18 +101,18 @@ QStringList QAndroidMetaDataReaderControl::availableMetaData() const return m_metadata.keys(); } -void QAndroidMetaDataReaderControl::onMediaChanged(const QMediaContent &media) +void QAndroidMetaDataReaderControl::onMediaChanged(const QString &url) { if (!m_retriever) return; - m_mediaContent = media; + m_mediaLocation = url; updateData(); } void QAndroidMetaDataReaderControl::onUpdateMetaData() { - if (!m_retriever || m_mediaContent.isNull()) + if (!m_retriever || m_mediaLocation.isEmpty()) return; updateData(); @@ -122,8 +122,8 @@ void QAndroidMetaDataReaderControl::updateData() { m_metadata.clear(); - if (!m_mediaContent.isNull()) { - if (m_retriever->setDataSource(m_mediaContent.canonicalUrl())) { + if (!m_mediaLocation.isEmpty()) { + if (m_retriever->setDataSource(m_mediaLocation)) { QString mimeType = m_retriever->extractMetadata(AndroidMediaMetadataRetriever::MimeType); if (!mimeType.isNull()) m_metadata.insert(QMediaMetaData::MediaType, mimeType); diff --git a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h index 67b92f1eb..a8f1d92f2 100644 --- a/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h +++ b/src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h @@ -62,13 +62,13 @@ public: QStringList availableMetaData() const Q_DECL_OVERRIDE; public Q_SLOTS: - void onMediaChanged(const QMediaContent &media); + void onMediaChanged(const QString &url); void onUpdateMetaData(); private: void updateData(); - QMediaContent m_mediaContent; + QString m_mediaLocation; bool m_available; QVariantMap m_metadata; diff --git a/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.cpp b/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.cpp index 7dfc6a6e3..83f12cb8c 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.cpp +++ b/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.cpp @@ -43,9 +43,24 @@ #include #include +#include +#include QT_BEGIN_NAMESPACE +static bool exceptionCheckAndClear(JNIEnv *env) +{ + if (Q_UNLIKELY(env->ExceptionCheck())) { +#ifdef QT_DEBUG + env->ExceptionDescribe(); +#endif // QT_DEBUG + env->ExceptionClear(); + return true; + } + + return false; +} + AndroidMediaMetadataRetriever::AndroidMediaMetadataRetriever() { m_metadataRetriever = QJNIObjectPrivate("android/media/MediaMetadataRetriever"); @@ -76,55 +91,105 @@ void AndroidMediaMetadataRetriever::release() m_metadataRetriever.callMethod("release"); } -bool AndroidMediaMetadataRetriever::setDataSource(const QUrl &url) +bool AndroidMediaMetadataRetriever::setDataSource(const QString &urlString) { if (!m_metadataRetriever.isValid()) return false; QJNIEnvironmentPrivate env; + QUrl url(urlString); - bool loaded = false; + if (url.isLocalFile()) { // also includes qrc files (copied to a temp file) + QJNIObjectPrivate string = QJNIObjectPrivate::fromString(url.path()); + QJNIObjectPrivate fileInputStream("java/io/FileInputStream", + "(Ljava/lang/String;)V", + string.object()); - QJNIObjectPrivate string = QJNIObjectPrivate::fromString(url.toString()); + if (exceptionCheckAndClear(env)) + return false; + + QJNIObjectPrivate fd = fileInputStream.callObjectMethod("getFD", + "()Ljava/io/FileDescriptor;"); + if (exceptionCheckAndClear(env)) { + fileInputStream.callMethod("close"); + exceptionCheckAndClear(env); + return false; + } - QJNIObjectPrivate uri = m_metadataRetriever.callStaticObjectMethod("android/net/Uri", - "parse", - "(Ljava/lang/String;)Landroid/net/Uri;", - string.object()); - if (env->ExceptionCheck()) { - env->ExceptionClear(); - } else { m_metadataRetriever.callMethod("setDataSource", - "(Landroid/content/Context;Landroid/net/Uri;)V", - QtAndroidPrivate::activity(), - uri.object()); - if (env->ExceptionCheck()) - env->ExceptionClear(); - else - loaded = true; - } + "(Ljava/io/FileDescriptor;)V", + fd.object()); + + bool ok = !exceptionCheckAndClear(env); + + fileInputStream.callMethod("close"); + exceptionCheckAndClear(env); + + if (!ok) + return false; + } else if (url.scheme() == QLatin1String("assets")) { + QJNIObjectPrivate string = QJNIObjectPrivate::fromString(url.path().mid(1)); // remove first '/' + QJNIObjectPrivate activity(QtAndroidPrivate::activity()); + QJNIObjectPrivate assetManager = activity.callObjectMethod("getAssets", + "()Landroid/content/res/AssetManager;"); + QJNIObjectPrivate assetFd = assetManager.callObjectMethod("openFd", + "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;", + string.object()); + if (exceptionCheckAndClear(env)) + return false; + + QJNIObjectPrivate fd = assetFd.callObjectMethod("getFileDescriptor", + "()Ljava/io/FileDescriptor;"); + if (exceptionCheckAndClear(env)) { + assetFd.callMethod("close"); + exceptionCheckAndClear(env); + return false; + } - return loaded; -} + m_metadataRetriever.callMethod("setDataSource", + "(Ljava/io/FileDescriptor;JJ)V", + fd.object(), + assetFd.callMethod("getStartOffset"), + assetFd.callMethod("getLength")); -bool AndroidMediaMetadataRetriever::setDataSource(const QString &path) -{ - if (!m_metadataRetriever.isValid()) - return false; + bool ok = !exceptionCheckAndClear(env); - QJNIEnvironmentPrivate env; + assetFd.callMethod("close"); + exceptionCheckAndClear(env); - bool loaded = false; + if (!ok) + return false; + } else if (QtAndroidPrivate::androidSdkVersion() >= 14) { + // On API levels >= 14, only setDataSource(String, Map) accepts remote media + QJNIObjectPrivate string = QJNIObjectPrivate::fromString(urlString); + QJNIObjectPrivate hash("java/util/HashMap"); - m_metadataRetriever.callMethod("setDataSource", - "(Ljava/lang/String;)V", - QJNIObjectPrivate::fromString(path).object()); - if (env->ExceptionCheck()) - env->ExceptionClear(); - else - loaded = true; + m_metadataRetriever.callMethod("setDataSource", + "(Ljava/lang/String;Ljava/util/Map;)V", + string.object(), + hash.object()); + if (exceptionCheckAndClear(env)) + return false; + } else { + // While on API levels < 14, only setDataSource(Context, Uri) is available and works for + // remote media... + QJNIObjectPrivate string = QJNIObjectPrivate::fromString(urlString); + QJNIObjectPrivate uri = m_metadataRetriever.callStaticObjectMethod("android/net/Uri", + "parse", + "(Ljava/lang/String;)Landroid/net/Uri;", + string.object()); + if (exceptionCheckAndClear(env)) + return false; + + m_metadataRetriever.callMethod("setDataSource", + "(Landroid/content/Context;Landroid/net/Uri;)V", + QtAndroidPrivate::activity(), + uri.object()); + if (exceptionCheckAndClear(env)) + return false; + } - return loaded; + return true; } QT_END_NAMESPACE diff --git a/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.h b/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.h index f18cec11d..1a4a876ee 100644 --- a/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.h +++ b/src/plugins/android/src/wrappers/jni/androidmediametadataretriever.h @@ -43,7 +43,6 @@ #define ANDROIDMEDIAMETADATARETRIEVER_H #include -#include QT_BEGIN_NAMESPACE @@ -81,8 +80,7 @@ public: QString extractMetadata(MetadataKey key); void release(); - bool setDataSource(const QUrl &url); - bool setDataSource(const QString &path); + bool setDataSource(const QString &url); private: QJNIObjectPrivate m_metadataRetriever; -- cgit v1.2.3 From bee6244e2428c4a2f4b62dd1e8896f310b2208c8 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 8 May 2014 15:22:11 +0200 Subject: AVFoundation: fix retrieving tracks information from live sources. For live sources, tracks information is available only after the AVPlayer changed its status to AVPlayerStatusReadyToPlay. It also seems to be available only from AVPlayerItem.tracks rather than AVAsset.tracks. The audioAvailableChanged() and videoAvailableChanged() signals are now correclty emitted and the video layer is correctly positioned for live sources. Task-number: QTBUG-38666 Change-Id: I8ee015a6ce81694c1fc1e44c679887cf7ccb0fd6 Reviewed-by: Andy Nichols --- .../mediaplayer/avfmediaplayersession.h | 3 + .../mediaplayer/avfmediaplayersession.mm | 103 +++++++++++---------- 2 files changed, 55 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h index 58a2d84c9..18e923aec 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.h @@ -156,6 +156,9 @@ private: QByteArray rawData; }; + void setAudioAvailable(bool available); + void setVideoAvailable(bool available); + AVFMediaPlayerService *m_service; AVFVideoOutput *m_videoOutput; diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm index a73974ccd..106e81a37 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayersession.mm @@ -70,15 +70,11 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe AVPlayerItem *m_playerItem; AVPlayerLayer *m_playerLayer; NSURL *m_URL; - bool m_audioAvailable; - bool m_videoAvailable; } @property (readonly, getter=player) AVPlayer* m_player; @property (readonly, getter=playerItem) AVPlayerItem* m_playerItem; @property (readonly, getter=playerLayer) AVPlayerLayer* m_playerLayer; -@property (readonly, getter=audioAvailable) bool m_audioAvailable; -@property (readonly, getter=videoAvailable) bool m_videoAvailable; @property (readonly, getter=session) AVFMediaPlayerSession* m_session; - (AVFMediaPlayerSessionObserver *) initWithMediaPlayerSession:(AVFMediaPlayerSession *)session; @@ -96,7 +92,7 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe @implementation AVFMediaPlayerSessionObserver -@synthesize m_player, m_playerItem, m_playerLayer, m_audioAvailable, m_videoAvailable, m_session; +@synthesize m_player, m_playerItem, m_playerLayer, m_session; - (AVFMediaPlayerSessionObserver *) initWithMediaPlayerSession:(AVFMediaPlayerSession *)session { @@ -186,18 +182,6 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe return; } - m_audioAvailable = false; - m_videoAvailable = false; - - //Check each track of asset for audio and video content - NSArray *tracks = [asset tracks]; - for (AVAssetTrack *track in tracks) { - if ([track hasMediaCharacteristic:AVMediaCharacteristicAudible]) - m_audioAvailable = true; - if ([track hasMediaCharacteristic:AVMediaCharacteristicVisual]) - m_videoAvailable = true; - } - //At this point we're ready to set up for playback of the asset. //Stop observing our prior AVPlayerItem, if we have one. if (m_playerItem) @@ -258,18 +242,7 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe m_playerLayer = [AVPlayerLayer playerLayerWithPlayer:m_player]; [m_playerLayer retain]; m_playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; - - //Get the native size of the new item, and reset the bounds of the player layer - AVAsset *asset = m_playerItem.asset; - if (asset) { - NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; - if ([tracks count]) { - AVAssetTrack *videoTrack = [tracks objectAtIndex:0]; - m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f); - m_playerLayer.bounds = CGRectMake(0.0f, 0.0f, videoTrack.naturalSize.width, videoTrack.naturalSize.height); - } - } - + m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f); } //Observe the AVPlayer "currentItem" property to find out when any @@ -366,22 +339,8 @@ static void *AVFMediaPlayerSessionObserverCurrentItemObservationContext = &AVFMe { AVPlayerItem *newPlayerItem = [change objectForKey:NSKeyValueChangeNewKey]; if (m_playerItem != newPlayerItem) - { m_playerItem = newPlayerItem; - //Get the native size of the new item, and reset the bounds of the player layer - //AVAsset *asset = m_playerItem.asset; - AVAsset *asset = [m_playerItem asset]; - if (asset) { - NSArray *tracks = [asset tracksWithMediaType:AVMediaTypeVideo]; - if ([tracks count]) { - AVAssetTrack *videoTrack = [tracks objectAtIndex:0]; - m_playerLayer.anchorPoint = CGPointMake(0.0f, 0.0f); - m_playerLayer.bounds = CGRectMake(0.0f, 0.0f, videoTrack.naturalSize.width, videoTrack.naturalSize.height); - } - } - - } if (self.session) QMetaObject::invokeMethod(m_session, "processCurrentItemChanged", Qt::AutoConnection); } @@ -513,6 +472,9 @@ void AVFMediaPlayerSession::setMedia(const QMediaContent &content, QIODevice *st m_resources = content; m_mediaStream = stream; + setAudioAvailable(false); + setVideoAvailable(false); + QMediaPlayer::MediaStatus oldMediaStatus = m_mediaStatus; if (content.isNull() || content.canonicalUrl().isEmpty()) { @@ -582,14 +544,32 @@ bool AVFMediaPlayerSession::isMuted() const return m_muted; } +void AVFMediaPlayerSession::setAudioAvailable(bool available) +{ + if (m_audioAvailable == available) + return; + + m_audioAvailable = available; + Q_EMIT audioAvailableChanged(available); +} + bool AVFMediaPlayerSession::isAudioAvailable() const { - return [(AVFMediaPlayerSessionObserver*)m_observer audioAvailable]; + return m_audioAvailable; +} + +void AVFMediaPlayerSession::setVideoAvailable(bool available) +{ + if (m_videoAvailable == available) + return; + + m_videoAvailable = available; + Q_EMIT videoAvailableChanged(available); } bool AVFMediaPlayerSession::isVideoAvailable() const { - return [(AVFMediaPlayerSessionObserver*)m_observer videoAvailable]; + return m_videoAvailable; } bool AVFMediaPlayerSession::isSeekable() const @@ -802,16 +782,37 @@ void AVFMediaPlayerSession::processLoadStateChange() bool isPlaying = (m_state != QMediaPlayer::StoppedState); if (currentStatus == AVPlayerStatusReadyToPlay) { + AVPlayerItem *playerItem = [(AVFMediaPlayerSessionObserver*)m_observer playerItem]; + if (playerItem) { + // Check each track for audio and video content + AVAssetTrack *videoTrack = nil; + NSArray *tracks = playerItem.tracks; + for (AVPlayerItemTrack *track in tracks) { + AVAssetTrack *assetTrack = track.assetTrack; + if (assetTrack) { + if ([assetTrack.mediaType isEqualToString:AVMediaTypeAudio]) + setAudioAvailable(true); + if ([assetTrack.mediaType isEqualToString:AVMediaTypeVideo]) { + setVideoAvailable(true); + if (!videoTrack) + videoTrack = assetTrack; + } + } + } + + // Get the native size of the video, and reset the bounds of the player layer + AVPlayerLayer *playerLayer = [(AVFMediaPlayerSessionObserver*)m_observer playerLayer]; + if (videoTrack && playerLayer) { + playerLayer.bounds = CGRectMake(0.0f, 0.0f, + videoTrack.naturalSize.width, + videoTrack.naturalSize.height); + } + } + qint64 currentDuration = duration(); if (m_duration != currentDuration) Q_EMIT durationChanged(m_duration = currentDuration); - if (m_audioAvailable != isAudioAvailable()) - Q_EMIT audioAvailableChanged(m_audioAvailable = !m_audioAvailable); - - if (m_videoAvailable != isVideoAvailable()) - Q_EMIT videoAvailableChanged(m_videoAvailable = !m_videoAvailable); - newStatus = isPlaying ? QMediaPlayer::BufferedMedia : QMediaPlayer::LoadedMedia; if (m_state == QMediaPlayer::PlayingState && [(AVFMediaPlayerSessionObserver*)m_observer player]) { -- cgit v1.2.3 From 5f0f81bcc1b82ea3418e4e5ce939ce22b11af0af Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Thu, 5 Jun 2014 15:25:55 +0200 Subject: AVFoundation: fix some controls not being correctly destroyed on iOS. This patch also makes sure AVF video layers are removed from their parent layer when their corresponding Qt video outputs are destroyed. Task-number: QTBUG-39385 Change-Id: I164cd0da7084f84c0473ed3e396e734acce2a22e Reviewed-by: Andy Nichols --- src/plugins/avfoundation/camera/avfcameraservice.mm | 4 ++-- src/plugins/avfoundation/mediaplayer/avfmediaplayerservice.mm | 5 +++-- src/plugins/avfoundation/mediaplayer/avfvideowidget.mm | 4 +++- src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm | 4 +++- 4 files changed, 11 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm index 25111c5cc..966202ede 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.mm +++ b/src/plugins/avfoundation/camera/avfcameraservice.mm @@ -135,9 +135,9 @@ QMediaControl *AVFCameraService::requestControl(const char *name) void AVFCameraService::releaseControl(QMediaControl *control) { if (m_videoOutput == control) { - m_videoOutput = 0; m_session->setVideoOutput(0); - delete control; + delete m_videoOutput; + m_videoOutput = 0; } } diff --git a/src/plugins/avfoundation/mediaplayer/avfmediaplayerservice.mm b/src/plugins/avfoundation/mediaplayer/avfmediaplayerservice.mm index e5549803f..bb75adb8b 100644 --- a/src/plugins/avfoundation/mediaplayer/avfmediaplayerservice.mm +++ b/src/plugins/avfoundation/mediaplayer/avfmediaplayerservice.mm @@ -118,14 +118,15 @@ void AVFMediaPlayerService::releaseControl(QMediaControl *control) #ifdef QT_DEBUG_AVF qDebug() << Q_FUNC_INFO << control; #endif -#if defined(Q_OS_OSX) if (m_videoOutput == control) { +#if defined(Q_OS_OSX) AVFVideoRendererControl *renderControl = qobject_cast(m_videoOutput); if (renderControl) renderControl->setSurface(0); +#endif m_videoOutput = 0; m_session->setVideoOutput(0); + delete control; } -#endif } diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm index d4fa7c4c6..2893921f3 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideowidget.mm @@ -64,8 +64,10 @@ AVFVideoWidget::~AVFVideoWidget() qDebug() << Q_FUNC_INFO; #endif - if (m_playerLayer) + if (m_playerLayer) { + [m_playerLayer removeFromSuperlayer]; [m_playerLayer release]; + } } QSize AVFVideoWidget::sizeHint() const diff --git a/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm b/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm index 17fc94de7..8e96d732f 100644 --- a/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm +++ b/src/plugins/avfoundation/mediaplayer/avfvideowindowcontrol.mm @@ -61,8 +61,10 @@ AVFVideoWindowControl::AVFVideoWindowControl(QObject *parent) AVFVideoWindowControl::~AVFVideoWindowControl() { - if (m_playerLayer) + if (m_playerLayer) { + [m_playerLayer removeFromSuperlayer]; [m_playerLayer release]; + } } WId AVFVideoWindowControl::winId() const -- cgit v1.2.3 From 20da381608c61930e2eea46fe0175a355eac9a73 Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Mon, 14 Jul 2014 16:44:49 +0200 Subject: WMF: fix bufferStatus() and availablePlaybackRanges(). - Correctly initialize and clear PROPVARIANT structures - Return coherent data even when the information is not available Change-Id: I22b46f95f255cbb740a154c6296a5c3a91e64f67 Reviewed-by: Christian Stromme --- src/plugins/wmf/player/mfplayersession.cpp | 41 +++++++++++++++++++----------- 1 file changed, 26 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/plugins/wmf/player/mfplayersession.cpp b/src/plugins/wmf/player/mfplayersession.cpp index f61f7aba2..09c5a8c52 100644 --- a/src/plugins/wmf/player/mfplayersession.cpp +++ b/src/plugins/wmf/player/mfplayersession.cpp @@ -1403,14 +1403,17 @@ int MFPlayerSession::bufferStatus() if (!m_netsourceStatistics) return 0; PROPVARIANT var; + PropVariantInit(&var); PROPERTYKEY key; key.fmtid = MFNETSOURCE_STATISTICS; key.pid = MFNETSOURCE_BUFFERPROGRESS_ID; int progress = -1; - if (SUCCEEDED(m_netsourceStatistics->GetValue(key, &var))) { + // GetValue returns S_FALSE if the property is not available, which has + // a value > 0. We therefore can't use the SUCCEEDED macro here. + if (m_netsourceStatistics->GetValue(key, &var) == S_OK) { progress = var.lVal; + PropVariantClear(&var); } - PropVariantClear(&var); #ifdef DEBUG_MEDIAFOUNDATION qDebug() << "bufferStatus: progress = " << progress; @@ -1421,22 +1424,30 @@ int MFPlayerSession::bufferStatus() QMediaTimeRange MFPlayerSession::availablePlaybackRanges() { - if (!m_netsourceStatistics) - return QMediaTimeRange(); + // defaults to the whole media + qint64 start = 0; + qint64 end = qint64(m_duration / 10000); - qint64 start = 0, end = 0; - PROPVARIANT var; - PROPERTYKEY key; - key.fmtid = MFNETSOURCE_STATISTICS; - key.pid = MFNETSOURCE_SEEKRANGESTART_ID; - if (SUCCEEDED(m_netsourceStatistics->GetValue(key, &var))) { - start = qint64(var.uhVal.QuadPart / 10000); - key.pid = MFNETSOURCE_SEEKRANGEEND_ID; - if (SUCCEEDED(m_netsourceStatistics->GetValue(key, &var))) { - end = qint64(var.uhVal.QuadPart / 10000); + if (m_netsourceStatistics) { + PROPVARIANT var; + PropVariantInit(&var); + PROPERTYKEY key; + key.fmtid = MFNETSOURCE_STATISTICS; + key.pid = MFNETSOURCE_SEEKRANGESTART_ID; + // GetValue returns S_FALSE if the property is not available, which has + // a value > 0. We therefore can't use the SUCCEEDED macro here. + if (m_netsourceStatistics->GetValue(key, &var) == S_OK) { + start = qint64(var.uhVal.QuadPart / 10000); + PropVariantClear(&var); + PropVariantInit(&var); + key.pid = MFNETSOURCE_SEEKRANGEEND_ID; + if (m_netsourceStatistics->GetValue(key, &var) == S_OK) { + end = qint64(var.uhVal.QuadPart / 10000); + PropVariantClear(&var); + } } } - PropVariantClear(&var); + return QMediaTimeRange(start, end); } -- cgit v1.2.3 From b3c2dca466042cf362ffb8d803bf05c9b8a0f95f Mon Sep 17 00:00:00 2001 From: Bjoern Breitmeyer Date: Fri, 22 Aug 2014 14:59:11 +0200 Subject: Restore QWindowsAudio support on wince. Enabled Audio playback with wave device on WindowsCE again. Change-Id: Ic7749821ef8f991a909cbeb29083219ea988f5dc Reviewed-by: Yoann Lopes --- .../windowsaudio/qwindowsaudiodeviceinfo.cpp | 30 ++++++++++++++++++++++ src/plugins/windowsaudio/windowsaudio.pro | 3 ++- 2 files changed, 32 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp index d37056a5f..98c161ae5 100644 --- a/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp +++ b/src/plugins/windowsaudio/qwindowsaudiodeviceinfo.cpp @@ -412,6 +412,7 @@ QList QWindowsAudioDeviceInfo::availableDevices(QAudio::Mode mode) Q_UNUSED(mode) QList devices; +#ifndef Q_OS_WINCE //enumerate device fullnames through directshow api CoInitialize(NULL); ICreateDevEnum *pDevEnum = NULL; @@ -463,6 +464,35 @@ QList QWindowsAudioDeviceInfo::availableDevices(QAudio::Mode mode) } } CoUninitialize(); +#else // Q_OS_WINCE + if (mode == QAudio::AudioOutput) { + WAVEOUTCAPS woc; + unsigned long iNumDevs,i; + iNumDevs = waveOutGetNumDevs(); + for (i=0;i