/* * Copyright (C) 2010 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.graphics; import java.lang.ref.WeakReference; import android.os.Handler; import android.os.Looper; import android.os.Message; /** * Captures frames from an image stream as an OpenGL ES texture. * *
The image stream may come from either camera preview or video decode. A SurfaceTexture * may be used in place of a SurfaceHolder when specifying the output destination of a * {@link android.hardware.Camera} or {@link android.media.MediaPlayer} * object. Doing so will cause all the frames from the image stream to be sent to the * SurfaceTexture object rather than to the device's display. When {@link #updateTexImage} is * called, the contents of the texture object specified when the SurfaceTexture was created are * updated to contain the most recent image from the image stream. This may cause some frames of * the stream to be skipped. * *
When sampling from the texture one should first transform the texture coordinates using the * matrix queried via {@link #getTransformMatrix(float[])}. The transform matrix may change each * time {@link #updateTexImage} is called, so it should be re-queried each time the texture image * is updated. * This matrix transforms traditional 2D OpenGL ES texture coordinate column vectors of the form (s, * t, 0, 1) where s and t are on the inclusive interval [0, 1] to the proper sampling location in * the streamed texture. This transform compensates for any properties of the image stream source * that cause it to appear different from a traditional OpenGL ES texture. For example, sampling * from the bottom left corner of the image can be accomplished by transforming the column vector * (0, 0, 0, 1) using the queried matrix, while sampling from the top right corner of the image can * be done by transforming (1, 1, 0, 1). * *
The texture object uses the GL_TEXTURE_EXTERNAL_OES texture target, which is defined by the * * GL_OES_EGL_image_external OpenGL ES extension. This limits how the texture may be used. * Each time the texture is bound it must be bound to the GL_TEXTURE_EXTERNAL_OES target rather than * the GL_TEXTURE_2D target. Additionally, any OpenGL ES 2.0 shader that samples from the texture * must declare its use of this extension using, for example, an "#extension * GL_OES_EGL_image_external : require" directive. Such shaders must also access the texture using * the samplerExternalOES GLSL sampler type. * *
SurfaceTexture objects may be created on any thread. {@link #updateTexImage} may only be
* called on the thread with the OpenGL ES context that contains the texture object. The
* frame-available callback is called on an arbitrary thread, so unless special care is taken {@link
* #updateTexImage} should not be called directly from the callback.
*/
public class SurfaceTexture {
private EventHandler mEventHandler;
private OnFrameAvailableListener mOnFrameAvailableListener;
/**
* This field is used by native code, do not access or modify.
*/
private int mSurfaceTexture;
/**
* Callback interface for being notified that a new stream frame is available.
*/
public interface OnFrameAvailableListener {
void onFrameAvailable(SurfaceTexture surfaceTexture);
}
/**
* Exception thrown when a surface couldn't be created or resized
*/
public static class OutOfResourcesException extends Exception {
public OutOfResourcesException() {
}
public OutOfResourcesException(String name) {
super(name);
}
}
/**
* Construct a new SurfaceTexture to stream images to a given OpenGL texture.
*
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
*/
public SurfaceTexture(int texName) {
this(texName, true);
}
/**
* Construct a new SurfaceTexture to stream images to a given OpenGL texture.
*
* @param texName the OpenGL texture object name (e.g. generated via glGenTextures)
* @param allowSynchronousMode whether the SurfaceTexture can run in the synchronous mode.
* When the image stream comes from OpenGL, SurfaceTexture may run in the synchronous
* mode where the producer side may be blocked to avoid skipping frames. To avoid the
* thread block, set allowSynchronousMode to false.
*/
public SurfaceTexture(int texName, boolean allowSynchronousMode) {
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(looper);
} else {
mEventHandler = null;
}
nativeInit(texName, new WeakReference