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