summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Strømme <christian.stromme@digia.com>2013-01-14 14:23:38 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-03-06 00:23:50 +0100
commit909a09069fbdec8d99cf91f505ca8c925a0e2ccd (patch)
tree0f9beee73e9c83f6f63117c7cbf279288d4ff0f1
parent68a38b151e5eb36568f6a2f51bdd95e312c20138 (diff)
Android multimedia plug-in.
Adds MediaPlayer support for Android. Change-Id: I4c7b1e19927b2e50b227f3a3b3f7ca2e99397618 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
-rw-r--r--src/multimedia/multimedia.pro5
-rw-r--r--src/plugins/android/android.pro5
-rw-r--r--src/plugins/android/jar/AndroidManifest.xml6
-rw-r--r--src/plugins/android/jar/jar.pro11
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java445
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java74
-rw-r--r--src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java114
-rw-r--r--src/plugins/android/mediaplayer/mediaplayer.json3
-rw-r--r--src/plugins/android/mediaplayer/mediaplayer.pro24
-rw-r--r--src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp496
-rw-r--r--src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h127
-rw-r--r--src/plugins/android/mediaplayer/qandroidmediaservice.cpp97
-rw-r--r--src/plugins/android/mediaplayer/qandroidmediaservice.h71
-rw-r--r--src/plugins/android/mediaplayer/qandroidmediaserviceplugin.cpp107
-rw-r--r--src/plugins/android/mediaplayer/qandroidmediaserviceplugin.h72
-rw-r--r--src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.cpp221
-rw-r--r--src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.h80
-rw-r--r--src/plugins/android/mediaplayer/qandroidvideooutput.h64
-rw-r--r--src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp375
-rw-r--r--src/plugins/android/mediaplayer/qandroidvideorendercontrol.h95
-rw-r--r--src/plugins/android/wrappers/jmediametadataretriever.cpp126
-rw-r--r--src/plugins/android/wrappers/jmediametadataretriever.h91
-rw-r--r--src/plugins/android/wrappers/jmediaplayer.cpp265
-rw-r--r--src/plugins/android/wrappers/jmediaplayer.h133
-rw-r--r--src/plugins/android/wrappers/jsurfacetexture.cpp118
-rw-r--r--src/plugins/android/wrappers/jsurfacetexture.h75
-rw-r--r--src/plugins/android/wrappers/jsurfacetextureholder.cpp65
-rw-r--r--src/plugins/android/wrappers/jsurfacetextureholder.h59
-rw-r--r--src/plugins/android/wrappers/wrappers.pri15
-rw-r--r--src/plugins/plugins.pro4
30 files changed, 3443 insertions, 0 deletions
diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro
index 9dbea399b..2a1c6afb5 100644
--- a/src/multimedia/multimedia.pro
+++ b/src/multimedia/multimedia.pro
@@ -51,6 +51,11 @@ include(radio/radio.pri)
include(recording/recording.pri)
include(video/video.pri)
+ANDROID_JAR_DEPENDENCIES = \
+ jar/QtMultimedia.jar:org.qtproject.qt5.android.multimedia.QtAndroidMediaPlayer
+ANDROID_LIB_DEPENDENCIES = \
+ plugins/mediaservice/libandroidmediaplayer.so
+
mac {
LIBS += -framework AppKit -framework QuartzCore -framework QTKit
}
diff --git a/src/plugins/android/android.pro b/src/plugins/android/android.pro
new file mode 100644
index 000000000..2cfc83f0e
--- /dev/null
+++ b/src/plugins/android/android.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+
+SUBDIRS += mediaplayer \
+ jar
+
diff --git a/src/plugins/android/jar/AndroidManifest.xml b/src/plugins/android/jar/AndroidManifest.xml
new file mode 100644
index 000000000..7eae1854d
--- /dev/null
+++ b/src/plugins/android/jar/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.qtproject.qt5.android.multimedia"
+ android:versionCode="1"
+ android:versionName="1.0" >
+ <supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
+</manifest>
diff --git a/src/plugins/android/jar/jar.pro b/src/plugins/android/jar/jar.pro
new file mode 100644
index 000000000..b256412fc
--- /dev/null
+++ b/src/plugins/android/jar/jar.pro
@@ -0,0 +1,11 @@
+load(qt_build_paths)
+CONFIG += java
+TARGET = QtMultimedia
+DESTDIR = $$MODULE_BASE_OUTDIR/jar
+API_VERSION = android-11
+
+JAVACLASSPATH += $$PWD/src
+
+JAVASOURCES += $$PWD/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java \
+ $$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java \
+ $$PWD/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java
new file mode 100644
index 000000000..b2115b7d9
--- /dev/null
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java
@@ -0,0 +1,445 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtMultimedia module 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 Digia. For licensing terms and
+ ** conditions see http://qt.digia.com/licensing. For further information
+ ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.LGPL included in the
+ ** packaging of this file. Please review the following information to
+ ** ensure the GNU Lesser General Public License version 2.1 requirements
+ ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ **
+ ** In addition, as a special exception, Digia gives you certain additional
+ ** rights. These rights are described in the Digia Qt LGPL Exception
+ ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+ **
+ ** GNU General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU
+ ** General Public License version 3.0 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.GPL included in the
+ ** packaging of this file. Please review the following information to
+ ** ensure the GNU General Public License version 3.0 requirements will be
+ ** met: http://www.gnu.org/copyleft/gpl.html.
+ **
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+package org.qtproject.qt5.android.multimedia;
+
+import java.io.IOException;
+import java.lang.String;
+
+// API is level is < 9 unless marked otherwise.
+import android.app.Activity;
+import android.content.Context;
+import android.media.MediaPlayer;
+import android.net.Uri;
+import android.util.Log;
+
+public class QtAndroidMediaPlayer extends MediaPlayer
+{
+ // Native callback functions for MediaPlayer
+ native public void onErrorNative(int what, int extra, long id);
+ native public void onBufferingUpdateNative(int percent, long id);
+ native public void onInfoNative(int what, int extra, long id);
+ native public void onMediaPlayerInfoNative(int what, int extra, long id);
+ native public void onVideoSizeChangedNative(int width, int height, long id);
+
+ private Uri mUri = null;
+ private final long mID;
+ private boolean mMuted = false;
+ private boolean mPreparing = false;
+ private boolean mInitialized = false;
+ private int mVolume = 100;
+ private static final String TAG = "Qt MediaPlayer";
+ private static Context mApplicationContext = null;
+
+ final int MEDIA_PLAYER_INVALID_STATE = 1;
+ final int MEDIA_PLAYER_PREPARING = 2;
+ final int MEDIA_PLAYER_READY = 3;
+ final int MEDIA_PLAYER_DURATION = 4;
+ final int MEDIA_PLAYER_PROGRESS = 5;
+ final int MEDIA_PLAYER_FINISHED = 6;
+
+ // Activity set by Qt on load.
+ static public void setActivity(final Activity activity)
+ {
+ try {
+ mApplicationContext = activity.getApplicationContext();
+ } catch(final Exception e) {
+ Log.d(TAG, e.getMessage());
+ }
+ }
+
+ private class ProgressWatcher implements Runnable
+ {
+ @Override
+ public void run()
+ {
+ final int duratation = getDuration();
+ int currentPosition = getCurrentPosition();
+
+ try {
+ while (duratation >= currentPosition && isPlaying()) {
+ onMediaPlayerInfoNative(MEDIA_PLAYER_PROGRESS, currentPosition, mID);
+ Thread.sleep(1000);
+ currentPosition = getCurrentPosition();
+ }
+ } catch (final InterruptedException e) {
+ Log.d(TAG, e.getMessage());
+ return;
+ }
+ }
+ }
+
+ /**
+ * MediaPlayer OnErrorListener
+ */
+ private class MediaPlayerErrorListener
+ implements MediaPlayer.OnErrorListener
+ {
+ @Override
+ public boolean onError(final MediaPlayer mp,
+ final int what,
+ final int extra)
+ {
+ reset();
+ onErrorNative(what, extra, mID);
+ return true;
+ }
+
+ }
+
+ /**
+ * MediaPlayer OnBufferingListener
+ */
+ private class MediaPlayerBufferingListener
+ implements MediaPlayer.OnBufferingUpdateListener
+ {
+ private int mBufferPercent = -1;
+ @Override
+ public void onBufferingUpdate(final android.media.MediaPlayer mp,
+ final int percent)
+ {
+ // Avoid updates when percent is unchanged.
+ // E.g., we keep getting updates when percent == 100
+ if (mBufferPercent == percent)
+ return;
+
+ onBufferingUpdateNative((mBufferPercent = percent), mID);
+ }
+
+ }
+
+ /**
+ * MediaPlayer OnCompletionListener
+ */
+ private class MediaPlayerCompletionListener
+ implements MediaPlayer.OnCompletionListener
+ {
+ @Override
+ public void onCompletion(final MediaPlayer mp)
+ {
+ onMediaPlayerInfoNative(MEDIA_PLAYER_FINISHED, 0, mID);
+ reset();
+ }
+
+ }
+
+ /**
+ * MediaPlayer OnInfoListener
+ */
+ private class MediaPlayerInfoListener
+ implements MediaPlayer.OnInfoListener
+ {
+ @Override
+ public boolean onInfo(final MediaPlayer mp,
+ final int what,
+ final int extra)
+ {
+ onInfoNative(what, extra, mID);
+ return true;
+ }
+
+ }
+
+ /**
+ * MediaPlayer OnPreparedListener
+ */
+ private class MediaPlayerPreparedListener
+ implements MediaPlayer.OnPreparedListener
+ {
+
+ @Override
+ public void onPrepared(final MediaPlayer mp)
+ {
+ onMediaPlayerInfoNative(MEDIA_PLAYER_DURATION, getDuration(), mID);
+ onMediaPlayerInfoNative(MEDIA_PLAYER_READY, 0, mID);
+ mPreparing = false;
+ }
+
+ }
+
+ /**
+ * MediaPlayer OnSeekCompleteListener
+ */
+ private class MediaPlayerSeekCompleteListener
+ implements MediaPlayer.OnSeekCompleteListener
+ {
+
+ @Override
+ public void onSeekComplete(final MediaPlayer mp)
+ {
+ onMediaPlayerInfoNative(MEDIA_PLAYER_PROGRESS, getCurrentPosition(), mID);
+ }
+
+ }
+
+ /**
+ * MediaPlayer OnVideoSizeChangedListener
+ */
+ private class MediaPlayerVideoSizeChangedListener
+ implements MediaPlayer.OnVideoSizeChangedListener
+ {
+
+ @Override
+ public void onVideoSizeChanged(final MediaPlayer mp,
+ final int width,
+ final int height)
+ {
+ onVideoSizeChangedNative(width, height, mID);
+ }
+
+ }
+
+ public QtAndroidMediaPlayer(final long id)
+ {
+ super();
+ mID = id;
+ setOnBufferingUpdateListener(new MediaPlayerBufferingListener());
+ setOnCompletionListener(new MediaPlayerCompletionListener());
+ setOnInfoListener(new MediaPlayerInfoListener());
+ setOnSeekCompleteListener(new MediaPlayerSeekCompleteListener());
+ setOnVideoSizeChangedListener(new MediaPlayerVideoSizeChangedListener());
+ setOnErrorListener(new MediaPlayerErrorListener());
+ }
+
+ @Override
+ public void start()
+ {
+ if (!mInitialized) {
+ onMediaPlayerInfoNative(MEDIA_PLAYER_INVALID_STATE, 0, mID);
+ return;
+ }
+
+ if (mApplicationContext == null)
+ return;
+
+ if (mPreparing)
+ return;
+
+ if (isPlaying())
+ return;
+
+ try {
+ super.start();
+ Thread progressThread = new Thread(new ProgressWatcher());
+ progressThread.start();
+ } catch (final IllegalStateException e) {
+ reset();
+ Log.d(TAG, e.getMessage());
+ }
+ }
+
+ @Override
+ public void pause()
+ {
+ if (!isPlaying())
+ return;
+
+ try {
+ super.pause();
+ } catch (final IllegalStateException e) {
+ reset();
+ Log.d(TAG, e.getMessage());
+ }
+ }
+
+ @Override
+ public void stop()
+ {
+ if (!mInitialized)
+ return;
+
+ try {
+ super.stop();
+ } catch (final IllegalStateException e) {
+ Log.d(TAG, e.getMessage());
+ } finally {
+ reset();
+ }
+ }
+
+ @Override
+ public void seekTo(final int msec)
+ {
+ if (!mInitialized)
+ return;
+
+ try {
+ super.seekTo(msec);
+ onMediaPlayerInfoNative(MEDIA_PLAYER_PROGRESS, msec, mID);
+ } catch (final IllegalStateException e) {
+ Log.d(TAG, e.getMessage());
+ }
+ }
+
+ @Override
+ public boolean isPlaying()
+ {
+ boolean playing = false;
+
+ if (!mInitialized)
+ return playing;
+
+ try {
+ playing = super.isPlaying();
+ } catch (final IllegalStateException e) {
+ Log.d(TAG, e.getMessage());
+ }
+
+ return playing;
+ }
+
+ public void setMediaPath(final String path)
+ {
+ if (mInitialized)
+ reset();
+
+ try {
+ mPreparing = true;
+ onMediaPlayerInfoNative(MEDIA_PLAYER_PREPARING, 0, mID);
+ mUri = Uri.parse(path);
+ setDataSource(mApplicationContext, mUri);
+ mInitialized = true;
+ setOnPreparedListener(new MediaPlayerPreparedListener());
+ prepareAsync();
+ } catch (final IOException e) {
+ mPreparing = false;
+ onErrorNative(MEDIA_ERROR_UNKNOWN,
+ /* MEDIA_ERROR_UNSUPPORTED= */ -1010,
+ mID);
+ } catch (final IllegalArgumentException e) {
+ Log.d(TAG, e.getMessage());
+ } catch (final SecurityException e) {
+ Log.d(TAG, e.getMessage());
+ } catch (final IllegalStateException e) {
+ Log.d(TAG, e.getMessage());
+ } catch (final NullPointerException e) {
+ Log.d(TAG, e.getMessage());
+ }
+ }
+
+ @Override
+ public int getCurrentPosition()
+ {
+ int currentPosition = 0;
+
+ if (!mInitialized)
+ return currentPosition;
+
+ try {
+ currentPosition = super.getCurrentPosition();
+ } catch (final IllegalStateException e) {
+ Log.d(TAG, e.getMessage());
+ }
+
+ return currentPosition;
+ }
+
+ @Override
+ public int getDuration()
+ {
+ int duration = 0;
+
+ if (!mInitialized)
+ return duration;
+
+ try {
+ duration = super.getDuration();
+ } catch (final IllegalStateException e) {
+ Log.d(TAG, e.getMessage());
+ }
+
+ return duration;
+ }
+
+ private float adjustVolume(final int volume)
+ {
+ if (volume < 1)
+ return 0.0f;
+
+ if (volume > 98)
+ return 1.0f;
+
+ return (float) (1-(Math.log(100-volume)/Math.log(100)));
+ }
+
+ public void setVolume(int volume)
+ {
+ if (volume < 0)
+ volume = 0;
+
+ if (volume > 100)
+ volume = 100;
+
+ float newVolume = adjustVolume(volume);
+
+ try {
+ super.setVolume(newVolume, newVolume);
+ if (!mMuted)
+ mVolume = volume;
+ } catch (final IllegalStateException e) {
+ Log.d(TAG, e.getMessage());
+ }
+ }
+
+ public int getVolume()
+ {
+ return mVolume;
+ }
+
+ public void mute(final boolean mute)
+ {
+ mMuted = mute;
+ setVolume(mute ? 0 : mVolume);
+ }
+
+ public boolean isMuted()
+ {
+ return mMuted;
+ }
+
+ @Override
+ public void reset()
+ {
+ mInitialized = false;
+ super.reset();
+ }
+
+}
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java
new file mode 100644
index 000000000..b8837d557
--- /dev/null
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java
@@ -0,0 +1,74 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtMultimedia module 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 Digia. For licensing terms and
+ ** conditions see http://qt.digia.com/licensing. For further information
+ ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.LGPL included in the
+ ** packaging of this file. Please review the following information to
+ ** ensure the GNU Lesser General Public License version 2.1 requirements
+ ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ **
+ ** In addition, as a special exception, Digia gives you certain additional
+ ** rights. These rights are described in the Digia Qt LGPL Exception
+ ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+ **
+ ** GNU General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU
+ ** General Public License version 3.0 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.GPL included in the
+ ** packaging of this file. Please review the following information to
+ ** ensure the GNU General Public License version 3.0 requirements will be
+ ** met: http://www.gnu.org/copyleft/gpl.html.
+ **
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+package org.qtproject.qt5.android.multimedia;
+
+import android.graphics.SurfaceTexture;
+
+public class QtSurfaceTexture implements SurfaceTexture.OnFrameAvailableListener
+{
+ public SurfaceTexture surfaceTexture;
+ private int texID;
+
+ public QtSurfaceTexture(int texName)
+ {
+ texID = texName;
+ surfaceTexture = new SurfaceTexture(texName);
+ surfaceTexture.setOnFrameAvailableListener(this);
+ }
+
+ public void getTransformMatrix(float[] mtx)
+ {
+ surfaceTexture.getTransformMatrix(mtx);
+ }
+
+ public void updateTexImage()
+ {
+ surfaceTexture.updateTexImage();
+ }
+
+ public void onFrameAvailable(SurfaceTexture surfaceTexture)
+ {
+ notifyFrameAvailable(texID);
+ }
+
+ private static native void notifyFrameAvailable(int id);
+}
diff --git a/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java
new file mode 100644
index 000000000..15c5f231f
--- /dev/null
+++ b/src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java
@@ -0,0 +1,114 @@
+/****************************************************************************
+ **
+ ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+ ** Contact: http://www.qt-project.org/legal
+ **
+ ** This file is part of the QtMultimedia module 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 Digia. For licensing terms and
+ ** conditions see http://qt.digia.com/licensing. For further information
+ ** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.LGPL included in the
+ ** packaging of this file. Please review the following information to
+ ** ensure the GNU Lesser General Public License version 2.1 requirements
+ ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+ **
+ ** In addition, as a special exception, Digia gives you certain additional
+ ** rights. These rights are described in the Digia Qt LGPL Exception
+ ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+ **
+ ** GNU General Public License Usage
+ ** Alternatively, this file may be used under the terms of the GNU
+ ** General Public License version 3.0 as published by the Free Software
+ ** Foundation and appearing in the file LICENSE.GPL included in the
+ ** packaging of this file. Please review the following information to
+ ** ensure the GNU General Public License version 3.0 requirements will be
+ ** met: http://www.gnu.org/copyleft/gpl.html.
+ **
+ **
+ ** $QT_END_LICENSE$
+ **
+ ****************************************************************************/
+
+package org.qtproject.qt5.android.multimedia;
+
+import android.view.SurfaceHolder;
+import android.view.Surface;
+import android.graphics.Rect;
+import android.graphics.Canvas;
+
+public class QtSurfaceTextureHolder implements SurfaceHolder
+{
+ private Surface surfaceTexture;
+
+ public QtSurfaceTextureHolder(Surface surface)
+ {
+ surfaceTexture = surface;
+ }
+
+ public void addCallback(SurfaceHolder.Callback callback)
+ {
+ }
+
+ public Surface getSurface()
+ {
+ return surfaceTexture;
+ }
+
+ public Rect getSurfaceFrame()
+ {
+ return new Rect();
+ }
+
+ public boolean isCreating()
+ {
+ return false;
+ }
+
+ public Canvas lockCanvas(Rect dirty)
+ {
+ return new Canvas();
+ }
+
+ public Canvas lockCanvas()
+ {
+ return new Canvas();
+ }
+
+ public void removeCallback(SurfaceHolder.Callback callback)
+ {
+ }
+
+ public void setFixedSize(int width, int height)
+ {
+ }
+
+ public void setFormat(int format)
+ {
+ }
+
+ public void setKeepScreenOn(boolean screenOn)
+ {
+ }
+
+ public void setSizeFromLayout()
+ {
+ }
+
+ public void setType(int type)
+ {
+ }
+
+ public void unlockCanvasAndPost(Canvas canvas)
+ {
+ }
+}
diff --git a/src/plugins/android/mediaplayer/mediaplayer.json b/src/plugins/android/mediaplayer/mediaplayer.json
new file mode 100644
index 000000000..c4a27ea01
--- /dev/null
+++ b/src/plugins/android/mediaplayer/mediaplayer.json
@@ -0,0 +1,3 @@
+{
+ "Keys": ["org.qt-project.qt.mediaplayer"]
+}
diff --git a/src/plugins/android/mediaplayer/mediaplayer.pro b/src/plugins/android/mediaplayer/mediaplayer.pro
new file mode 100644
index 000000000..cabe4c666
--- /dev/null
+++ b/src/plugins/android/mediaplayer/mediaplayer.pro
@@ -0,0 +1,24 @@
+TARGET = androidmediaplayer
+QT += multimedia-private gui-private platformsupport-private network
+
+PLUGIN_TYPE = mediaservice
+PLUGIN_CLASS_NAME = QAndroidMediaPlayerServicePlugin
+load(qt_plugin)
+
+HEADERS += \
+ qandroidmediaplayercontrol.h \
+ qandroidmediaservice.h \
+ qandroidmetadatareadercontrol.h \
+ qandroidmediaserviceplugin.h \
+ qandroidvideorendercontrol.h \
+ qandroidvideooutput.h
+SOURCES += \
+ qandroidmediaplayercontrol.cpp \
+ qandroidmediaservice.cpp \
+ qandroidmetadatareadercontrol.cpp \
+ qandroidmediaserviceplugin.cpp \
+ qandroidvideorendercontrol.cpp
+
+OTHER_FILES += mediaplayer.json
+
+include (../wrappers/wrappers.pri)
diff --git a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp
new file mode 100644
index 000000000..5a9c8b84f
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp
@@ -0,0 +1,496 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidmediaplayercontrol.h"
+#include "jmediaplayer.h"
+#include "qandroidvideooutput.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidMediaPlayerControl::QAndroidMediaPlayerControl(QObject *parent)
+ : QMediaPlayerControl(parent),
+ mMediaPlayer(new JMediaPlayer),
+ mCurrentState(QMediaPlayer::StoppedState),
+ mCurrentMediaStatus(QMediaPlayer::NoMedia),
+ mMediaStream(0),
+ mVideoOutput(0),
+ mSeekable(true),
+ mBufferPercent(-1),
+ mAudioAvailable(false),
+ mVideoAvailable(false),
+ mBuffering(false),
+ mMediaPlayerReady(false),
+ mPendingPosition(-1)
+{
+ connect(mMediaPlayer, SIGNAL(bufferingUpdate(qint32)),
+ this, SLOT(onBufferChanged(qint32)));
+ connect(mMediaPlayer, SIGNAL(info(qint32, qint32)),
+ this, SLOT(onInfo(qint32, qint32)));
+ connect(mMediaPlayer, SIGNAL(error(qint32, qint32)),
+ this, SLOT(onError(qint32, qint32)));
+ connect(mMediaPlayer, SIGNAL(mediaPlayerInfo(qint32, qint32)),
+ this, SLOT(onMediaPlayerInfo(qint32, qint32)));
+ connect(mMediaPlayer, SIGNAL(videoSizeChanged(qint32,qint32)),
+ this, SLOT(onVideoSizeChanged(qint32,qint32)));
+}
+
+QAndroidMediaPlayerControl::~QAndroidMediaPlayerControl()
+{
+ delete mMediaPlayer;
+}
+
+QMediaPlayer::State QAndroidMediaPlayerControl::state() const
+{
+ return mCurrentState;
+}
+
+QMediaPlayer::MediaStatus QAndroidMediaPlayerControl::mediaStatus() const
+{
+ return mCurrentMediaStatus;
+}
+
+qint64 QAndroidMediaPlayerControl::duration() const
+{
+ return (mCurrentMediaStatus == QMediaPlayer::InvalidMedia
+ || mCurrentMediaStatus == QMediaPlayer::NoMedia) ? 0
+ : mMediaPlayer->getDuration();
+}
+
+qint64 QAndroidMediaPlayerControl::position() const
+{
+ if (!mMediaPlayerReady)
+ return mPendingPosition < 0 ? 0 : mPendingPosition;
+
+ return mMediaPlayer->getCurrentPosition();
+}
+
+void QAndroidMediaPlayerControl::setPosition(qint64 position)
+{
+ if (!mSeekable)
+ return;
+
+ const int seekPosition = (position > INT_MAX) ? INT_MAX : position;
+
+ if (!mMediaPlayerReady) {
+ mPendingPosition = seekPosition;
+ Q_EMIT positionChanged(seekPosition);
+ return;
+ }
+
+ mMediaPlayer->seekTo(seekPosition);
+ mPendingPosition = -1;
+}
+
+int QAndroidMediaPlayerControl::volume() const
+{
+ return mMediaPlayer->volume();
+}
+
+void QAndroidMediaPlayerControl::setVolume(int volume)
+{
+ mMediaPlayer->setVolume(volume);
+ Q_EMIT volumeChanged(volume);
+}
+
+bool QAndroidMediaPlayerControl::isMuted() const
+{
+ return mMediaPlayer->isMuted();
+}
+
+void QAndroidMediaPlayerControl::setMuted(bool muted)
+{
+ mMediaPlayer->setMuted(muted);
+ Q_EMIT mutedChanged(muted);
+}
+
+int QAndroidMediaPlayerControl::bufferStatus() const
+{
+ return mBufferPercent;
+}
+
+bool QAndroidMediaPlayerControl::isAudioAvailable() const
+{
+ return mAudioAvailable;
+}
+
+bool QAndroidMediaPlayerControl::isVideoAvailable() const
+{
+ return mVideoAvailable;
+}
+
+bool QAndroidMediaPlayerControl::isSeekable() const
+{
+ return mSeekable;
+}
+
+QMediaTimeRange QAndroidMediaPlayerControl::availablePlaybackRanges() const
+{
+ return mAvailablePlaybackRange;
+}
+
+void QAndroidMediaPlayerControl::updateAvailablePlaybackRanges()
+{
+ if (mBuffering) {
+ const qint64 pos = position();
+ const qint64 end = (duration() / 100) * mBufferPercent;
+ mAvailablePlaybackRange.addInterval(pos, end);
+ } else if (mSeekable) {
+ mAvailablePlaybackRange = QMediaTimeRange(0, duration());
+ } else {
+ mAvailablePlaybackRange = QMediaTimeRange();
+ }
+
+ Q_EMIT availablePlaybackRangesChanged(mAvailablePlaybackRange);
+}
+
+qreal QAndroidMediaPlayerControl::playbackRate() const
+{
+ return 1.0f;
+}
+
+void QAndroidMediaPlayerControl::setPlaybackRate(qreal rate)
+{
+ Q_UNUSED(rate);
+}
+
+QMediaContent QAndroidMediaPlayerControl::media() const
+{
+ return mMediaContent;
+}
+
+const QIODevice *QAndroidMediaPlayerControl::mediaStream() const
+{
+ return mMediaStream;
+}
+
+void QAndroidMediaPlayerControl::setMedia(const QMediaContent &mediaContent,
+ QIODevice *stream)
+{
+ mMediaContent = mediaContent;
+ mMediaStream = stream;
+
+ const QString uri = mediaContent.canonicalUrl().toString();
+
+ if (!uri.isEmpty())
+ mMediaPlayer->setDataSource(uri);
+ else
+ setMediaStatus(QMediaPlayer::NoMedia);
+
+ Q_EMIT mediaChanged(mMediaContent);
+
+ resetBufferingProgress();
+
+ // reset some properties
+ setAudioAvailable(false);
+ setVideoAvailable(false);
+ setSeekable(true);
+}
+
+void QAndroidMediaPlayerControl::setVideoOutput(QAndroidVideoOutput *videoOutput)
+{
+ if (mVideoOutput)
+ mVideoOutput->stop();
+
+ mVideoOutput = videoOutput;
+}
+
+void QAndroidMediaPlayerControl::play()
+{
+ if (!mMediaPlayerReady) {
+ mPendingState = QMediaPlayer::PlayingState;
+ if (mCurrentState == QMediaPlayer::StoppedState
+ && !mMediaContent.isNull()
+ && mCurrentMediaStatus != QMediaPlayer::LoadingMedia) {
+ setMedia(mMediaContent, 0);
+ }
+ return;
+ }
+
+ mMediaPlayer->play();
+ setState(QMediaPlayer::PlayingState);
+}
+
+void QAndroidMediaPlayerControl::pause()
+{
+ if (!mMediaPlayerReady) {
+ mPendingState = QMediaPlayer::PausedState;
+ return;
+ }
+
+ mMediaPlayer->pause();
+ setState(QMediaPlayer::PausedState);
+}
+
+void QAndroidMediaPlayerControl::stop()
+{
+ mMediaPlayer->stop();
+ setState(QMediaPlayer::StoppedState);
+}
+
+void QAndroidMediaPlayerControl::onInfo(qint32 what, qint32 extra)
+{
+ Q_UNUSED(extra);
+ switch (what) {
+ case JMediaPlayer::MEDIA_INFO_UNKNOWN:
+ break;
+ case JMediaPlayer::MEDIA_INFO_VIDEO_TRACK_LAGGING:
+ // IGNORE
+ break;
+ case JMediaPlayer::MEDIA_INFO_VIDEO_RENDERING_START:
+ break;
+ case JMediaPlayer::MEDIA_INFO_BUFFERING_START:
+ mPendingState = mCurrentState;
+ setState(QMediaPlayer::PausedState);
+ setMediaStatus(QMediaPlayer::StalledMedia);
+ break;
+ case JMediaPlayer::MEDIA_INFO_BUFFERING_END:
+ setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia : QMediaPlayer::BufferingMedia);
+ flushPendingStates();
+ break;
+ case JMediaPlayer::MEDIA_INFO_BAD_INTERLEAVING:
+ break;
+ case JMediaPlayer::MEDIA_INFO_NOT_SEEKABLE:
+ setSeekable(false);
+ break;
+ case JMediaPlayer::MEDIA_INFO_METADATA_UPDATE:
+ Q_EMIT metaDataUpdated();
+ break;
+ }
+}
+
+void QAndroidMediaPlayerControl::onMediaPlayerInfo(qint32 what, qint32 extra)
+{
+ switch (what) {
+ case JMediaPlayer::MEDIA_PLAYER_INVALID_STATE:
+ setError(what, QStringLiteral("Error: Invalid state"));
+ break;
+ case JMediaPlayer::MEDIA_PLAYER_PREPARING:
+ setMediaStatus(QMediaPlayer::LoadingMedia);
+ setState(QMediaPlayer::StoppedState);
+ break;
+ case JMediaPlayer::MEDIA_PLAYER_READY:
+ if (mBuffering) {
+ setMediaStatus(mBufferPercent == 100 ? QMediaPlayer::BufferedMedia
+ : QMediaPlayer::BufferingMedia);
+ } else {
+ setMediaStatus(QMediaPlayer::LoadedMedia);
+ mBufferPercent = 100;
+ Q_EMIT bufferStatusChanged(mBufferPercent);
+ updateAvailablePlaybackRanges();
+ }
+ setAudioAvailable(true);
+ mMediaPlayerReady = true;
+ flushPendingStates();
+ break;
+ case JMediaPlayer::MEDIA_PLAYER_DURATION:
+ Q_EMIT durationChanged(extra);
+ break;
+ case JMediaPlayer::MEDIA_PLAYER_PROGRESS:
+ Q_EMIT positionChanged(extra);
+ break;
+ case JMediaPlayer::MEDIA_PLAYER_FINISHED:
+ setState(QMediaPlayer::StoppedState);
+ setMediaStatus(QMediaPlayer::EndOfMedia);
+ break;
+ }
+}
+
+void QAndroidMediaPlayerControl::onError(qint32 what, qint32 extra)
+{
+ QString errorString;
+ QMediaPlayer::Error error = QMediaPlayer::ResourceError;
+
+ switch (what) {
+ case JMediaPlayer::MEDIA_ERROR_UNKNOWN:
+ errorString = QLatin1String("Error:");
+ break;
+ case JMediaPlayer::MEDIA_ERROR_SERVER_DIED:
+ errorString = QLatin1String("Error: Server died");
+ error = QMediaPlayer::ServiceMissingError;
+ break;
+ }
+
+ switch (extra) {
+ case JMediaPlayer::MEDIA_ERROR_IO: // Network OR file error
+ errorString += QLatin1String(" (I/O operation failed)");
+ error = QMediaPlayer::NetworkError;
+ setMediaStatus(QMediaPlayer::InvalidMedia);
+ break;
+ case JMediaPlayer::MEDIA_ERROR_MALFORMED:
+ errorString += QLatin1String(" (Malformed bitstream)");
+ error = QMediaPlayer::FormatError;
+ setMediaStatus(QMediaPlayer::InvalidMedia);
+ break;
+ case JMediaPlayer::MEDIA_ERROR_UNSUPPORTED:
+ errorString += QLatin1String(" (Unsupported media)");
+ error = QMediaPlayer::FormatError;
+ setMediaStatus(QMediaPlayer::InvalidMedia);
+ break;
+ case JMediaPlayer::MEDIA_ERROR_TIMED_OUT:
+ errorString += QLatin1String(" (Timed out)");
+ break;
+ case JMediaPlayer::MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK:
+ errorString += QLatin1String(" (Unable to start progressive playback')");
+ error = QMediaPlayer::FormatError;
+ setMediaStatus(QMediaPlayer::InvalidMedia);
+ break;
+ }
+
+ setError(error, errorString);
+}
+
+void QAndroidMediaPlayerControl::onBufferChanged(qint32 percent)
+{
+ mBuffering = true;
+ mBufferPercent = percent;
+ Q_EMIT bufferStatusChanged(mBufferPercent);
+
+ updateAvailablePlaybackRanges();
+
+ if (mBufferPercent == 100)
+ setMediaStatus(QMediaPlayer::BufferedMedia);
+}
+
+void QAndroidMediaPlayerControl::onVideoSizeChanged(qint32 width, qint32 height)
+{
+ if (width == 0 || height == 0)
+ return;
+
+ setVideoAvailable(true);
+
+ if (mVideoOutput) {
+ if (!mMediaPlayer->display())
+ mMediaPlayer->setDisplay(mVideoOutput->surfaceHolder());
+ if (mMediaPlayer->display())
+ mVideoOutput->setVideoSize(QSize(width, height));
+ }
+}
+
+void QAndroidMediaPlayerControl::setState(QMediaPlayer::State state)
+{
+ if (mCurrentState == state)
+ return;
+
+ if (state == QMediaPlayer::StoppedState) {
+ if (mVideoOutput)
+ mVideoOutput->stop();
+ resetBufferingProgress();
+ mMediaPlayerReady = false;
+ mPendingPosition = -1;
+ Q_EMIT positionChanged(0);
+ }
+
+ mCurrentState = state;
+ Q_EMIT stateChanged(mCurrentState);
+}
+
+void QAndroidMediaPlayerControl::setMediaStatus(QMediaPlayer::MediaStatus status)
+{
+ if (mCurrentMediaStatus == status)
+ return;
+
+ if (status == QMediaPlayer::NoMedia || status == QMediaPlayer::InvalidMedia)
+ Q_EMIT durationChanged(0);
+
+ mCurrentMediaStatus = status;
+ Q_EMIT mediaStatusChanged(mCurrentMediaStatus);
+}
+
+void QAndroidMediaPlayerControl::setError(int error,
+ const QString &errorString)
+{
+ setState(QMediaPlayer::StoppedState);
+ Q_EMIT QMediaPlayerControl::error(error, errorString);
+}
+
+void QAndroidMediaPlayerControl::setSeekable(bool seekable)
+{
+ if (mSeekable == seekable)
+ return;
+
+ mSeekable = seekable;
+ Q_EMIT seekableChanged(mSeekable);
+}
+
+void QAndroidMediaPlayerControl::setAudioAvailable(bool available)
+{
+ if (mAudioAvailable == available)
+ return;
+
+ mAudioAvailable = available;
+ Q_EMIT audioAvailableChanged(mAudioAvailable);
+}
+
+void QAndroidMediaPlayerControl::setVideoAvailable(bool available)
+{
+ if (mVideoAvailable == available)
+ return;
+
+ mVideoAvailable = available;
+ Q_EMIT videoAvailableChanged(mVideoAvailable);
+}
+
+void QAndroidMediaPlayerControl::resetBufferingProgress()
+{
+ mBuffering = false;
+ mBufferPercent = 0;
+ mAvailablePlaybackRange = QMediaTimeRange();
+ Q_EMIT bufferStatusChanged(mBufferPercent);
+}
+
+void QAndroidMediaPlayerControl::flushPendingStates()
+{
+ switch (mPendingState) {
+ case QMediaPlayer::PlayingState:
+ if (mPendingPosition > -1)
+ setPosition(mPendingPosition);
+ play();
+ break;
+ case QMediaPlayer::PausedState:
+ pause();
+ break;
+ case QMediaPlayer::StoppedState:
+ stop();
+ break;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h
new file mode 100644
index 000000000..445e8de7a
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMEDIAPLAYERCONTROL_H
+#define QANDROIDMEDIAPLAYERCONTROL_H
+
+#include <qglobal.h>
+#include <QMediaPlayerControl>
+
+QT_BEGIN_NAMESPACE
+
+class JMediaPlayer;
+class QAndroidVideoOutput;
+
+class QAndroidMediaPlayerControl : public QMediaPlayerControl
+{
+ Q_OBJECT
+public:
+ explicit QAndroidMediaPlayerControl(QObject *parent = 0);
+ ~QAndroidMediaPlayerControl() Q_DECL_OVERRIDE;
+
+ QMediaPlayer::State state() const Q_DECL_OVERRIDE;
+ QMediaPlayer::MediaStatus mediaStatus() const Q_DECL_OVERRIDE;
+ qint64 duration() const Q_DECL_OVERRIDE;
+ qint64 position() const Q_DECL_OVERRIDE;
+ int volume() const Q_DECL_OVERRIDE;
+ bool isMuted() const Q_DECL_OVERRIDE;
+ int bufferStatus() const Q_DECL_OVERRIDE;
+ bool isAudioAvailable() const Q_DECL_OVERRIDE;
+ bool isVideoAvailable() const Q_DECL_OVERRIDE;
+ bool isSeekable() const Q_DECL_OVERRIDE;
+ QMediaTimeRange availablePlaybackRanges() const Q_DECL_OVERRIDE;
+ qreal playbackRate() const Q_DECL_OVERRIDE;
+ void setPlaybackRate(qreal rate) Q_DECL_OVERRIDE;
+ QMediaContent media() const Q_DECL_OVERRIDE;
+ const QIODevice *mediaStream() const Q_DECL_OVERRIDE;
+ void setMedia(const QMediaContent &mediaContent, QIODevice *stream) Q_DECL_OVERRIDE;
+
+ void setVideoOutput(QAndroidVideoOutput *videoOutput);
+
+Q_SIGNALS:
+ void metaDataUpdated();
+
+public Q_SLOTS:
+ void setPosition(qint64 position) Q_DECL_OVERRIDE;
+ void play() Q_DECL_OVERRIDE;
+ void pause() Q_DECL_OVERRIDE;
+ void stop() Q_DECL_OVERRIDE;
+ void setVolume(int volume) Q_DECL_OVERRIDE;
+ void setMuted(bool muted) Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ void onError(qint32 what, qint32 extra);
+ void onInfo(qint32 what, qint32 extra);
+ void onMediaPlayerInfo(qint32 what, qint32 extra);
+ void onBufferChanged(qint32 percent);
+ void onVideoSizeChanged(qint32 width, qint32 height);
+
+private:
+ JMediaPlayer *mMediaPlayer;
+ QMediaPlayer::State mCurrentState;
+ QMediaPlayer::MediaStatus mCurrentMediaStatus;
+ QMediaContent mMediaContent;
+ QIODevice *mMediaStream;
+ QAndroidVideoOutput *mVideoOutput;
+ bool mSeekable;
+ int mBufferPercent;
+ bool mAudioAvailable;
+ bool mVideoAvailable;
+ bool mBuffering;
+ QMediaTimeRange mAvailablePlaybackRange;
+ bool mMediaPlayerReady;
+ QMediaPlayer::State mPendingState;
+ qint64 mPendingPosition;
+
+ void setState(QMediaPlayer::State state);
+ void setMediaStatus(QMediaPlayer::MediaStatus status);
+ void setError(int error, const QString &errorString);
+ void setSeekable(bool seekable);
+ void setAudioAvailable(bool available);
+ void setVideoAvailable(bool available);
+ void updateAvailablePlaybackRanges();
+ void resetBufferingProgress();
+ void flushPendingStates();
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMEDIAPLAYERCONTROL_H
diff --git a/src/plugins/android/mediaplayer/qandroidmediaservice.cpp b/src/plugins/android/mediaplayer/qandroidmediaservice.cpp
new file mode 100644
index 000000000..175958676
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidmediaservice.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidmediaservice.h"
+
+#include "qandroidmediaplayercontrol.h"
+#include "qandroidmetadatareadercontrol.h"
+#include "qandroidvideorendercontrol.h"
+
+QT_BEGIN_NAMESPACE
+
+QAndroidMediaService::QAndroidMediaService(QObject *parent)
+ : QMediaService(parent)
+ , mVideoRendererControl(0)
+{
+ mMediaControl = new QAndroidMediaPlayerControl;
+ mMetadataControl = new QAndroidMetaDataReaderControl;
+ connect(mMediaControl, SIGNAL(mediaChanged(QMediaContent)),
+ mMetadataControl, SLOT(onMediaChanged(QMediaContent)));
+ connect(mMediaControl, SIGNAL(metaDataUpdated()),
+ mMetadataControl, SLOT(onUpdateMetaData()));
+}
+
+QAndroidMediaService::~QAndroidMediaService()
+{
+ delete mMediaControl;
+ delete mMetadataControl;
+ delete mVideoRendererControl;
+}
+
+QMediaControl *QAndroidMediaService::requestControl(const char *name)
+{
+ if (qstrcmp(name, QMediaPlayerControl_iid) == 0)
+ return mMediaControl;
+
+ if (qstrcmp(name, QMetaDataReaderControl_iid) == 0)
+ return mMetadataControl;
+
+ if (qstrcmp(name, QVideoRendererControl_iid) == 0) {
+ if (!mVideoRendererControl) {
+ mVideoRendererControl = new QAndroidVideoRendererControl;
+ mMediaControl->setVideoOutput(mVideoRendererControl);
+ return mVideoRendererControl;
+ }
+ }
+
+ return 0;
+}
+
+void QAndroidMediaService::releaseControl(QMediaControl *control)
+{
+ if (control == mVideoRendererControl) {
+ mMediaControl->setVideoOutput(0);
+ delete mVideoRendererControl;
+ mVideoRendererControl = 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/mediaplayer/qandroidmediaservice.h b/src/plugins/android/mediaplayer/qandroidmediaservice.h
new file mode 100644
index 000000000..4d310e8e0
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidmediaservice.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMEDIASERVICE_H
+#define QANDROIDMEDIASERVICE_H
+
+#include <QMediaService>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidMediaPlayerControl;
+class QAndroidMetaDataReaderControl;
+class QAndroidVideoRendererControl;
+
+class QAndroidMediaService : public QMediaService
+{
+ Q_OBJECT
+public:
+ explicit QAndroidMediaService(QObject *parent = 0);
+ ~QAndroidMediaService() Q_DECL_OVERRIDE;
+
+ QMediaControl* requestControl(const char *name) Q_DECL_OVERRIDE;
+ void releaseControl(QMediaControl *control) Q_DECL_OVERRIDE;
+
+private:
+ QAndroidMediaPlayerControl *mMediaControl;
+ QAndroidMetaDataReaderControl *mMetadataControl;
+ QAndroidVideoRendererControl *mVideoRendererControl;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMEDIASERVICE_H
diff --git a/src/plugins/android/mediaplayer/qandroidmediaserviceplugin.cpp b/src/plugins/android/mediaplayer/qandroidmediaserviceplugin.cpp
new file mode 100644
index 000000000..3bf703413
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidmediaserviceplugin.cpp
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidmediaserviceplugin.h"
+
+#include "qandroidmediaservice.h"
+#include "jmediaplayer.h"
+#include "jsurfacetexture.h"
+#include "jsurfacetextureholder.h"
+#include <qdebug.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidMediaServicePlugin::QAndroidMediaServicePlugin()
+{
+}
+
+QAndroidMediaServicePlugin::~QAndroidMediaServicePlugin()
+{
+}
+
+QMediaService *QAndroidMediaServicePlugin::create(const QString &key)
+{
+ if (key == QStringLiteral(Q_MEDIASERVICE_MEDIAPLAYER))
+ return new QAndroidMediaService;
+
+ qWarning() << "Android service plugin: unsupported key:" << key;
+ return 0;
+}
+
+void QAndroidMediaServicePlugin::release(QMediaService *service)
+{
+ delete service;
+}
+
+QMediaServiceProviderHint::Features QAndroidMediaServicePlugin::supportedFeatures(const QByteArray &service) const
+{
+ if (service == Q_MEDIASERVICE_MEDIAPLAYER)
+ return QMediaServiceProviderHint::VideoSurface;
+
+ return QMediaServiceProviderHint::Features();
+}
+
+
+Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*reserved*/)
+{
+ typedef union {
+ JNIEnv *nativeEnvironment;
+ void *venv;
+ } UnionJNIEnvToVoid;
+
+ UnionJNIEnvToVoid uenv;
+ uenv.venv = NULL;
+
+ if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK)
+ return JNI_ERR;
+
+ JNIEnv *jniEnv = uenv.nativeEnvironment;
+
+ if (!JMediaPlayer::initJNI(jniEnv) ||
+ !JSurfaceTexture::initJNI(jniEnv) ||
+ !JSurfaceTextureHolder::initJNI(jniEnv)) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_4;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/mediaplayer/qandroidmediaserviceplugin.h b/src/plugins/android/mediaplayer/qandroidmediaserviceplugin.h
new file mode 100644
index 000000000..d004635f2
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidmediaserviceplugin.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMEDIASERVICEPLUGIN_H
+#define QANDROIDMEDIASERVICEPLUGIN_H
+
+#include <QMediaServiceProviderPlugin>
+
+QT_BEGIN_NAMESPACE
+
+class QMediaService;
+class QAndroidMediaService;
+
+class QAndroidMediaServicePlugin
+ : public QMediaServiceProviderPlugin
+ , public QMediaServiceFeaturesInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QMediaServiceFeaturesInterface)
+ Q_PLUGIN_METADATA(IID "org.qt-project.qt.mediaserviceproviderfactory/5.0"
+ FILE "mediaplayer.json")
+
+public:
+ QAndroidMediaServicePlugin();
+ ~QAndroidMediaServicePlugin();
+
+ QMediaService* create(QString const& key) Q_DECL_OVERRIDE;
+ void release(QMediaService *service) Q_DECL_OVERRIDE;
+ QMediaServiceProviderHint::Features supportedFeatures(const QByteArray &service) const Q_DECL_OVERRIDE;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMEDIASERVICEPLUGIN_H
diff --git a/src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.cpp b/src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.cpp
new file mode 100644
index 000000000..9b2f4e17b
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.cpp
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidmetadatareadercontrol.h"
+
+#include "jmediametadataretriever.h"
+#include <qsize.h>
+#include <QDate>
+
+QT_BEGIN_NAMESPACE
+
+// Genre name ordered by ID
+// see: http://id3.org/id3v2.3.0#Appendix_A_-_Genre_List_from_ID3v1
+static const char* qt_ID3GenreNames[] =
+{
+ "Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop", "Jazz",
+ "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno",
+ "Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno",
+ "Ambient", "Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental",
+ "Acid", "House", "Game", "Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk",
+ "Space", "Meditative", "Instrumental Pop", "Instrumental Rock", "Ethnic", "Gothic", "Darkwave",
+ "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance", "Dream", "Southern Rock", "Comedy",
+ "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle", "Native American",
+ "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal",
+ "Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk",
+ "Folk-Rock", "National Folk", "Swing", "Fast Fusion", "Bebob", "Latin", "Revival", "Celtic",
+ "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock", "Psychedelic Rock",
+ "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour",
+ "Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus",
+ "Porn Groove", "Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad",
+ "Power Ballad", "Rhythmic Soul", "Freestyle", "Duet", "Punk Rock", "Drum Solo", "A capella",
+ "Euro-House", "Dance Hall"
+};
+
+QAndroidMetaDataReaderControl::QAndroidMetaDataReaderControl(QObject *parent)
+ : QMetaDataReaderControl(parent)
+ , m_available(false)
+ , m_retriever(0)
+{
+ m_retriever = new JMediaMetadataRetriever;
+ if (!m_retriever->isValid()) {
+ delete m_retriever;
+ m_retriever = 0;
+ }
+}
+
+QAndroidMetaDataReaderControl::~QAndroidMetaDataReaderControl()
+{
+ if (m_retriever) {
+ m_retriever->release();
+ delete m_retriever;
+ }
+}
+
+bool QAndroidMetaDataReaderControl::isMetaDataAvailable() const
+{
+ return m_available;
+}
+
+QVariant QAndroidMetaDataReaderControl::metaData(const QString &key) const
+{
+ return m_metadata.value(key);
+}
+
+QStringList QAndroidMetaDataReaderControl::availableMetaData() const
+{
+ return m_metadata.keys();
+}
+
+void QAndroidMetaDataReaderControl::onMediaChanged(const QMediaContent &media)
+{
+ if (!m_retriever)
+ return;
+
+ m_mediaContent = media;
+ updateData();
+}
+
+void QAndroidMetaDataReaderControl::onUpdateMetaData()
+{
+ if (!m_retriever || m_mediaContent.isNull())
+ return;
+
+ updateData();
+}
+
+void QAndroidMetaDataReaderControl::updateData()
+{
+ m_metadata.clear();
+
+ if (!m_mediaContent.isNull()) {
+ if (m_retriever->setDataSource(m_mediaContent.canonicalUrl())) {
+ QString mimeType = m_retriever->extractMetadata(JMediaMetadataRetriever::MimeType);
+ if (!mimeType.isNull())
+ m_metadata.insert(QMediaMetaData::MediaType, mimeType);
+
+ bool isVideo = !m_retriever->extractMetadata(JMediaMetadataRetriever::HasVideo).isNull()
+ || mimeType.startsWith(QStringLiteral("video"));
+
+ QString string = m_retriever->extractMetadata(JMediaMetadataRetriever::Album);
+ if (!string.isNull())
+ m_metadata.insert(QMediaMetaData::AlbumTitle, string);
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::AlbumArtist);
+ if (!string.isNull())
+ m_metadata.insert(QMediaMetaData::AlbumArtist, string);
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::Artist);
+ if (!string.isNull()) {
+ m_metadata.insert(isVideo ? QMediaMetaData::LeadPerformer
+ : QMediaMetaData::ContributingArtist,
+ string.split('/', QString::SkipEmptyParts));
+ }
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::Author);
+ if (!string.isNull())
+ m_metadata.insert(QMediaMetaData::Author, string.split('/', QString::SkipEmptyParts));
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::Bitrate);
+ if (!string.isNull()) {
+ m_metadata.insert(isVideo ? QMediaMetaData::VideoBitRate
+ : QMediaMetaData::AudioBitRate,
+ string.toInt());
+ }
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::CDTrackNumber);
+ if (!string.isNull())
+ m_metadata.insert(QMediaMetaData::TrackNumber, string.toInt());
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::Composer);
+ if (!string.isNull())
+ m_metadata.insert(QMediaMetaData::Composer, string.split('/', QString::SkipEmptyParts));
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::Date);
+ if (!string.isNull())
+ m_metadata.insert(QMediaMetaData::Date, QDateTime::fromString(string, QStringLiteral("yyyyMMddTHHmmss.zzzZ")).date());
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::Duration);
+ if (!string.isNull())
+ m_metadata.insert(QMediaMetaData::Duration, string.toLongLong());
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::Genre);
+ if (!string.isNull()) {
+ // The genre can be returned as an ID3v2 id, get the name for it in that case
+ if (string.startsWith('(') && string.endsWith(')')) {
+ bool ok = false;
+ int genreId = string.mid(1, string.length() - 2).toInt(&ok);
+ if (ok && genreId >= 0 && genreId <= 125)
+ string = QLatin1String(qt_ID3GenreNames[genreId]);
+ }
+ m_metadata.insert(QMediaMetaData::Genre, string);
+ }
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::Title);
+ if (!string.isNull())
+ m_metadata.insert(QMediaMetaData::Title, string);
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::VideoHeight);
+ if (!string.isNull()) {
+ int height = string.toInt();
+ int width = m_retriever->extractMetadata(JMediaMetadataRetriever::VideoWidth).toInt();
+ m_metadata.insert(QMediaMetaData::Resolution, QSize(width, height));
+ }
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::Writer);
+ if (!string.isNull())
+ m_metadata.insert(QMediaMetaData::Writer, string.split('/', QString::SkipEmptyParts));
+
+ string = m_retriever->extractMetadata(JMediaMetadataRetriever::Year);
+ if (!string.isNull())
+ m_metadata.insert(QMediaMetaData::Year, string.toInt());
+ }
+ }
+
+ bool oldAvailable = m_available;
+ m_available = !m_metadata.isEmpty();
+ if (m_available != oldAvailable)
+ Q_EMIT metaDataAvailableChanged(m_available);
+
+ Q_EMIT metaDataChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.h b/src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.h
new file mode 100644
index 000000000..7ea736ffd
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMETADATAREADERCONTROL_H
+#define QANDROIDMETADATAREADERCONTROL_H
+
+#include <QMetaDataReaderControl>
+#include <qmediacontent.h>
+
+QT_BEGIN_NAMESPACE
+
+class JMediaMetadataRetriever;
+
+class QAndroidMetaDataReaderControl : public QMetaDataReaderControl
+{
+ Q_OBJECT
+public:
+ explicit QAndroidMetaDataReaderControl(QObject *parent = 0);
+ ~QAndroidMetaDataReaderControl() Q_DECL_OVERRIDE;
+
+ bool isMetaDataAvailable() const Q_DECL_OVERRIDE;
+
+ QVariant metaData(const QString &key) const Q_DECL_OVERRIDE;
+ QStringList availableMetaData() const Q_DECL_OVERRIDE;
+
+public Q_SLOTS:
+ void onMediaChanged(const QMediaContent &media);
+ void onUpdateMetaData();
+
+private:
+ void updateData();
+
+ QMediaContent m_mediaContent;
+ bool m_available;
+ QVariantMap m_metadata;
+
+ JMediaMetadataRetriever *m_retriever;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMETADATAREADERCONTROL_H
diff --git a/src/plugins/android/mediaplayer/qandroidvideooutput.h b/src/plugins/android/mediaplayer/qandroidvideooutput.h
new file mode 100644
index 000000000..99db7c3e7
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidvideooutput.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDVIDEOOUTPUT_H
+#define QANDROIDVIDEOOUTPUT_H
+
+#include <qglobal.h>
+#include <qsize.h>
+#include <jni.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidVideoOutput
+{
+public:
+ QAndroidVideoOutput() { }
+ virtual ~QAndroidVideoOutput() { }
+
+ virtual jobject surfaceHolder() = 0;
+ virtual void setVideoSize(const QSize &size) = 0;
+ virtual void stop() = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDVIDEOOUTPUT_H
diff --git a/src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp b/src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp
new file mode 100644
index 000000000..7b810fa41
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp
@@ -0,0 +1,375 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidvideorendercontrol.h"
+
+#include <QtPlatformSupport/private/qjnihelpers_p.h>
+#include "jsurfacetextureholder.h"
+#include <QAbstractVideoSurface>
+#include <QOpenGLContext>
+#include <QOffscreenSurface>
+#include <QOpenGLFramebufferObject>
+#include <QVideoSurfaceFormat>
+#include <QOpenGLFunctions>
+#include <QOpenGLShaderProgram>
+
+QT_BEGIN_NAMESPACE
+
+static const GLfloat g_vertex_data[] = {
+ -1.f, 1.f,
+ 1.f, 1.f,
+ 1.f, -1.f,
+ -1.f, -1.f
+};
+
+static const GLfloat g_texture_data[] = {
+ 0.f, 0.f,
+ 1.f, 0.f,
+ 1.f, 1.f,
+ 0.f, 1.f
+};
+
+class TextureVideoBuffer : public QAbstractVideoBuffer
+{
+public:
+ TextureVideoBuffer(GLuint textureId)
+ : QAbstractVideoBuffer(GLTextureHandle)
+ , m_textureId(textureId)
+ {}
+
+ virtual ~TextureVideoBuffer() {}
+
+ MapMode mapMode() const { return NotMapped; }
+ uchar *map(MapMode, int*, int*) { return 0; }
+ void unmap() {}
+
+ QVariant handle() const
+ {
+ return QVariant::fromValue<unsigned int>(m_textureId);
+ }
+
+private:
+ GLuint m_textureId;
+};
+
+class ImageVideoBuffer : public QAbstractVideoBuffer
+{
+public:
+ ImageVideoBuffer(const QImage &image)
+ : QAbstractVideoBuffer(NoHandle)
+ , m_image(image)
+ , m_mode(NotMapped)
+ {
+
+ }
+
+ MapMode mapMode() const { return m_mode; }
+ uchar *map(MapMode mode, int *, int *)
+ {
+ if (mode != NotMapped && m_mode == NotMapped) {
+ m_mode = mode;
+ return m_image.bits();
+ }
+
+ return 0;
+ }
+
+ void unmap()
+ {
+ m_mode = NotMapped;
+ }
+
+private:
+ QImage m_image;
+ MapMode m_mode;
+};
+
+QAndroidVideoRendererControl::QAndroidVideoRendererControl(QObject *parent)
+ : QVideoRendererControl(parent)
+ , m_surface(0)
+ , m_offscreenSurface(0)
+ , m_glContext(0)
+ , m_fbo(0)
+ , m_program(0)
+ , m_useImage(false)
+ , m_androidSurface(0)
+ , m_surfaceTexture(0)
+ , m_surfaceHolder(0)
+ , m_externalTex(0)
+{
+}
+
+QAndroidVideoRendererControl::~QAndroidVideoRendererControl()
+{
+ if (m_glContext)
+ m_glContext->makeCurrent(m_offscreenSurface);
+
+ if (m_surfaceTexture) {
+ QJNILocalRef<jobject> surfaceTex = m_surfaceTexture->surfaceTexture();
+ QJNIObject obj(surfaceTex.object());
+ obj.callMethod<void>("release");
+ delete m_surfaceTexture;
+ m_surfaceTexture = 0;
+ }
+ if (m_androidSurface) {
+ m_androidSurface->callMethod<void>("release");
+ delete m_androidSurface;
+ m_androidSurface = 0;
+ }
+ if (m_surfaceHolder) {
+ delete m_surfaceHolder;
+ m_surfaceHolder = 0;
+ }
+ if (m_externalTex)
+ glDeleteTextures(1, &m_externalTex);
+
+ delete m_fbo;
+ delete m_program;
+ delete m_glContext;
+ delete m_offscreenSurface;
+}
+
+QAbstractVideoSurface *QAndroidVideoRendererControl::surface() const
+{
+ return m_surface;
+}
+
+void QAndroidVideoRendererControl::setSurface(QAbstractVideoSurface *surface)
+{
+ if (surface == m_surface)
+ return;
+
+ if (m_surface && m_surface->isActive())
+ m_surface->stop();
+
+ m_surface = surface;
+
+ m_useImage = !m_surface->supportedPixelFormats(QAbstractVideoBuffer::GLTextureHandle).contains(QVideoFrame::Format_BGR32);
+}
+
+jobject QAndroidVideoRendererControl::surfaceHolder()
+{
+ if (m_surfaceHolder)
+ return m_surfaceHolder->object();
+
+ QOpenGLContext *currContext = QOpenGLContext::currentContext();
+
+ // If we don't have a GL context in the current thread, create one and share it
+ // with the render thread GL context
+ if (!currContext && !m_glContext) {
+ m_offscreenSurface = new QOffscreenSurface;
+ QSurfaceFormat format;
+ format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
+ m_offscreenSurface->setFormat(format);
+ m_offscreenSurface->create();
+
+ QOpenGLContext *shareContext = 0;
+ if (m_surface)
+ shareContext = qobject_cast<QOpenGLContext*>(m_surface->property("GLContext").value<QObject*>());
+ m_glContext = new QOpenGLContext;
+ m_glContext->setFormat(m_offscreenSurface->requestedFormat());
+
+ if (shareContext)
+ m_glContext->setShareContext(shareContext);
+
+ if (!m_glContext->create())
+ return 0;
+
+ // if sharing contexts is not supported, fallback to image rendering and send the bits
+ // to the video surface
+ if (!m_glContext->shareContext())
+ m_useImage = true;
+ }
+
+ if (m_glContext)
+ m_glContext->makeCurrent(m_offscreenSurface);
+
+ glGenTextures(1, &m_externalTex);
+ m_surfaceTexture = new JSurfaceTexture(m_externalTex);
+
+ if (m_surfaceTexture->isValid()) {
+ connect(m_surfaceTexture, SIGNAL(frameAvailable()), this, SLOT(onFrameAvailable()));
+
+ QJNILocalRef<jobject> surfaceTex = m_surfaceTexture->surfaceTexture();
+
+ m_androidSurface = new QJNIObject("android/view/Surface",
+ "(Landroid/graphics/SurfaceTexture;)V",
+ surfaceTex.object());
+
+ m_surfaceHolder = new JSurfaceTextureHolder(m_androidSurface->object());
+ } else {
+ delete m_surfaceTexture;
+ m_surfaceTexture = 0;
+ glDeleteTextures(1, &m_externalTex);
+ }
+
+ if (m_surfaceHolder)
+ return m_surfaceHolder->object();
+
+ return 0;
+}
+
+void QAndroidVideoRendererControl::setVideoSize(const QSize &size)
+{
+ if (m_nativeSize == size)
+ return;
+
+ m_nativeSize = size;
+
+ delete m_fbo;
+ m_fbo = 0;
+}
+
+void QAndroidVideoRendererControl::stop()
+{
+ if (m_surface && m_surface->isActive())
+ m_surface->stop();
+ m_nativeSize = QSize();
+}
+
+void QAndroidVideoRendererControl::onFrameAvailable()
+{
+ if (m_glContext)
+ m_glContext->makeCurrent(m_offscreenSurface);
+
+ m_surfaceTexture->updateTexImage();
+
+ if (!m_nativeSize.isValid())
+ return;
+
+ renderFrameToFbo();
+
+ QAbstractVideoBuffer *buffer = 0;
+ QVideoFrame frame;
+
+ if (m_useImage) {
+ buffer = new ImageVideoBuffer(m_fbo->toImage().mirrored());
+ frame = QVideoFrame(buffer, m_nativeSize, QVideoFrame::Format_RGB32);
+ } else {
+ buffer = new TextureVideoBuffer(m_fbo->texture());
+ frame = QVideoFrame(buffer, m_nativeSize, QVideoFrame::Format_BGR32);
+ }
+
+ if (m_surface && frame.isValid()) {
+ if (m_surface->isActive() && (m_surface->surfaceFormat().pixelFormat() != frame.pixelFormat()
+ || m_surface->nativeResolution() != frame.size())) {
+ m_surface->stop();
+ }
+
+ if (!m_surface->isActive()) {
+ QVideoSurfaceFormat format(frame.size(), frame.pixelFormat(),
+ m_useImage ? QAbstractVideoBuffer::NoHandle
+ : QAbstractVideoBuffer::GLTextureHandle);
+
+ m_surface->start(format);
+ }
+
+ if (m_surface->isActive())
+ m_surface->present(frame);
+ }
+}
+
+void QAndroidVideoRendererControl::renderFrameToFbo()
+{
+ createGLResources();
+
+ m_fbo->bind();
+
+ glViewport(0, 0, m_nativeSize.width(), m_nativeSize.height());
+
+ m_program->bind();
+ m_program->enableAttributeArray(0);
+ m_program->enableAttributeArray(1);
+ m_program->setUniformValue("frameTexture", GLuint(0));
+ m_program->setUniformValue("texMatrix", m_surfaceTexture->getTransformMatrix());
+
+ glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, g_vertex_data);
+ glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, g_texture_data);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ m_program->disableAttributeArray(0);
+ m_program->disableAttributeArray(1);
+ m_program->release();
+
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
+ m_fbo->release();
+
+ glFinish();
+}
+
+void QAndroidVideoRendererControl::createGLResources()
+{
+ if (!m_fbo)
+ m_fbo = new QOpenGLFramebufferObject(m_nativeSize);
+
+ if (!m_program) {
+ m_program = new QOpenGLShaderProgram;
+
+ QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_program);
+ vertexShader->compileSourceCode("attribute highp vec4 vertexCoordsArray; \n" \
+ "attribute highp vec2 textureCoordArray; \n" \
+ "uniform highp mat4 texMatrix; \n" \
+ "varying highp vec2 textureCoords; \n" \
+ "void main(void) \n" \
+ "{ \n" \
+ " gl_Position = vertexCoordsArray; \n" \
+ " textureCoords = (texMatrix * vec4(textureCoordArray, 0.0, 1.0)).xy; \n" \
+ "}\n");
+ m_program->addShader(vertexShader);
+
+ QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_program);
+ fragmentShader->compileSourceCode("#extension GL_OES_EGL_image_external : require \n" \
+ "varying highp vec2 textureCoords; \n" \
+ "uniform samplerExternalOES frameTexture; \n" \
+ "void main() \n" \
+ "{ \n" \
+ " gl_FragColor = texture2D(frameTexture, textureCoords); \n" \
+ "}\n");
+ m_program->addShader(fragmentShader);
+
+ m_program->bindAttributeLocation("vertexCoordsArray", 0);
+ m_program->bindAttributeLocation("textureCoordArray", 1);
+ m_program->link();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/mediaplayer/qandroidvideorendercontrol.h b/src/plugins/android/mediaplayer/qandroidvideorendercontrol.h
new file mode 100644
index 000000000..525291e1f
--- /dev/null
+++ b/src/plugins/android/mediaplayer/qandroidvideorendercontrol.h
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDVIDEORENDERCONTROL_H
+#define QANDROIDVIDEORENDERCONTROL_H
+
+#include <qvideorenderercontrol.h>
+#include "qandroidvideooutput.h"
+#include "jsurfacetexture.h"
+
+QT_BEGIN_NAMESPACE
+
+class QOpenGLContext;
+class QOffscreenSurface;
+class QOpenGLFramebufferObject;
+class QOpenGLShaderProgram;
+class JSurfaceTextureHolder;
+
+class QAndroidVideoRendererControl : public QVideoRendererControl, public QAndroidVideoOutput
+{
+ Q_OBJECT
+public:
+ explicit QAndroidVideoRendererControl(QObject *parent = 0);
+ ~QAndroidVideoRendererControl() Q_DECL_OVERRIDE;
+
+ QAbstractVideoSurface *surface() const Q_DECL_OVERRIDE;
+ void setSurface(QAbstractVideoSurface *surface) Q_DECL_OVERRIDE;
+
+ jobject surfaceHolder() Q_DECL_OVERRIDE;
+ void setVideoSize(const QSize &size) Q_DECL_OVERRIDE;
+ void stop() Q_DECL_OVERRIDE;
+
+private Q_SLOTS:
+ void onFrameAvailable();
+
+private:
+ void setupSurface();
+ void renderFrameToFbo();
+ void createGLResources();
+
+ QAbstractVideoSurface *m_surface;
+ QOffscreenSurface *m_offscreenSurface;
+ QOpenGLContext *m_glContext;
+ QOpenGLFramebufferObject *m_fbo;
+ QOpenGLShaderProgram *m_program;
+ bool m_useImage;
+ QSize m_nativeSize;
+
+ QJNIObject *m_androidSurface;
+ JSurfaceTexture *m_surfaceTexture;
+ JSurfaceTextureHolder *m_surfaceHolder;
+ uint m_externalTex;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDVIDEORENDERCONTROL_H
diff --git a/src/plugins/android/wrappers/jmediametadataretriever.cpp b/src/plugins/android/wrappers/jmediametadataretriever.cpp
new file mode 100644
index 000000000..ae5abcf43
--- /dev/null
+++ b/src/plugins/android/wrappers/jmediametadataretriever.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jmediametadataretriever.h"
+
+#include <QtPlatformSupport/private/qjnihelpers_p.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <qguiapplication.h>
+
+QT_BEGIN_NAMESPACE
+
+static jobject g_activity = 0;
+
+JMediaMetadataRetriever::JMediaMetadataRetriever()
+ : QJNIObject("android/media/MediaMetadataRetriever")
+{
+ if (!g_activity) {
+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
+ g_activity = static_cast<jobject>(nativeInterface->nativeResourceForIntegration("QtActivity"));
+ }
+}
+
+JMediaMetadataRetriever::~JMediaMetadataRetriever()
+{
+}
+
+QString JMediaMetadataRetriever::extractMetadata(MetadataKey key)
+{
+ QString value;
+
+ QJNILocalRef<jstring> metadata = callObjectMethod<jstring>("extractMetadata",
+ "(I)Ljava/lang/String;",
+ jint(key));
+ if (!metadata.isNull())
+ value = qt_convertJString(metadata.object());
+
+ return value;
+}
+
+void JMediaMetadataRetriever::release()
+{
+ callMethod<void>("release");
+}
+
+bool JMediaMetadataRetriever::setDataSource(const QUrl &url)
+{
+ QAttachedJNIEnv env;
+
+ bool loaded = false;
+
+ QJNILocalRef<jstring> string = qt_toJString(url.toString());
+
+ QJNILocalRef<jobject> uri = callStaticObjectMethod<jobject>("android/net/Uri",
+ "parse",
+ "(Ljava/lang/String;)Landroid/net/Uri;",
+ string.object());
+ if (env->ExceptionCheck()) {
+ env->ExceptionClear();
+ } else {
+ callMethod<void>("setDataSource",
+ "(Landroid/content/Context;Landroid/net/Uri;)V",
+ g_activity,
+ uri.object());
+ if (env->ExceptionCheck())
+ env->ExceptionClear();
+ else
+ loaded = true;
+ }
+
+ return loaded;
+}
+
+bool JMediaMetadataRetriever::setDataSource(const QString &path)
+{
+ QAttachedJNIEnv env;
+
+ bool loaded = false;
+
+ callMethod<void>("setDataSource", "(Ljava/lang/String;)V", qt_toJString(path).object());
+ if (env->ExceptionCheck())
+ env->ExceptionClear();
+ else
+ loaded = true;
+
+ return loaded;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/wrappers/jmediametadataretriever.h b/src/plugins/android/wrappers/jmediametadataretriever.h
new file mode 100644
index 000000000..dd63e0d87
--- /dev/null
+++ b/src/plugins/android/wrappers/jmediametadataretriever.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JMEDIAMETADATARETRIEVER_H
+#define JMEDIAMETADATARETRIEVER_H
+
+#include <QtPlatformSupport/private/qjniobject_p.h>
+#include <qurl.h>
+
+QT_BEGIN_NAMESPACE
+
+class JMediaMetadataRetriever : public QJNIObject
+{
+public:
+ enum MetadataKey {
+ Album = 1,
+ AlbumArtist = 13,
+ Artist = 2,
+ Author = 3,
+ Bitrate = 20,
+ CDTrackNumber = 0,
+ Compilation = 15,
+ Composer = 4,
+ Date = 5,
+ DiscNumber = 14,
+ Duration = 9,
+ Genre = 6,
+ HasAudio = 16,
+ HasVideo = 17,
+ Location = 23,
+ MimeType = 12,
+ NumTracks = 10,
+ Title = 7,
+ VideoHeight = 19,
+ VideoWidth = 18,
+ VideoRotation = 24,
+ Writer = 11,
+ Year = 8
+ };
+
+ JMediaMetadataRetriever();
+ ~JMediaMetadataRetriever();
+
+ QString extractMetadata(MetadataKey key);
+ void release();
+ bool setDataSource(const QUrl &url);
+ bool setDataSource(const QString &path);
+
+};
+
+QT_END_NAMESPACE
+
+#endif // JMEDIAMETADATARETRIEVER_H
diff --git a/src/plugins/android/wrappers/jmediaplayer.cpp b/src/plugins/android/wrappers/jmediaplayer.cpp
new file mode 100644
index 000000000..48e743b26
--- /dev/null
+++ b/src/plugins/android/wrappers/jmediaplayer.cpp
@@ -0,0 +1,265 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jmediaplayer.h"
+
+#include <QString>
+#include <qpa/qplatformnativeinterface.h>
+#include <qguiapplication.h>
+#include <QtPlatformSupport/private/qjnihelpers_p.h>
+
+namespace {
+
+jclass mediaPlayerClass = 0;
+
+QMap<jlong, JMediaPlayer *> mplayers;
+
+}
+
+QT_BEGIN_NAMESPACE
+
+bool JMediaPlayer::mActivitySet = false;
+
+JMediaPlayer::JMediaPlayer()
+ : QObject()
+ , QJNIObject(mediaPlayerClass, "(J)V", reinterpret_cast<jlong>(this))
+ , mId(reinterpret_cast<jlong>(this))
+ , mDisplay(0)
+{
+ mplayers.insert(mId, this);
+
+ if (!mActivitySet) {
+ QPlatformNativeInterface *nativeInterface = QGuiApplication::platformNativeInterface();
+ jobject activity = static_cast<jobject>(nativeInterface->nativeResourceForIntegration("QtActivity"));
+ QJNIObject::callStaticMethod<void>(mediaPlayerClass,
+ "setActivity",
+ "(Landroid/app/Activity;)V",
+ activity);
+ mActivitySet = true;
+ }
+}
+
+JMediaPlayer::~JMediaPlayer()
+{
+ mplayers.remove(mId);
+}
+
+void JMediaPlayer::onError(qint32 what, qint32 extra)
+{
+ Q_EMIT error(what, extra);
+}
+
+void JMediaPlayer::onBufferingUpdate(qint32 percent)
+{
+ Q_EMIT bufferingUpdate(percent);
+}
+
+void JMediaPlayer::onInfo(qint32 what, qint32 extra)
+{
+ Q_EMIT info(what, extra);
+}
+
+void JMediaPlayer::onMediaPlayerInfo(qint32 what, qint32 extra)
+{
+ Q_EMIT mediaPlayerInfo(what, extra);
+}
+
+void JMediaPlayer::onVideoSizeChanged(qint32 width, qint32 height)
+{
+ Q_EMIT videoSizeChanged(width, height);
+}
+
+int JMediaPlayer::getCurrentPosition()
+{
+ return callMethod<jint>("getCurrentPosition");
+}
+
+int JMediaPlayer::getDuration()
+{
+ return callMethod<jint>("getDuration");
+}
+
+bool JMediaPlayer::isPlaying()
+{
+ return callMethod<jboolean>("isPlaying");
+}
+
+int JMediaPlayer::volume()
+{
+ return callMethod<jint>("getVolume");
+}
+
+bool JMediaPlayer::isMuted()
+{
+ return callMethod<jboolean>("isMuted");
+}
+
+void JMediaPlayer::play()
+{
+ callMethod<void>("start");
+}
+
+void JMediaPlayer::pause()
+{
+ callMethod<void>("pause");
+}
+
+void JMediaPlayer::stop()
+{
+ callMethod<void>("stop");
+}
+
+void JMediaPlayer::seekTo(qint32 msec)
+{
+ callMethod<void>("seekTo", "(I)V", jint(msec));
+}
+
+void JMediaPlayer::setMuted(bool mute)
+{
+ callMethod<void>("mute", "(Z)V", jboolean(mute));
+}
+
+void JMediaPlayer::setDataSource(const QString &path)
+{
+ QJNILocalRef<jstring> string = qt_toJString(path);
+ callMethod<void>("setMediaPath", "(Ljava/lang/String;)V", string.object());
+}
+
+void JMediaPlayer::setVolume(int volume)
+{
+ callMethod<void>("setVolume", "(I)V", jint(volume));
+}
+
+void JMediaPlayer::setDisplay(jobject surfaceHolder)
+{
+ mDisplay = surfaceHolder;
+ callMethod<void>("setDisplay", "(Landroid/view/SurfaceHolder;)V", mDisplay);
+}
+
+QT_END_NAMESPACE
+
+static void onErrorNative(JNIEnv *env, jobject thiz, jint what, jint extra, jlong id)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(thiz);
+ JMediaPlayer *const mp = mplayers[id];
+ if (!mp)
+ return;
+
+ mp->onError(what, extra);
+}
+
+static void onBufferingUpdateNative(JNIEnv *env, jobject thiz, jint percent, jlong id)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(thiz);
+ JMediaPlayer *const mp = mplayers[id];
+ if (!mp)
+ return;
+
+ mp->onBufferingUpdate(percent);
+}
+
+static void onInfoNative(JNIEnv *env, jobject thiz, jint what, jint extra, jlong id)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(thiz);
+ JMediaPlayer *const mp = mplayers[id];
+ if (!mp)
+ return;
+
+ mp->onInfo(what, extra);
+}
+
+static void onMediaPlayerInfoNative(JNIEnv *env, jobject thiz, jint what, jint extra, jlong id)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(thiz);
+ JMediaPlayer *const mp = mplayers[id];
+ if (!mp)
+ return;
+
+ mp->onMediaPlayerInfo(what, extra);
+}
+
+static void onVideoSizeChangedNative(JNIEnv *env,
+ jobject thiz,
+ jint width,
+ jint height,
+ jlong id)
+{
+ Q_UNUSED(env);
+ Q_UNUSED(thiz);
+ JMediaPlayer *const mp = mplayers[id];
+ if (!mp)
+ return;
+
+ mp->onVideoSizeChanged(width, height);
+}
+
+QT_BEGIN_NAMESPACE
+
+bool JMediaPlayer::initJNI(JNIEnv *env)
+{
+ jclass jClass = env->FindClass("org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer");
+
+ if (jClass) {
+ mediaPlayerClass = static_cast<jclass>(env->NewGlobalRef(jClass));
+
+ JNINativeMethod methods[] = {
+ {"onErrorNative", "(IIJ)V", reinterpret_cast<void *>(onErrorNative)},
+ {"onBufferingUpdateNative", "(IJ)V", reinterpret_cast<void *>(onBufferingUpdateNative)},
+ {"onInfoNative", "(IIJ)V", reinterpret_cast<void *>(onInfoNative)},
+ {"onMediaPlayerInfoNative", "(IIJ)V", reinterpret_cast<void *>(onMediaPlayerInfoNative)},
+ {"onVideoSizeChangedNative", "(IIJ)V", reinterpret_cast<void *>(onVideoSizeChangedNative)}
+ };
+
+ if (env->RegisterNatives(mediaPlayerClass,
+ methods,
+ sizeof(methods) / sizeof(methods[0])) < 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/wrappers/jmediaplayer.h b/src/plugins/android/wrappers/jmediaplayer.h
new file mode 100644
index 000000000..f5cb11773
--- /dev/null
+++ b/src/plugins/android/wrappers/jmediaplayer.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDMEDIAPLAYER_H
+#define QANDROIDMEDIAPLAYER_H
+
+#include <QObject>
+#include <QtPlatformSupport/private/qjniobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class JMediaPlayer : public QObject, public QJNIObject
+{
+ Q_OBJECT
+public:
+ JMediaPlayer();
+ ~JMediaPlayer();
+
+ enum MediaError
+ {
+ // What
+ MEDIA_ERROR_UNKNOWN = 1,
+ MEDIA_ERROR_SERVER_DIED = 100,
+ // Extra
+ MEDIA_ERROR_IO = -1004,
+ MEDIA_ERROR_MALFORMED = -1007,
+ MEDIA_ERROR_UNSUPPORTED = -1010,
+ MEDIA_ERROR_TIMED_OUT = -110,
+ MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200
+ };
+
+ enum MediaInfo
+ {
+ MEDIA_INFO_UNKNOWN = 1,
+ MEDIA_INFO_VIDEO_TRACK_LAGGING = 700,
+ MEDIA_INFO_VIDEO_RENDERING_START = 3,
+ MEDIA_INFO_BUFFERING_START = 701,
+ MEDIA_INFO_BUFFERING_END = 702,
+ MEDIA_INFO_BAD_INTERLEAVING = 800,
+ MEDIA_INFO_NOT_SEEKABLE = 801,
+ MEDIA_INFO_METADATA_UPDATE = 802
+ };
+
+ enum MediaPlayerInfo
+ {
+ MEDIA_PLAYER_INVALID_STATE = 1,
+ MEDIA_PLAYER_PREPARING = 2,
+ MEDIA_PLAYER_READY = 3,
+ MEDIA_PLAYER_DURATION = 4,
+ MEDIA_PLAYER_PROGRESS = 5,
+ MEDIA_PLAYER_FINISHED = 6
+ };
+
+ int getCurrentPosition();
+ int getDuration();
+ bool isPlaying();
+ int volume();
+ bool isMuted();
+ jobject display() { return mDisplay; }
+
+ void play();
+ void pause();
+ void stop();
+ void seekTo(qint32 msec);
+ void setMuted(bool mute);
+ void setDataSource(const QString &path);
+ void setVolume(int volume);
+ void setDisplay(jobject surfaceHolder);
+
+ void onError(qint32 what, qint32 extra);
+ void onBufferingUpdate(qint32 percent);
+ void onInfo(qint32 what, qint32 extra);
+ void onMediaPlayerInfo(qint32 what, qint32 extra);
+ void onVideoSizeChanged(qint32 width, qint32 height);
+
+ static bool initJNI(JNIEnv *env);
+
+Q_SIGNALS:
+ void error(qint32 what, qint32 extra);
+ void bufferingUpdate(qint32 percent);
+ void completion();
+ void info(qint32 what, qint32 extra);
+ void mediaPlayerInfo(qint32 what, qint32 extra);
+ void videoSizeChanged(qint32 width, qint32 height);
+
+private:
+ jlong mId;
+ jobject mDisplay;
+
+ static bool mActivitySet;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDMEDIAPLAYER_H
diff --git a/src/plugins/android/wrappers/jsurfacetexture.cpp b/src/plugins/android/wrappers/jsurfacetexture.cpp
new file mode 100644
index 000000000..107f7be39
--- /dev/null
+++ b/src/plugins/android/wrappers/jsurfacetexture.cpp
@@ -0,0 +1,118 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsurfacetexture.h"
+#include <QtPlatformSupport/private/qjnihelpers_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static jclass g_qtSurfaceTextureClass = 0;
+static QHash<int, JSurfaceTexture*> g_objectMap;
+
+// native method for QtSurfaceTexture.java
+static void notifyFrameAvailable(JNIEnv* , jobject, int id)
+{
+ JSurfaceTexture *obj = g_objectMap.value(id, 0);
+ if (obj)
+ Q_EMIT obj->frameAvailable();
+}
+
+JSurfaceTexture::JSurfaceTexture(unsigned int texName)
+ : QObject()
+ , QJNIObject(g_qtSurfaceTextureClass, "(I)V", jint(texName))
+ , m_texID(int(texName))
+{
+ if (m_jobject)
+ g_objectMap.insert(int(texName), this);
+}
+
+JSurfaceTexture::~JSurfaceTexture()
+{
+ if (m_jobject)
+ g_objectMap.remove(m_texID);
+}
+
+QMatrix4x4 JSurfaceTexture::getTransformMatrix()
+{
+ QAttachedJNIEnv env;
+
+ QMatrix4x4 matrix;
+ jfloatArray array = env->NewFloatArray(16);
+ callMethod<void>("getTransformMatrix", "([F)V", array);
+ env->GetFloatArrayRegion(array, 0, 16, matrix.data());
+ env->DeleteLocalRef(array);
+
+ return matrix;
+}
+
+void JSurfaceTexture::updateTexImage()
+{
+ callMethod<void>("updateTexImage");
+}
+
+QJNILocalRef<jobject> JSurfaceTexture::surfaceTexture()
+{
+ return getObjectField<jobject>("surfaceTexture", "Landroid/graphics/SurfaceTexture;");
+}
+
+static JNINativeMethod methods[] = {
+ {"notifyFrameAvailable", "(I)V", (void *)notifyFrameAvailable}
+};
+
+bool JSurfaceTexture::initJNI(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("org/qtproject/qt5/android/multimedia/QtSurfaceTexture");
+ if (env->ExceptionCheck())
+ env->ExceptionClear();
+
+ if (clazz) {
+ g_qtSurfaceTextureClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ if (env->RegisterNatives(g_qtSurfaceTextureClass,
+ methods,
+ sizeof(methods) / sizeof(methods[0])) < 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/wrappers/jsurfacetexture.h b/src/plugins/android/wrappers/jsurfacetexture.h
new file mode 100644
index 000000000..49e007666
--- /dev/null
+++ b/src/plugins/android/wrappers/jsurfacetexture.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSURFACETEXTURE_H
+#define JSURFACETEXTURE_H
+
+#include <qobject.h>
+#include <QtPlatformSupport/private/qjniobject_p.h>
+
+#include <QMatrix4x4>
+
+QT_BEGIN_NAMESPACE
+
+class JSurfaceTexture : public QObject, public QJNIObject
+{
+ Q_OBJECT
+public:
+ explicit JSurfaceTexture(unsigned int texName);
+ ~JSurfaceTexture();
+
+ QMatrix4x4 getTransformMatrix();
+ void updateTexImage();
+
+ QJNILocalRef<jobject> surfaceTexture();
+
+ static bool initJNI(JNIEnv *env);
+
+Q_SIGNALS:
+ void frameAvailable();
+
+private:
+ int m_texID;
+};
+
+QT_END_NAMESPACE
+
+#endif // JSURFACETEXTURE_H
diff --git a/src/plugins/android/wrappers/jsurfacetextureholder.cpp b/src/plugins/android/wrappers/jsurfacetextureholder.cpp
new file mode 100644
index 000000000..4ec8935c2
--- /dev/null
+++ b/src/plugins/android/wrappers/jsurfacetextureholder.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "jsurfacetextureholder.h"
+
+QT_BEGIN_NAMESPACE
+
+static jclass g_qtSurfaceTextureHolderClass = 0;
+
+JSurfaceTextureHolder::JSurfaceTextureHolder(jobject surface)
+ : QJNIObject(g_qtSurfaceTextureHolderClass, "(Landroid/view/Surface;)V", surface)
+{
+}
+
+bool JSurfaceTextureHolder::initJNI(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder");
+ if (env->ExceptionCheck())
+ env->ExceptionClear();
+
+ if (clazz)
+ g_qtSurfaceTextureHolderClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ return true;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/android/wrappers/jsurfacetextureholder.h b/src/plugins/android/wrappers/jsurfacetextureholder.h
new file mode 100644
index 000000000..5b567de3a
--- /dev/null
+++ b/src/plugins/android/wrappers/jsurfacetextureholder.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/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 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef JSURFACETEXTUREHOLDER_H
+#define JSURFACETEXTUREHOLDER_H
+
+#include <QtPlatformSupport/private/qjniobject_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class JSurfaceTextureHolder : public QJNIObject
+{
+public:
+ JSurfaceTextureHolder(jobject surface);
+
+ static bool initJNI(JNIEnv *env);
+};
+
+QT_END_NAMESPACE
+
+#endif // JSURFACETEXTUREHOLDER_H
diff --git a/src/plugins/android/wrappers/wrappers.pri b/src/plugins/android/wrappers/wrappers.pri
new file mode 100644
index 000000000..5b47ef531
--- /dev/null
+++ b/src/plugins/android/wrappers/wrappers.pri
@@ -0,0 +1,15 @@
+QT += platformsupport-private
+
+INCLUDEPATH += $$PWD
+
+HEADERS += \
+ $$PWD/jmediaplayer.h \
+ $$PWD/jsurfacetexture.h \
+ $$PWD/jsurfacetextureholder.h \
+ $$PWD/jmediametadataretriever.h
+
+SOURCES += \
+ $$PWD/jmediaplayer.cpp \
+ $$PWD/jsurfacetexture.cpp \
+ $$PWD/jsurfacetextureholder.cpp \
+ $$PWD/jmediametadataretriever.cpp
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index c8826a814..998713f2c 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -8,6 +8,10 @@ TEMPLATE = subdirs
SUBDIRS += m3u
+android {
+ SUBDIRS += android
+}
+
blackberry {
SUBDIRS += blackberry
}