1 /*
2  * Copyright (C) 2012 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 /* Original code copied from NDK Native-media sample code */
18 package android.mediastress.cts;
19 
20 import android.app.Activity;
21 import android.content.res.Configuration;
22 import android.graphics.SurfaceTexture;
23 import android.os.Bundle;
24 import android.util.Log;
25 import android.view.Surface;
26 import android.view.WindowManager;
27 
28 import java.io.File;
29 import java.util.concurrent.BlockingQueue;
30 import java.util.concurrent.LinkedBlockingQueue;
31 import java.util.concurrent.TimeUnit;
32 
33 import junit.framework.Assert;
34 
35 public class NativeMediaActivity extends Activity implements OnSurfaceChangedListener {
36     public static final String EXTRA_VIDEO_HEIGHT = "videoHeight";
37     // should be long enough. time-out can be treated as error
38     public static final long NATIVE_MEDIA_LIFECYCLE_TIMEOUT_MS = 10000;
39     static final String TAG = "NativeMedia";
40     static final String[] MEDIA = {
41         "bbb_short/480x360/mp4_libx264_libfaac/" +
42         "bbb_short.ffmpeg.480x360.mp4.libx264_1000kbps_30fps.libfaac_stereo_192kbps_44100Hz.ts",
43         "bbb_short/720x480/mp4_libx264_libfaac/" +
44         "bbb_short.ffmpeg.720x480.mp4.libx264_1000kbps_30fps.libfaac_stereo_192kbps_44100Hz.ts",
45         "bbb_short/1280x720/mp4_libx264_libfaac/" +
46         "bbb_short.ffmpeg.1280x720.mp4.libx264_1000kbps_30fps.libfaac_stereo_192kbps_44100Hz.ts",
47         "bbb_short/1920x1080/mp4_libx264_libfaac/" +
48         "bbb_short.ffmpeg.1920x1080.mp4.libx264_5000kbps_30fps.libfaac_stereo_192kbps_48000Hz.ts"
49     };
50 
51     private SurfaceTextureGLSurfaceView mGLView;
52     private volatile boolean mNativeCreated = false;
53     private int mVideoHeight = 360;
54     // native media status queued whenever there is a change in life.
55     private final BlockingQueue<Boolean> mNativeWaitQ = new LinkedBlockingQueue<Boolean>();
56 
57     @Override
onCreate(Bundle icicle)58     public void onCreate(Bundle icicle) {
59         super.onCreate(icicle);
60         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
61                 WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
62         mVideoHeight = getIntent().getIntExtra(EXTRA_VIDEO_HEIGHT, mVideoHeight);
63         mGLView = new SurfaceTextureGLSurfaceView(this, this);
64         setContentView(mGLView);
65     }
66 
67     @Override
onConfigurationChanged(Configuration newConfig)68     public void onConfigurationChanged(Configuration newConfig) {
69         Log.w(TAG, "configuration changed " + newConfig.orientation);
70         super.onConfigurationChanged(newConfig);
71     }
72 
73     /**
74      * should be called by GLThread after GlSurface is created.
75      */
76     @Override
onSurfaceCreated()77     public void onSurfaceCreated() {
78         runOnUiThread(new Runnable() {
79             @Override
80             public void run() {
81                 Log.i(TAG, "onSurfaceCreated create engine");
82                 // initialize native media system
83                 Assert.assertTrue(createEngine());
84                 Assert.assertTrue(setSurfaceForNative());
85                 String fileName = getMediaString();
86                 File f = new File(fileName);
87                 Log.i(TAG, "start playing " + fileName + ", exists: " + f.exists());
88                 Assert.assertTrue("file '" + fileName + "' does not exist", f.exists());
89                 Assert.assertTrue(createMediaPlayer("file://" + fileName));
90                 mNativeCreated = true;
91                 mNativeWaitQ.add(mNativeCreated);
92             }
93         });
94     }
95 
96     /**
97      * should be called inside main thread
98      */
99     @Override
onSurfaceDestroyed()100     public void onSurfaceDestroyed() {
101         shutdownIfActive();
102     }
103 
104     /**
105      * check if native media is alive. If it does not become alive
106      * for more than certain time, assertion fail will happen.
107      * @return the status of native media, true if it is alive, null if timed-out
108      * @throws InterruptedException
109      */
waitForNativeMediaLifeCycle()110     public Boolean waitForNativeMediaLifeCycle() throws InterruptedException {
111         return mNativeWaitQ.poll(NATIVE_MEDIA_LIFECYCLE_TIMEOUT_MS, TimeUnit.MILLISECONDS);
112     }
113 
114     @Override
onPause()115     protected void onPause() {
116         //GLSurfaceView destroys surface on pause. so shutdown should be done.
117         shutdownIfActive();
118         mGLView.onPause();
119         super.onPause();
120     }
121 
122     @Override
onResume()123     protected void onResume() {
124         super.onResume();
125         mGLView.onResume();
126         if (mNativeCreated) {
127             Assert.assertTrue(playOrPauseMediaPlayer(true));
128         }
129     }
130 
131     @Override
onDestroy()132     protected void onDestroy() {
133         if (mNativeCreated) {
134             shutdown();
135         }
136         super.onDestroy();
137     }
138 
shutdownIfActive()139     private void shutdownIfActive() {
140         if (mNativeCreated) {
141             Log.i(TAG, "shutdownIfActive shutdown");
142             // surface no longer available, so just shutdown
143             shutdown();
144             mNativeCreated = false;
145             mNativeWaitQ.add(mNativeCreated);
146         }
147     }
148 
setSurfaceForNative()149     private boolean setSurfaceForNative() {
150         SurfaceTexture st = mGLView.getSurfaceTexture();
151         Assert.assertNotNull(st);
152         Surface s = new Surface(st);
153         boolean res = setSurface(s);
154         s.release();
155         return res;
156     }
157 
getMediaString()158     private String getMediaString() {
159         int mediaIndex = 0; // default: 480x360
160         switch(mVideoHeight) {
161         case 1080:
162             mediaIndex = 3;
163             break;
164         case 720:
165             mediaIndex = 2;
166             break;
167         case 480:
168             mediaIndex = 1;
169             break;
170         }
171         return WorkDir.getMediaDirString() + MEDIA[mediaIndex];
172     }
173 
174     /**
175      * creates OpenMaxAl Engine
176     */
createEngine()177     public static native boolean createEngine();
178     /**
179      * set surface to render. should be called before creating Media player
180      * @param surface
181      */
setSurface(Surface surface)182     public static native boolean setSurface(Surface surface);
183 
createMediaPlayer(String fileUri)184     public static native boolean createMediaPlayer(String fileUri);
playOrPauseMediaPlayer(boolean play)185     public static native boolean playOrPauseMediaPlayer(boolean play);
shutdown()186     public static native void shutdown();
187 
188     /** Load jni on initialization */
189     static {
190          System.loadLibrary("ctsmediastress_jni");
191     }
192 
193 }
194