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 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