我想从后台服务运行设备的前置摄像头,使用在摄像头捕获新帧时调用的回调来获取后台服务中摄像头捕获的帧(例如{{1} }),并对获得的帧应用一些实时处理。
搜索后我明白有两种方法可以在后台运行相机:
1-设置尺寸为1 X 1的SurfaceView。
2-使用SurfaceTexture(这不需要任何看起来效率更高的视图。)
我尝试了两种方式,我只能从后台运行相机,但是从未调用过获取帧的回调,尽管我尝试了不同的技巧。
我在方法1中使用的代码可以在这里找到:
请注意,我还尝试在surfaceChanged中调用onPreviewFrame,但是在尝试使用它设置回调时,我总是得到相机为null!我甚至试图将其重新实例化为onPreviewFrame
,但我收到错误消息“无法连接到相机服务。”
以下是方法2的代码:
camera = Camer.open()
以下是我如何通过活动调用服务:
public class BackgroundService extends Service implements TextureView.SurfaceTextureListener {
private Camera camera = null;
private int NOTIFICATION_ID= 1;
private static final String TAG = "OCVSample::Activity";
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
private WindowManager windowManager;
private SurfaceTexture mSurfaceTexture= new SurfaceTexture (10);
public class LocalBinder extends Binder {
BackgroundService getService() {
// Return this instance of this service so clients can call public methods
return BackgroundService.this;
}
}//end inner class that returns an instance of the service.
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}//end onBind.
@Override
public void onCreate() {
// Start foreground service to avoid unexpected kill
startForeground(NOTIFICATION_ID, buildNotification());
}
private Notification buildNotification () {
NotificationCompat.Builder notificationBuilder=new NotificationCompat.Builder(this);
notificationBuilder.setOngoing(true); //this notification should be ongoing
notificationBuilder.setContentTitle(getString(R.string.notification_title))
.setContentText(getString (R.string.notification_text_and_ticker))
.setSmallIcon(R.drawable.vecsat_logo)
.setTicker(getString(R.string.notification_text_and_ticker));
return(notificationBuilder.build());
}
@Override
public void onDestroy() {
Log.i(TAG, "surfaceDestroyed method");
}
/***********Ok now all service related methods were implemented**************/
/************now implement surface texture related methods*****************/
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i2) {
//Now the surfaceTexture available, so we can create the camera.
camera = Camera.open(1);
mSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
Log.e(TAG, "frame captured");
}
});
//now try to set the preview texture of the camera which is actually the surfaceTexture that has just been created.
try {
camera.setPreviewTexture(mSurfaceTexture);
}
catch (IOException e){
Log.e(TAG, "Error in setting the camera surface texture");
}
camera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
Log.e(TAG, "frame captured");
}
});
// the preview was set, now start it
camera.startPreview();
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i2) {
//super implementation is sufficient.
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
//stop the preview.
camera.stopPreview();
//release camera resource:
camera.release();
return false;
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {
mSurfaceTexture.setOnFrameAvailableListener(new SurfaceTexture.OnFrameAvailableListener() {
@Override
public void onFrameAvailable(SurfaceTexture surfaceTexture) {
Log.e(TAG, "frame captured from update");
}
});
camera.stopPreview(); //stop current preview.
try {
camera.setPreviewTexture(mSurfaceTexture);
}
catch (IOException e){
Log.e(TAG, "Error in setting the camera surface texture");
}
camera.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
Log.e(TAG, "frame captured");
}
});
camera.startPreview(); // start the preview again.
}
请帮忙,如何让帧回调起作用?我尝试了很多,但我无法理解。
无论是使用方法1还是2,都非常感谢任何帮助。
感谢。