Подгонка предварительного просмотра камеры к SurfaceView больше, чем дисплей

У меня есть приложение для Android, которое требует полноэкранного предварительного просмотра камеры независимо от размера предварительного просмотра, заданного getSupportedPreviewSizes() без искажений. Я ожидаю, что это обрезает предварительный просмотр на некоторое количество высоты или ширины, но это не касается меня. Причина, по которой я пытаюсь это сделать, заключается в том, что некоторые камеры Android (например, фронтальная камера Samsung Galaxy SII) не возвращают предварительный просмотр с таким же соотношением сторон, как у дисплея, и поэтому их необходимо растягивать и обрезать.

Можно ли полностью увеличить предварительный просмотр камеры до размера, превышающего размер экрана? Поверхность SurfaceView можно увеличить больше, чем возвращаемые размеры в пикселях предварительного просмотра, просто установив параметры макета представления поверхности в match_parent, но это приводит к искажению в некотором направлении и возможно только до тех пор, пока предварительный просмотр не заполнит дисплей. Кажется, это указывает на то, что предварительный просмотр за пределами дисплея невозможен, и аппаратное обеспечение (или ОС) ограничивает такое поведение.

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

Моя попытка:

У меня есть относительный макет, внутри него FrameLayout, и внутри него я создаю SurfaceView. Ширина всей относительной компоновки установлена ​​ниже на уровне 635dp, что в два раза больше размера экрана устройства. FrameLayout соответствует этому размеру, как и SurfaceView (добавлен программно позже)

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/camera_activity_layout"
    android:layout_width="635dp"
    android:layout_height="match_parent" >

    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </FrameLayout>

</RelativeLayout>

Ниже приведен код, который получает и устанавливает размер предварительного просмотра. Здесь я хочу увеличить предварительный просмотр камеры, чтобы заполнить весь FrameLayout (удвоить ширину экрана). Представление отображается и разрушается полностью нормально, поэтому я удаляю код, не связанный с этим конкретным вопросом, поскольку он отвлекает от основного вопроса, и мою попытку легко и просто увеличить представление до некоторого размера, превышающего размер экрана.

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

    ...

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        Camera.Parameters parameters = mCamera.getParameters();
        final DisplayMetrics dm = this.getResources().getDisplayMetrics();
            //getBestPreviewSize returns the best preview size, don't worry
            //but some devices do not return one for all camera matching the aspect ratio
        cameraSize = getBestPreviewSize(parameters, dm.heightPixels, dm.widthPixels);

        if (cameraSize!=null) {
            parameters.setPreviewSize(cameraSize.width, cameraSize.height);
            mCamera.setParameters(parameters);
        }

        FrameLayout.LayoutParams frameParams = (FrameLayout.LayoutParams) this.getLayoutParams();

        frameParams.width = 800; //For argument's sake making this ~double the width of the display. Same result occurs if I use MATCH_PARENT
        frameParams.height = LayoutParams.MATCH_PARENT;
        this.setLayoutParams(frameParams);

        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

            Log.d("surfChange","W/H of CamPreview (child) is "+this.getWidth()+"/"+this.getHeight()+" while parent is ");
            Log.d("surfChange","W/H of holder (child) is "+mHolder.getSurfaceFrame().width()+"/"+mHolder.getSurfaceFrame().height()+" while parent is ");
        } catch (Exception e){
        }
    }
};

Я обеспокоен тем, что единственный способ добиться успеха в этом начинании состоит в том, чтобы каким-то образом визуализировать поверхность openGL, но это, очевидно, может быть слишком медленным в полноцветном изображении. Также неприятно, если предварительный просмотр камеры можно просто растянуть и обрезать.

Заранее спасибо за любые попытки решения.

1 ответ

Хорошо, я знаю, что это очень поздно, но это возможно. Ниже приведен код из образца Android SDK. Чтобы увидеть остальную часть кода для реализации этого, загрузите образцы Android SDK и перейдите на Samples/android-10(one I used, could try whichever you want to target)/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java

class PreviewSurface extends ViewGroup implements SurfaceHolder.Callback {
...
@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);
        }
    }
}
}

этот код предназначен для подгонки предварительного просмотра к наименьшему измерению (которое не портит соотношение сторон) и центру, чтобы иметь черные полосы в другом измерении. Но если вы переверните > быть < вместо этого вы добьетесь того, чего хотите. Пример:

if (width * previewHeight < height * previewWidth) {...
Другие вопросы по тегам