0

I have found that the CameraPreview is displayed in a small area when I use the PreviewFrameLayout and is stretched when I use the aspect ratio and the FrameLayout. Here is the code that I currently use to set the Camera Preview and the FrameLayout size:

   private Size getOptimalPreviewSize(Activity currentActivity,
        List<Size> sizes, double targetRatio) {
    // Use a very small tolerance because we want an exact match.
    final double ASPECT_TOLERANCE = 0.001;
    if (sizes == null) return null;

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

    // Because of bugs of overlay and layout, we sometimes will try to
    // layout the viewfinder in the portrait orientation and thus get the
    // wrong size of mSurfaceView. When we change the preview size, the
    // new overlay will be created before the old one closed, which causes
    // an exception. For now, just get the screen size

    Display display = currentActivity.getWindowManager().getDefaultDisplay();

    int targetHeight = Math.min(display.getHeight(), display.getWidth());

    if (targetHeight <= 0) {
        // We don't know the size of SurfaceView, use screen height
        targetHeight = display.getHeight();

    }

    // Try to find an size match aspect ratio and size
    for (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);
        }
    }

    // Cannot find the one match the aspect ratio. This should not happen.
    // Ignore the requirement.
    if (optimalSize == null) {
        Log.w(TAG, "No preview size match the aspect ratio");
        minDiff = Double.MAX_VALUE;
        for (Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {

                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}

//this is what I really want to use:
private Size getDesiredPictureSize(List<Size> supportedSizeList)
{
    //Resolution is widthxheight

    Size result=null;
    final int minArea=500*500;  
    final int maxArea=1000*1000;
    for(Size size:supportedSizeList)
    {
        if(size.width*size.height>minArea && size.width*size.height<maxArea)
        {
            if(result==null)
                result=size;
            else
            {
                int resultArea=result.width*result.height;
                int sizeArea=size.width*size.height;
                if(resultArea<sizeArea)
                {   
                    result=size;
                }   
            }
        }
    }
    return result;
}

//I am just testing with this method:  
private Size getBestPictureSize(List<Size> supportedSizeList)
{
    Size result=null;
    for(Size size:supportedSizeList)
    {
        if(result==null)
            result=size;
            int resultArea=result.width*result.height;
            int sizeArea=size.width*size.height;
            if(resultArea<sizeArea)
                result=size;
    }
    return result;
}

List<Size> supportedPictureSizes=mParameters.getSupportedPictureSizes();
    List<Size> supportedPreviewSizes=mParameters.getSupportedPreviewSizes();

        Log.d(TAG,"Setting picture size");
        mPictureSize=getBestPictureSize(supportedPictureSizes);
        Log.d(TAG,"The Picture Width: "+mPictureSize.width+" The Picture Height: "+mPictureSize.height);

    double targetRatio=(double)mPictureSize.width/mPictureSize.height;
    mPreviewSize=getOptimalPreviewSize(this,supportedPreviewSizes, targetRatio);
    Log.d(TAG, "The Preview Width:"+mPreviewSize.width+" Preview Height: "+mPreviewSize.height);
    double ratio=(double)mPreviewSize.width/mPreviewSize.height;
    Log.d(TAG,"Picture Ratio: "+targetRatio);
    Log.d(TAG, "Preview Ratio: "+ratio);
    int new_width=0, new_height=0;
    if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT)
    {
        if((double)previewFrame.getWidth()/previewFrame.getHeight()<ratio)
        {
            new_width=(int)(Math.round(previewFrame.getHeight()*ratio));
            new_height=getWindowManager().getDefaultDisplay().getHeight();
        }
        else
        {
            new_width=getWindowManager().getDefaultDisplay().getHeight();
            new_height=(int)Math.round((double)new_width/ratio);
        }
      }

 if(getResources().getConfiguration().orientation==Configuration.ORIENTATION_LANDSCAPE)
    {
        if((double)previewFrame.getWidth()/previewFrame.getHeight()<ratio)
        {
            new_width=(int)(Math.round(previewFrame.getHeight()*ratio));
            new_height=getWindowManager().getDefaultDisplay().getHeight();
        }
        else
        {
            new_width=getWindowManager().getDefaultDisplay().getWidth();
            new_height=(int)Math.round((double)new_width/ratio);
        }
    }


//Should I set the size of the container first???
 mParameters.setPictureSize(mPictureSize.width, mPictureSize.height);
    mParameters.setPreviewSize(mPreviewSize.width,mPreviewSize.height);
    previewFrame.setLayoutParams(new RelativeLayout.LayoutParams(new_width, new_height));  

I found that using the PreviewFrameLayout from AOSP displayed my CDamera Preview in a box and not full-screen,details of my use of PreviewFrameLayout can be found at Camera Preview does not appear full screen(displayed in a box)

Community
  • 1
  • 1
vamsiampolu
  • 6,328
  • 19
  • 82
  • 183

1 Answers1

1

First of all, if you use FrameLayout in your xml to host previewFrame, you should also call

previewFrame.setLayoutParams(new FrameLayout.LayoutParams(new_width, new_height));

Next, you can see that whether getResources().getConfiguration().orientation==Configuration.ORIENTATION_PORTRAIT or Configuration.ORIENTATION_LANDSCAPE, you do the same calculations, so this orientation is not relevant at all.

Finally, you should set the camera orientation when the screen is rotated.

I believe that you can find a [working example here] (https://stackoverflow.com/a/19448369/192373).

Community
  • 1
  • 1
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • get a ClassCastException upon using FrameLayout.LayoutParams,my layout and the error here http://pastebin.com/grSSH3v0 – vamsiampolu Jan 22 '14 at 05:41
  • I happen to be setting the camera orientation at many places at once like this http://pastebin.com/8zXXJCwB – vamsiampolu Jan 22 '14 at 05:47
  • removing the code for landscape when computing width and height turns the preview into a box in landscape – vamsiampolu Jan 22 '14 at 05:53
  • Changing the code to only use rotation in `getDisplayOrientation` and nowhere else causes this to occur http://pastebin.com/kyikWLDQ – vamsiampolu Jan 22 '14 at 07:01
  • can I use OrientationEventListener with SENSOR_DELAY_FASTEST to ensure that landscape1-->landscape2 does not cause 180 degree flip – vamsiampolu Jan 22 '14 at 07:26
  • No, SENSOR_DELAY_FASTEST will not help you with that. But you should not be worried: even if the sensor response is delayed by few milliseconds, you will still find that the orientation is reverse landscape, and can take care of that. You can not wait for a rotation event to recalculate the orientation. You should be constantly listening to accelerator sensor, and keep track of the calculated orientation, as shown in the [example](http://stackoverflow.com/a/10218309/192373) I referenced above. – Alex Cohn Jan 22 '14 at 10:07