playback/player: android: Use gradle & ndk-build combo to generate the Android App

Also add a video List selector.
This commit is contained in:
Sebastian Roth 2015-05-05 16:08:18 +08:00 committed by Sebastian Dröge
parent 59d822fc2b
commit a31f95d06d
28 changed files with 932 additions and 280 deletions

View file

@ -1,79 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.freedesktop.gstreamer.play"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="14"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-feature android:glEsVersion="0x00020000"/>
<application android:label="@string/app_name">
<activity android:name=".Play"
android:label="@string/app_name">
<!-- <intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>-->
<!-- Local files whose MIME type is known to Android -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="audio/*" />
<data android:mimeType="video/*" />
<data android:mimeType="image/*" />
</intent-filter>
<!-- Local files with unknown MIME type.
The list of extensions and supported protocols can certainly be extended. -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.avi" />
<data android:pathPattern=".*\\.AVI" />
<data android:pathPattern=".*\\.mkv" />
<data android:pathPattern=".*\\.MKV" />
<data android:pathPattern=".*\\.webm" />
<data android:pathPattern=".*\\.WEBM" />
<data android:pathPattern=".*\\.ogv" />
<data android:pathPattern=".*\\.OGV" />
<data android:pathPattern=".*\\.mp4" />
<data android:pathPattern=".*\\.MP4" />
<data android:pathPattern=".*\\.mov" />
<data android:pathPattern=".*\\.MOV" />
</intent-filter>
<!-- Remote files. These typically have unknown MIME type.
The list of extensions and supported protocols can certainly be extended. -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:pathPattern=".*\\.avi" />
<data android:pathPattern=".*\\.AVI" />
<data android:pathPattern=".*\\.mkv" />
<data android:pathPattern=".*\\.MKV" />
<data android:pathPattern=".*\\.webm" />
<data android:pathPattern=".*\\.WEBM" />
<data android:pathPattern=".*\\.ogv" />
<data android:pathPattern=".*\\.OGV" />
<data android:pathPattern=".*\\.mp4" />
<data android:pathPattern=".*\\.MP4" />
<data android:pathPattern=".*\\.mov" />
<data android:pathPattern=".*\\.MOV" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -1,10 +1,24 @@
EXTRA_DIST = \
AndroidManifest.xml \
jni/Android.mk \
jni/player.c \
res/layout/main.xml \
res/values/strings.xml \
src/org/freedesktop/gstreamer/Player.java \
src/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java \
src/org/freedesktop/gstreamer/player/Play.java
build.gradle \
gradlew \
gradlew.bat \
README.md \
settings.gradle \
app/build.gradle \
app/src/main/AndroidManifest.xml \
app/src/main/java/org/freedesktop/gstreamer/Player.java \
app/src/main/java/org/freedesktop/gstreamer/player/GStreamerSurfaceView.java \
app/src/main/java/org/freedesktop/gstreamer/player/Play.java \
app/src/main/java/org/freedesktop/gstreamer/player/VideoSelector.java \
app/src/main/jni/Android.mk \
app/src/main/jni/Application.mk \
app/src/main/jni/player.c \
app/src/main/res/layout/activity_player.xml \
app/src/main/res/layout/activity_video_selector.xml \
app/src/main/res/menu/menu_video_selector.xml \
app/src/main/res/values/dimens.xml \
app/src/main/res/values/strings.xml \
app/src/main/res/values/styles.xml \
app/src/main/res/values-w820dp/styles.xml \
gradle/wrapper/gradle-wrapper.jar \
gradle/wrapper/gradle-wrapper.properties

View file

@ -0,0 +1,50 @@
GST Player Android port
=======================
Prerequisites
-------------
1. Install Android SDK from https://developer.android.com/sdk/ & set `sdk.dir` in **local.properties** to the installation path
2. Install Android NDK from https://developer.android.com/tools/sdk/ndk/index.html & set `ndk.dir` in **local.properties** to the installation path
3. If you have a different special directory for pkg-config or other tools (e.g. on OSX when using Homebrew), then also set this path using the `ndk.extraPath` variable in **local.properties**
4. Download the GStreamer android ports http://gstreamer.freedesktop.org/data/pkg/android/ and set `gstreamer.$ABI.dir` properties in **local.properties**:
gstreamer.arm.dir=/path/to/gstreamer-1.0-android-arm-release-1.4.5/
gstreamer.armv7.dir=/path/to/gstreamer-1.0-android-armv7-release-1.4.5/
gstreamer.x86.dir=/path/to/gstreamer-1.0-android-x86-release-1.4.5/
Compiling the sample
--------------------
Use
./gradlew installDebug
to compile and install a debug version onto all connected devices.
Please note this component is using the new Android build system based on Gradle. More information about this is available on http://tools.android.com/tech-docs/new-build-system.
Android Studio
--------------
Android Studio builds will work out of the box. Simply open `build.gradle` in this folder to import the project.
Manual NDK build
----------------
It is still possible to build just the NDK portion. This will speed up the process a bit as you don't need to start gradle first and compile the complete App.
First, make sure to set `NDK_PROJECT_PATH` to this projects main source path. Additionally the SDK & NDK tools are available in `$PATH`.
export NDK_PROJECT_PATH=$PWD/app/src/main
Second, set the following environment variables to the GStreamer installation folders:
export GSTREAMER_ROOT_ARM=/path/to/gstreamer-1.0-android-arm-release-1.4.5/
export GSTREAMER_ROOT_ARMV7=/path/to/tmp/gstreamer-1.0-android-armv7-release-1.4.5/
export GSTREAMER_ROOT_X86=/path/to/gstreamer-1.0-android-x86-release-1.4.5/
If you don't want to build all architectures, please modify the file `app/src/main/jni/Application.mk`
Finally, within the `app/src/main/` directory, invoke:
ndk-build

View file

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="android" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="android-gradle" name="Android-Gradle">
<configuration>
<option name="GRADLE_PROJECT_PATH" value=":app" />
</configuration>
</facet>
<facet type="android" name="Android">
<configuration>
<option name="SELECTED_BUILD_VARIANT" value="debug" />
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
<option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
<option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
<option name="ALLOW_USER_CONFIGURATION" value="false" />
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni/assets" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/jni/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/22.1.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/22.1.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/22.1.1/jars" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
</content>
<orderEntry type="jdk" jdkName="Android API 22 Platform" jdkType="Android SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" exported="" name="appcompat-v7-22.1.1" level="project" />
<orderEntry type="library" exported="" name="recyclerview-v7-22.1.1" level="project" />
<orderEntry type="library" exported="" name="support-v4-22.1.1" level="project" />
<orderEntry type="library" exported="" name="support-annotations-22.1.1" level="project" />
</component>
</module>

View file

@ -0,0 +1,68 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "org.freedesktop.gstreamer.play"
minSdkVersion 9
targetSdkVersion 22
ndk {
moduleName "gstplayer"
}
}
sourceSets {
main {
// GStreamer will generate these files.
java {
srcDir 'src/main/jni/src'
}
assets {
srcDir 'src/main/jni/assets'
}
//Tell Gradle where to put the compiled shared library
jniLibs.srcDir 'src/main/libs'
//disable automatic ndk-build call
jni.srcDirs = [];
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
}
}
// Thank you http://stackoverflow.com/q/28878689/375209
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
task ndkBuild(type: Exec) {
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
def ndkDir = properties.getProperty('ndk.dir')
environment GSTREAMER_ROOT_ARM: properties.getProperty('gstreamer.arm.dir')
environment GSTREAMER_ROOT_ARMV7: properties.getProperty('gstreamer.armv7.dir')
environment GSTREAMER_ROOT_X86: properties.getProperty('gstreamer.x86.dir')
def ndkExtraPath = properties.getProperty('ndk.extraPath')
if (! "".equalsIgnoreCase(ndkExtraPath)) {
environment PATH: "${System.getenv("PATH")}${File.pathSeparator}${ndkExtraPath}"
}
commandLine "${ndkDir}/ndk-build", '-C', file('src/main/jni').absolutePath //, 'V=1' // Enable V=1 for debugging messages.
}
}
dependencies {
compile 'com.android.support:appcompat-v7:22.1.1'
compile "com.android.support:recyclerview-v7:22.1.1"
compile "com.android.support:support-annotations:22.1.1"
}

View file

@ -0,0 +1,97 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
package="org.freedesktop.gstreamer.play"
xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-feature android:glEsVersion="0x00020000"/>
<application
android:allowBackup="false"
android:label="@string/app_name"
android:theme="@style/GstPlayTheme">
<activity
android:name=".Play"
android:label="@string/app_name">
<!-- Local files whose MIME type is known to Android -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="audio/*"/>
<data android:mimeType="video/*"/>
<data android:mimeType="image/*"/>
</intent-filter>
<!--
Local files with unknown MIME type.
The list of extensions and supported protocols can certainly be extended.
-->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="file"/>
<data android:mimeType="*/*"/>
<data android:pathPattern=".*\\.avi"/>
<data android:pathPattern=".*\\.AVI"/>
<data android:pathPattern=".*\\.mkv"/>
<data android:pathPattern=".*\\.MKV"/>
<data android:pathPattern=".*\\.webm"/>
<data android:pathPattern=".*\\.WEBM"/>
<data android:pathPattern=".*\\.ogv"/>
<data android:pathPattern=".*\\.OGV"/>
<data android:pathPattern=".*\\.mp4"/>
<data android:pathPattern=".*\\.MP4"/>
<data android:pathPattern=".*\\.mov"/>
<data android:pathPattern=".*\\.MOV"/>
</intent-filter>
<!--
Remote files. These typically have unknown MIME type.
The list of extensions and supported protocols can certainly be extended.
-->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="http"/>
<data android:pathPattern=".*\\.avi"/>
<data android:pathPattern=".*\\.AVI"/>
<data android:pathPattern=".*\\.mkv"/>
<data android:pathPattern=".*\\.MKV"/>
<data android:pathPattern=".*\\.webm"/>
<data android:pathPattern=".*\\.WEBM"/>
<data android:pathPattern=".*\\.ogv"/>
<data android:pathPattern=".*\\.OGV"/>
<data android:pathPattern=".*\\.mp4"/>
<data android:pathPattern=".*\\.MP4"/>
<data android:pathPattern=".*\\.mov"/>
<data android:pathPattern=".*\\.MOV"/>
</intent-filter>
</activity>
<activity
android:name=".VideoSelector"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -20,18 +20,13 @@
package org.freedesktop.gstreamer.play;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
@ -42,13 +37,16 @@ import android.widget.Toast;
import org.freedesktop.gstreamer.Player;
public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarChangeListener {
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Play extends AppCompatActivity implements SurfaceHolder.Callback, OnSeekBarChangeListener {
private PowerManager.WakeLock wake_lock;
private Player player;
@Override
public void onCreate(Bundle savedInstanceState)
{
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
@ -59,7 +57,7 @@ public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarC
return;
}
setContentView(R.layout.main);
setContentView(R.layout.activity_player);
player = new Player();
@ -88,7 +86,7 @@ public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarC
player.setPositionUpdatedListener(new Player.PositionUpdatedListener() {
public void positionUpdated(Player player, final long position) {
runOnUiThread (new Runnable() {
runOnUiThread(new Runnable() {
public void run() {
sb.setProgress((int) (position / 1000000));
updateTimeWidget();
@ -99,7 +97,7 @@ public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarC
player.setDurationChangedListener(new Player.DurationChangedListener() {
public void durationChanged(Player player, final long duration) {
runOnUiThread (new Runnable() {
runOnUiThread(new Runnable() {
public void run() {
sb.setMax((int) (duration / 1000000));
updateTimeWidget();
@ -109,31 +107,35 @@ public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarC
});
final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video);
player.setVideoDimensionsChangedListener(new Player.VideoDimensionsChangedListener() {
public void videoDimensionsChanged(Player player, final int width, final int height) {
runOnUiThread (new Runnable() {
runOnUiThread(new Runnable() {
public void run() {
Log.i ("GStreamer", "Media size changed to " + width + "x" + height);
gsv.media_width = width;
gsv.media_height = height;
runOnUiThread(new Runnable() {
public void run() {
gsv.requestLayout();
}
});
Log.i("GStreamer", "Media size changed to " + width + "x" + height);
if (width > 0 && height > 0) {
gsv.media_width = width;
gsv.media_height = height;
runOnUiThread(new Runnable() {
public void run() {
gsv.requestLayout();
}
});
} else {
Log.i("GStreamer", "Ignoring media size.");
}
}
});
}
});
SurfaceView sv = (SurfaceView) this.findViewById(R.id.surface_video);
SurfaceHolder sh = sv.getHolder();
SurfaceHolder sh = gsv.getHolder();
sh.addCallback(this);
String mediaUri = null;
Intent intent = getIntent();
android.net.Uri uri = intent.getData();
Log.i ("GStreamer", "Received URI: " + uri);
Log.i("GStreamer", "Received URI: " + uri);
if (uri.getScheme().equals("content")) {
android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
@ -152,7 +154,7 @@ public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarC
super.onDestroy();
}
private void updateTimeWidget () {
private void updateTimeWidget() {
final TextView tv = (TextView) this.findViewById(R.id.textview_time);
final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar);
final int pos = sb.getProgress();
@ -160,14 +162,12 @@ public class Play extends Activity implements SurfaceHolder.Callback, OnSeekBarC
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
final String message = df.format(new Date (pos)) + " / " + df.format(new Date (max));
final String message = df.format(new Date(pos)) + " / " + df.format(new Date(max));
tv.setText(message);
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.d("GStreamer", "Surface changed to format " + format + " width "
+ width + " height " + height);
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d("GStreamer", "Surface changed to format " + format + " width " + width + " height " + height);
player.setSurface(holder.getSurface());
}

View file

@ -0,0 +1,151 @@
/* GStreamer
*
* Copyright (C) 2015 Sebastian Roth <sebastian.roth@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
package org.freedesktop.gstreamer.play;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
public class VideoSelector extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
VideoAdapter adapter;
boolean sortByName = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_video_selector);
ListView videoList = (ListView) findViewById(R.id.videoList);
adapter = new VideoAdapter(this);
videoList.setAdapter(adapter);
videoList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, final int position, final long id) {
final String videoPath = adapter.getVideoPath(position);
if (!TextUtils.isEmpty(videoPath)) {
Intent intent = new Intent(VideoSelector.this, Play.class);
intent.setData(Uri.parse("file://" + videoPath));
startActivity(intent);
}
}
});
getSupportLoaderManager().initLoader(1, null, this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_video_selector, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_about) {
return true;
}
//noinspection SimplifiableIfStatement
if (id == R.id.action_sort) {
sortByName = !sortByName;
getSupportLoaderManager().restartLoader(1, null, this);
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
if (sortByName) {
return new CursorLoader(this, MediaStore.Video.Media.getContentUri("external"), null, null, null,
"UPPER(" + MediaStore.Video.Media.DATA + ")");
} else {
return new CursorLoader(this, MediaStore.Video.Media.getContentUri("external"), null, null, null,
"UPPER(" + MediaStore.Video.Media.DISPLAY_NAME + ")");
}
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
adapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
}
class VideoAdapter extends SimpleCursorAdapter {
public VideoAdapter(Context context) {
super(context, android.R.layout.simple_list_item_2, null,
new String[]{MediaStore.Video.Media.DISPLAY_NAME, MediaStore.Video.Media.DATA},
new int[]{android.R.id.text1, android.R.id.text2}, 0);
}
@Override
public long getItemId(int position) {
final Cursor cursor = getCursor();
if (cursor.getCount() == 0 || position >= cursor.getCount()) {
return 0;
}
cursor.moveToPosition(position);
return cursor.getLong(0);
}
public String getVideoPath(int position) {
final Cursor cursor = getCursor();
if (cursor.getCount() == 0) {
return "";
}
cursor.moveToPosition(position);
return cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));
}
}
}

View file

@ -2,18 +2,25 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
GST_PATH := $(LOCAL_PATH)/../../../../../
LOCAL_MODULE := gstplayer
LOCAL_SRC_FILES := player.c ../../lib/gst/player/gstplayer.c ../../lib/gst/player/gstplayer-media-info.c
LOCAL_C_INCLUDES := $(LOCAL_PATH)/../../lib
LOCAL_SRC_FILES := player.c \
$(GST_PATH)/lib/gst/player/gstplayer.c \
$(GST_PATH)/lib/gst/player/gstplayer-media-info.c
LOCAL_C_INCLUDES := $(GST_PATH)/lib
LOCAL_SHARED_LIBRARIES := gstreamer_android
LOCAL_LDLIBS := -llog -landroid
include $(BUILD_SHARED_LIBRARY)
ifndef GSTREAMER_ROOT
ifndef GSTREAMER_ROOT_ANDROID
$(error GSTREAMER_ROOT_ANDROID is not defined!)
endif
GSTREAMER_ROOT := $(GSTREAMER_ROOT_ANDROID)
ifeq ($(TARGET_ARCH_ABI),armeabi)
GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARM)
else ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
GSTREAMER_ROOT := $(GSTREAMER_ROOT_ARMV7)
else ifeq ($(TARGET_ARCH_ABI),x86)
GSTREAMER_ROOT := $(GSTREAMER_ROOT_X86)
else
$(error Target arch ABI $(TARGET_ARCH_ABI) not supported)
endif
GSTREAMER_NDK_BUILD_PATH := $(GSTREAMER_ROOT)/share/gst-android/ndk-build/

View file

@ -0,0 +1,2 @@
APP_ABI := armeabi armeabi-v7a x86
APP_PLATFORM := android-9

View file

@ -25,7 +25,7 @@
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include "gst/player/gstplayer.h"
#include "gst/player/player.h"
GST_DEBUG_CATEGORY_STATIC (debug_category);
#define GST_CAT_DEFAULT debug_category

View file

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical">
<org.freedesktop.gstreamer.play.GStreamerSurfaceView
android:id="@+id/surface_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="#33000000"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dip"
android:gravity="center_horizontal"
android:orientation="horizontal">
<ImageButton
android:id="@+id/button_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/button_play"
android:src="@android:drawable/ic_media_play"
android:text="@string/button_play"/>
<ImageButton
android:id="@+id/button_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/button_pause"
android:src="@android:drawable/ic_media_pause"
android:text="@string/button_pause"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dip"
android:gravity="center_horizontal"
android:orientation="horizontal">
<TextView
android:id="@+id/textview_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip"/>
<SeekBar
android:id="@+id/seek_bar"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:indeterminate="false"/>
</LinearLayout>
</LinearLayout>
</FrameLayout>

View file

@ -0,0 +1,15 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="org.freedesktop.gstreamer.play.VideoSelector">
<ListView
android:id="@+id/videoList"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>

View file

@ -0,0 +1,17 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.freedesktop.gstreamer.play.VideoSelector">
<item
android:id="@+id/action_sort"
android:title="@string/sort"
android:orderInCategory="100"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_about"
android:orderInCategory="100"
android:title="@string/action_about"
app:showAsAction="never"/>
</menu>

View file

@ -0,0 +1,6 @@
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View file

@ -0,0 +1,5 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>

View file

@ -3,4 +3,7 @@
<string name="app_name">GStreamer Play</string>
<string name="button_play">Play</string>
<string name="button_pause">Pause</string>
<string name="action_about">About</string>
<string name="sort">Sort</string>
</resources>

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="GstPlayTheme" parent="Theme.AppCompat">
</style>
</resources>

View file

@ -0,0 +1,15 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.2.2'
}
}
allprojects {
repositories {
jcenter()
}
}

View file

@ -1,92 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="gst-play" default="help">
<!-- The local.properties file is created and updated by the 'android' tool.
It contains the path to the SDK. It should *NOT* be checked into
Version Control Systems. -->
<property file="local.properties" />
<!-- The ant.properties file can be created by you. It is only edited by the
'android' tool to add properties to it.
This is the place to change some Ant specific build properties.
Here are some properties you may want to change/update:
source.dir
The name of the source directory. Default is 'src'.
out.dir
The name of the output directory. Default is 'bin'.
For other overridable properties, look at the beginning of the rules
files in the SDK, at tools/ant/build.xml
Properties related to the SDK location or the project target should
be updated using the 'android' tool with the 'update' action.
This file is an integral part of the build system for your
application and should be checked into Version Control Systems.
-->
<property file="ant.properties" />
<!-- if sdk.dir was not set from one of the property file, then
get it from the ANDROID_HOME env var.
This must be done before we load project.properties since
the proguard config can use sdk.dir -->
<property environment="env" />
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
<isset property="env.ANDROID_HOME" />
</condition>
<!-- The project.properties file is created and updated by the 'android'
tool, as well as ADT.
This contains project specific properties such as project target, and library
dependencies. Lower level build properties are stored in ant.properties
(or in .classpath for Eclipse projects).
This file is an integral part of the build system for your
application and should be checked into Version Control Systems. -->
<loadproperties srcFile="project.properties" />
<!-- quick check on sdk.dir -->
<fail
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
unless="sdk.dir"
/>
<!--
Import per project custom build rules if present at the root of the project.
This is the place to put custom intermediary targets such as:
-pre-build
-pre-compile
-post-compile (This is typically used for code obfuscation.
Compiled code location: ${out.classes.absolute.dir}
If this is not done in place, override ${out.dex.input.absolute.dir})
-post-package
-post-build
-pre-clean
-->
<import file="custom_rules.xml" optional="true" />
<!-- Import the actual build file.
To customize existing targets, there are two options:
- Customize only one target:
- copy/paste the target into this file, *before* the
<import> task.
- customize it to your needs.
- Customize the whole content of build.xml
- copy/paste the content of the rules files (minus the top node)
into this file, replacing the <import> task.
- customize to your needs.
***********************
****** IMPORTANT ******
***********************
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
in order to avoid having your file be overridden by tools such as "android update project"
-->
<!-- version-tag: 1 -->
<import file="${sdk.dir}/tools/ant/build.xml" />
</project>

Binary file not shown.

View file

@ -0,0 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip

164
playback/player/android/gradlew vendored Executable file
View file

@ -0,0 +1,164 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# For Cygwin, ensure paths are in UNIX format before anything is touched.
if $cygwin ; then
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >&-
APP_HOME="`pwd -P`"
cd "$SAVED" >&-
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
playback/player/android/gradlew.bat vendored Normal file
View file

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View file

@ -1,62 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dip"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<ImageButton
android:id="@+id/button_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/button_play"
android:src="@android:drawable/ic_media_play"
android:text="@string/button_play" />
<ImageButton
android:id="@+id/button_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/button_pause"
android:src="@android:drawable/ic_media_pause"
android:text="@string/button_pause" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dip"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<TextView
android:id="@+id/textview_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="5dip"
android:layout_marginRight="5dip" />
<SeekBar
android:id="@+id/seek_bar"
android:layout_width="0dip"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:indeterminate="false" />
</LinearLayout>
<org.freedesktop.gstreamer.play.GStreamerSurfaceView
android:id="@+id/surface_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|center_horizontal" />
</LinearLayout>

View file

@ -0,0 +1 @@
include ':app'