7

I'm using a SurfaceView with a SurfaceHolder to start off with a camera preview in my test app.

public class TextLocatorActivity extends Activity {

    private Preview pvw;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);

        pvw = new Preview(this);
        setContentView(pvw);        
    }   

I want to use the CameraPreview (comes with the SDK Samples for SDK version 7). A click on the UI takes a picture. Here's the Preview class:

public class Preview extends SurfaceView implements OnClickListener, SurfaceHolder.Callback {

SurfaceHolder holder;
Camera cam; 

final static String TAG = "TextLocator:Preview";

Preview(Context context) {
    super(context);

    holder = getHolder();
    holder.addCallback(this);
    this.setOnClickListener(this);
    // seems to be required (although the docs state, this enum is deprecated, as the type will be chosen automatically...
    holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void surfaceCreated(SurfaceHolder holder) {
    cam = Camera.open();
    try {
        Camera.Parameters params = cam.getParameters();
        params.set("orientation", "landscape");
        Camera.Size bestSize = getBestPreviewSize(480, 320);
        params.setPreviewSize(bestSize.width, bestSize.height);
        cam.setParameters(params);
        // where to draw:
        cam.setPreviewDisplay(holder);
    } catch (IOException exception) {
        cam.release();
        cam = null;
        // TODO: add more exception handling logic here
    }
}

private Camera.Size getBestPreviewSize(int width, int height)
{
    // checks for supported sizes close to the demanded values - implemented.
}


public void surfaceDestroyed(SurfaceHolder holder) {
    cam.stopPreview();
    cam.release();
    cam = null;
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
    Camera.Parameters parameters = cam.getParameters();
    parameters.setPreviewSize(w, h);

    cam.setParameters(parameters);
    cam.startPreview();
}

Camera.PictureCallback picCallback = new Camera.PictureCallback() {

    public void onPictureTaken(byte[] bytes, Camera arg1) {
        synchronized(holder) {
                Canvas c = null;    

                try {
                    c = holder.lockCanvas();                

                    Paint paint = new Paint();
                    paint.setAntiAlias(false);
                    paint.setARGB(200, 120, 180, 0);

                    c.drawLine(10, 10, c.getWidth() - 10, c.getHeight() - 10, paint);
                }
                catch (Exception e) {
                    Log.d(TAG, "Exception: " + e.getMessage());
                    // IllegalArguementException Surface Type is SURFACE_TYPE_PUSH_BUFFERS
                }
                finally {       
                    holder.unlockCanvasAndPost(c);  
                }
            }
    }
};

public void onClick(View v) 
{
    cam.takePicture(null, null, picCallback);    
}

}

Next I'm trying to do some additional painting to the corresponding Canvas of the SurfaceHolder. Therefore I'm calling canvas = holder.lockCanvas(). This will result in an IllegalArgumentException with the Message:

Surface type is SURFACE_TYPE_PUSH_BUFFERS

Now, docs state that those Surface Types are deprecated, the value set will be ignored. However, the camera preview only works, if I set the type to this specific value.

How can I achieve drawing on the Canvas of the SurfaceView the picture taken is displayed in? Or should that be put on a different layer/view?

rdoubleui
  • 3,554
  • 4
  • 30
  • 51
  • 1
    Concerning my closing question, there's such an approach to use an extra view and draw on that. It's using `RealtiveLayout` or `FrameLayout` to preserve the z-order of the `SurfaceView` and that overlay: http://stackoverflow.com/questions/2933882/how-to-draw-an-overlay-on-a-surfaceview-used-by-camera-on-android – rdoubleui Jun 14 '11 at 20:31
  • FYI: The workaround in the link above was helpful and I ended up using this approach by using an extra view above the camera preview. – rdoubleui Jul 19 '11 at 11:46

1 Answers1

5

You cannot both display the camera preview and draw with a Canvas. You have to do one or the other.

Romain Guy
  • 97,993
  • 18
  • 219
  • 200
  • While that surely is the true, could you elaborate or give some hint about where to find some documentation on this topic? Because I thougt Android would simply load the buffer of the preview onto the view and I should be able to draw on it. – rdoubleui Jul 19 '11 at 11:44
  • 2
    There's not much more to say, when using a SurfaceView, the associated Surface can be used for only one type of rendering: video, GPU or software. Once one type of rendering was chosen, it cannot be used for another type. It's all about the format of the buffers in memory and where that memory is stored. – Romain Guy Jul 19 '11 at 17:12