Skip to content

Commit 2bfe695

Browse files
committed
Add MultiSurfaceTest
Presents multiple surfaces with static content.
1 parent 5377834 commit 2bfe695

File tree

7 files changed

+283
-15
lines changed

7 files changed

+283
-15
lines changed

AndroidManifest.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
1919
package="com.android.grafika"
20-
android:versionCode="20"
20+
android:versionCode="21"
2121
android:versionName="1.0" >
2222

2323
<uses-sdk
@@ -102,6 +102,10 @@
102102
android:name="com.android.grafika.PlayMovieSurfaceActivity"
103103
android:label="@string/title_activity_play_movie_surface" >
104104
</activity>
105+
<activity
106+
android:name="com.android.grafika.MultiSurfaceTest"
107+
android:label="@string/title_activity_multi_surface_test" >
108+
</activity>
105109
</application>
106110

107111
</manifest>

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Current features
5050
create video leave their files there. You'll also find two automatically-generated videos
5151
(gen-eight-rects.mp4 and gen-slides.mp4).
5252
- By default the video is played once, at the same rate it was recorded. You can use the
53-
checkboxes to loop playback and/or play the frames as quickly as possible.
53+
checkboxes to loop playback and/or play the frames at a fixed rate of 60 FPS.
5454
- Uses a `TextureView` for output.
5555
- Name starts with an asterisk so it's at the top of the list of activities.
5656

@@ -88,6 +88,11 @@ Current features
8888
- Uses the default (rear-facing) camera. If the device has no default camera (e.g.
8989
Nexus 7 (2012)), the Activity will crash.
9090

91+
[Multi-surface test](src/com/android/grafika/MultiSurfaceTest.java). Simple activity with three overlapping SurfaceViews, one marked secure.
92+
- Useful for examining HWC behavior with multiple static layers, and
93+
screencap / screenrecord behavior with a secure surface. (If you record or capture the
94+
screen, one of the circles should be missing.)
95+
9196
[Play video (SurfaceView)](src/com/android/grafika/PlayMovieSurfaceActivity.java). Plays the video track from an MP4 file.
9297
- Works very much like "Play video (TextureView)", though not all features are present.
9398
See the class comment for a list of advantages to using SurfaceView.
@@ -134,14 +139,20 @@ Feature & fix ideas
134139

135140
In no particular order.
136141

142+
- Try to detect when the codec selects a software AVC codec, as the current SoftAVC
143+
codec does not work with input surfaces.
144+
- If initial movie generation fails, handle it better (currently crashes -- should
145+
show a dialog explaining what happened).
137146
- Add a trivial glTexImage2D texture upload speed benchmark (maybe 512x512 RGBA).
138147
- Update MoviePlayer#doExtract() to improve startup latency
139148
(http://stackoverflow.com/questions/21440820/).
140149
- Add camera demo that sends preview to ST and then renders it in a small window that
141150
can be flung around / scaled / rotated by touch.
142151
- Add a "fat bits" viewer for camera (single SurfaceView; left half has live camera feed
143152
and a pan rect, right half has 8x pixels)
144-
- Cross-fade from one video to another, recording the result.
153+
- Change the "Simple GL in TextureView" animation. Or add an epilepsy warning.
154+
- Cross-fade from one video to another, recording the result. Allow specification of
155+
the resolution (maybe QVGA, 720p, 1080p) and generate appropriately.
145156
- Add features to the video player, like a slider for random access, and buttons for
146157
single-frame advance / rewind (requires seeking to nearest sync frame and decoding frames
147158
until target is reached).
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright 2014 Google Inc. All rights reserved.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
18+
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
19+
xmlns:tools="http://schemas.android.com/tools"
20+
android:layout_width="match_parent"
21+
android:layout_height="match_parent"
22+
android:paddingBottom="@dimen/activity_vertical_margin"
23+
android:paddingLeft="@dimen/activity_horizontal_margin"
24+
android:paddingRight="@dimen/activity_horizontal_margin"
25+
android:paddingTop="@dimen/activity_vertical_margin"
26+
tools:context=".MultiSurfaceTest" >
27+
28+
<SurfaceView
29+
android:id="@+id/multiSurfaceView1"
30+
android:layout_width="fill_parent"
31+
android:layout_height="fill_parent" />
32+
33+
<SurfaceView
34+
android:id="@+id/multiSurfaceView2"
35+
android:layout_width="fill_parent"
36+
android:layout_height="fill_parent" />
37+
38+
<SurfaceView
39+
android:id="@+id/multiSurfaceView3"
40+
android:layout_width="fill_parent"
41+
android:layout_height="fill_parent" />
42+
43+
<TextView
44+
android:id="@+id/multiSurfaceMessage_text"
45+
android:layout_width="wrap_content"
46+
android:layout_height="wrap_content"
47+
android:layout_centerHorizontal="true"
48+
android:layout_centerVertical="true"
49+
android:text="@string/multiSurfaceMessage"
50+
android:textAppearance="?android:attr/textAppearanceLarge"
51+
android:textColor="#0f0" />
52+
53+
</RelativeLayout>

res/values/strings.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
<string name="surfaceSizeMedium">[medium]</string>
7777
<string name="surfaceSizeFull">[full]</string>
7878
<string name="flatShaded">flat shaded</string>
79+
<string name="multiSurfaceMessage">This is a test!</string>
7980

8081
<!-- for cameraFilter_spinner; match with CameraCaptureActivity constants -->
8182
<string-array name="camera_filter_names">
@@ -101,5 +102,6 @@
101102
<string name="title_activity_hardware_scaler">Hardware Scaler Activity</string>
102103
<string name="title_activity_gles_info">OpenGL ES Info</string>
103104
<string name="title_activity_play_movie_surface">Play video (SurfaceView)</string>
105+
<string name="title_activity_multi_surface_test">Multi-Surface Test</string>
104106

105107
</resources>

src/com/android/grafika/MainActivity.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -55,27 +55,30 @@ public class MainActivity extends ListActivity {
5555
{ "Continuous capture",
5656
"Records camera continuously, saves a snapshot when requested",
5757
"ContinuousCaptureActivity" },
58-
{ "Show + capture camera",
59-
"Shows camera preview, records when requested",
60-
"CameraCaptureActivity" },
61-
{ "Record GL app",
62-
"Records GL app with FBO, re-render, or FB blit",
63-
"RecordFBOActivity" },
64-
{ "Simple GL in TextureView",
65-
"Renders frames as fast as possible",
66-
"TextureViewGLActivity" },
67-
{ "Live camera (TextureView)",
68-
"Trivially feeds the camera preview to a view",
69-
"LiveCameraActivity" },
7058
{ "Double decode",
7159
"Decodes two videos side-by-side",
7260
"DoubleDecodeActivity" },
7361
{ "Hardware scaler exerciser",
7462
"Exercises SurfaceHolder#setFixedSize()",
7563
"HardwareScalerActivity" },
64+
{ "Live camera (TextureView)",
65+
"Trivially feeds the camera preview to a view",
66+
"LiveCameraActivity" },
67+
{ "Multi-surface test",
68+
"Two overlapping SurfaceViews, one secure",
69+
"MultiSurfaceTest" },
7670
{ "Play video (SurfaceView)",
7771
"Plays .mp4 videos created by Grafika",
7872
"PlayMovieSurfaceActivity" },
73+
{ "Record GL app",
74+
"Records GL app with FBO, re-render, or FB blit",
75+
"RecordFBOActivity" },
76+
{ "Show + capture camera",
77+
"Shows camera preview, records when requested",
78+
"CameraCaptureActivity" },
79+
{ "Simple GL in TextureView",
80+
"Renders frames as fast as possible",
81+
"TextureViewGLActivity" },
7982
{ "{bench} glReadPixels speed test",
8083
"Tests glReadPixels() performance with 720p frames",
8184
"ReadPixelsActivity" },
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*
2+
* Copyright 2014 Google Inc. All rights reserved.
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.android.grafika;
18+
19+
import android.opengl.GLES20;
20+
import android.os.Bundle;
21+
import android.util.Log;
22+
import android.view.Surface;
23+
import android.view.SurfaceHolder;
24+
import android.view.SurfaceView;
25+
import android.app.Activity;
26+
import android.graphics.Canvas;
27+
import android.graphics.Color;
28+
import android.graphics.Paint;
29+
import android.graphics.PixelFormat;
30+
31+
import com.android.grafika.gles.EglCore;
32+
import com.android.grafika.gles.WindowSurface;
33+
34+
/**
35+
* Exercises some less-commonly-used aspects of SurfaceView. In particular:
36+
* <ul>
37+
* <li> We have three overlapping SurfaceViews.
38+
* <li> One is at the default depth, one is at "media overlay" depth, and one is on top of the UI.
39+
* <li> One is marked "secure".
40+
* </ul>
41+
*/
42+
public class MultiSurfaceTest extends Activity implements SurfaceHolder.Callback {
43+
private static final String TAG = MainActivity.TAG;
44+
45+
private SurfaceView mSurfaceView1;
46+
private SurfaceView mSurfaceView2;
47+
private SurfaceView mSurfaceView3;
48+
49+
@Override
50+
protected void onCreate(Bundle savedInstanceState) {
51+
super.onCreate(savedInstanceState);
52+
setContentView(R.layout.activity_multi_surface_test);
53+
54+
// #1 is at the bottom; mark it as secure just for fun
55+
mSurfaceView1 = (SurfaceView) findViewById(R.id.multiSurfaceView1);
56+
mSurfaceView1.getHolder().addCallback(this);
57+
mSurfaceView1.setSecure(true);
58+
59+
// #2 is above it, in the "media overlay"; must be translucent or we will
60+
// totally obscure #1 and it will be ignored by the compositor
61+
mSurfaceView2 = (SurfaceView) findViewById(R.id.multiSurfaceView2);
62+
mSurfaceView2.getHolder().addCallback(this);
63+
mSurfaceView2.getHolder().setFormat(PixelFormat.TRANSLUCENT);
64+
mSurfaceView2.setZOrderMediaOverlay(true);
65+
66+
// #3 is above everything, including the UI
67+
mSurfaceView3 = (SurfaceView) findViewById(R.id.multiSurfaceView3);
68+
mSurfaceView3.getHolder().addCallback(this);
69+
mSurfaceView3.getHolder().setFormat(PixelFormat.TRANSLUCENT);
70+
mSurfaceView3.setZOrderOnTop(true);
71+
}
72+
73+
/**
74+
* Returns an ordinal value for the SurfaceHolder, or -1 for an invalid surface.
75+
*/
76+
private int getSurfaceId(SurfaceHolder holder) {
77+
if (holder.equals(mSurfaceView1.getHolder())) {
78+
return 1;
79+
} else if (holder.equals(mSurfaceView2.getHolder())) {
80+
return 2;
81+
} else if (holder.equals(mSurfaceView3.getHolder())) {
82+
return 3;
83+
} else {
84+
return -1;
85+
}
86+
}
87+
88+
@Override
89+
public void surfaceCreated(SurfaceHolder holder) {
90+
int id = getSurfaceId(holder);
91+
if (id < 0) {
92+
Log.w(TAG, "surfaceCreated UNKNOWN holder=" + holder);
93+
} else {
94+
Log.d(TAG, "surfaceCreated #" + id + " holder=" + holder);
95+
96+
}
97+
}
98+
99+
/**
100+
* SurfaceHolder.Callback method
101+
* <p>
102+
* Draws when the surface changes. Since nothing else is touching the surface, and
103+
* we're not animating, we just draw here and ignore it.
104+
*/
105+
@Override
106+
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
107+
Log.d(TAG, "surfaceChanged fmt=" + format + " size=" + width + "x" + height +
108+
" holder=" + holder);
109+
110+
int id = getSurfaceId(holder);
111+
boolean portrait = height > width;
112+
Surface surface = holder.getSurface();
113+
114+
switch (id) {
115+
case 1:
116+
// default layer: circle on left / top
117+
if (portrait) {
118+
drawCircleSurface(surface, width / 2, height / 4, width / 4);
119+
} else {
120+
drawCircleSurface(surface, width / 4, height / 2, height / 4);
121+
}
122+
break;
123+
case 2:
124+
// media overlay layer: circle on right / bottom
125+
if (portrait) {
126+
drawCircleSurface(surface, width / 2, height * 3 / 4, width / 4);
127+
} else {
128+
drawCircleSurface(surface, width * 3 / 4, height / 2, height / 4);
129+
}
130+
break;
131+
case 3:
132+
// top layer: faint blue line
133+
if (portrait) {
134+
int halfLine = width / 16 + 1;
135+
drawRectSurface(surface, width/2 - halfLine, 0, width/2 + halfLine, height);
136+
} else {
137+
int halfLine = height / 16 + 1;
138+
drawRectSurface(surface, 0, height/2 - halfLine, width, height/2 + halfLine);
139+
}
140+
break;
141+
default:
142+
throw new RuntimeException("wha?");
143+
}
144+
}
145+
146+
@Override
147+
public void surfaceDestroyed(SurfaceHolder holder) {
148+
// ignore
149+
Log.d(TAG, "Surface destroyed holder=" + holder);
150+
}
151+
152+
/**
153+
* Clears the surface, then draws a blue alpha-blended rectangle with GL.
154+
* <p>
155+
* Creates a temporary EGL context just for the duration of the call.
156+
*/
157+
private void drawRectSurface(Surface surface, int left, int top, int right, int bottom) {
158+
EglCore eglCore = new EglCore();
159+
WindowSurface win = new WindowSurface(eglCore, surface, false);
160+
win.makeCurrent();
161+
GLES20.glClearColor(0, 0, 0, 0);
162+
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
163+
164+
GLES20.glEnable(GLES20.GL_SCISSOR_TEST);
165+
GLES20.glScissor(left, top, right - left, bottom - top);
166+
GLES20.glClearColor(0.0f, 0.0f, 0.5f, 0.25f);
167+
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
168+
GLES20.glDisable(GLES20.GL_SCISSOR_TEST);
169+
170+
win.swapBuffers();
171+
win.release();
172+
eglCore.release();
173+
}
174+
175+
/**
176+
* Clears the surface, then draws a filled circle with a shadow.
177+
* <p>
178+
* The Canvas drawing we're doing may not be fully implemented for hardware-accelerated
179+
* renderers (shadow layers only supported for text). However, Surface#lockCanvas()
180+
* currently only returns an unaccelerated Canvas, so it all comes out looking fine.
181+
*/
182+
private void drawCircleSurface(Surface surface, int x, int y, int radius) {
183+
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
184+
paint.setColor(Color.WHITE);
185+
paint.setStyle(Paint.Style.FILL);
186+
paint.setShadowLayer(radius / 4 + 1, 0, 0, Color.RED);
187+
188+
Canvas canvas = surface.lockCanvas(null);
189+
Log.d(TAG, "drawCircleSurface: isHwAcc=" + canvas.isHardwareAccelerated());
190+
canvas.drawARGB(0, 0, 0, 0);
191+
canvas.drawCircle(x, y, radius, paint);
192+
surface.unlockCanvasAndPost(canvas);
193+
}
194+
}

src/com/android/grafika/PlayMovieActivity.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ public void clickPlayStop(@SuppressWarnings("unused") View unused) {
157157
Log.d(TAG, "starting movie");
158158
SpeedControlCallback callback = new SpeedControlCallback();
159159
if (((CheckBox) findViewById(R.id.locked60fps_checkbox)).isChecked()) {
160+
// TODO: consider changing this to be "free running" mode
160161
callback.setFixedPlaybackRate(60);
161162
}
162163
SurfaceTexture st = mTextureView.getSurfaceTexture();

0 commit comments

Comments
 (0)