gpt4 book ai didi

Android 相机在 startPreview() 时卡住,没有任何错误信息

转载 作者:行者123 更新时间:2023-11-29 17:29:22 24 4
gpt4 key购买 nike

我正在编写一个应用程序来通过 Android 相机拍照。显示代码 in this question .目前我不需要处理预览帧,所以 setPreviewCallback() 不用于相机。

在具有 768MB RAM 的 HTC Sensation 设备上,相机在拍照过程中有一些奇怪的 Action 。其中之一是在拍照并在 onPictureTaken() 回调中获取数据后,startPreview()(拍摄下一张照片)给出了 RuntimeException。目前我只能捕获异常并关闭/重新打开相机作为解决方法。

但是,这个设备上有一个更严重的问题。有时我重新打开相机,但 startPreview() 给我一个没有异常或错误消息的卡住帧。我的 AP 没有崩溃。它仍然可以关闭相机并退出,但不能拍摄更多照片(我会得到 startPreview() 或 takePicture() 失败的运行时异常)。发生这种情况时,除非我重新启动设备,否则内置相机 APP 也会损坏。

作为稳定性测试,我拍摄照片,获取 JPEG 数据,但不将它们写入文件。当我拍摄大约100张照片时,我需要重新打开相机大约10次,最后相机会坏掉。如果我通过 BitmapFactory 解码内存中的 JPEG 数据(仍然不写入文件),重新打开/卡住率会大大增加。

当 startPreview() 失败时我收到这些错误消息:

E/SurfaceTexture(112): [SurfaceView] setBufferCount: client owns some buffers
E/SurfaceTextureClient(115): ISurfaceTexture::setBufferCount(7) returned Invalid argument
E/SurfaceTexture(112): [SurfaceView] dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=2 exceeded (dequeued=5)
E/QualcommCameraHardwareZSL(115): getBuffersAndStartPreview: dequeueBuffer failed for preview buffer. Error = -16

当预览卡住时,我没有收到任何错误或相关消息。当时甚至没有关于内存不足异常的消息。如果我关闭我的应用程序并启动内置相机应用程序,它会立即退出并出现以下错误:

E/MemoryHeapBase(115): mmap(fd=142, size=9011200) failed (Out of memory)
E/QualcommCameraHardwareZSL(115): Failed to get camera memory for RawZSLAdsppool heap cnt(20)
E/MemoryHeapBase(115): mmap(fd=142, size=9011200) failed (Out of memory)
E/QualcommCameraHardwareZSL(115): Failed to get camera memory for RawZSLAdsppool heap cnt(18)

...

E/QualcommCameraHardwareZSL(115): initZslBuffer X failed cnt(0)
E/QualcommCameraHardwareZSL(115): initRaw X: error initializing mRawZSLAdspMapped
E/QualcommCameraHardwareZSL(115): Init ZSL buffers X failed
E/QualcommCameraHardwareZSL(115): Failed to allocate ZSL buffers
E/QualcommCameraHardwareZSL(115): Starting ZSL CAMERA_OPS_STREAMING_ZSL failed!!!

如果我再次启动我的应用程序,我可以打开相机而不会出现上述错误,但它会在 startPreview() 或 takePicture() 时失败。然后我必须重新启动设备。由于该设备的 RAM 较小,只有 768MB,我怀疑内存不足是主要问题,尽管我没有直接从我的应用程序中获得 OOM 异常。

我已经测试了大约 500 次运行,重启设备约 15 次,发现:

  1. startPreview() 仅在拍摄照片并在相机打开后获得 onPictureTaken() 回调后失败并出现 RuntimeException。
  2. 只有当我在 startPreview() 失败后重新打开相机时才会出现预览卡住问题。当一切正常时,它不会直接从 startPreview() 发生。

我知道如果我的APP没有适当关闭相机就崩溃了,它可能会锁定相机。但是我已经检查过我的APP在问题发生后仍然关闭并释放相机(但相机在重新启动设备之前不可用)。看来相机内部有问题。谁能帮帮我?

编辑:以下是关于打开相机和开始预览的代码:

public Camera m_camera;
int m_camera_index;
int m_camera_rotation;
String m_camera_focus_mode;
int m_preview_width;
int m_preview_height;
int m_picture_width;
int m_picture_height;

SurfaceHolder m_surface_holder;
boolean m_is_during_preview;

public CameraView(Context context)
{
super(context);

m_surface_holder = getHolder();
m_surface_holder.addCallback(this);
m_surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

m_is_during_preview = false;
}

public void OpenCamera()
{
CloseCamera();

// Determine m_camera_index on this device
...

m_camera = Camera.open(m_camera_index);
if (m_camera == null)
{
LogError("Failed to open any camera.");
return;
}

try
{
m_camera.setPreviewDisplay(m_surface_holder);
}
catch (IOException e)
{
e.printStackTrace();
m_camera = null;
return;
}

// Determine m_display_orientation
...

m_camera.setDisplayOrientation(m_display_orientation);

Camera.Parameters parameters = m_camera.getParameters();

// Determine m_preview_width x m_preview_height
// and m_picture_width x m_picture_height from the supported ones
...

parameters.setPictureSize(m_picture_width, m_picture_height);
parameters.setPreviewSize(m_preview_width, m_preview_height);

// Set m_camera_rotation so we get the picture data with correct orientation
m_camera_rotation = m_display_orientation;
if (m_activity.m_is_frontal_camera)
{
m_camera_rotation = 360 - m_display_orientation;
if (m_camera_rotation == 360)
m_camera_rotation = 0;
}
parameters.setRotation(m_camera_rotation);

parameters.setPreviewFormat(ImageFormat.NV21);

// Determine m_camera_focus_mode from the supported ones
...

parameters.setFocusMode(m_camera_focus_mode);

m_camera.setParameters(parameters);

m_is_during_preview = false;
}

public void CloseCamera()
{
if (m_camera != null)
{
StopPreview();

m_camera.release();
m_camera = null;
}
}

public void RestartCamera()
{
// Only use to restart the camera when startPreview() fails after taking a picture

CloseCamera();

m_camera = Camera.open(m_camera_index);
if (m_camera == null)
{
LogError("Failed to reopen camera.");
return;
}

try
{
m_camera.setPreviewDisplay(m_surface_holder);
}
catch (IOException e)
{
e.printStackTrace();
m_camera = null;
return;
}

m_camera.setDisplayOrientation(m_display_orientation);

Camera.Parameters parameters = m_camera.getParameters();

parameters.setPictureSize(m_picture_width, m_picture_height);
parameters.setPreviewSize(m_preview_width, m_preview_height);
parameters.setRotation(m_camera_rotation);
parameters.setPreviewFormat(ImageFormat.NV21);
parameters.setFocusMode(m_camera_focus_mode);

m_camera.setParameters(parameters);

StartPreview();
}

public void StartPreview()
{
if (m_camera == null)
return;
if (m_is_during_preview == true)
return;

m_camera.startPreview();
m_is_during_preview = true;
}

public void StopPreview()
{
if (m_is_during_preview == false)
return;

if (m_camera != null)
{
m_camera.stopPreview();
}

m_is_during_preview = false;
}

拍照过程正在尝试拍摄多张(预定义数量)照片,如连拍模式:

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

private void StartPreviewAfterPictureTaken()
{
// Start preview in onPictureTaken() callback,
// which may get RuntimeException in some devices.

try
{
m_camera.startPreview();
}
catch (RuntimeException e)
{
LogError("Fail to start preview. Workaround: reopen camera.");
RestartCamera();
}
}

在许多示例代码中,startPreview() 只是在 onPictureTaken() 中调用。 StartPreviewAfterPictureTaken()流程用于处理startPreview可能失败的RuntimeException。

最佳答案

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

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

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

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

关于Android 相机在 startPreview() 时卡住,没有任何错误信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33649173/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com