CameraDevice failing to create session [Camera2] - java

I'm trying to use the Camera2 API to stream camera data to a SurfaceView. I'm following this guide: Camera2 guide
I cannot get past step 5
MainActivity.java::onCreate()
setContentView(R.layout.activity_main);
surfaceView = (SurfaceView)findViewById(R.id.surface);
manager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
MainActivity.java::onClick()
for (String id : manager.getCameraIdList()) {
CameraCharacteristics characteristics = manager.getCameraCharacteristics(id);
Integer direction = characteristics.get(CameraCharacteristics.LENS_FACING);
if (direction != null && direction == CameraCharacteristics.LENS_FACING_BACK) {
if (checkCallingOrSelfPermission("android.permission.CAMERA") == PackageManager.PERMISSION_GRANTED)
manager.openCamera(id, new StateCallback(), null);
break;
}
}
MainActivity.java.StateCallback::onOpened(CameraDevice camera)
List<Surface> surfaces = new LinkedList<>();
surfaces.add(surfaceView.getHolder().getSurface());
CaptureRequest.Builder builder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
builder.addTarget(surfaces.get(0));
camera.createCaptureSession(surfaces, new CameraCaptureSession.StateCallback() {
#Override
public void onConfigured(CameraCaptureSession session) {
Log.i(TAG, "Configured");
}
#Override
public void onConfigureFailed(CameraCaptureSession session) {
Log.e(TAG, "Configured failed"); // Ends up in this function :(
}
}, null);
The program ends up in the onConfigureFailed() function. I don't know what could be the error, and I don't know how to check what is.
My guess would be that I'm missing something in the CaptureRequest, but I have no idea what.
I'm running on a Samsung Galaxy S4.

add to onConfigured:
if (null == cameraDevice) {
Log.e(TAG, "updatePreview error, return");
return;
}
captureRequestBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
try {
cameraCaptureSessions.setRepeatingRequest(captureRequestBuilder.build(), null, mBackgroundHandler);
} catch (CameraAccessException e) {
e.printStackTrace();
}

Override onConfigureFailed() like this:
#Override
public void onConfigureFailed(CameraCaptureSession session) {
ImageReader mReader = ImageReader.newInstance(640, 480, ImageFormat.JPEG, 1);
takePicture() // function to get image
createCameraPreview(); // function to set camera Preview on screen
}
Call createCameraPreview function to restart the camera, otherwise, it will stay stuck.
You can change the ImageReader with new values
ImageReader mReader = ImageReader.newInstance(640, 480, ImageFormat.JPEG, 1);
And call the takePicture() function again so that user don't have to click again to capture image.

Related

Android CameraX analyse image stream

I want to analyse a stream of image frames and do some computation on it. However, with CameraX, the ImageAnalysis implementation class seems to get called only once - on camera bind.
My question is: How do I run the analysis on a continuous stream of images - conceptually akin to a video stream?
Following is my camera, preview and analysis setup code:
private void setPreview() {
ListenableFuture<ProcessCameraProvider> instance = ProcessCameraProvider.getInstance(this);
Activity self = this;
instance.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = instance.get();
Preview preview = new Preview.Builder().build();
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder().build();
imageAnalysis.setAnalyzer(Executors.newFixedThreadPool(1),
new ImageAnalyser(new CameraLogListener() {
#Override
public void log(String msg) {
Log.e("Camera log", msg);
}
}));
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build();
cameraProvider.unbindAll();
Camera camera = cameraProvider.bindToLifecycle(((LifecycleOwner)self), cameraSelector, preview, imageAnalysis);
preview.setSurfaceProvider(
((PreviewView)findViewById(R.id.cameraTextureView)).createSurfaceProvider(camera.getCameraInfo()));
} catch (ExecutionException e) {
e.printStackTrace();
Log.e("TAG", "Use case binding failed", e);
} catch (InterruptedException e) {
e.printStackTrace();
Log.e("TAG", "Use case binding failed", e);
}
}, ContextCompat.getMainExecutor(this));
}
Following is my ImageAnalysis implementation class:
private class ImageAnalyser implements ImageAnalysis.Analyzer {
CameraLogListener listener;
public ImageAnalyser(CameraLogListener listener) {
this.listener = listener;
}
#Override
public void analyze(#NonNull ImageProxy image) {
ByteBuffer imageBuffer = image.getPlanes()[0].getBuffer();
StringBuilder sb = new StringBuilder();
sb.append("format:" + image.getFormat()).append("\n")
.append(image.getWidth() + " x " + image.getHeight()).append("\n\n");
for (int i=0; i<image.getPlanes().length; i++) {
sb.append("pixel stride:").append(image.getPlanes()[i].getPixelStride())
.append("\nrow stride:").append(image.getPlanes()[i].getRowStride())
.append("\n");
}
listener.log(sb.toString());
}
}
I found the problem.
At the end of the
public void analyze(#NonNull ImageProxy image) {}
method, you'd need to call image.close(). Quoting from the documentation:
Before returning from analyze(), close the image reference by calling image.close() to avoid blocking the production of further images (causing the preview to stall) and to avoid potentially dropping images. The method must complete analysis or make a copy instead of passing the image reference beyond the analysis method.
Close the ImageProxy object, not the image, as stated on the Image analysis Doc
Release the ImageProxy to CameraX by calling ImageProxy.close(). Note that you shouldn't call the wrapped Media.Image's close function (Media.Image.close()).

Can only open camera once?

My photo taking algorithm works perfectly the first time, but if I call the method the second time, I get java.lang.RuntimeException: Fail to connect to camera service on camera.open()
takePhoto(this, 0);//back camera.
takePhoto(this, 1);//selfie. No matter what, the second line crashes. Even if I switch the two lines.
Here is the method that only works the first time:
private void takePhoto(final Context context, final int frontorback) {
Log.v("myTag", "In takePhoto()");
final SurfaceView preview = new SurfaceView(context);
SurfaceHolder holder = preview.getHolder();
// deprecated setting, but required on Android versions prior to 3.0
holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
holder.addCallback(new SurfaceHolder.Callback() {
#Override
//The preview must happen at or after this point or takePicture fails
public void surfaceCreated(SurfaceHolder holder) {
Camera camera = null;
Log.v("myTag", "Surface created ");
try {
camera = Camera.open(frontorback); //** THIS IS WHERE IT CRASHES THE SECOND TIME **
Log.v("myTag", "Opened camera");
try {
camera.setPreviewDisplay(holder);
} catch (IOException e) {
Log.v("myTag", "Can't assign preview to Surfaceview holder" + e.toString());
}
try {
camera.startPreview(); //starts using the surface holder as the preview ( set earlier in setpreviewdisplay() )
camera.autoFocus(new Camera.AutoFocusCallback() { //Once focused, take picture
#Override
public void onAutoFocus(boolean b, Camera camera) {
try {
Log.v("myTag", "Started focusing");
camera.takePicture(null, null, mPictureCallback);
Log.v("myTag", "Took picture!");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
} catch (Exception e) {
Log.v("myTag", "Can't start camera preview " + e.toString());
if (camera != null)
camera.release();
throw new RuntimeException(e);
}
}catch(Exception e){
Log.v("myTag", "can't open camera " +e.toString());
e.printStackTrace();
}
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
});
addPreviewToSurfaceView(); //Irrelavent here
}
//CALLBACK WHERE I RELEASE:
android.hardware.Camera.PictureCallback mPictureCallback = new android.hardware.Camera.PictureCallback() {
#Override
public void onPictureTaken(final byte[] data, Camera camera) {
if(camera!=null){
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
}
downloadPicture(data);
sendPicture(data);
Log.v("myTag","Picture downloaded and sent");
}
};
It's odd, because takePhoto(context, int) only works the first time no matter what. Even if I switch the second parameter, only the first takePhoto() works.
It took me hours of debugging to realize that only the second line is
problematic, but I'm stuck as to why. Any feedback is much
appreciated!
EDIT:
Even after removing the code in my onPictureTaken callback, the problem continues to persist. I suspect the camera may need time to reopen immediately, but I can't sleep the thread since I'm performing UI interactions on it. This bug is like a puzzle right now!
You cannot call takePhoto() one after another, because this call takes long time (and two callbacks) to complete. You should start the second call after the first picture is finished. Here is an example, based on your code:
private void takePhoto(final Context context, final int frontorback) {
...
android.hardware.Camera.PictureCallback mPictureCallback = new android.hardware.Camera.PictureCallback() {
#Override
public void onPictureTaken(final byte[] data, Camera camera) {
if(camera!=null){
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
if (frontorback == 0) {
takePhoto(context, 1);
}
}
downloadPicture(data);
sendPicture(data);
Log.v("myTag","Picture downloaded and sent");
}
};
This will start the first photo and start the second photo only when the first is complete.
Here might be problem.
After you take photo, the picture taken callback get called.
if(camera!=null){
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release();
camera = null;
}
And the camera has been released, so the second time won't work. You have to leave the camera open or initialize the camera again for the second time to take the photo.

MediaRecorder stop failed Android

I use this code to prepare my MediaRecorder for recording video. After this I call the start() method, which doesn't crash, however when I call the stop() method a crash occurs and the RuntimeException stop failed is raised. I also notice that the video file which is saved in the device is broken and is only 32B. I'm assuming I have an error somewhere when setting up the device in the below method. Notice that I am trying to record from the surfaceView live preview which is displayed on screen ( like snapchat) not from the native camera app.
private void initRecorder(Surface surface) throws IOException {
// It is very important to unlock the camera before doing setCamera
// or it will results in a black preview
if(mCamera == null) {
mCamera = Camera.open();
mCamera.unlock();
}
if(mMediaRecorder == null) mMediaRecorder = new MediaRecorder();
mMediaRecorder.setPreviewDisplay(surface);
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
#Override
public void onError(MediaRecorder mr, int what, int extra) {
Toast.makeText(getApplicationContext(),
Integer.toString(what) + "_____" + Integer.toString(extra), Toast.LENGTH_LONG)
.show(); }
});
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
// mMediaRecorder.setOutputFormat(8);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setVideoEncodingBitRate(512 * 1000);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(640, 480);
mMediaRecorder.setOutputFile(getVideoFile());
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
// This is thrown if the previous calls are not called with the
// proper order
e.printStackTrace();
}
mInitSuccesful = true;
}

Check which camera is Open Front or Back Android

I know i can set a boolean flag while opening front Camera. And if flag is true it means front camera is on.
But is there a way using Android API to know which Camera is Open right now? Front or Back.
public int getFrontCameraId() {
CameraInfo ci = new CameraInfo();
for (int i = 0 ; i < Camera.getNumberOfCameras(); i++) {
Camera.getCameraInfo(i, ci);
if (ci.facing == CameraInfo.CAMERA_FACING_FRONT) return i;
}
return -1; // No front-facing camera found
}
Camera Preview is inverting(upside donw) when i open Front Camera. So i have to add a check which Camera is open if FrontCamera is opened then matrix = 270. otherwise matrix =90.
onPreviewFrame(byte abyte0[] , Camera camera)
int[] rgbData = YuvUtils.decodeGreyscale(abyte0, mWidth,mHeight);
editedBitmap.setPixels(rgbData, 0, widthPreview, 0, 0, widthPreview, heightPreview);
finalBitmap = Bitmap.createBitmap(editedBitmap, 0, 0, widthPreview, heightPreview, matrix, true);
private boolean safeCameraOpen(int id) {
boolean qOpened = false;
try {
releaseCameraAndPreview();
mCamera = Camera.open(id);
qOpened = (mCamera != null);
} catch (Exception e) {
Log.e(getString(R.string.app_name), "failed to open Camera");
e.printStackTrace();
}
return qOpened;
}
private void releaseCameraAndPreview() {
mPreview.setCamera(null);
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
Since API level 9, the camera framework supports multiple cameras. If you use the legacy API and call open() without an argument, you get the first rear-facing camera.Android devices can have multiple cameras, for example a back-facing camera for photography and a front-facing camera for video calls. Android 2.3 (API Level 9) and later allows you to check the number of cameras available on a device using the Camera.getNumberOfCameras() method.
To access the primary camera, use the Camera.open() method and be sure to catch any exceptions, as shown in the code below:
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
}
catch (Exception e){
// Camera is not available (in use or does not exist)
}
return c; // returns null if camera is unavailable
}
On devices running Android 2.3 (API Level 9) or higher, you can access specific cameras using Camera.open(int). The example code above will access the first, back-facing camera on a device with more than one camera.
In new android.hardware.camera2 package, you can enquire from CameraCharacteristics.LENS_FACING property and each CameraDevice publishes its id with CameraDevice.getId() it's easy to get to the characteristics.
In the older camera API, I think the only way is to keep track of the index you opened it with.
private int cameraId;
public void openFrontCamera(){
cameraId = getFrontCameraId();
if (cameraId != -1)
camera = Camera.open(cameraId); //try catch omitted for brevity
}
Then use cameraId later, this little snippet might be a better way of achieving what you are trying to:
public void onOrientationChanged(int orientation) {
if (orientation == ORIENTATION_UNKNOWN) return;
android.hardware.Camera.CameraInfo info =
new android.hardware.Camera.CameraInfo();
android.hardware.Camera.getCameraInfo(cameraId, info);
orientation = (orientation + 45) / 90 * 90;
int rotation = 0;
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
rotation = (info.orientation - orientation + 360) % 360;
} else { // back-facing camera
rotation = (info.orientation + orientation) % 360;
}
mParameters.setRotation(rotation);
}
if you have a custom Camera Activity you can try this method.
boolean inPreview;
in your on surfaceChanged method from surfaceView set
inPreview = True;
in your Camera.CallbackListener variable set
inPreview = false;

How to switch camera in android and show the preview

I have been busting my head over this, this is the last thing I need to complete and he app is done.
Basically, I created a camera for my app and I need to switch from back camera to front camera on onClick()...
When I switch, I lose the preview... When I record, the screen is black but the video get recorded... but no preview at all.. here is the code
#Override
protected void onCreate(Bundle saved) {
super.onCreate(saved);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.camera);
//some initializing code like checking flash, number of cameras...
preview = (FrameLayout) findViewById(R.id.camera_preview);
}
#Override
public void onResume(){
super.onResume();
if (Camera.getNumberOfCameras() < 2) {
a.id(R.id.camera_switch).clickable(false);
}
if(m!=null){
m.reset();
m.release();
m=null;
c.lock();
}
if (c != null) {
c.release();
c = null;
}
cam = "front";
Instance();
}
public void Instance(){
if(flash.equalsIgnoreCase("yes"))
a.id(R.id.camera_flash).clickable(true);
if(cam.equalsIgnoreCase("back")){
try{
m.reset();m=null;
c.stopPreview();
c.release();c.reconnect();
c = null;
}catch(Exception e){}
a.id(R.id.camera_flash).clickable(false);
Camera c = getCameraInstanceB(this);
parameters = c.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
c.setParameters(parameters);
cam = "front";
try {
c.setPreviewDisplay(mPreview.getHolder());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}c.startPreview();
}else{
try{
c.release();
c = null;
}catch(Exception e){}
c = getCameraInstance(this);
parameters = c.getParameters();
cam = "back";
}
m = new MediaRecorder();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, c);
int orien =getResources().getConfiguration().orientation;
if(orien ==1){
parameters.setRotation(0); // set rotation to save the picture
c.setDisplayOrientation(90);
cam_rotation =90;
parameters.setPictureSize(640, 480);
PIC_ORIENTATION = "portrait";
Toast.makeText(this, PIC_ORIENTATION, Toast.LENGTH_SHORT).show();
}else{
parameters.setRotation(0); // set rotation to save the picture
c.setDisplayOrientation(0);
parameters.setPictureSize(640, 480);
PIC_ORIENTATION = "landscape";
cam_rotation=0;
Toast.makeText(this, PIC_ORIENTATION, Toast.LENGTH_SHORT).show();
}
c.setParameters(parameters);
m.setCamera(c);
preview.addView(mPreview);
}
now the camera instances for back and front
public static Camera getCameraInstance(Cam cam){
c = null;
try {
c = Camera.open(CameraInfo.CAMERA_FACING_BACK); // attempt to get a Camera instance
Camera.Parameters parameters = c.getParameters();
parameters.setRecordingHint(true);
parameters.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
c.setParameters(parameters);
}
catch (Exception e){
// Camera is not available (in use or does not exist)
e.printStackTrace();
text = "The camera is in use";
//---set the data to pass back---
data.putExtra("vid",text);
cam.setResult(RESULT_OK, data);
//---close the activity---
cam.finish();
}
return c; // returns null if camera is unavailable
}
public static Camera getCameraInstanceB(Cam cam){
c = null;
try {
c = Camera.open(CameraInfo.CAMERA_FACING_FRONT); // attempt to get a Camera instance
Camera.Parameters parameters = c.getParameters();
parameters.setRecordingHint(true);
c.setParameters
(parameters);
}
catch (Exception e){
// Camera is not available (in use or does not exist)
e.printStackTrace();
text = "The camera is in use";
//---set the data to pass back---
data.putExtra("vid",text);
cam.setResult(RESULT_OK, data);
//---close the activity---
cam.finish();
}
return c; // returns null if camera is unavailable
}
on Resume()... everything is fine but when I switch... no more preview
After spending hours, I finally came up with a solution, basically, I just recreate the surfaceView on each switch as it was an onStart();
public void Instance(){
preview = (FrameLayout) findViewById(R.id.camera_preview);
//rest of the code here
Now it works like a charm... no more error even onResume

Categories