I'm trying to learn Camera2 API and I have built a simple camera app just for taking pictures but the problem that I'm facing is that the preview is stretched for some resolutions. I went through a number of different posts and all them suggested that my aspect ratio might be wrong but I have used google's recommended AutoFitTextureView with the correct aspect ratio still my preview is stretched. I downloaded some open source camera apps from playstore and a bunch of them also had the same issue with my front camera(EXCEPT OPEN CAMERA) but the funny part is I used my same app in another device and the preview was absolutely perfect. So finally I decided to test my app with different resolutions and observe the results but I couldn't find any pattern can anyone please help me to make some sense out of it???
my device display size is 720x1280
Front camera results:
SurfaceTexture AutoFitTextureView Result
buffer size size
2576x1932 720x960 Normal
2560x1440 720x1280 Normal
2048x1536 720x960 Normal
2048x1152 720x1280 Normal
1920x1920 720x720 Normal
1920x1080 720x1280 Normal
1440x1080 720x960 Horizontally Stretched
1280x720 720x1280 Horizontally Stretched
1072x1072 720x720 Normal
960x720 720x960 Normal
720x480 720x1080 Horizontally Stretched
640x480 720x960 Horizontally Stretched
352x288 720x880 Normal
320x240 720x960 Normal
256x144 720x1280 Horizontally Stretched
176x144 720x880 Normal
They key is to set the correct transform on the TextureView on which you're rendering the preview. The TextureView's width and height are set to match its parent layout.
TextureView textureView;
void setTextureTransform(CameraCharacteristics characteristics) {
Size previewSize = getPreviewSize(characteristics);
int width = previewSize.getWidth();
int height = previewSize.getHeight();
int sensorOrientation = getCameraSensorOrientation(characteristics);
// Indicate the size of the buffer the texture should expect
textureView.getSurfaceTexture().setDefaultBufferSize(width, height);
// Save the texture dimensions in a rectangle
RectF viewRect = new RectF(0,0, textureView.getWidth(), textureView.getHeight());
// Determine the rotation of the display
float rotationDegrees = 0;
try {
rotationDegrees = (float)getDisplayRotation();
} catch (Exception ignored) {
}
float w, h;
if ((sensorOrientation - rotationDegrees) % 180 == 0) {
w = width;
h = height;
} else {
// Swap the width and height if the sensor orientation and display rotation don't match
w = height;
h = width;
}
float viewAspectRatio = viewRect.width()/viewRect.height();
float imageAspectRatio = w/h;
final PointF scale;
// This will make the camera frame fill the texture view, if you'd like to fit it into the view swap the "<" sign for ">"
if (viewAspectRatio < imageAspectRatio) {
// If the view is "thinner" than the image constrain the height and calculate the scale for the texture width
scale = new PointF((viewRect.height() / viewRect.width()) * ((float) height / (float) width), 1f);
} else {
scale = new PointF(1f, (viewRect.width() / viewRect.height()) * ((float) width / (float) height));
}
if (rotationDegrees % 180 != 0) {
// If we need to rotate the texture 90º we need to adjust the scale
float multiplier = viewAspectRatio < imageAspectRatio ? w/h : h/w;
scale.x *= multiplier;
scale.y *= multiplier;
}
Matrix matrix = new Matrix();
// Set the scale
matrix.setScale(scale.x, scale.y, viewRect.centerX(), viewRect.centerY());
if (rotationDegrees != 0) {
// Set rotation of the device isn't upright
matrix.postRotate(0 - rotationDegrees, viewRect.centerX(), viewRect.centerY());
}
// Transform the texture
textureView.setTransform(matrix);
}
int getDisplayRotation() {
switch (textureView.getDisplay().getRotation()) {
case Surface.ROTATION_0:
default:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return 270;
}
}
Size getPreviewSize(CameraCharacteristics characteristics) {
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class);
// TODO: decide on which size fits your view size the best
return previewSizes[0];
}
int getCameraSensorOrientation(CameraCharacteristics characteristics) {
Integer cameraOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
return (360 - (cameraOrientation != null ? cameraOrientation : 0)) % 360;
}
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