Android: la vista previa de la cámara está de lado

123

Estoy usando una Vista previa para mostrar lo que la cámara ve en la pantalla.

Puedo hacer que todo funcione bien, superficie creada, conjunto de superficie y se muestra la superficie.

Sin embargo, siempre muestra la imagen en un ángulo incorrecto de 90 grados en modo vertical.

Como en la imagen:

texto alternativo

Soy consciente de que usar el siguiente código aclarará la situación:

setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

Sin embargo, tengo la Vista previa dentro de una Actividad que tiene otros elementos y no tiene sentido que mi Actividad se muestre en modo horizontal. (Está deshabilitado por defecto)

Entonces, me preguntaba ¿hay alguna forma de cambiar la orientación de la Vista previa? ¿Y dejar el resto de mi actividad correctamente en modo vertical?

¿O de todos modos rotar la vista previa para que se muestre correctamente?

Donal Rafferty
fuente
Eche un vistazo - stackoverflow.com/questions/10259299/…
Suvam Roy el

Respuestas:

145

Este problema parece comenzar como un error con cierto hardware, vea aquí, pero puede superarse mediante el uso de la llamada a mCamera.setDisplayOrientation (grados) disponible en la API 8. Entonces, así es como lo implemento:

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {            
    if (isPreviewRunning) {
        mCamera.stopPreview();
    }

    Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager)getSystemService(WINDOW_SERVICE)).getDefaultDisplay();

    if(display.getRotation() == Surface.ROTATION_0) {
        parameters.setPreviewSize(height, width);                           
        mCamera.setDisplayOrientation(90);
    }

    if(display.getRotation() == Surface.ROTATION_90) {
        parameters.setPreviewSize(width, height);                           
    }

    if(display.getRotation() == Surface.ROTATION_180) {
        parameters.setPreviewSize(height, width);               
    }

    if(display.getRotation() == Surface.ROTATION_270) {
        parameters.setPreviewSize(width, height);
        mCamera.setDisplayOrientation(180);
    }

    mCamera.setParameters(parameters);
    previewCamera();                      
}

And the previewCamera method :

public void previewCamera() {        
    try {           
        mCamera.setPreviewDisplay(mSurfaceHolder);          
        mCamera.startPreview();
        isPreviewRunning = true;
    } catch(Exception e) {
        Log.d(APP_CLASS, "Cannot start preview", e);    
    }
}

Esto estaba en un HTC Desire y tuve que poner inicialmente declaraciones de registro en cada una de las comprobaciones de rotación para decir cuál era la rotación y luego depurar en el dispositivo y observar la salida de logCat mientras giraba el dispositivo. Para el HTC Desire, 0 era el teléfono como era de esperar (retrato), 90 grados giraba el teléfono 90 grados en sentido contrario a las agujas del reloj (supuse que habría sido en el sentido de las agujas del reloj). En el código que verá, no necesitaba hacer ninguna rotación de pantalla cuando el teléfono estaba a 90 o 180 grados; el dispositivo parecía manejar esto por sí mismo. Solo un punto no funciona correctamente: la rotación de 270 grados es cuando gira el dispositivo 90 grados en el sentido de las agujas del reloj y la rotación de la pantalla muestra que está bien, pero si gira el dispositivo 270 grados en sentido contrario a las agujas del reloj, no parece compensarlo correctamente.

PD Tenga en cuenta el swapover de ancho y alto en las rotaciones apropiadas.

John J Smith
fuente
77
pero setDisplayOrientation (grado); El método admite el formulario 2.2, ¿qué pasa con la versión inferior? parámetros.setRotation (90); parámetros.set ("orientación", "retrato"); No estan funcionando. Si tienes alguna solución para versiones inferiores, por favor, ayúdame.
Vikram
1
Implementé una vista previa en mi aplicación que siempre se mostrará en modo vertical. Siempre estaba girando la pantalla 90 grados y esto parecía funcionar en todos los dispositivos hasta que lo probamos en el HTC Desire C. Como no cuento con el dispositivo ahora para probar esto, me gustaría que aclararas si esto te soluciona Sugerir finalmente funcionó bien en el deseo de HTC. ¡Gracias!
argenkiwi
13
La mCamera.setParameters(parameters);declaración bloquea mi aplicación, porque las dimensiones de la superficie no son un tamaño de vista previa válido para mi teléfono (¿tal vez porque mantengo la barra de estado visible?). Sin embargo, ¡descubrí que usar mCamera.setDisplayOrientation(90)entonces mCamera.setPreviewDisplay(mSurfaceHolder);sin establecer los parámetros también funcionó!
nicopico
3
estaría más limpio con una declaración de cambio
Siavash
2
¿No supone esto que la vista previa es lateral en TODOS los dispositivos? porque está de lado en algunos dispositivos y arriba en otros ... ¿hay alguna forma de verificar si la orientación de la cámara predeterminada de un dispositivo está en línea con el lado vertical del teléfono o no?
Siavash
16

intente establecer la orientación de la pantalla. Resuelve mi problema.

 mCamera.setDisplayOrientation(90);
ksu
fuente
55
a la hora de guardarlo guarda la imagen vertical en horizontal. ¿Alguna solución?
Akanksha Rathore
@Akanksha: esta bandera solo se aplica a la visualización de vista previa. No cambia la orientación del búfer devuelto en onPreviewFrame()oonPictureTaken()
Alex Cohn
13
 public void surfaceCreated(SurfaceHolder holder) {
     mCamera = Camera.open();
     mCamera.setDisplayOrientation(90);
     try {
         mCamera.setPreviewDisplay(holder);
         mCamera.setPreviewCallback(new PreviewCallback() {

             @Override
             public void onPreviewFrame(byte[] data, Camera camera) {
             }
         });

     } catch (Exception e) {
         e.printStackTrace();
     }
}

prueba este código

jitendra G2
fuente
3
a la hora de guardarlo guarda la imagen vertical en horizontal. ¿Alguna solución?
Akanksha Rathore
@Akanksha probablemente tenga que ver con los parámetros EXIF.
EpicPandaForce
4

Estaba teniendo un problema con la cámara frontal (problema al revés). Luego utilicé el siguiente método documentado en Documentos de Android :

public void setCameraDisplayOrientation(Activity activity , int icameraId , Camera camera1s)
    {
        CameraInfo cameraInfo = new CameraInfo();

        Camera.getCameraInfo(icameraId, cameraInfo);

        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();

        int degrees = 0; // k

        switch (rotation)
        {
        case Surface.ROTATION_0:
            degrees = 0;
            break;
        case Surface.ROTATION_90:
            degrees = 90;
            break;
        case Surface.ROTATION_180:
            degrees = 180;
            break;
        case Surface.ROTATION_270:
            degrees = 270;
            break;

        }

        int result;

        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT)
        {
            // cameraType=CAMERATYPE.FRONT;

            result = (cameraInfo.orientation + degrees) % 360;
            result = (360 - result) % 360; // compensate the mirror

        }
        else
        { // back-facing

            result = (cameraInfo.orientation - degrees + 360) % 360;

        }
        // displayRotate=result;
        camera.setDisplayOrientation(result);


    }
Zar E Ahmer
fuente
3
Este método proviene de la documentación de la cámara: developer.android.com/reference/android/hardware/…
VinceFior
@VinceFior ¿Algo mal si publica desde un documento oficial?
Ranjith Kumar
1
@RanjithKumar No particularmente, solo quería dar crédito a la fuente y señalar a las personas allí para obtener más contexto. :)
VinceFior
3

Lo hice siguiendo los consejos de mCamera.setDisplayOrientation (90); pero también roté el mapa de bits porque, por alguna razón, los otros enfoques no funcionan para mí en la versión 2.3.3.

Para rotar el mapa de bits hice esto:

Matrix matrix = new Matrix();
matrix.postRotate(90);
imageView1 = new ImageView(this);
Bitmap bitmap = BitmapFactory.decodeFile(files[i].getAbsolutePath());
Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap , 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
Bitmap scaledBitmap = Bitmap.createScaledBitmap(rotatedBitmap, 80, 80, true);
imageView1.setImageBitmap(scaledBitmap);
yngrdyn
fuente
0

Comparé mi código con el tutorial y lo que finalmente solucionó fue poner el siguiente código en mi AndroidManifext.xml: En la <activity>etiqueta:

android:screenOrientation="landscape"
android:configChanges="keyboardHidden|orientation">
sbaechler
fuente
0
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;
    }

    try {
        mCamera.stopPreview();
    } catch (Exception e) {
        e.printStackTrace();
    }

    Camera.Parameters parameters = mCamera.getParameters();
    Display display = ((WindowManager) getContext().getSystemService(WINDOW_SERVICE)).getDefaultDisplay();

    if (display.getRotation() == Surface.ROTATION_0) {
        parameters.setPreviewSize(h, w);
        mCamera.setDisplayOrientation(90);
    }

    if (display.getRotation() == Surface.ROTATION_90) {
        parameters.setPreviewSize(w, h);
        mCamera.setDisplayOrientation(0);
    }

    if (display.getRotation() == Surface.ROTATION_180) {
        parameters.setPreviewSize(h, w);
        mCamera.setDisplayOrientation(270);
    }

    if (display.getRotation() == Surface.ROTATION_270) {
        parameters.setPreviewSize(w, h);
        mCamera.setDisplayOrientation(180);
    }

    previewCamera();
}

public void previewCamera() {
    try {
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();
    } catch (Exception e) {
        //Log.d(APP_CLASS, "Cannot start preview", e);
        e.printStackTrace();
    }
}
sofi37
fuente
0

Creo que el valor SENSOR_ORIENTATION explicará qué valor se usará para la rotación en lugar de codificar a 90 grados

CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
        if (manager == null) {
            Log.i(TAG, "camera manager is null");
            return;
        }
        for (String id: manager.getCameraIdList()) {
            CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
            Integer orientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
            Log.i(TAG, "camera sensor orientation is " + orientation);
        }
psykid
fuente