/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.nativemedia;
import android.app.Activity;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Spinner;
import java.io.IOException;
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaPlayer;
public class NativeMedia extends Activity {
static final String TAG = "NativeMedia";
String mSourceString = null;
String mSinkString = null;
// member variables for Java media player
MediaPlayer mMediaPlayer;
boolean mMediaPlayerIsPrepared = false;
SurfaceView mSurfaceView1;
SurfaceHolder mSurfaceHolder1;
// member variables for native media player
boolean mIsPlayingStreaming = false;
SurfaceView mSurfaceView2;
SurfaceHolder mSurfaceHolder2;
VideoSink mSelectedVideoSink;
VideoSink mJavaMediaPlayerVideoSink;
VideoSink mNativeMediaPlayerVideoSink;
SurfaceHolderVideoSink mSurfaceHolder1VideoSink, mSurfaceHolder2VideoSink;
GLViewVideoSink mGLView1VideoSink, mGLView2VideoSink;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
mGLView1 = (MyGLSurfaceView) findViewById(R.id.glsurfaceview1);
mGLView2 = (MyGLSurfaceView) findViewById(R.id.glsurfaceview2);
//setContentView(mGLView);
//setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// initialize native media system
createEngine();
// set up the Surface 1 video sink
mSurfaceView1 = (SurfaceView) findViewById(R.id.surfaceview1);
mSurfaceHolder1 = mSurfaceView1.getHolder();
mSurfaceHolder1.addCallback(new SurfaceHolder.Callback() {
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.v(TAG, "surfaceChanged format=" + format + ", width=" + width + ", height=" +
height);
}
public void surfaceCreated(SurfaceHolder holder) {
Log.v(TAG, "surfaceCreated");
setSurface(holder.getSurface());
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.v(TAG, "surfaceDestroyed");
}
});
// set up the Surface 2 video sink
mSurfaceView2 = (SurfaceView) findViewById(R.id.surfaceview2);
mSurfaceHolder2 = mSurfaceView2.getHolder();
mSurfaceHolder2.addCallback(new SurfaceHolder.Callback() {
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.v(TAG, "surfaceChanged format=" + format + ", width=" + width + ", height=" +
height);
}
public void surfaceCreated(SurfaceHolder holder) {
Log.v(TAG, "surfaceCreated");
setSurface(holder.getSurface());
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.v(TAG, "surfaceDestroyed");
}
});
// create Java media player
mMediaPlayer = new MediaPlayer();
// set up Java media player listeners
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mediaPlayer) {
int width = mediaPlayer.getVideoWidth();
int height = mediaPlayer.getVideoHeight();
Log.v(TAG, "onPrepared width=" + width + ", height=" + height);
if (width != 0 && height != 0 && mJavaMediaPlayerVideoSink != null) {
mJavaMediaPlayerVideoSink.setFixedSize(width, height);
}
mMediaPlayerIsPrepared = true;
mediaPlayer.start();
}
});
mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
public void onVideoSizeChanged(MediaPlayer mediaPlayer, int width, int height) {
Log.v(TAG, "onVideoSizeChanged width=" + width + ", height=" + height);
if (width != 0 && height != 0 && mJavaMediaPlayerVideoSink != null) {
mJavaMediaPlayerVideoSink.setFixedSize(width, height);
}
}
});
// initialize content source spinner
Spinner sourceSpinner = (Spinner) findViewById(R.id.source_spinner);
ArrayAdapter<CharSequence> sourceAdapter = ArrayAdapter.createFromResource(
this, R.array.source_array, android.R.layout.simple_spinner_item);
sourceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
sourceSpinner.setAdapter(sourceAdapter);
sourceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
mSourceString = parent.getItemAtPosition(pos).toString();
Log.v(TAG, "onItemSelected " + mSourceString);
}
public void onNothingSelected(AdapterView parent) {
Log.v(TAG, "onNothingSelected");
mSourceString = null;
}
});
// initialize video sink spinner
Spinner sinkSpinner = (Spinner) findViewById(R.id.sink_spinner);
ArrayAdapter<CharSequence> sinkAdapter = ArrayAdapter.createFromResource(
this, R.array.sink_array, android.R.layout.simple_spinner_item);
sinkAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
sinkSpinner.setAdapter(sinkAdapter);
sinkSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
mSinkString = parent.getItemAtPosition(pos).toString();
Log.v(TAG, "onItemSelected " + mSinkString);
if ("Surface 1".equals(mSinkString)) {
if (mSurfaceHolder1VideoSink == null) {
mSurfaceHolder1VideoSink = new SurfaceHolderVideoSink(mSurfaceHolder1);
}
mSelectedVideoSink = mSurfaceHolder1VideoSink;
} else if ("Surface 2".equals(mSinkString)) {
if (mSurfaceHolder2VideoSink == null) {
mSurfaceHolder2VideoSink = new SurfaceHolderVideoSink(mSurfaceHolder2);
}
mSelectedVideoSink = mSurfaceHolder2VideoSink;
} else if ("SurfaceTexture 1".equals(mSinkString)) {
if (mGLView1VideoSink == null) {
mGLView1VideoSink = new GLViewVideoSink(mGLView1);
}
mSelectedVideoSink = mGLView1VideoSink;
} else if ("SurfaceTexture 2".equals(mSinkString)) {
if (mGLView2VideoSink == null) {
mGLView2VideoSink = new GLViewVideoSink(mGLView2);
}
mSelectedVideoSink = mGLView2VideoSink;
}
}
public void onNothingSelected(AdapterView parent) {
Log.v(TAG, "onNothingSelected");
mSinkString = null;
mSelectedVideoSink = null;
}
});
// initialize button click handlers
// Java MediaPlayer start/pause
((Button) findViewById(R.id.start_java)).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (mJavaMediaPlayerVideoSink == null) {
if (mSelectedVideoSink == null) {
return;
}
mSelectedVideoSink.useAsSinkForJava(mMediaPlayer);
mJavaMediaPlayerVideoSink = mSelectedVideoSink;
}
if (!mMediaPlayerIsPrepared) {
if (mSourceString != null) {
try {
mMediaPlayer.setDataSource(mSourceString);
} catch (IOException e) {
Log.e(TAG, "IOException " + e);
}
mMediaPlayer.prepareAsync();
}
} else if (mMediaPlayer.isPlaying()) {
mMediaPlayer.pause();
} else {
mMediaPlayer.start();
}
}
});
// native MediaPlayer start/pause
((Button) findViewById(R.id.start_native)).setOnClickListener(new View.OnClickListener() {
boolean created = false;
public void onClick(View view) {
if (!created) {
if (mNativeMediaPlayerVideoSink == null) {
if (mSelectedVideoSink == null) {
return;
}
mSelectedVideoSink.useAsSinkForNative();
mNativeMediaPlayerVideoSink = mSelectedVideoSink;
}
if (mSourceString != null) {
created = createStreamingMediaPlayer(mSourceString);
}
}
if (created) {
mIsPlayingStreaming = !mIsPlayingStreaming;
setPlayingStreamingMediaPlayer(mIsPlayingStreaming);
}
}
});
// Java MediaPlayer rewind
((Button) findViewById(R.id.rewind_java)).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (mMediaPlayerIsPrepared) {
mMediaPlayer.seekTo(0);
}
}
});
// native MediaPlayer rewind
((Button) findViewById(R.id.rewind_native)).setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if (mNativeMediaPlayerVideoSink != null) {
rewindStreamingMediaPlayer();
}
}
});
}
/** Called when the activity is about to be paused. */
@Override
protected void onPause()
{
mIsPlayingStreaming = false;
setPlayingStreamingMediaPlayer(false);
mGLView1.onPause();
mGLView2.onPause();
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
mGLView1.onResume();
mGLView2.onResume();
}
/** Called when the activity is about to be destroyed. */
@Override
protected void onDestroy()
{
shutdown();
super.onDestroy();
}
private MyGLSurfaceView mGLView1, mGLView2;
/** Native methods, implemented in jni folder */
public static native void createEngine();
public static native boolean createStreamingMediaPlayer(String filename);
public static native void setPlayingStreamingMediaPlayer(boolean isPlaying);
public static native void shutdown();
public static native void setSurface(Surface surface);
public static native void rewindStreamingMediaPlayer();
/** Load jni .so on initialization */
static {
System.loadLibrary("native-media-jni");
}
// VideoSink abstracts out the difference between Surface and SurfaceTexture
// aka SurfaceHolder and GLSurfaceView
static abstract class VideoSink {
abstract void setFixedSize(int width, int height);
abstract void useAsSinkForJava(MediaPlayer mediaPlayer);
abstract void useAsSinkForNative();
}
static class SurfaceHolderVideoSink extends VideoSink {
private final SurfaceHolder mSurfaceHolder;
SurfaceHolderVideoSink(SurfaceHolder surfaceHolder) {
mSurfaceHolder = surfaceHolder;
}
void setFixedSize(int width, int height) {
mSurfaceHolder.setFixedSize(width, height);
}
void useAsSinkForJava(MediaPlayer mediaPlayer) {
mediaPlayer.setDisplay(mSurfaceHolder);
}
void useAsSinkForNative() {
setSurface(mSurfaceHolder.getSurface());
}
}
static class GLViewVideoSink extends VideoSink {
private final MyGLSurfaceView mMyGLSurfaceView;
GLViewVideoSink(MyGLSurfaceView myGLSurfaceView) {
mMyGLSurfaceView = myGLSurfaceView;
}
void setFixedSize(int width, int height) {
}
void useAsSinkForJava(MediaPlayer mediaPlayer) {
SurfaceTexture st = mMyGLSurfaceView.getSurfaceTexture();
Surface s = new Surface(st);
mediaPlayer.setSurface(s);
s.release();
}
void useAsSinkForNative() {
Surface surface = new Surface(mMyGLSurfaceView.getSurfaceTexture());
setSurface(surface);
surface.release();
}
}
}