首页 文章

在几台Android设备上延伸的相机预览

提问于
浏览
25

我正在为Android应用程序制作自定义相机,如"SnapChat",但相机预览在诸如(Moto g第二代,一个)但很少(三星s3,三星s4)等少数设备上延伸 . 我使用了以下参考Camera display / preview in full screen does not maintain aspect ratio - image is skewed, stretched in order to fit on the screen . 但这对我100%没有帮助 . 我在分享屏幕 .

Stretched image on Samsung Moto G second generation is .
enter image description here

enter image description here

Samsung S3 images which does not stretched is Above

private void setPreviewLayout() {
    if (null == mCamera) {
        return;
    }
    Camera.Parameters parameters = null;
    Camera.Size size = null;
    try {
        int screenWidth = (int) getResources().getDisplayMetrics().widthPixels;
        int screenHeight = (int) getResources().getDisplayMetrics().heightPixels;
        parameters = mCamera.getParameters();
        size = getOptimalPreviewSize(mCamera.getParameters().getSupportedPreviewSizes(), screenWidth, screenHeight);
        if (size != null) {

            parameters.setPreviewSize(size.width, size.height);

        }

        parameters.setPictureSize(screenHeight, screenWidth);
        ;
        mCamera.setParameters(parameters);
        if (on && currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) {
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON);
        } else {
            parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
        }
        parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO);
        parameters.setExposureCompensation(0);
        parameters.setPictureFormat(ImageFormat.JPEG);
        parameters.setJpegQuality(100);
        List<String> focusModes = parameters.getSupportedFocusModes();
        if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        } else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
            parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
        }
        mCamera.setParameters(parameters);
        /*
         * camera.setPreviewDisplay(surfaceHolder); camera.startPreview();
         */

    } catch (Exception e) {
        e.printStackTrace();
    }

}
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.1;
    double targetRatio = (double) h / w;

    if (sizes == null)
        return null;

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

    int targetHeight = h;

    for (Camera.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);
        }
    }

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

3 回答

  • 16

    使用 getOptimalPreviewSize() 很重要,但它并不能解决所有布局中所有设备的所有拉伸问题 . 您必须准备好稍微裁剪预览,以便预览填充屏幕而不会失真 .

    有不同的技术来强制表面的大小不同于实际的屏幕尺寸,但这个我觉得最容易:

    我将 CameraView 添加到我的布局中:

    public class CameraView extends SurfaceView implements SurfaceHolder.Callback {
    
    public CameraView(Context context, AttributeSet attr) {
        super(context, attr);
    
        // install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        getHolder().addCallback(this);
    }
    
    @Override public void surfaceCreated(SurfaceHolder holder) {
        openCamera();
        bCameraInitialized = false;
    }
    
    @Override public void surfaceDestroyed(SurfaceHolder holder) {
        camera.release();
    }
    
    @Override public void surfaceChanged(SurfaceHolder holder,
            int format, int w, int h) {
            if (bCameraInitialized) {
                // we will get here after we have resized the surface, see below 
                return;
            }
            cameraSetup(w, h);
            bCameraInitialized = true;
    }
    
    private void cameraSetup(int w, int h) {
        // set the camera parameters, including the preview size
    
        FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
        double cameraAspectRatio = ((double)optimalSize.width)/optimalSize.height;
    
        if (((double)h)/w > cameraAspectRatio) {
            lp.width = (int)(h/cameraAspectRatio+0.5);
            lp.height = h;
        }
        else {
            lp.height = (int)(w*cameraAspectRatio + 0.5);
            lp.width = w;
            lp.topMargin = (h - lp.height)/2;
        }
        lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
    
        setLayoutParams(lp);
        requestLayout();
    }
    

    为了强调主要思想,我没有包含错误处理,而且我这里没有显示相机如何is actually started with a secondary Looper .

  • 0

    您需要覆盖SurfaceView类的onMeasure方法以获取surfaceview的宽度和高度

    @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(mCamera.getParameters().getSupportedPreviewSizes(), width, height);
            }
        }
    

    然后将您获得的预览大小设置为相机参数预览大小 .

    cameraParameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
    mCamera.setParameters(cameraParameters);
    

    getSuggestedMinimumHeight(),getSuggestedMinimumWidth()是View类的方法

    希望这可以帮助 !!!

  • 1

    试试这个它正在工作......

    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    
    private static final String TAG = "Camera Preview";
    private static final double PREVIEW_SIZE_FACTOR = 3.00;
    private SurfaceHolder mHolder = null;
    private Camera mCamera = null;
    Camera.Parameters _parameters=null;
    
    @SuppressWarnings("deprecation")
    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;
        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        mHolder = getHolder();
        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }
    
    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            Camera.Parameters parameters = mCamera.getParameters();
            final Size mPreviewSize = getOptimalSize();
            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
             requestLayout();
            mCamera.setParameters(parameters);
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
            //startContinuousAutoFocus();
        } catch (Exception e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }
    public void surfaceDestroyed(SurfaceHolder holder) {
    }
    
    @SuppressLint("NewApi")
    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.
    
        if (mHolder.getSurface() == null){
            // preview surface does not exist
            return;
        }
    
        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
            // ignore: tried to stop a non-existent preview
        }
    
        // set preview size and make any resize, rotate or
        // reformatting changes here
        // set Camera parameters
    
        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();
    
        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
        }
    public void startPreview(){
        try{
            mCamera.startPreview();
        }catch (Exception e) {
        }
            } 
            private Size getOptimalSize() {
        Camera.Size result = null;
        final Camera.Parameters parameters = mCamera.getParameters();
        Log.i(CameraPreview.class.getSimpleName(), "window width: " + getWidth() + ", height: " + getHeight());
        for (final Camera.Size size : parameters.getSupportedPreviewSizes()) {
            if (size.width <= getWidth() * PREVIEW_SIZE_FACTOR && size.height <= getHeight() * PREVIEW_SIZE_FACTOR) {
                if (result == null) {
                    result = size;
                } else {
                    final int resultArea = result.width * result.height;
                    final int newArea = size.width * size.height;
    
                    if (newArea > resultArea) {
                        result = size;
                    }
                }
            }
        }
        if (result == null) {
            result = parameters.getSupportedPreviewSizes().get(0);
        }
        Log.i(CameraPreview.class.getSimpleName(), "Using PreviewSize: " + result.width + " x " + result.height);
        return result;
    }
    }
    

相关问题