Skip to content

Commit

Permalink
android: use jmi for io to get rid of private module dependency
Browse files Browse the repository at this point in the history
also add new protocol "android.resource" supported by android, not tested
  • Loading branch information
wang-bin committed Jan 28, 2018
1 parent bbf3c64 commit b813048
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 21 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 7,6 @@
[submodule "contrib/uchardet"]
path = contrib/uchardet
url = https://github.com/BYVoid/uchardet.git
[submodule "src/jmi"]
path = src/jmi
url = https://github.com/wang-bin/JMI.git
58 changes: 39 additions & 19 deletions src/io/AndroidIO.cpp
Original file line number Diff line number Diff line change
@@ -1,6 1,6 @@
/******************************************************************************
QtAV: Multimedia framework based on Qt and FFmpeg
Copyright (C) 2012-2016 Wang Bin <[email protected]>
Copyright (C) 2012-2018 Wang Bin <[email protected]>
* This file is part of QtAV (from 2015)
Expand All @@ -24,10 24,10 @@
#include "QtAV/private/mkid.h"
#include "QtAV/private/factory.h"
#include <QtCore/QFile>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/QGuiApplication>
#include <QtAndroidExtras>
#include "utils/Logger.h"
#include "jmi/jmi.h"

// TODO: how to get filename and find subtitles?
//http://stackoverflow.com/questions/5657411/android-getting-a-file-uri-from-a-content-uri
Expand All @@ -46,7 46,7 @@ class AndroidIO : public MediaIO
QString name() const Q_DECL_OVERRIDE { return QLatin1String(kName);}
const QStringList& protocols() const Q_DECL_OVERRIDE
{
static QStringList p = QStringList() << QStringLiteral("content"); // "file:" is supported too but we use QFile
static QStringList p = QStringList() << QStringLiteral("content") << QStringLiteral("android.resource"); // "file:" is supported too but we use QFile
return p;
}
virtual bool isSeekable() const Q_DECL_OVERRIDE;
Expand All @@ -63,7 63,6 @@ class AndroidIO : public MediaIO
void onUrlChanged() Q_DECL_OVERRIDE;

private:
QAndroidJniObject app_ctx;
QFile qt_file;
// if use Java.io.InputStream, record pos
};
Expand All @@ -74,9 73,7 @@ FACTORY_REGISTER(MediaIO, Android, kName)
AndroidIO::AndroidIO()
: MediaIO()
{
QPlatformNativeInterface *interface = QGuiApplication::platformNativeInterface();
jobject activity = (jobject)interface->nativeResourceForIntegration("QtActivity");
app_ctx = QAndroidJniObject(activity).callObjectMethod("getApplicationContext","()Landroid/content/Context;");
jmi::javaVM(QAndroidJniEnvironment::javaVM()); // nativeResourceForIntegration("javaVM")
}

bool AndroidIO::isSeekable() const
Expand Down Expand Up @@ -106,22 103,45 @@ qint64 AndroidIO::position() const
void AndroidIO::onUrlChanged()
{
qt_file.close();
QAndroidJniObject content_resolver = app_ctx.callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;");
if (!content_resolver.isValid()) {
qWarning("getContentResolver error");
if (url().isEmpty())
return;
struct Application final: jmi::ClassTag { static std::string name() {return "android/app/Application";}};
jmi::JObject<Application> app_ctx(jmi::android::application());

struct ContentResolver final: jmi::ClassTag { static std::string name() { return "android/content/ContentResolver";}};
struct GetContentResolver final: jmi::MethodTag { static const char* name() {return "getContentResolver";}};
jmi::JObject<ContentResolver> cr = app_ctx.call<jmi::JObject<ContentResolver>, GetContentResolver>();
if (!cr.error().empty()) {
qWarning("getContentResolver error: %s", cr.error().data());
return;
}
struct Uri final: jmi::ClassTag { static std::string name() { return "android/net/Uri";}};
struct Parse final: jmi::MethodTag { static const char* name() {return "parse";}};
jmi::JObject<Uri> uri = jmi::JObject<Uri>::callStatic<jmi::JObject<Uri>, Parse>(url().toUtf8().constData()); // move?
// openInputStream?
struct ParcelFileDescriptor final: jmi::ClassTag { static std::string name() { return "android/os/ParcelFileDescriptor";}};
// AssetFileDescriptor supported schemes: content, android.resource, file
// ParcelFileDescriptor supported schemes: content, file
#if 1
struct AssetFileDescriptor final: jmi::ClassTag { static std::string name() { return "android/content/res/AssetFileDescriptor";}};
struct OpenAssetFileDescriptor final: jmi::MethodTag { static const char* name() {return "openAssetFileDescriptor";}};
jmi::JObject<AssetFileDescriptor> afd = cr.call<jmi::JObject<AssetFileDescriptor>, OpenAssetFileDescriptor>(std::move(uri), "r"); // TODO: rw
if (!afd.error().empty()) {
qWarning("openAssetFileDescriptor error: %s", afd.error().data());
return;
}
QAndroidJniObject s = QAndroidJniObject::fromString(url());
QAndroidJniObject uri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", s.object<jstring>());
//input_stream = content_resolver.callObjectMethod("openInputStream", "(Landroid.net.Uri;)Ljava.io.InputStream;", uri.object<jobject>()); // TODO: why error?
//qDebug() << "onUrlChanged InputStream: " << input_stream.toString();
s = QAndroidJniObject::fromString(QStringLiteral("r"));
QAndroidJniObject pfd = content_resolver.callObjectMethod("openFileDescriptor", "(Landroid/net/Uri;Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;", uri.object<jobject>(), s.object<jstring>());
if (!pfd.isValid()) {
qWarning("openFileDescriptor error");
struct GetParcelFileDescriptor final: jmi::MethodTag { static const char* name() {return "getParcelFileDescriptor";}};
jmi::JObject<ParcelFileDescriptor> pfd = afd.call<jmi::JObject<ParcelFileDescriptor>, GetParcelFileDescriptor>();
#else
struct OpenFileDescriptor final: jmi::MethodTag { static const char* name() {return "openFileDescriptor";}};
jmi::JObject<ParcelFileDescriptor> pfd = cr.call<jmi::JObject<ParcelFileDescriptor>, OpenFileDescriptor>(std::move(uri), "r");
#endif
if (!pfd.error().empty()) {
qWarning("get ParcelFileDescriptor error: %s", pfd.error().data());
return;
}
int fd = pfd.callMethod<int>("detachFd", "()I");
struct DetachFd final: jmi::MethodTag { static const char* name() {return "detachFd";}};
int fd = pfd.call<int,DetachFd>();
qt_file.open(fd, QIODevice::ReadOnly);
}
} //namespace QtAV
1 change: 1 addition & 0 deletions src/jmi
Submodule jmi added at 1fa075
5 changes: 3 additions & 2 deletions src/libQtAV.pro
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 118,9 @@ config_gl|config_opengl {
DEFINES = __STDC_CONSTANT_MACROS
android {
CONFIG *= config_opensl
!no_gui_private:qtHaveModule(androidextras) { #qt5.2 has QAndroidJniObject
QT *= androidextras gui-private #QPlatformNativeInterface get "QtActivity"
SOURCES *= jmi/jmi.cpp
qtHaveModule(androidextras) { #qt5.2 has QAndroidJniObject
QT *= androidextras #QPlatformNativeInterface get "QtActivity"
SOURCES *= io/AndroidIO.cpp
SOURCES *= codec/video/VideoDecoderMediaCodec.cpp
exists($$[QT_INSTALL_HEADERS]/MediaCodecTextureStandalone.h) {
Expand Down

0 comments on commit b813048

Please sign in to comment.