Peter Zhu Peter Zhu - 6 months ago 93
Android Question

Can I use Android Camera in service without preview?

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

Answer

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.