如何在Android平台上打开“前置摄像头”?

85
更普遍地说,如果一个设备有多个嵌入式摄像头,是否有一种特殊的方式来初始化其中一个摄像头?
我在Android参考文档中没有找到相关信息: 三星SHW-M100S手机有两个摄像头。如果没有任何关于如何使用两个摄像头的参考信息,那么你有什么想法吗?

可能是如何在三星Galaxy S上使用前置摄像头的重复问题。 - Esteban Küber
10个回答

114
private Camera openFrontFacingCameraGingerbread() {
    int cameraCount = 0;
    Camera cam = null;
    Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
    cameraCount = Camera.getNumberOfCameras();
    for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
        Camera.getCameraInfo(camIdx, cameraInfo);
        if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            try {
                cam = Camera.open(camIdx);
            } catch (RuntimeException e) {
                Log.e(TAG, "Camera failed to open: " + e.getLocalizedMessage());
            }
        }
    }

    return cam;
}

请在AndroidManifest.xml文件中添加以下权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.front" android:required="false" />

注意:此功能仅适用于Gingerbread(2.3)及以上版本的Android系统。


有没有可能将这个与“Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);”技术结合起来,以打开现有的相机应用程序? - loeschg
3
Intent以其自己的方式处理相机操作。当您使用SurfaceView来利用相机功能时,就会使用这种技术。 - user456118
我明白了。谢谢! - loeschg
2
非常棒的帖子。我花了一些时间才弄清楚相机面向不一定与相机索引相同。例如,我的平板电脑只有一个相机(索引:0),但是面向前方(面向索引:1)。因此,使用像Camera.open(CameraInfo.CAMERA_FACING_FRONT)这样的简单代码是无意义的。 - Matthias
@Matthias 我同意你的看法。由于我们有不同的OEM厂商,我们的编程技术也会根据我们的需求而改变。感谢你的指出。 - user456118
无法在 Android 的 Pie 或 Oreo 更新版本上工作。 - civani mahida

14

所有旧的答案方法都已被Google弃用(据说是因为像这样的麻烦),自API 21起,您需要使用相机2 API:

此类已于API级别21中过时。我们建议新应用程序使用新android.hardware.camera2 API。

较新的API中,您几乎可以完全控制Android设备相机,并且文档明确建议如下:

String[] getCameraIdList()

然后使用获得的CameraId打开相机:

void openCamera(String cameraId, CameraDevice.StateCallback callback, Handler handler)

前置摄像头99%的ID为"1",后置摄像头ID为"0",根据以下内容:

不可拆卸的相机使用从0开始的整数作为其标识符,而可拆卸的相机则对每个单独的设备具有唯一的标识符,即使它们是相同的型号。

然而,这意味着如果设备情况很少,比如只有一个前置摄像头的平板电脑,您需要计算您有多少内置摄像头,并按其重要性(“0”)排序。因此,CAMERA_FACING_FRONT == 1 CAMERA_FACING_BACK == 0,这意味着后置摄像头比前置摄像头更重要

我不知道在所有Android设备上识别前置摄像头的统一方法。简单地说,设备内部的Android操作系统可能由于某些原因无法确定哪个摄像头位于何处:可能唯一的硬编码ID是表示其重要性的整数,也可能在某些设备上,你转身的任何一面都是.. "后置"。

文档: https://developer.android.com/reference/android/hardware/camera2/package-summary.html

明确的例子: https://github.com/googlesamples/android-Camera2Basic


对于旧的API(不建议使用,因为它不能在新的Android版本上工作,并且传输起来很麻烦)。只需像这个答案中一样使用相同的整数CameraID(1)打开前置摄像头即可。

cam = Camera.open(1);
如果您信任 OpenCV 处理相机部分:

内部:


    <org.opencv.android.JavaCameraView
    ../>

使用以下内容来使用前置摄像头:

        opencv:camera_id="1"

10

从Android 2.1版本开始,Android SDK 只支持单个摄像头。未来的Android版本可能会增加支持多个摄像头的功能。


1
这个语句对于Android 2.2也有效吗? - ozmank
2
@ozmank:是的,直到Android 2.3才添加了多摄像头支持。 - CommonsWare

6

打开后置相机:

val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA)

如何打开前置摄像头:

val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
when {
     Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.O -> {
         cameraIntent.putExtra("android.intent.extras.CAMERA_FACING", CameraCharacteristics.LENS_FACING_FRONT)  // Tested on API 24 Android version 7.0(Samsung S6)
     }
     Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> {
         cameraIntent.putExtra("android.intent.extras.CAMERA_FACING", CameraCharacteristics.LENS_FACING_FRONT) // Tested on API 27 Android version 8.0(Nexus 6P)
         cameraIntent.putExtra("android.intent.extra.USE_FRONT_CAMERA", true)
     }
     else -> cameraIntent.putExtra("android.intent.extras.CAMERA_FACING", 1)  // Tested API 21 Android version 5.0.1(Samsung S4)
}
startActivityForResult(cameraIntent, REQUEST_CODE_CAMERA)

我无法使其在API 28及以上版本中正常工作。此外,直接打开前置摄像头在某些设备上不可能(取决于制造商)。


1
你有没有找到解决方案来应对API 28及以上的问题? - Ankit Gupta
对于后置摄像头解决方案无效。 - Kirguduck

4
public void surfaceCreated(SurfaceHolder holder) {
    try {
        mCamera = Camera.open();
        mCamera.setDisplayOrientation(90);
        mCamera.setPreviewDisplay(holder);

        Camera.Parameters p = mCamera.getParameters();
        p.set("camera-id",2);
        mCamera.setParameters(p);   
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

3
在Galaxy S上表现良好,重要的是使用"camera-id"而不是"camera_id"。 - Mahesh
3
不要假设90度旋转能获得正确的竖屏显示方向,因为在许多设备上情况是不同的。 - colintheshots

4

对于API 21(5.0)及更高版本,您可以使用CameraManager API

来处理与相机有关的事务。

try {
    String desiredCameraId = null;
    for(String cameraId : mCameraIDsList) {
        CameraCharacteristics chars =  mCameraManager.getCameraCharacteristics(cameraId);
        List<CameraCharacteristics.Key<?>> keys = chars.getKeys();
        try {
            if(CameraCharacteristics.LENS_FACING_FRONT == chars.get(CameraCharacteristics.LENS_FACING)) {
               // This is the one we want.
               desiredCameraId = cameraId;
               break;
            }
        } catch(IllegalArgumentException e) {
            // This key not implemented, which is a bit of a pain. Either guess - assume the first one
            // is rear, second one is front, or give up.
        }
    }
}

2
随着Android 2.3(姜饼)的发布,现在可以使用android.hardware.Camera类来获取相机数量、有关特定相机的信息以及引用特定的Camera。请查看新的Camera API 这里

1

build.gradle

 dependencies {
       compile 'com.google.android.gms:play-services-vision:9.4.0+'
    }

设置视图

CameraSourcePreview mPreview = (CameraSourcePreview) findViewById(R.id.preview);

GraphicOverlay mGraphicOverlay = (GraphicOverlay) findViewById(R.id.faceOverlay);

CameraSource mCameraSource = new CameraSource.Builder(context, detector)
                            .setRequestedPreviewSize(640, 480)
                            .setFacing(CameraSource.CAMERA_FACING_FRONT)
                            .setRequestedFps(30.0f)
                            .build();

           mPreview.start(mCameraSource, mGraphicOverlay);

0

我发现这个很好用。

fun frontCamera(context: Context): Int {
    val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
    return cameraManager.cameraIdList
        .find { id ->
            cameraManager.getCameraCharacteristics(id)[LENS_FACING] == LENS_FACING_FRONT
        }?.toInt() ?: 0
}

0
Camera camera;   
if (Camera.getNumberOfCameras() >= 2) {

    //if you want to open front facing camera use this line   
    camera = Camera.open(CameraInfo.CAMERA_FACING_FRONT);

    //if you want to use the back facing camera
    camera = Camera.open(CameraInfo.CAMERA_FACING_BACK);                
}

try {
    camera.setPreviewDisplay("your surface holder here");
    camera.startPreview();      
} catch (Exception e) {  
    camera.release();
}

/* 这不是正确的方法,这是针对运行 Android 4.0 或更早版本的旧设备的解决方案。这可以用于测试目的,但不建议用于主要开发。这个解决方案只能被视为临时解决方案。但是这个解决方案已经帮助了很多人,所以我不打算删除这个答案 */


7
我不认为这是正式的用法。open(int id)接受id,而非摄像头位置。 - X.Y.
13
请移除这个误导性的回答。 - Alex Cohn
13
请看@AmalanDhananjayan的评论,举个例子,例如@Matthias上面的评论:…我花了一些时间才明白相机面向不一定与相机索引相同。例如我的平板电脑只有一个相机(索引:0),但面向前方(面向索引:1)。因此,使用像Camera.open(CameraInfo.CAMERA_FACING_FRONT)这样的简单代码是无意义的。 - Alex Cohn
6
这完全是胡说八道。甚至不要尝试使用这个。 - Adam
4
这太可怕了,绝对不要这样做。这个答案应该被禁止。Camera.open()接受相机id,而不是相机朝向的序数值!在大部分设备上会失败,只有侥幸才能起作用。 - colintheshots
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接