Home | History | Annotate | Download | only in nativemedia
      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