Skip to content
This repository has been archived by the owner on Sep 20, 2019. It is now read-only.

Camera2 1440x1080 is maximum? What? #123

Closed
anonym24 opened this issue Sep 17, 2018 · 23 comments
Closed

Camera2 1440x1080 is maximum? What? #123

anonym24 opened this issue Sep 17, 2018 · 23 comments

Comments

@anonym24
Copy link

anonym24 commented Sep 17, 2018

I'm trying to display normal Full HD preview in landscape orientation (1920x1080) using Camera2, but camera returns 1440x1080 as the highest resolution.

With Legacy Camera (android.hardware.camera) there was no such issue for the same device. What am I doing wrong?

CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];

for (Size size : map.getOutputSizes(SurfaceTexture.class)) {
    Log.i(TAG, "imageDimension " + size);
}

Output:

imageDimension 1440x1080
imageDimension 1280x960
imageDimension 1280x720
imageDimension 864x480
imageDimension 640x640
imageDimension 832x486
imageDimension 800x480
imageDimension 720x480
imageDimension 768x432
imageDimension 640x480

Also it seems that to correctly display preview in landscape we need a lot of headache code like:

private void configureTransform(int viewWidth, int viewHeight) {
        Activity activity = getActivity();
        if (null == mTextureView || null == mPreviewSize || null == activity) {
            return;
        }
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        Matrix matrix = new Matrix();
        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
        float centerX = viewRect.centerX();
        float centerY = viewRect.centerY();
        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / mPreviewSize.getHeight(),
                    (float) viewWidth / mPreviewSize.getWidth());
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(90 * (rotation - 2), centerX, centerY);
        } else if (Surface.ROTATION_180 == rotation) {
            matrix.postRotate(180, centerX, centerY);
        }
        mTextureView.setTransform(matrix);
    }

From official sample https://github.com/googlesamples/android-Camera2Basic/blob/master/Application/src/main/java/com/example/android/camera2basic/Camera2BasicFragment.java#L740

Isn't Camera2 supposed to make things easier than legacy camera? I'm not sure...

Though one good thing I see: we can set many surface targets, with legacy camera we could not use setPreviewDisplay and setPreviewTexture together, but Camera2 allows many outputs

@anonym24
Copy link
Author

anonym24 commented Sep 17, 2018

Next information depressed me:

image

https://stackoverflow.com/questions/31362202/android-camera2-output-sizes#comment50709560_31362202

p.s. I have tested on Xiaomi device

@GuanacoDevs
Copy link

@anonym24 I'm not really sure if I can help you, but that's kinda concerning...
For what I understand you want to fill the whole screen with the image without distortion, I think that your best bet at the moment is to come up with a method that will return the biggest output size that is lesser or equals to your device screen; which in this particular case shall be the third option: imageDimension 1280x720, currently you are not choosing the best but choosing the first. And obviusly you have to make sure that the imageReader is also set to the same 16:9 proportion as the autoFitTextureView
Are you using the chooseOptimalSize() method?
If you come up with a method that will guarantee that you get 1280x720 your preview might be streched because in your layout you have match_parent and it will be stretched to fill the parent, but not distorted and I think that should give you what you want, no?
Perhaps you could try imageDimension = new Size(1920, 1080); for testing purposes only, I think it will crash as it is not supported.
Also you might want to check what you get from here to check if you are getting the 16:9 proportion for your imageReader from map.getOutputSizes(ImageFormat.JPEG)

Regards

@GuanacoDevs
Copy link

@anonym24 Would you mind trying my app to see how my camera is displayed on your device, you made me doubt and I have no device like yours to test it, although since I'm using chooseOptimalSize() I think it should be ok.
My camera is used to read numbers from a Bingo Card, you don't need to read a Bingo Card only open the camera and check that is ok in your device.
To open the camera in my app:
Menu(top-left)>My Cards>FAB(bottom-right)>Camera(bottom-center)
My app
UBV

@anonym24
Copy link
Author

anonym24 commented Sep 18, 2018

chooseOptimalSize doesn't make sense here cause it also chooses from that list chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class)..., and it chooses 1440x1080 (you aren't correct about 1280x720, anyway I don't need 1280x720)

Manually I also tried to set 1920x1080 (texture.setDefaultBufferSize(1920, 1080), no crashes, it just stretched 1440 to 1920

@anonym24
Copy link
Author

anonym24 commented Sep 18, 2018

using your app it's also not fullscreen (seems also 1080x1440 but portrait orientation):

you can see black at the bottom

UBV

screenshot_2018-09-18-10-37-16-594_com guanacodevs ubv

it should be 1080x1920 (my display size in fullscreen)

@GuanacoDevs
Copy link

GuanacoDevs commented Sep 18, 2018

@anonym24
Thank you for taking the time to test UBV, UBV Camera is OK regarding of what I am expecting, at the end it will crop the top with the guidelines to read the picture, it is located in the internal memory/Android/data/com.guanacodevs.ubv/files

it should be 1080x1920 (my display size in fullscreen)

I just measured the screenshot and it is in fact 1080x1440, the black frame at the bottom is because I have the TextureView to be fixed to the top-center. It chooses 1080x1440 because this is the maximum ratio it gets from map.getOutputSizes(ImageFormat.JPEG) when setting the output ratio for the picture to be taken. You can notice a black frame also in your stock camera when you change resolutions.
I suggest to go:
autoFitTextureView.setAspectRatio(1280, 720)
and
texture.setDefaultBufferSize(1280, 720)
that should show the preview ok(I'm still assuming that you want to show the preview full screen regardless of the resolution not that you want to push the full resolution on the preview)
would you mind sharing your createCameraPreviewSession and setUpCameraOutputs?

EDIT: If what you want is to set 1920x1080 as you would with the deprecated Camera, I'm affraid can't help you any further I was looking for a workaround to get a fullscreen preview.

Regards

@anonym24
Copy link
Author

anonym24 commented Sep 18, 2018

@GuanacoDevs
yes I need normal resolution (fullHd)
because I want to use SurfaceTexture for video recording (MediaCodec + OpenGL)
but Camera2 puts camera frames with 1440x1080 into SurfaceTexture

So I wanted to use two SurfaceTexture (one for preview, another for video recording) - add two targets

@GuanacoDevs
Copy link

@anonym24 Ouch, sorry, know nothing regarding Video Recording.
I have just put together this method that is intended to return the maximum preview size supported that will match your Phisical Screen Ratio only, this should show you a full screen preview.
DISCLAIMER: I just made this one up, tweaking might be a must.

    private Size chooseFullScreenPreview(Size[] sizes) {
        Point displaySize = new Point();
        getWindowManager().getDefaultDisplay().getRealSize(displaySize);
        int screenWidth;
        int screenHeight;
        if (displaySize.x > displaySize.y) {
            screenWidth = displaySize.x;
            screenHeight = displaySize.y;
        } else {
            screenWidth = displaySize.y;
            screenHeight = displaySize.x;
        }
        ArrayList<Size> fullScreenSizes = new ArrayList<>();
        for (Size size : sizes) {
            if (size.getWidth() == size.getHeight() * screenWidth / screenHeight) {
                fullScreenSizes.add(size);
            }
        }
        return Collections.max(fullScreenSizes, new CompareSizesByArea());
    }

Usage:
previewSize = chooseFullScreenPreview(map.getOutputSizes(SurfaceTexture.class));
mediaSize = chooseFullScreenPreview(map.getOutputSizes(MediaRecorder.class));
pictureSize = chooseFullScreenPreview(map.getOutputSizes(ImageFormat.JPEG));

For the Video Recording, maybe changing SurfaceTexture.class for another equivalent that will get you a higher resolution.
Can't help anymore since I haven't gone into Video Recording myself, wish you the best.

Best Regards

@anonym24
Copy link
Author

@GuanacoDevs there is no point to use any calc method as I already tried to manually set 1920x1080 and it didn't work (picture just was stretched from 1440x1080 to 1920x1080)

anyway it doesn't matter anymore as I decided to not use Camera2 api anyway but just stay with legacy api

seems really many phone manufactures just didn't implement it normally

@yudikarma
Copy link

i solve this issue in my case by followed this answer

https://stackoverflow.com/questions/53957388/camera2-api-issue?noredirect=1#comment94752473_53957388

@anonym24
Copy link
Author

anonym24 commented Jan 6, 2019

@yudikarma is this a joke? So did you just crop the frame? And how is it related to this issue?

@anonym24
Copy link
Author

anonym24 commented Jan 6, 2019

Actually all of this in general is normal thing in Android developing. android/sunflower#299

@yudikarma
Copy link

No, before i have isue my preview not full screnn then i chek on here and some one tell to change onmeisure in autofitTextureview.class to make full screen. But that not help, that just scale frame and makes preview full screen and make image capture not same with preview. Then i read this issue and find the problem is camera 2 api output is so small then mw screen. So i need chooseOptimalsize method better to get maximal size output. Then i find and paste that method on that link. So this is not joke

@anonym24
Copy link
Author

anonym24 commented Jan 6, 2019

@yudikarma as I said before already I tried to set FullHD (1920x1080) manually and all I got is stretched 1440x1080 to 1920x1080. If you got a real 1920x1080 with Camera2 on your device it doesn't mean that you can get it 100% on other devices

@alejouribesanchez
Copy link

alejouribesanchez commented Jan 24, 2019

I was having the same issue and it was affecting my preview image size, I checked step by step and I found there was an issue in the AutoFitTextureView class you should replace this

if (width < height * ratioWidth / ratioHeight) by
if (width > height * ratioWidth / ratioHeight)

after that, the function who gets the largest size will work well.

@anonym24
Copy link
Author

anonym24 commented Jan 25, 2019

@alejouribesanchez sorry but you don't understand this issue at all. You didn't even read though it! It's not about a function which chooses resolution!

just for a test you can remove all these calculations, functions, auto texture views

get phone with FullHD display resolution (1920x1080)

use ordinary TextureView, set its width and height as match_parent

set width, height to 1920, 1080 (constants) in your code for texture buffer texture.setDefaultBufferSize(1920, 1080)

you're the second here trying to suggest nonsense without even understanding the issue (as @yudikarma did)

@dnhyde
Copy link

dnhyde commented Mar 31, 2019

I had the same issue...
Sad news is that there is nothing you can do if the phone manufacturer does not support camera2 (Xiaomi as well in my case). Basically checking with CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL in my case it was equal to CameraMetadata.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY.
As stated in the official docs:

LEGACY: These devices expose capabilities to apps through the Camera API2 interfaces that are approximately the same capabilities as those exposed to apps through the Camera API1 interfaces. The legacy frameworks code conceptually translates Camera API2 calls into Camera API1 calls; legacy devices do not support Camera API2 features such as per-frame controls.

But it goes further than that, since apparently the SCALER_STREAM_CONFIGURATION_MAP does have access to all possible resolutions that are available through Camera API1, so there must be something wrong in the "conceptual translation" to Camera API1 calls...
This is quite frustrating for developers...

@shpingalet007
Copy link

Same thing. Developing app using Honor 8X. As described by anonym24 i have same situation with Camera2 API. I give it Surface object with size that i got as supported from Camera2 - 1920x1080. In fact, when my algorithm selects this size and proceed with it, Camera2 give to my Surface object only 1440x1080 image. It is stretched. I have no idea how to solve it.

Camera2 hardware support level of my device is limited.

@anonym24
Copy link
Author

anonym24 commented Aug 6, 2019

@ancaiova you have no idea what are you talking about

read this #123 (comment)

@shpingalet007
Copy link

shpingalet007 commented Aug 9, 2019

@anonym24 i solved my problem. After that i moved ISurfaceHolder.SetFixedSize from SurfaceCreated method to OnMeasure everything is okay.

I placed it before View.SetMeasuredDimension.
It helped me, but something in my soul saying me that you tryied it..
Anyway. It looks now like that:
Снимок экрана 2019-08-09 в 16 42 12

Hope it helps somebody.

@anonym24
Copy link
Author

anonym24 commented Aug 9, 2019

@shpingalet007 you solved nothing

@anonym24 anonym24 closed this as completed Aug 9, 2019
@shpingalet007
Copy link

@anonym24 keep in mind when you creating an issue you are communicating with other. I solved my issue that was the same with described method. If it doesn't works for you - okay. But i tried to help and it worked for me. Good luck

@anonym24
Copy link
Author

anonym24 commented Aug 10, 2019

@shpingalet007 I understand, but you are a fourth or fifth user here who absolutely doesn't understand the problem I described in the question.

You don't need to move any methods if you can set a hardcoded resolution to just test that it doesn't work.

Also there is a method which returns which resolutions supports camera2 on your device:

CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
cameraId = manager.getCameraIdList()[0];
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
assert map != null;
imageDimension = map.getOutputSizes(SurfaceTexture.class)[0];

for (Size size : map.getOutputSizes(SurfaceTexture.class)) {
    Log.i(TAG, "imageDimension " + size);
}

e.g. Output on some Xiaomi devices:

imageDimension 1440x1080 (the highest... not a full hd)
...

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants