FileDocCategorySizeDatePackage
SurfaceTargetFilter.javaAPI DocAndroid 5.1 API8879Thu Mar 12 22:22:30 GMT 2015android.filterpacks.ui

SurfaceTargetFilter

public class SurfaceTargetFilter 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 android.view.Surface
mSurface
Required. Sets the destination surface for this node. This assumes that higher-level code is ensuring that the surface is valid, and properly updates Surface parameters if they change.
private int
mScreenWidth
Required. Width of the output surface
private int
mScreenHeight
Required. Height of the output surface
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.core.ShaderProgram
mProgram
private android.filterfw.core.GLEnvironment
mGlEnv
private android.filterfw.core.GLFrame
mScreen
private int
mRenderMode
private float
mAspectRatio
private int
mSurfaceId
private boolean
mLogVerbose
private static final String
TAG
Constructors Summary
public SurfaceTargetFilter(String name)


       
        super(name);

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

        unregisterSurface();
    
public voidfieldPortValueUpdated(java.lang.String name, android.filterfw.core.FilterContext context)

        mScreen.setViewport(0, 0, mScreenWidth, mScreenHeight);
        updateTargetRect();
    
public voidopen(android.filterfw.core.FilterContext context)

        registerSurface();
    
public voidprepare(android.filterfw.core.FilterContext context)

        mGlEnv = context.getGLEnvironment();

        // 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.setClearsOutput(true);
        mProgram.setClearColor(0.0f, 0.0f, 0.0f);

        MutableFrameFormat screenFormat = ImageFormat.create(mScreenWidth,
                                                             mScreenHeight,
                                                             ImageFormat.COLORSPACE_RGBA,
                                                             FrameFormat.TARGET_GPU);
        mScreen = (GLFrame)context.getFrameManager().newBoundFrame(screenFormat,
                                                                   GLFrame.EXISTING_FBO_BINDING,
                                                                   0);

        // Set up cropping
        updateRenderMode();
    
public voidprocess(android.filterfw.core.FilterContext context)

        if (mLogVerbose) Log.v(TAG, "Starting frame processing");

        // 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, "New aspect ratio: " + currentAspectRatio +", previously: " + mAspectRatio);
            mAspectRatio = currentAspectRatio;
            updateTargetRect();
        }

        // See if we need to copy to GPU
        Frame gpuFrame = null;
        if (mLogVerbose) Log.v("SurfaceRenderFilter", "Got input format: " + input.getFormat());
        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
        mGlEnv.activateSurfaceWithId(mSurfaceId);

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

        // And swap buffers
        mGlEnv.swapBuffers();

        if (createdFrame) {
            gpuFrame.release();
        }
    
private voidregisterSurface()

        mSurfaceId = mGlEnv.registerSurface(mSurface);
        if (mSurfaceId < 0) {
            throw new RuntimeException("Could not register Surface: " + mSurface);
        }
    
public voidsetupPorts()

        // Make sure we have a Surface
        if (mSurface == null) {
            throw new RuntimeException("NULL Surface passed to SurfaceTargetFilter");
        }

        // Add input port
        addMaskedInputPort("frame", ImageFormat.create(ImageFormat.COLORSPACE_RGBA));
    
public voidtearDown(android.filterfw.core.FilterContext context)

        if (mScreen != null) {
            mScreen.release();
        }
    
private voidunregisterSurface()

        if (mSurfaceId > 0) {
            mGlEnv.unregisterSurfaceId(mSurfaceId);
        }
    
public voidupdateRenderMode()

        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 {
                throw new RuntimeException("Unknown render mode '" + mRenderModeString + "'!");
            }
        }
        updateTargetRect();
    
private voidupdateTargetRect()

        if (mScreenWidth > 0 && mScreenHeight > 0 && mProgram != null) {
            float screenAspectRatio = (float)mScreenWidth / mScreenHeight;
            float relativeAspectRatio = screenAspectRatio / mAspectRatio;

            switch (mRenderMode) {
                case RENDERMODE_STRETCH:
                    mProgram.setTargetRect(0, 0, 1, 1);
                    break;
                case RENDERMODE_FIT:
                    if (relativeAspectRatio > 1.0f) {
                        // Screen is wider than the camera, scale down X
                        mProgram.setTargetRect(0.5f - 0.5f / relativeAspectRatio, 0.0f,
                                               1.0f / relativeAspectRatio, 1.0f);
                    } else {
                        // Screen is taller than the camera, scale down Y
                        mProgram.setTargetRect(0.0f, 0.5f - 0.5f * relativeAspectRatio,
                                               1.0f, relativeAspectRatio);
                    }
                    break;
                case RENDERMODE_FILL_CROP:
                    if (relativeAspectRatio > 1) {
                        // Screen is wider than the camera, crop in Y
                        mProgram.setTargetRect(0.0f, 0.5f - 0.5f * relativeAspectRatio,
                                               1.0f, relativeAspectRatio);
                    } else {
                        // Screen is taller than the camera, crop in X
                        mProgram.setTargetRect(0.5f - 0.5f / relativeAspectRatio, 0.0f,
                                               1.0f / relativeAspectRatio, 1.0f);
                    }
                    break;
            }
        }