Android Camera 2 Api - android

I have been trying camera2 API. I have downloaded code from
https://developer.android.com/samples/Camera2Video/index.html to learn about how it works. It works fine till I stop recording. When I stop recording it runs following code.
private void stopRecordingVideo() {
// UI
mIsRecordingVideo = false;
mBtn_Video.setText(R.string.record);
// Stop recording
try {
mMediaRecorder.stop();
mMediaRecorder.reset();
}
catch (Exception e) {
e.printStackTrace();
}
Activity activity = getActivity();
if (null != activity) {
System.out.println("file " + getVideoFile(activity));
Toast.makeText(activity, "Video saved: " + getVideoFile(activity),
Toast.LENGTH_SHORT).show();
}
startPreview();
at mMediaRecorder.stop(); it throw following error
01-12 16:24:23.115 2161-2200/com.cameratwoapi E/Surface﹕ queueBuffer: error queuing buffer to SurfaceTexture, -19
01-12 16:24:23.135 2161-2200/com.cameratwoapi E/EGL_emulation﹕ tid 2200: swapBuffers(285): error 0x3003 (EGL_BAD_ALLOC)
01-12 16:24:23.197 2161-2200/com.cameratwoapi E/CameraDeviceGLThread-0﹕ Received exception on GL render thread:
java.lang.IllegalStateException: swapBuffers: EGL error: 0x3003
at android.hardware.camera2.legacy.SurfaceTextureRenderer.checkEglError(SurfaceTextureRenderer.java:487)
at android.hardware.camera2.legacy.SurfaceTextureRenderer.swapBuffers(SurfaceTextureRenderer.java:480)
at android.hardware.camera2.legacy.SurfaceTextureRenderer.drawIntoSurfaces(SurfaceTextureRenderer.java:681)
at android.hardware.camera2.legacy.GLThreadManager$1.handleMessage(GLThreadManager.java:103)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:135)
at android.os.HandlerThread.run(HandlerThread.java:61)
Any Idea what I am doing wrong. I spent few hours but couldn't find any solution.
Edit - I am using geneymotion emulator. The path I am using
file /storage/emulated/0/Android/data/com.gold.cameratwoapi/files/video.mp4
Thanks

My solution is to change void stopRecordingVideo() as following:
private void stopRecordingVideo() {
// UI
mIsRecordingVideo = false;
mButtonVideo.setText(R.string.record);
// Added by Ben Ning, to resolve exception issue when stop recording.
try {
mPreviewSession.stopRepeating();
mPreviewSession.abortCaptures();
} catch (CameraAccessException e) {
e.printStackTrace();
}
// Stop recording
mMediaRecorder.stop();
mMediaRecorder.reset();
}
Key is:
try {
mPreviewSession.stopRepeating();
mPreviewSession.abortCaptures();
} catch (CameraAccessException e) {
e.printStackTrace();
}

private void stopRecordingVideo() {
// UI
mIsRecordingVideo = false;
mButtonVideo.setText(R.string.record);
// Added by Ben Ning, to resolve exception issue when stop recording.
try {
mPreviewSession.stopRepeating();
mPreviewSession.abortCaptures();
} catch (CameraAccessException e) {
e.printStackTrace();
}
// Stop recording
mMediaRecorder.stop();
mMediaRecorder.reset();
Activity activity = getActivity();
if (null != activity) {
Toast.makeText(activity, "Video saved: " + getVideoFile(activity),
Toast.LENGTH_SHORT).show();
}
startPreview();
}
this is working for me.

After calling mMediaRecorder.stop() an IllegalStateException is always thrown. I've noticed that on devices with INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY the CameraDevice changes status to error, immediately calling onError() in the CameraDevice.StateCallback.
In the sample you referenced, onError() closes the camera and finishes the activity, so just change onError() to re-open the camera, like this:
#Override
public void onError(CameraDevice cameraDevice, int error) {
// mCameraOpenCloseLock.release();
// cameraDevice.close();
// mCameraDevice = null;
// Activity activity = getActivity();
// if (null != activity) {
// activity.finish();
// }
closeCamera();
openCamera(mTextureView.getWidth(), mTextureView.getHeight());
}
It'd also be a good idea to put some check in there to make sure that if an error really did happen, that the commented out code gets called instead of entering a loop of trying to open the camera over and over.
Tested on a Moto G 2nd gen, with Android 5.0.2

It depends on what you are doing with the CameraCaptureSession and the MediaRecorder but when you call mMediaRecorder.stop() I think it is destroying the surface used for the camera preview session which causes this error because the documentation says
Once recording is stopped, you will have to configure it again as if it has just been constructed
Therefore if you call PreviewSession.abortCaptures() (mPreviewSession.stopRepeating(); isn't necessary from what I gather) it stops the camera sending output to the recorder surface which will allow you to stop the MediaRecorder without issue.
PreviewSession.abortCaptures(); doesn't instantly stop the camera preview output so you might find you need to call MediaRecorder.stop() in the onClosed() or onReady() method of the CameraCaptureSession.StateCallback

In my case, I use TimerTask and a Handler. There is error direct to the mMediaRecorder.stop(). So I use this method
final Handler mTimerHandler = new Handler(Looper.getMainLooper());
mIsRecordingVideo = false;
// Stop recording
try {
mPreviewSession.stopRepeating();
mPreviewSession.abortCaptures();
} catch (CameraAccessException e) {
e.printStackTrace();
}
try{
Timer timer = new Timer();
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
mTimerHandler.post(new Runnable() {
#Override
public void run() {
mMediaRecorder.stop();
mMediaRecorder.reset();
}
});
}
};
timer.schedule(timerTask,30);
}catch(RuntimeException e){
Log.e("----------------","---->>>>>>>>>"+e);
e.printStackTrace();
}

Related

CameraX - crash app on onPause() while recording video

if minimize app while recording video - everything all right, but once I deploy the application, ерут getting this error:
E/AndroidRuntime: FATAL EXCEPTION: CameraX-video encoding thread
Process: <pkgname>, PID: 12340
java.lang.IllegalStateException
at android.media.MediaCodec.native_dequeueOutputBuffer(Native Method)
at android.media.MediaCodec.dequeueOutputBuffer(MediaCodec.java:2698)
at androidx.camera.core.VideoCapture.videoEncode(VideoCapture.java:604)
at androidx.camera.core.VideoCapture$2.run(VideoCapture.java:348)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:65)
Or
if I stopped recording on onPause videoCapture?.stopRecording(), then getting this error:
E/AndroidRuntime: FATAL EXCEPTION: CameraX-
Process: <pkgname>, PID: 9489
java.lang.IllegalStateException
at androidx.core.util.Preconditions.checkState(Preconditions.java:96)
at androidx.core.util.Preconditions.checkState(Preconditions.java:108)
at androidx.camera.camera2.impl.Camera.openCaptureSession(Camera.java:874)
at androidx.camera.camera2.impl.Camera.onUseCaseReset(Camera.java:625)
at androidx.camera.camera2.impl.Camera$11.run(Camera.java:611)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:214)
at android.os.HandlerThread.run(HandlerThread.java:65)
How right stop record video while minimize app???
here's my code:
I collect configurations:
CameraX.unbindAll()
getDisplayMetrics()
setPreviewConfig()
when (typeCapture) {
TYPE_IMAGE -> {
setImageCapture()
CameraX.bindToLifecycle(this, preview, imageCapture)
}
TYPE_VIDEO -> {
setVideoCapture()
CameraX.bindToLifecycle(this, preview, videoCapture)
}
}
set videoConfig and videoCapture:
val videoCaptureConfig = VideoCaptureConfig.Builder().apply {
setLensFacing(lensFacing)
setTargetAspectRatioCustom(screenAspectRatio)
setTargetRotation(rotation)
}.build()
videoCapture = VideoCapture(videoCaptureConfig)
then I start recording video:
videoCapture?.startRecording(videoFile,
CameraXExecutors.mainThreadExecutor(), recordListener)
on onPause() the errors I get are described above
Thanks
I had the same error when stoping the video on onPause. To solve it I added a delay before to call super.onPause() ( see : android: camera onPause/onResume issue).
Declare videoSavedListener
private VideoCapture.OnVideoSavedListener videoSavedListener= new VideoCapture.OnVideoSavedListener() {
#Override
public void onVideoSaved(#NonNull File file) {
if(isRecording) {
isRecording = false;
// Do whatever you want
}
}
#Override
public void onError(#NonNull VideoCapture.VideoCaptureError videoCaptureError, #NonNull String message, #Nullable Throwable cause) {
}
};
Add onClickListener
button.setOnClickListener(v -> {
if(!isRecording){
videoCapture.startRecording(videoFile, CameraXExecutors.mainThreadExecutor(), videoSavedListener);
isRecording = true;
}else{
videoCapture.stopRecording();
}
});
Override onPause()
#SuppressLint("RestrictedApi")
#Override
public void onPause() {
if(isRecording){
isRecording = false;
videoCapture.stopRecording();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
super.onPause();
}else
super.onPause();
}
Please note that video recording use case is currently marked as
hidden in the API and is in a very preliminary state and subject to
change.
EDIT: With some devices the app still crash when calling onPause() with the videoCapture use case set. I added CameraX.unbindAll() to remove all the use cases before calling super.onPause(). Then, in the onResume() method I bind them again.
Declare a boolean variable
public class MyClass{
private boolean isSafe;
private boolean isPending
onPause{
isSafe=false;
}
onPostResume{
isSafe=true;
if(isPending)
methodForDoingUrAction();
}
methodForDoingUrAction(){
if(isSAfe){
//do your process
isPending=false;
}
else
isPending=true;
}
}

Android camera fails to take photo from background service

I've implemented a service to take a picture from a background thread, but the photo never gets taken on any of my devices... here is the code (logging output below):
public class PhotoCaptureService extends Service {
private static final String TAG = "PhotoCaptureService";
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
Log.d(TAG, "Starting the PhotoCaptureService");
takePhoto();
}
private void takePhoto() {
Log.d(TAG, "Preparing to take photo");
Camera camera = null;
try {
camera = Camera.open();
} catch (RuntimeException e) {
Log.e(TAG, "Camera not available", e);
return;
}
if (null == camera) {
Log.e(TAG, "Could not get camera instance");
return;
}
Log.d(TAG, "Got the camera, creating the dummy surface texture");
SurfaceTexture dummySurfaceTexture = new SurfaceTexture(0);
try {
camera.setPreviewTexture(dummySurfaceTexture);
} catch (Exception e) {
Log.e(TAG, "Could not set the surface preview texture", e);
}
Log.d(TAG, "Preview texture set, starting preview");
camera.startPreview();
Log.d(TAG, "Preview started");
camera.takePicture(null, null, new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(TAG, "Photo taken, stopping preview");
camera.stopPreview();
Log.d(TAG, "Preview stopped, releasing camera");
camera.release();
Log.d(TAG, "Camera released");
}
});
}
Logging output:
D/PhotoCaptureService﹕ Starting the PhotoCaptureService
D/PhotoCaptureService﹕ Preparing to take photo
D/PhotoCaptureService﹕ Got the camera, creating the dummy surface texture
D/PhotoCaptureService﹕ Preview texture set, starting preview
D/PhotoCaptureService﹕ Preview started
At this point nothing else happens, the onPictureTaken method never gets called and there is no error or exception thrown. Does anyone know why this is happening? I've looked at every camera tutorial on StackOverflow and nothing seems to work.
From my experience and what I've read, the dummy SurfaceTexture strategy doesn't work on all phones. Try instead adding a 1x1 pixel SurfaceView and starting the preview in the SurfaceView.getHolder()'s onSurfaceCreated callback (added via addCallback).
See Taking picture from camera without preview for more information.

IllegalStateException when calling AudioRecord.start()

I'm using AudioRecorder to record short audio clips but I'm getting IllegalStateException when calling AudioRecord.start() I've been looking for hours but can't find the cause of this...
I've set Audio Rec + Write External Storage permissions.
Here's a piece of my code:
// main activity...
// Audio inits
final MediaRecorder recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(getTempPath());
...
// called the sound rec async
new SoundComponent(tvmic, pb, tb).execute(recorder);
// SoundComponent.java
// Getting IllegalStateException when calling recorder[0].start();
[..]
protected Long doInBackground(MediaRecorder... recorder) {
try {
recorder[0].prepare();
} catch (IOException e) {
Log.e("100", "prepare() failed");
}
while (tb.isChecked())
{
//publishProgress();
//recorder[0].prepare();
recorder[0].start(); // here it were it throws
try {
Thread.sleep(250);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// int amplitude = recorder[0].getMaxAmplitude();
recorder[0].stop();
}
// TODO Auto-generated method stub
return null;
}
[..]
public String getTempPath() // audio temp path
{
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
path+="/temp/audiorectemp.3gp";
return path;
}
Starting and stopping the MediaRecorder multiple times in a loop probably isn't a good idea. Look closely at what you're doing, I've trimmed your code to make it easier to see...
while (tb.isChecked())
{
recorder[0].start(); // here it were it throws
// Sleep here
recorder[0].stop();
}
It probably isn't throwing an exception the first time you call start() but it will on the second loop. See the state machine diagram...MediaRecorder
Also, to detect when the doInBackground(...) thread should be exited, ther is a method on AsyncTask which can be called from the UI thread to cancel it.
The loop should ideally be while (!isCancelled()) and you should call the AsyncTask.cancel(...) method from the onCheckedChanged listener of tb in the main Activity code (assuming tb is a CheckBox or some other CompoundButton).

MediaRecorder on Android interfeering with other Media Aplications

I am using the MediaRecorder in my app to measure decibel. For this a new MediaRecorder-Object is created once every 10 seconds, it runs for one second during which getMaxAmplitude() is called 10 times and the average is calculated. After this the MediaRecorder object is stopped and deleted.
The Method to start the Recorder looks like this
public boolean start()
{
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setOutputFile("/dev/null");
try
{
mRecorder.prepare();
}
catch (IllegalStateException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
catch(Exception e)
{
e.printStackTrace();
return false;
}
mRecorder.start();
mRecorder.getMaxAmplitude();
return true;
}
and the Method to stop looks like this
public void stop()
{
//Log.d("SPLService", "stop()");
mRecorder.stop();
mRecorder.reset();
mRecorder.release();
mRecorder=null;
}
This is pretty much the way the tutorial on the Android Website instructed.
The problem arises when I use this app in parallel with other Apps using Media, like the Mediaplayer on Android. Whenever a sound measurement is taken using my App other media Apps stop or even crash, even though their objects should be independent of mine.
I have tried using AudioRecord instead of MediaRecorder but the interference with other apps was the same.
I guess my question would be: how can I avoid such interference?

recreating camera object after error 100 (camera server died)

I have classic android app with camera preview (common implem that can be found in many tutorials [marakana etc.]) that is supposed to take picture in a given time interval. Threading and killing threads is done, errors such "method called after release" are handled. But sometimes the well-known error 100 occurs. I accepted the fact that it happens and tried to handle it too. I implemented ErrorCallback and its onError method where the current camera object is released and instantiated a new one as written in official documentation.
But (with no surprise) it is not enough. New camera is maybe wrongly allocated because an message "CameraDemo has been exited unexpectedly" appears now.
I've read many docs and examples in hope, that a proper proceeding will be somewhere explained but no one has such problem apparently. So I would like to ask what else should I do beside releasing and creating new camera? Here is the code:
ErrorCallback CEC = new ErrorCallback()
{
public void onError(int error, Camera camera)
{
Log.d("CameraDemo", "camera error detected");
if(error == Camera.CAMERA_ERROR_SERVER_DIED)
{
Log.d("CameraDemo", "attempting to reinstantiate new camera");
camera.stopPreview();
camera.setPreviewCallback(null);
camera.release(); //written in documentation...
camera = null;
camera = Camera.open();
}
}
};
Shortly - if I release and recreate camera in onError callback then RuntimeException Method called after release (takePicture) is raised. So should I somehow assign the surface holder to camera again or recreate the surface holder too?
It would be enough to direct me e.g. to some forums, where it is described or solved, etc. Thanks for any help.
In my app to handle the camere i use this :
public void onResume() {
super.onResume();
if(mCamera == null)
mCamera = getCameraInstance():
}
public static Camera getCameraInstance() {
mCamera = null;
try {
mCamera = Camera.open();
Parameters parameters = mCamera.getParameters();
mCamera.cancelAutoFocus();
mCamera.setPreviewCallback(yourPreviewCb);
mCamera.startPreview();
mCamera.setParameters(parameters);
mCamera.autoFocus(yourAutoFocusCB);
} catch (Exception e) {
//TODO
}
return mCamera;
}
The mCamera = null in the getCameraInstance() is just to be sure there is no camera running at all.
I think you need to recreate a complete camera, not just open it with the
camera.open();
Set this in the onResume or in the error callback, depending on your needs.
This is how I fixed it, here is a sample of code, think you get the idea:
private Camera camera;
// code...
public Camera getCameraInstance() {
Camera camera = Camera.open();
// code...
camera.setErrorCallback(new ErrorCallback() {
#Override
public void onError(int error, Camera camera) {
if(error == Camera.CAMERA_ERROR_SERVER_DIED) {
releaseCamera();
startCamera();
}
}
});
return camera;
}
protected void startCamera() {
if(getCamera() == null)
setCamera(getCameraInstance());
refreshCamera();
}
protected void releaseCamera() {
if (getCamera() != null) {
getCamera().release();
setCamera(null);
}
}
public Camera getCamera() {
return camera;
}
public void setCamera(Camera camera) {
this.camera = camera;
}

Categories

Resources