7

I have create a application in Android that using a camera I can measure out the distance between user's face to the phone screen.

Problem description:

Now I want to make it running background so that the feature is available while I am using other applications. It means I should open camera in service without preview, and process it in service.

What I did yet:

I referred some questions here

How to record video from background of application : Android

How to use Android Camera in Background?

Taking picture from camera without preview

API level 16

My Service File

import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.media.MediaRecorder;
import android.os.IBinder;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.util.List;

public class RecorderService extends Service {
private static final String TAG = "RecorderService";
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private static Camera mServiceCamera;
private boolean mRecordingStatus;
private MediaRecorder mMediaRecorder;
File path = android.os.Environment.getExternalStorageDirectory();


@Override
public void onCreate() {
    Log.i(TAG,"onCreate");
    mRecordingStatus = false;
    //mServiceCamera = CameraRecorder.mCamera;
    mServiceCamera = Camera.open(1);
    mSurfaceView = MainActivity.mSurfaceView;
    mSurfaceHolder = MainActivity.mSurfaceHolder;

    super.onCreate();
    if (mRecordingStatus == false)
        startRecording();
}

@Override
public IBinder onBind(Intent intent) {
    // TODO Auto-generated method stub
    return null;
}

@Override
public void onDestroy() {
    Log.i(TAG,"onDestroy");

    stopRecording();
    mRecordingStatus = false;

    super.onDestroy();
}

public boolean startRecording(){
    Log.i(TAG,"startRecording");

    try {
        Toast.makeText(getBaseContext(), "Recording Started", Toast.LENGTH_SHORT).show();

        //mServiceCamera = Camera.open();
        Camera.Parameters params = mServiceCamera.getParameters();
        mServiceCamera.setParameters(params);
        Camera.Parameters p = mServiceCamera.getParameters();

        final List<Size> listSize = p.getSupportedPreviewSizes();
        Size mPreviewSize = listSize.get(2);
        Log.v(TAG, "use: width = " + mPreviewSize.width
                + " height = " + mPreviewSize.height);
        p.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
        p.setPreviewFormat(PixelFormat.YCbCr_420_SP);
        mServiceCamera.setParameters(p);

        try {
            mServiceCamera.setPreviewDisplay(mSurfaceHolder);
            mServiceCamera.startPreview();
        }
        catch (IOException e) {
            Log.e(TAG, e.getMessage());
            e.printStackTrace();
        }

        mServiceCamera.unlock();

        mMediaRecorder = new MediaRecorder();
        mMediaRecorder.setCamera(mServiceCamera);
        mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
        mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
        mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);
        mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);
        mMediaRecorder.setOutputFile(path+"/outputVideo.mp4");
        mMediaRecorder.setVideoFrameRate(30);
        mMediaRecorder.setVideoSize(mPreviewSize.width, mPreviewSize.height);
        mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

        mMediaRecorder.prepare();
        mMediaRecorder.start();

        mRecordingStatus = true;

        return true;
    } catch (IllegalStateException e) {
        Log.d(TAG, e.getMessage());
        e.printStackTrace();
        return false;
    } catch (IOException e) {
        Log.d(TAG, e.getMessage());
        e.printStackTrace();
        return false;
    }
}

public void stopRecording() {
    Log.i(TAG,"stopRecording");

    Toast.makeText(getBaseContext(), "Recording Stopped", Toast.LENGTH_SHORT).show();
    try {
        mServiceCamera.reconnect();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    try{
        mMediaRecorder.stop();
    }catch (Exception ignored)
    {

    }
    mMediaRecorder.reset();
    mMediaRecorder.release();
    mServiceCamera.stopPreview();
    mServiceCamera.release();
    mServiceCamera = null;
}
}
Community
  • 1
  • 1
Peter Zhu
  • 1,154
  • 3
  • 15
  • 27
  • What's you API level? Have you tried the Camera2 APIs which supported from Android 5.0? – chartsai Mar 19 '15 at 02:56
  • My API level is 21, Camera2 is ok, but I don't know how to use it. Can you give me a explanation? – Peter Zhu Mar 19 '15 at 03:22
  • Check the sample project "Camera2Basic" provided by Android Sdk. – chartsai Mar 19 '15 at 03:26
  • @Chatea But if I use Camera2 API , then I can't run the app on device which API level is 16 or 19? Do you have any ideas? – Peter Zhu Mar 19 '15 at 04:14
  • No, you can't. So you must decide the usage first. I ask this question to clarify which API you use. – chartsai Mar 19 '15 at 04:18
  • I'm Sorry. I had updated my question. So what should I do if I want my app compatible with device which API level 16? – Peter Zhu Mar 19 '15 at 04:26
  • I think you should use Camera(1) API. Or, you can determine the API level in runtime and choice the prefer Camera APIs. – chartsai Mar 19 '15 at 05:56
  • How to solve my problem using Camera(1) API, the main goal is to activate camera in background. – Peter Zhu Mar 19 '15 at 06:03
  • Possible duplicate of [Android SDK: Get raw preview camera image without displaying it](http://stackoverflow.com/questions/10775942/android-sdk-get-raw-preview-camera-image-without-displaying-it) – Eddy Talvala Sep 22 '16 at 20:53

1 Answers1

11

You can refer this Question, which discuss how to do video record in the service. The steps to capture image is same as it.

To achieve your requirement, you may need:

  1. Get camera instance in your service. Check this Official Guideline.
  2. Setup your camera parameters. Use the APIs like Camera.getParameters(), Camera.setParameters(), Camera.Parameters.setPictureSize(int with, int height) and Camera.Parameters.setPictureFormat(int format) to do so.
  3. Prepare a file used to store the image. You need to implement Camera.PictureCallback to do so.
  4. Call Camera.startPreview() before you takeing picutre. If you don't call this function before taking picture, you will get exception. (Note: You don't need to do Camera.setPreviewdisplay(SurfaceHolder display) first.)
  5. Call camera.takePicture() in your service. Then you can get the captured image stored on the file you specified.

After it work, don forget to maintain the resource durning lifecycle to acquire/release camera correctly.

Here is my sample code on Github, it is also mentioned in the comment.

Community
  • 1
  • 1
chartsai
  • 368
  • 3
  • 7
  • Yes, I tried exactly the code [Question](http://stackoverflow.com/questions/10121660/how-to-record-video-from-background-of-application-android) you given yestoday. However, I meet a problem as I describe the question that, if I switch to another application while recording. Then I switch back. The camera seems like stopped. – Peter Zhu Mar 19 '15 at 08:00
  • 1
    I don't have the problem as your description. I think you may miss some resource handling in the lifecycle of your Activity or Service. BTW if you don't stop and release the camera in your service, it cannot be got again. – chartsai Mar 19 '15 at 09:25
  • You mean your program still work well while you switch to another application? – Peter Zhu Mar 19 '15 at 10:31
  • Really Really Amazing !! – Peter Zhu Mar 19 '15 at 13:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73354/discussion-between-peter-zhu-and-chatea). – Peter Zhu Mar 19 '15 at 14:13
  • 2
    In general, the camera API does not guarantee that startPreview will work if you have not called setPreviewDisplay or setPreviewTexture beforehand. This works on some subset of devices (which are technically breaking the API specifications) but not on many. Please don't rely on this behavior if you want to run on all Android devices. – Eddy Talvala Sep 22 '16 at 20:50
  • Thanks for the code, but I am wondering whether camera can be open in a remote services? – flankechen Jun 27 '18 at 08:17