summaryrefslogtreecommitdiff
path: root/tutorials/android-tutorial-4/src/com/gst_sdk_tutorials/tutorial_4/Tutorial4.java
diff options
context:
space:
mode:
Diffstat (limited to 'tutorials/android-tutorial-4/src/com/gst_sdk_tutorials/tutorial_4/Tutorial4.java')
-rw-r--r--tutorials/android-tutorial-4/src/com/gst_sdk_tutorials/tutorial_4/Tutorial4.java250
1 files changed, 250 insertions, 0 deletions
diff --git a/tutorials/android-tutorial-4/src/com/gst_sdk_tutorials/tutorial_4/Tutorial4.java b/tutorials/android-tutorial-4/src/com/gst_sdk_tutorials/tutorial_4/Tutorial4.java
new file mode 100644
index 0000000..f3d5977
--- /dev/null
+++ b/tutorials/android-tutorial-4/src/com/gst_sdk_tutorials/tutorial_4/Tutorial4.java
@@ -0,0 +1,250 @@
+package com.gst_sdk_tutorials.tutorial_4;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.TimeZone;
+
+import android.app.Activity;
+import android.os.Bundle;
+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 org.freedesktop.gstreamer.GStreamer;
+
+public class Tutorial4 extends Activity implements SurfaceHolder.Callback, OnSeekBarChangeListener {
+ private native void nativeInit(); // Initialize native code, build pipeline, etc
+ private native void nativeFinalize(); // Destroy pipeline and shutdown native code
+ private native void nativeSetUri(String uri); // Set the URI of the media to play
+ private native void nativePlay(); // Set pipeline to PLAYING
+ private native void nativeSetPosition(int milliseconds); // Seek to the indicated position, in milliseconds
+ private native void nativePause(); // Set pipeline to PAUSED
+ private static native boolean nativeClassInit(); // Initialize native class: cache Method IDs for callbacks
+ private native void nativeSurfaceInit(Object surface); // A new surface is available
+ private native void nativeSurfaceFinalize(); // Surface about to be destroyed
+ private long native_custom_data; // Native code will use this to keep private data
+
+ private boolean is_playing_desired; // Whether the user asked to go to PLAYING
+ private int position; // Current position, reported by native code
+ private int duration; // Current clip duration, reported by native code
+ private boolean is_local_media; // Whether this clip is stored locally or is being streamed
+ private int desired_position; // Position where the users wants to seek to
+ private String mediaUri; // URI of the clip being played
+
+ private final String defaultMediaUri = "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.ogv";
+
+ // Called when the activity is first created.
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ // Initialize GStreamer and warn if it fails
+ try {
+ GStreamer.init(this);
+ } catch (Exception e) {
+ Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
+ finish();
+ return;
+ }
+
+ setContentView(R.layout.main);
+
+ ImageButton play = (ImageButton) this.findViewById(R.id.button_play);
+ play.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ is_playing_desired = true;
+ nativePlay();
+ }
+ });
+
+ ImageButton pause = (ImageButton) this.findViewById(R.id.button_stop);
+ pause.setOnClickListener(new OnClickListener() {
+ public void onClick(View v) {
+ is_playing_desired = false;
+ nativePause();
+ }
+ });
+
+ SurfaceView sv = (SurfaceView) this.findViewById(R.id.surface_video);
+ SurfaceHolder sh = sv.getHolder();
+ sh.addCallback(this);
+
+ SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar);
+ sb.setOnSeekBarChangeListener(this);
+
+ // Retrieve our previous state, or initialize it to default values
+ if (savedInstanceState != null) {
+ is_playing_desired = savedInstanceState.getBoolean("playing");
+ position = savedInstanceState.getInt("position");
+ duration = savedInstanceState.getInt("duration");
+ mediaUri = savedInstanceState.getString("mediaUri");
+ Log.i ("GStreamer", "Activity created with saved state:");
+ } else {
+ is_playing_desired = false;
+ position = duration = 0;
+ mediaUri = defaultMediaUri;
+ Log.i ("GStreamer", "Activity created with no saved state:");
+ }
+ is_local_media = false;
+ Log.i ("GStreamer", " playing:" + is_playing_desired + " position:" + position +
+ " duration: " + duration + " uri: " + mediaUri);
+
+ // Start with disabled buttons, until native code is initialized
+ this.findViewById(R.id.button_play).setEnabled(false);
+ this.findViewById(R.id.button_stop).setEnabled(false);
+
+ nativeInit();
+ }
+
+ protected void onSaveInstanceState (Bundle outState) {
+ Log.d ("GStreamer", "Saving state, playing:" + is_playing_desired + " position:" + position +
+ " duration: " + duration + " uri: " + mediaUri);
+ outState.putBoolean("playing", is_playing_desired);
+ outState.putInt("position", position);
+ outState.putInt("duration", duration);
+ outState.putString("mediaUri", mediaUri);
+ }
+
+ protected void onDestroy() {
+ nativeFinalize();
+ super.onDestroy();
+ }
+
+ // Called from native code. This sets the content of the TextView from the UI thread.
+ private void setMessage(final String message) {
+ final TextView tv = (TextView) this.findViewById(R.id.textview_message);
+ runOnUiThread (new Runnable() {
+ public void run() {
+ tv.setText(message);
+ }
+ });
+ }
+
+ // Set the URI to play, and record whether it is a local or remote file
+ private void setMediaUri() {
+ nativeSetUri (mediaUri);
+ is_local_media = mediaUri.startsWith("file://");
+ }
+
+ // Called from native code. Native code calls this once it has created its pipeline and
+ // the main loop is running, so it is ready to accept commands.
+ private void onGStreamerInitialized () {
+ Log.i ("GStreamer", "GStreamer initialized:");
+ Log.i ("GStreamer", " playing:" + is_playing_desired + " position:" + position + " uri: " + mediaUri);
+
+ // Restore previous playing state
+ setMediaUri ();
+ nativeSetPosition (position);
+ if (is_playing_desired) {
+ nativePlay();
+ } else {
+ nativePause();
+ }
+
+ // Re-enable buttons, now that GStreamer is initialized
+ final Activity activity = this;
+ runOnUiThread(new Runnable() {
+ public void run() {
+ activity.findViewById(R.id.button_play).setEnabled(true);
+ activity.findViewById(R.id.button_stop).setEnabled(true);
+ }
+ });
+ }
+
+ // The text widget acts as an slave for the seek bar, so it reflects what the seek bar shows, whether
+ // it is an actual pipeline position or the position the user is currently dragging to.
+ 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();
+
+ SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
+ df.setTimeZone(TimeZone.getTimeZone("UTC"));
+ final String message = df.format(new Date (pos)) + " / " + df.format(new Date (duration));
+ tv.setText(message);
+ }
+
+ // Called from native code
+ private void setCurrentPosition(final int position, final int duration) {
+ final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar);
+
+ // Ignore position messages from the pipeline if the seek bar is being dragged
+ if (sb.isPressed()) return;
+
+ runOnUiThread (new Runnable() {
+ public void run() {
+ sb.setMax(duration);
+ sb.setProgress(position);
+ updateTimeWidget();
+ }
+ });
+ this.position = position;
+ this.duration = duration;
+ }
+
+ static {
+ System.loadLibrary("gstreamer_android");
+ System.loadLibrary("tutorial-4");
+ nativeClassInit();
+ }
+
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {
+ Log.d("GStreamer", "Surface changed to format " + format + " width "
+ + width + " height " + height);
+ nativeSurfaceInit (holder.getSurface());
+ }
+
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.d("GStreamer", "Surface created: " + holder.getSurface());
+ }
+
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.d("GStreamer", "Surface destroyed");
+ nativeSurfaceFinalize ();
+ }
+
+ // Called from native code when the size of the media changes or is first detected.
+ // Inform the video surface about the new size and recalculate the layout.
+ private void onMediaSizeChanged (int width, int height) {
+ Log.i ("GStreamer", "Media size changed to " + width + "x" + height);
+ final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video);
+ gsv.media_width = width;
+ gsv.media_height = height;
+ runOnUiThread(new Runnable() {
+ public void run() {
+ gsv.requestLayout();
+ }
+ });
+ }
+
+ // The Seek Bar thumb has moved, either because the user dragged it or we have called setProgress()
+ public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) {
+ if (fromUser == false) return;
+ desired_position = progress;
+ // If this is a local file, allow scrub seeking, this is, seek as soon as the slider is moved.
+ if (is_local_media) nativeSetPosition(desired_position);
+ updateTimeWidget();
+ }
+
+ // The user started dragging the Seek Bar thumb
+ public void onStartTrackingTouch(SeekBar sb) {
+ nativePause();
+ }
+
+ // The user released the Seek Bar thumb
+ public void onStopTrackingTouch(SeekBar sb) {
+ // If this is a remote file, scrub seeking is probably not going to work smoothly enough.
+ // Therefore, perform only the seek when the slider is released.
+ if (!is_local_media) nativeSetPosition(desired_position);
+ if (is_playing_desired) nativePlay();
+ }
+}