2016-06-01 91 views
0

倒我試圖創建的實際工作正常,所有場景自定義相機預覽邏輯:相機在Nexus設備

any device: phone, tablet 
any camera: front-facing, rear-facing 
android.hardware.Camera 

android:minSdkVersion14android:targetSdkVersion21。 我已經實現了自定義攝像頭預覽類,以設置相機預覽的顯示方向,並且非常適合所有設備,而無需使用Nexus設備。 Nexus設備有我認爲默認180方向。

雖然我在Nexus設備中啓動相機,但它顯示倒置。爲了克服與我已經檢查與Build.MANUFACTURER & Build.MODEL來識別設備並根據它設置方向。

if (Build.MODEL.equals("Nexus 6P") && Build.MANUFACTURER.equals("Huawei")) mCamera.setDisplayOrientation(90); 
     else mCamera.setDisplayOrientation(270); 

但它不工作。所以任何人都可以有想法克服這個和推薦的方式!提前幫助將不勝感激!

+0

我已經在Nexus 5中測試了我的自定義相機代碼。它的工作原理 – Nisarg

+0

哪些代碼?如果可能的話與我分享 – Piyush

+0

是的,肯定會放,給我一些時間需要做一些修改 – Nisarg

回答

0

要發起活動:

CameraPreviewNew mPreview = new ResizableCameraPreview(this, cameraId, CameraPreviewNew.LayoutMode.NoBlank, false, screenHeight, screenWidth); // cameraId for front or rear 
     LinearLayout.LayoutParams previewLayoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); 
     frameCamera.addView(mPreview, 0, previewLayoutParams); 

CameraPreviewNew.java

public class CameraPreviewNew extends SurfaceView implements SurfaceHolder.Callback { 
    private static boolean DEBUGGING = false; 
    private static final String LOG_TAG = "CameraPreviewSample"; 
    private static final String CAMERA_PARAM_ORIENTATION = "orientation"; 
    private static final String CAMERA_PARAM_LANDSCAPE = "landscape"; 
    private static final String CAMERA_PARAM_PORTRAIT = "portrait"; 
    protected Activity mActivity; 
    private SurfaceHolder mHolder; 
    protected Camera mCamera; 
    protected List<Camera.Size> mPreviewSizeList; 
    protected List<Camera.Size> mPictureSizeList; 
    protected Camera.Size mPreviewSize; 
    protected Camera.Size mPictureSize; 
    private int mSurfaceChangedCallDepth = 0; 
    private int mCameraId; 
    private LayoutMode mLayoutMode; 
    private int mCenterPosX = -1; 
    private int mCenterPosY; 
    private int screenHeight, screenWidth; 

    PreviewReadyCallback mPreviewReadyCallback = null; 

    public enum LayoutMode { 
     FitToParent, // Scale to the size that no side is larger than the parent 
     NoBlank // Scale to the size that no side is smaller than the parent 
    } 

    public interface PreviewReadyCallback { 
     void onPreviewReady(); 
    } 

    /** 
    * State flag: true when surface's layout size is set and surfaceChanged() 
    * process has not been completed. 
    */ 
    protected boolean mSurfaceConfiguring = false; 

    public CameraPreviewNew(Activity activity, int cameraId, LayoutMode mode, int screenHeight, int screenWidth) { 
     super(activity); // Always necessary 
     mActivity = activity; 
     mLayoutMode = mode; 
     this.screenHeight = screenHeight; 
     this.screenWidth = screenWidth; 
     mHolder = getHolder(); 
     mHolder.addCallback(this); 
     mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); 
//  mHolder.setFixedSize(fixWidth, fixHeight); 

//  FileLog.v("Camera ID ::::::::::: " + cameraId); 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { 
      if (Camera.getNumberOfCameras() > cameraId) { 
       mCameraId = cameraId; 
      } else { 
       mCameraId = 0; 
      } 
     } else { 
      mCameraId = 0; 
     } 
//  FileLog.d("Camera ID ::::::::::: " + cameraId); 

     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { 
      mCamera = Camera.open(mCameraId); 
     } else { 
      mCamera = Camera.open(); 
     } 
     Camera.Parameters cameraParams = mCamera.getParameters(); 
     mPreviewSizeList = cameraParams.getSupportedPreviewSizes(); 
     mPictureSizeList = cameraParams.getSupportedPictureSizes(); 

//  FileLog.d("Preview Size ID ::::::::::: " + mPreviewSizeList); 
    } 

    @Override 
    public void surfaceCreated(SurfaceHolder holder) { 
     try { 
      mCamera.setPreviewDisplay(mHolder); 
     } catch (IOException e) { 
      mCamera.release(); 
      mCamera = null; 
     } 
    } 

    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
     mSurfaceChangedCallDepth++; 
     doSurfaceChanged(width, height); 
     mSurfaceChangedCallDepth--; 
    } 

    public void doSurfaceChanged(int width, int height) { 
     mCamera.stopPreview(); 

     Camera.Parameters cameraParams = mCamera.getParameters(); 
     boolean portrait = isPortrait(); 

     // The code in this if-statement is prevented from executed again when surfaceChanged is 
     // called again due to the change of the layout size in this if-statement. 
     if (!mSurfaceConfiguring) { 
      Camera.Size previewSize = determinePreviewSize(portrait, width, height); 
      Camera.Size pictureSize = determinePictureSize(previewSize); 
      if (DEBUGGING) { Log.v(LOG_TAG, "Desired Preview Size - w: " + width + ", h: " + height); } 
      mPreviewSize = previewSize; 
      mPictureSize = pictureSize; 
      mSurfaceConfiguring = adjustSurfaceLayoutSize(previewSize, portrait, width, height); 
      // Continue executing this method if this method is called recursively. 
      // Recursive call of surfaceChanged is very special case, which is a path from 
      // the catch clause at the end of this method. 
      // The later part of this method should be executed as well in the recursive 
      // invocation of this method, because the layout change made in this recursive 
      // call will not trigger another invocation of this method. 
      if (mSurfaceConfiguring && (mSurfaceChangedCallDepth <= 1)) { 
       return; 
      } 
     } 

     configureCameraParameters(cameraParams, portrait); 
     mSurfaceConfiguring = false; 

     try { 
      mCamera.startPreview(); 
     } catch (Exception e) { 
      Log.w(LOG_TAG, "Failed to start preview: " + e.getMessage()); 

      // Remove failed size 
      mPreviewSizeList.remove(mPreviewSize); 
      mPreviewSize = null; 

      // Reconfigure 
      if (mPreviewSizeList.size() > 0) { // prevent infinite loop 
       surfaceChanged(null, 0, width, height); 
      } else { 
       Log.w(LOG_TAG, "Gave up starting preview"); 
      } 
     } 

     if (null != mPreviewReadyCallback) { 
      mPreviewReadyCallback.onPreviewReady(); 
     } 
    } 

    /** 
    * @param portrait 
    * @param reqWidth must be the value of the parameter passed in surfaceChanged 
    * @param reqHeight must be the value of the parameter passed in surfaceChanged 
    * @return Camera.Size object that is an element of the list returned from Camera.Parameters.getSupportedPreviewSizes. 
    */ 
    protected Camera.Size determinePreviewSize(boolean portrait, int reqWidth, int reqHeight) { 
     // Meaning of width and height is switched for preview when portrait, 
     // while it is the same as user's view for surface and metrics. 
     // That is, width must always be larger than height for setPreviewSize. 
     int reqPreviewWidth; // requested width in terms of camera hardware 
     int reqPreviewHeight; // requested height in terms of camera hardware 
     if (portrait) { 
      reqPreviewWidth = reqHeight; 
      reqPreviewHeight = reqWidth; 
     } else { 
      reqPreviewWidth = reqWidth; 
      reqPreviewHeight = reqHeight; 
     } 

     if (DEBUGGING) { 
      Log.v(LOG_TAG, "Listing all supported preview sizes"); 
      for (Camera.Size size : mPreviewSizeList) { 
       Log.v(LOG_TAG, " w: " + size.width + ", h: " + size.height); 
      } 
      Log.v(LOG_TAG, "Listing all supported picture sizes"); 
      for (Camera.Size size : mPictureSizeList) { 
       Log.v(LOG_TAG, " w: " + size.width + ", h: " + size.height); 
      } 
     } 

     // Adjust surface size with the closest aspect-ratio 
     float reqRatio = ((float) reqPreviewWidth)/reqPreviewHeight; 
     float curRatio, deltaRatio; 
     float deltaRatioMin = Float.MAX_VALUE; 
     Camera.Size retSize = null; 
     for (Camera.Size size : mPreviewSizeList) { 
      curRatio = ((float) size.width)/size.height; 
      deltaRatio = Math.abs(reqRatio - curRatio); 
      if (deltaRatio < deltaRatioMin) { 
       deltaRatioMin = deltaRatio; 
       retSize = size; 
      } 
     } 

     retSize = mPreviewSizeList.get(0); 

     return retSize; 
    } 

    protected Camera.Size determinePictureSize(Camera.Size previewSize) { 
     Camera.Size retSize = null; 
     for (Camera.Size size : mPictureSizeList) { 
      if (size.equals(previewSize)) { 
       return size; 
      } 
     } 

     if (DEBUGGING) { Log.v(LOG_TAG, "Same picture size not found."); } 

     // if the preview size is not supported as a picture size 
     float reqRatio = ((float) previewSize.width)/previewSize.height; 
     float curRatio, deltaRatio; 
     float deltaRatioMin = Float.MAX_VALUE; 
     for (Camera.Size size : mPictureSizeList) { 
      curRatio = ((float) size.width)/size.height; 
      deltaRatio = Math.abs(reqRatio - curRatio); 
      if (deltaRatio < deltaRatioMin) { 
       deltaRatioMin = deltaRatio; 
       retSize = size; 
      } 
     } 

     retSize = mPictureSizeList.get(0); 

     return retSize; 
    } 

    protected boolean adjustSurfaceLayoutSize(Camera.Size previewSize, boolean portrait, 
               int availableWidth, int availableHeight) { 
     float tmpLayoutHeight, tmpLayoutWidth; 
     if (portrait) { 
      tmpLayoutHeight = previewSize.width; 
      tmpLayoutWidth = previewSize.height; 
     } else { 
      tmpLayoutHeight = previewSize.height; 
      tmpLayoutWidth = previewSize.width; 
     } 

     float factH, factW, fact; 
     factH = availableHeight/tmpLayoutHeight; 
     factW = availableWidth/tmpLayoutWidth; 
     if (mLayoutMode == LayoutMode.FitToParent) { 
      // Select smaller factor, because the surface cannot be set to the size larger than display metrics. 
      if (factH < factW) { 
       fact = factH; 
      } else { 
       fact = factW; 
      } 
     } else { 
      if (factH < factW) { 
       fact = factW; 
      } else { 
       fact = factH; 
      } 
     } 

     LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams)this.getLayoutParams(); 

     int layoutHeight = (int) (tmpLayoutHeight * fact); 
     int layoutWidth = (int) (tmpLayoutWidth * fact); 
     if (DEBUGGING) { 
      Log.v(LOG_TAG, "Preview Layout Size - w: " + layoutWidth + ", h: " + layoutHeight); 
      Log.v(LOG_TAG, "Scale factor: " + fact); 
     } 

     boolean layoutChanged; 
     if ((layoutWidth != this.getWidth()) || (layoutHeight != this.getHeight())) { 
      int diffHeight = (screenHeight - layoutHeight)/2; 
      layoutParams.height = layoutHeight + diffHeight; 
      int diffWidth = (screenWidth - layoutWidth)/2; 
      layoutParams.width = layoutWidth + diffWidth; 
      if (mCenterPosX >= 0) { 
       layoutParams.topMargin = mCenterPosY - (layoutHeight/2); 
       layoutParams.leftMargin = mCenterPosX - (layoutWidth/2); 
      } 
      this.setLayoutParams(layoutParams); // this will trigger another surfaceChanged invocation. 
      layoutChanged = true; 
     } else { 
      layoutChanged = false; 
     } 

     return layoutChanged; 
    } 

    /** 
    * @param x X coordinate of center position on the screen. Set to negative value to unset. 
    * @param y Y coordinate of center position on the screen. 
    */ 
    public void setCenterPosition(int x, int y) { 
     mCenterPosX = x; 
     mCenterPosY = y; 
    } 

    protected void configureCameraParameters(Camera.Parameters cameraParams, boolean portrait) { 
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.FROYO) { // for 2.1 and before 
      if (portrait) { 
       cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_PORTRAIT); 
      } else { 
       cameraParams.set(CAMERA_PARAM_ORIENTATION, CAMERA_PARAM_LANDSCAPE); 
      } 
     } else { // for 2.2 and later 
      int angle; 
      Display display = mActivity.getWindowManager().getDefaultDisplay(); 
      switch (display.getRotation()) { 
       case Surface.ROTATION_0: // This is display orientation 
        angle = 90; // This is camera orientation 
        break; 
       case Surface.ROTATION_90: 
        angle = 0; 
        break; 
       case Surface.ROTATION_180: 
        angle = 270; 
        break; 
       case Surface.ROTATION_270: 
        angle = 180; 
        break; 
       default: 
        angle = 90; 
        break; 
      } 
      Log.v(LOG_TAG, "angle: " + angle); 
      mCamera.setDisplayOrientation(angle); 
     } 

     cameraParams.setPreviewSize(mPreviewSize.width, mPreviewSize.height); 
     cameraParams.setPictureSize(mPictureSize.width, mPictureSize.height); 
     cameraParams.setZoom(0); 

//  if (cameraParams.isZoomSupported()) { 
      final int maxZoomLevel = cameraParams.getMaxZoom(); 
      Log.e("max ZOOM ", "is " + maxZoomLevel); 
//  } 
//  cameraParams.setPreviewSize(fixWidth, fixHeight); 
//  cameraParams.setPictureSize(fixWidth, fixHeight); 
     if (DEBUGGING) { 
      Log.v(LOG_TAG, "Preview Actual Size - w: " + mPreviewSize.width + ", h: " + mPreviewSize.height); 
      Log.v(LOG_TAG, "Picture Actual Size - w: " + mPictureSize.width + ", h: " + mPictureSize.height); 
     } 

     mCamera.setParameters(cameraParams); 
    } 

    @SuppressWarnings("unused") 
    private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { 
     final double ASPECT_TOLERANCE = 0.2; 
     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) { 
      Log.d("Camera", "Checking size " + size.width + "w " + size.height 
        + "h"); 
      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; 
    } 

    @Override 
    public void surfaceDestroyed(SurfaceHolder holder) { 
     stop(); 
    } 

    public void stop() { 
     try { 
      if (null == mCamera) { 
       return; 
      } 
      if(mCamera != null) { 
       mCamera.stopPreview(); 
       mCamera.release(); 
       mCamera = null; 
      } 
     }catch (Exception e){ 
      e.printStackTrace(); 
     } 

    } 

    public boolean isPortrait() { 
     return (mActivity.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT); 
    } 

    public void setOneShotPreviewCallback(PreviewCallback callback) { 
     if (null == mCamera) { 
      return; 
     } 
     mCamera.setOneShotPreviewCallback(callback); 
    } 

    public void setPreviewCallback(PreviewCallback callback) { 
     if (null == mCamera) { 
      return; 
     } 
     mCamera.setPreviewCallback(callback); 
    } 

    public Camera.Size getPreviewSize() { 
     return mPreviewSize; 
    } 

    public void setOnPreviewReady(PreviewReadyCallback cb) { 
     mPreviewReadyCallback = cb; 
    } 

    public Camera getPreviewCamera() { 
     return mCamera; 
    } 
} 

ResizableCameraPreview.java

public class ResizableCameraPreview extends CameraPreviewNew { 
    private static boolean DEBUGGING = false; 
    private static final String LOG_TAG = "ResizableCameraPreviewSample"; 

    /** 
    * @param activity 
    * @param addReversedSizes is set to true to add reversed values of supported preview-sizes to the list. 
    */ 
    public ResizableCameraPreview(Activity activity, int cameraId, LayoutMode mode, boolean addReversedSizes, int screenHeight, int screenWidth) { 
     super(activity, cameraId, mode, screenHeight, screenWidth); 
     if (addReversedSizes) {    
      List<Camera.Size> sizes = mPreviewSizeList; 
      int length = sizes.size(); 
      for (int i = 0; i < length; i++) { 
       Camera.Size size = sizes.get(i); 
       Camera.Size revSize = mCamera.new Size(size.height, size.width); 
       sizes.add(revSize); 
      } 
     } 
    } 

    @Override 
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { 
     mCamera.stopPreview(); 

     Camera.Parameters cameraParams = mCamera.getParameters(); 
     boolean portrait = isPortrait(); 

     if (!mSurfaceConfiguring) { 
      Camera.Size previewSize = determinePreviewSize(portrait, width, height); 
      Camera.Size pictureSize = determinePictureSize(previewSize); 
      Log.v(LOG_TAG, "Desired Preview Size - w: " + width + ", h: " + height); 
      mPreviewSize = previewSize; 
      mPictureSize = pictureSize; 
      mSurfaceConfiguring = adjustSurfaceLayoutSize(previewSize, portrait, width, height); 
      if (mSurfaceConfiguring) { 
       return; 
      } 
     } 

     configureCameraParameters(cameraParams, portrait); 
     mSurfaceConfiguring = false; 

     try { 
      mCamera.startPreview(); 
     } catch (Exception e) { 
      Log.w(LOG_TAG, "Failed to start preview: " + e.getMessage()); 
     } 
    } 

    /** 
    * 
    * @param index selects preview size from the list returned by CameraPreview.getSupportedPreivewSizes(). 
    * @param width is the width of the available area for this view 
    * @param height is the height of the available area for this view 
    */ 
    public void setPreviewSize(int index, int width, int height) { 
     mCamera.stopPreview(); 

     Camera.Parameters cameraParams = mCamera.getParameters(); 
     boolean portrait = isPortrait(); 

     Camera.Size previewSize = mPreviewSizeList.get(index); 
     Camera.Size pictureSize = determinePictureSize(previewSize); 
     if (DEBUGGING) { Log.v(LOG_TAG, "Requested Preview Size - w: " + previewSize.width + ", h: " + previewSize.height); } 
     mPreviewSize = previewSize; 
     mPictureSize = pictureSize; 
     boolean layoutChanged = adjustSurfaceLayoutSize(previewSize, portrait, width, height); 
     if (layoutChanged) { 
      mSurfaceConfiguring = true; 
      return; 
     } 

     configureCameraParameters(cameraParams, portrait); 
     try { 
      mCamera.startPreview(); 
     } catch (Exception e) { 
     } 
     mSurfaceConfiguring = false; 
    } 

    public List<Camera.Size> getSupportedPreivewSizes() { 
     return mPreviewSizeList; 
    } 
} 

XML文件:

<FrameLayout 
    android:id="@+id/frm" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    > 
    <LinearLayout 
     android:id="@+id/frameCamera" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:orientation="vertical" > 
    </LinearLayout> 
</FrameLayout> 
+0

我已經在我身邊做了相同的代碼。 – Piyush

+0

@PiyushGupta有雙重檢查其工作中的Nexus 5 – Nisarg

+0

據我知道這並不在Nexus 5,嘗試用一臺Nexus 5X或6P發生,看看它的工作 –

2

據我所知,Nexus 5上不會出現這個問題。我不得不在Nexus 5X上處理它,並且我失去了一些時間嘗試(Click here to see why)。值得注意的是,我不能保證它是最好的解決方案,但它解決了我所有的問題。爲了解決它,我做了這樣的事情:

我創建了一個類CameraPreview extends SurfaceView只是爲了封裝所有的預覽初始化在一個地方。以下是一個類的構造函數:

public CameraPreview(Context context, int screenRotation, Camera camera) { 
    super(context); 
    mCamera = camera; 
    mScreenRotation = screenRotation; 
    mHolder = getHolder(); 
    mHolder.addCallback(this); 
    setFocusable(true); 
    setFocusableInTouchMode(true); 
} 

要創建我用這個預覽:,其中screenRotationint screenRotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();surfaceCreated回調被稱爲:

public void surfaceCreated(SurfaceHolder holder) { 
    try { 
     mCamera.setPreviewDisplay(holder); 
     setCameraDisplayOrientation(mScreenRotation, 0, mCamera); 

這裏,0來自cameraId(如果您使用前置攝像頭,可能會有所不同)。這裏是所有的魔法:

public void setCameraDisplayOrientation(int screenRotation, int cameraId, Camera camera) { 
    int rotation = getRotationAngle(screenRotation, cameraId); 
    camera.setDisplayOrientation(rotation); 
} 

public static int getRotationAngle(int screenRotation, int cameraId) { 
    Camera.CameraInfo info = new Camera.CameraInfo(); 
    android.hardware.Camera.getCameraInfo(cameraId, info); 
    int degrees = 0; 
    switch (screenRotation) { 
     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; 
    } 
    return result; 
} 

我希望這能解決問題,但開始寫之前,請確保您閱讀我提供明白爲什麼這個問題發生的環節。希望這會爲你解決它。