1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.nativemedia; 18 19 import android.app.Activity; 20 import android.graphics.SurfaceTexture; 21 import android.media.MediaPlayer; 22 import android.os.Bundle; 23 import android.util.Log; 24 import android.view.Surface; 25 import android.view.SurfaceHolder; 26 import android.view.SurfaceView; 27 import android.view.View; 28 import android.widget.AdapterView; 29 import android.widget.ArrayAdapter; 30 import android.widget.Button; 31 import android.widget.Spinner; 32 import java.io.IOException; 33 34 import android.content.Context; 35 36 import android.graphics.SurfaceTexture; 37 38 import android.media.MediaPlayer.OnPreparedListener; 39 import android.media.MediaPlayer; 40 41 public class NativeMedia extends Activity { 42 static final String TAG = "NativeMedia"; 43 44 String mSourceString = null; 45 String mSinkString = null; 46 47 // member variables for Java media player 48 MediaPlayer mMediaPlayer; 49 boolean mMediaPlayerIsPrepared = false; 50 SurfaceView mSurfaceView1; 51 SurfaceHolder mSurfaceHolder1; 52 53 // member variables for native media player 54 boolean mIsPlayingStreaming = false; 55 SurfaceView mSurfaceView2; 56 SurfaceHolder mSurfaceHolder2; 57 58 VideoSink mSelectedVideoSink; 59 VideoSink mJavaMediaPlayerVideoSink; 60 VideoSink mNativeMediaPlayerVideoSink; 61 62 SurfaceHolderVideoSink mSurfaceHolder1VideoSink, mSurfaceHolder2VideoSink; 63 GLViewVideoSink mGLView1VideoSink, mGLView2VideoSink; 64 65 /** Called when the activity is first created. */ 66 @Override 67 public void onCreate(Bundle icicle) { 68 super.onCreate(icicle); 69 setContentView(R.layout.main); 70 71 mGLView1 = (MyGLSurfaceView) findViewById(R.id.glsurfaceview1); 72 mGLView2 = (MyGLSurfaceView) findViewById(R.id.glsurfaceview2); 73 74 //setContentView(mGLView); 75 //setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); 76 77 // initialize native media system 78 createEngine(); 79 80 // set up the Surface 1 video sink 81 mSurfaceView1 = (SurfaceView) findViewById(R.id.surfaceview1); 82 mSurfaceHolder1 = mSurfaceView1.getHolder(); 83 84 mSurfaceHolder1.addCallback(new SurfaceHolder.Callback() { 85 86 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 87 Log.v(TAG, "surfaceChanged format=" + format + ", width=" + width + ", height=" + 88 height); 89 } 90 91 public void surfaceCreated(SurfaceHolder holder) { 92 Log.v(TAG, "surfaceCreated"); 93 setSurface(holder.getSurface()); 94 } 95 96 public void surfaceDestroyed(SurfaceHolder holder) { 97 Log.v(TAG, "surfaceDestroyed"); 98 } 99 100 }); 101 102 // set up the Surface 2 video sink 103 mSurfaceView2 = (SurfaceView) findViewById(R.id.surfaceview2); 104 mSurfaceHolder2 = mSurfaceView2.getHolder(); 105 106 mSurfaceHolder2.addCallback(new SurfaceHolder.Callback() { 107 108 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 109 Log.v(TAG, "surfaceChanged format=" + format + ", width=" + width + ", height=" + 110 height); 111 } 112 113 public void surfaceCreated(SurfaceHolder holder) { 114 Log.v(TAG, "surfaceCreated"); 115 setSurface(holder.getSurface()); 116 } 117 118 public void surfaceDestroyed(SurfaceHolder holder) { 119 Log.v(TAG, "surfaceDestroyed"); 120 } 121 122 }); 123 124 // create Java media player 125 mMediaPlayer = new MediaPlayer(); 126 127 // set up Java media player listeners 128 mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 129 130 public void onPrepared(MediaPlayer mediaPlayer) { 131 int width = mediaPlayer.getVideoWidth(); 132 int height = mediaPlayer.getVideoHeight(); 133 Log.v(TAG, "onPrepared width=" + width + ", height=" + height); 134 if (width != 0 && height != 0 && mJavaMediaPlayerVideoSink != null) { 135 mJavaMediaPlayerVideoSink.setFixedSize(width, height); 136 } 137 mMediaPlayerIsPrepared = true; 138 mediaPlayer.start(); 139 } 140 141 }); 142 143 mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() { 144 145 public void onVideoSizeChanged(MediaPlayer mediaPlayer, int width, int height) { 146 Log.v(TAG, "onVideoSizeChanged width=" + width + ", height=" + height); 147 if (width != 0 && height != 0 && mJavaMediaPlayerVideoSink != null) { 148 mJavaMediaPlayerVideoSink.setFixedSize(width, height); 149 } 150 } 151 152 }); 153 154 // initialize content source spinner 155 Spinner sourceSpinner = (Spinner) findViewById(R.id.source_spinner); 156 ArrayAdapter<CharSequence> sourceAdapter = ArrayAdapter.createFromResource( 157 this, R.array.source_array, android.R.layout.simple_spinner_item); 158 sourceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 159 sourceSpinner.setAdapter(sourceAdapter); 160 sourceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 161 162 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 163 mSourceString = parent.getItemAtPosition(pos).toString(); 164 Log.v(TAG, "onItemSelected " + mSourceString); 165 } 166 167 public void onNothingSelected(AdapterView parent) { 168 Log.v(TAG, "onNothingSelected"); 169 mSourceString = null; 170 } 171 172 }); 173 174 // initialize video sink spinner 175 Spinner sinkSpinner = (Spinner) findViewById(R.id.sink_spinner); 176 ArrayAdapter<CharSequence> sinkAdapter = ArrayAdapter.createFromResource( 177 this, R.array.sink_array, android.R.layout.simple_spinner_item); 178 sinkAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 179 sinkSpinner.setAdapter(sinkAdapter); 180 sinkSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 181 182 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 183 mSinkString = parent.getItemAtPosition(pos).toString(); 184 Log.v(TAG, "onItemSelected " + mSinkString); 185 if ("Surface 1".equals(mSinkString)) { 186 if (mSurfaceHolder1VideoSink == null) { 187 mSurfaceHolder1VideoSink = new SurfaceHolderVideoSink(mSurfaceHolder1); 188 } 189 mSelectedVideoSink = mSurfaceHolder1VideoSink; 190 } else if ("Surface 2".equals(mSinkString)) { 191 if (mSurfaceHolder2VideoSink == null) { 192 mSurfaceHolder2VideoSink = new SurfaceHolderVideoSink(mSurfaceHolder2); 193 } 194 mSelectedVideoSink = mSurfaceHolder2VideoSink; 195 } else if ("SurfaceTexture 1".equals(mSinkString)) { 196 if (mGLView1VideoSink == null) { 197 mGLView1VideoSink = new GLViewVideoSink(mGLView1); 198 } 199 mSelectedVideoSink = mGLView1VideoSink; 200 } else if ("SurfaceTexture 2".equals(mSinkString)) { 201 if (mGLView2VideoSink == null) { 202 mGLView2VideoSink = new GLViewVideoSink(mGLView2); 203 } 204 mSelectedVideoSink = mGLView2VideoSink; 205 } 206 } 207 208 public void onNothingSelected(AdapterView parent) { 209 Log.v(TAG, "onNothingSelected"); 210 mSinkString = null; 211 mSelectedVideoSink = null; 212 } 213 214 }); 215 216 // initialize button click handlers 217 218 // Java MediaPlayer start/pause 219 220 ((Button) findViewById(R.id.start_java)).setOnClickListener(new View.OnClickListener() { 221 222 public void onClick(View view) { 223 if (mJavaMediaPlayerVideoSink == null) { 224 if (mSelectedVideoSink == null) { 225 return; 226 } 227 mSelectedVideoSink.useAsSinkForJava(mMediaPlayer); 228 mJavaMediaPlayerVideoSink = mSelectedVideoSink; 229 } 230 if (!mMediaPlayerIsPrepared) { 231 if (mSourceString != null) { 232 try { 233 mMediaPlayer.setDataSource(mSourceString); 234 } catch (IOException e) { 235 Log.e(TAG, "IOException " + e); 236 } 237 mMediaPlayer.prepareAsync(); 238 } 239 } else if (mMediaPlayer.isPlaying()) { 240 mMediaPlayer.pause(); 241 } else { 242 mMediaPlayer.start(); 243 } 244 } 245 246 }); 247 248 // native MediaPlayer start/pause 249 250 ((Button) findViewById(R.id.start_native)).setOnClickListener(new View.OnClickListener() { 251 252 boolean created = false; 253 public void onClick(View view) { 254 if (!created) { 255 if (mNativeMediaPlayerVideoSink == null) { 256 if (mSelectedVideoSink == null) { 257 return; 258 } 259 mSelectedVideoSink.useAsSinkForNative(); 260 mNativeMediaPlayerVideoSink = mSelectedVideoSink; 261 } 262 if (mSourceString != null) { 263 created = createStreamingMediaPlayer(mSourceString); 264 } 265 } 266 if (created) { 267 mIsPlayingStreaming = !mIsPlayingStreaming; 268 setPlayingStreamingMediaPlayer(mIsPlayingStreaming); 269 } 270 } 271 272 }); 273 274 // Java MediaPlayer rewind 275 276 ((Button) findViewById(R.id.rewind_java)).setOnClickListener(new View.OnClickListener() { 277 278 public void onClick(View view) { 279 if (mMediaPlayerIsPrepared) { 280 mMediaPlayer.seekTo(0); 281 } 282 } 283 284 }); 285 286 // native MediaPlayer rewind 287 288 ((Button) findViewById(R.id.rewind_native)).setOnClickListener(new View.OnClickListener() { 289 290 public void onClick(View view) { 291 if (mNativeMediaPlayerVideoSink != null) { 292 rewindStreamingMediaPlayer(); 293 } 294 } 295 296 }); 297 298 } 299 300 /** Called when the activity is about to be paused. */ 301 @Override 302 protected void onPause() 303 { 304 mIsPlayingStreaming = false; 305 setPlayingStreamingMediaPlayer(false); 306 mGLView1.onPause(); 307 mGLView2.onPause(); 308 super.onPause(); 309 } 310 311 @Override 312 protected void onResume() { 313 super.onResume(); 314 mGLView1.onResume(); 315 mGLView2.onResume(); 316 } 317 318 /** Called when the activity is about to be destroyed. */ 319 @Override 320 protected void onDestroy() 321 { 322 shutdown(); 323 super.onDestroy(); 324 } 325 326 private MyGLSurfaceView mGLView1, mGLView2; 327 328 /** Native methods, implemented in jni folder */ 329 public static native void createEngine(); 330 public static native boolean createStreamingMediaPlayer(String filename); 331 public static native void setPlayingStreamingMediaPlayer(boolean isPlaying); 332 public static native void shutdown(); 333 public static native void setSurface(Surface surface); 334 public static native void rewindStreamingMediaPlayer(); 335 336 /** Load jni .so on initialization */ 337 static { 338 System.loadLibrary("native-media-jni"); 339 } 340 341 // VideoSink abstracts out the difference between Surface and SurfaceTexture 342 // aka SurfaceHolder and GLSurfaceView 343 static abstract class VideoSink { 344 345 abstract void setFixedSize(int width, int height); 346 abstract void useAsSinkForJava(MediaPlayer mediaPlayer); 347 abstract void useAsSinkForNative(); 348 349 } 350 351 static class SurfaceHolderVideoSink extends VideoSink { 352 353 private final SurfaceHolder mSurfaceHolder; 354 355 SurfaceHolderVideoSink(SurfaceHolder surfaceHolder) { 356 mSurfaceHolder = surfaceHolder; 357 } 358 359 void setFixedSize(int width, int height) { 360 mSurfaceHolder.setFixedSize(width, height); 361 } 362 363 void useAsSinkForJava(MediaPlayer mediaPlayer) { 364 mediaPlayer.setDisplay(mSurfaceHolder); 365 } 366 367 void useAsSinkForNative() { 368 setSurface(mSurfaceHolder.getSurface()); 369 } 370 371 } 372 373 static class GLViewVideoSink extends VideoSink { 374 375 private final MyGLSurfaceView mMyGLSurfaceView; 376 377 GLViewVideoSink(MyGLSurfaceView myGLSurfaceView) { 378 mMyGLSurfaceView = myGLSurfaceView; 379 } 380 381 void setFixedSize(int width, int height) { 382 } 383 384 void useAsSinkForJava(MediaPlayer mediaPlayer) { 385 SurfaceTexture st = mMyGLSurfaceView.getSurfaceTexture(); 386 Surface s = new Surface(st); 387 mediaPlayer.setSurface(s); 388 s.release(); 389 } 390 391 void useAsSinkForNative() { 392 Surface surface = new Surface(mMyGLSurfaceView.getSurfaceTexture()); 393 setSurface(surface); 394 surface.release(); 395 } 396 397 } 398 399 } 400