Commit 23f424bc authored by Thibault Saunier's avatar Thibault Saunier 🌵

Merging gst-examples

parents 5b7877ee 35da788b
include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml"
This diff is collapsed.
project('gst-examples', 'c', version : '1.17.0.1', license : 'LGPL')
cc = meson.get_compiler('c')
m_dep = cc.find_library('m', required : false)
glib_dep = dependency('glib-2.0', version: '>= 2.38',
fallback: ['glib', 'libglib_dep'])
gio_dep = dependency('gio-2.0',
fallback: ['glib', 'libgio_dep'])
gobject_dep = dependency('gobject-2.0', version: '>= 2.38',
fallback: ['glib', 'libgobject_dep'])
gmodule_dep = dependency('gmodule-2.0',
fallback: ['glib', 'libgmodule_dep'])
gst_dep = dependency('gstreamer-1.0',
fallback : ['gstreamer', 'gst_dep'])
gstplayer_dep = dependency('gstreamer-player-1.0', version: '>= 1.7.1.1',
fallback: ['gst-plugins-bad', 'gstplayer_dep'])
gsttag_dep = dependency('gstreamer-tag-1.0',
fallback: ['gst-plugins-base', 'tag_dep'])
subdir('playback')
subdir('network')
This diff is collapsed.
executable('http-launch', 'http-launch.c', dependencies : [gst_dep, gio_dep])
subdir('http-launch')
subdir('player')
# Android GStreamer sample player application
## Build and deploy
First of all you need to replace the gold linker with bfd in the `gst-android-1.14/armv7/share/gst-android/ndk-build/gstreamer-1.0.mk`
See also this [NDK issue](https://github.com/android-ndk/ndk/issues/337)
Then to build and deploy the player app to your device, use a command similar to:
```bash
$ GSTREAMER_ROOT_ANDROID=/path/to/gst-android-1.14/ PATH=~/dev/android/tools/bin:~/dev/android/ndk-bundle:$PATH ANDROID_HOME="$HOME/dev/android/" ./gradlew installDebug
```
## Run the application on the device
```bash
$ adb shell am start -n org.freedesktop.gstreamer.play/.Play http://ftp.nluug.nl/pub/graphics/blender/demo/movies/Sintel.2010.720p.mkv
```
To see the GStreamer logs at runtime:
```bash
$ adb logcat | egrep '(gst)'
```
.externalNativeBuild/
assets/
gst-build-*/
src/main/java/org/freedesktop/gstreamer/GStreamer.java
src/main/java/org/freedesktop/gstreamer/androidmedia/
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion '27.0.3'
defaultConfig {
applicationId "org.freedesktop.gstreamer.play"
minSdkVersion 15
targetSdkVersion 15
versionCode 1
versionName "1.0"
externalNativeBuild {
ndkBuild {
def gstRoot
if (project.hasProperty('gstAndroidRoot'))
gstRoot = project.gstAndroidRoot
else
gstRoot = System.env.GSTREAMER_ROOT_ANDROID
if (gstRoot == null)
throw new GradleException('GSTREAMER_ROOT_ANDROID must be set, or "gstAndroidRoot" must be defined in your gradle.properties in the top level directory of the unpacked universal GStreamer Android binaries')
arguments "NDK_APPLICATION_MK=src/main/jni/Application.mk", "GSTREAMER_JAVA_SRC_DIR=src/main/java", "GSTREAMER_ROOT_ANDROID=$gstRoot", "GSTREAMER_ASSETS_DIR=src/main/assets"
targets "gstplayer"
// All archs except MIPS and MIPS64 are supported
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'
// x86_64 abis disabled because of https://bugzilla.gnome.org/show_bug.cgi?id=795454
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
externalNativeBuild {
ndkBuild {
path 'src/main/jni/Android.mk'
}
}
}
afterEvaluate {
if (project.hasProperty('compileDebugJavaWithJavac'))
project.compileDebugJavaWithJavac.dependsOn 'externalNativeBuildDebug'
if (project.hasProperty('compileReleaseJavaWithJavac'))
project.compileReleaseJavaWithJavac.dependsOn 'externalNativeBuildRelease'
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
implementation 'com.android.support:appcompat-v7:23.1.1'
}
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /home/arun/code/android/sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
This diff is collapsed.
/* GStreamer
*
* Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.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;
import java.io.Closeable;
import android.view.Surface;
import android.content.Context;
import org.freedesktop.gstreamer.GStreamer;
public class Player implements Closeable {
private static native void nativeClassInit();
public static void init(Context context) throws Exception {
System.loadLibrary("gstreamer_android");
GStreamer.init(context);
System.loadLibrary("gstplayer");
nativeClassInit();
}
private long native_player;
private native void nativeNew();
public Player() {
nativeNew();
}
private native void nativeFree();
@Override
public void close() {
nativeFree();
}
private native void nativePlay();
public void play() {
nativePlay();
}
private native void nativePause();
public void pause() {
nativePause();
}
private native void nativeStop();
public void stop() {
nativeStop();
}
private native void nativeSeek(long position);
public void seek(long position) {
nativeSeek(position);
}
private native String nativeGetUri();
public String getUri() {
return nativeGetUri();
}
private native void nativeSetUri(String uri);
public void setUri(String uri) {
nativeSetUri(uri);
}
private native long nativeGetPosition();
public long getPosition() {
return nativeGetPosition();
}
private native long nativeGetDuration();
public long getDuration() {
return nativeGetDuration();
}
private native double nativeGetVolume();
public double getVolume() {
return nativeGetVolume();
}
private native void nativeSetVolume(double volume);
public void setVolume(double volume) {
nativeSetVolume(volume);
}
private native boolean nativeGetMute();
public boolean getMute() {
return nativeGetMute();
}
private native void nativeSetMute(boolean mute);
public void setMute(boolean mute) {
nativeSetMute(mute);
}
private Surface surface;
private native void nativeSetSurface(Surface surface);
public void setSurface(Surface surface) {
this.surface = surface;
nativeSetSurface(surface);
}
public Surface getSurface() {
return surface;
}
public static interface PositionUpdatedListener {
abstract void positionUpdated(Player player, long position);
}
private PositionUpdatedListener positionUpdatedListener;
public void setPositionUpdatedListener(PositionUpdatedListener listener) {
positionUpdatedListener = listener;
}
private void onPositionUpdated(long position) {
if (positionUpdatedListener != null) {
positionUpdatedListener.positionUpdated(this, position);
}
}
public static interface DurationChangedListener {
abstract void durationChanged(Player player, long duration);
}
private DurationChangedListener durationChangedListener;
public void setDurationChangedListener(DurationChangedListener listener) {
durationChangedListener = listener;
}
private void onDurationChanged(long duration) {
if (durationChangedListener != null) {
durationChangedListener.durationChanged(this, duration);
}
}
private static final State[] stateMap = {State.STOPPED, State.BUFFERING, State.PAUSED, State.PLAYING};
public enum State {
STOPPED,
BUFFERING,
PAUSED,
PLAYING
}
public static interface StateChangedListener {
abstract void stateChanged(Player player, State state);
}
private StateChangedListener stateChangedListener;
public void setStateChangedListener(StateChangedListener listener) {
stateChangedListener = listener;
}
private void onStateChanged(int stateIdx) {
if (stateChangedListener != null) {
State state = stateMap[stateIdx];
stateChangedListener.stateChanged(this, state);
}
}
public static interface BufferingListener {
abstract void buffering(Player player, int percent);
}
private BufferingListener bufferingListener;
public void setBufferingListener(BufferingListener listener) {
bufferingListener = listener;
}
private void onBuffering(int percent) {
if (bufferingListener != null) {
bufferingListener.buffering(this, percent);
}
}
public static interface EndOfStreamListener {
abstract void endOfStream(Player player);
}
private EndOfStreamListener endOfStreamListener;
public void setEndOfStreamListener(EndOfStreamListener listener) {
endOfStreamListener = listener;
}
private void onEndOfStream() {
if (endOfStreamListener != null) {
endOfStreamListener.endOfStream(this);
}
}
// Keep these in sync with gstplayer.h
private static final Error[] errorMap = {Error.FAILED};
public enum Error {
FAILED
}
public static interface ErrorListener {
abstract void error(Player player, Error error, String errorMessage);
}
private ErrorListener errorListener;
public void setErrorListener(ErrorListener listener) {
errorListener = listener;
}
private void onError(int errorCode, String errorMessage) {
if (errorListener != null) {
Error error = errorMap[errorCode];
errorListener.error(this, error, errorMessage);
}
}
public static interface VideoDimensionsChangedListener {
abstract void videoDimensionsChanged(Player player, int width, int height);
}
private VideoDimensionsChangedListener videoDimensionsChangedListener;
public void setVideoDimensionsChangedListener(VideoDimensionsChangedListener listener) {
videoDimensionsChangedListener = listener;
}
private void onVideoDimensionsChanged(int width, int height) {
if (videoDimensionsChangedListener != null) {
videoDimensionsChangedListener.videoDimensionsChanged(this, width, height);
}
}
}
/* GStreamer
*
* Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.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.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceView;
import android.view.View;
// A simple SurfaceView whose width and height can be set from the outside
public class GStreamerSurfaceView extends SurfaceView {
public int media_width = 320;
public int media_height = 240;
// Mandatory constructors, they do not do much
public GStreamerSurfaceView(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public GStreamerSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GStreamerSurfaceView (Context context) {
super(context);
}
// Called by the layout manager to find out our size and give us some rules.
// We will try to maximize our size, and preserve the media's aspect ratio if
// we are given the freedom to do so.
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (media_width == 0 || media_height == 0) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int width = 0, height = 0;
int wmode = View.MeasureSpec.getMode(widthMeasureSpec);
int hmode = View.MeasureSpec.getMode(heightMeasureSpec);
int wsize = View.MeasureSpec.getSize(widthMeasureSpec);
int hsize = View.MeasureSpec.getSize(heightMeasureSpec);
Log.i ("GStreamer", "onMeasure called with " + media_width + "x" + media_height);
// Obey width rules
switch (wmode) {
case View.MeasureSpec.AT_MOST:
if (hmode == View.MeasureSpec.EXACTLY) {
width = Math.min(hsize * media_width / media_height, wsize);
break;
}
case View.MeasureSpec.EXACTLY:
width = wsize;
break;
case View.MeasureSpec.UNSPECIFIED:
width = media_width;
}
// Obey height rules
switch (hmode) {
case View.MeasureSpec.AT_MOST:
if (wmode == View.MeasureSpec.EXACTLY) {
height = Math.min(wsize * media_height / media_width, hsize);
break;
}
case View.MeasureSpec.EXACTLY:
height = hsize;
break;
case View.MeasureSpec.UNSPECIFIED:
height = media_height;
}
// Finally, calculate best size when both axis are free
if (hmode == View.MeasureSpec.AT_MOST && wmode == View.MeasureSpec.AT_MOST) {
int correct_height = width * media_height / media_width;
int correct_width = height * media_width / media_height;
if (correct_height < height)
height = correct_height;
else
width = correct_width;
}
// Obey minimum size
width = Math.max (getSuggestedMinimumWidth(), width);
height = Math.max (getSuggestedMinimumHeight(), height);
setMeasuredDimension(width, height);
}
}
/* GStreamer
*
* Copyright (C) 2014 Sebastian Dröge <sebastian@centricular.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 java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.PowerManager;
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;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;
import android.support.v7.app.AppCompatActivity;
import org.freedesktop.gstreamer.Player;
public class Play extends AppCompatActivity implements SurfaceHolder.Callback, OnSeekBarChangeListener {
private PowerManager.WakeLock wake_lock;
private Player player;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
try {
Player.init(this);
} catch (Exception e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
finish();
return;
}
setContentView(R.layout.main);
player = new Player();
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer Play");
wake_lock.setReferenceCounted(false);
ImageButton play = (ImageButton) this.findViewById(R.id.button_play);
play.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
player.play();
wake_lock.acquire();
}
});
ImageButton pause = (ImageButton) this.findViewById(R.id.button_pause);
pause.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
player.pause();
wake_lock.release();
}
});
final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar);
sb.setOnSeekBarChangeListener(this);
player.setPositionUpdatedListener(new Player.PositionUpdatedListener() {
public void positionUpdated(Player player, final long position) {
runOnUiThread (new Runnable() {
public void run() {
sb.setProgress((int) (position / 1000000));
updateTimeWidget();
}
});
}
});
player.setDurationChangedListener(new Player.DurationChangedListener() {
public void durationChanged(Player player, final long duration) {
runOnUiThread (new Runnable() {
public void run() {
sb.setMax((int) (duration / 1000000));
updateTimeWidget();