Android MediaRecorder 宽高比不正确

标签 android video camera mediarecorder

我的 Android 应用程序中 MediaRecorder 的宽高比存在问题。我在三星 Galaxy S II 上遇到了这个问题,它的视频摄像头似乎比普通摄像头放大了(我在手机上使用默认摄像头应用程序时也注意到了这种情况)。

在此视频中,您可以看到当我从使用相机切换到使用 MediaRecorder 时,宽高比是如何拉伸(stretch)的:

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

在下面的屏幕截图中:

相机宽高比(正确):

Camera aspect ratio

视频宽高比(不正确):

Video aspect ratio

如何确保视频预览的宽高比正确?

这是我的代码:

自定义相机 Activity :

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

最佳答案

正在设置任何 Camera.Parameters ?您需要使用setPreviewSize(int width, int height)并将其设置为视频的宽度和高度。

在您的 MediaRecorder 中,您可能还需要使用setVideoSize(int,int)并(再次)设置为视频的大小。

我遇到了与您相同的问题,为了获得正确的视频宽高比,布局大小、相机预览大小和 MediaRecorder 大小应具有相同的宽高比。当其中一项关闭时,通常会发生错误。

关于Android MediaRecorder 宽高比不正确,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22105251/

相关文章:

php ffmpeg 获取视频时长

html - 背景视频未集中在 Bootstrap 单元中

android - MediaRecorder setVideoSize 在不同设备中显示不同的行为

android - phonegap android 中的 "Camera cancelled"错误

ios - 前后摄像头切换由加速度计决定

android - Intent.action_pick_activity 的功能?

android - 使用 GCM 的 Azure 推送通知

Android回调和监听器的区别

android - Horizo​​ntalScrollView 分页

video - XNA可变音频速度