SurfaceTextureSourcepublic class SurfaceTextureSource extends android.filterfw.core.Filter A filter that converts textures from a SurfaceTexture object into frames for
processing in the filter framework.
To use, connect up the sourceListener callback, and then when executing
the graph, use the SurfaceTexture object passed to the callback to feed
frames into the filter graph. For example, pass the SurfaceTexture into
{#link
android.hardware.Camera.setPreviewTexture(android.graphics.SurfaceTexture)}.
This filter is intended for applications that need for flexibility than the
CameraSource and MediaSource provide. Note that the application needs to
provide width and height information for the SurfaceTextureSource, which it
should obtain from wherever the SurfaceTexture data is coming from to avoid
unnecessary resampling. |
Fields Summary |
---|
private SurfaceTextureSourceListener | mSourceListenerA callback to send the internal SurfaceTexture object to, once it is
created. This callback will be called when the the filter graph is
preparing to execute, but before any processing has actually taken
place. The SurfaceTexture object passed to this callback is the only way
to feed this filter. When the filter graph is shutting down, this
callback will be called again with null as the source.
This callback may be called from an arbitrary thread, so it should not
assume it is running in the UI thread in particular. | private int | mWidthThe width of the output image frame. If the texture width for the
SurfaceTexture source is known, use it here to minimize resampling. | private int | mHeightThe height of the output image frame. If the texture height for the
SurfaceTexture source is known, use it here to minimize resampling. | private boolean | mWaitForNewFrameWhether the filter will always wait for a new frame from its
SurfaceTexture, or whether it will output an old frame again if a new
frame isn't available. The filter will always wait for the first frame,
to avoid outputting a blank frame. Defaults to true. | private int | mWaitTimeoutMaximum timeout before signaling error when waiting for a new frame. Set
this to zero to disable the timeout and wait indefinitely. In milliseconds. | private boolean | mCloseOnTimeoutWhether a timeout is an exception-causing failure, or just causes the
filter to close. | private android.filterfw.core.GLFrame | mMediaFrame | private android.filterfw.core.ShaderProgram | mFrameExtractor | private android.graphics.SurfaceTexture | mSurfaceTexture | private android.filterfw.core.MutableFrameFormat | mOutputFormat | private android.os.ConditionVariable | mNewFrameAvailable | private boolean | mFirstFrame | private float[] | mFrameTransform | private float[] | mMappedCoords | private static final float[] | mSourceCoords | private final String | mRenderShader | private static final String | TAG | private static final boolean | mLogVerbose | private SurfaceTexture.OnFrameAvailableListener | onFrameAvailableListener |
Constructors Summary |
---|
public SurfaceTextureSource(String name)
super(name);
mNewFrameAvailable = new ConditionVariable();
mFrameTransform = new float[16];
mMappedCoords = new float[16];
|
Methods Summary |
---|
public void | close(android.filterfw.core.FilterContext context)
if (mLogVerbose) Log.v(TAG, "SurfaceTextureSource closed");
mSourceListener.onSurfaceTextureSourceReady(null);
mSurfaceTexture.release();
mSurfaceTexture = null;
| private void | createFormats()
mOutputFormat = ImageFormat.create(mWidth, mHeight,
ImageFormat.COLORSPACE_RGBA,
FrameFormat.TARGET_GPU);
| public void | fieldPortValueUpdated(java.lang.String name, android.filterfw.core.FilterContext context)
if (name.equals("width") || name.equals("height") ) {
mOutputFormat.setDimensions(mWidth, mHeight);
}
| public void | open(android.filterfw.core.FilterContext context)
if (mLogVerbose) Log.v(TAG, "Opening SurfaceTextureSource");
// Create SurfaceTexture anew each time - it can use substantial memory.
mSurfaceTexture = new SurfaceTexture(mMediaFrame.getTextureId());
// Connect SurfaceTexture to callback
mSurfaceTexture.setOnFrameAvailableListener(onFrameAvailableListener);
// Connect SurfaceTexture to source
mSourceListener.onSurfaceTextureSourceReady(mSurfaceTexture);
mFirstFrame = true;
| protected void | prepare(android.filterfw.core.FilterContext context)
if (mLogVerbose) Log.v(TAG, "Preparing SurfaceTextureSource");
createFormats();
// Prepare input
mMediaFrame = (GLFrame)context.getFrameManager().newBoundFrame(mOutputFormat,
GLFrame.EXTERNAL_TEXTURE,
0);
// Prepare output
mFrameExtractor = new ShaderProgram(context, mRenderShader);
| public void | process(android.filterfw.core.FilterContext context)
if (mLogVerbose) Log.v(TAG, "Processing new frame");
// First, get new frame if available
if (mWaitForNewFrame || mFirstFrame) {
boolean gotNewFrame;
if (mWaitTimeout != 0) {
gotNewFrame = mNewFrameAvailable.block(mWaitTimeout);
if (!gotNewFrame) {
if (!mCloseOnTimeout) {
throw new RuntimeException("Timeout waiting for new frame");
} else {
if (mLogVerbose) Log.v(TAG, "Timeout waiting for a new frame. Closing.");
closeOutputPort("video");
return;
}
}
} else {
mNewFrameAvailable.block();
}
mNewFrameAvailable.close();
mFirstFrame = false;
}
mSurfaceTexture.updateTexImage();
mSurfaceTexture.getTransformMatrix(mFrameTransform);
Matrix.multiplyMM(mMappedCoords, 0,
mFrameTransform, 0,
mSourceCoords, 0);
mFrameExtractor.setSourceRegion(mMappedCoords[0], mMappedCoords[1],
mMappedCoords[4], mMappedCoords[5],
mMappedCoords[8], mMappedCoords[9],
mMappedCoords[12], mMappedCoords[13]);
// Next, render to output
Frame output = context.getFrameManager().newFrame(mOutputFormat);
mFrameExtractor.process(mMediaFrame, output);
output.setTimestamp(mSurfaceTexture.getTimestamp());
pushOutput("video", output);
output.release();
| public void | setupPorts()
// Add input port
addOutputPort("video", ImageFormat.create(ImageFormat.COLORSPACE_RGBA,
FrameFormat.TARGET_GPU));
| public void | tearDown(android.filterfw.core.FilterContext context)
if (mMediaFrame != null) {
mMediaFrame.release();
}
|
|