2014-02-28 33 views
2

我在Android應用程序中遇到MediaRecorder長寬比問題。我專門針對三星Galaxy S II的問題,相比普通相機,其視頻相機的放大倍數更高(這是我在使用手機上的默認相機應用程序時注意到的行爲)。Android MediaRecorder寬高比不正確

你可以看到,當我從使用相機此視頻中使用MediaRecorder切換長寬比如何拉伸:

https://www.youtube.com/watch?v=U8vCwiNjCPU

,並在下面的截圖:

照相機方面比例(正確):

Camera aspect ratio

視頻寬高比(不正確):

Video aspect ratio

我怎樣才能確保視頻預覽的寬高比是正確的?

這裏是我的代碼:

CustomCamera活動:

public class CustomCamera extends SherlockActivity { 

private boolean prepareVideoRecorder() { 
     Log.d(TAG, "in prepareVideoRecorder()"); 
     // It is very important to unlock the camera before doing setCamera 
     // or it will results in a black preview 
     if (camera == null) 
     { 
      camera = getCameraInstance(); 
     } 

     if (recorder == null){ 
      recorder = new MediaRecorder(); 
     } 

     //Have to stop preview before starting to record 
     camera.stopPreview(); 
     // Step 1: Unlock and set camera to MediaRecorder 
     camera.unlock(); 
     recorder.setCamera(camera); 

     // Step 2: Set sources 
     recorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER); 
     recorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); 

     // Step 3: Set a CamcorderProfile (requires API Level 8 or higher) 
     recorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); 

     // Step 4: Set output file 
     recorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).getAbsolutePath()); 

     // No limit. Don't forget to check the space on disk. 
     recorder.setMaxDuration(50000); 
     recorder.setVideoFrameRate(30); 
     recorder.setVideoEncodingBitRate(3000000); 
     recorder.setAudioEncodingBitRate(8000); 

     // Step 5: Set the preview output 
     recorder.setPreviewDisplay(cameraPreview.getHolder().getSurface()); 

     //Setting the camera's orientation 
     int degree = 0; 
     // do not rotate image, just put rotation info in 
     switch (mOrientation) { 
     case ORIENTATION_LANDSCAPE_INVERTED: 
      degree = 180; 
      break; 
     case ORIENTATION_PORTRAIT_NORMAL: 
      degree = 90; 
      break; 
     case ORIENTATION_LANDSCAPE_NORMAL: 
      degree = 0; 
      break; 
     case ORIENTATION_PORTRAIT_INVERTED: 
      degree = 270; 
      break; 
     } 

     recorder.setOrientationHint(degree); 

     // Step 6: Prepare configured MediaRecorder 
     try { 
      recorder.prepare(); 
     } catch (IllegalStateException e) { 
      // This is thrown if the previous calls are not called with the 
      // proper order 
      e.printStackTrace(); 
      releaseMediaRecorder(); 
      return false; 
     } catch (IOException e) { 
      releaseMediaRecorder(); 
      e.printStackTrace(); 
      return false; 
     }   
     //Everything went successfully 
     return true; 
    } 


} 

    /** 
    * Method used to set the camera preview's parameters to match the 
    * phone's width and set the height accordingly to assure that there are 
    * no aspect ratio issues. 
    */ 
    private void setHolderParameters() { 
     Log.d(TAG, "setting camera layout parameters"); 
     DisplayMetrics metrics = new DisplayMetrics(); 
     getWindowManager().getDefaultDisplay().getMetrics(metrics); 

     int height = metrics.heightPixels; 
     int width = metrics.widthPixels; 

     Size mPreviewSize = CameraPreview.getOptimalPreviewSize(camera.getParameters().getSupportedPreviewSizes(), width, height); 
     double ratio = ((double)mPreviewSize.width)/mPreviewSize.height; 

     FrameLayout.LayoutParams previewParams = new FrameLayout.LayoutParams(width, (int)(width*ratio)); 

     cameraPreview.setLayoutParams(previewParams);  
    } 

    /** 
    * Open the camera asynchronously to reduce the lag when opening 
    * activity 
    */ 
    public void openCameraAsync(){ 
     new AsyncTask<Object, Object, Object>(){ 
      @Override 
      protected Object doInBackground(Object... arg0) { 
       if (!isFinishing()){ 
        //Resuming camera and display when resuming 
        if(camera == null){ 
         Log.d(TAG, "Resuming with a null camera"); 
         camera = getCameraInstance(); 
        } 
       } 
       return null; 
      } 

      @Override 
      protected void onPostExecute(Object result){ 
       setHolderParameters(); 
       cameraPreview.setCamera(camera); 

       //Calling surface created so that the preview of the camera is correct 
       cameraPreview.surfaceCreated(cameraPreview.getHolder()); 
      } 
     }.execute(); 
    } 

CameraPreview.java:

public static Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { 
     Log.d(TAG, "getOptimalPreviewSize"); 
     final double ASPECT_TOLERANCE = 0.05; 
     double targetRatio = (double) w/h; 

     if (sizes==null) return null; 

     Size optimalSize = null; 

     double minDiff = Double.MAX_VALUE; 

     int targetHeight = h; 

     // Find 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); 
      } 
     } 

     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); 
       } 
      } 
     } 
     Log.d(TAG, "targetRatio: " + targetRatio); 
     Log.d(TAG, "optimalSize: " + optimalSize); 
     return optimalSize; 
    } 

    public void setRecorder(MediaRecorder recorder){ 
     this.recorder = recorder; 
    } 
+0

你這樣做了嗎? –

+0

你能分享你的經驗嗎 –

+0

你解決了你的問題嗎? – Crash

回答

3

正在設置任何Camera.Parameters?您需要使用setPreviewSize(int width, int height)並將其設置爲視頻的寬度和高度。

在您的MediaRecorder中,您可能還需要使用setVideoSize(int,int)並(再次)設置爲視頻的大小。

我遇到了同樣的問題,爲了獲得視頻的正確高寬比,佈局大小,相機預覽大小和MediaRecorder大小應該具有相同的寬高比。當其中一個關閉時,通常會發生錯誤。

+0

謝謝@ user2743753,它爲我工作。 – JosephM

+0

您可以請發佈適當的解決方案代碼? –

+0

@JosephM請爲此解決方案添加您的代碼..我不知道這將如何工作 –

0

在度量返回的某些手機上,返回的寬度和高度與DisplayMatrics提供的寬度和高度不同,這就是爲什麼當您按下記錄時會縮小或放大圖片的原因。

具體地,這些值:

@Override 
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 
    measuredWidth = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec); 
    measuredHeight = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec); 
     setMeasuredDimension(measuredWidth, measuredHeight); 
     //setMeasuredDimension(mPreviewSize.height, mPreviewSize.width); 
    } 
} 

從表面視圖可以比不同:

public static Camera.Size getDeviceSpecificOptimalPreviewSize(Context context, Camera camera, int w, int h) { 
    List<Camera.Size> mSupportedPreviewSizes = camera.getParameters().getSupportedPreviewSizes(); 
    if (mSupportedPreviewSizes != null) { 
     final double ASPECT_TOLERANCE = 0.1; 
     DisplayMetrics metrics = context.getResources().getDisplayMetrics(); 
     int width = metrics.widthPixels; 
     int height = metrics.heightPixels; 
     double targetRatio = (double) height/width; 

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

     for (Camera.Size size : mSupportedPreviewSizes) { 
      double ratio = (double) size.width/size.height; 
      if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; 
      if (Math.abs(size.height - h) < minDiff) { 
       optimalSize = size; 
       minDiff = Math.abs(size.height - h); 
      } 
     } 

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

這些值返回Camera.Size對象。 mPreviewSize在我的情況。您還需要將它們設置在SurfaceView類中的onSurfaceCreated和onSurfaceChanged方法中的相機對象上。

設置值時要小心,因爲某些電話上的onMeasure按相反順序返回高度和寬度。