FileDocCategorySizeDatePackage
SurfaceTextureTarget.javaAPI DocAndroid 5.1 API13986Thu Mar 12 22:22:30 GMT 2015android.filterpacks.videosrc

SurfaceTextureTarget

public class SurfaceTextureTarget extends android.filterfw.core.Filter
hide

Fields Summary
private final int
RENDERMODE_STRETCH
private final int
RENDERMODE_FIT
private final int
RENDERMODE_FILL_CROP
private final int
RENDERMODE_CUSTOMIZE
private android.graphics.SurfaceTexture
mSurfaceTexture
Required. Sets the destination surfaceTexture.
private int
mScreenWidth
Required. Sets the width of the output surfaceTexture images
private int
mScreenHeight
Required. Sets the height of the output surfaceTexture images
private String
mRenderModeString
Optional. Control how the incoming frames are rendered onto the output. Default is FIT. RENDERMODE_STRETCH: Just fill the output surfaceView. RENDERMODE_FIT: Keep aspect ratio and fit without cropping. May have black bars. RENDERMODE_FILL_CROP: Keep aspect ratio and fit without black bars. May crop.
private android.filterfw.geometry.Quad
mSourceQuad
private android.filterfw.geometry.Quad
mTargetQuad
private int
mSurfaceId
private android.filterfw.core.ShaderProgram
mProgram
private android.filterfw.core.GLFrame
mScreen
private int
mRenderMode
private float
mAspectRatio
private boolean
mLogVerbose
private static final String
TAG
Constructors Summary
public SurfaceTextureTarget(String name)


       
        super(name);

        mLogVerbose = Log.isLoggable(TAG, Log.VERBOSE);
    
Methods Summary
public synchronized voidclose(android.filterfw.core.FilterContext context)

        if (mSurfaceId > 0) {
            context.getGLEnvironment().unregisterSurfaceId(mSurfaceId);
            mSurfaceId = -1;
        }
    
public synchronized voiddisconnect(android.filterfw.core.FilterContext context)

        if (mLogVerbose) Log.v(TAG, "disconnect");
        if (mSurfaceTexture == null) {
            Log.d(TAG, "SurfaceTexture is already null. Nothing to disconnect.");
            return;
        }
        mSurfaceTexture = null;
        // Make sure we unregister the surface as well if a surface was registered.
        // There can be a situation where the surface was not registered but the
        // surfacetexture was valid. For example, the disconnect can be called before
        // the filter was opened. Hence, the surfaceId may not be a valid one here,
        // and need to check for its validity.
        if (mSurfaceId > 0) {
            context.getGLEnvironment().unregisterSurfaceId(mSurfaceId);
            mSurfaceId = -1;
        }
    
public voidfieldPortValueUpdated(java.lang.String name, android.filterfw.core.FilterContext context)

        if (mLogVerbose) Log.v(TAG, "FPVU. Thread: " + Thread.currentThread());
        updateRenderMode();
    
public synchronized voidopen(android.filterfw.core.FilterContext context)

        // Set up SurfaceTexture internals
        if (mSurfaceTexture == null) {
            Log.e(TAG, "SurfaceTexture is null!!");
            throw new RuntimeException("Could not register SurfaceTexture: " + mSurfaceTexture);
        }
        mSurfaceId = context.getGLEnvironment().registerSurfaceTexture(
            mSurfaceTexture, mScreenWidth, mScreenHeight);
        if (mSurfaceId <= 0) {
            throw new RuntimeException("Could not register SurfaceTexture: " + mSurfaceTexture);
        }
    
public voidprepare(android.filterfw.core.FilterContext context)

        if (mLogVerbose) Log.v(TAG, "Prepare. Thread: " + Thread.currentThread());
        // Create identity shader to render, and make sure to render upside-down, as textures
        // are stored internally bottom-to-top.
        mProgram = ShaderProgram.createIdentity(context);
        mProgram.setSourceRect(0, 1, 1, -1);
        mProgram.setClearColor(0.0f, 0.0f, 0.0f);

        updateRenderMode();

        // Create a frame representing the screen
        MutableFrameFormat screenFormat = new MutableFrameFormat(FrameFormat.TYPE_BYTE,
                                                                 FrameFormat.TARGET_GPU);
        screenFormat.setBytesPerSample(4);
        screenFormat.setDimensions(mScreenWidth, mScreenHeight);
        mScreen = (GLFrame)context.getFrameManager().newBoundFrame(screenFormat,
                                                                   GLFrame.EXISTING_FBO_BINDING,
                                                                   0);
    
public synchronized voidprocess(android.filterfw.core.FilterContext context)

        // Surface is not registered. Nothing to render into.
        if (mSurfaceId <= 0) {
            return;
        }
        GLEnvironment glEnv = context.getGLEnvironment();

        // Get input frame
        Frame input = pullInput("frame");
        boolean createdFrame = false;

        float currentAspectRatio =
          (float)input.getFormat().getWidth() / input.getFormat().getHeight();
        if (currentAspectRatio != mAspectRatio) {
            if (mLogVerbose) {
                Log.v(TAG, "Process. New aspect ratio: " + currentAspectRatio +
                    ", previously: " + mAspectRatio + ". Thread: " + Thread.currentThread());
            }
            mAspectRatio = currentAspectRatio;
            updateTargetRect();
        }

        // See if we need to copy to GPU
        Frame gpuFrame = null;
        int target = input.getFormat().getTarget();
        if (target != FrameFormat.TARGET_GPU) {
            gpuFrame = context.getFrameManager().duplicateFrameToTarget(input,
                                                                        FrameFormat.TARGET_GPU);
            createdFrame = true;
        } else {
            gpuFrame = input;
        }

        // Activate our surface
        glEnv.activateSurfaceWithId(mSurfaceId);

        // Process
        mProgram.process(gpuFrame, mScreen);

        glEnv.setSurfaceTimestamp(input.getTimestamp());

        // And swap buffers
        glEnv.swapBuffers();

        if (createdFrame) {
            gpuFrame.release();
        }
    
public synchronized voidsetupPorts()

        // Make sure we have a SurfaceView
        if (mSurfaceTexture == null) {
            throw new RuntimeException("Null SurfaceTexture passed to SurfaceTextureTarget");
        }

        // Add input port - will accept anything that's 4-channel.
        addMaskedInputPort("frame", ImageFormat.create(ImageFormat.COLORSPACE_RGBA));
    
public voidtearDown(android.filterfw.core.FilterContext context)

        if (mScreen != null) {
            mScreen.release();
        }
    
public voidupdateRenderMode()

        if (mLogVerbose) Log.v(TAG, "updateRenderMode. Thread: " + Thread.currentThread());
        if (mRenderModeString != null) {
            if (mRenderModeString.equals("stretch")) {
                mRenderMode = RENDERMODE_STRETCH;
            } else if (mRenderModeString.equals("fit")) {
                mRenderMode = RENDERMODE_FIT;
            } else if (mRenderModeString.equals("fill_crop")) {
                mRenderMode = RENDERMODE_FILL_CROP;
            } else if (mRenderModeString.equals("customize")) {
                mRenderMode = RENDERMODE_CUSTOMIZE;
            } else {
                throw new RuntimeException("Unknown render mode '" + mRenderModeString + "'!");
            }
        }
        updateTargetRect();
    
private voidupdateTargetRect()

        if (mLogVerbose) Log.v(TAG, "updateTargetRect. Thread: " + Thread.currentThread());
        if (mScreenWidth > 0 && mScreenHeight > 0 && mProgram != null) {
            float screenAspectRatio = (float)mScreenWidth / mScreenHeight;
            float relativeAspectRatio = screenAspectRatio / mAspectRatio;
            if (mLogVerbose) {
                Log.v(TAG, "UTR. screen w = " + (float)mScreenWidth + " x screen h = " +
                    (float)mScreenHeight + " Screen AR: " + screenAspectRatio +
                    ", frame AR: "  + mAspectRatio + ", relative AR: " + relativeAspectRatio);
            }

            if (relativeAspectRatio == 1.0f && mRenderMode != RENDERMODE_CUSTOMIZE) {
                mProgram.setTargetRect(0, 0, 1, 1);
                mProgram.setClearsOutput(false);
            } else {
                switch (mRenderMode) {
                    case RENDERMODE_STRETCH:
                        mTargetQuad.p0.set(0f, 0.0f);
                        mTargetQuad.p1.set(1f, 0.0f);
                        mTargetQuad.p2.set(0f, 1.0f);
                        mTargetQuad.p3.set(1f, 1.0f);
                        mProgram.setClearsOutput(false);
                        break;
                    case RENDERMODE_FIT:
                        if (relativeAspectRatio > 1.0f) {
                            // Screen is wider than the camera, scale down X
                            mTargetQuad.p0.set(0.5f - 0.5f / relativeAspectRatio, 0.0f);
                            mTargetQuad.p1.set(0.5f + 0.5f / relativeAspectRatio, 0.0f);
                            mTargetQuad.p2.set(0.5f - 0.5f / relativeAspectRatio, 1.0f);
                            mTargetQuad.p3.set(0.5f + 0.5f / relativeAspectRatio, 1.0f);

                        } else {
                            // Screen is taller than the camera, scale down Y
                            mTargetQuad.p0.set(0.0f, 0.5f - 0.5f * relativeAspectRatio);
                            mTargetQuad.p1.set(1.0f, 0.5f - 0.5f * relativeAspectRatio);
                            mTargetQuad.p2.set(0.0f, 0.5f + 0.5f * relativeAspectRatio);
                            mTargetQuad.p3.set(1.0f, 0.5f + 0.5f * relativeAspectRatio);
                        }
                        mProgram.setClearsOutput(true);
                        break;
                    case RENDERMODE_FILL_CROP:
                        if (relativeAspectRatio > 1) {
                            // Screen is wider than the camera, crop in Y
                            mTargetQuad.p0.set(0.0f, 0.5f - 0.5f * relativeAspectRatio);
                            mTargetQuad.p1.set(1.0f, 0.5f - 0.5f * relativeAspectRatio);
                            mTargetQuad.p2.set(0.0f, 0.5f + 0.5f * relativeAspectRatio);
                            mTargetQuad.p3.set(1.0f, 0.5f + 0.5f * relativeAspectRatio);
                        } else {
                            // Screen is taller than the camera, crop in X
                            mTargetQuad.p0.set(0.5f - 0.5f / relativeAspectRatio, 0.0f);
                            mTargetQuad.p1.set(0.5f + 0.5f / relativeAspectRatio, 0.0f);
                            mTargetQuad.p2.set(0.5f - 0.5f / relativeAspectRatio, 1.0f);
                            mTargetQuad.p3.set(0.5f + 0.5f / relativeAspectRatio, 1.0f);
                        }
                        mProgram.setClearsOutput(true);
                        break;
                    case RENDERMODE_CUSTOMIZE:
                        ((ShaderProgram) mProgram).setSourceRegion(mSourceQuad);
                        break;
                }
                if (mLogVerbose) Log.v(TAG,  "UTR. quad: " + mTargetQuad);
                ((ShaderProgram) mProgram).setTargetRegion(mTargetQuad);
            }
        }