当前位置: 首页 > 知识库问答 >
问题:

如何在Android中修正相机预览(surfaceview)的正确纵横比?

孟俊晖
2023-03-14

我正在创建带有摄像头功能的Android应用程序。相机屏幕包含顶部的工具栏、工具栏下方的surfaceview(相机预览)以及屏幕底部的相机控制按钮。屏幕总是纵向的。

[删除与问题无关的部分代码行]

这是我的片段FragmentCamera

import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.dmc.R;
import com.dmc.entities.Preview;

public class CameraFragment implements View.OnClickListener, View.OnTouchListener {

    public static final String ARG_CAMERA_MODE = "camera.mode";
    public static final String TYPE_CAMERA_MODE_IMAGE = "image";
    public static final String TYPE_CAMERA_MODE_VIDEO = "video";
    public MediaRecorder mrec = new MediaRecorder();

    private Camera camera;
    private String mCameraMode = TYPE_CAMERA_MODE_IMAGE; //or video
    private com.dmc.entities.Preview preview;
    private ImageView btnStopRecording;
    private SurfaceView surfaceView;
    private View view;

    public static FrCamera getInstance(String cameraMode) {
        CameraFragment fragment = new CameraFragment();
        Bundle bundle = new Bundle(1);
        bundle.putString(ARG_CAMERA_MODE, cameraMode);
        return fragment.setArguments(bundle);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mCameraMode = getArguments().getString(ARG_CAMERA_MODE);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        view = inflater.inflate(R.layout.fragment_camera, container, false);
        view.setOnTouchListener(this);
        btnStopRecording = (ImageView) view.findViewById(R.id.btnStopRecording);
        if (!mCameraMode.equals(TYPE_CAMERA_MODE_IMAGE)) {
            btnStopRecording.setOnClickListener(this);
        }
        surfaceView = (SurfaceView) view.findViewById(R.id.surfaceView);
        view.findViewById(R.id.imgCameraTakePicture).setOnClickListener(this);

        preview = new Preview(getActivity(), (SurfaceView) view.findViewById(R.id.surfaceView));
        preview.setKeepScreenOn(true);
        return view;
    }

    @Override
    public void onStart() {
        super.onStart();

        int numCams = Camera.getNumberOfCameras();
        if (numCams > 0) {
            try {
                camera = Camera.open(0);
                preview.setCamera(camera);
                camera.startPreview();
            } catch (RuntimeException ex) {
            }
        }
    }

    @Override
    public void onPause() {
        if (camera != null) {
            camera.stopPreview();
            preview.setCamera(null);
            camera.release();
            camera = null;
        }
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
        camera.startPreview();
    }

    private void startVideoRecording() {
        try {
            mrec = new MediaRecorder();
            mrec.setCamera(camera);
            mrec.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            mrec.setAudioSource(MediaRecorder.AudioSource.MIC);
            CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
            mrec.setProfile(profile);
            camera.lock();
            camera.unlock();
            mrec.setPreviewDisplay(preview.mHolder.getSurface());
            mrec.setOutputFile(outVideoFile.getPath());
            mrec.setOrientationHint(Preview.rotate);
            mrec.prepare();
            mrec.start();
        } catch (Exception ex) {
            Log.e(getClass().getName(), ex.getMessage());
        }
    }

    protected void stopRecording() {
        if (mrec != null) {
            mrec.stop();
            mrec.release();
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.imgCameraTakenPicture:
                // Save image
                break;
            case R.id.btnStopRecording:
                stopRecording();
                break;
            case R.id.imgCameraTakePicture:
                if (mCameraMode.equals(TYPE_CAMERA_MODE_IMAGE)) {
                    camera.takePicture(shutterCallback, rawCallback, jpegCallback);
                } else
                    startVideoRecording();
                break;
        }
    }
}

这是预览

import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;

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

public class Preview extends ViewGroup implements SurfaceHolder.Callback {
    public static final float RATIO = 0.75f;
    public static int rotate;

    public SurfaceView mSurfaceView;
    public SurfaceHolder mHolder;
    Size mPreviewSize;
    List<Size> mSupportedPreviewSizes;
    Camera mCamera;

    public Preview(Context context, SurfaceView sv) {
        super(context);
        mSurfaceView = sv;
        mHolder = mSurfaceView.getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void setCamera(Camera camera) {
        mCamera = camera;
        if (mCamera != null) {
            mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
            requestLayout();
            // get Camera parameters
            Camera.Parameters params = mCamera.getParameters();

            List<String> focusModes = params.getSupportedFocusModes();
            if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
                params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
            } else {
                params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
            }

            params.setJpegThumbnailQuality(100);
            params.setJpegQuality(100);

            // Configure image format. RGB_565 is the most common format.
            List<Integer> formats = params.getSupportedPictureFormats();
            if (formats.contains(PixelFormat.RGB_565))
                params.setPictureFormat(PixelFormat.RGB_565);
            else if (formats.contains(PixelFormat.JPEG))
                params.setPictureFormat(PixelFormat.JPEG);
            else params.setPictureFormat(formats.get(0));

            Camera.CameraInfo camInfo = new Camera.CameraInfo();
            Camera.getCameraInfo(Camera.CameraInfo.CAMERA_FACING_BACK, camInfo);
            int cameraRotationOffset = camInfo.orientation;

            Camera.Parameters parameters = mCamera.getParameters();

            int rotation = ((Activity) getContext()).getWindowManager().getDefaultDisplay().getRotation();
            int degrees = 0;
            switch (rotation) {
                case Surface.ROTATION_0:
                    degrees = 0;
                    break; // Natural orientation
                case Surface.ROTATION_90:
                    degrees = 90;
                    break; // Landscape left
                case Surface.ROTATION_180:
                    degrees = 180;
                    break;// Upside down
                case Surface.ROTATION_270:
                    degrees = 270;
                    break;// Landscape right
            }
            int displayRotation;
            if (camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                displayRotation = (cameraRotationOffset + degrees) % 360;
                //displayRotation = (360 - displayRotation) % 360; // compensate the mirror
            } else { // back-facing
                displayRotation = (cameraRotationOffset - degrees + 360) % 360;
            }
            mCamera.setDisplayOrientation(displayRotation);

            if (camInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                rotate = (360 + cameraRotationOffset + degrees) % 360;
            } else {
                rotate = (360 + cameraRotationOffset - degrees) % 360;
            }

            parameters.set("orientation", "portrait");
            parameters.setRotation(rotate);

            mCamera.setParameters(params);
        }
    }

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

    public void surfaceCreated(SurfaceHolder holder) {
        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(holder);
                mCamera.startPreview();
            }
        } catch (IOException exception) {}
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
        }
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        if (mHolder.getSurface() == null) {
            return;
        }
        stopPreview();
        setCamera(mCamera);
        startPreview();
        mCamera.startPreview();
    }

    public void startPreview() {
        try {
            if (mCamera != null) {
                mCamera.setPreviewDisplay(mHolder);
                mCamera.startPreview();
            } 
        } catch (Exception e) {}
    }

    public void stopPreview() {
        try {
            if (mCamera != null)
                mCamera.stopPreview();
        } catch (Exception e) {}
    }
}

共有1个答案

潘俊
2023-03-14

相机1和Android 4-5的源代码:

@Override
protected void onResume() {
    super.onResume();
    camera = Camera.open(CAMERA_ID);
    setPreviewSize();
}

@Override
protected void onPause() {
    super.onPause();
    if (camera != null)
        camera.release();
    camera = null;
}
...
void setPreviewSize() {
    // получаем размеры экрана
    Display display = getWindowManager().getDefaultDisplay();
    int w1 = display.getWidth();
    int h1 = display.getHeight();
    boolean widthIsMax = display.getWidth() > display.getHeight();

    // определяем размеры превью камеры
    Camera.Size size = camera.getParameters().getPreviewSize();

    RectF rectDisplay = new RectF();
    RectF rectPreview = new RectF();

    // RectF экрана, соотвествует размерам экрана
    rectDisplay.set(0, 0, w1, h1);

    // подготовка матрицы преобразования
    Matrix matrix = new Matrix();
    // RectF первью
    if (widthIsMax) {
        // превью в горизонтальной ориентации
        rectPreview.set(0, 0, size.width, size.height);

        // если экран будет "втиснут" в превью (третий вариант из урока)
        matrix.setRectToRect(rectPreview, rectDisplay,
                Matrix.ScaleToFit.START);
    } else {
        // превью в вертикальной ориентации
        rectPreview.set(0, 0, size.height, size.width);

        // если превью будет "втиснут" в экран (второй вариант из урока)
        matrix.setRectToRect(rectPreview, rectDisplay,
                Matrix.ScaleToFit.START);
    }

    // преобразование
    matrix.mapRect(rectPreview);

    // установка размеров surface из получившегося преобразования
    h0 = (int) (rectPreview.bottom);
    w0 = (int) (rectPreview.right);

    surfaceView.getLayoutParams().height = h0;
    surfaceView.getLayoutParams().width = w0;
}

看见http://startandroid.ru/ru/uroki/vse-uroki-spiskom/264-urok-132-kamera-vyvod-izobrazhenija-na-ekran-obrabotka-povorota.html

 类似资料:
  • 我有一个SurfaceView可以在我的Android应用程序中显示一个实时相机预览图像。SurfaceView覆盖了纵向屏幕的整个宽度和屏幕高度的一部分。 我试着设置了各种预览尺寸,所以预览有一个扭曲的纵横比,矮胖或者高高的骨瘦如柴。 我打印了显示实际预览显示大小和可用预览相机大小的调试,这样我就可以计算出纵横比错误。 我试穿了这个 阿尔卡特995,Android 4.0.4 三星Note 2,

  • 我一直在努力在Android上制作我的自定义相机活动,但当旋转相机时,表面视图的纵横比会变得混乱。 在我的oncreate for the activity中,我设置了framelayout,它保存了显示相机参数的曲面视图。 然后,在曲面视图中,我设置要显示的相机参数 您可以看到,当手机旋转时,乐高男会变得更高、更瘦: 如何确保相机视图的纵横比正确?

  • 我正在创建一个相机应用程序,实现它自己的相机预览拍照。该应用目前强制进入人像模式。 我的问题是来自相机的预览略有拉伸(纵横比有点偏)。有趣的是,我正在设置我的SurfaceView大小总是匹配预览大小。这确保纵横比应始终保持...但它不是... 下面是我用来展示相机预览的布局:

  • 请帮助正确配置Android摄像头(在HTC Desire 2.3.3上测试),以便在旋转(人像)模式下从摄像头预览。预览必须占用屏幕的一半以下,它的宽度必须等于设备的宽度,缩放必须根据相机的纵横比动态设置。我的当前代码: 活动布局: AndroidManifest配置为肖像: 你可以看到图像的比例不对。如何使以适当的比例显示旋转和缩放相机预览? 部分代码取自Mixare开源项目,http://w

  • 我有一个自定义的相机应用程序,我想任何预览大小显示在全屏模式下,而不拉伸相机预览图像。为此,我需要使surfaceView比屏幕更大,以保持纵横比,这样用户实际看到的比摄像机实际捕获的要少。 由于某些原因,我无法使大于屏幕大小。 到目前为止我所尝试的: > 调整相机预览在方法 但是没有任何成功-每次的行为都是一样的:1秒钟内它看起来正常,然后它就会拉伸。 下面是代码: 以下是整个项目:https:

  • 我使用相机仅显示预览(不拍照或录制视频)。 该应用程序始终处于竖屏状态(横向模式被禁用)。相机预览始终旋转90度ccw,我无法更改它(无论是还是和。 预览总是这样旋转还是依赖于设备?如果在纵向模式下总是这样,我可以在之后旋转图像。 或者有没有办法正确设置摄像头?我读了很多关于这个的帖子,但没有一个答案对我有用(Galaxy s2,Android v2.3)