2

On one of my two devices, onPreviewFrame is not called, despite me using the same code.

I am trying to get, process (with OpenCV) and then display the camera frames using the deprecated camera API. (Because I am using a LEGACY device and the deprecated API provides better performance for it.)

This means that I do not want to directly display the preview frames, but I was able to determine that on this device, setting a display is necessary for previews to be taken. This means I have to set some sort of high-performance dummy display. My options are: setPreviewDisplay -> SurfaceHolder and setPreviewTexture -> SurfaceTexture.

Another thing I learned is that setPreviewCallbackWithBuffer does not work either on this device: I have to use setPreviewCallback.

Ideally, I would want to detect whether I need these extra steps for previews to work: if not necessary, I do not want to do these on devices which do not require them.

I was unable to find a dummy SurfaceHolder for the setPreviewDisplay method, therefore I wasn't able to get preview callbacks to be called using that. On the other hand, setPreviewTexture with a new SurfaceTexture does make the onPreviewFrame get called, but I am constantly getting "BufferQueue has been abandoned" errors and the preview data seems incorrect as well: while I set the image format, the image created from said data is incorrect. Looking at different colors causes the image to show different colors. Again, the same code worked on another device and I set the image format, therefore the output should be valid.

My current code, where onPreviewFrame is called, but with invalid data:

camera = Camera.open();
camera.setPreviewTexture(new SurfaceTexture(1));
camera.setPreviewCallback(this);
camera.setParameters(configurator.getParameters()); //sets the resolution (same on both devices), the fps range and the format to ImageFormat.YV12 (or NV21, makes no difference)
camera.startPreview();

The phone for which a preview display is not necessary: Doogee X5 MAX
The phone which had issues: Samsung Galaxy J3 (2016)

Trigary
  • 366
  • 4
  • 14
  • Welcome to the club! Don't expect working with camera to be easy. – Alex Cohn Feb 03 '19 at 07:48
  • *Re:* image format and correct colors. Please provide more info: which format you tried, what colors you get (a sample image would be nice). If you can disclose the device model, it could also be extremely helpful both to answer your question and for other developers who may get stuck with the same problem. – Alex Cohn Feb 03 '19 at 08:10
  • *Re:* setPreviewCallbackWithBuffer() – this is essential for high performance camera, as correct threading. Please explain *how* it does not work. – Alex Cohn Feb 03 '19 at 08:22
  • 1
    @AlexCohn I'm afraid I don't know how, but I got rid of the invalid preview output issue. I think this output was similar to the one shown [here](https://stackoverflow.com/questions/13350490/android-camera-preview-is-incorrect-on-samsung-galaxy-s3/13407925). Regarding the buffers: I think I know what happened (I am really unsure to be honest), see my answer. Thank you very much for all of your help! – Trigary Feb 03 '19 at 09:37

2 Answers2

1

Re: dummy preview texture, this is the best workaround you can get. The official API requires that preview must go somewhere, and most devices enforce this policy.

There is no way to check at runtime whether the device delivers live preview without a 'sink' (surface or texture) to draw upon. In other similar situations, we are forced to maintain white-lists and black-lists of devices, based on QA lab experiments and end-user complaints. For some features, the technique is to try the optimal setup on the first run of your app (on the specific device), and, if it crashes or fails otherwise, use a less efficient alternative on the second attempt, and keep this flag in SharedPreferences for future launches.

Luckily, adding a dummy SurfaceTexture does not negatively effect performance even on devices that can work without it.

To avoid "BufferQueue has been abandoned" errors, add the dummy SurfaceTexture as a field in your activity or fragment.

Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
1

setPreviewCallbackWithBuffer wasn't working because the buffer was too small. I did not see the error until I got rid of the "BufferQueue has been abandoned" errors. The reason for the buffer being too small is that:

  • I did not query the preview size, I just used the value I set the preview size to

  • I called Camera.Parameters#setRecordingHint(true), which locked my resolution (and probably other settings as well) to hardcoded values. This resolution is not the same as the one I selected, therefore my buffer was indeed too small.

Trigary
  • 366
  • 4
  • 14
  • 1
    That's another common platform bug: some devices ignore or misinterpret the parameters we pass to camera. Sometimes, they lie about supported features, sizes, etc. Note that any call to camera, and especially **setParameters()** may throw a RuntimeException, sometimes for no legitimate reason. – Alex Cohn Feb 03 '19 at 10:46