Android camera face detection does not work the second time - android

I copied the code Google example in:
https://developer.android.com/guide/topics/media/camera.html
For the first time I open the Camera, face detection works correctly and the callback is fired, I take the photo, close the camera, open the camera again but this time the face detection callback is not called.
If I'll restart my app, the same thing will happen - face detection will only work for the first time I'll use the camera.
here is my code:
private PictureTakenListener mPictureTakenListener;
AlertDialog mAlertDialog;
private Camera mCamera;
boolean mFaceDetectionAvailable;
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
showText("took a photo with a size of " + data.length);
releaseCamera();
if (mAlertDialog != null) mAlertDialog.dismiss();
mPictureTakenListener.photoTaken(data);
}
};
public class MyFaceDetectionListener implements Camera.FaceDetectionListener {
#Override
public void onFaceDetection(Camera.Face[] faces, Camera camera) {
if (faces != null)
if (faces.length > 0)
if (faces[0].score >= 40)
if (!takingPhotoFlag.get()){
takingPhotoFlag.set(true);
mCamera.takePicture(null, null, mPicture);
}
}
}
private void takePicture(PictureTakenListener listener){
mPictureTakenListener = listener;
if (this.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
showText("this device has a camera");
showText("device has " + String.valueOf(Camera.getNumberOfCameras()) + " cameras");
int foundCamera = -1;
for (int i = 0; i < Camera.getNumberOfCameras(); i++){
Camera.CameraInfo info = new Camera.CameraInfo(); ;
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT){
foundCamera = i;
break;
}
}
if (foundCamera == -1){
return;
}
mCamera = null;
try {
mCamera = Camera.open(foundCamera); // attempt to get a Camera instance
}
catch (Exception e){
e.printStackTrace();
showText("could not open the front camera. " + e.getMessage());
return;
}
showText("successfully opened the camera");
mCamera.setDisplayOrientation(90);
Camera.Parameters params = mCamera.getParameters();
params.setPreviewSize(640, 480);
params.setRotation(270);
params.setPictureSize(640, 480);
mFaceDetectionAvailable = params.getMaxNumDetectedFaces() > 0;
mCamera.setParameters(params);
FrameLayout frameLayout = new FrameLayout(this);
if (!mFaceDetectionAvailable) {
frameLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCamera.takePicture(null, null, mPicture);
}
});
}
AlertDialog.Builder alert = new AlertDialog.Builder(this);
if (!mFaceDetectionAvailable)
alert.setTitle("CLICK IMAGE TO CAPTURE");
alert.setView(frameLayout).setCancelable(true).setOnCancelListener(new DialogInterface.OnCancelListener() {
#Override
public void onCancel(DialogInterface dialog) {
releaseCamera();
runOnUiThread(new Runnable() {
#Override
public void run() {
//do UI stuff...
}
});
}
});
mAlertDialog = alert.create();
mAlertDialog.show();
mAlertDialog.getCurrentFocus();
mAlertDialog.getWindow().setLayout(960, 1280); //Controlling width and height.
mAlertDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
CameraPreview mPreview = new CameraPreview(this, mCamera);
frameLayout.addView(mPreview);
} else {
showText("no camera on this device");
}
}
public interface PictureTakenListener{
void photoTaken(byte[] image);
}
/** A basic Camera preview class */
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
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
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
if (mFaceDetectionAvailable) {
mCamera.startFaceDetection();
mCamera.setFaceDetectionListener(new MyFaceDetectionListener());
}
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
private void releaseCamera(){
if (mCamera != null){
mCamera.setPreviewCallback(null);
mCamera.setFaceDetectionListener(null);
mCamera.stopFaceDetection();
mCamera.setErrorCallback(null);
mCamera.release();
mCamera = null;
showText("released camera");
}
}
Thank you.

Related

using camera.hardware reduces image quality

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);

onPreviewFrame() not being invoked

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

Camera is being used after Camera.release() was called in Galaxy s6 Edge

I have the following exception on Galaxy s6 edge device
java.lang.RuntimeException: Camera is being used after Camera.release() was called
at android.hardware.Camera.setPreviewSurface(Native Method)
at android.hardware.Camera.setPreviewDisplay(Camera.java:702)
at com.forsale.forsale.view.uicomponent.qrcode.CameraPreview.surfaceCreated(CameraPreview.java:59)
at android.view.SurfaceView.updateWindow(SurfaceView.java:712)
at android.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:316)
at android.view.View.dispatchWindowVisibilityChanged(View.java:10434)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1328)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1328)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1328)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1328)
at android.view.ViewGroup.dispatchWindowVisibilityChanged(ViewGroup.java:1328)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1750)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1437)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:7397)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:920)
at android.view.Choreographer.doCallbacks(Choreographer.java:695)
at android.view.Choreographer.doFrame(Choreographer.java:631)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:906)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:158)
at android.app.ActivityThread.main(ActivityThread.java:7224)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
this is my code :
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private PreviewCallback previewCallback;
private AutoFocusCallback autoFocusCallback;
public CameraPreview(Context context, Camera camera,
PreviewCallback previewCb,
AutoFocusCallback autoFocusCb) {
super(context);
mCamera = camera;
previewCallback = previewCb;
autoFocusCallback = autoFocusCb;
/*
* Set camera to continuous focus if supported, otherwise use
* software auto-focus. Only works for API level >=9.
*/
/*
Camera.Parameters parameters = camera.getParameters();
for (String f : parameters.getSupportedFocusModes()) {
if (f == Parameters.FOCUS_MODE_CONTINUOUS_PICTURE) {
mCamera.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
autoFocusCallback = null;
break;
}
}
*/
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
// deprecated setting, but required on Android versions prior to 3.0
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
Log.d("DBG", "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// Camera preview released in activity
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
/*
* 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
}
try {
// Hard code camera surface rotation 90 degs to match Activity view in portrait
mCamera.setDisplayOrientation(90);
mCamera.setPreviewDisplay(mHolder);
mCamera.setPreviewCallback(previewCallback);
mCamera.startPreview();
mCamera.autoFocus(autoFocusCallback);
} catch (Exception e){
Log.d("DBG", "Error starting camera preview: " + e.getMessage());
}
}
}
this is the code of the activity
public class QRCodeActivity extends BaseActivity
{
private Camera mCamera;
private CameraPreview mPreview;
private Handler mAutoFocusHandler;
private ImageScanner mScanner;
private boolean mBarcodeScanned = false;
private boolean mPreviewing = true;
static {
System.loadLibrary("iconv");
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_qrcode);
initializeActionBar();
setActionBarTitle(getString(R.string.qrcode));
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mAutoFocusHandler = new Handler();
mCamera = getCameraInstance();
mScanner = new ImageScanner();
mScanner.setConfig(0, Config.X_DENSITY, 3);
mScanner.setConfig(0, Config.Y_DENSITY, 3);
mPreview = new CameraPreview(this, mCamera, previewCb, autoFocusCB);
FrameLayout preview = (FrameLayout)findViewById(R.id.cameraPreview);
preview.addView(mPreview);
}
public void onPause() {
super.onPause();
releaseCamera();
}
public static Camera getCameraInstance(){
Camera c = null;
try {
c = Camera.open();
} catch (Exception e){
}
return c;
}
private void releaseCamera() {
if (mCamera != null) {
mPreviewing = false;
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
private Runnable doAutoFocus = new Runnable() {
public void run() {
if (mPreviewing)
mCamera.autoFocus(autoFocusCB);
}
};
PreviewCallback previewCb = new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
Parameters parameters = camera.getParameters();
Size size = parameters.getPreviewSize();
Image barcode = new Image(size.width, size.height, "Y800");
barcode.setData(data);
int result = mScanner.scanImage(barcode);
if (result != 0) {
mPreviewing = false;
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
SymbolSet syms = mScanner.getResults();
for (Symbol sym : syms) {
showProgressDialog();
ForSaleServerManager.getInstance().verifyQRCode(QRCodeActivity.this, PhoneUtils.getDeviceId(QRCodeActivity.this) , sym.getData() , new VerifyQRCodeUIListener() {
#Override
public void onVerifyQRCodeCompleted(QRCodeResponse response, AppError error) {
hideProgressDialog();
if (error != null) {
DialogUtils.showDialogMessage(
QRCodeActivity.this,
getString(R.string.error),
PhoneUtils.getErrorMessage(QRCodeActivity.this, error),
getString(R.string.ok), null);
} else {
if (response != null && response.getError() == null) {
DialogUtils.showDialogMessage(QRCodeActivity.this, getString(R.string.info),
response.getMessage(), getString(R.string.ok), new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
});
} else if (response != null && response.getError() != null) {
DialogUtils.showDialogMessage(
QRCodeActivity.this,
getString(R.string.error),
response.getError().getMessage(),
getString(R.string.ok), null);
}
}
}
});
mBarcodeScanned = true;
}
}
}
};
AutoFocusCallback autoFocusCB = new AutoFocusCallback() {
public void onAutoFocus(boolean success, Camera camera) {
mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
}
};
#Override
protected void initializeUIComponents() {
}
#Override
protected void initializeUIComponentsData() {
}
#Override
protected void initializeUIComponentsTheme() {
}
#Override
protected void initializeUIComponentsAction() {
}
#Override
public void goodTimeToReleaseMemory() {
/*mCamera = null;
mPreview = null;
mAutoFocusHandler = null;
mScanner = null;*/
Runtime.getRuntime().gc();
finish();
}
}
There is a serious flaw in your code: mCamera.release() is called on every onPause, but Camera.open() is only called onCreate.
This said, it is a bad practice to open camera on the main (UI) thread: this call may take too long on some devices (not on Samsung Galaxy 6) and even cause ANR.
The best practice is to open camera on a background HandlerThread (see https://stackoverflow.com/a/19154438/192373). This will guarantee that the camera callbacks (including onPictureTaken()) don't freeze your UI thread.
At any rate, to keep the mCamera object synchronized with the lifecycle of your activity and its SurfaceView, I recommend to start Camera.open() from surfaceCreated and mCamera.release() - from surfaceDestroyed.

Capturing Photo from SurfaceView

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) {
}
}
}

Camera Preview not visible after App Resumes

I am developing this app which requires access to the camera. I have accessed it well. But there are two issues.
The preview is all stretched when the phone is vertical. Secondly, the camera preview isn't visible when I resume the app. The camera.open() function does opens the camera but I am not able to see the preview. I have tried all the help available on the forum but nothing is actually solving my problem.
-Thanks in advance!
//Camera Activity file
#SuppressLint("SimpleDateFormat")
public class CameraActivity extends Activity {
private Camera mCamera;
private CameraPreview mPreview;
private FrameLayout preview;
private Button bCapture;
private Button bGallery;
private static final String TAG = "CameraActivity";
private static final int PICK_IMAGE_REQUEST = 1;
private TextView tvCheck;
public final static String EXTRA_MESSAGE = "com.epfl.mycamera.MESSAGE";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_camera);
if (checkCameraHardware(getBaseContext())){
// Create an instance of Camera
mCamera = getCameraInstance();
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera, CameraActivity.this);
preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
//Adding Camera Button
bCapture = (Button) findViewById(R.id.bCapture);
//Button Listener for storing images
bCapture.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
mCamera.takePicture(null, null, null, jpegCallback);
mCamera.startPreview();
Log.d(TAG, "takePicture");
}
});
//Adding Gallery Button
bGallery = (Button) findViewById (R.id.bGallery);
bGallery.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tvCheck = (TextView) findViewById (R.id.tvCheck);
selectImageFromGallery();
}
});
}
Log.d(TAG, "OnCreate");
}
/******************************************************************/
public void selectImageFromGallery() {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"),PICK_IMAGE_REQUEST);
}
#Override
protected void onActivityResult(int aRequestCode, int aResultCode, Intent aData) {
switch (aRequestCode) {
case PICK_IMAGE_REQUEST:
handleImage(aData);
break;
default:
tvCheck.setText("You can only select images.");
break;
}
super.onActivityResult(aRequestCode, aResultCode, aData);
}
private void handleImage(Intent aData) {
if ((aData != null) && (aData.getData() != null)) {
Uri selectedImage = aData.getData();
String[] filePathColumn = {MediaColumns.DATA};
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
cursor.moveToFirst();
Log.d("ImageActivity", "After extracting file Path");
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
Log.d("ImageActivity", "After closing the cursor");
setContentView(R.layout.activity_image_old); //setting the view to the image
ImageView imgView = (ImageView) findViewById(R.id.ivGallery);
imgView.setImageBitmap(BitmapFactory.decodeFile(picturePath));
Button bLiveCamera = (Button) findViewById(R.id.bCameraPreview);
bLiveCamera.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setContentView(R.layout.activity_camera);
mCamera.startPreview();
}
});
}
else {
tvCheck.setText("You did not select an image");
}
}
/****************************************************************/
/** Stores jpeg picture */
PictureCallback jpegCallback = new PictureCallback() {
public void onPictureTaken(byte[] data, Camera camera) {
try {
File mediaStorageDir = new File(Environment .getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),"MyCamera");
// Saving image to the SD CARD with a file operation
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator +"IMG_"+ timeStamp + ".jpg");
FileOutputStream outStream = new FileOutputStream(mediaFile);
outStream.write(data);
outStream.close();
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
Log.d(TAG, "onPictureTaken - wrote bytes: " + data.length);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
} Log.d(TAG, "onPictureTaken - jpeg");
}
};
/***************************************************************/
/** Check if this device has a camera */
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
Log.d(TAG, "Camera Available");
return true;
} else {
Log.d(TAG, "No Camera Found");
return false;
}
}
/** A safe way to get an instance of the Camera object. */
public Camera getCameraInstance(){
Camera c = null;
try {
int i = Camera.getNumberOfCameras();
releaseCamera(); //in case camera is being accessed by any other app.
Log.d(TAG, "Number of Cameras "+i +"\n");
c = Camera.open(); // attempt to get a Camera instance
Log.d(TAG, "Camera Opened");
}
catch (Exception e){
Log.d(TAG, "Camera Can't Be Accessed");
}
return c; // returns null if camera is unavailable
}
#Override
protected void onPause() {
super.onPause();
releaseCamera(); // release the camera immediately on pause event
}
private void releaseCamera(){
if (mCamera != null){
mPreview.getHolder().removeCallback(mPreview);
mCamera.release(); // release the camera for other applications
}
}
#Override
public void onResume() {
super.onResume();
// Get the Camera instance as the activity achieves full user focus
if (mCamera == null) {
getCameraInstance();
mCamera.startPreview();
}
}
}
this is my camera preview class:
#SuppressLint({ "ViewConstructor", "SdCardPath" })
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private SurfaceHolder mHolder;
private Camera mCamera;
private Size mPreviewSize;
// private Activity CameraActivity;
#SuppressWarnings("deprecation")
public CameraPreview(Context context, Camera camera, Activity activity) {
super(context);
mCamera = camera;
//CameraActivity = activity;
// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
//add camera preview call back here.
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
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 parameters = mCamera.getParameters();
List<Size> localSizes = mCamera.getParameters().getSupportedPreviewSizes();
mPreviewSize = localSizes.get(0);
Log.d(TAG, "Width " + mPreviewSize.width);
Log.d(TAG, "Height " + mPreviewSize.height);
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height );
mHolder.setFixedSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();
mCamera.setParameters(parameters);
//start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.setDisplayOrientation(90);
//setCameraDisplayOrientation(CameraActivity, 0, mCamera);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
You create a CameraPreview only onCreate() of your Activity. But the camera instance is released onPause(), and a new one is opened onResume(). Therefore, you need to set the surface again.

Categories

Resources