Camera Preview Stretched on Few Android Devices

Android Camera Preview is stretched on Full screen

In the surface changed block, you have to choose the optimal size according to your device programmatically.

List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();

this will give you total supported camera sizes. you have to choose appropriate size from this. I have use the function called "chooseOptimalSize".

Size aspectRatio = new Size(matrix.widthPixels, matrix.heightPixels);

Camera.Size previewSize = chooseOptimalSize(previewSizes, PREFERRED_PREVIEW_WIDTH, PREFERRED_PREVIEW_HEIGHT, aspectRatio, this);

This is the function "chooseOptimalSize":-

public static Camera.Size chooseOptimalSize(List<Camera.Size> choices, int width, int height, Size aspectRatio, Context c) {
// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
double ratio = (double) h / w;
int loopCounter=0;
for (Camera.Size size : choices) {
int orientation = c.getResources().getConfiguration().orientation;
if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
//if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=720) {
//if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=3840 ) {
//if((size.getWidth()/16) == (size.getHeight()/9) && size.getWidth() <=5120 ) {//Retina 5K
if((size.width/16) == (size.height/9) && size.width <=7680 ) {//8K UHDTV Super Hi-Vision
Log.e(TAG, "chooseOptimalSize:"+size+"--LoopPosition---==>"+loopCounter);
return size;
}
} else {
Log.e(TAG, "chooseOptimalSize:--given--"+size);
if((size.width/16) == (size.height/9) && ((size.width <=1280)||(size.height<=1920))) {
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=4320 ) ) {//8K UHDTV Super Hi-Vision
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=2880 ) ) {//Retina 5K
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=2160 ) ) {
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=1280 ) ) {
//if((size.getWidth()/16) == (size.getHeight()/9) && (size.getWidth() <=4480 && size.getWidth() >=1280) ) {
Log.e(TAG, "chooseOptimalSize:"+size+"-16:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((size.width/18) == (size.height/9) && ((size.width <=3840)||(size.height<=2160))) {
Log.e(TAG, "chooseOptimalSize:"+size+"-18:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((size.width/18.5) == (size.height/9) && ((size.width <=3840)||(size.height<=2160))) {
Log.e(TAG, "chooseOptimalSize:"+size+"-18.5:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((width/19) == (height/9) && ((width <=3840)||(height<=2160))) {
/*if((size.getWidth()/19) == (size.getHeight()/9) && ((size.getWidth() <=3840)||(size.getHeight()<=2160))) {*/
Log.e(TAG, "chooseOptimalSize:"+size+"-19:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else if((size.width/19.5) == (size.height/9) && ((size.width<=3840)||(size.height<=2160))) {
Log.e(TAG, "chooseOptimalSize:"+size+"-19.5:9"+"--LoopPosition---==>"+loopCounter);
return size;
}else{
Log.e(TAG, "chooseOptimalSize"+" not proper aspect resolution");
}
//2340
}

// if(screenWidth==size.getWidth()){
// Log.e(TAG1, loopCounter+".choose:width Matched:"+screenWidth+"="+size.getWidth());
// }else{
// Log.e(TAG1, loopCounter+".choose:width Not Matched:"+screenWidth+"="+size.getWidth());
// }
//
// if(screenHeight==size.getHeight()){
// Log.e(TAG1, loopCounter+".choose:height Matched:"+screenHeight+"="+size.getHeight());
// }else{
// Log.e(TAG1, loopCounter+".choose:height Not Matched:"+screenHeight+"="+size.getHeight());
// }
loopCounter++;
}
// Pick the smallest of those, assuming we found any
// if (bigEnough.size() > 0) {
// return Collections.min(bigEnough, new CompareSizesByArea());
// } else {
// Log.e(TAG, "Couldn't find any suitable preview size");
return choices.get(0);
// }
}

/*
* Compares two {@code Size}s based on their areas.
*/
static class CompareSizesByArea implements Comparator<Size> {
@Override
public int compare(Size lhs, Size rhs) {
// We cast here to ensure the multiplications won't overflow
return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
(long) rhs.getWidth() * rhs.getHeight());
}
}

you can uncomment the code if you want in my case there is no need of that code.

This function will give you optimal size of the device's camera. you can set that using :

parameters.setPreviewSize(previewSize.width,previewSize.height);

and you are done !!!

Android Camera2 preview is stretched

Camera2 is very hard to learn as a beginner. Consider using camera libraries that does the most parts. Here is one which is the best that I have found : https://camerakit.io/docs. It's really easy and it will take care all of the problems that you are facing right now.


(Note that I do not own this project and I am not promoting it in anyway. I have tried camera2 API and it really is hard, which is why I suggested an easier solution.

Android Camera Preview Stretched

I'm using this method -> based on API Demos to get my Preview Size:

private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;

if (sizes == null) return null;

Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;

int targetHeight = h;

for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}

if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}

As you can see you have to input width and height of your screen. This method will calculate screen ratio based on those values and then from the list of supportedPreviewSizes it will choose the best for you from avaliable ones. Get your supportedPreviewSize list in place where Camera object isn't null by using

mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();

And then on in onMeasure you can get your optimal previewSize like that:

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);

if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
}

And then (in my code in surfaceChanged method, like I said I'm using API Demos structure of CameraActivity code, you can generate it in Eclipse):

Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.startPreview();

And one hint for you, because I did almost the same app like you. Good practice for Camera Activity is to hide StatusBar. Applications like Instagram are doing it. It reduces your screen height value and change your ratio value. It is possible to get strange Preview Sizes on some devices (your SurfaceView will be cut a little)


And to answer your question, how to check if your preview ratio is correct? Then get height and width of parameters that you set in:

mCamera.setParameters(parameters);

your set ratio is equal to height/width. If you want camera to look good on your screen then height/width ratio of parameters that you set to camera must be the same as height(minus status bar)/width ratio of your screen.

Camera PreviewView is stretched in some Android devices

Solved!

I had a default values for the BufferSize of my texture, which just are restarted when I inicializated a new Session or after change the after ratio. But the Width and Height values for the texture were not updated with the ratio, so it becomes streched again and again.

I solved it changing my defaultbufferSize with the PreviewSizes which I update always that i change the ratio.

   public void createCameraPreviewSession(Size previewsize, Surface recordingSurface) {
try {
if (mCaptureSession != null) {
mCaptureSession.stopRepeating();
mCaptureSession.close();
mCaptureSession = null;
}

SurfaceTexture texture = mTextureView.getSurfaceTexture();
assert texture != null;

List<Surface> surfaces = new ArrayList<Surface>();

// We configure the size of default buffer to be the size of camera preview we want.
texture.setDefaultBufferSize(previewsize.getWidth(),previewsize.getHeight());
;
// This is the output Surface we need to start preview.
Surface surface = new Surface(texture);
.......

Android Camera Preview Stretched in Preview, Not After Picture Taken

I found this comment in another post that solved my issue!

It changes the size of the view so that the image isn't stretched while always trying to fill the screen.

My camera preview is stretched and squashed. How can I solve this problem?

You should take a look at the official Android Camera2 sample from Google: https://github.com/googlesamples/android-Camera2Basic

Specifically, what you are trying to achieve is mostly accomplished by the AutoFitTextureView class and the chooseOptimalSize method in the Camera2BasicFragment file, here's a snippet:

private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
int textureViewHeight, int maxWidth, int maxHeight, Size aspectRatio) {

// Collect the supported resolutions that are at least as big as the preview Surface
List<Size> bigEnough = new ArrayList<>();
// Collect the supported resolutions that are smaller than the preview Surface
List<Size> notBigEnough = new ArrayList<>();
int w = aspectRatio.getWidth();
int h = aspectRatio.getHeight();
for (Size option : choices) {
if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
option.getHeight() == option.getWidth() * h / w) {
if (option.getWidth() >= textureViewWidth &&
option.getHeight() >= textureViewHeight) {
bigEnough.add(option);
} else {
notBigEnough.add(option);
}
}
}

// Pick the smallest of those big enough. If there is no one big enough, pick the
// largest of those not big enough.
if (bigEnough.size() > 0) {
return Collections.min(bigEnough, new CompareSizesByArea());
} else if (notBigEnough.size() > 0) {
return Collections.max(notBigEnough, new CompareSizesByArea());
} else {
Log.e(TAG, "Couldn't find any suitable preview size");
return choices[0];
}
}

Getting started with Android Camera2 API can be pretty daunting. Besides the official documentation and the aforementioned official sample, there are also a few (hopefully) helpful blog posts like:

  • https://medium.com/androiddevelopers/camera-enumeration-on-android-9a053b910cb5
  • https://medium.com/androiddevelopers/understanding-android-camera-capture-sessions-and-requests-4e54d9150295


Related Topics



Leave a reply



Submit