Android multimedia plug-in.
authorChristian Strømme <christian.stromme@digia.com>
Mon, 14 Jan 2013 13:23:38 +0000 (14:23 +0100)
committerThe Qt Project <gerrit-noreply@qt-project.org>
Tue, 5 Mar 2013 23:23:50 +0000 (00:23 +0100)
Adds MediaPlayer support for Android.

Change-Id: I4c7b1e19927b2e50b227f3a3b3f7ca2e99397618
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
30 files changed:
src/multimedia/multimedia.pro
src/plugins/android/android.pro [new file with mode: 0644]
src/plugins/android/jar/AndroidManifest.xml [new file with mode: 0644]
src/plugins/android/jar/jar.pro [new file with mode: 0644]
src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtAndroidMediaPlayer.java [new file with mode: 0644]
src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTexture.java [new file with mode: 0644]
src/plugins/android/jar/src/org/qtproject/qt5/android/multimedia/QtSurfaceTextureHolder.java [new file with mode: 0644]
src/plugins/android/mediaplayer/mediaplayer.json [new file with mode: 0644]
src/plugins/android/mediaplayer/mediaplayer.pro [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidmediaplayercontrol.cpp [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidmediaplayercontrol.h [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidmediaservice.cpp [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidmediaservice.h [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidmediaserviceplugin.cpp [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidmediaserviceplugin.h [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.cpp [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidmetadatareadercontrol.h [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidvideooutput.h [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidvideorendercontrol.cpp [new file with mode: 0644]
src/plugins/android/mediaplayer/qandroidvideorendercontrol.h [new file with mode: 0644]
src/plugins/android/wrappers/jmediametadataretriever.cpp [new file with mode: 0644]
src/plugins/android/wrappers/jmediametadataretriever.h [new file with mode: 0644]
src/plugins/android/wrappers/jmediaplayer.cpp [new file with mode: 0644]
src/plugins/android/wrappers/jmediaplayer.h [new file with mode: 0644]
src/plugins/android/wrappers/jsurfacetexture.cpp [new file with mode: 0644]
src/plugins/android/wrappers/jsurfacetexture.h [new file with mode: 0644]
src/plugins/android/wrappers/jsurfacetextureholder.cpp [new file with mode: 0644]
src/plugins/android/wrappers/jsurfacetextureholder.h [new file with mode: 0644]
src/plugins/android/wrappers/wrappers.pri [new file with mode: 0644]
src/plugins/plugins.pro

index 9dbea39..2a1c6af 100644 (file)
@@ -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 (file)
index 0000000..2cfc83f
--- /dev/null
@@ -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 (file)
index 0000000..7eae185
--- /dev/null
@@ -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 (file)
index 0000000..b256412
--- /dev/null
@@ -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 (file)
index 0000000..b2115b7
--- /dev/null
@@ -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 (file)
index 0000000..b8837d5
--- /dev/null
@@ -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 (file)
index 0000000..15c5f23
--- /dev/null
@@ -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 (file)
index 0000000..c4a27ea
--- /dev/null
@@ -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 (file)
index 0000000..cabe4c6
--- /dev/null
@@ -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 (file)
index 0000000..5a9c8b8
--- /dev/null
@@ -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 (file)
index 0000000..445e8de
--- /dev/null
@@ -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 (file)
index 0000000..1759586
--- /dev/null
@@ -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 (file)
index 0000000..4d310e8
--- /dev/null
@@ -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 (file)
index 0000000..3bf7034
--- /dev/null
@@ -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 (file)
index 0000000..d004635
--- /dev/null
@@ -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 (file)
index 0000000..9b2f4e1
--- /dev/null
@@ -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 (file)
index 0000000..7ea736f
--- /dev/null
@@ -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 (file)
index 0000000..99db7c3
--- /dev/null
@@ -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 (file)
index 0000000..7b810fa
--- /dev/null
@@ -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 (file)
index 0000000..525291e
--- /dev/null
@@ -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 (file)
index 0000000..ae5abcf
--- /dev/null
@@ -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 (file)
index 0000000..dd63e0d
--- /dev/null
@@ -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 (file)
index 0000000..48e743b
--- /dev/null
@@ -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 (file)
index 0000000..f5cb117
--- /dev/null
@@ -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 (file)
index 0000000..107f7be
--- /dev/null
@@ -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 (file)
index 0000000..49e0076
--- /dev/null
@@ -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 (file)
index 0000000..4ec8935
--- /dev/null
@@ -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 (file)
index 0000000..5b567de
--- /dev/null
@@ -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 (file)
index 0000000..5b47ef5
--- /dev/null
@@ -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
index c8826a8..998713f 100644 (file)
@@ -8,6 +8,10 @@ TEMPLATE = subdirs
 
 SUBDIRS += m3u
 
+android {
+   SUBDIRS += android
+}
+
 blackberry {
     SUBDIRS += blackberry
 }