0

I have a weird problem with my Camera-SurfaceHolder.

I want to show the image of the camera in my activity. It all works greatly on my GalaxyS1 (CyanogenMod - Android 4.4) On my S3 (also CyanogenMod - Android 4.4) on the other hand it looks weird.

The landscape image without title bar is okay but when I show the title bar or turn it into portrait mode it looks distorted:

enter image description here

--- EDIT ---

Thank you Alex Cohn for your help. It looks like you are right. The preview for the portraid mode is now working nicely. But still it looks distorted on the landscape view. I checked the preview scale and it looks okay. As far as I can see I set the preview size properly, too. So what is wrong with it?

Here is the current code:

    private static final String TAG = CameraView.class.getSimpleName();

      private SurfaceHolder surfaceHolder;
      private Camera camera;
      private List<Size> mSupportedPreviewSizes;
      private Size mPreviewSize;

      public CameraView(Activity activity) {
        super(activity);
        surfaceHolder = getHolder();
        surfaceHolder.addCallback(this);
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        camera = Camera.open();
        mSupportedPreviewSizes = camera.getParameters()
                .getSupportedPreviewSizes();
        setCameraDisplayOrientation(activity, 0, camera);
      }

      @Override
      public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Camera.Parameters parameters = camera.getParameters();
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        camera.setParameters(parameters);
        camera.startPreview();
      }

      @Override
      public void surfaceCreated(SurfaceHolder holder) {
       try {
         camera.setPreviewDisplay(holder);
       } catch (IOException exception) {
             camera.release();
             camera = null;
       }
      }

     @Override
       public void surfaceDestroyed(SurfaceHolder arg0) {
       camera.stopPreview();
       camera.release();
       camera = null;
     }

   @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);
    }
  }

  private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w,
                int h) {...}

  public static void setCameraDisplayOrientation(Activity activity,
                int cameraId, Camera camera) {...}

--- EDIT ---

I logged the values for the onMeasure and surface Changed. They seem to be ok:

Portrait:

SURFACE CHANGED: Witdh:720 Height:1134

onMeasure: width:720 height:1134

Landscape:

SURFACE CHANGED: Witdh:1280 Height:590

onMeasure: width:1280 height:590

Preview Size: Width: 704 Height:576

I get the following possible preview sizes.

There are 8 elements in the array:

960 x 720, 1280 x 720, 1184 x 666, 960 x 640, 704 x 576, 640 x 480, 352 x 288, 320 x 240

Hopefully anyone can help!

Thanks, Tobias

Tobias Reich
  • 4,952
  • 3
  • 47
  • 90

1 Answers1

2

The source of your problem is the following line:

parameters.setPreviewSize(w, h);

in surfaceChanged() method. You cannot set preview size to arbitrary values in Android. You should only use the pairs of (w, h) as returned by Parameters.getSupportedPreviewSizes(). Otherwise, you hit the appearing to succeed is a valid form of undefined behavior situation. Actually, many devices will simply raise a RuntimeException on camera.setParameters(parameters), but your dev platforms chose to behave differently.

There is no requirement that the preview size be same as the surface used to display it, e.g. using 320x240 preview on a 640x480 surface is OK. But if your preview and surface have different aspect ratios, than the image will look stretched (see https://i.stack.imgur.com/VFwes.jpg). Minor distortions may be tolerable, like using 1280x720 preview on 800x400 pixel sceen, but above certain threshold, you have no choice but to only use part of the screen, leaving margins above and below the preview.

You can find what the developers community came up with: use getOptimalPreviewSize() for given width, hight (this is just one example).

Community
  • 1
  • 1
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • Wow, this seems to help. The portrait mode works this way. Still I get problems in landscape (see code). Maybe you know why? Thanks so far! – Tobias Reich Mar 25 '14 at 14:08
  • Would you kindly print to log the size that you are choosing and the `w, h` parameters in both `surfaceChanged()` and `onMeasure()` callbacks. – Alex Cohn Mar 25 '14 at 19:38
  • I logged the values. They seem to be ok but perhaps you find something. I guess it has to do something with the title bar since it seems to work find in fullscreen. – Tobias Reich Mar 29 '14 at 17:40
  • So, what is the preview size that you `getOptimalPreviewSize()` choose for 1280x590? – Alex Cohn Mar 29 '14 at 21:04
  • Preview Size is: Width: 704 Height:576 - used from the function in OnMeasure(); Besides: if I set the preview automatically to, say, 320 x 240 it works fine (just stretched) as planed! – Tobias Reich Mar 30 '14 at 13:01
  • 1280 x 720 also works as expected! So is it possible that one of the "possible preview sizes" is not working correctly? – Tobias Reich Mar 30 '14 at 13:12
  • `Camera.Paramaters.getSupportedPreviewSizes()` may be not 100% reliable. Still, I would be very much surprised if this list includes 704x576 frame size. Anyways, you can see the full list of truly supported preview sizes for S3 device (and lots of other useful data) at http://androidfragmentation.com/database/v/dr/622716/oem/Samsung/dm/I9300/ – Alex Cohn Mar 30 '14 at 19:46
  • well I did it with the function from the other stackoverflos page you linked. And after all, the other preview sizes all look fine! – Tobias Reich Mar 31 '14 at 13:03
  • I see. But just of pure curiosity, what is the list you have for your S3? – Alex Cohn Mar 31 '14 at 16:48
  • There are 8 elements in the array: 960 x 720, 1280 x 720, 1184 x 666, 960 x 640, 704 x 576, 640 x 480, 352 x 288, 320 x 240 – Tobias Reich Apr 01 '14 at 11:35
  • Well, I decided to accept this as a mystery I can't solve right now. I wanted to do it fullscreen anyway so there are other things to solve first. Thank you for your help! – Tobias Reich Apr 01 '14 at 11:45
  • The stock ROM reports preview-size-values=176x144,320x240,352x288,480x320,480x368,640x480,720x480,800x480,864x480,1280x720 for main, and preview-size-values=176x144,320x240,352x288,640x480,720x480 for front camera. I guess the bug may be in CyanogenMod. – Alex Cohn Apr 02 '14 at 20:24
  • Might be the case but unfortunately I can't check this right now. But I will try to get another S3 to check this! :) – Tobias Reich Apr 07 '14 at 10:21