gstreamer/subprojects/gst-docs/examples/tutorials/android/android-tutorial-5/src/org/freedesktop/gstreamer/tutorials/tutorial_5/Tutorial5.java

310 lines
12 KiB
Java

package org.freedesktop.gstreamer.tutorials.tutorial_5;
import java.io.File;
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.Environment;
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 org.freedesktop.gstreamer.GStreamer;
import com.lamerman.FileDialog;
public class Tutorial5 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";
static private final int PICK_FILE_CODE = 1;
private String last_folder;
private PowerManager.WakeLock wake_lock;
// 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);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer tutorial 5");
wake_lock.setReferenceCounted(false);
ImageButton play = (ImageButton) this.findViewById(R.id.button_play);
play.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
is_playing_desired = true;
wake_lock.acquire();
nativePlay();
}
});
ImageButton pause = (ImageButton) this.findViewById(R.id.button_stop);
pause.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
is_playing_desired = false;
wake_lock.release();
nativePause();
}
});
ImageButton select = (ImageButton) this.findViewById(R.id.button_select);
select.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
Intent i = new Intent(getBaseContext(), FileDialog.class);
i.putExtra(FileDialog.START_PATH, last_folder);
startActivityForResult(i, PICK_FILE_CODE);
}
});
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");
last_folder = savedInstanceState.getString("last_folder");
Log.i ("GStreamer", "Activity created with saved state:");
} else {
is_playing_desired = false;
position = duration = 0;
last_folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath();
Intent intent = getIntent();
android.net.Uri uri = intent.getData();
if (uri == null)
mediaUri = defaultMediaUri;
else {
Log.i ("GStreamer", "Received URI: " + uri);
if (uri.getScheme().equals("content")) {
android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null);
cursor.moveToFirst();
mediaUri = "file://" + cursor.getString(cursor.getColumnIndex(android.provider.MediaStore.Video.Media.DATA));
cursor.close();
} else
mediaUri = uri.toString();
}
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);
outState.putString("last_folder", last_folder);
}
protected void onDestroy() {
nativeFinalize();
if (wake_lock.isHeld())
wake_lock.release();
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();
wake_lock.acquire();
} else {
nativePause();
wake_lock.release();
}
// 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 () {
TextView tv = (TextView) this.findViewById(R.id.textview_time);
SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar);
int pos = sb.getProgress();
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
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();
sb.setEnabled(duration != 0);
}
});
this.position = position;
this.duration = duration;
}
static {
System.loadLibrary("gstreamer_android");
System.loadLibrary("tutorial-5");
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();
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
if (resultCode == RESULT_OK && requestCode == PICK_FILE_CODE) {
mediaUri = "file://" + data.getStringExtra(FileDialog.RESULT_PATH);
position = 0;
last_folder = new File (data.getStringExtra(FileDialog.RESULT_PATH)).getParent();
Log.i("GStreamer", "Setting last_folder to " + last_folder);
setMediaUri();
}
}
}