【问题标题】:Unable to Switch Front and Back Camera无法切换前后摄像头
【发布时间】:2017-06-17 19:57:30
【问题描述】:

所以我有一个对话,我想按顺序显示前后摄像头预览,比如延迟 2 秒后。问题是,我总是可以为框架设置 1 个相机视图,如何自动动态更改它?

这是我想即时更改的地方:

public class CameraExample extends AnimatedViewContainer {

    private final static String TAG = "CameraExample";

    private Camera mCamera;
    private CameraPreview mPreview;
    private Context mContext;

    public CameraExample(Context context, int i) {
        super(context, i);

        mPreview = null;
        mContext = context;

        initCamera(mContext);

    }

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

    private void initCamera(Context context) {

        // Check if this device has a camera
        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            // no camera on this device
            Log.e(TAG, "CameraExample: " + "this device has no camera");
        } else {
            // this device has a camera
            int numCameras = Camera.getNumberOfCameras();
            if (numCameras >= 0) {
                for (int cameraId = 0; cameraId < numCameras; cameraId++) {
                    mCamera = getCameraInstance(cameraId);
                    if (mCamera != null) {
                        CameraInfo cameraInfo = new CameraInfo();
                        Camera.getCameraInfo(cameraId, cameraInfo);
                        if (cameraInfo.facing == CameraInfo.CAMERA_FACING_FRONT) {
                            try {
                                //Create our Preview view and set it as the content of this LinearLayout View
                                mPreview = new CameraPreview(context, mCamera, cameraId);
                            } catch (RuntimeException e) {
                                Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
                            }
                        }
                        if (createView() == false) {
                            break;
                        }
                    }
                }
            }
        }
    }

    @Override
    public void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index) {
        containerViews[index] = layoutInflater.inflate(R.layout.example_camera, parentGroup, false);
        FrameLayout previewFrame = (FrameLayout) containerViews[index].findViewById(R.id.preview);

        // Add preview for inflation
        previewFrame.addView(mPreview);

    }

    @Override
    public void cleanup() {
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }
}

CameraPreview 类:

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {

        private static final String TAG = "CameraPreview";

        private Context mContext;
        private SurfaceHolder mHolder;
        private Camera mCamera;
        private int mCameraId;

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

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

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.e(TAG, "CameraExample: " + "Error setting camera preview: " + e.getMessage());
        }
    }

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

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 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
        }
    }
}

我在这里设置我的观点:

 @Override
    public void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index) {
        containerViews[index] = layoutInflater.inflate(R.layout.example_camera, parentGroup, false);
        FrameLayout previewFrame = (FrameLayout) containerViews[index].findViewById(R.id.preview);

        previewFrame.addView(mPreview);

    }

问题是,我不知道如何拥有设备通常具有的 2 个不同摄像头的 2 个实例,并在特定秒后自动更改它们,以便我的框架在每次之后一个接一个地显示前后摄像头预览一定的秒数。任何解决方案都非常感谢!我想我必须在surfaceChanged()方法中处理它,但我真的不知道如何!

按照要求,这是AnimatedViewContainer 类:

public abstract class AnimatedViewContainer extends Example {

    Context mContext;
    int mAnimationDuration;
    int mAnimationDurationShort;
    LayoutInflater mLayoutInflater;
    ViewGroup mParentGroup;
    View[] mContainerViews;

    boolean hasBeenClicked = false;

    int mCurrentIndex;
    int mMaxNumItems;
    int mIndexVisibleItem;

    public AnimatedViewContainer(Context context, int maxNumItems) {
        super(context);

        mContext = context;
        mMaxNumItems = maxNumItems;
        mContainerViews = new View[mMaxNumItems];

        // Retrieve and cache the system's default "medium" animation time
        mAnimationDuration = getResources().getInteger(android.R.integer.config_mediumAnimTime);
        // and "short"
        mAnimationDurationShort = getResources().getInteger(android.R.integer.config_shortAnimTime);

        mCurrentIndex = 0;

        mLayoutInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        //TODO: shouldn't be null, should be any ViewGroup with the right LayoutParams
        mParentGroup = null;
    }





    public abstract void onCreateViewContent(LayoutInflater layoutInflater, ViewGroup parentGroup, View[] containerViews, int index);

    public boolean createView() {

        if (mCurrentIndex >= mMaxNumItems) {
            return false; // indicates to terminate the loop
        }


        // handle/execute the concrete definition of the view content defined by the child class
        onCreateViewContent(mLayoutInflater, mParentGroup, mContainerViews, mCurrentIndex);


        // only the first container view should be visible
        if (mCurrentIndex == 0) {
            mContainerViews[mCurrentIndex].setVisibility(View.VISIBLE);
            mIndexVisibleItem = mCurrentIndex;
        } else {
            mContainerViews[mCurrentIndex].setVisibility(View.GONE);
        }


        // if you click on the container view, show next container view with a crossfade animation
        mContainerViews[mCurrentIndex].setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                crossfade(true);
                hasBeenClicked = true;
            }
        });


        // add the container view to the FrameLayout
        addView(mContainerViews[mCurrentIndex]);


        mCurrentIndex++;

        return true;
    }


    public void crossfade(boolean manuallyClicked) {
        //only rotate when example is actually shown and at least one content item was created. This may also prevent NPEs due to incompletely loaded views.
        if(!this.isShown() || mCurrentIndex == 0)
            return;

        //when example was previously clicked, don't do anything
        if(!manuallyClicked && hasBeenClicked){
            hasBeenClicked = false;
            return;
        }

        int numTotalItems = mCurrentIndex;
        final int indexVisibleItem = mIndexVisibleItem;


        int nextIndex = indexVisibleItem + 1;

        if (nextIndex >= numTotalItems) {
            nextIndex = 0;
        }

        final boolean hasOnlyOneItem;
        if (numTotalItems == 1) {
            hasOnlyOneItem = true;
        } else {
            hasOnlyOneItem = false;
        }


        if (hasOnlyOneItem) { //there is only one item in the mContainerViews
            mContainerViews[indexVisibleItem].animate().alpha(0.5f).setDuration(mAnimationDurationShort).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mContainerViews[indexVisibleItem].animate().alpha(1f).setDuration(mAnimationDurationShort).setListener(null);
                }
            });
        } else {
            // Set the next view to 0% opacity but visible, so that it is visible (but fully transparent) during the animation.
            mContainerViews[nextIndex].setAlpha(0f);
            mContainerViews[nextIndex].setVisibility(View.VISIBLE);

            // Animate the next view to 100% opacity, and clear any animation
            // listener set on the view.
            mContainerViews[nextIndex].animate().alpha(1f).setDuration(mAnimationDuration).setListener(null);

            // Animate the current view to 0% opacity. After the animation ends,
            // set its visibility to GONE as an optimization step (it won't participate in layout passes, etc.)
            mContainerViews[indexVisibleItem].animate().alpha(0f).setDuration(mAnimationDuration).setListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    mContainerViews[indexVisibleItem].setVisibility(View.GONE);
                }
            });
        }

        mIndexVisibleItem = nextIndex;
    }

    @Override
    public void cleanup() {

    }

}

【问题讨论】:

  • 您需要自动延迟 2 秒吗?我说的对吗?
  • @AndroidHacker 是的,我完全做不到!这也是我尝试做但失败的事情:stackoverflow.com/questions/44659650/…
  • 好吧..你也愿意使用设备原生相机形式捕获图像吗?
  • @AndroidHacker 不,如果这就是你的意思,我不需要图像捕获功能。预览就好了!
  • 尝试使用 Timer.. 并告诉我。

标签: android camera android-camera


【解决方案1】:

我可以在几秒钟内找到更换相机的解决方案(但请记住,正如 Alex Cohn 所说,您无法在 2 秒内更换相机,因为通常需要 2 秒以上才能开始预览,这取决于设备)通过稍微改变你的代码。请使用下面的代码并检查。

注意:我没有实现任何方向改变和拍照功能,希望你已经开发了这些功能,实际上你只是要求在几秒钟内自动更换相机。

我使用对话框片段在对话框中显示预览。这是CameraExample的代码

import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.support.v4.app.DialogFragment;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

/**
 * Created by Admin on 6/26/2017.
 */

public class CameraExample extends DialogFragment {
    private final static String TAG = "CameraExample";

    private Camera mCamera;
    private CameraPreview mPreview;
    private Context mContext;
    private View view;
    private int mCamId = 0;

    public CameraExample() {

        mPreview = null;
        mContext = getContext();

    }

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

    private void initCamera(Context context, int cameraId) {
        // Check if this device has a camera
        if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            // no camera on this device
            Log.e(TAG, "CameraExample: " + "this device has no camera");
        } else {
            // this device has a camera
            int numCameras = Camera.getNumberOfCameras();
            if (numCameras >= 0) {
                mCamera = getCameraInstance(cameraId);
                if (mCamera != null) {
                    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
                    Camera.getCameraInfo(cameraId, cameraInfo);
                    try {
                        //Create our Preview view and set it as the content of this LinearLayout View
                        mPreview = new CameraPreview(context, mCamera, cameraId);
                        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
                        mPreview.setLayoutParams(layoutParams);
                    } catch (RuntimeException e) {
                        Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
                    }
                }
            }
        }
    }

    private CountDownTimer countDownTimer;

    private void switchCam() {
        //10 seconds
        countDownTimer = new CountDownTimer(10000, 1000) {

            @Override
            public void onTick(long l) {
                System.out.println(l + " left");
            }

            @Override
            public void onFinish() {
                cleanup();
                startCam();
            }
        }.start();

    }


    private void startCam() {

        initCamera(getContext(), mCamId);
        FrameLayout previewFrame = (FrameLayout) view.findViewById(R.id.preview);
        previewFrame.removeAllViews();
        // Add preview for inflation
        previewFrame.addView(mPreview);

        mCamId = mCamId == 0 ? 1 : 0;

        switchCam();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        getDialog().getWindow().setGravity(Gravity.CENTER);
//        getDialog().getWindow().setBackgroundDrawableResource(android.R.color.transparent);


        view = inflater.inflate(R.layout.camera_fragment, container, false);
        startCam();
        return view;
    }

    @Override
    public void onPause() {
        super.onPause();
        cleanup();
        if (countDownTimer != null)
            countDownTimer.cancel();
    }

    @Override
    public void onStart() {
        super.onStart();
        getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    }

    public void cleanup() {
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }
}

而且我还必须更改您的预览课程。代码见下文。

import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import java.io.IOException;

/**
 * Created by Admin on 6/26/2017.
 */

public class CameraPreview  extends SurfaceView implements SurfaceHolder.Callback {

    private static final String TAG = "CameraPreview";

    private Context mContext;
    private SurfaceHolder mHolder;
    private Camera mCamera;
    private int mCameraId;

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

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

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.e(TAG, "CameraExample: " + "Error setting camera preview: " + e.getMessage());
        }
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e) {
            // ignore: tried to stop a non-existent preview
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        // 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;
        }


    }
} 

【讨论】:

  • 非常感谢!我收到此错误:`连接到相机时发生错误:2,无法连接到服务`这我最终改为使用您的代码:pastebin.com/PdcqRfUb
  • @Jeet.Deir 你能把错误日志发给我吗?你能告诉我们这个 AnimatedViewContainer 类是什么吗?
【解决方案2】:

您的课程中有一个双重初始化错误。我可以让它运行并看到相机从 0 切换到 1 并在 10 秒后切换回来:

我从 CameraExample 构造函数中删除了对 initCamera() 的调用。相反,我将调用 CreateView()。或者,您可以从创建 new CameraExample(context, i) 的位置调用 CreateView(),这是一个公共方法。

请注意,这是指dropbox 中的代码,而不是问题中发布的内容。

【讨论】:

  • 太棒了!谢谢!
【解决方案3】:

您必须停止摄像头,切换朝向,然后重新启动:

使用计时器并每隔 2 秒定期调用 switchFacing()

但请注意:

此类在 API 级别 21 中已弃用。 我们建议使用新的 android.hardware.camera2 API 应用程序。

edit2:这是可以使用的完整类。

//This class uses Camera1 API to be backwards compatible.

private static String TAG = "CameraManager";

private Context mContext = null;
private SurfaceView mPreview = null;
private SurfaceHolder mHolder = null;
private Camera mCamera = null;
private int mFrontFaceID = -1;
private int mBackFaceID = -1;
private int mActualFacingID = -1;

public CameraManager(Context context, SurfaceView preview) {
    mContext = context;
    mPreview = preview;
    mHolder = mPreview.getHolder();
    mHolder.addCallback(this);
}

//called in onCreate
public void init() {
    Camera.CameraInfo info = new Camera.CameraInfo();
    for (int i = 0; i < Camera.getNumberOfCameras(); i++) {
        Camera.getCameraInfo(i, info);
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            mFrontFaceID = i;
        }
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
            mBackFaceID = i;
        }
    }
    if (mActualFacingID == -1) {
        if (mFrontFaceID != -1) {
            mActualFacingID = mFrontFaceID;
        } else {
            mActualFacingID = mBackFaceID;
        }
    }
    //At least one one camera will be available because of manifest declaration
}

//called first on surface created
public void start() {
    Log.i(TAG, "startCamera()");
    if (mCamera == null) {
        mCamera = getCameraInstance(mActualFacingID);
    }
    if (mCamera == null) {
        Log.i(TAG, "can't get camera instance");
        return;
    }
    try {
        mCamera.setPreviewDisplay(mHolder);
    } catch (IOException e) {
        e.printStackTrace();
    }
    setCameraDisplayOrientation();
    setBestSupportedSizes();
    mCamera.startPreview();
}

public void stop() {
    Log.i(TAG, "stopCamera()");
    if (mCamera != null) {
        mCamera.stopPreview();
        mCamera.release();
        mCamera = null;
    }
}

public void switchFacing() {
    if (mFrontFaceID == -1 || mBackFaceID == -1) {
        return;
    }
    stop();
    if (mActualFacingID == mFrontFaceID) {
        mActualFacingID = mBackFaceID;
    } else {
        mActualFacingID = mFrontFaceID;
    }
    start();
}

public Camera getCameraInstance(int cameraID) {
    Camera c = null;
    if (cameraID != -1) {
        try {
            c = Camera.open(cameraID);
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(TAG, "error opening camera: " + cameraID);
        }
    }
    return c;
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    Log.i(TAG, "surfaceCreated()");
    start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    Log.i(TAG, "surfaceChanged()");
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
    Log.i(TAG, "surfaceDestroyed()");
    stop();
}

private void setBestSupportedSizes() {
    if (mCamera == null) {
        return;
    }
    Camera.Parameters parameters = mCamera.getParameters();
    List<Point> pictureSizes=getSortedSizes(parameters.getSupportedPictureSizes());

    List<Point> previewSizes=getSortedSizes(parameters.getSupportedPreviewSizes());

    Point previewResult=null;
    for (Point size:previewSizes){
        float ratio = (float) size.y / size.x;
        if(Math.abs(ratio-4/(float)3)<0.05){ //Aspect ratio of 4/3 because otherwise the image scales to much.
            previewResult=size;
            break;
        }
    }
    Log.i(TAG,"preview: "+previewResult.x+"x"+previewResult.y);
    Point pictureResult=null;
    if(previewResult!=null){
        float previewRatio=(float)previewResult.y/previewResult.x;
        for (Point size:pictureSizes){
            float ratio = (float) size.y / size.x;
            if(Math.abs(previewRatio-ratio)<0.05){
                pictureResult=size;
                break;
            }
        }
    }
    Log.i(TAG,"preview: "+pictureResult.x+"x"+pictureResult.y);

    if(previewResult!=null && pictureResult!=null){
        Log.i(TAG,"best preview: "+previewResult.x+"x"+previewResult.y);
        Log.i(TAG, "best picture: " + pictureResult.x + "x" + pictureResult.y);
        parameters.setPreviewSize(previewResult.y, previewResult.x);
        parameters.setPictureSize(pictureResult.y, pictureResult.x);
        mCamera.setParameters(parameters);
        mPreview.setBackgroundColor(Color.TRANSPARENT); //in the case of errors needed
    }else{
        mCamera.stopPreview();
        mPreview.setBackgroundColor(Color.BLACK);
    }
}

private List<Point> getSortedSizes(List<Camera.Size> sizes) {
    ArrayList<Point> list = new ArrayList<>();

    for (Camera.Size size : sizes) {
        int height;
        int width;
        if (size.width > size.height) {
            height = size.width;
            width = size.height;
        } else {
            height = size.height;
            width = size.width;
        }
        list.add(new Point(width, height));

    }

    Collections.sort(list, new Comparator<Point>() {
        @Override
        public int compare(Point lhs, Point rhs) {
            long lhsCount = lhs.x * (long) lhs.y;
            long rhsCount = rhs.x * (long) rhs.y;
            if (lhsCount < rhsCount) {
                return 1;
            }
            if (lhsCount > rhsCount) {
                return -1;
            }
            return 0;
        }
    });
    return list;
}

//TAKE PICTURE
public void takePhoto() {
    if (mCamera != null) {
        mCamera.takePicture(null, null, this);
    }
}

@Override
public void onPictureTaken(byte[] data, Camera camera) {
    //do something with your picture
}

//ROTATION
private void setCameraDisplayOrientation() {
    if (mCamera != null) {
        mCamera.setDisplayOrientation(getRotation());
    }
}

public int getRotation() {
    Camera.CameraInfo info = new Camera.CameraInfo();
    Camera.getCameraInfo(mActualFacingID, info);
    int rotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
            .getRotation();
    int degrees = 0;
    switch (rotation) {
        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;
}

在一些类调用中:

SurfaceView preview = (SurfaceView) findViewById(R.id.surfaceView);
CameraManager mgr = new CameraManager(MainActivity.this, MainActivity.this, preview);
mgr.init();
...
mgr.takePhoto(); //surface must already be created 
mgr.switchFacing();
mgr.takePhoto();

此代码应支持几乎所有设备。最受支持的纵横比是 4:3,代码会处理这个问题。

edit3:surface view must be in the xml of course

<SurfaceView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/surfaceView" />

【讨论】:

  • 您能否参考我发布的实际代码而不是您所做的通用答案来展示这一点?
  • mActualFacingID 是一个定义为成员变量的整数。此 id 标识相机(正面或背面)您不能同时拥有两个实例,因此您必须停止一切,使用 id 获取正确的相机并重新开始一切。我编辑了我的问题,向您展示如何获取这些 ID。
  • 我会试试看,如果成功的话,我会奖励你!
  • 我再次编辑了答案,向您展示了完整的课程。
  • 为什么会被否决?这正是您需要做的。我建议对相机开关使用处理程序,以确保您的更改是同步的。
【解决方案4】:

没有办法快速切换相机。停止相机、关闭相机、打开另一个相机和开始预览所需的时间取决于设备,但在许多情况下(有时在功能强大的现代设备上),您设定的目标将超过 2 秒。

另一方面,一些 Android 设备支持同时操作两个摄像头,请参阅 Is it possible to use front and back Camera at same time in AndroidAndroid, Open Front and Back Cameras Simultaneously。因此,在某些基于 Snapdragon 801 的设备上,您可以让两个摄像头都“准备就绪”,并将视频流切换到每秒 30 次。

【讨论】:

  • 我用 2 秒没问题,但它怎么回答这个问题呢?
  • 让我更好地理解您的要求:您希望在屏幕上看到 2 秒的前置摄像头预览;摄像头切换到后置时出现黑屏; 2秒后预览;等等。?或者重要的是在前一张照片后 4 秒内再次获得一张正面照片,背面也一样?
【解决方案5】:

我认为你应该使用这个

mCamera= Camera.open(cameraId);

CAMERA_FACING_BACK 为 0

CAMERA_FACING_FRONT 1 个

更多参考流程如下:-

https://developer.android.com/reference/android/hardware/Camera.html#open(int)

https://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#CAMERA_FACING_BACK

【讨论】:

【解决方案6】:

我们可以使用线程来保持一台摄像机处于活动状态并让它保持一段时间。交换相机并重复相同的无限时间。

private boolean isActive;

public void onStart(){
    super.onStart();
    isActive = true;
    continuousCameraChange(your_camera)
}

public void onResume(){
    super.onResume();
    isActive = true;
    continuousCameraChange(your_camera)
}

public void onPause(){
    super.onPause();
    isActive = false;
}


public void onDestroy(){
    super.onDestroy();
    isActive = false;
}


public void onStop(){
    super.onStop();
    isActive = false;
}

private void continuousCameraChange(Camera camera){
    do{
        switchCamera(camera);
    }while(isActive);
}

private void switchCamera(Camera camera){
    if (Camera.CameraInfo.facing == CAMERA_FACING_BACK){
        try{
            Thread.sleep(2000);
            camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
        }catch(InterruptedException ex){
            Thread.currentThread().interrupt();
        }
        //change your camera
        Camera.CameraInfo.facing == CAMERA_FACING_FRONT;
    }else{
        try{//change 2000 to change the time for which your camera stays available
            Thread.sleep(2000);
            camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);
        }catch(InterruptedException ex){
            Thread.currentThread().interrupt();
        }
        //change your camera
        Camera.CameraInfo.facing == CAMERA_FACING_BACK;
    }
}

【讨论】:

    【解决方案7】:

    我猜这就是你要找的东西:

    ImageButton useOtherCamera = (ImageButton) findViewById(R.id.useOtherCamera);
    //if phone has only one camera, hide "switch camera" button
    if(Camera.getNumberOfCameras() == 1){
    useOtherCamera.setVisibility(View.INVISIBLE);
    }
    else {
    useOtherCamera.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
    if (inPreview) {
        camera.stopPreview();
    }
    //NB: if you don't release the current camera before switching, you app will crash
    camera.release();
    
    //swap the id of the camera to be used
    if(currentCameraId == Camera.CameraInfo.CAMERA_FACING_BACK){
        currentCameraId = Camera.CameraInfo.CAMERA_FACING_FRONT;
    }
    else {
        currentCameraId = Camera.CameraInfo.CAMERA_FACING_BACK;
    }
    camera = Camera.open(currentCameraId);
    //Code snippet for this method from somewhere on android developers, i forget where
    setCameraDisplayOrientation(CameraActivity.this, currentCameraId, camera);
    try {
        //this step is critical or preview on new camera will no know where to render to
        camera.setPreviewDisplay(previewHolder);
    } catch (IOException e) {
        e.printStackTrace();
    }
    camera.startPreview();
    }
    

    这是一个示例代码,我在其中即时在前后摄像头之间切换。希望它会有所帮助。

    【讨论】:

    • 请注意,用于 Camera.open() 的相机 ID 不是为 Camera.CameraInfo 定义的值之一。您应该使用Camera.CameraInfo.facing() 方法检查每个相机 ID 在 0 ... getNumberOfCameras() -1 范围内的朝向
    • 能否请您定义使用相机 ID 的任何缺点?这样我就可以防止使用它。因为它适用于相机 ID。
    • Google Nexus 平板电脑 (2012) 就是一个例子,它有一个前置摄像头。它的 ID 为 0。
    • 谢谢@AlexCohn,我会处理的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多