0

I want to take a picture with the official Raspberry Pi Camera and save it to a temp folder to use it as an resource for an embedded http (nanoHttp) server to show it on a web page running on the current version of Android Things.

The problem is, that I'm far away from my goal. I know that this is more a Android question in general but it is for me relative hard to debug without a screen to test other scenarios.

I get always a "buffer has been freed" exception in my ImageReader.OnImageAvailableListener onImageAvailableListener (see code snippet).

I don't know why. Maybe something is wrong with the camera? O is just my code a horrible bunch of mistakes?

Code

private ImageReader.OnImageAvailableListener onImageAvailableListener = new ImageReader.OnImageAvailableListener()
    {
        @Override
        public void onImageAvailable(ImageReader imageReader)
        {
            Log.d(TAG, "Camera image listener triggered");

            try
            {
                Image image = imageReader.acquireLatestImage();
                ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer();
                byteBuffer.rewind();
                image.close();

                File file = File.createTempFile("test.jpg", null, getApplicationContext().getCacheDir());

                if (!file.exists())
                {
                    file.createNewFile();
                }

                BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter(file, false));
                bufferedWriter.write(byteBuffer.asCharBuffer().array());
                bufferedWriter.close();

                Log.d(TAG, "Camera image listener wrote to file: " + file.getAbsolutePath());
            }
            catch (IOException e)
            {
                Log.e(TAG, "Camera image saving failed with error; " + e.getLocalizedMessage());
            }
        }
    };

Error

E/AndroidRuntime: FATAL EXCEPTION: CameraThread
    Process: com.example.app, PID: 2634
    java.lang.IllegalStateException: buffer has been freed
        at java.nio.DirectByteBuffer.asCharBuffer(DirectByteBuffer.java:428)
        at com.example.org.MainActivity$1.onImageAvailable(MainActivity.java:115)
        at android.media.ImageReader$ListenerHandler.handleMessage(ImageReader.java:812)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)

UPDATE

@nick-felker thanks for helping me out! I also tried to learn from the office Android Things image classifier example, but with no success.

The camera if recognized correctly, I get a bunch of console output due to the I still get the error:

D/TobbotActivity: Camera - onImageAvailable triggered
W/ImageReader_JNI: Unable to acquire a buffer item, very likely client tried to acquire more than maxImages buffers
W/AndroidMediaUtils: Image_getJpegSize: No JPEG header detected, defaulting to size=width=480252
E/AndroidRuntime: FATAL EXCEPTION: BackgroundThread
    Process: io.github.tscholze.tobbot, PID: 2492
    java.lang.UnsupportedOperationException
        at java.nio.CharBuffer.array(CharBuffer.java:713)
        at io.github.tscholze.tobbot.TobbotActivity.onImageAvailable(TobbotActivity.java:238)
        at android.media.ImageReader$ListenerHandler.handleMessage(ImageReader.java:812)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:164)
        at android.os.HandlerThread.run(HandlerThread.java:65)

Maybe you could have a look at the class on Github.

I would be very grateful for each ideas how to solve my issue. :)

Tobonaut
  • 2,245
  • 2
  • 26
  • 39
  • `byteBuffer` is baked of `byte`s, not `char`s, even though you use `asCharBuffer()` on it. This [results in UnsupportedOperationException](https://developer.android.com/reference/java/nio/CharBuffer.html#array()). Check if the array is accessible with `hasArray()`. If won't help, then first [Convert a byte array to a string?](https://stackoverflow.com/q/9655181/3290339). – Onik Oct 02 '18 at 19:39
  • 1
    @Onik sorry for not responding to you. This is my spare time project, I do not have that much spare time in the last few days. I'll let you know after I tested it. But thank you in advanced for your time and help! – Tobonaut Oct 06 '18 at 17:18

1 Answers1

1

I'd wait to close everything at the end of your operations. In fact, it would be ideal to declare your closeable variables up-front and then close them all in the finally block so that you can be sure they close regardless of any exceptions that appear in the middle of your code. It will also help ensure your codeflow will only close resources when you can be sure they're no longer used.

Image image = null;
File file = null;
BufferedWriter bufferedWriter = null;

try {
  image = imageReader.acquireLatestImage();
  ByteBuffer byteBuffer = image.getPlanes()[0].getBuffer();
  byteBuffer.rewind();

  file = File.createTempFile("test.jpg", null, getApplicationContext().getCacheDir());

  if (!file.exists()) {
      file.createNewFile();
  }

  bufferedWriter = new BufferedWriter(new FileWriter(file, false));
  bufferedWriter.write(byteBuffer.asCharBuffer().array());

  Log.d(TAG, "Camera image listener wrote to file: " + file.getAbsolutePath());
} catch (IOException e) {
  Log.e(TAG, "Camera image saving failed with error; " + e.getLocalizedMessage());
} finally {
  if (image != null) {
    image.close();
  }
  if (file != null) {
    file.close();
  }
  if (bufferedWriter != null) {
    bufferedWriter.close();
  }
}
Nick Felker
  • 11,536
  • 1
  • 21
  • 35