summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@digia.com>2014-07-17 18:41:44 +0200
committerYoann Lopes <yoann.lopes@digia.com>2014-08-25 17:29:37 +0200
commit341b86c63fbe9e9f284e2d6547cb639f487a2ec4 (patch)
tree24eed023702ebbe11c625f3afc4975db622a9e7b /src
parentfb35f025e320ef1639adf9a5d7bee73faa44e442 (diff)
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 <christian.stromme@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.cpp4
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaplayercontrol.h1
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmediaservice.cpp4
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.cpp10
-rw-r--r--src/plugins/android/src/mediaplayer/qandroidmetadatareadercontrol.h4
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediametadataretriever.cpp133
-rw-r--r--src/plugins/android/src/wrappers/jni/androidmediametadataretriever.h4
7 files changed, 113 insertions, 47 deletions
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 <QtCore/private/qjnihelpers_p.h>
#include <QtCore/private/qjni_p.h>
+#include <QtCore/QUrl>
+#include <qdebug.h>
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<void>("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<void>("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<void>("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<void>("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<void>("close");
+ exceptionCheckAndClear(env);
+ return false;
+ }
- return loaded;
-}
+ m_metadataRetriever.callMethod<void>("setDataSource",
+ "(Ljava/io/FileDescriptor;JJ)V",
+ fd.object(),
+ assetFd.callMethod<jlong>("getStartOffset"),
+ assetFd.callMethod<jlong>("getLength"));
-bool AndroidMediaMetadataRetriever::setDataSource(const QString &path)
-{
- if (!m_metadataRetriever.isValid())
- return false;
+ bool ok = !exceptionCheckAndClear(env);
- QJNIEnvironmentPrivate env;
+ assetFd.callMethod<void>("close");
+ exceptionCheckAndClear(env);
- bool loaded = false;
+ if (!ok)
+ return false;
+ } else if (QtAndroidPrivate::androidSdkVersion() >= 14) {
+ // On API levels >= 14, only setDataSource(String, Map<String, String>) accepts remote media
+ QJNIObjectPrivate string = QJNIObjectPrivate::fromString(urlString);
+ QJNIObjectPrivate hash("java/util/HashMap");
- m_metadataRetriever.callMethod<void>("setDataSource",
- "(Ljava/lang/String;)V",
- QJNIObjectPrivate::fromString(path).object());
- if (env->ExceptionCheck())
- env->ExceptionClear();
- else
- loaded = true;
+ m_metadataRetriever.callMethod<void>("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<void>("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 <QtCore/private/qjni_p.h>
-#include <qurl.h>
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;