Предварительный просмотр растягивается в camera2 apis

Ниже приведены скриншоты при использовании текстурного вида в camera2 apis. В полноэкранном режиме предварительный просмотр растягивается, но он работает при использовании более низкого разрешения (второе изображение). Как использовать этот предварительный просмотр в полноэкранном режиме, не растягивая его.

Ответ 1

Ниже ответа предполагается, что вы находитесь только в портретном режиме.

Ваш вопрос:

Как использовать предварительный просмотр в полноэкранном режиме без растягивания

Позвольте разбить его на две вещи:

  1. Вы хотите, чтобы предварительный просмотр заполнил экран
  2. Предварительный просмотр не может быть искажен

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

Поэтому я бы предположил, что вы принимаете обрезку предварительного просмотра.

Шаг 1. Получите список доступных разрешений.

StreamConfigurationMap map = mCameraCharacteristics.get(
                CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
if (map == null) {
    throw new IllegalStateException("Failed to get configuration map: " + mCameraId);
}
Size[] sizes = map.getOutputSizes(SurfaceTexture.class);

Теперь вы получаете список доступных разрешений (размеров) вашей камеры устройства.

Шаг 2. Найдите наилучшее соотношение сторон

Идея состоит в том, чтобы зацикливать размеры и посмотреть, какой из них лучше всего подходит. Вам, вероятно, нужно написать собственную реализацию "лучших приемов".

Я не собираюсь предоставлять какой-либо код здесь, так как то, что у меня есть, сильно отличается от вашего варианта использования. Но в идеале это должно быть примерно так:

Size findBestSize (Size[] sizes) {
    //Logic goes here
}

Шаг 3. Скажите API-интерфейсу камеры, что вы хотите использовать этот размер

    //...
    textureView.setBufferSize(bestSize.getWidth(), bestSize.getHeight());
    Surface surface = textureView.getSurface();
    try {
        mPreviewRequestBuilder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
        mPreviewRequestBuilder.addTarget(surface);
        mCamera.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                mSessionCallback, null);
    } catch (final Exception e) {
        //...
    }

Шаг 4: Сделайте свой предварительный просмотр за пределами области просмотра

Тогда это не связано с API Camera2. Мы " SurfaceView " предварительный просмотр, позволяя SurfaceView/TextureView за пределы TextureView просмотра устройства.

Сначала разместите SurfaceView или TextureView в RelativeLayout.

Используйте ниже, чтобы расширить его за пределы экрана, после того как вы получите соотношение сторон с шага 2.
Обратите внимание, что в этом случае вам, вероятно, нужно знать это соотношение сторон, прежде чем вы даже начнете работу с камерой.

   //Suppose this value is obtained from Step 2.
    //I simply test here by hardcoding a 3:4 aspect ratio, where my phone has a thinner aspect ratio.
    float cameraAspectRatio = (float) 0.75;

    //Preparation
    DisplayMetrics metrics = new DisplayMetrics();
    getWindowManager().getDefaultDisplay().getMetrics(metrics);
    int screenWidth = metrics.widthPixels;
    int screenHeight = metrics.heightPixels;
    int finalWidth = screenWidth;
    int finalHeight = screenHeight;
    int widthDifference = 0;
    int heightDifference = 0;
    float screenAspectRatio = (float) screenWidth / screenHeight;

    //Determines whether we crop width or crop height
    if (screenAspectRatio > cameraAspectRatio) { //Keep width crop height
        finalHeight = (int) (screenWidth / cameraAspectRatio);
        heightDifference = finalHeight - screenHeight;
    } else { //Keep height crop width
        finalWidth = (int) (screenHeight * cameraAspectRatio);
        widthDifference = finalWidth - screenWidth;
    }

    //Apply the result to the Preview
    RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) cameraView.getLayoutParams();
    lp.width = finalWidth;
    lp.height = finalHeight;
    //Below 2 lines are to center the preview, since cropping default occurs at the right and bottom
    lp.leftMargin = - (widthDifference / 2);
    lp.topMargin = - (heightDifference / 2);
    cameraView.setLayoutParams(lp);

Если вы не заботитесь о результате шага 2, вы можете фактически проигнорировать шаги с 1 по 3 и просто используйте библиотеку там, пока вы можете настроить его соотношение сторон. (Похоже, что это лучший, но я еще не пробовал)

Я проверил, используя мою разветвленную библиотеку. Не изменяя код моей библиотеки, мне удалось сделать полноэкранный просмотр только с помощью шага 4:

Перед использованием Шаг 4:
enter image description here

После использования шага 4:
enter image description here

И предварительный просмотр сразу после съемки не искажает, потому что предварительный просмотр также выходит за пределы вашего экрана.
Но выходное изображение будет включать область, которую вы не видите в предварительном просмотре, что имеет смысл.

Код с шага 1-го шага 3 обычно ссылается на Google CameraView.

Ответ 2

Это общая проблема на некоторых устройствах. Я заметил это в основном на samsung. Вы можете использовать трюк с настройкой преобразования на вашем TextureView чтобы сделать его centerCrop похожим на поведение ImageView

Ответ 3

Я понял, что это был ваш пороблем. Вероятно, вы пытались что-то вроде этого:

textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int j) {
        cam.startPreview(surfaceTexture, i, j);
        cam.takePicture();
    }

    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) { }
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) { return false; }
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) { }
});