如何在 Android 中线程化相机回调?

How to thread camera callbacks in Android?

我正在编写一个 Android 应用程序,它从相机获取持续更新并在调用 onPreviewFrame(byte[] data, Camera camera) 时处理它们。

问题是 onPreviewFrame 每秒仅被调用 8-10 次,而不是 30 次(我预计对于 30 FPS 的相机)。我认为这是因为我的 UI 正在接收所有相机回调,而不是一个单独的线程。

这是我的 SurfaceView,它持有相机并接收相机回调:

public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback, Callback {
private Camera mCamera;
...
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
                @Override
                public void onPreviewFrame(byte[] data, Camera camera) {
                    //Frame received (about 8 per second)

这是我打开相机的代码(在我的主程序中 activity):

final Camera camera = getCameraInstance();    //calls camera.open()

mPreview = new CameraPreview(this, camera);

我应该如何使用线程、Asynctask 或 Handler 来让相机回调发生在一旁?我如何在 UI 线程中接收这些更新?

是的,将在主 (UI) 线程上调用回调。根据 Documentation 来自其他方法的所有相机回调都被传递到调用 open() 的线程的事件循环。
这意味着如果线程没有任何事件循环,则回调将传递到主应用程序事件循环。如果没有主应用程序事件循环,则根本不会传递回调。

在那种情况下,由于 onPreviewFrame 在主线程上被调用,因此在执行 UI 操作(例如显示动画)时处理巨大像素矩阵的任务可能会卡住, 打开菜单或即使消息打印在屏幕上。

一个解决方案是创建一个新的 HandlerThread。 HandlerThread 可以方便地启动一个具有内置循环机制的新线程。

此外,请尝试使用 setPreviewCallbackWithBuffer(),而不是 setPreviewCallback(),因为它会重复使用一个缓冲区,而不必在每一帧上分配新的缓冲区。它通过允许重用预览帧内存来提高预览效率和帧速率。

a good tutorial for understanding Looper, AsyncTask and HandlerThread

请看这里

这是我的答案,这个问题困扰了我几个星期。

在我的例子中,我的相机是从一个用低级 C 代码创建的线程启动的。

但正如@Pavitra Kansara 回答的那样,线程需要一个事件循环,如果不需要,则可能会调用 onPreviewFrame。因此,您需要将相机打开的函数调用返回到主线程(UI),它是这样的:

((SomeActivity)context).runOnUiThread(new Runnable() {
        @Override
        public void run() {
            try {
                open camera funcalls ...
            }
            catch (Exception e) {
                e.printStackTrace();
            }
        }
    });