Я пишу APP для съемки с камеры Android. Коды показаны in this question. В настоящее время мне не нужно обрабатывать рамку предварительного просмотра, поэтому setPreviewCallback() не используется для камеры.Камера для Android замораживается при запуске (без ошибок)
На устройстве HTC Sensation с ОЗУ 768 МБ камера имеет некоторые странные действия в процессе съемки. Одним из них является то, что после съемки и получения данных в обратном вызове onPictureTaken() startPreview() (чтобы сделать следующее изображение) дает исключение RuntimeException. В настоящее время я могу только поймать исключение и закрыть/снова открыть камеру в качестве обходного пути.
Однако на этом устройстве существует более серьезная проблема. Иногда я снова открываю камеру, но startPreview() дает мне замороженный фрейм без исключения или сообщение об ошибке. Мой AP не падает. Он все равно может закрыть камеру и выйти, но не может делать больше снимков (я получаю исключение во время выполнения startPreview() или takePicture() сбой). Когда это произойдет, встроенная камера APP также будет отключена, если я не перезапущу устройство.
Как тест стабильности, я беру фотографии, получаю данные JPEG, но не записываю их в файлы. Когда я беру около 100 фотографий, мне нужно снова открыть камеру примерно 10 раз, и, наконец, камера сломается. Если я дешифровать данные JPEG в памяти BitmapFactory (все еще не записывать в файлы), скорость повторного открытия/замораживания значительно увеличивается.
я получаю эти сообщения об ошибке при 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
Когда предварительный просмотр замерзает, я не получаю сообщение об ошибке или связанных сообщений. В то время даже нет сообщения об исключении из памяти. Если я закрываю приложение и запустить встроенную камеру APP, он выходит сразу с этими ошибками:
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(). Затем я должен перезапустить устройство. Поскольку у устройства небольшой размер оперативной памяти 768 МБ, я подозреваю, что основной проблемой является нехватка памяти, хотя я не получаю исключение OOM непосредственно из своего APP.
я испытал около 500 пробегов с ~ 15 раз перезапуска устройства, и обнаружили, что:
- startPreview() не только с RuntimeException после съемки и получать onPictureTaken() обратного вызова, так как камера открыта ,
- Предварительный просмотр замороженной проблемы возникает только при повторном открытии камеры после сбоя startPreview(). Это происходит не сразу от startPreview(), когда все в порядке.
Я знаю, что если мой APP аварийно завершает работу, не закрывая камеру, он может заблокировать камеру. Но я проверил, что мой APP все еще закрывается и отпускает камеру после того, как проблема (но камера недоступна до перезапуска устройства). Кажется, что что-то не так внутри камеры. Может ли кто-нибудь мне помочь?
Edit: Вот коды об открытии камеры и начала просмотра:
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() используется для обработки возможного исключения RuntimeException для startPreview.
Мы не знаем, как вы устанавливаете камеру в первую очередь. Покажите код, в котором вы инициализируете камеру, и как вы делаете снимки. –
почему вы не используете вспомогательную библиотеку .... проверьте, что у GitHub есть как минимум 10 полезных. не изобретать велосипед. – OWADVL
Что бы вы порекомендовали @OWADL –