really confused with setPreviewCallback in Android, need advice

10,831

Solution 1

Are you calling setPreviewDisplay(), startPreview() and setPreviewCallback(this) from the app? Without that you will not get any calls to onPreviewFrame(). In fact if you are using SurfaceView, then the callback preview buffers are a copy of the actual buffers that are being displayed on the screen. So if you want to display these copied buffers, you need to create a new view and overwrite it. This would be inefficient. I would suggest you use SurfaceTexture instead and use 'onFrameAvailable' callback to get the frames and then draw & display manually. An example of this can be found in the PanoramaActivity code of the default Android Camera App.

Solution 2

Without camera_object.setPreviewDisplay(surface_holder); you cannot receive camera callbacks; don't forget also

surface_view.setVisibility(View.VISIBLE);
surface_holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

You can hide the camera preview under another view; on 3.0 and higher you can even push the surface out of the screen (display it below the bottom of the screen). I am not sure if the latter trick works on 2.3.6.

Share:
10,831
Mohamed Heiba
Author by

Mohamed Heiba

Updated on June 04, 2022

Comments

  • Mohamed Heiba
    Mohamed Heiba almost 2 years

    I'm building an application on Android to take frames from the camera, process them, and then display the frame on a surfaceView, as well as drawing on the SurfaceView via the canvas and drawbitmap and all.

    Just to check, is SurfaceView and Bitmaps and Canvases the best way to do it ? I'm after speed.

    Assuming the answer to the above is Yes, the question would be: Where should I place the following function

    camera_object.setPreviewCallback(new PreviewCallback()
         public void onPreviewFrame(byte[] data, Camera camera){
    

    should I place it in onCreate() or should I place it in surfaceCreated() or surfaceChanged() ?

    I declared my mainactivity class as follows:

    public class MainActivity extends Activity implements SurfaceHolder.Callback, Camera.PreviewCallback
    {
    

    and in that class Eclipse forces me to create an override function for onpreviewframe in the MainActivity class as follows

    public void onPreviewFrame(byte[] data, Camera camera){
    }
    

    but it never gets called. Should I try to use this function ? is it better to use it ? or is it just an Eclipse thing ?

    Please advise

  • Mohamed Heiba
    Mohamed Heiba almost 12 years
    Thank you very much for your response. What I'm doing is, yes I use the following surface_view = (SurfaceView) findViewById(R.id.surfaceview1); surface_holder = surface_view.getHolder(); surface_holder.addCallback(this); and camera_object.startPreview(); but I don't use camera_object.setPreviewDisplay(surface_holder); because I don't want to display the actual frames, I only want to display the ones from the callback. I will check SurfaceTexture looks very promising
  • Mohamed Heiba
    Mohamed Heiba almost 12 years
    I think I know why I didn't consider SurfaceTexture, cause it only starts from API 11, I've got API 10 (Android 2.3.3) my phone has android 2.3.6 do you think SurfaceTexture can work on it ?
  • Mohamed Heiba
    Mohamed Heiba almost 12 years
    Hi, What I do is that I actually grab the frame from the onpreviewframe, convert to Bitmap, use the canvas to hold surface, draw the bitmap image and draw on the bitmap image also using canvas
  • vikky.rk
    vikky.rk almost 12 years
    I don't think so. Your only way out it to replace the view with your own view. But your frame-rate would be affected. Also you have to use camera_object.setPreviewDisplay(surface_holder) without which the Camera hardware has no buffers to write data to. It will dequeue the buffers from the surface and write data to it. So you need to send the surface.
  • Mohamed Heiba
    Mohamed Heiba almost 12 years
    Guys I got it working fine without using setpreviewdisplay, I don't want the camera frames to be rendered directly on the surfaceview, instead I take those frames, process them, using canvas to draw them and draw on them. But the problem is that this is very slow. If I used setpreviewdisplay, my processed frames will be out of sync from the rendered display, so the squares will only show on faces like 2 seconds late during which the face will have moved to a different place in the screen, I'm doing face detection btw
  • vikky.rk
    vikky.rk almost 12 years
    I see, you are right. The frame that is received through callback is not the same that is being displayed. Onpreviewframe callback is not in sync with preview frames. Yes you don't need to do set preview display then.
  • vikky.rk
    vikky.rk almost 12 years
    But don't be sure that it works on every device. Some hardware vendor might not be sending a callback if previewDisplay is not set. It depends on the implementation.
  • Mohamed Heiba
    Mohamed Heiba almost 12 years
    Yeah I know HTC ONE X for instance will never work without setpreviewdisplay :D crazy!
  • Alex Cohn
    Alex Cohn almost 12 years
    This is OK, but very slow... It is significantly faster to use OpenGL rendering for the grabbed frames.