1 package com.gst_sdk_tutorials.tutorial_5;
4 import java.text.SimpleDateFormat;
6 import java.util.TimeZone;
8 import android.app.Activity;
9 import android.content.Context;
10 import android.content.Intent;
11 import android.os.Bundle;
12 import android.os.Environment;
13 import android.os.PowerManager;
14 import android.util.Log;
15 import android.view.SurfaceHolder;
16 import android.view.SurfaceView;
17 import android.view.View;
18 import android.view.View.OnClickListener;
19 import android.widget.ImageButton;
20 import android.widget.SeekBar;
21 import android.widget.SeekBar.OnSeekBarChangeListener;
22 import android.widget.TextView;
23 import android.widget.Toast;
25 import org.freedesktop.gstreamer.GStreamer;
26 import com.lamerman.FileDialog;
28 public class Tutorial5 extends Activity implements SurfaceHolder.Callback, OnSeekBarChangeListener {
29 private native void nativeInit(); // Initialize native code, build pipeline, etc
30 private native void nativeFinalize(); // Destroy pipeline and shutdown native code
31 private native void nativeSetUri(String uri); // Set the URI of the media to play
32 private native void nativePlay(); // Set pipeline to PLAYING
33 private native void nativeSetPosition(int milliseconds); // Seek to the indicated position, in milliseconds
34 private native void nativePause(); // Set pipeline to PAUSED
35 private static native boolean nativeClassInit(); // Initialize native class: cache Method IDs for callbacks
36 private native void nativeSurfaceInit(Object surface); // A new surface is available
37 private native void nativeSurfaceFinalize(); // Surface about to be destroyed
38 private long native_custom_data; // Native code will use this to keep private data
40 private boolean is_playing_desired; // Whether the user asked to go to PLAYING
41 private int position; // Current position, reported by native code
42 private int duration; // Current clip duration, reported by native code
43 private boolean is_local_media; // Whether this clip is stored locally or is being streamed
44 private int desired_position; // Position where the users wants to seek to
45 private String mediaUri; // URI of the clip being played
47 private final String defaultMediaUri = "https://www.freedesktop.org/software/gstreamer-sdk/data/media/sintel_trailer-480p.ogv";
49 static private final int PICK_FILE_CODE = 1;
50 private String last_folder;
52 private PowerManager.WakeLock wake_lock;
54 // Called when the activity is first created.
56 public void onCreate(Bundle savedInstanceState)
58 super.onCreate(savedInstanceState);
60 // Initialize GStreamer and warn if it fails
63 } catch (Exception e) {
64 Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
69 setContentView(R.layout.main);
71 PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
72 wake_lock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "GStreamer tutorial 5");
73 wake_lock.setReferenceCounted(false);
75 ImageButton play = (ImageButton) this.findViewById(R.id.button_play);
76 play.setOnClickListener(new OnClickListener() {
77 public void onClick(View v) {
78 is_playing_desired = true;
84 ImageButton pause = (ImageButton) this.findViewById(R.id.button_stop);
85 pause.setOnClickListener(new OnClickListener() {
86 public void onClick(View v) {
87 is_playing_desired = false;
93 ImageButton select = (ImageButton) this.findViewById(R.id.button_select);
94 select.setOnClickListener(new OnClickListener() {
95 public void onClick(View v) {
96 Intent i = new Intent(getBaseContext(), FileDialog.class);
97 i.putExtra(FileDialog.START_PATH, last_folder);
98 startActivityForResult(i, PICK_FILE_CODE);
102 SurfaceView sv = (SurfaceView) this.findViewById(R.id.surface_video);
103 SurfaceHolder sh = sv.getHolder();
104 sh.addCallback(this);
106 SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar);
107 sb.setOnSeekBarChangeListener(this);
109 // Retrieve our previous state, or initialize it to default values
110 if (savedInstanceState != null) {
111 is_playing_desired = savedInstanceState.getBoolean("playing");
112 position = savedInstanceState.getInt("position");
113 duration = savedInstanceState.getInt("duration");
114 mediaUri = savedInstanceState.getString("mediaUri");
115 last_folder = savedInstanceState.getString("last_folder");
116 Log.i ("GStreamer", "Activity created with saved state:");
118 is_playing_desired = false;
119 position = duration = 0;
120 last_folder = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES).getAbsolutePath();
121 Intent intent = getIntent();
122 android.net.Uri uri = intent.getData();
124 mediaUri = defaultMediaUri;
126 Log.i ("GStreamer", "Received URI: " + uri);
127 if (uri.getScheme().equals("content")) {
128 android.database.Cursor cursor = getContentResolver().query(uri, null, null, null, null);
129 cursor.moveToFirst();
130 mediaUri = "file://" + cursor.getString(cursor.getColumnIndex(android.provider.MediaStore.Video.Media.DATA));
133 mediaUri = uri.toString();
135 Log.i ("GStreamer", "Activity created with no saved state:");
137 is_local_media = false;
138 Log.i ("GStreamer", " playing:" + is_playing_desired + " position:" + position +
139 " duration: " + duration + " uri: " + mediaUri);
141 // Start with disabled buttons, until native code is initialized
142 this.findViewById(R.id.button_play).setEnabled(false);
143 this.findViewById(R.id.button_stop).setEnabled(false);
148 protected void onSaveInstanceState (Bundle outState) {
149 Log.d ("GStreamer", "Saving state, playing:" + is_playing_desired + " position:" + position +
150 " duration: " + duration + " uri: " + mediaUri);
151 outState.putBoolean("playing", is_playing_desired);
152 outState.putInt("position", position);
153 outState.putInt("duration", duration);
154 outState.putString("mediaUri", mediaUri);
155 outState.putString("last_folder", last_folder);
158 protected void onDestroy() {
160 if (wake_lock.isHeld())
165 // Called from native code. This sets the content of the TextView from the UI thread.
166 private void setMessage(final String message) {
167 final TextView tv = (TextView) this.findViewById(R.id.textview_message);
168 runOnUiThread (new Runnable() {
175 // Set the URI to play, and record whether it is a local or remote file
176 private void setMediaUri() {
177 nativeSetUri (mediaUri);
178 is_local_media = mediaUri.startsWith("file://");
181 // Called from native code. Native code calls this once it has created its pipeline and
182 // the main loop is running, so it is ready to accept commands.
183 private void onGStreamerInitialized () {
184 Log.i ("GStreamer", "GStreamer initialized:");
185 Log.i ("GStreamer", " playing:" + is_playing_desired + " position:" + position + " uri: " + mediaUri);
187 // Restore previous playing state
189 nativeSetPosition (position);
190 if (is_playing_desired) {
198 // Re-enable buttons, now that GStreamer is initialized
199 final Activity activity = this;
200 runOnUiThread(new Runnable() {
202 activity.findViewById(R.id.button_play).setEnabled(true);
203 activity.findViewById(R.id.button_stop).setEnabled(true);
208 // The text widget acts as an slave for the seek bar, so it reflects what the seek bar shows, whether
209 // it is an actual pipeline position or the position the user is currently dragging to.
210 private void updateTimeWidget () {
211 TextView tv = (TextView) this.findViewById(R.id.textview_time);
212 SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar);
213 int pos = sb.getProgress();
215 SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
216 df.setTimeZone(TimeZone.getTimeZone("UTC"));
217 String message = df.format(new Date (pos)) + " / " + df.format(new Date (duration));
221 // Called from native code
222 private void setCurrentPosition(final int position, final int duration) {
223 final SeekBar sb = (SeekBar) this.findViewById(R.id.seek_bar);
225 // Ignore position messages from the pipeline if the seek bar is being dragged
226 if (sb.isPressed()) return;
228 runOnUiThread (new Runnable() {
231 sb.setProgress(position);
233 sb.setEnabled(duration != 0);
236 this.position = position;
237 this.duration = duration;
241 System.loadLibrary("gstreamer_android");
242 System.loadLibrary("tutorial-5");
246 public void surfaceChanged(SurfaceHolder holder, int format, int width,
248 Log.d("GStreamer", "Surface changed to format " + format + " width "
249 + width + " height " + height);
250 nativeSurfaceInit (holder.getSurface());
253 public void surfaceCreated(SurfaceHolder holder) {
254 Log.d("GStreamer", "Surface created: " + holder.getSurface());
257 public void surfaceDestroyed(SurfaceHolder holder) {
258 Log.d("GStreamer", "Surface destroyed");
259 nativeSurfaceFinalize ();
262 // Called from native code when the size of the media changes or is first detected.
263 // Inform the video surface about the new size and recalculate the layout.
264 private void onMediaSizeChanged (int width, int height) {
265 Log.i ("GStreamer", "Media size changed to " + width + "x" + height);
266 final GStreamerSurfaceView gsv = (GStreamerSurfaceView) this.findViewById(R.id.surface_video);
267 gsv.media_width = width;
268 gsv.media_height = height;
269 runOnUiThread(new Runnable() {
276 // The Seek Bar thumb has moved, either because the user dragged it or we have called setProgress()
277 public void onProgressChanged(SeekBar sb, int progress, boolean fromUser) {
278 if (fromUser == false) return;
279 desired_position = progress;
280 // If this is a local file, allow scrub seeking, this is, seek as soon as the slider is moved.
281 if (is_local_media) nativeSetPosition(desired_position);
285 // The user started dragging the Seek Bar thumb
286 public void onStartTrackingTouch(SeekBar sb) {
290 // The user released the Seek Bar thumb
291 public void onStopTrackingTouch(SeekBar sb) {
292 // If this is a remote file, scrub seeking is probably not going to work smoothly enough.
293 // Therefore, perform only the seek when the slider is released.
294 if (!is_local_media) nativeSetPosition(desired_position);
295 if (is_playing_desired) nativePlay();
299 protected void onActivityResult(int requestCode, int resultCode, Intent data)
301 if (resultCode == RESULT_OK && requestCode == PICK_FILE_CODE) {
302 mediaUri = "file://" + data.getStringExtra(FileDialog.RESULT_PATH);
304 last_folder = new File (data.getStringExtra(FileDialog.RESULT_PATH)).getParent();
305 Log.i("GStreamer", "Setting last_folder to " + last_folder);