做一个SurfaceView大于屏幕(拟合摄像头preVIEW到SurfaceView比显示大) [英] Make a SurfaceView larger than the screen (Fitting a camera preview to a SurfaceView larger than the display)

查看:701
本文介绍了做一个SurfaceView大于屏幕(拟合摄像头preVIEW到SurfaceView比显示大)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的摄像头应用程序,我想任何preVIEW尺寸在不拉伸摄像头preVIEW图像以全屏模式显示。 对于这一点,我需要做的surfaceView大于屏幕,以保持纵横比,所以实际上用户将看到小于相机实际拍摄。

由于某些原因,我不能让 SurfaceView 大于屏幕尺寸更大。

我试过到目前为止:

  • 调整相机preVIEW在 surfaceChanged 方法

  • 调整相机preVIEW在 onMeasure 方法

  • 在调整其大小在 onLayout <一个href="http://stackoverflow.com/questions/11321251/fitting-a-camera-$p$pview-to-a-surfaceview-larger-than-the-display?rq=1">method
  • 加入 FLAG_LAYOUT_NO_LIMITS 来活动 - <一个href="http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_LAYOUT_NO_LIMITS">info
  • 添加机器人: clipChildren 的表面观 - <一个href="http://developer.android.com/reference/android/view/ViewGroup.html#attr_android%3aclipChildren">info
  • 在XML设置宽度:机器人:layout_width =852px
  • getWindow()的setLayout(852,1280); 的活动

但没有任何成功 - 的行为是一样的,每次:它似乎确定为1秒钟,之后它被拉伸

下面是code:

 公共类相机preVIEW延伸SurfaceView实现SurfaceHolder.Callback {

    私有静态最终诠释CAMERA_ROTATE_ANGLE = 90;

    私人SurfaceHolder cameraHolder;
    私人相机androidHardCamera;
    私人上下文的背景下;

    公共摄像头preVIEW(上下文的背景下){
        超(上下文);
        this.context =背景;

        //安装SurfaceHolder.Callback所以我们得到通知时,该
        //下垫面创建和销毁。
        cameraHolder = getHolder();
        cameraHolder.addCallback(本);
        //德precated设置,但在Android上之前的版本3.0所需
        cameraHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    公共无效setCamera(摄像机镜头){
        this.androidHardCamera =摄像头;
        如果(androidHardCamera!= NULL){
            requestLayout();
        }
    }

    @覆盖
    公共无效surfaceCreated(SurfaceHolder持有者){
        //表面有被创建,现在告诉相机在哪里画preVIEW。
        尝试 {
            如果(androidHardCamera!= NULL){
                androidHardCamera.stop preVIEW(); //这是需要与API级别和LT装置; 14(从文件:启动
                //从API级别14,这种方法,又名setDisplayOrientation,可以在preVIEW激活调用。)

                androidHardCamera.setDisplayOrientation(CAMERA_ROTATE_ANGLE); //强制preVIEW显示方向
                //为纵向(旋转摄像头的方向/显示为纵向)

                //holder.setFixedSize(852,1280);
                androidHardCamera.set previewDisplay(保持器);
                androidHardCamera.start preVIEW();
            }
        }赶上(IOException异常E){
        }
    }

    @覆盖
    公共无效surfaceChanged(SurfaceHolder持有人,INT格式,诠释的宽度,高度INT){
        //如果你的preVIEW可以改变或旋转,把这些事件的关心在这里。
        //确保调整或重新格式化之前停止preVIEW。

        如果(cameraHolder.getSurface()== NULL){
            // preVIEW表面不存在
            返回;
        }

        在进行更改之前//停止preVIEW
        尝试 {
            androidHardCamera.stop preVIEW();
        }赶上(例外五){
            //忽略:试图阻止一个不存在的preVIEW
        }

        //设置preVIEW大小并进行调整大小,旋转或
        //重新格式化的变化在这里
        FrameLayout.LayoutParams的LayoutParams =(FrameLayout.LayoutParams)this.getLayoutParams();
        layoutParams.height = 1280;
        layoutParams.width = 852;
        this.setLayoutParams(的LayoutParams);

        //cameraHolder.setFixedSize(852,1280);
        requestLayout();

        //启动preVIEW使用新设置
        尝试 {
            androidHardCamera.set previewDisplay(cameraHolder);
            androidHardCamera.start preVIEW();
        }赶上(例外五){
        }
    }

    @覆盖
    公共无效surfaceDestroyed(SurfaceHolder持有者){
    }

// @覆盖
//保护无效onMeasure(INT widthMeasureSpec,诠释heightMeasureSpec){
// // super.onMeasure(widthMeasureSpec,heightMeasureSpec); //要改变的重载方法体使用文件|设置|文件模板。
// //super.onMeasure(852,1280);
// setMeasuredDimension(852,1280);
//}
}

公共类MyActivity延伸活动{

    私人摄像头摄像头;
    私人相机preVIEW previewCamera;

    @覆盖
    公共无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow()setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN)。
        getWindow()addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS)。

        的setContentView(R.layout.camera_screen);

        previewCamera =新相机preVIEW(本);
        的FrameLayout preVIEW =(的FrameLayout)findViewById(R.id.camera_ preVIEW);
        preview.addView(previewCamera);

        //getWindow().setLayout(852,1280);
    }

    @覆盖
    保护无效onResume(){
        //创建相机的一个实例
        相机= getCameraInstance(1);
        如果(相机== NULL){
            Toast.makeText(这一点,在使用照相机!,Toast.LENGTH_LONG).show();
        } 其他 {
            previewCamera.setCamera(摄像头);
            camera.stop preVIEW();

            Camera.Parameters p值= camera.getParameters();
            P.SET previewSize(176,144);
            // P.SET previewSize(480,800);
            camera.setParameters(对);

            启动previewCamera();
        }
        super.onResume();
    }

    @覆盖
    保护无效的onPause(){
        releaseCameraAnd preVIEW();
        super.onPause();
    }

    公共相机getCameraInstance(INT cameraInstance){
        相机C = NULL;
        尝试 {
            C = Camera.open(cameraInstance);
        }赶上(例外五){
            //相机无法使用(使用或不存在)
            的System.out.println(异常:+ E);
        }
        返回℃;
    }

    公共无效开始previewCamera(){
        //强制preVIEW显示方向为纵向(旋转摄像头的方向/显示为纵向)
        camera.setDisplayOrientation(90);
        camera.start preVIEW();
    }

    公共无效releaseCameraAnd preVIEW(){
        如果(相机!= NULL){
            camera.stop preVIEW(); //更新preVIEW面
            camera.set previewCallback(空);
            // camera.lock(); //如果我们不锁相机,版本()将无法在某些设备上
            camera.release();
            摄像头= NULL;
        }
    }
}

&LT; XML版本=1.0编码=UTF-8&GT?;
&LT; LinearLayout中的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
              机器人:方向=垂直
              机器人:layout_width =match_parent
              机器人:layout_height =match_parent&GT;

    &所述;! - 这是在容器的相机preVIEW屏幕 - &GT;
    &LT;的FrameLayout机器人:ID =@ + ID / camera_ preVIEW
                 机器人:layout_width =match_parent
                 机器人:layout_height =match_parent
                 机器人:clipChildren =假
                 机器人:layout_weight =1/&GT;
&LT; / LinearLayout中&GT;
 

下面是整个项目:<一href="https://www.dropbox.com/sh/96jih9kw5zmmnzy/z7VX16T30M">https://www.dropbox.com/sh/96jih9kw5zmmnzy/z7VX16T30M

我测试S3设备上。在一个S2设备似乎铁锅罚款...我只是不知道该怎么做更多来解决这个问题...

更新1

例如索尼Xperia具有八百五十四分之四百八十〇的屏幕显示。 其中preVIEW大小我可以使用的为176/144

为了显示全屏幕大小,我需要有698/854 preVIEW相机尺寸 - 但我不知道如何设置这个值,其中

下面的code不工作...相机preVIEW被拉伸/拉长。

 进口android.app.Activity;
进口android.graphics.Point;
进口android.hardware.Camera;
进口android.os.Bundle;
进口android.view.Display;
进口android.view.View;
进口android.view.Window;
进口android.view.WindowManager;
进口android.widget.FrameLayout;
进口android.widget.LinearLayout;

公共类相机preVIEW延伸活动实现了preVIEW。previewListener {

    私人preVIEW米preVIEW;
    私人相机mCamera;

    的FrameLayout preVIEW;

    @覆盖
    保护无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        。getWindow()addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        的setContentView(R.layout.main);

        //创建我们的preVIEW观点,并将其作为我们活动的内容。
        米preVIEW =新的preVIEW(本);
        preVIEW =(的FrameLayout)findViewById(R.id.surface_camera);
        preview.addView(M preVIEW);

        显示显示= getWindowManager()getDefaultDisplay()。
        getDisplaySize(显示);
    }

    私人静点getDisplaySize(最终显示显示器){
        最后一点一点=新的点();
        尝试 {
            display.getSize(点);
        }赶上(java.lang.NoSuchMethodError忽略){
            point.x = display.getWidth();
            point.y = display.getHeight();
        }
        的System.out.println(============:屏幕+ point.x +/+ point.y);
        返回点;
    }

    @覆盖
    保护无效onResume(){
        super.onResume();
        mCamera = Camera.open(1);
        米preview.setCamera(mCamera,这一点);
    }

    @覆盖
    保护无效的onPause(){
        super.onPause();
        如果(mCamera!= NULL){
            米preview.setCamera(NULL,NULL);
            mCamera.release();
            mCamera = NULL;
        }
    }


    @覆盖
    公共无效onSurfaceChanged(){
        LinearLayout.LayoutParams PARAMS =(LinearLayout.LayoutParams)preview.getLayoutParams();
        params.setMargins(0,-218,0,0);
        preview.setLayoutParams(新FrameLayout.LayoutParams(480,854));
        preview.setLayoutParams(PARAMS);

        preview.setVisibility(View.VISIBLE);
    }
}
 


 进口android.content.Context;
进口android.hardware.Camera;
进口android.util.Log;
进口android.view.SurfaceHolder;
进口android.view.SurfaceView;

进口java.io.IOException异常;
进口的java.util.List;

类preVIEW延伸SurfaceView实现SurfaceHolder.Callback {

    私人SurfaceHolder mHolder;
    私人相机mCamera;

    私人previewListener监听;

    公共静态接口previewListener {
        无效onSurfaceChanged();
    }

    preVIEW(上下文的背景下){
        超(上下文);

        mHolder = getHolder();
        mHolder.addCallback(本);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    公共无效setCamera(摄像头摄像头,previewListener监听器){
        this.listener =侦听器;
        mCamera =摄像头;
        如果(mCamera!= NULL){
            名单&LT; Camera.Size&GT; mSupported previewSizes = mCamera.getParameters()getSupported previewSizes()。
            对于(Camera.Size S:mSupported previewSizes){
                的System.out.println(============:+ s.width +/+ s.height);
            }
            requestLayout();
        }
    }

    公共无效surfaceCreated(SurfaceHolder持有者){
        //表面经创建,获取摄像机,并告诉它在哪里
        //绘制。
        尝试 {
            如果(mCamera!= NULL){
                mCamera.set previewDisplay(保持器);
            }
        }赶上(IOException异常除外){
            Log.e(错误:,IOException异常造成集previewDisplay(),除外);
        }
    }

    公共无效surfaceDestroyed(SurfaceHolder持有者){
        //面,当我们返回将被销毁,所以停止了preVIEW。
        如果(mCamera!= NULL){
            mCamera.stop preVIEW();
        }
    }

    公共无效surfaceChanged(SurfaceHolder持有人,INT格式,INT W,INT高){
        mCamera.stop preVIEW(); // PE Xpedia DACA NU贝ASTA crapa拉setDisplayOrientation

        //现在的尺寸是已知的,设置相机参数和beginthe preVIEW。
        Camera.Parameters参数= mCamera.getParameters();

        mCamera.setDisplayOrientation(90);
        parameters.set previewSize(176,144);

        requestLayout();

        mCamera.setParameters(参数);
        mCamera.start preVIEW();
    }

// @覆盖
//保护无效onSizeChanged(\ INT W,INT小时,INT oldw,诠释oldh){
// super.onSizeChanged(W,H,oldw,oldh);
// // setLayoutParams(新的LayoutParams((int)的比率* W,W));
//
// FrameLayout.LayoutParams PARAMS =(FrameLayout.LayoutParams)getLayoutParams();
// setLayoutParams(新FrameLayout.LayoutParams(960,1280));
// params.setMargins(0,-120,0,0);
// setLayoutParams(PARAMS);
//
// //$p$pview.setVisibility(View.VISIBLE);
//}

    @覆盖
    保护无效onMeasure(INT widthMeasureSpec,诠释heightMeasureSpec){
        super.onMeasure(widthMeasureSpec,heightMeasureSpec); //要改变的重载方法体使用文件|设置|文件模板。

// FrameLayout.LayoutParams PARAMS =(FrameLayout.LayoutParams)getLayoutParams();
// setLayoutParams(新FrameLayout.LayoutParams(698,854));
// params.setMargins(0,-218,0,0);
// setLayoutParams(PARAMS);
    }

    //http://stackoverflow.com/questions/11853297/change-size-of-android-custom-surfaceview
    @覆盖
    公共无效onLayout(布尔改变,诠释离开,INT顶部,诠释权,诠释底部){
        如果(改变){
            // setLayoutParams();
                 listener.onSurfaceChanged();
            //(this).layout(0,0,viewWidth,viewHeight);
        }
    }

}
 

这是一类测试,其根据显示屏幕尺寸和摄像头preVIEW尺寸正确的表面观尺寸:

 公共类测试{

    / **
     *确定适当的宽度应以不拉伸摄像机的现场preVIEW用于表面观。
     * /
    公共静态无效的主要(字串[] args){
        //摄像头preVIEW尺寸:
        INT surfaceViewWidth = 176;
        INT surfaceViewHeight = 144;

        INT持有人;
        如果(surfaceViewWidth&GT; surfaceViewHeight){
            持有人= surfaceViewWidth;
            surfaceViewWidth = surfaceViewHeight;
            surfaceViewHeight =持有人;
        }

        //设备屏幕显示尺寸:
        INT宽度= 480;
        INT高= 854;

        双SC1 =(双)宽/ surfaceViewWidth;
        双SC2 =(双)身高/ surfaceViewHeight;
        双REZ;
        如果(SC1&GT; SC2){
            苏亚雷斯= SC1;
        } 其他 {
            苏亚雷斯= SC2;
        }

        的System.out.println(宽度/高度:+(INT)(surfaceViewWidth *苏亚雷斯)+/+(INT)(surfaceViewHeight *苏亚雷斯)); //我们需要设置preVIEW尺寸大小
        的System.out.println(((INT)(surfaceViewWidth *苏亚雷斯)) - 宽); // preVIEW大小和设备的屏幕尺寸=丝毫的差异是多少大的preVIEW尺寸比屏幕尺寸
    }
}
 

解决方案

首先,删除崩溃来源:开始previewCamera调用onResume。 相机preVIEW应SurfaceHolder.Callback方法来启动。

那么你应该知道,你可以设置preVIEW大小只报道Camera.Parameters.getSupported previewSizes大小。和这些尺寸将最有可能是小于或等于设备的屏幕尺寸。

然后你只需拨打

  Camera.Parameters P = camera.getParameters();
P.SET previewSize(W,H); // 1支持的尺寸
camera.setParameters(对);
 

然后,preVIEW表面会产生这种规模(可能是旋转和W / H互换)。而这面将搭载Android被重新调整到你的相机preVIEW鉴于规模正在绘制的时候,所以这一点也很重要,你如何设置你的相机preVIEW大小。

您可以通过调用设置你的相机preVIEW固定大小

  previewCamera.setLayoutParams(新FrameLayout.LayoutParams(W,H));
 

因此​​,在短期中,设置所需的preVIEW大小Camera.setParameters,和你的大小您的preVIEW视图需要,可能以相同的大小preVIEW,为的是您的要求。您的preVIEW视图,则可能等于屏幕尺寸或更小(假设相机不提供​​preVIEW大于屏幕)。如果摄像头提供了更大的preVIEW比屏幕上,你仍然可以调用preview.setX,preview.setY移动它。

I have a custom camera application and I want for any preview sizes to display it in full screen mode without stretching the camera preview image. For this, I need to make the surfaceView larger than the screen in order to keep aspect ratio, so actually the user will see less than camera actually captures.

For some reason, I cannot make the SurfaceView larger than the screen size.

What I've tried so far:

  • resize camera preview in surfaceChanged method

  • resize camera preview in on onMeasure method

  • resize it in in onLayout method
  • adding FLAG_LAYOUT_NO_LIMITS to activity - info
  • adding android:clipChildren for the surface view - info
  • setting width in xml: android:layout_width="852px"
  • getWindow().setLayout(852, 1280); in activity

but without any success - the behaviour is the same each time: it appears ok for 1 second and after that it gets stretched.

Here is the code:

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    private static final int CAMERA_ROTATE_ANGLE = 90;

    private SurfaceHolder cameraHolder;
    private Camera androidHardCamera;
    private Context context;

    public CameraPreview(Context context) {
        super(context);
        this.context = context;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed.
        cameraHolder = getHolder();
        cameraHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
        cameraHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void setCamera(Camera camera) {
        this.androidHardCamera = camera;
        if (androidHardCamera != null) {
            requestLayout();
        }
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            if (androidHardCamera != null) {
                androidHardCamera.stopPreview();//this is needed for devices with API level < 14 (from doc.: Starting
                // from API level 14, this method, aka setDisplayOrientation, can be called when preview is active.)

                androidHardCamera.setDisplayOrientation(CAMERA_ROTATE_ANGLE);//force the preview Display Orientation
                // to Portrait (rotate camera orientation/display to portrait)

                //holder.setFixedSize(852, 1280);
                androidHardCamera.setPreviewDisplay(holder);
                androidHardCamera.startPreview();
            }
        } catch (IOException e) {
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 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 (cameraHolder.getSurface() == null) {
            // preview surface does not exist
            return;
        }

        // stop preview before making changes
        try {
            androidHardCamera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here
        FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) this.getLayoutParams();
        layoutParams.height = 1280;
        layoutParams.width = 852;
        this.setLayoutParams(layoutParams);

        //cameraHolder.setFixedSize(852, 1280);
        requestLayout();

        // start preview with new settings
        try {
            androidHardCamera.setPreviewDisplay(cameraHolder);
            androidHardCamera.startPreview();
        } catch (Exception e) {
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    }

//    @Override
//    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//       // super.onMeasure(widthMeasureSpec, heightMeasureSpec);    //To change body of overridden methods use File | Settings | File Templates.
//        //super.onMeasure(852, 1280);
//        setMeasuredDimension(852, 1280);
//    }
}

public class MyActivity extends Activity{

    private Camera camera;
    private CameraPreview previewCamera;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);

        setContentView(R.layout.camera_screen);

        previewCamera = new CameraPreview(this);
        FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
        preview.addView(previewCamera);

        //getWindow().setLayout(852, 1280);
    }

    @Override
    protected void onResume() {
        // Create an instance of Camera
        camera = getCameraInstance(1);
        if (camera == null) {
            Toast.makeText(this, "Camera in use!", Toast.LENGTH_LONG).show();
        } else {
            previewCamera.setCamera(camera);
            camera.stopPreview();

            Camera.Parameters p = camera.getParameters();
            p.setPreviewSize(176, 144);
            // p.setPreviewSize(480, 800);
            camera.setParameters(p);

            startPreviewCamera();
        }
        super.onResume();
    }

    @Override
    protected void onPause() {
        releaseCameraAndPreview();
        super.onPause();
    }

    public Camera getCameraInstance(int cameraInstance) {
        Camera c = null;
        try {
            c = Camera.open(cameraInstance);
        } catch (Exception e) {
            // Camera is not available (in use or does not exist)
            System.out.println("exception: " + e);
        }
        return c;
    }

    public void startPreviewCamera() {
        //Force the preview Display Orientation to Portrait (rotate camera orientation/display to portrait)
        camera.setDisplayOrientation(90);
        camera.startPreview();
    }

    public void releaseCameraAndPreview() {
        if (camera != null) {
            camera.stopPreview(); // updating the preview surface
            camera.setPreviewCallback(null);
            // camera.lock(); //if we don't lock the camera, release() will fail on some devices
            camera.release();
            camera = null;
        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <!-- This is the container for the camera preview screen -->
    <FrameLayout android:id="@+id/camera_preview"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:clipChildren="false"
                 android:layout_weight="1"/>
</LinearLayout>

Here is the entire project: https://www.dropbox.com/sh/96jih9kw5zmmnzy/z7VX16T30M

I am testing on a S3 device. On a S2 device seems to wok fine... I just do not know what to do more to solve this issue...

UPDATE 1

For example Sony Xperia has a screen display of 480 / 854. One of the preview sizes I can use is 176 / 144.

In order to display full screen size I need to have the preview camera size of 698 / 854 - but I do not know how to set this value and where.

The code below is not working... the camera preview is stretched/elongated.

import android.app.Activity;
import android.graphics.Point;
import android.hardware.Camera;
import android.os.Bundle;
import android.view.Display;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

public class CameraPreview extends Activity implements Preview.PreviewListener {

    private Preview mPreview;
    private Camera mCamera;

    FrameLayout preview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.main);

        // Create our Preview view and set it as the content of our activity.
        mPreview = new Preview(this);
        preview = (FrameLayout) findViewById(R.id.surface_camera);
        preview.addView(mPreview);

        Display display = getWindowManager().getDefaultDisplay();
        getDisplaySize(display);
    }

    private static Point getDisplaySize(final Display display) {
        final Point point = new Point();
        try {
            display.getSize(point);
        } catch (java.lang.NoSuchMethodError ignore) {
            point.x = display.getWidth();
            point.y = display.getHeight();
        }
        System.out.println("============: Screen " + point.x + "/" + point.y);
        return point;
    }

    @Override
    protected void onResume() {
        super.onResume();
        mCamera = Camera.open(1);
        mPreview.setCamera(mCamera, this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mCamera != null) {
            mPreview.setCamera(null, null);
            mCamera.release();
            mCamera = null;
        }
    }


    @Override
    public void onSurfaceChanged() {
        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) preview.getLayoutParams();
        params.setMargins(0, -218, 0, 0);
        preview.setLayoutParams(new FrameLayout.LayoutParams(480, 854));
        preview.setLayoutParams(params);

        preview.setVisibility(View.VISIBLE);
    }
}


import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.io.IOException;
import java.util.List;

class Preview extends SurfaceView implements SurfaceHolder.Callback {

    private SurfaceHolder mHolder;
    private Camera mCamera;

    private PreviewListener listener;

    public static interface PreviewListener {
        void onSurfaceChanged();
    }

    Preview(Context context) {
        super(context);

        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void setCamera(Camera camera, PreviewListener listener) {
        this.listener = listener;
        mCamera = camera;
        if (mCamera != null) {
            List<Camera.Size> mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
            for (Camera.Size s : mSupportedPreviewSizes) {
                System.out.println("============: " + s.width + "/" + s.height);
            }
            requestLayout();
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, acquire the camera and tell it where
        // to draw.
        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
            }
        } catch (IOException exception) {
            Log.e("Error: ", "IOException caused by setPreviewDisplay()", exception);
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // Surface will be destroyed when we return, so stop the preview.
        if (mCamera != null) {
            mCamera.stopPreview();
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        mCamera.stopPreview(); // pe Xpedia daca nu pui asta crapa la  setDisplayOrientation

        // Now that the size is known, set up the camera parameters and beginthe preview.
        Camera.Parameters parameters = mCamera.getParameters();

        mCamera.setDisplayOrientation(90);
        parameters.setPreviewSize(176, 144);

        requestLayout();

        mCamera.setParameters(parameters);
        mCamera.startPreview();
    }

//    @Override
//    protected void onSizeChanged(\int w, int h, int oldw, int oldh) {
//        super.onSizeChanged(w, h, oldw, oldh);
//        //setLayoutParams(new LayoutParams((int)RATIO * w, w));
//
//        FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
//        setLayoutParams(new FrameLayout.LayoutParams(960, 1280));
//        params.setMargins(0, -120, 0,0);
//        setLayoutParams(params);
//
//        //preview.setVisibility(View.VISIBLE);
//    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);    //To change body of overridden methods use File | Settings | File Templates.

//        FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) getLayoutParams();
//       setLayoutParams(new FrameLayout.LayoutParams(698, 854));
//        params.setMargins(0, -218, 0,0);
//        setLayoutParams(params);
    }

    //http://stackoverflow.com/questions/11853297/change-size-of-android-custom-surfaceview
    @Override
    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (changed) {
            //setLayoutParams();
                 listener.onSurfaceChanged();
            //(this).layout(0, 0, viewWidth , viewHeight);
        }
    }

}

This is a class test which calculates the correct surface view size based on display screen size and camera preview size:

public class Test {

    /**
     * Determine proper width to be used for surface view in order to not stretch the camera live preview.
     */
    public static void main(String[] args) {
        // camera preview size:
        int surfaceViewWidth = 176;
        int surfaceViewHeight = 144;

        int holder;
        if (surfaceViewWidth > surfaceViewHeight) {
            holder = surfaceViewWidth;
            surfaceViewWidth = surfaceViewHeight;
            surfaceViewHeight = holder;
        }

        //device screen display sizes:
        int width = 480;
        int height = 854;

        double sc1 = (double) width / surfaceViewWidth;
        double sc2 = (double) height / surfaceViewHeight;
        double rez;
        if (sc1 > sc2) {
            rez = sc1;
        } else {
            rez = sc2;
        }

        System.out.println("Width/height: " + (int) (surfaceViewWidth * rez) + "/" + (int) (surfaceViewHeight * rez)); // size of the preview size we need to set
        System.out.println(((int) (surfaceViewWidth * rez))-width); // difference between preview size and device screen size = whit how much is bigger the preview size than screen size 
    }
}

解决方案

First, remove source of crashes: startPreviewCamera called in onResume. Camera preview shall be started in SurfaceHolder.Callback methods.

Then you should know that you can set preview size only to sizes reported by Camera.Parameters.getSupportedPreviewSizes. And these sizes will most likely be smaller or equal to device's screen size.

Then you simply call

Camera.Parameters p = camera.getParameters();
p.setPreviewSize(w, h); // one of supported sizes
camera.setParameters(p);

Then Surface of preview will have that size (possibly rotated and w/h swapped). And this surface will be rescaled by Android to size of your CameraPreview view when being drawn, so it's also important how you set size of your CameraPreview.

You can set fixed size of your CameraPreview simply by calling

previewCamera.setLayoutParams(new FrameLayout.LayoutParams(w, h));

So in short, you set requested preview size in Camera.setParameters, and you size your preview view as desired, possibly to same size as preview, as is your requirement. Your preview view then may be equal to screen size or be smaller (assuming camera doesn't provide preview bigger than screen). If camera provides bigger preview than screen, you can still call preview.setX, preview.setY to move it around.

这篇关于做一个SurfaceView大于屏幕(拟合摄像头preVIEW到SurfaceView比显示大)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆