2015-05-05 10 views
23

Ich mache benutzerdefinierte Kamera wie "SnapChat" für eine Android-App, aber Kamera Vorschau ist auf einige Geräte gestreckt wie (Moto g zweite Generation, eins + eins), aber nicht auf (Samsung s3, Samsung s4). Ich habe die folgende Referenz Camera display/preview in full screen does not maintain aspect ratio - image is skewed, stretched in order to fit on the screen verwenden. Aber das hilft mir nicht 100%. Ich teile den Bildschirm.Kamera Vorschau gestreckt auf wenigen Android Geräten

Gestrecktes Bild auf Samsung Moto G der zweiten Generation ist. enter image description here enter image description here

Samsung S3 Bilder, die nicht gedehnt wird ist Above

private void setPreviewLayout() { 
    if (null == mCamera) { 
     return; 
    } 
    Camera.Parameters parameters = null; 
    Camera.Size size = null; 
    try { 
     int screenWidth = (int) getResources().getDisplayMetrics().widthPixels; 
     int screenHeight = (int) getResources().getDisplayMetrics().heightPixels; 
     parameters = mCamera.getParameters(); 
     size = getOptimalPreviewSize(mCamera.getParameters().getSupportedPreviewSizes(), screenWidth, screenHeight); 
     if (size != null) { 

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

     } 

     parameters.setPictureSize(screenHeight, screenWidth); 
     ; 
     mCamera.setParameters(parameters); 
     if (on && currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK) { 
      parameters.setFlashMode(Camera.Parameters.FLASH_MODE_ON); 
     } else { 
      parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); 
     } 
     parameters.setWhiteBalance(Camera.Parameters.WHITE_BALANCE_AUTO); 
     parameters.setExposureCompensation(0); 
     parameters.setPictureFormat(ImageFormat.JPEG); 
     parameters.setJpegQuality(100); 
     List<String> focusModes = parameters.getSupportedFocusModes(); 
     if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { 
      parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); 
     } else if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) { 
      parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO); 
     } 
     mCamera.setParameters(parameters); 
     /* 
     * camera.setPreviewDisplay(surfaceHolder); camera.startPreview(); 
     */ 

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

} 
private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) { 
    final double ASPECT_TOLERANCE = 0.1; 
    double targetRatio = (double) h/w; 

    if (sizes == null) 
     return null; 

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

    int targetHeight = h; 

    for (Camera.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); 
     } 
    } 

    if (optimalSize == null) { 
     minDiff = Double.MAX_VALUE; 
     for (Camera.Size size : sizes) { 
      if (Math.abs(size.height - targetHeight) < minDiff) { 
       optimalSize = size; 
       minDiff = Math.abs(size.height - targetHeight); 
      } 
     } 
    } 
    return optimalSize; 
} 
+0

Kann mir jemand helfen.? –

Antwort

12

Mit getOptimalPreviewSize() wichtig ist, aber es löst nicht alle Strecken auf alle Geräte in allen Layouts. Sie müssen darauf vorbereitet sein, die Vorschau ein wenig zu beschneiden, damit die Vorschau den Bildschirm ohne Verzerrungen ausfüllt.

Es gibt verschiedene Techniken, um die Größe der Oberfläche unterscheidet sich von der tatsächlichen Bildschirmgröße zu erzwingen, aber diese finde ich die einfachste:

ich die CameraView meinem Layout hinzufügen:

public class CameraView extends SurfaceView implements SurfaceHolder.Callback { 

public CameraView(Context context, AttributeSet attr) { 
    super(context, attr); 

    // install a SurfaceHolder.Callback so we get notified when the 
    // underlying surface is created and destroyed. 
    getHolder().addCallback(this); 
} 

@Override public void surfaceCreated(SurfaceHolder holder) { 
    openCamera(); 
    bCameraInitialized = false; 
} 

@Override public void surfaceDestroyed(SurfaceHolder holder) { 
    camera.release(); 
} 

@Override public void surfaceChanged(SurfaceHolder holder, 
     int format, int w, int h) { 
     if (bCameraInitialized) { 
      // we will get here after we have resized the surface, see below 
      return; 
     } 
     cameraSetup(w, h); 
     bCameraInitialized = true; 
} 

private void cameraSetup(int w, int h) { 
    // set the camera parameters, including the preview size 

    FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams(); 
    double cameraAspectRatio = ((double)optimalSize.width)/optimalSize.height; 

    if (((double)h)/w > cameraAspectRatio) { 
     lp.width = (int)(h/cameraAspectRatio+0.5); 
     lp.height = h; 
    } 
    else { 
     lp.height = (int)(w*cameraAspectRatio + 0.5); 
     lp.width = w; 
     lp.topMargin = (h - lp.height)/2; 
    } 
    lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP; 

    setLayoutParams(lp); 
    requestLayout(); 
} 

zu betonen die Grundidee, ich habe keine Fehlerbehandlung, und ich habe hier nicht gezeigt, wie die Kamera is actually started with a secondary Looper.

+0

Ich habe Ihren Code verwendet, aber das löst mein Problem nicht. Ich verwende TextureView.SurfaceTextureListener anstelle von Surface View. Sie können mich auf skype sachin.auxiliumit hinzufügen oder geben Sie mir Ihre Skype-ID. Ich werde mich wirklich voll von dir bedanken. –

+0

Ich werde nicht bis morgen auf Skype verfügbar sein. Ich glaube, dass Sie selbst mit TextureView immer noch die gleichen Layout-Ereignisse haben. Sie können 'onMeasure()' wie oben erklärt oder 'OnLayoutListener' verwenden - Sie müssen nur die feste Breite und Höhe für Ihre Ansicht einstellen, egal welcher Typ - und wahrscheinlich die Mitte in ihrem Container zentrieren. –

+0

Vielen Dank ................... –

0

versuchen, dies es funktioniert ...

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback { 

private static final String TAG = "Camera Preview"; 
private static final double PREVIEW_SIZE_FACTOR = 3.00; 
private SurfaceHolder mHolder = null; 
private Camera mCamera = null; 
Camera.Parameters _parameters=null; 

@SuppressWarnings("deprecation") 
public CameraPreview(Context context, Camera camera) { 
    super(context); 
    mCamera = camera; 
    // Install a SurfaceHolder.Callback so we get notified when the 
    // underlying surface is created and destroyed. 
    mHolder = getHolder(); 
    mHolder.addCallback(this); 
    // deprecated setting, but required on Android versions prior to 3.0 
    mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
} 

public void surfaceCreated(SurfaceHolder holder) { 
    // The Surface has been created, now tell the camera where to draw the preview. 
    try { 
     Camera.Parameters parameters = mCamera.getParameters(); 
     final Size mPreviewSize = getOptimalSize(); 
     parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
     requestLayout(); 
     mCamera.setParameters(parameters); 
     mCamera.setPreviewDisplay(holder); 
     mCamera.startPreview(); 
     //startContinuousAutoFocus(); 
    } catch (Exception e) { 
     Log.d(TAG, "Error setting camera preview: " + e.getMessage()); 
    } 
} 
public void surfaceDestroyed(SurfaceHolder holder) { 
} 

@SuppressLint("NewApi") 
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; 
    } 

    // stop preview before making changes 
    try { 
     mCamera.stopPreview(); 
    } catch (Exception e){ 
     // ignore: tried to stop a non-existent preview 
    } 

    // set preview size and make any resize, rotate or 
    // reformatting changes here 
    // set Camera parameters 

    // start preview with new settings 
    try { 
     mCamera.setPreviewDisplay(mHolder); 
     mCamera.startPreview(); 

    } catch (Exception e){ 
     Log.d(TAG, "Error starting camera preview: " + e.getMessage()); 
    } 
    } 
public void startPreview(){ 
    try{ 
     mCamera.startPreview(); 
    }catch (Exception e) { 
    } 
     } 
     private Size getOptimalSize() { 
    Camera.Size result = null; 
    final Camera.Parameters parameters = mCamera.getParameters(); 
    Log.i(CameraPreview.class.getSimpleName(), "window width: " + getWidth() + ", height: " + getHeight()); 
    for (final Camera.Size size : parameters.getSupportedPreviewSizes()) { 
     if (size.width <= getWidth() * PREVIEW_SIZE_FACTOR && size.height <= getHeight() * PREVIEW_SIZE_FACTOR) { 
      if (result == null) { 
       result = size; 
      } else { 
       final int resultArea = result.width * result.height; 
       final int newArea = size.width * size.height; 

       if (newArea > resultArea) { 
        result = size; 
       } 
      } 
     } 
    } 
    if (result == null) { 
     result = parameters.getSupportedPreviewSizes().get(0); 
    } 
    Log.i(CameraPreview.class.getSimpleName(), "Using PreviewSize: " + result.width + " x " + result.height); 
    return result; 
} 
} 
+0

Dies funktioniert nicht. Ich benutze TextureView.SurfaceTextureListener anstelle von Surface View können Sie mir sagen, wie ich es kann. –

+0

Bitte sehen Sie meinen ganzen Code unter –

0

Sie benötigen die onMeasure Methode der Klasse Surface außer Kraft zu setzen Breite und Höhe des Surface

@Override 
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
     final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); 
     final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); 
     setMeasuredDimension(width, height); 

     if (mSupportedPreviewSizes != null) { 
      mPreviewSize = getOptimalPreviewSize(mCamera.getParameters().getSupportedPreviewSizes(), width, height); 
     } 
    } 

Dann die Vorschau zu bekommen Größe stellen Sie bekam zur Vorschau der Kamera-Parameter.

cameraParameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
mCamera.setParameters(cameraParameters); 

getSuggestedMinimumHeight(), getSuggestedMinimumWidth() sind die Methoden der View-Klasse

hoffe, das hilft !!!

+0

Hallo Lakshay, ich benutze TextureView.SurfaceTextureListener anstelle der Oberfläche zu sehen. Es hat keine Methode onMeasure. kannst du mir sagen, wie ich es kann. –

+0

Können Sie Ihren Code dann bitte weiter ausarbeiten?Will sehen, wie ich noch nie TextureView Listener verwendet habe diskutiert – lakshay

+0

Bitte lesen Sie meinen ganzen Code oben –

Verwandte Themen