• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
onCreate(Bundle icicle)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=" + height);
88             }
89 
90             public void surfaceCreated(SurfaceHolder holder) {
91                 Log.v(TAG, "surfaceCreated");
92                 setSurface(holder.getSurface());
93             }
94 
95             public void surfaceDestroyed(SurfaceHolder holder) {
96                 Log.v(TAG, "surfaceDestroyed");
97             }
98 
99         });
100 
101         // set up the Surface 2 video sink
102         mSurfaceView2 = (SurfaceView) findViewById(R.id.surfaceview2);
103         mSurfaceHolder2 = mSurfaceView2.getHolder();
104 
105         mSurfaceHolder2.addCallback(new SurfaceHolder.Callback() {
106 
107             public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
108                 Log.v(TAG, "surfaceChanged format=" + format + ", width=" + width + ", height=" + height);
109             }
110 
111             public void surfaceCreated(SurfaceHolder holder) {
112                 Log.v(TAG, "surfaceCreated");
113                 setSurface(holder.getSurface());
114             }
115 
116             public void surfaceDestroyed(SurfaceHolder holder) {
117                 Log.v(TAG, "surfaceDestroyed");
118             }
119 
120         });
121 
122         // create Java media player
123         mMediaPlayer = new MediaPlayer();
124 
125         // set up Java media player listeners
126         mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
127 
128             public void onPrepared(MediaPlayer mediaPlayer) {
129                 int width = mediaPlayer.getVideoWidth();
130                 int height = mediaPlayer.getVideoHeight();
131                 Log.v(TAG, "onPrepared width=" + width + ", height=" + height);
132                 if (width != 0 && height != 0 && mJavaMediaPlayerVideoSink != null) {
133                     mJavaMediaPlayerVideoSink.setFixedSize(width, height);
134                 }
135                 mMediaPlayerIsPrepared = true;
136                 mediaPlayer.start();
137             }
138 
139         });
140 
141         mMediaPlayer.setOnVideoSizeChangedListener(new MediaPlayer.OnVideoSizeChangedListener() {
142 
143             public void onVideoSizeChanged(MediaPlayer mediaPlayer, int width, int height) {
144                 Log.v(TAG, "onVideoSizeChanged width=" + width + ", height=" + height);
145                 if (width != 0 && height != 0 && mJavaMediaPlayerVideoSink != null) {
146                     mJavaMediaPlayerVideoSink.setFixedSize(width, height);
147                 }
148             }
149 
150         });
151 
152         // initialize content source spinner
153         Spinner sourceSpinner = (Spinner) findViewById(R.id.source_spinner);
154         ArrayAdapter<CharSequence> sourceAdapter = ArrayAdapter.createFromResource(
155                 this, R.array.source_array, android.R.layout.simple_spinner_item);
156         sourceAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
157         sourceSpinner.setAdapter(sourceAdapter);
158         sourceSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
159 
160             public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
161                 mSourceString = parent.getItemAtPosition(pos).toString();
162                 Log.v(TAG, "onItemSelected " + mSourceString);
163             }
164 
165             public void onNothingSelected(AdapterView parent) {
166                 Log.v(TAG, "onNothingSelected");
167                 mSourceString = null;
168             }
169 
170         });
171 
172         // initialize video sink spinner
173         Spinner sinkSpinner = (Spinner) findViewById(R.id.sink_spinner);
174         ArrayAdapter<CharSequence> sinkAdapter = ArrayAdapter.createFromResource(
175                 this, R.array.sink_array, android.R.layout.simple_spinner_item);
176         sinkAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
177         sinkSpinner.setAdapter(sinkAdapter);
178         sinkSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
179 
180             public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
181                 mSinkString = parent.getItemAtPosition(pos).toString();
182                 Log.v(TAG, "onItemSelected " + mSinkString);
183                 if ("Surface 1".equals(mSinkString)) {
184                     if (mSurfaceHolder1VideoSink == null) {
185                         mSurfaceHolder1VideoSink = new SurfaceHolderVideoSink(mSurfaceHolder1);
186                     }
187                     mSelectedVideoSink = mSurfaceHolder1VideoSink;
188                 } else if ("Surface 2".equals(mSinkString)) {
189                     if (mSurfaceHolder2VideoSink == null) {
190                         mSurfaceHolder2VideoSink = new SurfaceHolderVideoSink(mSurfaceHolder2);
191                     }
192                     mSelectedVideoSink = mSurfaceHolder2VideoSink;
193                 } else if ("SurfaceTexture 1".equals(mSinkString)) {
194                     if (mGLView1VideoSink == null) {
195                         mGLView1VideoSink = new GLViewVideoSink(mGLView1);
196                     }
197                     mSelectedVideoSink = mGLView1VideoSink;
198                 } else if ("SurfaceTexture 2".equals(mSinkString)) {
199                     if (mGLView2VideoSink == null) {
200                         mGLView2VideoSink = new GLViewVideoSink(mGLView2);
201                     }
202                     mSelectedVideoSink = mGLView2VideoSink;
203                 }
204             }
205 
206             public void onNothingSelected(AdapterView parent) {
207                 Log.v(TAG, "onNothingSelected");
208                 mSinkString = null;
209                 mSelectedVideoSink = null;
210             }
211 
212         });
213 
214         // initialize button click handlers
215 
216         // Java MediaPlayer start/pause
217 
218         ((Button) findViewById(R.id.start_java)).setOnClickListener(new View.OnClickListener() {
219 
220             public void onClick(View view) {
221                 if (mJavaMediaPlayerVideoSink == null) {
222                     if (mSelectedVideoSink == null) {
223                         return;
224                     }
225                     mSelectedVideoSink.useAsSinkForJava(mMediaPlayer);
226                     mJavaMediaPlayerVideoSink = mSelectedVideoSink;
227                 }
228                 if (!mMediaPlayerIsPrepared) {
229                     if (mSourceString != null) {
230                         try {
231                             mMediaPlayer.setDataSource(mSourceString);
232                         } catch (IOException e) {
233                             Log.e(TAG, "IOException " + e);
234                         }
235                         mMediaPlayer.prepareAsync();
236                     }
237                 } else if (mMediaPlayer.isPlaying()) {
238                     mMediaPlayer.pause();
239                 } else {
240                     mMediaPlayer.start();
241                 }
242             }
243 
244         });
245 
246         // native MediaPlayer start/pause
247 
248         ((Button) findViewById(R.id.start_native)).setOnClickListener(new View.OnClickListener() {
249 
250             boolean created = false;
251             public void onClick(View view) {
252                 if (!created) {
253                     if (mNativeMediaPlayerVideoSink == null) {
254                         if (mSelectedVideoSink == null) {
255                             return;
256                         }
257                         mSelectedVideoSink.useAsSinkForNative();
258                         mNativeMediaPlayerVideoSink = mSelectedVideoSink;
259                     }
260                     if (mSourceString != null) {
261                         created = createStreamingMediaPlayer(mSourceString);
262                     }
263                 }
264                 if (created) {
265                     mIsPlayingStreaming = !mIsPlayingStreaming;
266                     setPlayingStreamingMediaPlayer(mIsPlayingStreaming);
267                 }
268             }
269 
270         });
271 
272         // Java MediaPlayer rewind
273 
274         ((Button) findViewById(R.id.rewind_java)).setOnClickListener(new View.OnClickListener() {
275 
276             public void onClick(View view) {
277                 if (mMediaPlayerIsPrepared) {
278                     mMediaPlayer.seekTo(0);
279                 }
280             }
281 
282         });
283 
284         // native MediaPlayer rewind
285 
286         ((Button) findViewById(R.id.rewind_native)).setOnClickListener(new View.OnClickListener() {
287 
288             public void onClick(View view) {
289                 if (mNativeMediaPlayerVideoSink != null) {
290                     rewindStreamingMediaPlayer();
291                 }
292             }
293 
294         });
295 
296     }
297 
298     /** Called when the activity is about to be paused. */
299     @Override
onPause()300     protected void onPause()
301     {
302         mIsPlayingStreaming = false;
303         setPlayingStreamingMediaPlayer(false);
304         mGLView1.onPause();
305         mGLView2.onPause();
306         super.onPause();
307     }
308 
309     @Override
onResume()310     protected void onResume() {
311         super.onResume();
312         mGLView1.onResume();
313         mGLView2.onResume();
314     }
315 
316     /** Called when the activity is about to be destroyed. */
317     @Override
onDestroy()318     protected void onDestroy()
319     {
320         shutdown();
321         super.onDestroy();
322     }
323 
324     private MyGLSurfaceView mGLView1, mGLView2;
325 
326     /** Native methods, implemented in jni folder */
createEngine()327     public static native void createEngine();
createStreamingMediaPlayer(String filename)328     public static native boolean createStreamingMediaPlayer(String filename);
setPlayingStreamingMediaPlayer(boolean isPlaying)329     public static native void setPlayingStreamingMediaPlayer(boolean isPlaying);
shutdown()330     public static native void shutdown();
setSurface(Surface surface)331     public static native void setSurface(Surface surface);
setSurfaceTexture(SurfaceTexture surfaceTexture)332     public static native void setSurfaceTexture(SurfaceTexture surfaceTexture);
rewindStreamingMediaPlayer()333     public static native void rewindStreamingMediaPlayer();
334 
335     /** Load jni .so on initialization */
336     static {
337          System.loadLibrary("native-media-jni");
338     }
339 
340     // VideoSink abstracts out the difference between Surface and SurfaceTexture
341     // aka SurfaceHolder and GLSurfaceView
342     static abstract class VideoSink {
343 
setFixedSize(int width, int height)344         abstract void setFixedSize(int width, int height);
useAsSinkForJava(MediaPlayer mediaPlayer)345         abstract void useAsSinkForJava(MediaPlayer mediaPlayer);
useAsSinkForNative()346         abstract void useAsSinkForNative();
347 
348     }
349 
350     static class SurfaceHolderVideoSink extends VideoSink {
351 
352         private final SurfaceHolder mSurfaceHolder;
353 
SurfaceHolderVideoSink(SurfaceHolder surfaceHolder)354         SurfaceHolderVideoSink(SurfaceHolder surfaceHolder) {
355             mSurfaceHolder = surfaceHolder;
356         }
357 
setFixedSize(int width, int height)358         void setFixedSize(int width, int height) {
359             mSurfaceHolder.setFixedSize(width, height);
360         }
361 
useAsSinkForJava(MediaPlayer mediaPlayer)362         void useAsSinkForJava(MediaPlayer mediaPlayer) {
363             mediaPlayer.setDisplay(mSurfaceHolder);
364         }
365 
useAsSinkForNative()366         void useAsSinkForNative() {
367             setSurface(mSurfaceHolder.getSurface());
368         }
369 
370     }
371 
372     static class GLViewVideoSink extends VideoSink {
373 
374         private final MyGLSurfaceView mMyGLSurfaceView;
375 
GLViewVideoSink(MyGLSurfaceView myGLSurfaceView)376         GLViewVideoSink(MyGLSurfaceView myGLSurfaceView) {
377             mMyGLSurfaceView = myGLSurfaceView;
378         }
379 
setFixedSize(int width, int height)380         void setFixedSize(int width, int height) {
381         }
382 
useAsSinkForJava(MediaPlayer mediaPlayer)383         void useAsSinkForJava(MediaPlayer mediaPlayer) {
384             SurfaceTexture st = mMyGLSurfaceView.getSurfaceTexture();
385             Surface s = new Surface(st);
386             mediaPlayer.setSurface(s);
387             s.release();
388         }
389 
useAsSinkForNative()390         void useAsSinkForNative() {
391             setSurfaceTexture(mMyGLSurfaceView.getSurfaceTexture());
392         }
393 
394     }
395 
396 }
397