Home | History | Annotate | Download | only in nativecodec
      1 /*
      2  * Copyright (C) 2014 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.nativecodec;
     18 
     19 import android.app.Activity;
     20 import android.graphics.SurfaceTexture;
     21 import android.os.Bundle;
     22 import android.util.Log;
     23 import android.view.Surface;
     24 import android.view.SurfaceHolder;
     25 import android.view.SurfaceView;
     26 import android.view.View;
     27 import android.widget.AdapterView;
     28 import android.widget.ArrayAdapter;
     29 import android.widget.Button;
     30 import android.widget.CompoundButton;
     31 import android.widget.CompoundButton.OnCheckedChangeListener;
     32 import android.widget.RadioButton;
     33 import android.widget.Spinner;
     34 
     35 import java.io.IOException;
     36 
     37 public class NativeCodec extends Activity {
     38     static final String TAG = "NativeCodec";
     39 
     40     String mSourceString = null;
     41 
     42     SurfaceView mSurfaceView1;
     43     SurfaceHolder mSurfaceHolder1;
     44 
     45     VideoSink mSelectedVideoSink;
     46     VideoSink mNativeCodecPlayerVideoSink;
     47 
     48     SurfaceHolderVideoSink mSurfaceHolder1VideoSink;
     49     GLViewVideoSink mGLView1VideoSink;
     50 
     51     boolean mCreated = false;
     52     boolean mIsPlaying = false;
     53 
     54     /** Called when the activity is first created. */
     55     @Override
     56     public void onCreate(Bundle icicle) {
     57         super.onCreate(icicle);
     58         setContentView(R.layout.main);
     59 
     60         mGLView1 = (MyGLSurfaceView) findViewById(R.id.glsurfaceview1);
     61 
     62         // set up the Surface 1 video sink
     63         mSurfaceView1 = (SurfaceView) findViewById(R.id.surfaceview1);
     64         mSurfaceHolder1 = mSurfaceView1.getHolder();
     65 
     66         mSurfaceHolder1.addCallback(new SurfaceHolder.Callback() {
     67 
     68             @Override
     69             public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
     70                 Log.v(TAG, "surfaceChanged format=" + format + ", width=" + width + ", height="
     71                         + height);
     72             }
     73 
     74             @Override
     75             public void surfaceCreated(SurfaceHolder holder) {
     76                 Log.v(TAG, "surfaceCreated");
     77                 if (mRadio1.isChecked()) {
     78                     setSurface(holder.getSurface());
     79                 }
     80             }
     81 
     82             @Override
     83             public void surfaceDestroyed(SurfaceHolder holder) {
     84                 Log.v(TAG, "surfaceDestroyed");
     85             }
     86 
     87         });
     88 
     89         // initialize content source spinner
     90         Spinner sourceSpinner = (Spinner) findViewById(R.id.source_spinner);
     91         ArrayAdapter<CharSequence> sourceAdapter = ArrayAdapter.createFromResource(
     92                 this, R.array.source_array, android.R.layout.simple_spinner_item);
     93         sourceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
     94         sourceSpinner.setAdapter(sourceAdapter);
     95         sourceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
     96 
     97             @Override
     98             public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
     99                 mSourceString = parent.getItemAtPosition(pos).toString();
    100                 Log.v(TAG, "onItemSelected " + mSourceString);
    101             }
    102 
    103             @Override
    104             public void onNothingSelected(AdapterView parent) {
    105                 Log.v(TAG, "onNothingSelected");
    106                 mSourceString = null;
    107             }
    108 
    109         });
    110 
    111         mRadio1 = (RadioButton) findViewById(R.id.radio1);
    112         mRadio2 = (RadioButton) findViewById(R.id.radio2);
    113 
    114         OnCheckedChangeListener checklistener = new CompoundButton.OnCheckedChangeListener() {
    115 
    116           @Override
    117           public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
    118               Log.i("@@@@", "oncheckedchanged");
    119               if (buttonView == mRadio1 && isChecked) {
    120                   mRadio2.setChecked(false);
    121               }
    122               if (buttonView == mRadio2 && isChecked) {
    123                   mRadio1.setChecked(false);
    124               }
    125               if (isChecked) {
    126                   if (mRadio1.isChecked()) {
    127                       if (mSurfaceHolder1VideoSink == null) {
    128                           mSurfaceHolder1VideoSink = new SurfaceHolderVideoSink(mSurfaceHolder1);
    129                       }
    130                       mSelectedVideoSink = mSurfaceHolder1VideoSink;
    131                       mGLView1.onPause();
    132                       Log.i("@@@@", "glview pause");
    133                   } else {
    134                       mGLView1.onResume();
    135                       if (mGLView1VideoSink == null) {
    136                           mGLView1VideoSink = new GLViewVideoSink(mGLView1);
    137                       }
    138                       mSelectedVideoSink = mGLView1VideoSink;
    139                   }
    140                   switchSurface();
    141               }
    142           }
    143         };
    144         mRadio1.setOnCheckedChangeListener(checklistener);
    145         mRadio2.setOnCheckedChangeListener(checklistener);
    146         mRadio2.toggle();
    147 
    148         // the surfaces themselves are easier targets than the radio buttons
    149         mSurfaceView1.setOnClickListener(new View.OnClickListener() {
    150             @Override
    151             public void onClick(View v) {
    152                 mRadio1.toggle();
    153             }
    154         });
    155         mGLView1.setOnClickListener(new View.OnClickListener() {
    156             @Override
    157             public void onClick(View v) {
    158                 mRadio2.toggle();
    159             }
    160       });
    161 
    162         // initialize button click handlers
    163 
    164         // native MediaPlayer start/pause
    165         ((Button) findViewById(R.id.start_native)).setOnClickListener(new View.OnClickListener() {
    166 
    167             @Override
    168             public void onClick(View view) {
    169                 if (!mCreated) {
    170                     if (mNativeCodecPlayerVideoSink == null) {
    171                         if (mSelectedVideoSink == null) {
    172                             return;
    173                         }
    174                         mSelectedVideoSink.useAsSinkForNative();
    175                         mNativeCodecPlayerVideoSink = mSelectedVideoSink;
    176                     }
    177                     if (mSourceString != null) {
    178                         mCreated = createStreamingMediaPlayer(mSourceString);
    179                     }
    180                 }
    181                 if (mCreated) {
    182                     mIsPlaying = !mIsPlaying;
    183                     setPlayingStreamingMediaPlayer(mIsPlaying);
    184                 }
    185             }
    186 
    187         });
    188 
    189 
    190         // native MediaPlayer rewind
    191         ((Button) findViewById(R.id.rewind_native)).setOnClickListener(new View.OnClickListener() {
    192 
    193             @Override
    194             public void onClick(View view) {
    195                 if (mNativeCodecPlayerVideoSink != null) {
    196                     rewindStreamingMediaPlayer();
    197                 }
    198             }
    199 
    200         });
    201 
    202     }
    203 
    204     void switchSurface() {
    205         if (mCreated && mNativeCodecPlayerVideoSink != mSelectedVideoSink) {
    206             // shutdown and recreate on other surface
    207           Log.i("@@@", "shutting down player");
    208             shutdown();
    209             mCreated = false;
    210             mSelectedVideoSink.useAsSinkForNative();
    211             mNativeCodecPlayerVideoSink = mSelectedVideoSink;
    212             if (mSourceString != null) {
    213                 Log.i("@@@", "recreating player");
    214                 mCreated = createStreamingMediaPlayer(mSourceString);
    215                 mIsPlaying = false;
    216             }
    217         }
    218     }
    219 
    220     /** Called when the activity is about to be paused. */
    221     @Override
    222     protected void onPause()
    223     {
    224         mIsPlaying = false;
    225         setPlayingStreamingMediaPlayer(false);
    226         mGLView1.onPause();
    227         super.onPause();
    228     }
    229 
    230     @Override
    231     protected void onResume() {
    232         super.onResume();
    233         if (mRadio2.isChecked()) {
    234             mGLView1.onResume();
    235         }
    236     }
    237 
    238     /** Called when the activity is about to be destroyed. */
    239     @Override
    240     protected void onDestroy()
    241     {
    242         shutdown();
    243         mCreated = false;
    244         super.onDestroy();
    245     }
    246 
    247     private MyGLSurfaceView mGLView1;
    248 
    249     private RadioButton mRadio1;
    250 
    251     private RadioButton mRadio2;
    252 
    253     /** Native methods, implemented in jni folder */
    254     public static native void createEngine();
    255     public static native boolean createStreamingMediaPlayer(String filename);
    256     public static native void setPlayingStreamingMediaPlayer(boolean isPlaying);
    257     public static native void shutdown();
    258     public static native void setSurface(Surface surface);
    259     public static native void rewindStreamingMediaPlayer();
    260 
    261     /** Load jni .so on initialization */
    262     static {
    263          System.loadLibrary("native-codec-jni");
    264     }
    265 
    266     // VideoSink abstracts out the difference between Surface and SurfaceTexture
    267     // aka SurfaceHolder and GLSurfaceView
    268     static abstract class VideoSink {
    269 
    270         abstract void setFixedSize(int width, int height);
    271         abstract void useAsSinkForNative();
    272 
    273     }
    274 
    275     static class SurfaceHolderVideoSink extends VideoSink {
    276 
    277         private final SurfaceHolder mSurfaceHolder;
    278 
    279         SurfaceHolderVideoSink(SurfaceHolder surfaceHolder) {
    280             mSurfaceHolder = surfaceHolder;
    281         }
    282 
    283         @Override
    284         void setFixedSize(int width, int height) {
    285             mSurfaceHolder.setFixedSize(width, height);
    286         }
    287 
    288         @Override
    289         void useAsSinkForNative() {
    290             Surface s = mSurfaceHolder.getSurface();
    291             Log.i("@@@", "setting surface " + s);
    292             setSurface(s);
    293         }
    294 
    295     }
    296 
    297     static class GLViewVideoSink extends VideoSink {
    298 
    299         private final MyGLSurfaceView mMyGLSurfaceView;
    300 
    301         GLViewVideoSink(MyGLSurfaceView myGLSurfaceView) {
    302             mMyGLSurfaceView = myGLSurfaceView;
    303         }
    304 
    305         @Override
    306         void setFixedSize(int width, int height) {
    307         }
    308 
    309         @Override
    310         void useAsSinkForNative() {
    311             SurfaceTexture st = mMyGLSurfaceView.getSurfaceTexture();
    312             Surface s = new Surface(st);
    313             setSurface(s);
    314             s.release();
    315         }
    316 
    317     }
    318 
    319 }
    320