I have an application to get camera preview frames with a surface. It was working on Android 4.0.4 but it does not work with Jelly Bean, 4.1.2 on the same device after the update. Simply, the callback is never called back. Here is the code: Snipped a little bit:
public class Panel extends Activity {
Camera myCamera;
int cameraId = -1;
MyCameraSurfaceView myCameraSurfaceView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_panel);
myCamera = getCameraInstance();
myCamera.setPreviewCallback(new Camera.PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
Log.d("Camera Preview", data.length + "");
}
});
myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
FrameLayout myCameraPreview = (FrameLayout) findViewById(R.id.videoview);
myCameraPreview.addView(myCameraSurfaceView);
}
private Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open();
} catch (Exception e) {
e.printStackTrace();
}
return c;
}
public class MyCameraSurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public MyCameraSurfaceView(Context context, Camera camera) {
super(context);
mCamera = camera;
mHolder = getHolder();
mHolder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
}
}
}
}
The video frames are being displayed on the activity, so I cannot figure out what I am doing wrong.
I have rewrote the code by using another tutorial. It works, but now slower. I don't know the exact reason (it may be due to leaked N7000 ROM I use, it may have a bug or this is implemented differently in 4.1, not sure)
CameraPreview.java
public class CameraPreview implements SurfaceHolder.Callback,
Camera.PreviewCallback {
int PreviewSizeWidth;
int PreviewSizeHeight;
SurfaceHolder mSurfHolder;
Camera mCamera;
public CameraPreview(int PreviewlayoutWidth, int PreviewlayoutHeight) {
PreviewSizeWidth = PreviewlayoutWidth;
PreviewSizeHeight = PreviewlayoutHeight;
}
#Override
public void onPreviewFrame(byte[] data, Camera camera) {
Parameters p = camera.getParameters();
int width = p.getPreviewSize().width;
int height = p.getPreviewSize().height;
ByteArrayOutputStream outstr = new ByteArrayOutputStream();
Rect rect = new Rect(0, 0, width, height);
YuvImage yuvimage = new YuvImage(data, ImageFormat.NV21, width,
height, null);
yuvimage.compressToJpeg(rect, 80, outstr); // outstr contains image in jpeg
String encodedImage = Base64.encodeToString(
outstr.toByteArray(), Base64.DEFAULT); // this is base64 encoding of image
}
#Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
Parameters parameters;
mSurfHolder = arg0;
parameters = mCamera.getParameters();
parameters.setPreviewSize(PreviewSizeWidth, PreviewSizeHeight);
mCamera.setParameters(parameters);
mCamera.startPreview();
}
public void surfaceCreated(SurfaceHolder arg0) {
mCamera = Camera.open();
try {
// If did not set the SurfaceHolder, the preview area will be black.
mCamera.setPreviewDisplay(arg0);
mCamera.setPreviewCallback(this);
Parameters p = mCamera.getParameters();
p.setPreviewSize(PreviewSizeWidth, PreviewSizeHeight);
mCamera.setParameters(p);
} catch (IOException e) {
mCamera.release();
mCamera = null;
}
}
#Override
public void surfaceDestroyed(SurfaceHolder arg0) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
PanelActivity.java
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_panel);
SurfaceView camView = new SurfaceView(this);
SurfaceHolder camHolder = camView.getHolder();
int width = 352; // must set a compatible value, otherwise it gets the default width and height
int height = 288;
camPreview = new CameraPreview(width, height);
camHolder.addCallback(camPreview);
camHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mainLayout = (FrameLayout) findViewById(R.id.videoview);
mainLayout.addView(camView, new LayoutParams(width, height));
}
Related
I have been following two links to create custom camera for my application. I have been successful in opening the camera. The problem is that it reduces that image quality. The links I have been following are these:
http://www.coderzheaven.com/2011/12/28/how-to-create-a-custom-layout-for-your-camera-in-android/
http://blog.rhesoft.com/2015/04/02/tutorial-how-to-use-camera-with-android-and-android-studio/
and my code is:
Camera Activity:
public class CameraSetter extends Activity {
public Context context;
public int CAMERA;
// ImageView photo_setter;
private Camera mCamera = null;
private CameraView mCameraView = null;
public CameraSetter() {
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TypefaceProvider.registerDefaultIconSets();
setContentView(R.layout.camera_preview);
Initialize();
}
private void Initialize() {
//photo_setter = (ImageView)findViewById(R.id.imview_camera_setter);
try {
mCamera = Camera.open();//you can use open(int) to use different cameras
} catch (Exception e) {
Log.d("ERROR", "Failed to get camera: " + e.getMessage());
}
if (mCamera != null) {
mCameraView = new CameraView(this, mCamera);//create a SurfaceView to show camera data
FrameLayout camera_view = (FrameLayout) findViewById(R.id.camera_view);
camera_view.addView(mCameraView);//add the SurfaceView to the layout
}
//btn to close the application
ImageButton imgClose = (ImageButton) findViewById(R.id.imgClose);
imgClose.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
System.exit(0);
}
});
}
}
and my cameraview class is:
public class CameraView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraView(Context context, Camera camera) {
super(context);
mCamera = camera;
mCamera.setDisplayOrientation(90);
//get the holder and set this class as the callback, so we can get camera data here
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
//when the surface is created, we can set the camera to draw images in this surfaceholder
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (IOException e) {
Log.d("ERROR", "Camera error on surfaceCreated " + e.getMessage());
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i2, int i3) {
if (mHolder.getSurface() == null)//check if the surface is ready to receive camera data
return;
try {
mCamera.stopPreview();
} catch (Exception e) {
//this will happen when you are trying the camera if it's not running
}
//now, recreate the camera preview
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (IOException e) {
Log.d("ERROR", "Camera error on surfaceChanged " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//our app has only one screen, so we'll destroy the camera in the surface
//if you are unsing with more screens, please move this code your activity
mCamera.stopPreview();
mCamera.release();
}
}
Can I increase the image quality using the same code or I have to do something else?
problem is solved by adding in surfacechanged:
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
parameters.setJpegQuality(100);
parameters.setRotation(90);
List<Camera.Size> sizes = parameters.getSupportedPictureSizes();
Camera.Size size = sizes.get(0);
for(int j=0;j<sizes.size();j++)
{
if(sizes.get(j).width > size.width)
size = sizes.get(j);
}
parameters.setPictureSize(size.width, size.height);
Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
if (display.getRotation() == Surface.ROTATION_0) {
mCamera.setDisplayOrientation(90);
} else if (display.getRotation() == Surface.ROTATION_270) {
mCamera.setDisplayOrientation(180);
}
mCamera.setParameters(parameters);
Created the application to take picture using custom Camera but the camera is not capturing the image in clear visible like Intent Camera. here is the code:
Custom_CameraActivity.java:-
public class Custom_CameraActivity extends Activity {
private Camera mCamera;
private CameraPreview mCameraPreview;
Context context;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
context = getApplicationContext();
mCamera = getCameraInstance();
mCameraPreview = new CameraPreview(this, mCamera);
SurfaceView preview = (SurfaceView) findViewById(R.id.camera_preview);
preview.addView(mCameraPreview);
Button captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCamera.takePicture(null, null, mPicture);
}
});
}
/**
* Helper method to access the camera returns null if it cannot get the
* camera or does not exist
*
* #return
*/
private Camera getCameraInstance() {
Camera camera = null;
try {
camera = Camera.open();
Camera.Parameters parameters = camera.getParameters();
parameters.set("jpeg-quality", 100);
parameters.setPictureFormat(PixelFormat.JPEG);
parameters.setPictureSize(800, 600);
parameters.setRotation(180);
camera.setDisplayOrientation(90);
camera.setParameters(parameters);
} catch (Exception e) {
// cannot get camera or does not exist
}
return camera;
}
Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
try {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
if (bitmap.getWidth() > bitmap.getHeight()) {
Matrix matrix = new Matrix();
matrix.postRotate(180);
bitmap = Bitmap.createBitmap(bitmap , 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
} catch (Exception e) {
}
}
};
}
CameraPreview.java:-
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
// Constructor that obtains context and camera
#SuppressWarnings("deprecation")
public CameraPreview(Context context, Camera camera) {
super(context);
this.mCamera = camera;
this.mSurfaceHolder = this.getHolder();
this.mSurfaceHolder.addCallback(this);
this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (IOException e) {
// left blank for now
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mCamera.stopPreview();
mCamera.release();
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
int width, int height) {
// start preview with new settings
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.startPreview();
} catch (Exception e) {
// intentionally left blank for a test
}
}}
In this image the letters can't be read.
Fixed the issue by adding below Code:-
Camera.Parameters params = c.getParameters();
if (params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
} else {
params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
}
c.setParameters(params);
try this
private Camera getCameraInstance() {
Camera camera = null;
try {
camera = Camera.open();
Camera.Parameters parameters = camera.getParameters();
parameters.set("s3d-prv-frame-layout", "none");
parameters.set("s3d-cap-frame-layout", "none");
parameters.set("iso", "auto");
parameters.set("contrast", 100);
parameters.set("brightness", 50);
parameters.set("saturation", 100);
parameters.set("sharpness", 100);
parameters.setAntibanding("auto");
parameters.setPictureFormat(ImageFormat.JPEG);
parameters.set("jpeg-quality", 100);
if (params.isZoomSupported())
params.setZoom(0);
parameters.setPictureSize(800, 600);
parameters.setRotation(180);
camera.setDisplayOrientation(90);
camera.setParameters(parameters);
} catch (Exception e) {
// cannot get camera or does not exist
}
return camera;
}
EDIT 1.
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bytes);
I want to continuously receive frames from the camera and manipulate them. Since the manipulation will be a CPU heavy task, i have opened the camera on a separate handler thread so that any callbacks land on that thread as well.
However, the problem that i am having is that my onPreviewFrame() never gets called, and i cannot seem to figure out why. I tried but i cannot figure out. There is no error either.
I understand, in order for the PreviewCallbacks to occur, i need to do the following:
Open Camera
Set Preview Display (a camera preview)
Start the preview
I have done all of these and the preview even shows perfectly in the app UI. I wonder what part i am missing or doing wrong. Following is my relevant code.
ODFragment.java
public class ODFragment extends Fragment {
static View rootView;
static Context mainActivityContext;
static final String TAG = "DBG_" + "ODFragment";
static Camera mCamera;
static CameraPreview mCameraPreview;
static FrameLayout frameLayout_cameraLens;
static CameraHandlerThread mCameraHandlerThread = null;
static Handler mUiHandler = new Handler();
//static TessBaseAPI tessBaseAPI = new TessBaseAPI();
public ODFragment() {}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_od, container, false);
mainActivityContext = this.getActivity();
//one time tasks
frameLayout_cameraLens = (FrameLayout) rootView.findViewById(R.id.frameLayout_cameraLens);
setCameraViewDimensions();
return rootView;
}
#Override
public void onResume() {
super.onResume();
//1 open camera
if (mCameraHandlerThread == null) {
mCameraHandlerThread = new CameraHandlerThread("Camera Handler Thread");
}
if (!mCameraHandlerThread.isAlive() || mCameraHandlerThread.getCamera()==null)
{
synchronized (mCameraHandlerThread) {
Log.d(TAG, "onResume: starting mCameraHandlerThread");
mCameraHandlerThread.start();
mCameraHandlerThread.openCamera();
}
}
//rest of the steps will be invoked (hookOpenedCamera()) by cameraHandlerThread
}
public static void hookOpenedCamera(){
mUiHandler.post(new Runnable() {
#Override
public void run() {
//2 create camera and camera preview
mCamera = mCameraHandlerThread.getCamera();
mCameraPreview = new CameraPreview(getMainActivityContext(), mCamera);
//3 add cameraPreview to layout
frameLayout_cameraLens.addView(mCameraPreview);
//4 start preview
mCamera.startPreview();
//5 hook previewCallback
mCamera.setPreviewCallback(new Camera.PreviewCallback() {
#Override
public void onPreviewFrame(byte[] data, Camera camera) { //TODO: incomplete
Log.d(TAG, "onPreviewFrame: called");
}
});
}
});
}
#Override
public void onPause() {
super.onPause();
//-4
mCamera.stopPreview();
//-3
frameLayout_cameraLens.removeView(mCameraPreview);
//-2
mCameraPreview = null;
mCamera = null;
//-1
mCameraHandlerThread.setCamera(null);
mCameraHandlerThread.quit();
mCameraHandlerThread = null;
}
private void setCameraViewDimensions() {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
//calculate dimensions of cameraLens and height of ROI
DisplayMetrics displaymetrics = new DisplayMetrics();
getActivity().getWindowManager().getDefaultDisplay().getMetrics(displaymetrics);
final int width = displaymetrics.widthPixels;
final int height = (int) (width * 1.33333333334);
final int ROIHeight = height / 5;
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
Log.d(TAG, "run: frameLayout_cameraLens dim (BEFORE): "+frameLayout_cameraLens.getLayoutParams().width+" x "+frameLayout_cameraLens.getLayoutParams().height);
//set dimensions of cameraLens
frameLayout_cameraLens.getLayoutParams().width = width;
frameLayout_cameraLens.getLayoutParams().height = height;
frameLayout_cameraLens.requestLayout();
//set height of ROI
LinearLayout linearLayout = (LinearLayout) rootView.findViewById(R.id.ROI);
linearLayout.getLayoutParams().height = ROIHeight;
linearLayout.requestLayout();
Log.d(TAG, "run: frameLayout_cameraLens dim (AFTER): " +frameLayout_cameraLens.getLayoutParams().width+" x "+frameLayout_cameraLens.getLayoutParams().height);
}
});
}
});
thread.run();
}
public static Context getMainActivityContext() {
return mainActivityContext;
}
}
CameraHandlerThread.java
public class CameraHandlerThread extends HandlerThread {
static final String TAG = "DBG_" + "CameraHandlerThread";
Handler mCameraHandler = null;
Camera mCamera = null;
public CameraHandlerThread(String name) {
super(name);
}
#Override
public synchronized void start() {
super.start();
//prepare handler
if (mCameraHandler == null) {
mCameraHandler = new Handler(getLooper());
}
}
void openCamera() {
mCameraHandler.post(new Runnable() {
#Override
public void run() {
try {
//done on cameraHandlerThread (step 1)
mCamera = Camera.open();
//done on UiThread (steps 2, 3, 4)
ODFragment.hookOpenedCamera();
}
catch (RuntimeException e) {
Log.e(TAG, "failed to open camera");
}
}
});
}
public Camera getCamera() {
return this.mCamera;
}
public void setCamera(Camera camera) {
this.mCamera = camera;
}
}
CameraPreview.java
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
static final String TAG = "DBG_" + "CameraPreview";
private Camera.Size mPreviewSize = null;
public CameraPreview(Context context){
super(context);
}
public CameraPreview(Context context, Camera mCamera) {
super(context);
//Log.d(TAG, "CameraPreview() initialized");
//mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
setCamera(mCamera);
mHolder = getHolder();
mHolder.addCallback(this);
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview
try {
mCamera.setDisplayOrientation(90); //because only supporting portrait currently
mCamera.setPreviewDisplay(holder);
//mCamera.startPreview();
//Log.d(TAG, "surfaceCreated(): Started camera preview");
} catch (IOException e) {
Log.d(TAG, "surfaceCreated(): Error setting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null){
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e){
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
Camera.Parameters cameraParameters = mCamera.getParameters();
//change camera preview size
cameraParameters.setPreviewSize(getPreviewSize().width, getPreviewSize().height);
//continuous autofocus
cameraParameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
//set focus area to top part of the camera view //TODO
//cameraParameters.setFocusAreas();
//set parameters now
mCamera.setParameters(cameraParameters);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
//Log.d(TAG, "surfaceChanged(): Restarted camera preview");
} catch (Exception e){
Log.d(TAG, "surfaceChanged(): Error starting camera preview: " + e.getMessage());
}
}
private Camera.Size getPreviewSize() {
if (mPreviewSize == null) {
List<Camera.Size> mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mPreviewSize = mSupportedPreviewSizes.get(mSupportedPreviewSizes.size() - 6);
Log.d(TAG, "getPreviewSize(): Camera Preview Size selected: " + mPreviewSize.width + " x " + mPreviewSize.height);
}
return mPreviewSize;
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
//Log.d(TAG, "surfaceDestroyed() invoked");
}
public void setCamera(Camera camera) {
this.mCamera = camera;
}
}
Thank you in advance
SOLVED
I realized that my PreviewCallback does get hooked. But after that, the surfaceChanged() gets called at a point, which stops and then starts the CameraPreview. This removes my callback.
So, i have to invoke my callback hooking routine, everywhere that i am invoking startPreview
I'm trying to capture an image from a SurfaceView custom camera. I have set up the initial code but I don't know how to call the 'take photo' method so that I can see the preview on the surface.
Currently this code displays the preview in realtime. I need to take the picture and access the byte[] array
Please help me complete the code:
private SurfaceView mSurfaceView;
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
captureImage = (ImageButton) findViewById(R.id.captureImage);
mSurfaceView = (SurfaceView) findViewById(R.id.surfaceView);
captureImage.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
//this button press should take the picture
}
});
mSurfaceView.getHolder().addCallback(this);
mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mCamera = Camera.open();
}
#Override
public void onPause() {
super.onPause();
mCamera.stopPreview();
}
#Override
public void onDestroy() {
super.onDestroy();
mCamera.release();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(mSurfaceView.getHolder());
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
Camera.Size selected = sizes.get(0);
params.setPreviewSize(selected.width,selected.height);
mCamera.setParameters(params);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
I need to get the bytes [] data so that I can convert the image to a base64 string. How do I call the necessary methods to take the picture using the code above?
Check "jpegCallback" in my example:
public class CameraActivity extends ActionBarActivity implements SurfaceHolder.Callback {
Camera camera;
SurfaceView surfaceView;
SurfaceHolder surfaceHolder;
PictureCallback jpegCallback;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
surfaceHolder = surfaceView.getHolder();
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
surfaceHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));
outStream.write(data);
outStream.close();
Log.d("Log", "onPictureTaken - wrote bytes: " + data.length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
}
Toast.makeText(getApplicationContext(), "Picture Saved", 2000).show();
refreshCamera();
}
};
}
public void captureImage(View v) throws IOException {
//take the picture
camera.takePicture(null, null, jpegCallback);
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
try {
// open the camera
camera = Camera.open();
} catch (RuntimeException e) {
// check for exceptions
System.err.println(e);
return;
}
Camera.Parameters param;
param = camera.getParameters();
// modify parameter
List<Camera.Size> sizes = param.getSupportedPreviewSizes();
Camera.Size selected = sizes.get(0);
param.setPreviewSize(selected.width,selected.height);
camera.setParameters(param);
try {
// The Surface has been created, now tell the camera where to draw
// the preview.
camera.setDisplayOrientation(90);
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
// check for exceptions
System.err.println(e);
return;
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
refreshCamera();
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
// stop preview and release camera
camera.stopPreview();
camera.release();
camera = null;
}
public void refreshCamera() {
if (surfaceHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
camera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
camera.setPreviewDisplay(surfaceHolder);
camera.startPreview();
} catch (Exception e) {
}
}
}
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?
You cannot both display the camera preview and draw with a Canvas. You have to do one or the other.