2

I am using custom camera in my app built with target sdk 22. I have tested camera through my app on many devices including Samsung S5, Samsung Note 4 and huawei ascend mate 7 and Image preview is fine.

But when I open Camera through my app in Samsung Galaxy S4 (Android 5.0.1) I get camera preview distorted. Following is the image of the preview:

enter image description here

I have seen many posts on stackoverflow but they about after capturing the image and my problem is before capturing the picture.

Following is the code I am using for the preview:

  1. surfaceChanged Method

         public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
            try {
             holder.addCallback(this);
                holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
                Camera.Parameters parameters = camera.getParameters();
                try {
                List<Camera.Size> supportedSizes = null;
                supportedSizes = Compatibility.getSupportedPreviewSizes(parameters);
    
                //preview form factor
                float ff = (float)w/h;
                Log.d("", "Screen res: w:"+ w + " h:" + h + " aspect ratio:" + ff);
    
                //holder for the best form factor and size
                float bff = 0;
                int bestw = 0;
                int besth = 0;
                Iterator<Camera.Size> itr = supportedSizes.iterator();
    
                while(itr.hasNext()) {
                    Camera.Size element = itr.next();
                    //current form factor
                    float cff = (float)element.width/element.height;
    
                    Log.d("Camera", "Candidate camera element: w:"+ element.width + " h:" + element.height + " aspect ratio:" + cff);
                    int currentRes = element.width*element.height;
                    //ff = Asp ratio of current Screen
                    // cff =  Asp ratio of current Size from Size list
                    // bff =  Asp ratio of current best aspect ratio selected
                    if ((Math.abs(ff-cff) <= Math.abs(ff-bff) ) ) {
                          bff=cff;
                          bestw = element.width;
                          besth = element.height;
                         }
                } 
    
                Log.d("Camera", "Chosen camera element: w:"+ bestw + " h:" + besth + " aspect ratio:" + bff);
                if ((bestw == 0) || (besth == 0)){
                    Log.d("Camera", "Using default camera parameters!");
                    bestw = 480;
                    besth = 320;
                    Log.d("Camera","Using default camera parameters! aspect ratio "+480/320);
                }
                parameters.setPreviewSize(bestw, besth);
    
                //Handling camera angle
                switch(this.getWindowManager().getDefaultDisplay().getRotation()){
                case 0:
                    camera.setDisplayOrientation(90);
                    break;
                case 1:
                    camera.setDisplayOrientation(0);
                    break;
                case 2:
                case 3:
                    camera.setDisplayOrientation(180);
                    break;
                }
    
            } catch (Exception ex) {
                parameters.setPreviewSize(480 , 320);
            }
    
            camera.setParameters(parameters);
            camera.startPreview();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
    
  2. Compatibility.getSupportedPreviewSizes(parameters) Method

     @SuppressWarnings("unchecked")
     public static List<Camera.Size> getSupportedPreviewSizes(Camera.Parameters params) {
    List<Camera.Size> retList = null;
    
    try {
        Object retObj = mParameters_getSupportedPreviewSizes.invoke(params);
        if (retObj != null) {
            retList = (List<Camera.Size>)retObj;
        }
    }
    catch (InvocationTargetException ite) {
        /* unpack original exception when possible */
        Throwable cause = ite.getCause();
        if (cause instanceof RuntimeException) {
            throw (RuntimeException) cause;
        } else if (cause instanceof Error) {
            throw (Error) cause;
        } else {
            /* unexpected checked exception; wrap and re-throw */
            throw new RuntimeException(ite);
        }
    } catch (IllegalAccessException ie) {
        //System.err.println("unexpected " + ie);
    }
    return retList;
    }
    

I would appreciate any kind of help.

Thanks in advance.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
Sateesh
  • 103
  • 1
  • 9
  • Which preview size did you choose? – Alex Cohn Aug 28 '15 at 08:53
  • Preview size is 480 by 320 – Sateesh Aug 28 '15 at 09:35
  • You mean, it falls back to 480x320, because none of the supported sizes was not good enough? The problem is, to the best of my knowledge, this resolution is not supported on S4. Results of using unsupported resolution are unpredictable. – Alex Cohn Aug 28 '15 at 18:38
  • Yes, it falls back to 480 * 320. Then what is the solution ? – Sateesh Aug 28 '15 at 22:33
  • There is no supported preview size that answers your criterion. But using a non-supported size is no-no. So, you should loosen your criterion, and also check the [solutions](http://stackoverflow.com/questions/19577299/android-camera-preview-stretched) that fix aspect ratio when the screen and camera sizes don't fit exactly. – Alex Cohn Aug 29 '15 at 06:08

1 Answers1

0

On Samsung Note IV, I realised that you just should not use setPreviewSize(), even though the sizes you get from getSupportedPreviewSizes() ought to be legal and usable.

It is an awkward bug in Samsung's low level camera software. Uncool, Samsung! It reproduces only with some devices.

Still shooting, however, is impeccable. So, here is my code:

    Camera.Parameters parameters = camera.getParameters();

    boolean currentPreviewSettingsAreValid = parameters != null;
    currentPreviewSettingsAreValid = currentPreviewSettingsAreValid && parameters.getPreviewSize() != null;
    currentPreviewSettingsAreValid = currentPreviewSettingsAreValid && parameters.getPreviewSize().width > 0 && parameters.getPreviewSize().height > 0;

    if (parameters != null && !currentPreviewSettingsAreValid) {
        Camera.Size bestSize = getBestSizeOfSupported(parameters.getSupportedPreviewSizes(), width, height);

        if (bestSize != null) {
            parameters.setPreviewSize(bestSize.width, bestSize.height);
        }
    }

Hoping it helps anybody

Meymann
  • 2,520
  • 2
  • 28
  • 22