Android using front facing camera to take a pictur

2019-03-10 20:09发布

问题:

This is my first time using a camera. I've read a lot of examples and also the documentation, so I tried to make my own class to take pictures with the front facing camera.

This is what I came up with:

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

So the class seems to be fine, but I can't get any picture from it. In LogCat I get the following:

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)

回答1:

I solved the problem. After reading some other posts and tutorials seems like that the camera needs a "dummy" surface to preview, even if we don't want the preview to be shown.

Here's my final code in case anyone needs it. Notice that by "hasCamera" I mean a front facing camera:

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


回答2:

Take a look at this question for info and code how to do it: Taking pictures with camera on Android programmatically

The code you used here is not wrong, but this one works.

If you want to take a pic without the user being shown a preview, take a look at this code: https://github.com/aporter/coursera-android/blob/master/Examples/AudioVideoCamera/src/course/examples/AudioVideo/Camera/AudioVideoCameraActivity.java

You need to get rid of the SurfaceView that shows the user the preview.