Android使用前置摄像头拍照

7

这是我第一次使用相机。我已经阅读了很多示例和文档,所以尝试编写自己的类来使用前置摄像头拍照。

以下是我的代码:

    public class CameraController {

private Context context;

private boolean hasCamera;

private Camera camera;
private int cameraId;

public CameraController(Context c){
    context = c.getApplicationContext();

    if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
        cameraId = getFrontCameraId();

        if(cameraId != -1){
            hasCamera = true;
        }else{
            hasCamera = false;
        }
    }else{
        hasCamera = false;
    }
}

public boolean hasCamera(){
    return hasCamera;
}

public void getCameraInstance(){
    camera = null;

    if(hasCamera){
        try{
            camera = Camera.open(cameraId);
        }
        catch(Exception e){

        }
    }
}

public void takePicture(){
    if(hasCamera){
        camera.takePicture(null,null,mPicture);
    }
}

public void releaseCamera(){
    if(camera != null){
        camera.release();
        camera = null;
    }
}

private int getFrontCameraId(){
    int camId = -1;
    int numberOfCameras = Camera.getNumberOfCameras();
    CameraInfo ci = new CameraInfo();

    for(int i = 0;i < numberOfCameras;i++){
        Camera.getCameraInfo(i,ci);
        if(ci.facing == CameraInfo.CAMERA_FACING_FRONT){
            camId = i;
        }
    }

    return camId;
}

private PictureCallback mPicture = new PictureCallback(){
    @Override
    public void onPictureTaken(byte[] data, Camera camera){
        File pictureFile = getOutputMediaFile();

        if(pictureFile == null){
            Log.d("TEST", "Error creating media file, check storage permissions");
            return;
        }

        try{
            FileOutputStream fos = new FileOutputStream(pictureFile);
            fos.write(data);
            fos.close();
        }catch(FileNotFoundException e){
            Log.d("TEST","File not found: "+e.getMessage());
        } catch (IOException e){
            Log.d("TEST","Error accessing file: "+e.getMessage());
        }
    }
};

private  File getOutputMediaFile(){
    // 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_PICTURES),"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()){
            return null;
        }
    }

    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());

    File mediaFile;
    mediaFile = new File(mediaStorageDir.getPath()+File.separator+"IMG_"+timeStamp+".jpg");

    return mediaFile;
}
}

看起来这个类没问题,但我无法从中获取任何图片。 在LogCat中我得到了以下信息:

03-11 19:23:58.556: D/TEST(18655): SNAPSHOT GO!
03-11 19:23:58.556: I/caladbolg(272): 2752686164 cald_client.c                      (464) 24404 I [INF] + Cald_Client_ICamera_GetBufInfo index[0x2]
03-11 19:23:58.556: I/caladbolg(272): 2752687080 cald_client.c                      (487) 24404 I [INF] - Cald_Client_ICamera_GetBufInfo (0)
03-11 19:23:58.556: I/caladbolg(272): 2752687355 cald_client.c                      (464) 24404 I [INF] + Cald_Client_ICamera_GetBufInfo index[0x3]
03-11 19:23:58.566: I/caladbolg(272): 2752688057 cald_client.c                      (487) 24404 I [INF] - Cald_Client_ICamera_GetBufInfo (0)
03-11 19:23:58.566: I/caladbolg(272): 2752691108 cald_client.c                      (755) 24404 I [INF] + Cald_Client_ICamera_EnableThumbnail 
03-11 19:23:58.566: I/caladbolg(272): 2752691749 cald_client.c                      (772) 24404 I [INF] pBufNum[1]
03-11 19:23:58.566: I/caladbolg(272): 2752692024 cald_client.c                      (778) 24404 I [INF] pBuf[0]:0x4311b000
03-11 19:23:58.566: I/caladbolg(272): 2752692817 cald_client.c                      (792) 24404 I [INF] - Cald_Client_ICamera_EnableThumbnail (0)
03-11 19:23:58.566: I/caladbolg(272): 2752693519 cald_client.c                      (832) 24404 I [INF] + Cald_Client_ICamera_TakeSnapshot 
03-11 19:23:58.566: I/caladbolg(272): 2752693763 cald_client.c                      (849) 24404 I [INF] pBufNum[1]
03-11 19:23:58.566: I/caladbolg(272): 2752694007 cald_client.c                      (855) 24404 I [INF] pBuf[0]:0x4ad01000
03-11 19:23:58.566: I/caladbolg(272): 2752694831 cald_camctrl.c                    (6197) 20324 P [PFM] 2752694831 Cald_CamCtrl_ICamera_TakeSnapshot
03-11 19:23:58.566: E/caladbolg(272): 2752695137 cald_camctrl.c                   (19650) 20324 E [CAM] Error: The event is not ready in the current state.
03-11 19:23:58.566: E/libcamera(272): receivePictureDone: unnecessary callback was received.
03-11 19:23:58.566: I/caladbolg(272): 2752696205 cald_client.c                      (869) 24404 I [INF] - Cald_Client_ICamera_TakeSnapshot (0)
2个回答

10

我解决了这个问题。在阅读其他帖子和教程之后,似乎相机需要一个“虚拟”的表面来预览,即使我们不想显示预览。

以下是我的最终代码,如果有人需要的话,请注意,通过“hasCamera”,我指的是前置摄像头:

   public class CameraController {

    private Context context;

    private boolean hasCamera;

    private Camera camera;
    private int cameraId;

    public CameraController(Context c){
        context = c.getApplicationContext();

        if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
            cameraId = getFrontCameraId();

            if(cameraId != -1){
                hasCamera = true;
            }else{
                hasCamera = false;
            }
        }else{
            hasCamera = false;
        }
    }

    public boolean hasCamera(){
        return hasCamera;
    }

    public void getCameraInstance(){
        camera = null;

        if(hasCamera){
            try{
                camera = Camera.open(cameraId);
                prepareCamera();
            }
            catch(Exception e){
                hasCamera = false;
            }
        }
    }

    public void takePicture(){
        if(hasCamera){
            camera.takePicture(null,null,mPicture);
        }
    }

    public void releaseCamera(){
        if(camera != null){
            camera.stopPreview();
            camera.release();
            camera = null;
        }
    }

    private int getFrontCameraId(){
        int camId = -1;
        int numberOfCameras = Camera.getNumberOfCameras();
        CameraInfo ci = new CameraInfo();

        for(int i = 0;i < numberOfCameras;i++){
            Camera.getCameraInfo(i,ci);
            if(ci.facing == CameraInfo.CAMERA_FACING_FRONT){
                camId = i;
            }
        }

        return camId;
    }

    private void prepareCamera(){
        SurfaceView view = new SurfaceView(context);

        try{
            camera.setPreviewDisplay(view.getHolder());
        }catch(IOException e){
            throw new RuntimeException(e);
        }

        camera.startPreview();

        Camera.Parameters params = camera.getParameters();
        params.setJpegQuality(100);

        camera.setParameters(params);  
    }

    private PictureCallback mPicture = new PictureCallback(){
        @Override
        public void onPictureTaken(byte[] data, Camera camera){
            File pictureFile = getOutputMediaFile();

            if(pictureFile == null){
                Log.d("TEST", "Error creating media file, check storage permissions");
                return;
            }

            try{
                Log.d("TEST","File created");
                FileOutputStream fos = new FileOutputStream(pictureFile);
                fos.write(data);
                fos.close();
            }catch(FileNotFoundException e){
                Log.d("TEST","File not found: "+e.getMessage());
            } catch (IOException e){
                Log.d("TEST","Error accessing file: "+e.getMessage());
            }
        }
    };

    private File getOutputMediaFile(){
        // 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_PICTURES),"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()){
                return null;
            }
        }

        // Create a media file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());

        File mediaFile;
        mediaFile = new File(mediaStorageDir.getPath()+File.separator+"IMG_"+timeStamp+".jpg");

        return mediaFile;
    }
}

1
请问您能指导我如何使用这个吗? - WISHY
1
我该如何在我的应用程序中使用它?如果我在我的应用程序中调用任何方法,它会显示“Surface为空”,该如何解决这个问题。 - Hanuman
代码运行完美,但您需要通过以下方式编辑CameraInfo: Camera.CameraInfo ci = new Camera.CameraInfo(); - Sofien Rahmouni
2
我正在使用这段代码,但是出现了错误“应用程序传递了空表面错误1001”。 - Mukesh
1
@Androiderson 我声明了一个你的类的变量,然后我使用了 "getCameraInstance",最后我调用了 "takePicture"。当应用程序运行 "takePicture" 时,应用程序崩溃并显示此错误 "RuntimeException: takePicture failed"。你能帮我吗? - Sergio Antonio Snchez Camarero
@SergioAntonioSnchezCamarero 请为相机和存储实现运行时权限。这样就可以工作了。 - Nikhil Pawar

0

那个例子使用了相机意图,所以我认为它会打开默认的相机活动。我只需要在用户不知情的情况下拍照。 - Juan Bentel
那会很糟糕,因为这可能被视为间谍行为而从应用商店中删除。 - ElectronicGeek
不,你没明白哈哈。这是一个玩笑应用程序,它会在你不知道的时候拍下你的照片,然后稍后向你展示。无论如何,相机权限已经声明,以便用户知道该应用程序可以使用它。 - Juan Bentel

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