72

I have a simple program that draws the preview of the Camera into a SurfaceView. What I'm trying to do is using the onPreviewFrame method, which is invoked each time a new frame is drawn into the SurfaceView, in order to execute the invalidate method which is supposed to invoke the onDraw method. In fact, the onDraw method is being invoked, but nothing there is being printed (I guess the camera preview is overwriting the text I'm trying to draw).

This is a simplify version of the SurfaceView subclass I have:

public class Superficie extends SurfaceView implements SurfaceHolder.Callback {
 SurfaceHolder mHolder;
 public Camera camera;
 Superficie(Context context) {
  super(context);
  mHolder = getHolder();
  mHolder.addCallback(this);
  mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
 }
 public void surfaceCreated(final SurfaceHolder holder) {
  camera = Camera.open();
  try {
   camera.setPreviewDisplay(holder);
   camera.setPreviewCallback(new PreviewCallback() {
    public void onPreviewFrame(byte[] data, Camera arg1) {
     invalidar();
    }
   });
  } catch (IOException e) {}
 }
 public void invalidar(){
  invalidate();
 }
 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
  Camera.Parameters parameters = camera.getParameters();
  parameters.setPreviewSize(w, h);
  camera.setParameters(parameters);
  camera.startPreview();
 }
 @Override
 public void draw(Canvas canvas) {
  super.draw(canvas);
  // nothing gets drawn :(
  Paint p = new Paint(Color.RED);
  canvas.drawText("PREVIEW", canvas.getWidth() / 2,
    canvas.getHeight() / 2, p);
 }
}
Cristian
  • 198,401
  • 62
  • 356
  • 264
  • can u pls help me how u have done i m trying to change drawing color on button click like BUTTON1->red button2->yellow etc how will i do this using canvas ? i want to apply on live camera same as live camera effects work – Erum Nov 10 '14 at 11:11

3 Answers3

88

SurfaceView probably does not work like a regular View in this regard.

Instead, do the following:

  1. Put your SurfaceView inside of a FrameLayout or RelativeLayout in your layout XML file, since both of those allow stacking of widgets on the Z-axis
  2. Move your drawing logic into a separate custom View class
  3. Add an instance of the custom View class to the layout XML file as a child of the FrameLayout or RelativeLayout, but have it appear after the SurfaceView

This will cause your custom View class to appear to float above the SurfaceView.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • Thanks so much... that's a nice example and I'm sure that's all I need to do what I want :) – Cristian May 29 '10 at 16:21
  • @CommonsWare So will this answer that you supplied work in a situation where you are trying to overlay one surfaceview on top of another surfaceview? What do you mean by custom View class? The reason that I'm asking is because I'm facing a similar problem located here: http://stackoverflow.com/questions/3548666/overlay-images-onto-camera-preview-surfaceview – GobiasKoffi Aug 24 '10 at 15:05
  • @rohanbk: You cannot overlay two `SurfaceView` widgets, as I understand it. "What do you mean by custom View class?" -- your own subclass of `android.view.View`, or your own subclass of an existing widget class. – CommonsWare Aug 24 '10 at 22:14
  • @CommonsWare So, in your honest opinion, would there be any way for me to modify the SurfaceViewOverlay example in the API demos (http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/SurfaceViewOverlay.html) so that I can draw bitmap images in a surfaceview on top of a camera surfaceview using the FrameLayout? – GobiasKoffi Aug 25 '10 at 02:29
  • @rohanbk: You do not need a `SurfaceView` to draw bitmap images. For example, `ImageView` does not use a `SurfaceView`, AFAIK. – CommonsWare Aug 25 '10 at 04:20
  • @CommonsWare I'm building an Augmented Reality tool, so I need to update the positions of many images (the images are 50x50px png files) on the screen very rapidly. I tried using a View, but it wasn't fast enough. I used a SurfaceView to draw the images, and it worked, but I wasn't able to overlay it onto the camera (since according to you, surfaceview overlaying doesn't work). Will an ImageView be able to quickly render images on the phone screen? Also, thank you for all the help you've given. I really appreciate it. – GobiasKoffi Aug 25 '10 at 14:39
  • @rohanbk: I have no idea how the AR apps do it -- sorry! – CommonsWare Aug 25 '10 at 21:28
  • @CommonsWare Thanks for all the other advice though. I've been grappling with a means to overlay a rapidly updating view on top of a live camera feed for a while now. – GobiasKoffi Aug 26 '10 at 04:56
  • @GobiasKoffi : Budy i think u have done with what i want. See here: http://stackoverflow.com/questions/7749480/how-to-set-just-a-green-camera-view-with-the-l-e-d-light-in-android/7749522#7749522 – Shreyash Mahajan Oct 13 '11 at 04:58
  • @GobiasKoffi : I need your help to implement such camera effect with canvas in android. So Please help me in this. It will be realy appreciate. – Shreyash Mahajan Oct 13 '11 at 04:59
  • @iDroidExplorer I ended up going with OpenGL-ES. It has a steep learning curve, but it will do what you're trying to do. I haven't touched any Android code in the past year as my academic and professional focus shifted, so good luck with what you're trying to do :) – GobiasKoffi Oct 20 '11 at 21:27
  • You can do it easily using AndEngine and its andengineaugmentedrealityextension. Unfortunately, the extension itself is lesser GPL licensed. – Yar Apr 15 '12 at 13:58
  • @CommonsWare Any idea on how to record a video that combines the surface preview and the overlay together? – GuyZ Jun 30 '16 at 12:17
  • @GuyZ: Other than the media projection APIs (to record the entire screen), I do not know how to do this. That's not saying there is no solution, but this is not a problem area that I have investigated. – CommonsWare Jun 30 '16 at 13:55
  • @CommonsWare I'm talking about a SnapChat like solution. Add a face blur to a recorded video for example... – GuyZ Jun 30 '16 at 14:11
  • @CommonsWare , I want to watermark video with help of ffmpeg , like stickers are added to video, I know how to use ffmpeg, but my problem is to get the position and rotation of sticker on surfaceview any help that you can provide would be useful my question is here https://stackoverflow.com/questions/43963522/android-stickers-on-video-using-ffmpeg – 1234567 May 17 '17 at 11:17
  • @CommonsWare The link is dead now, please update. – Shailendra Madda Jun 10 '21 at 14:45
17

Try calling setWillNotDraw(false) from surfaceCreated:

public void surfaceCreated(SurfaceHolder holder) {
    try {
        setWillNotDraw(false); 
        mycam.setPreviewDisplay(holder);
        mycam.startPreview();
    } catch (Exception e) {
        e.printStackTrace();
        Log.d(TAG,"Surface not created");
    }
}

@Override
protected void onDraw(Canvas canvas) {

    canvas.drawRect(area, rectanglePaint);
    Log.w(this.getClass().getName(), "On Draw Called");
}

and calling invalidate from onTouchEvent:

public boolean onTouch(View v, MotionEvent event) {

    invalidate();
    return true;
}
BartoszKP
  • 34,786
  • 15
  • 102
  • 130
mchouhan_google
  • 1,775
  • 1
  • 20
  • 28
1

I think you should call the super.draw() method first before you do anything in surfaceView's draw method.

Stephan Branczyk
  • 9,363
  • 2
  • 33
  • 49