I have been trying to encode bitmap images from a view into a mp4 video. I am using MediaRecorder setup with Surface as input. The code is failing on the second iteration in the loop. It appears that the canvas is not successfully unlocked, and then lockCanvas fails and throws an error.
What could be causing this exception?
public class ViewRecorder
{
private View recordView;
private boolean run = true;
private String filename;
public ViewRecorder(View recordView, String filename)
{
this.recordView = recordView;
this.filename = filename;
Thread thread = new Thread(new Task());
thread.start();
}
/*
* Stops the recording
*/
public void Stop()
{
this.run = false;
}
/*
* Encodes a frame every 100 mS
*/
private class Task implements Runnable
{
#Override
public void run()
{
try
{
MediaRecorder mediaRecorder = new MediaRecorder();
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mediaRecorder.setVideoFrameRate(10);
//this.mediaRecorder.setVideoEncodingBitRate(20000);
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mediaRecorder.setOutputFile(filename + ".mp4");
recordView.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(recordView.getDrawingCache());
recordView.setDrawingCacheEnabled(false);
mediaRecorder.setVideoSize(bitmap.getWidth(), bitmap.getHeight());
mediaRecorder.prepare();
mediaRecorder.start(); // Recording is now started
while(run)
{
Thread.sleep(100);
recordView.setDrawingCacheEnabled(true);
bitmap = Bitmap.createBitmap(recordView.getDrawingCache());
recordView.setDrawingCacheEnabled(false);
Surface surface = mediaRecorder.getSurface();
Canvas canvas = surface.lockCanvas(null);
canvas.drawBitmap(bitmap, 0, 0, new Paint());
surface.unlockCanvasAndPost(canvas);
}
mediaRecorder.stop();
mediaRecorder.reset();
mediaRecorder.release();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}
This is the exception:
11-21 18:59:35.220 26737-27432/ W/System.err: java.lang.IllegalArgumentException
11-21 18:59:35.220 26737-27432/ W/System.err: at android.view.Surface.nativeLockCanvas(Native Method)
11-21 18:59:35.220 26737-27432/ W/System.err: at android.view.Surface.lockCanvas(Surface.java:322)
11-21 18:59:35.221 26737-27432/ W/System.err: at .ViewRecorder$Task.run(ViewRecorder.java:77)
11-21 18:59:35.221 26737-27432/ W/System.err: at java.lang.Thread.run(Thread.java:762)
11-21 19:00:47.783 26737-26744/ W/art: Suspending all threads took: 35.361ms
11-21 19:01:25.983 26737-26744/ W/art: Suspending all threads took: 22.830ms
Not sure if you're still after a solution but I found this:
Move - Surface surface = mediaRecorder.getSurface();
outside of the loop so it's only called once. Errors on the second time it's called
Related
I'm trying blur some images 1024x1024 and sometimes I'm getting java.lang.OutOfMemoryError and i don't know why.
I'm testing directly in my tablet Android 4.1.2 and I have always 1.5gb Ram free.
Here the class I'm using:
package com.example.playerclient.blur;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v8.renderscript.*;
public class BlurBuilder {
private static final float BITMAP_SCALE = 0.6f;
public static Bitmap blur(Context context, Bitmap image, float blurRadius) {
Bitmap outputBitmap = null;
if (image != null) {
if (blurRadius == 0) {
return image;
}
if (blurRadius < 1) {
blurRadius = 1;
}
if (blurRadius > 25) {
blurRadius = 25;
}
int width = Math.round(image.getWidth() * BITMAP_SCALE);
int height = Math.round(image.getHeight() * BITMAP_SCALE);
Bitmap inputBitmap = Bitmap.createScaledBitmap(image, width, height, false);
outputBitmap = Bitmap.createBitmap(inputBitmap);
RenderScript rs = RenderScript.create(context);
ScriptIntrinsicBlur theIntrinsic = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
Allocation tmpIn = Allocation.createFromBitmap(rs, inputBitmap);
Allocation tmpOut = Allocation.createFromBitmap(rs, outputBitmap);
theIntrinsic.setRadius(blurRadius);
theIntrinsic.setInput(tmpIn);
theIntrinsic.forEach(tmpOut);
tmpOut.copyTo(outputBitmap);
}
return outputBitmap;
}
}
Here where I call the method:
public class MusicaActivity extends AppCompatActivity implements View.OnClickListener {
// Others methods here.
private void mostraDadosMusica() {
Intent intent = getIntent();
Musica musica = (Musica)intent.getSerializableExtra(MainActivity.VISUALIZA_PLAYER);
// Where i'm having problems.
Bitmap originalBmp = BitmapFactory.decodeResource(getResources(), musica.getAlbum().getIdCapa());
Bitmap resultBmp = BlurBuilder.blur(this, originalBmp, 15f);
backgroundImageView.setImageBitmap(resultBmp);
}
}
Ande here the exception message:
11-04 22:05:07.453 18928-18928/com.example.playerclient E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.OutOfMemoryError
at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method)
at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:636)
at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:484)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:512)
at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:542)
at com.example.playerclient.activity.MusicaActivity.mostraDadosMusica(MusicaActivity.java:48)
at com.example.playerclient.activity.MusicaActivity.onCreate(MusicaActivity.java:87)
at android.app.Activity.performCreate(Activity.java:5188)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1094)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2074)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2135)
at android.app.ActivityThread.access$700(ActivityThread.java:140)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:137)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
at dalvik.system.NativeStart.main(Native Method)
I am taking pictures in the background inside my Android App. However it gives an error:
02-09 15:22:12.061: E/cheeta(28633): timer testing
02-09 15:22:13.546: W/System.err(28633): java.lang.RuntimeException: takePicture failed
02-09 15:22:13.546: W/System.err(28633): at android.hardware.Camera.native_takePicture(Native Method)
02-09 15:22:13.546: W/System.err(28633): at android.hardware.Camera.takePicture(Camera.java:1194)
02-09 15:22:13.551: W/System.err(28633): at cam.sharp.MainActivity$MyTimerTask.run(MainActivity.java:69)
02-09 15:22:13.551: W/System.err(28633): at java.util.Timer$TimerImpl.run(Timer.java:284)
02-09 15:22:13.551: E/cheeta(28633): timer testing
02-09 15:22:15.051: W/System.err(28633): java.lang.RuntimeException: takePicture failed
02-09 15:22:15.051: W/System.err(28633): at android.hardware.Camera.native_takePicture(Native Method)
02-09 15:22:15.051: W/System.err(28633): at android.hardware.Camera.takePicture(Camera.java:1194)
02-09 15:22:15.051: W/System.err(28633): at cam.sharp.MainActivity$MyTimerTask.run(MainActivity.java:69)
02-09 15:22:15.051: W/System.err(28633): at java.util.Timer$TimerImpl.run(Timer.java:284)
02-09 15:22:15.051: E/cheeta(28633): timer testing
02-09 15:22:16.551: W/System.err(28633): java.lang.RuntimeException: takePicture failed
02-09 15:22:16.556: W/System.err(28633): at android.hardware.Camera.native_takePicture(Native Method)
02-09 15:22:16.556: W/System.err(28633): at android.hardware.Camera.takePicture(Camera.java:1194)
02-09 15:22:16.561: W/System.err(28633): at cam.sharp.MainActivity$MyTimerTask.run(MainActivity.java:69)
02-09 15:22:16.561: W/System.err(28633): at java.util.Timer$TimerImpl.run(Timer.java:284)
02-09 15:22:16.561: E/cheeta(28633): timer testing
I have two files.
MainActivity.java and CameraPreview.java
Here is the code for both.
MainActivity.java
package cam.sharp;
import java.io.File;
import java.io.FileOutputStream;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.content.Context;
import android.hardware.Camera;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.widget.FrameLayout;
import android.widget.Toast;
public class MainActivity extends Activity {
private int cameraId = 0;
private Camera mCamera;
private CameraPreview mPreview;
String fileName = "tempImage.jpeg";
File file;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Create an instance of Camera
mCamera = getCameraInstance(cameraId);
if (mCamera == null) {
Toast.makeText(
getApplicationContext(),
"The camera service is currently unavailable, please try again!",
Toast.LENGTH_LONG).show();
finish();
} else {
// Create our Preview view and set it as the content of our
// activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.camera_preview);
frameLayout.addView(mPreview);
}
// start thread for these
MyTimerTask myTask = new MyTimerTask();
Timer myTimer = new Timer();
// public void schedule (TimerTask task, long delay, long period)
// Schedule a task for repeated fixed-delay execution after a specific
// delay.
//
// Parameters
// task the task to schedule.
// delay amount of time in milliseconds before first execution.
// period amount of time in milliseconds between subsequent executions.
myTimer.schedule(myTask, 3000, 1500);
}
class MyTimerTask extends TimerTask {
public void run() {
try {
mCamera.takePicture(null, null, null, mPictureCallback);
file = new File(getFilesDir(), fileName);
} catch (Exception e) {
e.printStackTrace();
}
Log.e("cheeta", "timer testing");
}
}
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData, Camera c) {
Log.e("Callback TAG", "Here in jpeg Callback");
if (imageData != null) {
FileOutputStream outputStream;
try {
outputStream = openFileOutput(fileName,
Context.MODE_PRIVATE);
outputStream.write(imageData);
outputStream.close();
// Intent intent = new Intent(SnapScreen.this,
// PreviewScreen.class);
// if (fromMessageReview == true) {
// intent.putExtra("fromMessageReview", "true");
// }
// startActivity(intent);
// overridePendingTransition(R.anim.slide_in,
// R.anim.slide_out);
finish();
} catch (Exception e) {
e.printStackTrace();
}
}
}
};
#Override
protected void onDestroy() {
super.onDestroy();
releaseCamera();
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance(int cameraId) {
Camera c = null;
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
c = Camera.open(cameraId);
} else {
c = Camera.open();
}
} catch (Exception e) {
c = null;
}
return c; // returns null if camera is unavailable
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
}
CameraPreview.java
package cam.sharp;
import java.io.IOException;
import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.Camera;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/** A basic Camera preview class */
#SuppressLint("ViewConstructor")
public class CameraPreview extends SurfaceView implements
SurfaceHolder.Callback {
private static final String TAG = "Camera Preview";
private SurfaceHolder mHolder;
public Camera mCamera;
#SuppressWarnings("deprecation")
#SuppressLint("NewApi")
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
mCamera.setDisplayOrientation(90);
// 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);
mCamera.setDisplayOrientation(90);
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
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
Can anyone see what is the issue? I am calling mCamera.startPreview(); but still no use.
Thanks
You have 2 problems in your code:
First: In your onPictureTaken call back you are calling the finish() method, wich in turn signals that the activity should be destroyed, and calls the onDestroy() method, wich in turn releases your camera. However your MainActivity.java is not destroyed (not really sure why, but through logCat, I found that the onCreate() is only being called once, so I assumed the activity is not destroyed. A possible explanation for this might be that the Timer is controlled by a diferent thread and as such might not be aware that the MainActivity was destroyed, but I can't confirm), and so your myTimer will continue to run, and when it gets to mCamera.takePicture(null, null, null, mPictureCallback); it will throw a NullPointException because the camera was already released, and the MainActivity.onCreate() wasn't called again to get a new instance to mCamera.
So, to solve the first problem:
Camera.PictureCallback mPictureCallback = new Camera.PictureCallback() {
public void onPictureTaken(byte[] imageData, Camera c) {
Log.e("Callback TAG", "Here in jpeg Callback");
if (imageData != null) {
FileOutputStream outputStream = null;
try {
outputStream = openFileOutput(fileName, Context.MODE_PRIVATE);
outputStream.write(imageData);
// Removed the finish call you had here
} catch (Exception e) {
e.printStackTrace();
} finally {
if (outputStream != null) try {
outputStream.close();
} catch (IOException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
}
}
}
};
Second: Is where you call your startPreview() method. Accooding to the documentation of takePicture():
This method is only valid when preview is active (after
startPreview()). Preview will be stopped after the image is taken;
callers must call startPreview() again if they want to re-start
preview or take more pictures. This should not be called between
start() and stop().
You were only calling startPreview() once, when you create the camera, and because of problem 1, the onCreate() on MainActivity is only being called once. Since you have a timer taking pictures every 1.5 seconds, you should call startPreview() before calling takePicture(), so to solve this:
class MyTimerTask extends TimerTask {
public void run() {
try {
// Call startPreview before taking a picture
mCamera.startPreview();
mCamera.takePicture(null, null, null, mPictureCallback);
file = new File(getFilesDir(), fileName);
} catch (NullPointerException ne) {
ne.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Log.e("cheeta", "timer testing");
}
}
After this the app continuasly takes pictures, and stores them. I never used a Timer like that so Im not sure how to make it stop. If you only want a small number of pictures taken within each call to the CameraPreview Activity I suggest you use a Timer with an action listener, like so:
Timer tm = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// Take x pictures
tm.stop();
}
});
I'm am trying to capture an image in the ontouchevent of surfaceview. However, everytime a touch the screen, the app crashes with the following exception:
01-05 21:03:18.500: ERROR/AndroidRuntime(10367): FATAL EXCEPTION: main
java.lang.RuntimeException: takePicture failed
at android.hardware.Camera.native_takePicture(Native Method)
at android.hardware.Camera.takePicture(Camera.java:1126)
at android.hardware.Camera.takePicture(Camera.java:1071)
at com.test.MotionDetector.CameraSurfaceView.onTouchEvent(CameraSurfaceView.java:107)
at android.view.View.dispatchTouchEvent(View.java:7350)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212)
at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2470)
at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2212)
at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2151)
at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1480)
at android.app.Activity.dispatchTouchEvent(Activity.java:2469)
at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2099)
at android.view.View.dispatchPointerEvent(View.java:7535)
at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:3492)
at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:3424)
at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:4534)
at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:4512)
at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:4616)
at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:171)
at android.os.MessageQueue.nativePollOnce(Native Method)
at android.os.MessageQueue.next(MessageQueue.java:125)
at android.os.Looper.loop(Looper.java:124)
at android.app.ActivityThread.main(ActivityThread.java:4921)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:511)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1038)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:805)
at dalvik.system.NativeStart.main(Native Method)
My code:
package com.nadim.MotionDetector;
import android.content.Context;
import android.hardware.Camera;
import android.os.Environment;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private Context context;
public CameraSurfaceView(Context context, Camera camera) {
super(context);
this.context = 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.
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d("MotionDetector", "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
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d("MotionDetector", "Error starting camera preview: " + e.getMessage());
}
}
#Override
public boolean onTouchEvent(MotionEvent event) {
Toast.makeText(context, "Picture taken", Toast.LENGTH_SHORT).show();
//System.gc(); tried this because it was suggested in a stackoverflow question but it didn't help.
mCamera.takePicture(null, mPicture, mPicture);
return true; //processed
}
private Camera.PictureCallback mPicture = new Camera.PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile();
if (pictureFile == null) {
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d("MotionDetector", "File not found: " + e.getMessage());
} catch (IOException e) {
Log.d("MotionDetector", "Error accessing file: " + e.getMessage());
}
}
};
private static File getOutputMediaFile() {
File mediaStorageDir = new File(Environment.getExternalStorageDirectory(), "motiondetect");
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir, timeStamp + ".jpg");
return mediaFile;
}
}
Permissions and features used:
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.hardware.camera"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.flash" />
I don't know why the crash occurs. Many other topic suggest calling Camera.startPreview first. I am doing that, but it doesn't solve the issue.
LogCat before taking picture:
01-05 21:45:57.667: WARN/ActivityManager(754): No content provider found for permission revoke: file:///data/local/tmp/com.test.MotionDetector
01-05 21:45:57.667: WARN/ActivityManager(754): No content provider found for permission revoke: file:///data/local/tmp/com.test.MotionDetector
01-05 21:45:57.687: INFO/ActivityManager(754): Force stopping com.test.MotionDetector appid=10103 user=-1: uninstall pkg
01-05 21:45:57.687: INFO/ActivityManager(754): Killing 4264:com.test.MotionDetector/u0a103 (adj 7): stop com.test.MotionDetector
01-05 21:45:57.687: INFO/ActivityManager(754): Force finishing activity ActivityRecord{437a6678 u0 com.test.MotionDetector/.MotionDetectActivity t144}
01-05 21:45:57.697: WARN/InputDispatcher(754): channel '42adff40 com.test.MotionDetector/com.test.MotionDetector.MotionDetectActivity (server)' ~ Consumer closed input channel or an error occurred. events=0x9
01-05 21:45:57.697: ERROR/InputDispatcher(754): channel '42adff40 com.test.MotionDetector/com.test.MotionDetector.MotionDetectActivity (server)' ~ Channel is unrecoverably broken and will be disposed!
01-05 21:45:57.697: WARN/InputDispatcher(754): Attempted to unregister already unregistered input channel '42adff40 com.test.MotionDetector/com.test.MotionDetector.MotionDetectActivity (server)'
01-05 21:45:57.697: INFO/WindowState(754): WIN DEATH: Window{42adff40 u0 com.test.MotionDetector/com.test.MotionDetector.MotionDetectActivity}
01-05 21:45:57.757: INFO/PackageManager(754): Running dexopt on: com.test.MotionDetector
01-05 21:45:57.757: INFO/PackageManager(754): Package com.test.MotionDetector codePath changed from /data/app/com.test.MotionDetector-1.apk to /data/app/com.test.MotionDetector-2.apk; Retaining data and using new
01-05 21:45:57.807: INFO/ActivityManager(754): Force stopping com.test.MotionDetector appid=10103 user=-1: update pkg
01-05 21:45:57.807: WARN/PackageManager(754): Code path for pkg : com.test.MotionDetector changing from /data/app/com.test.MotionDetector-1.apk to /data/app/com.test.MotionDetector-2.apk
01-05 21:45:57.807: WARN/PackageManager(754): Resource path for pkg : com.test.MotionDetector changing from /data/app/com.test.MotionDetector-1.apk to /data/app/com.test.MotionDetector-2.apk
01-05 21:45:57.937: INFO/ActivityManager(754): Force stopping com.test.MotionDetector appid=10103 user=0: pkg removed
01-05 21:45:57.987: DEBUG/BackupManagerService(754): Received broadcast Intent { act=android.intent.action.PACKAGE_REMOVED dat=package:com.test.MotionDetector flg=0x4000010 (has extras) }
01-05 21:45:58.047: DEBUG/BackupManagerService(754): Received broadcast Intent { act=android.intent.action.PACKAGE_ADDED dat=package:com.test.MotionDetector flg=0x4000010 (has extras) }
01-05 21:45:58.567: INFO/Icing.InternalIcingCorporaProvider(12750): Updating corpora: A: com.test.MotionDetector, C: MAYBE
01-05 21:45:58.647: DEBUG/PackageAddedReceiver(1086): package added com.test.MotionDetector
01-05 21:45:58.737: INFO/ActivityManager(754): START u0 {flg=0x10000000 cmp=com.test.MotionDetector/.MotionDetectActivity} from pid 4578
01-05 21:45:58.777: INFO/ActivityManager(754): Start proc com.test.MotionDetector for activity com.test.MotionDetector/.MotionDetectActivity: pid=4630 uid=10103 gids={50103, 1028, 1015}
01-05 21:45:59.627: INFO/ActivityManager(754): Displayed com.test.MotionDetector/.MotionDetectActivity: +861ms (total +972ms)
01-05 21:45:59.657: INFO/WindowManager(754): Screen frozen for +869ms due to Window{43cb77a8 u0 com.test.MotionDetector/com.test.MotionDetector.MotionDetectActivity}
Assuming that you want the jpeg saved, you don't need raw callback, so
change the call to takePicture() from:
mCamera.takePicture(null, mPicture, mPicture);
to
mCamera.takePicture(null, null, mPicture);
in your onTouchEvent(). This will use jpeg picture callback.
Calling takePicture() also causes the preview to stop, so you might want to call startPreview() again in your onPictureTaken() callback, if you want to take more pictures or have a preview restarted.
Also, in your onTouchEvent(), you might be getting multiple events, so filter for the one that works for you:
#Override
public boolean onTouchEvent(MotionEvent event) {
Toast.makeText(context, "Picture taken", Toast.LENGTH_SHORT).show();
//System.gc(); tried this because it was suggested in a stackoverflow question but it didn't help.
switch(event.getAction()) {
case MotionEvent.ACTION_DOWN:
// A pressed gesture has started, the motion contains the initial starting location
break;
case MotionEvent.ACTION_UP:
// A pressed gesture has finished, the motion contains the final release location
// as well as any intermediate points since the last down or move event.
mCamera.takePicture(null, mPicture, mPicture);
break;
default:
break;
}
return true; //processed
}
If you place takePicture() in ACTION_DOWN, it will be called as soon as you touch the screen, whereas when in ACTION_UP, it will happen when you remove finger. See which one works for you.
I have been able to export my code into an application and use the Tess-Two file from this tutorial
to integrate the tesseract into it. But now I'm facing problems; when the picture is sent to the tesseract it just returns the same random characters each time: 'f' wig, W fin. A. " 5' ' ,{ >>zv' ' ~" > ';>'. What seems to be the problem?
ImageView iv;
TextView tv;
protected Bitmap _image;
protected Bitmap bmp;
public static String The_path = "/mnt/sdcard/DCIM/100MEDIA/TESS.jpg";
public static String lang = "eng";
public static final String DATA_PATH = Environment.getExternalStorageDirectory().toString() + "/SimpleAndroidOCR/";
private int pageSegmentationMode = TessBaseAPI.PageSegMode.PSM_AUTO;
#Override
public void onCreate(Bundle savedInstanceState) {
try {
AssetManager assetManager = getAssets();
InputStream in = assetManager.open("tessdata/eng.traineddata");
//GZIPInputStream gin = new GZIPInputStream(in);
OutputStream out = new FileOutputStream(DATA_PATH + "tessdata/eng.traineddata");
//Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
//while ((len = gin.read(buf)) > 0) {
while ((len = in.read(buf)) > 0) {
out.write(buf, 0, len);
}
in.close();
//gin.close();
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
iv = (ImageView) findViewById(R.id.imageView1);
tv = (TextView) findViewById(R.id.textView1);
Button but = (Button) findViewById(R.id.button1);
Button but2 = (Button) findViewById(R.id.button2);
but.setOnClickListener(new OnClickListener() {
public void onClick(View v){
//File file = new File( _path );
//Uri outputFileUri = Uri.fromFile( file );
Intent intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
//intent.putExtra( MediaStore.EXTRA_OUTPUT, outputFileUri );
startActivityForResult(intent, 0);
}
});
but2.setOnClickListener(new OnClickListener() {
public void onClick(View v){
TessBaseAPI baseApi = new TessBaseAPI();
baseApi.setDebug(true);
baseApi.setPageSegMode(pageSegmentationMode);
baseApi.init(DATA_PATH, lang);
// DATA_PATH = Path to the storage
// lang for which the language data exists, usually "eng"
try {
baseApi.setImage(ReadFile.readBitmap(bmp));
String recognizedText = baseApi.getUTF8Text();
txt(recognizedText);
} catch(RuntimeException e) {
}
baseApi.end();
}
private void txt(String txt) {
// TODO Auto-generated method stub
tv.setText(txt);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
options.inSampleSize = 4;
Bitmap bitmap = BitmapFactory.decodeFile(The_path, options);
try {
ExifInterface exif = new ExifInterface(The_path);
int exifOrientation = exif.getAttributeInt(
ExifInterface.TAG_ORIENTATION,
ExifInterface.ORIENTATION_NORMAL);
int rotate = 0;
switch (exifOrientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
rotate = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
rotate = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
rotate = 270;
break;
}
if (rotate != 0) {
// Getting width & height of the given image.
int w = bitmap.getWidth();
int h = bitmap.getHeight();
// Setting pre rotate
Matrix mtx = new Matrix();
mtx.preRotate(rotate);
// Rotating Bitmap
bitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, mtx, false);
}
bitmap = toGrayscale(bitmap);
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
} catch (IOException e) {
}
_image = (Bitmap) data.getExtras().get("data");
iv.setImageBitmap(_image);
bmp = bitmap;
} public static Bitmap toGrayscale(Bitmap bmpOriginal){
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
here is the new log cat after adding the grayscale function:
(receiving a new set of reoccurring random characters)
01-26 10:21:36.973: D/libEGL(1389): loaded /system/lib/egl/libEGL_adreno200.so
01-26 10:21:36.973: D/libEGL(1389): loaded /system/lib/egl/libGLESv1_CM_adreno200.so
01-26 10:21:36.973: D/libEGL(1389): loaded /system/lib/egl/libGLESv2_adreno200.so
01-26 10:21:36.983: I/Adreno200-EGL(1389): <eglInitialize:269>: EGL 1.4 QUALCOMM build: Nondeterministic AU_full_mako_PARTNER-ANDROID/JB-MR1- DEV_CL2946718_release_AU (CL2946718)
01-26 10:21:36.983: I/Adreno200-EGL(1389): Build Date: 11/04/12 Sun
01-26 10:21:36.983: I/Adreno200-EGL(1389): Local Branch:
01-26 10:21:36.983: I/Adreno200-EGL(1389): Remote Branch: m/partner-android/jb-mr1-dev
01-26 10:21:36.983: I/Adreno200-EGL(1389): Local Patches: NONE
01-26 10:21:36.983: I/Adreno200-EGL(1389): Reconstruct Branch: NOTHING
01-26 10:21:37.043: D/OpenGLRenderer(1389): Enabling debug mode 0
01-26 10:21:45.502: E/BitmapFactory(1389): Unable to decode stream: java.io.FileNotFoundException: /mnt/sdcard/DCIM/100MEDIA/TESS.jpg: open failed: ENOENT (No such file or directory)
01-26 10:21:45.502: E/JHEAD(1389): can't open '/mnt/sdcard/DCIM/100MEDIA/TESS.jpg'
01-26 10:21:45.512: D/AndroidRuntime(1389): Shutting down VM
01-26 10:21:45.512: W/dalvikvm(1389): threadid=1: thread exiting with uncaught exception (group=0x417b0930)
01-26 10:21:45.522: E/AndroidRuntime(1389): FATAL EXCEPTION: main
01-26 10:21:45.522: E/AndroidRuntime(1389): java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=0, result=-1, data=Intent { act=inline-data (has extras) }} to activity {com.cam.calc/cam.calc.Main}: java.lang.NullPointerException
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread.deliverResults(ActivityThread.java:3319)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread.handleSendResult(ActivityThread.java:3362)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread.access$1100(ActivityThread.java:141)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1282)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.os.Handler.dispatchMessage(Handler.java:99)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.os.Looper.loop(Looper.java:137)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread.main(ActivityThread.java:5039)
01-26 10:21:45.522: E/AndroidRuntime(1389): at java.lang.reflect.Method.invokeNative(Native Method)
01-26 10:21:45.522: E/AndroidRuntime(1389): at java.lang.reflect.Method.invoke(Method.java:511)
01-26 10:21:45.522: E/AndroidRuntime(1389): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
01-26 10:21:45.522: E/AndroidRuntime(1389): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
01-26 10:21:45.522: E/AndroidRuntime(1389): at dalvik.system.NativeStart.main(Native Method)
01-26 10:21:45.522: E/AndroidRuntime(1389): Caused by: java.lang.NullPointerException
01-26 10:21:45.522: E/AndroidRuntime(1389): at cam.calc.Main.onActivityResult(Main.java:388)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.Activity.dispatchActivityResult(Activity.java:5293)
01-26 10:21:45.522: E/AndroidRuntime(1389): at android.app.ActivityThread.deliverResults(ActivityThread.java:3315)
01-26 10:21:45.522: E/AndroidRuntime(1389): ... 11 more
You need to process the images before OCR, at least convert the image to black&white (gray scale) can enhance the result :
bitmap = toGrayscale(bitmap);
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
you can user OpenCV or any Image Processing Library, for for simple task like grayscale its enopugh to use
import android.graphics.*;
public static Bitmap toGrayscale(Bitmap bmpOriginal)
{
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
Also if the image is too large you may need to crop the image and get the area that contain the characters & numbers you want to recognize, its also make OCR engine job more easier/more accuracy and sometimes its prevents you from OutOfMemoryException.
I've been trying to look for a similar error but I'm having a hard time... I'm still new to android development, but hopefully someone can shine some direction.
I have a camera app that can preview, but when I tried to click on a button to take the picture, my app crashes. Can someone help me?
[PhotoActivity.java]
public class PhotoActivity extends Activity {
public static final int MEDIA_TYPE_IMAGE = 1;
protected static final String TAG = "Activity";
private Camera mCamera;
private CameraPreview mCameraPreview;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.photo);
mCamera = getCameraInstant();
mCameraPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(id.camera_preview);
preview.addView(mCameraPreview);
// Add a listener to the Capture button
Button captureButton = (Button) findViewById(id.button_capture);
captureButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// get an image from the camera
Log.e("log", "mPicture"+mPicture);
mCamera.takePicture(null, null, mPicture);
}
}
);
}
PictureCallback mPicture = new PictureCallback(){
#Override
public void onPictureTaken(byte[] data, Camera camera) {
// TODO Auto-generated method stub
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if(pictureFile==null){
return;
}
try {
FileOutputStream fos = new FileOutputStream(pictureFile);
fos.write(data);
fos.close();
} catch (FileNotFoundException e) {
Log.d(TAG, "File not found: " + e.getMessage());
} catch (IOException e){
Log.d(TAG, "Error accessing file: " + e.getMessage());
}
}
};
/**
* Helper method to access the camera returns null if
* it cannot get the camera or does not exist
* #return
*/
private Camera getCameraInstant(){
Camera camera = null;
try{
camera=Camera.open();
}catch (Exception e){
// cannot get camera or does not exist
}
return camera;
}
/** Create a File for saving the image */
private File getOutputMediaFile(int type){
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), "MyCameraApp");
if (! mediaStorageDir.exists()){
if (! mediaStorageDir.mkdirs()){
Log.d("MyCameraApp", "failed to create directory");
return null;
}
}
// Create a media file name
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
File mediaFile;
mediaFile = new File(mediaStorageDir.getPath() + File.separator +
"IMG_"+ timeStamp + ".jpg");
return mediaFile;
}
}
Sorry for all the coding, but I'm really in need of some help... Thanks in advance.
UPDATED
[CameraPreview.java]
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "Preview";
private SurfaceHolder mSurfaceHolder;
private Camera mCamera;
//Constructor that obtains context and camera
public CameraPreview(Context context, Camera camera) {
super(context);
//this.mCamera = camera;
this.mCamera = camera;
this.mSurfaceHolder = this.getHolder();
this.mSurfaceHolder.addCallback(this); // we get notified when underlying surface is created and destroyed
this.mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); //this is a deprecated method, is not requierd after 3.0
}
#Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
mCamera.release();
mCamera = Camera.open();
try {
mCamera.setPreviewDisplay(surfaceHolder);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (IOException e) {
// left blank for now
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
#Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
if (mCamera != null) {
Log.d(TAG,"Stopping preview in SurfaceDestroyed().");
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
}
}
#Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format,
int width, int height) {
if(mSurfaceHolder.getSurface()==null){
//preview surface does not exist
return;
}
try {
mCamera.stopPreview();
}catch(Exception e){
//ignore: tried to stop a non-existent preview
}
// start preview with new settings
try {
mCamera.setPreviewDisplay(mSurfaceHolder);
mCamera.setDisplayOrientation(90);
mCamera.startPreview();
} catch (Exception e) {
// intentionally left blank for a test
Log.d(TAG, "Error starting camera preview: "+e.getMessage());
}
}
}
Error
05-09 21:19:29.013: E/AndroidRuntime(3823): FATAL EXCEPTION: main
05-09 21:19:29.013: E/AndroidRuntime(3823): java.lang.RuntimeException: Method called after release()
05-09 20:21:01.214: E/AndroidRuntime(2813): at android.hardware.Camera.native_takePicture(Native Method)
05-09 20:21:01.214: E/AndroidRuntime(2813): at android.hardware.Camera.takePicture(Camera.java:746)
05-09 20:21:01.214: E/AndroidRuntime(2813): at android.hardware.Camera.takePicture(Camera.java:710)
05-09 20:21:01.214: E/AndroidRuntime(2813): at com.liu.photo.PhotoActivity$2.onClick(PhotoActivity.java:73)
05-09 20:21:01.214: E/AndroidRuntime(2813): at android.view.View.performClick(View.java:2486)
05-09 20:21:01.214: E/AndroidRuntime(2813): at android.view.View$PerformClick.run(View.java:9130)
05-09 20:21:01.214: E/AndroidRuntime(2813): at android.os.Handler.handleCallback(Handler.java:587)
05-09 20:21:01.214: E/AndroidRuntime(2813): at android.os.Handler.dispatchMessage(Handler.java:92)
05-09 20:21:01.214: E/AndroidRuntime(2813): at android.os.Looper.loop(Looper.java:130)
05-09 20:21:01.214: E/AndroidRuntime(2813): at android.app.ActivityThread.main(ActivityThread.java:3703)
05-09 20:21:01.214: E/AndroidRuntime(2813): at java.lang.reflect.Method.invokeNative(Native Method)
05-09 20:21:01.214: E/AndroidRuntime(2813): at java.lang.reflect.Method.invoke(Method.java:507)
05-09 20:21:01.214: E/AndroidRuntime(2813): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
05-09 20:21:01.214: E/AndroidRuntime(2813): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
05-09 20:21:01.214: E/AndroidRuntime(2813): at dalvik.system.NativeStart.main(Native Method)
Is this what the stack trace is? I'm very new, still learning the terms as well. Thank you
Remove these two lines from the surfaceCreated method:
mCamera.release();
mCamera = Camera.open();
You've already opened the Camera object in your Activity, no need to release it and reopen it again.
Edit You should actually remove your whole implementation of surfaceCreated and just leave the implementation empty. You're just repeating what you've already done in surfaceChanged, which is the important place to implement it anyway.
Please see this page:
http://developer.android.com/reference/android/hardware/Camera.html
And make sure you follow the rules.
Especially pay attention that you must start preview before you take a picture.