Fitting a camera preview to a SurfaceView larger than the display

18,521

Ok, I know this is very late as an answer but it is possible. Below is code from the Android SDK sample. To see the rest of the code to implement this download the android sdk samples and go to Samples/android-10(one I used, could try whichever you want to target)/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java

class PreviewSurface extends ViewGroup implements SurfaceHolder.Callback {
...
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
    if (changed && getChildCount() > 0) {
        final View child = getChildAt(0);

        final int width = r - l;
        final int height = b - t;

        int previewWidth = width;
        int previewHeight = height;
        if (mPreviewSize != null) {
            previewWidth = mPreviewSize.width;
            previewHeight = mPreviewSize.height;
        }

        // Center the child SurfaceView within the parent.
        if (width * previewHeight > height * previewWidth) {
            final int scaledChildWidth = previewWidth * height / previewHeight;
            child.layout((width - scaledChildWidth) / 2, 0,
                    (width + scaledChildWidth) / 2, height);
        } else {
            final int scaledChildHeight = previewHeight * width / previewWidth;
            child.layout(0, (height - scaledChildHeight) / 2,
                    width, (height + scaledChildHeight) / 2);
        }
    }
}
}

this code is intended to fit the preview to the smallest dimension (that doesn't mess up the aspcect ratio) and center to have black bars on the other dimension. But if you flip the > to be < instead you will achieve what you want. Ex:

if (width * previewHeight < height * previewWidth) {...
Share:
18,521

Related videos on Youtube

Daniel Smith
Author by

Daniel Smith

Updated on September 15, 2022

Comments

  • Daniel Smith
    Daniel Smith over 1 year

    I have an Android application that needs to fullscreen a camera preview regardless of the preview size given by getSupportedPreviewSizes() without distortion. I expect this to crop the preview by some amount in either the height or width, but this does not concern me. The reason I seek to do this is because certain android cameras (e.g. Samsung Galaxy SII front facing camera) do not return any previews with the same aspect ratio as the display, and therefore need to be stretched and clipped.

    Is it possible to fully grow the camera preview to a view larger than the display size? It is possible to grow the SurfaceView larger than the preview pixel dimensions returned by simply setting the surface view's layout params to match_parent, but this results in distortion in some direction and only is possible up until the preview fills the display. This seems to indicate that previewing outside of the display is impossible, and the hardware (or OS) limits such behavior.

    There is another question on the topic, but that question claims it is not possible to create a SurfaceView greater than the screen dimensions, which is false, as I have found with logging. However, what seems to be the case is that camera preview however cannot grow to the full size of an enormous SurfaceView.

    My Attempt:

    I have a relative layout, within it a FrameLayout, and within that I create a SurfaceView. The width of the entire relative layout is set below at 635dp, which is ~double the device's screen size. The FrameLayout matches this sizing and so does the SurfaceView (added programmatically later)

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/camera_activity_layout"
        android:layout_width="635dp"
        android:layout_height="match_parent" >
    
        <FrameLayout
            android:id="@+id/camera_preview"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
        </FrameLayout>
    
    </RelativeLayout>
    

    The following is the code that gets and sets preview size. Here I want to make the camera preview expand to fill the entire FrameLayout (double the screen width). The view shows up and destructs totally normally so I am removing code not related to this particular question because it distracts from the essential question, and my attempt to easily and simply grow the view to some larger-than-display size.

    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    
        ...
    
        public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
            Camera.Parameters parameters = mCamera.getParameters();
            final DisplayMetrics dm = this.getResources().getDisplayMetrics();
                //getBestPreviewSize returns the best preview size, don't worry
                //but some devices do not return one for all camera matching the aspect ratio
            cameraSize = getBestPreviewSize(parameters, dm.heightPixels, dm.widthPixels);
    
            if (cameraSize!=null) {
                parameters.setPreviewSize(cameraSize.width, cameraSize.height);
                mCamera.setParameters(parameters);
            }
    
            FrameLayout.LayoutParams frameParams = (FrameLayout.LayoutParams) this.getLayoutParams();
    
            frameParams.width = 800; //For argument's sake making this ~double the width of the display. Same result occurs if I use MATCH_PARENT
            frameParams.height = LayoutParams.MATCH_PARENT;
            this.setLayoutParams(frameParams);
    
            try {
                mCamera.setPreviewDisplay(mHolder);
                mCamera.startPreview();
    
                Log.d("surfChange","W/H of CamPreview (child) is "+this.getWidth()+"/"+this.getHeight()+" while parent is ");
                Log.d("surfChange","W/H of holder (child) is "+mHolder.getSurfaceFrame().width()+"/"+mHolder.getSurfaceFrame().height()+" while parent is ");
            } catch (Exception e){
            }
        }
    };
    

    I am concerned that the only way to succeed in this endeavor is to somehow render to an openGL surface, but this apparently might be too slow in full color. It is also a pain if the camera preview can simply be stretched and clipped.

    Thanks in advance to any attempts at the solution.

    • Vivek Bajpai
      Vivek Bajpai over 11 years
      Could u pls post ur oncreate() code . or where u call the setcontentview() method
    • Daniel Smith
      Daniel Smith over 11 years
      Why are you curious about that code? It was pretty basic, and simply set the content view to the xml I shared above.
    • Vivek Bajpai
      Vivek Bajpai over 11 years
      ok so i think expanding a view beyond window manager is not possible , i am also looking for zoom in a section of video but using all surface view and custom video view i dnt get any ,video is not cropped beyond the size
    • fadden
      fadden about 10 years
      FWIW, you can find code that adjusts the SurfaceView to maintain a specific aspect ratio, and modifies the camera preview with GLES, in Grafika (github.com/google/grafika). Things get a lot easier with recent releases of Android.
    • Sam
      Sam about 10 years
  • Pandiri Deepak
    Pandiri Deepak almost 6 years
    Awesome.. saved my time.