Merge changes I34dbae75,I582afae6 into ics-mr0
* changes:
Augment CTS test for MediaPlayer.setSurface
DO NOT MERGE: Add CTS test for MediaPlayer.setSurface() For bug 5088394.
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index b7f7cc6..9cdb13b 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -135,6 +135,14 @@
</intent-filter>
</activity>
+ <activity android:name="android.media.cts.MediaPlayerSurfaceStubActivity"
+ android:label="MediaPlayerSurfaceStubActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
<activity android:name="android.media.cts.RingtonePickerActivity"
android:label="RingtonePickerActivity">
<intent-filter>
diff --git a/tests/src/android/media/cts/MediaPlayerSurfaceStubActivity.java b/tests/src/android/media/cts/MediaPlayerSurfaceStubActivity.java
new file mode 100644
index 0000000..3cd6fc8
--- /dev/null
+++ b/tests/src/android/media/cts/MediaPlayerSurfaceStubActivity.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.media.cts;
+
+import com.android.cts.stub.R;
+
+import android.app.Activity;
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Resources;
+import android.media.MediaPlayer;
+import android.os.Bundle;
+import android.util.Log;
+
+public class MediaPlayerSurfaceStubActivity extends Activity {
+
+ private static final String TAG = "MediaPlayerSurfaceStubActivity";
+
+ protected Resources mResources;
+
+ private VideoSurfaceView mVideoView = null;
+ private MediaPlayer mMediaPlayer = null;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mResources = getResources();
+ mMediaPlayer = new MediaPlayer();
+
+ try {
+ AssetFileDescriptor afd = mResources.openRawResourceFd(R.raw.testvideo);
+ mMediaPlayer.setDataSource(
+ afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+ afd.close();
+ } catch (Exception e) {
+ Log.e(TAG, e.getMessage(), e);
+ }
+
+ mVideoView = new VideoSurfaceView(this, mMediaPlayer);
+ setContentView(mVideoView);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mVideoView.onResume();
+ }
+
+ public void playVideo() throws Exception {
+ mVideoView.startTest();
+ }
+
+}
diff --git a/tests/src/android/media/cts/VideoSurfaceView.java b/tests/src/android/media/cts/VideoSurfaceView.java
new file mode 100644
index 0000000..0f23a2d
--- /dev/null
+++ b/tests/src/android/media/cts/VideoSurfaceView.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import com.android.cts.stub.R;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.content.Context;
+import android.graphics.SurfaceTexture;
+import android.media.MediaPlayer;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+import android.opengl.Matrix;
+import android.util.Log;
+import android.view.Surface;
+
+class VideoSurfaceView extends GLSurfaceView {
+ private static final String TAG = "VideoSurfaceView";
+ private static final int SLEEP_TIME = 1000;
+
+ VideoRender mRenderer;
+ private MediaPlayer mMediaPlayer = null;
+
+ public VideoSurfaceView(Context context, MediaPlayer mp) {
+ super(context);
+
+ setEGLContextClientVersion(2);
+ mMediaPlayer = mp;
+ mRenderer = new VideoRender(context);
+ setRenderer(mRenderer);
+ }
+
+ @Override
+ public void onResume() {
+ queueEvent(new Runnable(){
+ public void run() {
+ mRenderer.setMediaPlayer(mMediaPlayer);
+ }});
+
+ super.onResume();
+ }
+
+ public void startTest() throws Exception {
+ Thread.sleep(SLEEP_TIME);
+ mMediaPlayer.start();
+
+ Thread.sleep(SLEEP_TIME * 5);
+ mMediaPlayer.setSurface(null);
+
+ Thread.sleep(SLEEP_TIME * 1);
+ SurfaceTexture surfaceTexture = new SurfaceTexture(0);
+ Surface surface = new Surface(surfaceTexture);
+ surface.release();
+ try {
+ mMediaPlayer.setSurface(surface);
+ throw new RuntimeException("setSurface with released Surface object didn't throw " +
+ "IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+
+ while (mMediaPlayer.isPlaying()) {
+ Thread.sleep(SLEEP_TIME);
+ }
+ }
+
+ private static class VideoRender
+ implements GLSurfaceView.Renderer, SurfaceTexture.OnFrameAvailableListener {
+ private static String TAG = "VideoRender";
+
+ private static final int FLOAT_SIZE_BYTES = 4;
+ private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
+ private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
+ private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
+ private final float[] mTriangleVerticesData = {
+ // X, Y, Z, U, V
+ -1.0f, -1.0f, 0, 0.f, 0.f,
+ 1.0f, -1.0f, 0, 1.f, 0.f,
+ -1.0f, 1.0f, 0, 0.f, 1.f,
+ 1.0f, 1.0f, 0, 1.f, 1.f,
+ };
+
+ private FloatBuffer mTriangleVertices;
+
+ private final String mVertexShader =
+ "uniform mat4 uMVPMatrix;\n" +
+ "uniform mat4 uSTMatrix;\n" +
+ "attribute vec4 aPosition;\n" +
+ "attribute vec4 aTextureCoord;\n" +
+ "varying vec2 vTextureCoord;\n" +
+ "void main() {\n" +
+ " gl_Position = uMVPMatrix * aPosition;\n" +
+ " vTextureCoord = (uSTMatrix * aTextureCoord).xy;\n" +
+ "}\n";
+
+ private final String mFragmentShader =
+ "#extension GL_OES_EGL_image_external : require\n" +
+ "precision mediump float;\n" +
+ "varying vec2 vTextureCoord;\n" +
+ "uniform samplerExternalOES sTexture;\n" +
+ "void main() {\n" +
+ " gl_FragColor = texture2D(sTexture, vTextureCoord);\n" +
+ "}\n";
+
+ private float[] mMVPMatrix = new float[16];
+ private float[] mSTMatrix = new float[16];
+
+ private int mProgram;
+ private int mTextureID;
+ private int muMVPMatrixHandle;
+ private int muSTMatrixHandle;
+ private int maPositionHandle;
+ private int maTextureHandle;
+
+ private SurfaceTexture mSurface;
+ private boolean updateSurface = false;
+
+ private static int GL_TEXTURE_EXTERNAL_OES = 0x8D65;
+
+ private MediaPlayer mMediaPlayer;
+
+ public VideoRender(Context context) {
+ mTriangleVertices = ByteBuffer.allocateDirect(
+ mTriangleVerticesData.length * FLOAT_SIZE_BYTES)
+ .order(ByteOrder.nativeOrder()).asFloatBuffer();
+ mTriangleVertices.put(mTriangleVerticesData).position(0);
+
+ Matrix.setIdentityM(mSTMatrix, 0);
+ }
+
+ public void setMediaPlayer(MediaPlayer player) {
+ mMediaPlayer = player;
+ }
+
+ public void onDrawFrame(GL10 glUnused) {
+ synchronized(this) {
+ if (updateSurface) {
+ mSurface.updateTexImage();
+ mSurface.getTransformMatrix(mSTMatrix);
+ updateSurface = false;
+ }
+ }
+
+ GLES20.glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
+ GLES20.glClear( GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_COLOR_BUFFER_BIT);
+
+ GLES20.glUseProgram(mProgram);
+ checkGlError("glUseProgram");
+
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+ GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
+
+ mTriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+ GLES20.glVertexAttribPointer(maPositionHandle, 3, GLES20.GL_FLOAT, false,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+ checkGlError("glVertexAttribPointer maPosition");
+ GLES20.glEnableVertexAttribArray(maPositionHandle);
+ checkGlError("glEnableVertexAttribArray maPositionHandle");
+
+ mTriangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+ GLES20.glVertexAttribPointer(maTextureHandle, 3, GLES20.GL_FLOAT, false,
+ TRIANGLE_VERTICES_DATA_STRIDE_BYTES, mTriangleVertices);
+ checkGlError("glVertexAttribPointer maTextureHandle");
+ GLES20.glEnableVertexAttribArray(maTextureHandle);
+ checkGlError("glEnableVertexAttribArray maTextureHandle");
+
+ Matrix.setIdentityM(mMVPMatrix, 0);
+ GLES20.glUniformMatrix4fv(muMVPMatrixHandle, 1, false, mMVPMatrix, 0);
+ GLES20.glUniformMatrix4fv(muSTMatrixHandle, 1, false, mSTMatrix, 0);
+
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
+ checkGlError("glDrawArrays");
+ GLES20.glFinish();
+
+ }
+
+ public void onSurfaceChanged(GL10 glUnused, int width, int height) {
+ }
+
+ public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
+ mProgram = createProgram(mVertexShader, mFragmentShader);
+ if (mProgram == 0) {
+ return;
+ }
+ maPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
+ checkGlError("glGetAttribLocation aPosition");
+ if (maPositionHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for aPosition");
+ }
+ maTextureHandle = GLES20.glGetAttribLocation(mProgram, "aTextureCoord");
+ checkGlError("glGetAttribLocation aTextureCoord");
+ if (maTextureHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for aTextureCoord");
+ }
+
+ muMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
+ checkGlError("glGetUniformLocation uMVPMatrix");
+ if (muMVPMatrixHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for uMVPMatrix");
+ }
+
+ muSTMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uSTMatrix");
+ checkGlError("glGetUniformLocation uSTMatrix");
+ if (muSTMatrixHandle == -1) {
+ throw new RuntimeException("Could not get attrib location for uSTMatrix");
+ }
+
+
+ int[] textures = new int[1];
+ GLES20.glGenTextures(1, textures, 0);
+
+ mTextureID = textures[0];
+ GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, mTextureID);
+ checkGlError("glBindTexture mTextureID");
+
+ GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
+ GLES20.GL_NEAREST);
+ GLES20.glTexParameterf(GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
+ GLES20.GL_LINEAR);
+
+ /*
+ * Create the SurfaceTexture that will feed this textureID,
+ * and pass it to the MediaPlayer
+ */
+ mSurface = new SurfaceTexture(mTextureID);
+ mSurface.setOnFrameAvailableListener(this);
+
+ Surface surface = new Surface(mSurface);
+ mMediaPlayer.setSurface(surface);
+ surface.release();
+
+ try {
+ mMediaPlayer.prepare();
+ } catch (IOException t) {
+ Log.e(TAG, "media player prepare failed");
+ }
+
+ synchronized(this) {
+ updateSurface = false;
+ }
+ }
+
+ synchronized public void onFrameAvailable(SurfaceTexture surface) {
+ updateSurface = true;
+ }
+
+ private int loadShader(int shaderType, String source) {
+ int shader = GLES20.glCreateShader(shaderType);
+ if (shader != 0) {
+ GLES20.glShaderSource(shader, source);
+ GLES20.glCompileShader(shader);
+ int[] compiled = new int[1];
+ GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+ if (compiled[0] == 0) {
+ Log.e(TAG, "Could not compile shader " + shaderType + ":");
+ Log.e(TAG, GLES20.glGetShaderInfoLog(shader));
+ GLES20.glDeleteShader(shader);
+ shader = 0;
+ }
+ }
+ return shader;
+ }
+
+ private int createProgram(String vertexSource, String fragmentSource) {
+ int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
+ if (vertexShader == 0) {
+ return 0;
+ }
+ int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
+ if (pixelShader == 0) {
+ return 0;
+ }
+
+ int program = GLES20.glCreateProgram();
+ if (program != 0) {
+ GLES20.glAttachShader(program, vertexShader);
+ checkGlError("glAttachShader");
+ GLES20.glAttachShader(program, pixelShader);
+ checkGlError("glAttachShader");
+ GLES20.glLinkProgram(program);
+ int[] linkStatus = new int[1];
+ GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, linkStatus, 0);
+ if (linkStatus[0] != GLES20.GL_TRUE) {
+ Log.e(TAG, "Could not link program: ");
+ Log.e(TAG, GLES20.glGetProgramInfoLog(program));
+ GLES20.glDeleteProgram(program);
+ program = 0;
+ }
+ }
+ return program;
+ }
+
+ private void checkGlError(String op) {
+ int error;
+ while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
+ Log.e(TAG, op + ": glError " + error);
+ throw new RuntimeException(op + ": glError " + error);
+ }
+ }
+
+ } // End of class VideoRender.
+
+} // End of class VideoSurfaceView.
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java
new file mode 100644
index 0000000..196382d
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerSurfaceTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import android.os.Bundle;
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ */
+public class MediaPlayerSurfaceTest extends ActivityInstrumentationTestCase2<MediaPlayerSurfaceStubActivity> {
+
+ public MediaPlayerSurfaceTest() {
+ super("com.android.cts.stub", MediaPlayerSurfaceStubActivity.class);
+ }
+
+ public void testSetSurface() throws Exception {
+ Bundle extras = new Bundle();
+ MediaPlayerSurfaceStubActivity activity = launchActivity("com.android.cts.stub",
+ MediaPlayerSurfaceStubActivity.class, extras);
+ activity.playVideo();
+ activity.finish();
+ }
+}