Android 拍摄多张照片时 camea startPreview() 失败

Android camea startPreview() fails when taking multiple pictures

我正在编写一个用相机拍摄多张照片的应用程序。 (就像 Camera2 中的连拍模式,但我正在研究旧版本。) 它由 takePicture() / onPictureTaken() 回调实现,并且在一些设备上正常工作,除了一些性能问题。但是,当我尝试开始第二张图片的预览时,在 HTC Sensation 设备上遇到 startPreview 的 RuntimeException 失败。

关于连拍的功能如下:

final int multishot_count = 3;

....

public void TakePicture()
{
    // Invoke multishot from UI when the camera preview is already started.

    // startup of multishot task
    ...

    m_take_picture_count = 0;

    TakeOnePicture();
}

private void TakeOnePicture()
{
    m_camera.takePicture(null, null, new Camera.PictureCallback()
    {
        @Override
        public void onPictureTaken(byte[] data, final Camera camera) 
        {
            m_take_picture_count++;

            // feed the JPEG data to a queue and handle it in another thread
            synchronized(m_jpeg_data_lock)
            {
                int data_size = data.length;
                ByteBuffer buffer = ByteBuffer.allocateDirect(data_size);
                buffer.put(data, 0, data_size);

                m_jpeg_data_queue.offer(buffer);

                if (m_take_picture_count == multishot_count)
                    m_is_all_pictures_taken = true;
            }

            if (m_take_picture_count < multishot_count)
            {
                m_camera.startPreview();
                TakeOnePicture();
            }
            else
            {
                // Finalize the multishot task and process the image data
                EndTakePictureTask end_take_picture_task = new EndTakePictureTask();
                end_take_picture_task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            }
        }
    });
}

拍摄第一张照片后,startPreview() 函数可能会在指定设备上以 10-20% 的比率失败。我的应用程序总是 运行 在前台,并且有一个可见的视图来显示预览帧。 JPEG数据我也尝试绕过不处理,还是报错

我找到了类似的报告at here。好像拍照的底层线程没有完成它的工作,但我们没有办法检查它。所以我尝试从 startPreview() 捕获异常并睡一会儿:

            if (m_take_picture_count < multishot_count)
            {
                boolean is_try_start_preview = true;
                while (is_try_start_preview)
                {
                    try
                    {
                        m_camera.startPreview();
                        is_try_start_preview = false;
                    }
                    catch (RuntimeException e)
                    {
                        try
                        {
                            Thread.sleep(50);
                        }
                        catch (InterruptedException e2)
                        {
                            e2.printStackTrace();
                        }
                    }
                }

                TakeOnePicture();
            }

但是一旦startPreview失败,不管我睡多少次都会永远失败

我还发现您需要为旧 Android 版本中的表面支架调用 setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS) 才能让 startPreview() 正常工作。但是设备有 Android 版本 4.0.3,应该不需要这个调用。我仍然尝试添加它,但问题仍然存在。此外, startPreview() 的第一次调用工作正常,而 onPictureTaken() 之后的第二次调用出现错误。这与旧版本中缺少 setType() 的问题不同。

最后我使用了一个可能会严重影响性能的解决方法:

            if (m_take_picture_count < multishot_count)
            {
                try
                {
                    m_camera.startPreview();
                }
                catch (RuntimeException e)
                {
                    // Fail to start preview. Workaround: reopen camera.
                    RestartCamera();
                }

                TakeOnePicture();
            }

也就是说,当 startPreview() 失败时,我只是关闭相机,以相同的设置重新打开它,然后开始预览以拍摄另一张照片。

我想知道我是否遗漏了一些关于拍照 API 的信息,是否有比这种蛮力解决方法更好的解决方案。

感谢 Alex Cohn 的建议,我找到了解决方案。此解决方案仅在 HTC Sensation 设备上进行了测试,但在该设备上效果显着。

我只是在将在 onPictureTaken() 中调用的 startPreview() 之前放置了一个睡眠指令:

try
{
    Thread.sleep(20);
}
catch (Exception e)
{
    e.printStackTrace();
}

然后我运行测试了100次,每次运行连续拍摄3张照片。随着睡眠,我在 100 运行 秒内没有从 startPreview() 收到任何错误。如果没有休眠,我需要在100运行秒内重新打开相机78次,并重启设备8次。