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 ?
Camera2 is the latest low-level Android camera package and replaces the deprecated Camera class. Camera2 provides in-depth controls for complex use cases, but requires you to manage device-specific configurations. You can read about specific Camera2 classes and functions in the reference documentation.
The camera-specific Application Programming Interface (API) resides on top of the HAL and acts as an app-level public framework. In a nutshell, the Camera API allows apps to probe the camera features on a device in a streamlined manner, without bothering about the nitty-gritty of the camera sensor.
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);
}
}
}
}
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With