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 public class NativeMedia extends Activity { 35 static final String TAG = "NativeMedia"; 36 37 String mSourceString = null; 38 String mSinkString = null; 39 40 // member variables for Java media player 41 MediaPlayer mMediaPlayer; 42 boolean mMediaPlayerIsPrepared = false; 43 SurfaceView mSurfaceView1; 44 SurfaceHolder mSurfaceHolder1; 45 46 // member variables for native media player 47 boolean mIsPlayingStreaming = false; 48 SurfaceView mSurfaceView2; 49 SurfaceHolder mSurfaceHolder2; 50 51 VideoSink mSelectedVideoSink; 52 VideoSink mJavaMediaPlayerVideoSink; 53 VideoSink mNativeMediaPlayerVideoSink; 54 55 SurfaceHolderVideoSink mSurfaceHolder1VideoSink, mSurfaceHolder2VideoSink; 56 GLViewVideoSink mGLView1VideoSink, mGLView2VideoSink; 57 58 /** Called when the activity is first created. */ 59 @Override 60 public void onCreate(Bundle icicle) { 61 super.onCreate(icicle); 62 setContentView(R.layout.main); 63 64 mGLView1 = (MyGLSurfaceView) findViewById(R.id.glsurfaceview1); 65 mGLView2 = (MyGLSurfaceView) findViewById(R.id.glsurfaceview2); 66 67 // initialize native media system 68 createEngine(); 69 70 // set up the Surface 1 video sink 71 mSurfaceView1 = (SurfaceView) findViewById(R.id.surfaceview1); 72 mSurfaceHolder1 = mSurfaceView1.getHolder(); 73 74 mSurfaceHolder1.addCallback(new SurfaceHolder.Callback() { 75 76 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 77 Log.v(TAG, "surfaceChanged format=" + format + ", width=" + width + ", height=" 78 + height); 79 } 80 81 public void surfaceCreated(SurfaceHolder holder) { 82 Log.v(TAG, "surfaceCreated"); 83 setSurface(holder.getSurface()); 84 } 85 86 public void surfaceDestroyed(SurfaceHolder holder) { 87 Log.v(TAG, "surfaceDestroyed"); 88 } 89 90 }); 91 92 // set up the Surface 2 video sink 93 mSurfaceView2 = (SurfaceView) findViewById(R.id.surfaceview2); 94 mSurfaceHolder2 = mSurfaceView2.getHolder(); 95 96 mSurfaceHolder2.addCallback(new SurfaceHolder.Callback() { 97 98 public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 99 Log.v(TAG, "surfaceChanged format=" + format + ", width=" + width + ", height=" 100 + height); 101 } 102 103 public void surfaceCreated(SurfaceHolder holder) { 104 Log.v(TAG, "surfaceCreated"); 105 setSurface(holder.getSurface()); 106 } 107 108 public void surfaceDestroyed(SurfaceHolder holder) { 109 Log.v(TAG, "surfaceDestroyed"); 110 } 111 112 }); 113 114 // create Java media player 115 mMediaPlayer = new MediaPlayer(); 116 117 // set up Java media player listeners 118 mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 119 120 public void onPrepared(MediaPlayer mediaPlayer) { 121 int width = mediaPlayer.getVideoWidth(); 122 int height = mediaPlayer.getVideoHeight(); 123 Log.v(TAG, "onPrepared width=" + width + ", height=" + height); 124 if (width != 0 && height != 0 && mJavaMediaPlayerVideoSink != null) { 125 mJavaMediaPlayerVideoSink.setFixedSize(width, height); 126 } 127 mMediaPlayerIsPrepared = true; 128 mediaPlayer.start(); 129 } 130 131 }); 132 133 mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() { 134 135 public void onVideoSizeChanged(MediaPlayer mediaPlayer, int width, int height) { 136 Log.v(TAG, "onVideoSizeChanged width=" + width + ", height=" + height); 137 if (width != 0 && height != 0 && mJavaMediaPlayerVideoSink != null) { 138 mJavaMediaPlayerVideoSink.setFixedSize(width, height); 139 } 140 } 141 142 }); 143 144 // initialize content source spinner 145 Spinner sourceSpinner = (Spinner) findViewById(R.id.source_spinner); 146 ArrayAdapter<CharSequence> sourceAdapter = ArrayAdapter.createFromResource( 147 this, R.array.source_array, android.R.layout.simple_spinner_item); 148 sourceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 149 sourceSpinner.setAdapter(sourceAdapter); 150 sourceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 151 152 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 153 mSourceString = parent.getItemAtPosition(pos).toString(); 154 Log.v(TAG, "onItemSelected " + mSourceString); 155 } 156 157 public void onNothingSelected(AdapterView parent) { 158 Log.v(TAG, "onNothingSelected"); 159 mSourceString = null; 160 } 161 162 }); 163 164 // initialize video sink spinner 165 Spinner sinkSpinner = (Spinner) findViewById(R.id.sink_spinner); 166 ArrayAdapter<CharSequence> sinkAdapter = ArrayAdapter.createFromResource( 167 this, R.array.sink_array, android.R.layout.simple_spinner_item); 168 sinkAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); 169 sinkSpinner.setAdapter(sinkAdapter); 170 sinkSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { 171 172 public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) { 173 mSinkString = parent.getItemAtPosition(pos).toString(); 174 Log.v(TAG, "onItemSelected " + mSinkString); 175 if ("Surface 1".equals(mSinkString)) { 176 if (mSurfaceHolder1VideoSink == null) { 177 mSurfaceHolder1VideoSink = new SurfaceHolderVideoSink(mSurfaceHolder1); 178 } 179 mSelectedVideoSink = mSurfaceHolder1VideoSink; 180 } else if ("Surface 2".equals(mSinkString)) { 181 if (mSurfaceHolder2VideoSink == null) { 182 mSurfaceHolder2VideoSink = new SurfaceHolderVideoSink(mSurfaceHolder2); 183 } 184 mSelectedVideoSink = mSurfaceHolder2VideoSink; 185 } else if ("SurfaceTexture 1".equals(mSinkString)) { 186 if (mGLView1VideoSink == null) { 187 mGLView1VideoSink = new GLViewVideoSink(mGLView1); 188 } 189 mSelectedVideoSink = mGLView1VideoSink; 190 } else if ("SurfaceTexture 2".equals(mSinkString)) { 191 if (mGLView2VideoSink == null) { 192 mGLView2VideoSink = new GLViewVideoSink(mGLView2); 193 } 194 mSelectedVideoSink = mGLView2VideoSink; 195 } 196 } 197 198 public void onNothingSelected(AdapterView parent) { 199 Log.v(TAG, "onNothingSelected"); 200 mSinkString = null; 201 mSelectedVideoSink = null; 202 } 203 204 }); 205 206 // initialize button click handlers 207 208 // Java MediaPlayer start/pause 209 210 ((Button) findViewById(R.id.start_java)).setOnClickListener(new View.OnClickListener() { 211 212 public void onClick(View view) { 213 if (mJavaMediaPlayerVideoSink == null) { 214 if (mSelectedVideoSink == null) { 215 return; 216 } 217 mSelectedVideoSink.useAsSinkForJava(mMediaPlayer); 218 mJavaMediaPlayerVideoSink = mSelectedVideoSink; 219 } 220 if (!mMediaPlayerIsPrepared) { 221 if (mSourceString != null) { 222 try { 223 mMediaPlayer.setDataSource(mSourceString); 224 } catch (IOException e) { 225 Log.e(TAG, "IOException " + e); 226 } 227 mMediaPlayer.prepareAsync(); 228 } 229 } else if (mMediaPlayer.isPlaying()) { 230 mMediaPlayer.pause(); 231 } else { 232 mMediaPlayer.start(); 233 } 234 } 235 236 }); 237 238 // native MediaPlayer start/pause 239 240 ((Button) findViewById(R.id.start_native)).setOnClickListener(new View.OnClickListener() { 241 242 boolean created = false; 243 public void onClick(View view) { 244 if (!created) { 245 if (mNativeMediaPlayerVideoSink == null) { 246 if (mSelectedVideoSink == null) { 247 return; 248 } 249 mSelectedVideoSink.useAsSinkForNative(); 250 mNativeMediaPlayerVideoSink = mSelectedVideoSink; 251 } 252 if (mSourceString != null) { 253 created = createStreamingMediaPlayer(mSourceString); 254 } 255 } 256 if (created) { 257 mIsPlayingStreaming = !mIsPlayingStreaming; 258 setPlayingStreamingMediaPlayer(mIsPlayingStreaming); 259 } 260 } 261 262 }); 263 264 // finish 265 266 ((Button) findViewById(R.id.finish)).setOnClickListener(new View.OnClickListener() { 267 268 public void onClick(View view) { 269 finish(); 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 // Use the newer MediaPlayer.setSurface(Surface) since API level 14 365 // instead of MediaPlayer.setDisplay(mSurfaceHolder) since API level 1, 366 // because setSurface also works with a Surface derived from a SurfaceTexture. 367 Surface s = mSurfaceHolder.getSurface(); 368 mediaPlayer.setSurface(s); 369 s.release(); 370 } 371 372 void useAsSinkForNative() { 373 Surface s = mSurfaceHolder.getSurface(); 374 setSurface(s); 375 s.release(); 376 } 377 378 } 379 380 static class GLViewVideoSink extends VideoSink { 381 382 private final MyGLSurfaceView mMyGLSurfaceView; 383 384 GLViewVideoSink(MyGLSurfaceView myGLSurfaceView) { 385 mMyGLSurfaceView = myGLSurfaceView; 386 } 387 388 void setFixedSize(int width, int height) { 389 } 390 391 void useAsSinkForJava(MediaPlayer mediaPlayer) { 392 SurfaceTexture st = mMyGLSurfaceView.getSurfaceTexture(); 393 Surface s = new Surface(st); 394 mediaPlayer.setSurface(s); 395 s.release(); 396 } 397 398 void useAsSinkForNative() { 399 SurfaceTexture st = mMyGLSurfaceView.getSurfaceTexture(); 400 Surface s = new Surface(st); 401 setSurface(s); 402 s.release(); 403 } 404 405 } 406 407 } 408