如何正确匹配Android Camera Preview?

时间:2015-06-22 15:38:21

标签: android camera android-camera screen-orientation preview

我正在尝试打开相机预览的应用程序,通过按钮,用户可以录制视频。该应用程序被认为有两个方向:肖像和风景。为此,我使用了以下代码:

CameraPreview

package com.recomovie.app;

import java.io.IOException;
import java.util.List;

import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.Size;
import android.view.Display;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.WindowManager;

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

private static final String TAG = "CameraPreview";

private Context mContext;
private SurfaceHolder mHolder;
private Camera mCamera;
private List<Camera.Size> mSupportedPreviewSizes;
private Camera.Size mPreviewSize;

public CameraPreview(Context context, Camera camera) {
    super(context);
    mContext = context;
    mCamera = camera;

    // supported preview sizes
    mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
    for(Camera.Size str: mSupportedPreviewSizes)

    // 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) {
    // empty. surfaceChanged will take care of stuff}
}

public void surfaceDestroyed(SurfaceHolder holder) {
    // empty. Take care of releasing the Camera preview in your activity.
}

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
    // start preview with new settings
    try {
        Camera.Parameters parameters = mCamera.getParameters();
        //parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        //mCamera.setDisplayOrientation(90);
        Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

        if(display.getRotation() == Surface.ROTATION_0)
        {
            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);                     
            mCamera.setDisplayOrientation(90);
        }
        if(display.getRotation() == Surface.ROTATION_90)
        {  
            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);     
            mCamera.setDisplayOrientation(0);       
        }

        if(display.getRotation() == Surface.ROTATION_180)
        {       
            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);       
        }

        if(display.getRotation() == Surface.ROTATION_270)
        {    
            parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
            mCamera.setDisplayOrientation(180);      
        }
        mCamera.setParameters(parameters);
        mCamera.setPreviewDisplay(mHolder);
        mCamera.startPreview();

    } catch (Exception e){
    }
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
    final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    if (height > width ) {
        setMeasuredDimension(width, height);
        if (mSupportedPreviewSizes != null) {
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }

        float ratio;
        if(mPreviewSize.height >= mPreviewSize.width)
            ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;
        else
            ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;

        float camHeight = (int) (width * ratio);
        float newCamHeight;
        float newHeightRatio;

        if (camHeight < height) {
            newHeightRatio = (float) height / (float) mPreviewSize.height;
            newCamHeight = (newHeightRatio * camHeight);
            setMeasuredDimension((int) (width * newHeightRatio), (int) newCamHeight);
        } else {
            newCamHeight = camHeight;
            setMeasuredDimension(width, (int) newCamHeight);
        }
    }
    else {
        setMeasuredDimension(width, height);
        if (mSupportedPreviewSizes != null) {
            mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
        }

        float ratio;
        if(mPreviewSize.width >= mPreviewSize.height)
            ratio = (float) mPreviewSize.width / (float) mPreviewSize.height;
        else
            ratio = (float) mPreviewSize.height / (float) mPreviewSize.width;

        float camWidth = (int) (height * ratio);
        float newCamWidth;
        float newWidthRatio;

        if (camWidth < width) {
            newWidthRatio = (float) width / (float) mPreviewSize.width;
            newCamWidth = (newWidthRatio * camWidth);
            setMeasuredDimension( (int) newCamWidth,(int) (height * newWidthRatio));
        } else {
            newCamWidth = camWidth;
            setMeasuredDimension((int) newCamWidth,height);
        }
    }

}

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.height / size.width;
        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;
}
}

CameraFragment

package com.recomovie.app;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.Thread.UncaughtExceptionHandler;
import java.text.SimpleDateFormat;
import java.util.Date;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.Display;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;

public class FragCamera extends Fragment{
    private Camera mCamera;
    private CameraPreview mPreview;
    private MediaRecorder mMediaRecorder;
    private boolean isRecording = false;

        /** Called when the activity is first created. */
    private Context context;
    private Activity act;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        context = getActivity().getApplicationContext();
        act = this.getActivity();
        View visor = inflater.inflate(R.layout.camera, container, false);
        // Create an instance of Camera
        if (checkCameraHardware(context)) {
            mCamera = getCameraInstance();
        }
        // Create our Preview view and set it as the content of our activity.
        mPreview = new CameraPreview(context, mCamera);
        FrameLayout preview = (FrameLayout) visor.findViewById(R.id.camera_preview);
        preview.addView(mPreview);
         //   List<Size> sizes = parameters.getSupportedPreviewSizes();
          //  Size optimalSize = getOptimalPreviewSize(sizes, width, height);
           // parameters.setPreviewSize(optimalSize.width, optimalSize.height);
            Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();

            if(display.getRotation() == Surface.ROTATION_0)
            {               LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) preview.getLayoutParams();

                //params.setMargins(0, -218, 0, 0);
                //preview.setLayoutParams(new FrameLayout.LayoutParams(300, 49));
                preview.setLayoutParams(params);

            }

            if(display.getRotation() == Surface.ROTATION_90)
            {           
                LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) preview.getLayoutParams();

                //params.setMargins(0, -218, 0, 0);
                //preview.setLayoutParams(new FrameLayout.LayoutParams(300, 49));params.setMargins(0, -218, 0, 0);
                preview.setLayoutParams(params);               
            }

            if(display.getRotation() == Surface.ROTATION_180)
            {           LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) preview.getLayoutParams();

                //params.setMargins(0, -218, 0, 0);
                //preview.setLayoutParams(new FrameLayout.LayoutParams(300, 49));
                preview.setLayoutParams(params);            
            }

            if(display.getRotation() == Surface.ROTATION_270)
            {           LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) preview.getLayoutParams();

                //params.setMargins(0, -218, 0, 0);
                //preview.setLayoutParams(new FrameLayout.LayoutParams(300, 49));
                preview.setLayoutParams(params);
            }

        final ImageButton captureButton = (ImageButton) visor.findViewById(R.id.button_capture2);


         // Add a listener to the Capture button
         captureButton.setOnClickListener(
             new View.OnClickListener() {
                 public void onClick(View v) {
                     if (isRecording) {
                         // stop recording and release camera
                         mMediaRecorder.stop();  // stop the recording
                         releaseMediaRecorder(); // release the MediaRecorder object
                         mCamera.lock();         // take camera access back from MediaRecorder

                         // inform the user that recording has stopped
                         //captureButton.setText("Record Video");
                         isRecording = false;
                     } else {
                         // initialize video camera
                         if (prepareVideoRecorder()) {
                             // Camera is available and unlocked, MediaRecorder is prepared,
                             // now you can start recording
                             mMediaRecorder.start();

                             // inform the user that recording has started
                             //captureButton.setText("Stop");
                             isRecording = true;
                         } else {
                             // prepare didn't work, release the camera
                             releaseMediaRecorder();
                             // inform user
                         }
                     }
                 }
             }
         );
         return visor;
    }

    /** Check if this device has a camera */
    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            // this device has a camera
            return true;
        } else {
            // no camera on this device
            return false;
        }
    }

    /** A safe way to get an instance of the Camera object. */
    public static Camera getCameraInstance(){
        Camera c = null;
        try {
            c = Camera.open(); // attempt to get a Camera instance
        }
        catch (Exception e){
            // Camera is not available (in use or does not exist)
        }
        return c; // returns null if camera is unavailable
    }

    private boolean prepareVideoRecorder(){

        //mCamera = getCameraInstance();
        mMediaRecorder = new MediaRecorder();

        // Step 1: Unlock and set camera to MediaRecorder
        mCamera.unlock();
        mMediaRecorder.setCamera(mCamera);

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

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

        // Step 4: Set output file
        mMediaRecorder.setOutputFile(getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());

        // Step 5: Set the preview output
        mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());

        // Step 6: Prepare configured MediaRecorder
        try {
            mMediaRecorder.prepare();
        } catch (IllegalStateException e) {
            releaseMediaRecorder();
            return false;
        } catch (IOException e) {
            releaseMediaRecorder();
            return false;
        }
        return true;
    }

    @Override
    public void onPause() {
        super.onPause();    
        if (mCamera != null) {         
            mCamera.stopPreview(); 
            mCamera.setPreviewCallback(null);
            mPreview.getHolder().removeCallback(mPreview);
            mCamera.release();
            mCamera = null;
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        try
        {
            if (mCamera==null  ) {
                context = getActivity().getApplicationContext();
                act = this.getActivity();
                //act.setContentView(R.layout.camera);
                mCamera = getCameraInstance();
                //mCamera.setPreviewCallback(null);
                mPreview = new CameraPreview(context, mCamera);//set preview
                FrameLayout preview = (FrameLayout) this.act.findViewById(R.id.camera_preview);
                preview.addView(mPreview);
            }

        } catch (Exception e){
        }
    }   



    private void releaseMediaRecorder(){
        if (mMediaRecorder != null) {
            mMediaRecorder.reset();   // clear recorder configuration
            mMediaRecorder.release(); // release the recorder object
            mMediaRecorder = null;
            mCamera.lock();           // lock camera for later use
        }
    }


    public static final int MEDIA_TYPE_IMAGE = 1;
    public static final int MEDIA_TYPE_VIDEO = 2;

    /** Create a file Uri for saving an image or video */
    private static Uri getOutputMediaFileUri(int type){
        return Uri.fromFile(getOutputMediaFile(type));
    }

    /** Create a File for saving an image or video */
    private static File getOutputMediaFile(int type){
        // To be safe, you should check that the SDCard is mounted
        // using Environment.getExternalStorageState() before doing this.

        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                  Environment.DIRECTORY_MOVIES), "MyCameraApp");
        // This location works best if you want the created images to be shared
        // between applications and persist after your app has been uninstalled.

        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                Log.d("MyCameraApp", "failed to create directory");
                return null;
            }
        }

        // Create a media file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File mediaFile;
        if (type == MEDIA_TYPE_IMAGE){
            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
            "IMG_"+ timeStamp + ".jpg");
        } else if(type == MEDIA_TYPE_VIDEO) {
            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
            "VID_"+ timeStamp + ".mp4");
        } else {
            return null;
        }

        return mediaFile;
    }

}

CameraFragment XML

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >    

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >  
    <FrameLayout
        android:id="@+id/camera_preview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </FrameLayout>
    </LinearLayout>
    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/rect169bueno"
    android:orientation="vertical" >    
        <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="horizontal" >


    </LinearLayout>

            <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="horizontal" >

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="horizontal" >

        </LinearLayout>

        <RelativeLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="horizontal" >
    <ImageButton
        android:id="@+id/button_capture2"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_centerHorizontal="true"
                    android:adjustViewBounds="true"
                    android:scaleType="matrix" >
    </ImageButton>
    <ImageView
                    android:id="@+id/imageView1"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_centerVertical="true"
                    android:layout_centerHorizontal="true"
                    android:adjustViewBounds="true"
                    android:scaleType="fitCenter"
                    android:src="@drawable/infoimage" />
        </RelativeLayout>

        <LinearLayout
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="horizontal" >
        </LinearLayout>

    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:orientation="horizontal" >

    </LinearLayout>
</LinearLayout>
</FrameLayout>

在我的手机中,该应用效果很好,您可以在以下屏幕中看到: Portrait Landscape

但是,我曾在其他手机上尝试过:

  • 在其中,预览中显示的宽高比是正确的,但预览有很多缩放。

  • 在其他情况下,宽高比是正确的,但预览与整个屏幕不匹配。

  • 在其他情况下,单击“录制”按钮时,宽高比会发生变化,然后预览的宽高比不正确(但视频会以良好的宽高比保存)。

    < / LI>

有人可以帮帮我吗?我不明白为什么这些问题在其他设备上完成。

0 个答案:

没有答案