Ajuste de una vista previa de la cámara a un SurfaceView más grande que la pantalla

Tengo una aplicación de Android que necesita una vista previa de la cámara a pantalla completa, independientemente del tamaño de vista previa proporcionado por getSupportedPreviewSizes() sin distorsión. Espero que esto recorte la vista previa en cierta medida, ya sea en altura o ancho, pero esto no me preocupa. La razón por la que busco hacer esto es porque ciertas cámaras de Android (por ejemplo, la cámara frontal Samsung Galaxy SII) no devuelven vistas previas con la misma relación de aspecto que la pantalla y, por lo tanto, deben estirarse y recortarse.

¿Es posible hacer crecer completamente la vista previa de la cámara a una vista más grande que el tamaño de la pantalla? Es posible hacer crecer SurfaceView más grande que las dimensiones de píxeles de la vista previa devuelta simplemente configurando los parámetros de diseño de la vista de superficie en match_parent, pero esto da como resultado una distorsión en alguna dirección y solo es posible hasta que la vista previa llena la pantalla. Esto parece indicar que la vista previa fuera de la pantalla es imposible y el hardware (o el sistema operativo) limita dicho comportamiento.

No hay otra pregunta sobre el tema, pero esa pregunta afirma que no es posible crear un SurfaceView mayor que las dimensiones de la pantalla, lo cual es falso, como descubrí con el registro. Sin embargo, lo que parece ser el caso es que la vista previa de la cámara no puede crecer hasta el tamaño completo de un SurfaceView enorme.

Mi intento:

Tengo un diseño relativo, dentro de él un FrameLayout, y dentro de eso creo un SurfaceView. El ancho de todo el diseño relativo se establece a continuación en 635 dp, que es ~ el doble del tamaño de la pantalla del dispositivo. FrameLayout coincide con este tamaño y también lo hace SurfaceView (agregado mediante programación más adelante)

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

El siguiente es el código que obtiene y establece el tamaño de vista previa. Aquí quiero hacer que la vista previa de la cámara se expanda para llenar todo el FrameLayout (el doble del ancho de la pantalla). La vista aparece y se destruye con total normalidad, por lo que estoy eliminando el código que no está relacionado con esta pregunta en particular porque distrae la atención de la pregunta esencial y mi intento de hacer crecer la vista de manera fácil y sencilla a un tamaño mayor que el de la pantalla.

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

Me preocupa que la única forma de tener éxito en este esfuerzo sea renderizar de alguna manera a una superficie openGL, pero esto aparentemente podría ser demasiado lento a todo color. También es un dolor si la vista previa de la cámara se puede simplemente estirar y recortar.

Gracias de antemano a cualquier intento de solución.

preguntado el 04 de julio de 12 a las 02:07

¿Podría publicar su código oncreate ()? o donde llamas al método setcontentview() -

¿Por qué tienes curiosidad acerca de ese código? Era bastante básico y simplemente configuraba la vista de contenido en el xml que compartí anteriormente. -

De acuerdo, creo que no es posible expandir una vista más allá del administrador de ventanas, también estoy buscando hacer zoom en una sección del video, pero al usar la vista de toda la superficie y la vista de video personalizada no obtengo ninguna, el video no se recorta más allá del tamaño -

FWIW, puede encontrar código que ajusta SurfaceView para mantener una relación de aspecto específica y modifica la vista previa de la cámara con GLES, en Grafika (github.com/google/grafika). Las cosas se vuelven mucho más fáciles con los lanzamientos recientes de Android. -

1 Respuestas

Ok, sé que esto es muy tarde como respuesta, pero es posible. A continuación se muestra el código de la muestra SDK de Android. Para ver el resto del código para implementar esto, descargue las muestras de SDK de Android y vaya a 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);
        }
    }
}
}

este código está destinado a ajustar la vista previa a la dimensión más pequeña (que no altera la relación de aspecto) y al centro para tener barras negras en la otra dimensión. Pero si volteas el > para ser < en cambio, lograrás lo que quieres. Ex:

if (width * previewHeight < height * previewWidth) {...

Respondido el 18 de enero de 13 a las 20:01

Impresionante... me salvó el tiempo. - Pandiri Deepak

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.