19

I am testing with new Android camera2 API and I want control each frame from camera. What I do for this is create an ImageReader and set up resolution and image format.

ImageReader imageReader = ImageReader.newInstance(1280,720,ImageFormat.YUV_420_888,1);
imageReader.setOnImageAvailableListener(new ImageReader.OnImageAvailableListener() {
    @Override
    public void onImageAvailable(ImageReader reader) {
        Image image = reader.acquireLatestImage();
        Log.i(MainActivity.LOG_TAG,"imageReader: "+System.currentTimeMillis());
        image.close();
    }
},null);

After that I create new CaptureRequest with parameter TEMPLATE_PREVIEW and add target to him imageReader. For cameraCaptureSession I create new setRepeatingRequest with this request

 try {
    final CaptureRequest.Builder builder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

    builder.addTarget(imageReader.getSurface());

    mCameraDevice.createCaptureSession(
            Arrays.asList(imageReader.getSurface()),
            new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    mSession = session;
                    try {
                        mSession.setRepeatingRequest(builder.build(),null,null);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();
                    }
                }
                @Override
                public void onConfigureFailed(CameraCaptureSession session) {

                }
            },
            null
    );
} catch (CameraAccessException e) {
    e.printStackTrace();
}

When I opened camera and start view what I have with preview I get exception. But before exception it I got some preview image and after that I have exception

10-30 16:00:32.850    1390-1894/.camera2tutorial E/BufferQueueProducer﹕ [unnamed-1390-1] dequeueBuffer: BufferQueue has been abandoned
10-30 16:00:32.850    1390-1894/.camera2tutorial E/Legacy-CameraDevice-JNI﹕ LegacyCameraDevice_nativeProduceFrame: Error while producing frame No such device (-19).
10-30 16:00:32.850    1390-1894/.camera2tutorial W/SurfaceTextureRenderer﹕ Surface abandoned, dropping frame.
    android.hardware.camera2.legacy.LegacyExceptionUtils$BufferQueueAbandonedException
            at android.hardware.camera2.legacy.LegacyExceptionUtils.throwOnError(LegacyExceptionUtils.java:64)
            at android.hardware.camera2.legacy.LegacyCameraDevice.produceFrame(LegacyCameraDevice.java:516)
            at android.hardware.camera2.legacy.SurfaceTextureRenderer.drawIntoSurfaces(SurfaceTextureRenderer.java:699)
            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:145)
            at android.os.HandlerThread.run(HandlerThread.java:61)

How can I fix this??

I am using a Samsung Galaxy S5 and Android API 21

dsh
  • 12,037
  • 3
  • 33
  • 51
mr.leo
  • 351
  • 2
  • 4
  • 9

3 Answers3

32

Make sure you're holding a reference to the ImageReader you create, probably wherever you have mSession defined.

The Surface you get from the ImageReader is roughly equivalent to a weak pointer - it won't prevent the ImageReader from getting garbage collected. So most likely (based on your naming) the ImageReader is getting destroyed and the abandonment error then occurs.

Eddy Talvala
  • 17,243
  • 2
  • 42
  • 47
  • 3
    i removed local variable from method and problem with exception was resolved. thanks! – mr.leo Nov 03 '15 at 08:00
  • 4
    @mr.leo consider marking this answer as accepted one. This solution helped also in my case. Funny thing is that it is platform specific - it worked fine for me on Nexues and other devices running Android 6, but failed with HTC One running Android 5. The beauty of android fragmentation. – stoiczek Mar 02 '16 at 05:37
  • @stoiczek how did you concretely keep a reference to the ImageReader? ( other than : "captureRequest.addTarget(imageReader.getSurface())" ) – Greelings May 27 '16 at 17:05
  • 2
    @Denis in the class where you setup the capture request, simply create a class member for the image reader and store a reference there. – stoiczek May 28 '16 at 01:12
  • That was my central problem with camera2 api. Thanks a lot! – DenisMath Dec 06 '18 at 15:14
  • 2020, same problem, this worked. Should be accepted as answer – Luis Mar 09 '20 at 10:16
  • Thanks, it helped me! – Dmytro Batyuk Dec 16 '21 at 20:44
  • @stoiczek Could you detail about fixing this issue, thanks – AnhPC03 Aug 24 '22 at 08:37
2

I had the same problem when switching between activities in my app and that was after calling onSurfaceTextureDestroyed() which was only returning false, But what i did is i changed it to

public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            Log.e(TAG, "onSurfaceTextureDestroyed");
            if(cameraDevice != null){
                closeCamera();

                cameraDevice = null;
            }
            return false;
        }

and that worked for me.

0

i found solution, this worked for me, infect error is in choosing correct size , so while using MediaRecorder.setVideoSize() use this method to choose optimal size

private static Size chooseOptimalSize(Size[] choices, int width, int height) {
        Size bigEnough = null;
        int minAreaDiff = Integer.MAX_VALUE;
        for (Size option : choices) {
            int diff = (width*height)-(option.getWidth()*option.getHeight()) ;
            if (diff >=0 && diff < minAreaDiff &&
                    option.getWidth() <= width &&
                    option.getHeight() <= height) {
                minAreaDiff = diff;
                bigEnough = option;
            }
        }
        if (bigEnough != null) {
            return bigEnough;
        } else {
            Arrays.sort(choices,new CompareSizeByArea());
            return choices[0];
        }

    }
Rakesh
  • 199
  • 1
  • 12