【问题标题】:How to thread camera callbacks in Android?如何在Android中线程相机回调?
【发布时间】:2016-02-01 01:25:21
【问题描述】:

我正在编写一个 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)

这是我打开相机的代码(在我的主要活动中):

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

mPreview = new CameraPreview(this, camera);

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

【问题讨论】:

标签: android multithreading optimization camera android-handler


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

    在这里查看a good tutorial for understanding Looper, AsyncTask and HandlerThread

    【讨论】:

    • 我用 setPreviewCallbackWithBuffer() 替换了 setPreviewCallback(),现在回调为零。我不知道怎么了。
    • 谢谢!使用 HandlerThread 将我每秒的回调从 10 次左右增加到 25 次左右。
    • @Piglet 你是如何解决无回调触发问题的?我在 HandlerThread 中打开相机,但 onPreviewFrame callbak 没有执行。我在 CameraPreview(扩展 SurfaceView)视图中的 surfaceChanged 事件上设置 .setPreviewCallbackWithBuffer(this)。
    猜你喜欢
    • 1970-01-01
    • 2019-05-18
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    • 2015-04-06
    • 1970-01-01
    相关资源
    最近更新 更多