slott
slott

Reputation: 3335

Camera2 with a SurfaceView

I'm trying to get the new Camera2 working with a simple SurfaceView and I'm having some problems with the live preview. On some devices the image is stretched out of proportions while looking fine on others.

I've setup a SurfaceView that I programatically adjust to fit the size of the preview stream size.

On Nexus 5 this looks fine but one Samsung devices its way off. Also the Samsung devices have a black border on the right part of the preview.

Is it really not possible to work with the SurfaceView or is this the time to switch to TextureView ?

Upvotes: 12

Views: 20359

Answers (3)

paleozogt
paleozogt

Reputation: 6573

In the docs for createCaptureSession it says

For drawing to a SurfaceView: Once the SurfaceView's Surface is created, set the size of the Surface with setFixedSize(int, int) to be one of the sizes returned by getOutputSizes(SurfaceHolder.class)

Upvotes: 1

rcsumner
rcsumner

Reputation: 1663

Yes, it is certainly possible. Note that the SurfaceView and its associated Surface are two different things, and each can/must be assigned a size.

The Surface is the actual memory buffer which will hold the output of the camera, and thus setting its size dictates the size of the actual image you will get from each frame. For each format available from the camera, there is a small set of possible (exact) sizes you can make this buffer.

The SurfaceView is what does the displaying of this image when it is available, and can basically be any size in your layout. It will stretch its underlying associated image data to fit whatever its layout size is, but note this display size is different from the data's size- Android will resize the image data for display automatically. This is what is probably causing your stretching.

For example, you can make a SurfaceView-based autofit View similar to the camera2basic's AutoFitTextureView as follows (this is what I use):

import android.content.Context;
import android.util.AttributeSet;
import android.view.SurfaceView;

public class AutoFitSurfaceView extends SurfaceView {

    private int mRatioWidth = 0;
    private int mRatioHeight = 0;

    public AutoFitSurfaceView(Context context) {
        this(context, null);
    }

    public AutoFitSurfaceView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public AutoFitSurfaceView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio
     * calculated from the parameters. Note that the actual sizes of parameters don't matter, that
     * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result.
     *
     * @param width  Relative horizontal size
     * @param height Relative vertical size
     */
    public void setAspectRatio(int width, int height) {
        if (width < 0 || height < 0) {
            throw new IllegalArgumentException("Size cannot be negative.");
        }
        mRatioWidth = width;
        mRatioHeight = height;
        requestLayout();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (0 == mRatioWidth || 0 == mRatioHeight) {
            setMeasuredDimension(width, height);
        } else {
            if (width < height * mRatioWidth / mRatioHeight) {
                setMeasuredDimension(width, width * mRatioHeight / mRatioWidth);
            } else {
                setMeasuredDimension(height * mRatioWidth / mRatioHeight, height);
            }
        }
    }
}

Upvotes: 3

Budius
Budius

Reputation: 39856

I've never worked with Camera2 (but very interesting in the new technology) and all I can suggest you is to follow the samples. And if you check it carefully, the sample uses a Custom TextureView, you should probalby try to copy it to your project:

http://developer.android.com/samples/Camera2Basic/src/com.example.android.camera2basic/AutoFitTextureView.html

/**
 * A {@link TextureView} that can be adjusted to a specified aspect ratio.
 */
public class AutoFitTextureView extends TextureView {

also considering that different between SurfaceView and TextureView (theoretically) is just that you can use as a normal view in layout and the other "punches a whole" through the view hierarchy, and that Camera2 is only available in API21+... there should be no harm in migrating to TextureView

Upvotes: -1

Related Questions