在Android Things上ImageReader.OnImageAvailableListener总是由于“缓冲区已释放”而失败的原因可能是

时间:2018-09-30 14:04:00

标签: java android android-camera buffer android-things

我想用官方的Raspberry Pi相机拍照,并将其保存到临时文件夹中,以用作嵌入式http(nanoHttp)服务器的资源,以在当前版本的Android上运行的网页上显示事情。

问题是,我离目标还很遥远。我知道这通常是一个Android问题,但是对我来说,如果没有屏幕来测试其他情况,就很难调试。

我的ImageReader.OnImageAvailableListener onImageAvailableListener中总是出现“缓冲区已释放”异常(请参见代码段)。

我不知道为什么。相机可能有问题吗?噢,我的代码只是一堆可怕的错误?

代码

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());
            }
        }
    };

错误

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)

更新

@ nick-felker感谢您的帮助! 我还尝试向办公室的Android Things image classifier example学习,但没有成功。

如果相机正确识别,我会得到一堆控制台输出,原因是 我仍然收到错误:

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)

也许您可以看看class on Github

我将非常感谢每个想法如何解决我的问题。 :)

1 个答案:

答案 0 :(得分:1)

在您操作结束时,我将等待关闭所有内容。实际上,最理想的是先声明可关闭变量,然后在finally块中将它们全部关闭,以确保无论代码中间出现任何异常,都可以确保它们关闭。这也将有助于确保您的代码流仅在您确定不再使用资源时才关闭它们。

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();
  }
}