自定义相机预览问题(拉伸)

Custom Camera Preview Issue (Stretch)

我的相机应用程序有问题。 我的应用有:

1) 一个 CameraActivity.class 和

2) 一个CameraPreview.class.

CameraPreview 实现一个 surfaceView ,它从 CameraActivity 调用它用于实际预览。 (同样在CameraActivity我有参数)

现在的问题是:当预览开始时,预览被拉伸了。 我尝试了很多东西(太多我记不起来了) 我需要有人告诉我写什么和在哪里。提前致谢。

这是CameraActivity(不是所有代码,但我认为重要的代码)

    private PictureCallback mPicture = new PictureCallback() {

    public void onPictureTaken(byte[] data, Camera camera) {

        // Replacing the button after a photho was taken.
        flBtnContainer.setVisibility(View.GONE);
        ibRetake.setVisibility(View.VISIBLE);
        ibUse.setVisibility(View.VISIBLE);

        // File name of the image that we just took.
        fileName = "IMG_" + new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()).toString() + ".jpg";

        // Creating the directory where to save the image. Sadly in older
        // version of Android we can not get the Media catalog name
        File mkDir = new File(sdRoot, dir);
        mkDir.mkdirs();

        // Main file where to save the data that we recive from the camera
        File pictureFile = new File(sdRoot, dir + fileName);

        try {
            FileOutputStream purge = new FileOutputStream(pictureFile);
            purge.write(data);
            purge.close();
        } catch (FileNotFoundException e) {
            Log.d("DG_DEBUG", "File not found: " + e.getMessage());
        } catch (IOException e) {
            Log.d("DG_DEBUG", "Error accessing file: " + e.getMessage());
        }

        // Adding Exif data for the orientation. For some strange reason the
        // ExifInterface class takes a string instead of a file.
        try {
            exif = new ExifInterface("/sdcard/" + dir + fileName);
            exif.setAttribute(ExifInterface.TAG_ORIENTATION, "" + orientation);
            exif.saveAttributes();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Intent intent = new Intent(CameraActivity.this, PicturePreview.class);
        Bundle extras = new Bundle();
        extras.putString("ImagePath", String.valueOf(pictureFile));
        intent.putExtras(extras);
        startActivity(intent);

        //SendBroadcasts let's us instantly update the SD card with our image
        sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.parse("file://"+Environment.getExternalStorageDirectory())));

    }



};



private void createCamera() {
    // Create an instance of Camera
    mCamera = getCameraInstance();

//        Setting the right parameters in the camera
    Camera.Parameters params = mCamera.getParameters();
    params.setRotation(90);
    mCamera.setParameters(params);

    // Create our Preview view and set it as the content of our activity.
    mPreview = new CameraPreview(this, mCamera);
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.addView(mPreview, 0);
}


@Override
protected void onResume() {
    super.onResume();

    // Test if there is a camera on the device and if the SD card is
    // mounted.
    if (!checkCameraHardware(this)) {
        Intent i = new Intent(this, NoCamera.class);
        startActivity(i);
        finish();
    } else if (!checkSDCard()) {
        Intent i = new Intent(this, NoSDCard.class);
        startActivity(i);
        finish();
    }

    // Creating the camera
    createCamera();

    // Register this class as a listener for the accelerometer sensor
    ////sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);
}

@Override
protected void onPause() {
    super.onPause();
    // release the camera immediately on pause event
    releaseCamera();

    // removing the inserted view - so when we come back to the app we
    // won't have the views on top of each other.
    FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
    preview.removeViewAt(0);
} 

这里是 CameraPreview.class

    public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
boolean isPreviewRunning = true;




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);
    mHolder.setFixedSize(100, 100);

}

public void surfaceCreated(SurfaceHolder holder) {
    // The Surface has been created, now tell the camera where to draw the
    // preview.
    try {
        mCamera.setPreviewDisplay(holder);
        mCamera.setDisplayOrientation(90);
        mCamera.startPreview();
    } catch (IOException e) {
        Log.d("DG_DEBUG", "Error setting camera preview: " + e.getMessage());
    }

}

public void surfaceChanged(SurfaceHolder holder,
                           int format, int width, int height) {


    if (isPreviewRunning){
        return;
    }
    isPreviewRunning = true;

    // 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
    }




    // make any resize, rotate or reformatting changes here

    // start preview with new settings
    try {
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();


    } catch (Exception e) {
        Log.d("DG_DEBUG", "Error starting camera preview: " + e.getMessage());
    }

}



public void surfaceDestroyed(SurfaceHolder holder) {
    // empty. Take care of releasing the Camera preview in your activity.
}



}

有人能告诉我我错过了什么吗?如果可能的话,我可以在 Facebook 或其他网站上聊天以更快地解决我的问题..

更新:@LikeWhiteOnRice 的解决方案。

这是我的原始代码

enter image description here

这里是 LikeWhiteOnRice 的代码:

enter image description here

有什么想法吗?

我将下面的代码添加到我的相机预览中 class,它适用于大多数设备。正如你所知,Android 中的相机库非常糟糕,使用起来非常痛苦。

将此功能放入您的 CameraPreview class:

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

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

在您的 surefaceCreated 函数中,在开始预览之前添加:

Camera.Parameters cameraParameters = mCamera.getParameters();
List<Camera.Size> previewSizes = cameraParameters.getSupportedPreviewSizes();
Camera.Size optimalPreviewSize = getOptimalSize(previewSizes, getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
cameraParameters.setPreviewSize(optimalPreviewSize.width, optimalPreviewSize.height);
mCamera.setParameters(cameraParameters);

编辑:另外,我不确定你是否想要

mHolder.setFixedSize(100, 100);

在你的构造函数中。