2012-10-05 45 views
5

Estoy implementando una aplicación de cámara y cuando miro la vista previa (especialmente con la cámara frontal), la imagen es muy gorda. Parece que la imagen se estira horizontalmente. Sigo la muestra sdk con el tamaño de la cámara optimizado, pero no ayuda. ¿Cómo puedo ajustar la configuración de mi cámara para que tenga una vista previa como la otra aplicación de la cámara?Vista previa de la cámara Android se ve extraño

Gracias.

Mi código está por debajo.

public class CameraActivity extends Activity implements SurfaceHolder.Callback, Camera.ShutterCallback, Camera.PictureCallback { 

Camera m_camera; 
SurfaceView m_surfaceView; 
int m_numOfCamera; 
int m_defaultCameraId; 
int m_currentCamera; 
int m_surfaceWidth; 
int m_surfaceHeight; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_camera); 
    getActionBar().setDisplayHomeAsUpEnabled(true); 


    m_surfaceView = (SurfaceView)findViewById(R.id.cameraPreview); 
    m_surfaceView.getHolder().addCallback(this); 

    m_camera = Camera.open(); 

    m_numOfCamera = Camera.getNumberOfCameras(); 

    CameraInfo cameraInfo = new CameraInfo(); 
    for (int i = 0; i < m_numOfCamera; ++i) { 
     Camera.getCameraInfo(i, cameraInfo); 
     if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) { 
      m_defaultCameraId = i; 
      m_currentCamera = m_defaultCameraId; 
     }  
    } 

    if (m_numOfCamera < 1) { 
     MenuItem switchCam = (MenuItem)findViewById(R.id.menu_switch_camera); 
     switchCam.setVisible(false); 
    } 
} 

@Override 
public void onPause() { 
    super.onPause(); 
    m_camera.stopPreview(); 
} 

@Override 
public void onDestroy() { 
    super.onDestroy(); 
    m_camera.release(); 
} 

@Override 
public boolean onCreateOptionsMenu(Menu menu) { 
    getMenuInflater().inflate(R.menu.activity_camera, menu); 
    return true; 
} 

@Override 
public boolean onOptionsItemSelected(final MenuItem item) 
{ 
    if (item.getItemId() == android.R.id.home) 
    { 
     Intent intent = new Intent(this, MainActivity.class); 
     intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
     startActivity(intent); 

     return true; 
    } 
    else if (item.getItemId() == R.id.menu_switch_camera) 
    { 
     if (m_camera != null) { 
      m_camera.stopPreview(); 
      m_camera.release(); 
      m_camera = null; 
     } 

     m_camera = Camera.open((m_currentCamera + 1) % m_numOfCamera); 
     m_currentCamera = (m_currentCamera + 1) % m_numOfCamera; 

     Camera.Parameters params = m_camera.getParameters(); 
     List<Camera.Size> sizes = params.getSupportedPreviewSizes(); 
     Camera.Size size = getOptimalPreviewSize(sizes, m_surfaceWidth, m_surfaceHeight); 

     params.setPreviewSize(size.width, size.height); 

     m_camera.setParameters(params); 
     setCameraDisplayOrientation(this, m_currentCamera, m_camera); 
     m_camera.startPreview(); 
     try { 
      m_camera.setPreviewDisplay(m_surfaceView.getHolder()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return true; 
    } 
    return true; 
} 

public void onPictureTaken(byte[] arg0, Camera arg1) { 
    // TODO Auto-generated method stub 

} 

public void onShutter() { 
    // TODO Auto-generated method stub 

} 

public void surfaceChanged(SurfaceHolder arg0, int format, int w, int h) { 
    m_surfaceWidth = w; 
    m_surfaceHeight = h; 
    Camera.Parameters params = m_camera.getParameters(); 
    List<Camera.Size> sizes = params.getSupportedPreviewSizes(); 
    Camera.Size selected = getOptimalPreviewSize(sizes, w, h); 

    params.setPreviewSize(selected.width, selected.height); 


    m_camera.setParameters(params); 
    setCameraDisplayOrientation(this, m_currentCamera, m_camera); 
    m_camera.startPreview();  
} 

private static void setCameraDisplayOrientation(Activity activity, 
     int cameraId, android.hardware.Camera camera) { 
    android.hardware.Camera.CameraInfo info = 
      new android.hardware.Camera.CameraInfo(); 
    android.hardware.Camera.getCameraInfo(cameraId, info); 
    int rotation = activity.getWindowManager().getDefaultDisplay() 
      .getRotation(); 
    int degrees = 0; 
    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 (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 
     result = (info.orientation + degrees) % 360; 
     result = (360 - result) % 360; // compensate the mirror 
    } else { // back-facing 
     result = (info.orientation - degrees + 360) % 360; 
    } 
    camera.setDisplayOrientation(result); 
} 


public void surfaceCreated(SurfaceHolder arg0) { 
    try { 
     m_camera.setPreviewDisplay(m_surfaceView.getHolder()); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 

public void surfaceDestroyed(SurfaceHolder arg0) { 
    // TODO Auto-generated method stub 

} 

private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { 


    final double ASPECT_TOLERANCE = 0.1; 
    double targetRatio = (double) w/h; 
    if (sizes == null) 
     return null; 

    Size optimalSize = null; 
    double minDiff = Double.MAX_VALUE; 

    int targetHeight = h; 

    // Try to find an size match aspect ratio and size 
    for (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); 
     } 
    } 

    // Cannot find the one match the aspect ratio, ignore the requirement 
    if (optimalSize == null) { 
     minDiff = Double.MAX_VALUE; 
     for (Size size : sizes) { 
      if (Math.abs(size.height - targetHeight) < minDiff) { 
       optimalSize = size; 
       minDiff = Math.abs(size.height - targetHeight); 
      } 
     } 
    } 

    return optimalSize; 
} 

} 

Respuesta

15

La vista previa de la cámara siempre llena el SurfaceView que lo muestra. Si la relación de aspecto de m_surfaceView no coincide con la relación de aspecto de la cámara, se ampliará la vista previa.

Deberá crear m_surfaceView que coincida con la relación de aspecto. Eso significa que tendrá que crearlo desde el código, no desde el archivo XML de diseño.

Hay un proyecto de ejemplo APIDemos que encontrará en proyectos de ejemplo de Android. En el proyecto hay una cosa llamada CameraPreview. Este tiene una buena demostración para configurar la vista previa de la cámara en un SurfaceView. Tiene una clase que extends ViewGroup, y agrega el SurfaceView como su hijo del código. El método onMeasure() se ha reemplazado para determinar la altura y el ancho del SurfaceView, por lo que se conserva la relación de aspecto. Echa un vistazo al proyecto, y espero que quede claro.

[Lo siento, no pude publicar el enlace aquí - Se supone que this es el enlace, pero lo encontré roto. Pero si ha instalado los proyectos de muestra con el SDK de Android, puede encontrar el proyecto en las muestras. Abra un nuevo Proyecto de ejemplo de Android, seleccione APIDemos, luego busque una clase llamada CameraPreview. Debería estar en el paquete com.example.android.apis.graphics, por lo que recuerdo.]

+0

Gracias ¡mucho! Probaré eso. –

+2

¿Cómo es posible que la cámara normal de cualquier dispositivo tenga una vista previa de pantalla completa, sin ningún estiramiento entonces? – idish

+0

Lo tengo dentro de sdk/sample/adroid-18. Gracias –

0

Cambié el método onLayout y no la vista previa de la cámara no se estira. El resto de la cosa es similar a APiDemo que se encuentra aquí sdk/sample/adroid-18.La idea es que solo tenemos un tamaño de vista previa compatible, pero nuestro tamaño de vista puede no coincidir siempre con el tamaño de vista previa. así que tomé un tamaño de vista previa más grande que mi tamaño de vista de imagen. esto funciona para mi. Puede ayudar a alguien ...

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

       left = (width - scaledChildWidth)/2; 
       top = 0; 
       right = (width + scaledChildWidth)/2; 
       bottom = height; 

       child.layout(left, top, right, bottom); 
      } else { 
       final int scaledChildHeight = previewHeight * width 
         /previewWidth; 

       left = 0; 
       top = (height - scaledChildHeight)/2; 
       right = width; 
       bottom = (height + scaledChildHeight)/2; 

       child.layout(left, top, right, bottom); 
      } 
     } 
    } 
+0

lo que podría quedar a la izquierda, derecha, abajo y arriba, ¿dónde están declarados? el mismo l, r, t, b? – desgraci

+0

es un método anulado, no necesita pasar valores para eso. Tomará el valor l, r, t, b de acuerdo con su diseño –

0

Tengo un problema con la vista previa de la cámara que se extiende demasiado. Es demasiado estirando en modo vertical y horizontal.

Así que al manifiesta añadí screenOrentation = "Retrato", pero no sirvió de nada, todavía vista previa se reajustarán en cualquier posición (vertical - vista previa es a ancho o paisaje es demasiado largo) se puede ver esto en pantallas. me gustaría añadir a Samsung Ace III que todo está bien, pero al LG Nexus 4 es estiramiento problema

package pl.probs.camera.component; 

import java.io.IOException; 
import java.util.ArrayList; 
import java.util.Collections; 
import java.util.Comparator; 
import java.util.List; 
import android.annotation.SuppressLint; 
import android.app.Activity; 
import android.content.Context; 
import android.graphics.Point; 
import android.hardware.Camera; 
import android.hardware.Camera.AutoFocusCallback; 
import android.hardware.Camera.CameraInfo; 
import android.hardware.Camera.Parameters; 
import android.hardware.Camera.Size; 
import android.util.Log; 
import android.view.Display; 
import android.view.MotionEvent; 
import android.view.Surface; 
import android.view.SurfaceHolder; 
import android.view.SurfaceView; 
import pl.probs.lib.debug.L; 

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { 
    private static final String TAG = "CameraPreview"; 
    private static boolean showLogs = true; 
    private SurfaceHolder mHolder; 
    private Camera mCamera; 
    private Context context; 
    private Parameters resolution; 
    private List<Size> lSuportedPreviewSize; 
    private static int cOrientation = 0; // aktualny kat orientacji 
    private static boolean cOrientationChanged = false; // Stan orientacji 
                 // zostal zmieniony 
                 // wzgledem poprzedniego 
    private Display display; // Rozmiar ekranu 
    private Point displaySize; // Zmienna przechowuje Rozmiar Ekranu 
    private Point optimalPreviewSize; 
public CameraPreview(Context context, Camera camera, int resolution) { 
    super(context); 
    this.optimalPreviewSize = new Point(); 
    this.context = context; 
    this.mCamera = camera; 
    setDisplaySize(this.display); 
    setFocusable(true); 
    setFocusableInTouchMode(true); 
    mHolder = getHolder(); 
    mHolder.addCallback(this); 
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
    this.resolution = getMinResolution(resolution); 
    this.optimalPreviewSize = getOptimalPreviewResolution(this.display); 
    Size s = mCamera.getParameters().getPreviewSize(); // Sprawdzenie jaki 
                 // prewiev ustawiony 
} 

public Point getOptimalPreviewSize() { 
    return optimalPreviewSize; 
} 

public void surfaceCreated(SurfaceHolder holder) { 
    try { 
     if (mCamera != null) { 
      mCamera.stopPreview(); 
      mCamera.setPreviewDisplay(holder); 
      Size s = mCamera.getParameters().getPreviewSize(); 
      mCamera.startPreview(); 
     } 
    } catch (IOException e) { 
     L.d("Błąd ustawiania podglÄ…du: " + e.getMessage()); 
    } 
} 

protected void onPause() { 
    // Because the Camera object is a shared resource, it's very 
    // important to release it when the activity is paused. 
    if (mCamera != null) { 
     mCamera.release(); 
     mCamera = null; 
    } 
} 

public void surfaceDestroyed(SurfaceHolder holder) { 
    if (mCamera != null) { 
     mCamera.stopPreview(); 
    } 
} 

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
    Camera.Parameters setPrevOrientation = mCamera.getParameters(); 
    if (mHolder.getSurface() == null) 
     return; 

    try { 
     mCamera.stopPreview(); 
     Size sizeBefore = mCamera.getParameters().getPreviewSize(); 
     setPrevOrientation.setRotation(setCameraDisplayOrientation((Activity) context, getCameraId(), mCamera)); 
     // Orientacja Portrait np 640x480 Landscape 480x640 
     this.resolution.setPreviewSize(this.optimalPreviewSize.x, this.optimalPreviewSize.y); 
     mCamera.setParameters(this.resolution); 
     Size sizeAfter = mCamera.getParameters().getPreviewSize(); 
    } catch (RuntimeException e) { 
     L.d("Podgląd nie istnieje"); 
    } 

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

    } catch (Exception e) { 
     L.d("błąd podgladu: " + e.getMessage()); 
    } 
} 

@SuppressLint("ClickableViewAccessibility") 
public boolean onTouchEvent(MotionEvent event) { 
    if (event.getAction() == MotionEvent.ACTION_DOWN) { 
     mCamera.autoFocus(new AutoFocusCallback() { 

      @Override 
      public void onAutoFocus(boolean success, Camera camera) { 
       // do something 
      } 
     }); 

    } 

    return true; 
} 

private static int setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) { 
    android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo(); 

    android.hardware.Camera.getCameraInfo(cameraId, info); 
    int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); 
    int degrees = 0; 
    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; 
    } 

    cOrientation = degrees; 

    int result; 
    if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) { 
     result = (info.orientation + degrees) % 360; 
     result = (360 - result) % 360; // compensate the mirror 
    } else { // back-facing 
     result = (info.orientation - degrees + 360) % 360; 
    } 

    camera.setDisplayOrientation(result); 
    return result; 
} 

private int getCameraId() { 
    int cameraId = -1; 
    int numberOfCameras = Camera.getNumberOfCameras(); 
    for (int i = 0; i < numberOfCameras; i++) { 
     CameraInfo info = new CameraInfo(); 
     Camera.getCameraInfo(i, info); 
     if (info.facing == CameraInfo.CAMERA_FACING_BACK) { 
      cameraId = i; 
      break; 
     } 
    } 
    return cameraId; 
} 

private Parameters getMinResolution(int desireResolutionInMpx) { 
    int height[], width[], size; 
    float megapixels; 
    Camera.Parameters p = mCamera.getParameters(); 
    size = p.getSupportedPictureSizes().size(); 
    height = new int[size]; 
    width = new int[size]; 
    for (int i = 0; i < size; i++) { 
     height[i] = p.getSupportedPictureSizes().get(i).height; 
     width[i] = p.getSupportedPictureSizes().get(i).width; 
     megapixels = (float) (((float) height[i] * (float) width[i])/1024000); 
     if (megapixels <= desireResolutionInMpx) { 
      p.setPictureSize(width[i], height[i]); 
      break; 
     } 
    } 
    return p; 
} 

private Point getOptimalPreviewResolution(Display displaySize) { 
    lSuportedPreviewSize = mCamera.getParameters().getSupportedPreviewSizes(); 
    Point optimalPreviewSize = new Point(); 
    int displayWidth = displaySize.getWidth(); // szerokosc ekranu 
    int displayHeight = displaySize.getHeight(); // wysokosc ekranu 
    int cameraHeight; // wspierana wysokosc kamery 
    int cameraWidth; // wspierana szerokosc kamery 

    // Lista przechowywujace SupportedPreviewSize kamery, wszyskie 
    // rozdzielczosci mniejsze od szerokosc i wysokosci ekranu 
    List<Point> lOptimalPoint = new ArrayList<Point>(); 

    // Pomocniczo do listowania zawartosci listy 
    // TODO manta displayHeight cameraHeight brak oraz width brak zgodnosci 
    // (
    System.out.println(lOptimalPoint.toString()); 
    for (int i = 0; i < lSuportedPreviewSize.size(); i++) { 
     Log.i(TAG, "w " + lSuportedPreviewSize.get(i).width + " h " + lSuportedPreviewSize.get(i).height + " \n"); 
    } 

    // Wyszukanie wszystkich wysokosci kamery mniejszej od wysokosci ekranu 
    for (int i = 0; i < lSuportedPreviewSize.size(); i++) { 
     // TODO Uwazaj kamera zapisuje swoj rozmiar dla pozycji landscape 
     // gdzie height = 480 a width = 800 
     cameraHeight = lSuportedPreviewSize.get(i).width; 
     cameraWidth = lSuportedPreviewSize.get(i).height; 
     // Porownaj wysokosc ekranu urzadzenia z wysokosci supportedPreview 
     // dodaj do listy 
     if (displayHeight > cameraHeight) { 
      lOptimalPoint.add(new Point(cameraHeight, cameraWidth)); 
     } 
    } 

    // Sortowanie rosnaco 
    Collections.sort(lOptimalPoint, new ComapreSupportedPreviewByWidth()); 
    // Ostatni element listy optymalny 
    optimalPreviewSize = lOptimalPoint.get(lOptimalPoint.size()-1); 

    // Zwracana rozdzielczosc landscape aparatu np (800x600) 
    return optimalPreviewSize; 
} 

private void setDisplaySize(Display display) { 
    Activity activity = (Activity) this.context; // Pobierz aktywnosc aby 
                // znać rozmiar ekranu 

    this.display = activity.getWindowManager().getDefaultDisplay(); 
} 

class ComapreSupportedPreviewByWidth implements Comparator<Point> { 

    @Override 
    public int compare(Point lhs, Point rhs) { 
     return lhs.x - rhs.x; 
    } 
} 

}

Link to screens and project doing at eclipse

0

ya he resuelto. Lo que podría causar problemas con la extraña vista previa de la cámara.

  • barra de estado toma espacios - se puede ocultar Hiding the Status Bar

  • Algunos espacios también tomar TitleBar - se puede desactivar esta en manifiesta

android: theme = "@ android: style/Theme.NoTitleBar ">

  • actividad de cambio de orientación a horizontal "por culpa soporte de la cámara de vista previa que la orientación" - se puede comprobar esto en API demo Gráficos-> CameraPreview

  • algoritmo que compara el tamaño de Display.getWidth() Tamaño de Camera.getParameters(). getSupportedPreviewSizes(); si son lo mismo es una función del cambio surfaceChanged Parametrs.setPreviewSize (x, y) que recibió cuando se busca la lista


public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { 
    Camera.Parameters setPrevOrientation = mCamera.getParameters(); 
    if (mHolder.getSurface() == null) 
     return; 

    try { 
     mCamera.stopPreview(); 
     Size sizeBefore = mCamera.getParameters().getPreviewSize(); 
     setPrevOrientation.setRotation(setCameraDisplayOrientation(
       (Activity) context, getCameraId(), mCamera)); 
     // Orientacja Portrait np 640x480 Landscape 480x640 
     this.resolution.setPreviewSize(this.optimalPreviewSize.x, 
       this.optimalPreviewSize.y); 
     mCamera.setParameters(this.resolution); 
     Size sizeAfter = mCamera.getParameters().getPreviewSize(); 
    } catch (RuntimeException e) { 

     L.d("Podgląd nie istnieje"); 
    } 

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

    } catch (Exception e) { 
     L.d("błąd podgladu: " + e.getMessage()); 
    } 
} 

private Point getOptimalPreviewResolution(Display displaySize) { 

     lSuportedPreviewSize = mCamera.getParameters() 
       .getSupportedPreviewSizes(); 
     Point optimalPreviewSize = new Point(); 
     int displayWidth = displaySize.getWidth(); 
     int displayHeight = displaySize.getHeight(); 
     int cameraHeight; 
     int cameraWidth; 

     List<Point> lOptimalPoint = new ArrayList<Point>(); 

     for (int i = 0; i < lSuportedPreviewSize.size(); i++) { 
      cameraHeight = lSuportedPreviewSize.get(i).width; 
      cameraWidth = lSuportedPreviewSize.get(i).height; 
      if (displayHeight >= cameraHeight) { 
       lOptimalPoint.add(new Point(cameraHeight, cameraWidth)); 
      } 
     } 

     // Sort ascending 
     Collections.sort(lOptimalPoint, 
       new ComapreSupportedPreviewByWidth()); 
     // Last element is optimal 
     optimalPreviewSize = lOptimalPoint.get(lOptimalPoint.size() - 1); 

     // Return resolution - camera at landscape mode (800x600) 
     return optimalPreviewSize; 
    } 

class ComapreSupportedPreviewByWidth implements Comparator<Point> { 

    @Override 
    public int compare(Point lhs, Point rhs) { 
     return lhs.x - rhs.x; 
    } 
Cuestiones relacionadas