33

I have developed a small application for displaying camera preview in full screen. I'm using Camera API for this.

This is the activity layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <!-- This is the container for the camera preview screen -->
    <FrameLayout android:id="@+id/camera_preview"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"/>
</LinearLayout>

When device is in portrait, the display is vertically scaled in order to match the height of device screen - so the aspect ratio is not the same as the one from native camera. These are 2 images which explains better what I'm saying:

enter image description hereenter image description here

The first image is made with native camera device. The second image is made with my app, with camera in full screen - the image is skewed, stretched in order to fit on the screen.

I need the camera preview to be full screen, regardless of the preview size given by getSupportedPreviewSizes() mehod and without distortion. Is there a way to accomplish this? Is there a way to maintain proper aspect ratio when camera preview is in full screen? I expected this to be done automatically by OS - cropping the image to match the requested resolution while maintaining aspect ratio, but this does not happen.

I've tried to make the SurfaceView larger than the display (following this question: Fitting a camera preview to a SurfaceView larger than the display), but is not ok in my case since I'm capture snapshots (6 frames/second) and those are not what user sees on the screen (the frame contains all camera preview even if not all of it is visible on the screen).

I posted here: https://www.dropbox.com/s/3d52xt8kazynsae/CameraFullScreen.7z?v=0mcn the entire project I've made.

Any idea/solution is more than important to me. Thanks a lot.

========================================================================

Update due to ss1271 answer:

I'll analyze a little the resolutions you wrote above for Samsung Galaxy Ace II.

I. Screen resolution: 480x800 - aspect ratio 3:5 = 0,6

II. getSupportedPreviewSizes - I'm almost sure that these values are from back camera. Below are the aspects ratio for these resolutions:

   2560x1920   - 0,75

   2560x1536   - 0,60

   2048x1536   - 0,75

   2048x1232   - 0,60

   960x720     - 0,75

   640x480     - 0,75

So, your method will return a Size corresponding to 2560x1536 or to 2048x1232 - these having the same aspect ratio as screen resolution and using these values will not distort the picture. The problem for me is that I cannot use so big resolutions since I capture 6 frames/second and these needs to be saved at a lower resolution.

I'll present below some results from a Samsung S2 device:

I. Screen resolution: 480 x 800 - aspect ratio 3:5 = 0,6

II. Back camera
a). getSupportedPreviewSizes:

800 / 480   - 480/800 = 0,60
800 / 450   - 450/800 = 0,56
720 / 480   - 0,66 
640 / 480   - 0,75
352 / 288   - 0,81
320 / 240   - 0,75
176 / 144   - 0,81

b). Native camera resolutions:

3264 / 2448  - 0,75  - not full screen
3264 / 1968  - 0,60  - FULL SCREEN (since has the same aspect ratio as device screen)
2048 / 1536  - 0,75  - not full screen
2048 / 1232  - 0,60  - FULL SCREEN (same aspect ratio as device screen)
800 / 480    - 0,60  - FULL SCREEN (same aspect ratio as device screen)
640 / 480    - 0, 75 - not full screen

III. Front camera
a). getSupportedPreviewSizes:

640 / 480   - 0,75
352 / 288   - 0,81
320 / 240   - 0,75
176 / 144   - 0,81

b). Native camera is not in full screen and I cannot choose a resolution - the option is disabled.

For S2, back camera, I'm wonder why getSupportedPreviewSizes() method do not return the same resolutions as Native camera does or the ones displayed by native camera are the picture sizes ? I'm wonder why I do not have options like 3264 / 1968, 2048 / 1232 given by getSupportedPreviewSizes() method ? : enter image description here

Community
  • 1
  • 1
Paul
  • 3,812
  • 10
  • 50
  • 73
  • what I want is actually the camera preview to be cropped in order to maintain proper aspect ratio – Paul May 24 '13 at 04:55
  • may I ask: do you require a customized camera or you just want to show the camera viewfinder(preview)? – dumbfingers May 24 '13 at 09:24
  • I have a customized camera, with overlay buttons. – Paul May 24 '13 at 10:28
  • the method `getSupportedPreviewSizes()` returns the preview sizes, and `getSupportedPictureSizes ()` will return the supported picture sizes. For your updated question, according to my experience, Samsung Galaxy devices seems more likely to stretch the preview image while using front camera. But actually you can make the difference as small as possible by comparing the ratios to find out the optimized size (that's why i have a `getOptimalSize` in my answer. :) – dumbfingers Jun 04 '13 at 10:47
  • Hi Paul,I am also facing the same issue.can u help me if solved this problem. I am using front camera in my app.Screen Res is 480*800 and i am getting preview size as 640*480.And the problem is when camera is in landscape then image is shrinking.Thank in advance. – sandeep Apr 04 '14 at 06:43
  • You will need to use a preview size which has the same aspect ratio as the screen aspect ration (or the view where you render the camera aspect ratio). – Paul Apr 04 '14 at 09:13
  • nothing worked for me then i commented the setAspectRatio code and now it is working fine. – sak Jul 01 '20 at 06:36

2 Answers2

28

In a nutshell, you can do a camera preview in full screen however you'll need to find out the appropriate sizes among the supported preview sizes by yourself, only if a customized camera preview is what you want.

For your question, according to the Android Developers -- Camera

If you want to set a specific size for your camera preview, set this in the surfaceChanged() method as noted in the comments above. When setting preview size, you must use values from getSupportedPreviewSizes(). Do not set arbitrary values in the setPreviewSize() method.

It seemed you can't manually pass the size you want other than the sizes provides by getSupportedPreviewSizes(). With a closer examine the sizes supported by your phones camera, you'll find the ratio of sizes supported might not exactly the same as your screen's ratio.

For example, Samsung Galaxy Ace II has 480x800 resolution screen, by reading the Size returned from getSupportedPreviewSizes(), its camera supports:

2560x1920

2560x1536

2048x1536

2048x1232

960x720

640x480

and if you want to display your camera preview in full screen correctly (without stretch), you'll need to calculate, compare and apply the suitable ratio in these supported preview sizes.

Implementation of finding a proper preview size is not that complicated stuff. A common method for doing this would be something like this:

    /**
     * Calculate the optimal size of camera preview
     * @param sizes
     * @param w
     * @param h
     * @return
     */
    private Size getOptimalSize(List<Size> sizes, int w, int h) {

        final double ASPECT_TOLERANCE = 0.2;        
        double targetRatio = (double) w / h;         
        if (sizes == null)             
            return null;          
        Size optimalSize = null;         
        double minDiff = Double.MAX_VALUE;          
        int targetHeight = h;          
        // Try to find an size match aspect ratio and size         
        for (Size size : sizes) 
        {             
//          Log.d("CameraActivity", "Checking size " + size.width + "w " + size.height + "h");            
            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);             
            }         
        }          
        // Cannot find the one match the aspect ratio, ignore the requirement     

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

        SharedPreferences previewSizePref;
        if (cameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
            previewSizePref = getSharedPreferences("PREVIEW_PREF",MODE_PRIVATE);
        } else {
            previewSizePref = getSharedPreferences("FRONT_PREVIEW_PREF",MODE_PRIVATE);
        }

        SharedPreferences.Editor prefEditor = previewSizePref.edit();
        prefEditor.putInt("width", optimalSize.width);
        prefEditor.putInt("height", optimalSize.height);

        prefEditor.commit();

//      Log.d("CameraActivity", "Using size: " + optimalSize.width + "w " + optimalSize.height + "h");            
        return optimalSize;     
    }

And you can also do the similar to find out the suitable camera sizes (the output picture size).

Note: I found the original version of the code above from Internet and I did some modification/optimisation for my own purpose.

Please let me know if this works for you.

dumbfingers
  • 7,001
  • 5
  • 54
  • 80
  • First, Thanks a lot for your answer. I've updated the question in order to respond to your answer for a better visibility. My application is using more front camera than back camera.Seems that, if native camera does not display front camera in fullscreen (at least not on a S2 and S3 phone) because of aspect ratio issue, I will not be able to do the same without distorting the image... – Paul May 24 '13 at 14:14
  • Thanks so much! Not using setPreviewSize() has fixed the issue for me. – BVB Feb 11 '14 at 21:51
  • 2
    anyone finding this thread, i recommend you also look here: http://stackoverflow.com/questions/17348614/make-a-surfaceview-larger-than-the-screen-fitting-a-camera-preview-to-a-surface – Sam Apr 16 '14 at 10:55
  • I am using samsung s7 camera preview showing only half of the screen. – saibaba vali Dec 07 '16 at 10:56
0

I was facing same Issue in Camera2 API, i have used Preview size and devices aspect ratio to solve the issue. You can also do the same with your Camera API.

Community
  • 1
  • 1
Ronak Patel
  • 130
  • 1
  • 10
  • how u fixed this issue ? still gettng stretched preview using camera2 API with textureview – Erum Jan 09 '20 at 10:53
  • No, I am able to fix the texture view stretch issue with below solution : https://stackoverflow.com/questions/37434494/android-camera-2-preview-size-and-devices-aspect-ratio/43516672#43516672 – Ronak Patel Jan 10 '20 at 05:46