Подтвердить что ты не робот

Предварительный просмотр камеры на нескольких устройствах Android

Я делаю обычную камеру как "SnapChat" для Android-приложения, но предварительный просмотр камеры растягивается на нескольких устройствах, таких как (Moto g второго поколения, один + один), но не на (Samsung s3, Samsung s4). Я использую следующую ссылку Отображение/предварительный просмотр камеры в полноэкранном режиме не поддерживает соотношение сторон - изображение искажено, растянуто для того, чтобы поместиться на экране. Но это не помогает мне на 100%. Я использую экран.

Растянутое изображение на Samsung Moto G второго поколения. enter image description hereenter image description here

Изображения Samsung S3, которые не растянуты, выше

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

Ответ 1

Использование 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();
}

Чтобы подчеркнуть основную идею, я не включил обработку ошибок, и я не показал здесь, как камера на самом деле начинается с вторичного Looper.

Ответ 2

Вам нужно переопределить метод 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);

getSposedMinimumHeight(), getSposedMinimumWidth() - это методы класса View

Надеюсь, это поможет!!!

Ответ 3

попробуйте это, он работает...

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