1

I'm trying to incorporate some camera-related features in my app. I open the camera manually and get the preview stream with setPreviewCallback and startPreview. I do not use the surface for displaying preview, but I do set it to comply with the Camera API docs. This is how I open the camera:

public Camera openCamera(int id)
{
    m_openedCamera = Camera.open(id);
    m_surfaceHolder = new SurfaceView(MyApplication.instance().getApplicationContext()).getHolder();
    Assert.assertNotNull(m_openedCamera);
    m_openedCamera.setPreviewDisplay(m_surfaceHolder);
    m_openedCameraFacing = facing;
    if (m_openedCamera != null)
        m_openedCamera.setPreviewCallback(this);
    m_openedCamera.startPreview();
}

And this is how I release it, nothing fancy here:

public void releaseCamera()
{
    if (m_openedCamera != null)
    {
        m_openedCamera.stopPreview();
        m_openedCamera.release();
        m_openedCamera = null;
    }
}

It kinda works at first, but as I release the camera, I get an exception "Method called after release()". To clarify: I do not call any camera methods after the camera has been released. Double and triple-checked under debugger that I don't. I think there's a mix of synchronous and asynchronous calls here that causes the problem.

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
  • checkout [this](http://stackoverflow.com/a/8003222/1288725) if it helps, the problem may get solved if you add `mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);` in your code as stated in answer. – Mehul Joisar Oct 08 '14 at 14:27
  • @MehulJoisar: please read my question carefully and realize I have no surface or holder whatsoever. – Violet Giraffe Oct 08 '14 at 17:04
  • Using no preview surface (or its OpenGL equivalent) is illegal and may lead to different problems on different devices. If I understand correctly, your purpose is to switch from the back facing camera to the front facing. Please understand that these two different devices **may** handle this key differently – Alex Cohn Oct 08 '14 at 20:14
  • @AlexCohn: not neccessarily to switch, right now I'm working with the same camera. But yes, the main purpose is switching cameras. Also, I think you're wrong, the documentation doesn't say I *must* use a display surface. That's just a convenience helper. I don't need it in my app. – Violet Giraffe Oct 09 '14 at 06:56
  • It's not a convenience helper. See [android.hardware.Camera](http://developer.android.com/reference/android/hardware/Camera.html#startPreview()): **startPreview()** *Starts capturing and drawing preview frames to the screen. Preview will not actually start until a surface is supplied with setPreviewDisplay(SurfaceHolder) or setPreviewTexture(SurfaceTexture)*. – Alex Cohn Oct 09 '14 at 11:49
  • @AlexCohn: thank you, I've missed that part. Still, preview works fine for me with no surface on 2 vastly different devices, one with Android 3.1 and one with 4.2.2. Anyway, can I set a dummy holder or texture that I won't use anywhere else? – Violet Giraffe Oct 09 '14 at 12:00
  • 1
    Sure you can. On 3.0 and higher it is easier to achieve with setPreviewTexture(). There is a long list of hacks workarounds in _[this SO topic](http://stackoverflow.com/questions/2386025/android-camera-without-preview)_. – Alex Cohn Oct 09 '14 at 15:04
  • Anyways, Camera.release() may take time, and Camera.open() - even more time. But both these calls are blocking. – Alex Cohn Oct 09 '14 at 15:07
  • If you continue to see problems with switching camera, please post the logcat (including all camera messages coming from the MediaServer process), and disclose which device and ROM you are using. – Alex Cohn Oct 09 '14 at 15:09
  • @AlexCohn: `release` is blocking, but what about `stopPreview` call? – Violet Giraffe Oct 10 '14 at 08:31
  • @AlexCohn: I have changed the question, please take a look if you can. – Violet Giraffe Oct 10 '14 at 08:53
  • Isn't this the preview callback that causes the exception? `onPreviewFrame()` is not synchroneous, and it receives a Camera parameter that may become invalid when `Camera.release()` is performed. This could happen even if callbacks happen in the same thread. You can call `setPreviewCallback(null)`, and keep a global flag to discard callbacks after the camera is released. – Alex Cohn Oct 10 '14 at 10:09
  • @AlexCohn: good catch, but that is certainly not my case. I've edited my question to reflect the most recent debugging conclusion I've got: it is `releaseCamera()` alone that causes the problem. I don't have to call `open` for it to occur. Also, I never use the `Camera` parameter of the callback. – Violet Giraffe Oct 10 '14 at 10:26
  • Tried `setPreviewCallback(null)`? – Alex Cohn Oct 10 '14 at 11:35
  • @AlexCohn: I took your advice (`setPreviewCallback(null)`), and all the problems I've been fighting for the past 2 days are gone! Please make this an answer. – Violet Giraffe Oct 10 '14 at 11:35

1 Answers1

5

The preview callback could cause this exception. onPreviewFrame() is not synchroneous, and it receives a Camera parameter that may become invalid when Camera.release() is performed. This could happen even if callbacks are not using a separate thread (highly recommended).

Before release(), call setPreviewCallback(null), and keep a global flag to discard callbacks after the camera is released.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • You recommend a separate thread for camera callbacks, did I get that right? How do I do that? By initializing the camera in a separate thread? – Violet Giraffe Oct 10 '14 at 12:46
  • 1
    Yes, by `Camera.open()` from a _[separate event thread](http://stackoverflow.com/questions/18149964/best-use-of-handlerthread-over-other-similar-classes)_ – Alex Cohn Oct 10 '14 at 21:09