My program is suppose to store a byte[] image from the camera in an ArrayList every 250 ms.
I am testing the same code on 2 separate devices:
the first is a Nexus 7 running Android 4.4.2 and the second is a Nexus 10 running Android 4.4.3.
The Nexus 7 runs the scheduleWithFixedDelay function perfectly, but the Nexus 10 does not. The Nexus 10 runs it once and then stops.
class RunnableCamera implements Runnable {
ScheduledExecutorService serviceCam = Executors.newSingleThreadScheduledExecutor();
#Override
public void run() {
startCamera CAM = new startCamera();
serviceCam.scheduleWithFixedDelay(new Runnable()
{
#Override
public void run()
{
camera.takePicture(null, null, mPicture);
}
}, 0, 250, TimeUnit.MILLISECONDS);
}
private PictureCallback mPicture = new PictureCallback() {
#Override
public void onPictureTaken(byte[] data, Camera camera) {
camera.startPreview();
imagesArrayList.add(data);
Log.d("image", "byte[] added to ArrayList");
}
};
public class startCamera implements Callback {
//private Camera camera;
private SurfaceHolder holder = null;
public startCamera() {
videoView = (VideoView) findViewById(R.id.vwCamera);
holder = videoView.getHolder();
holder.addCallback(this);
Log.d("bro", "startCamera() constructor");
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
try {
Log.i("bro", "surfaceCreated");
camera = Camera.open(0);
camera.setDisplayOrientation(90);
if (camera != null) {
camera.setPreviewDisplay(holder);
} else {
Log.i("bro", "camera = null");
}
} catch (Exception e) {
Log.v(TAG, "Could not start the preview-Display123");
e.printStackTrace();
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i("bro", "surfaceChanged");
//Sets correct preview resolution
if (holder.getSurface() == null){
Log.i("bro", "holder.getSurface() == null");
return;
}
Camera.Parameters parameters = camera.getParameters();
Log.i("bro", "camera.getParameters();");
sizes = parameters.getSupportedPreviewSizes();
Log.i("bro", "parameters.getSupportedPreviewSizes();");
Camera.Size optimalSize = getBestPreviewSize(width, height);
try {
parameters.setPreviewSize(optimalSize.width, optimalSize.height);
camera.setParameters(parameters);
} catch (NullPointerException a) {
}
Log.i("bro", "startPreview()");
camera.startPreview();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i("bro", "surfaceDestroyed");
if (camera != null) {
camera.stopPreview();
camera.release();
Log.i("bro", "CAMERA STOPPED");
}
}
private Camera.Size getBestPreviewSize(int width, int height) {
Camera.Size result = null;
Camera.Parameters p = camera.getParameters();
for (Camera.Size size : p.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return result;
}
}
}
In my onCreate method I start the Runnable class like:
Thread thread1 = new Thread(new RunnableCamera());
thread1.start();
If I change the time delay to 600 ms, the Nexus 10 runs it perfectly. I'm wondering if this is a device issue with the first generation Nexus 10, an Android 4.4.3 issue or something wrong with my code. Is there a better way to do this?
Related
I have the some of the following code to use the camera:
#Override
public void surfaceCreated(SurfaceHolder holder) {
if (mCamera == null) {
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
try {
mCamera.setPreviewDisplay(mHolder);
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void resetCamera() {
if (!videoReset) {
if (videoStarted && !videoStopped) {
mMediaRecorder.stop();
}
MediaScannerConnection.scanFile(TherapistActivity.this, new String[]{videoFile.getAbsolutePath()}, null, null);
mMediaRecorder.reset();
mMediaRecorder.release();
mCamera.release();
mCamera = null;
mMediaRecorder = null;
videoReset = true;
initSuccess = false;
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
surfaceWidth = width;
surfaceHeight = height;
try {
if (!initSuccess)
startPreview(mHolder.getSurface());
} catch (IOException e) {
e.printStackTrace();
}
}
private void initRecorder(Surface surface) throws IOException {
Camera.Parameters parameters = mCamera.getParameters();
Camera.Size previewSize = getOptimalPreviewSize(surfaceWidth, surfaceHeight);
if (previewSize != null) {
parameters.setPreviewSize(previewSize.width, previewSize.height);
}
parameters.setVideoStabilization(false);
mCamera.setParameters(parameters);
mCamera.startPreview();
mCamera.unlock();
if (mMediaRecorder == null) mMediaRecorder = new MediaRecorder();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT);
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setVideoEncodingBitRate(3072 * 1000);
mMediaRecorder.setVideoFrameRate(60);
mMediaRecorder.setVideoSize(1280, 720);
mMediaRecorder.setOutputFile(videoFile.getAbsolutePath());
if (!mApp.videoTime) {
mMediaRecorder.setMaxDuration(30000);
} else {
mMediaRecorder.setMaxDuration(Integer.MAX_VALUE);
}
mMediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() {
#Override
public void onInfo(MediaRecorder mr, int what, int extra) {
if (what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
mCameraWrapper.setBackgroundColor(Color.TRANSPARENT);
try {
mCamera.stopPreview();
videoRecorded = true;
} catch (RuntimeException re) {
Log.e("Error", "Could not stop camera!");
} finally {
videoPreviewStarted = false;
}
btRecord.setTag("stop");
btRecord.setBackgroundResource(R.drawable.stop_nobkgrnd_gray);
tvVideoCountdown.setVisibility(View.GONE);
initSuccess = false;
}
}
});
try {
mMediaRecorder.prepare();
videoPreviewStarted = true;
} catch (IllegalStateException e) {
e.printStackTrace();
}
initSuccess = true;
}
}
private Camera.Size getOptimalPreviewSize(int w, int h) {
Camera.Size result = null;
Camera.Parameters p = mCamera.getParameters();
for (Camera.Size size : p.getSupportedPreviewSizes()) {
if (size.width <= w && size.height <= h) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return result;
}
On the Astro Tab A10 running Marshmallow, apparently the Camera isn't being released properly when being run the second time, since the camera fails to open until the device is rebooted. I am pretty sure this isn't a permissions problem, since I granted the app permissions to the camera at runtime as well as including camera permissions in the manifest.
Does anyone know what might be the problem?
EDIT: Here is the stack trace:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mobilityresearch.treadmill3, PID: 4144
java.lang.RuntimeException: Fail to connect to camera service
at android.hardware.Camera.<init>(Camera.java:495)
at android.hardware.Camera.open(Camera.java:341)
at com.mobilityresearch.treadmill3.TherapistActivity.surfaceCreated(TherapistActivity.java:8260)
at android.view.SurfaceView.updateWindow(SurfaceView.java:583)
at android.view.SurfaceView.setVisibility(SurfaceView.java:257)
at com.mobilityresearch.treadmill3.TherapistActivity$26.onClick(TherapistActivity.java:1701)
at android.view.View.performClick(View.java:5204)
at android.view.View$PerformClick.run(View.java:21153)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:742)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:632)
This doesn't happen on any of our other tablets. In fact, it doesn't happen on the older version of the Astro Tab A10 running Android 5.1 Lollipop. I tried calling resetCamera the camera both in surfaceCreated before opening the preview, and surfacedDestroyed after closing the preview, and it doesn't work.
EDIT 2: I just found out that if I actually record video, it works fine, but if I don't record video and only display the preview, it doesn't work.
EDIT 3: Added surfaceChanged and initRecorder. Updated resetCamera.
You are missing call to stopPreview() which stops capturing and drawing preview frames to the surface and setPreviewDisplay(null) which releases the preview display.
Update your resetCamera() as follows:
private void resetCamera() {
...
mCamera.stopPreview();
mCamera.setPreviewDisplay(null);
mCamera.release();
...
}
}
In my camera app, whenever i am capturing images of bright lights such as LED screens. The white images become pink. WHY ?
i am getting bright images like this one
Here is what i have used to capture images:
btnCapture.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (safeToTakePicture) {
camera.takePicture(null, null, mPicture);
safeToTakePicture = false;
}
}
});
#Override
public void onResume() {
super.onResume();
camera=Camera.open();
}
#Override
public void onPause() {
super.onPause();
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera=null;
inPreview=false;
}
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result=null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result=size;
}
else {
int resultArea=result.width * result.height;
int newArea=size.width * size.height;
if (newArea > resultArea) {
result=size;
}
}
}
}
return(result);
}
private Camera.Size getSmallestPictureSize(Camera.Parameters parameters) {
Camera.Size result=null;
for (Camera.Size size : parameters.getSupportedPictureSizes()) {
if (result == null) {
result=size;
}
else {
int resultArea=result.width * result.height;
int newArea=size.width * size.height;
if (newArea < resultArea) {
result=size;
}
}
}
return(result);
}
SurfaceHolder.Callback surfaceCallback=new SurfaceHolder.Callback(){
public void surfaceCreated(SurfaceHolder holder) {
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable t) {
Log.e("PreviewDemo-surfaceCallback",
"Exception in setPreviewDisplay()", t);
Toast.makeText(CameraLauncherActivity.this, t.getMessage(), Toast.LENGTH_LONG).show();
}
}
public void surfaceChanged(SurfaceHolder holder,int format, int width,int height) {
params = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, params);
Camera.Size pictureSize=getSmallestPictureSize(params);
if (size != null && pictureSize != null) {
params.setPreviewSize(size.width, size.height);
params.setPictureSize(pictureSize.width,
pictureSize.height);
camera.setParameters(params);
camera.startPreview();
safeToTakePicture = true;
inPreview=true;
}
public void surfaceDestroyed(SurfaceHolder holder) {
}
};
}
I did not find any solution, and here i am looking for the best way to get bright screen images in white itself not in pink.
I worked with VIDEO ONLY. No pictures.
Noticed, that setDisplayOrientation does affect right display orientation only during preview.
But if to play any video captured either in landscape mode or portrait mode it is always in landscape mode.
I set in AndroidManifest.xml
But used to debug in 4.0.1 device. Maybe that is a problem.
However i noticed that default camera app works fine and capture portrait movies in portrait mode.
What do I miss?...
**CameraRecorder.java
public class CameraRecorder extends Activity {
private CameraPreview mPreview;
private Camera mCamera;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_surface);
// Create an instance of Camera
mCamera = getCameraInstance();
if (mCamera == null) {
Log.e(TAG, "Camera is not available");
finish();
}
// Create our Preview view and set it as the content of our activity.
mPreview = new CameraPreview(this, mCamera);
FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
mPreview.setOnClickListener(startStopListener);
}
private void changeOrientation(int what) {
if (what != orientation) {
setRequestedOrientation(orientation = what);
}
}
OnClickListener startStopListener = new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (isRecording) {
mMediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
mCamera.lock(); // take camera access back from MediaRecorder
// inform the user that recording has stopped
setCaptureButtonText("Capture");
isRecording = false;
} else {
// initialize video camera
if (prepareVideoRecorder()) {
// Camera is available and unlocked, MediaRecorder is
// prepared, now you can start recording
mMediaRecorder.start();
// inform the user that recording has started
isRecording = true;
} else {
// prepare didn't work, release the camera
releaseMediaRecorder();
}
}
}
};
File tempFile;
#Override
protected void onPause() {
super.onPause();
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
releaseCamera(); // release the camera immediately on pause event
}
/** A safe way to get an instance of the Camera object. */
public static Camera getCameraInstance() {
Camera c = null;
try {
c = Camera.open(); // attempt to get a Camera instance
} catch (Exception e) {
// Camera is not available (in use or does not exist)
Log.d(TAG, "Fail to connect to camera service. Is it locked?");
}
}
return c; // returns null if camera is unavailable
}
private boolean prepareVideoRecorder() {
if (mCamera == null)
mCamera = getCameraInstance();
if (mMediaRecorder == null)
mMediaRecorder = new MediaRecorder();
Camera.Parameters p = mCamera.getParameters();
// Step 1: Unlock and set camera to MediaRecorder
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
// Step 2: Set sources
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
CamcorderProfile profile = mPreview.getProfile();// CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
Size previewSize = mPreview.getPreviewSize();
if (previewSize != null) {
profile.videoFrameWidth = previewSize.width;
profile.videoFrameHeight = previewSize.height;
}
mMediaRecorder.setProfile(profile);
// Step 4: Set output file
mMediaRecorder.setOutputFile(MediaFile.getOutputMediaFile(MEDIA_TYPE_VIDEO).toString());
// Step 5: Set the preview output
mMediaRecorder.setPreviewDisplay(mPreview.getHolder().getSurface());
// Step 6: Prepare configured MediaRecorder
try {
mMediaRecorder.prepare();
} catch (IllegalStateException e) {
Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
} catch (IOException e) {
Log.d(TAG, "IOException preparing MediaRecorder: " + e.getMessage());
releaseMediaRecorder();
return false;
}
return true;
}
private void releaseMediaRecorder() {
if (mMediaRecorder != null) {
mMediaRecorder.reset(); // clear recorder configuration
mMediaRecorder.release(); // release the recorder object
mMediaRecorder = null;
mCamera.lock(); // lock camera for later use
}
}
private void releaseCamera() {
if (mPreview != null) {
mPreview.surfaceDestroyed(null);
}
if (mCamera != null) {
mCamera.release(); // release the camera for other applications
mCamera = null;
Log.d(TAG, "Camera released");
}
}
}
CameraPreview.java
/** A basic Camera preview class */
public class CameraPreview extends ViewGroup implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private SurfaceView mSurfaceView;
private Context mContext;
private final String TAG = "CameraPreview";
public CameraPreview(Context context, Camera camera) {
super(context);
mContext = context;
mCamera = camera;
setCamera(mCamera);
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView, 0);
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
mHolder.setKeepScreenOn(true);
}
public SurfaceHolder getHolder() {
return mSurfaceView.getHolder();
}
private Size mPreviewSize;
private List<Size> mSupportedPreviewSizes;
private List<String> mSupportedFlashModes;
public Camera getCamera() {
return mCamera;
}
private CamcorderProfile mProfile;
public CamcorderProfile getProfile() {
return mProfile;
}
public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
mSupportedFlashModes = mCamera.getParameters().getSupportedFlashModes();
mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
// Set the camera to Auto Flash mode.
if (mSupportedFlashModes != null && mSupportedFlashModes.contains(Camera.Parameters.FLASH_MODE_AUTO)) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_AUTO);
mCamera.setParameters(parameters);
}
}
requestLayout();
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
// mCamera.startPreview();
}
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, mProfile.videoFrameWidth, mProfile.videoFrameHeight);
}
setMeasuredDimension(width, height);
}
#Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
if (changed) {
final View cameraView = getChildAt(0);
final int width = right - left;
final int height = bottom - top;
Camera.Parameters p = mCamera.getParameters();
#SuppressWarnings("unused")
int previewWidth = width;
#SuppressWarnings("unused")
int previewHeight = height;
if (mPreviewSize != null) {
Display display = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
switch (display.getRotation()) {
case Surface.ROTATION_0:
mCamera.setDisplayOrientation(90);
break;
case Surface.ROTATION_90:
case Surface.ROTATION_180:
break;
case Surface.ROTATION_270:
mCamera.setDisplayOrientation(180);
break;
}
}
cameraView.layout(0, 0, width, height);
}
}
public void setSupportedPreviewSizes(List<Size> supportedPreviewSizes) {
mSupportedPreviewSizes = supportedPreviewSizes;
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
// Because the CameraDevice object is not a shared resource, it's very
// important to release it when the activity is paused.
try {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
// mCamera.release();
mCamera = null;
Log.d(TAG, "Preview destroyed");
}
} catch (Exception e) {
Log.e(TAG, "Camera release failure.");
}
}
#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 parameters = mCamera.getParameters();
Size previewSize = getPreviewSize();
if (previewSize != null)
parameters.setPreviewSize(previewSize.width, previewSize.height);
mCamera.setParameters(parameters);
// start preview with new settings
try {
previewCamera();
} catch (Exception e) {
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
public Size getPreviewSize() {
return mPreviewSize;
}
public static Size getOptimalPreviewSize(List<Size> sizes, int width, int height) {
double aspectTolerance = 0.05;
double targetRatio = (double) width / height;
if (sizes == null) {
return null;
}
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = height;
// Try to find an size match aspect ratio and size
for (Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > aspectTolerance)
continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
public void previewCamera() {
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Cannot start preview.", e);
}
}
}
Manifest.xml
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
android:name=".client.andi"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".activity.CameraRecorder"
android:label="#string/title_activity_main"
android:screenOrientation="landscape"
android:theme="#android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
** layout.xml**
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/RelativeLayout1"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="bottom"
android:orientation="vertical" >
<FrameLayout
android:id="#+id/camera_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true" >
</FrameLayout>
</RelativeLayout>
You should change android:screenOrientation="landscape" into android:screenOrientation="portrait"
Not sure if you encounter exactly the same problem with mine.
I've stuck with this problem before, too. I found that you can use the function setOrientationHint (API 9). Call this function before you call MediaRecorder.prepare(). You can setup the orientation degree for your output video.
Hope it helps, good luck!
i have an android application which has two camera activities. they switch time to time in between them. after switching several times first activity throws this exception.. any idea why this happen?
how to fix it? Please help me.thank you for reading my question and have a nice day!
public abstract class SampleViewBase extends SurfaceView implements SurfaceHolder.Callback, Runnable {
private static final String TAG = "LogcatActivity";
private Camera mCamera;
private SurfaceHolder mHolder;
private int mFrameWidth;
private int mFrameHeight;
private byte[] mFrame;
private boolean mThreadRun;
private int frameNumber=1;//my
public SampleViewBase(Context context) {///
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
Log.i(TAG, "Instantiated new " + this.getClass());
}
public int getFrameWidth() {
return mFrameWidth;
}
public int getFrameHeight() {
return mFrameHeight;
}
public void surfaceChanged(SurfaceHolder _holder, int format, int width, int height) {
Log.i(TAG, "surfaceCreated");
if (mCamera != null) {
Camera.Parameters params = mCamera.getParameters();
List<Camera.Size> sizes = params.getSupportedPreviewSizes();
//--
List<String> flashing_methords=params.getSupportedFlashModes();
params.setFlashMode(flashing_methords.get(3));
// List<String> color_effects=params.getSupportedColorEffects();
// params.setColorEffect(color_effects.get(2));
//--
mFrameWidth = width;
mFrameHeight = height;
// selecting optimal camera preview size
{
double minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - height) < minDiff) {
mFrameWidth = size.width;
mFrameHeight = size.height;
minDiff = Math.abs(size.height - height);
}
}
}
params.setPreviewSize(getFrameWidth(), getFrameHeight());
mCamera.setParameters(params);
mCamera.startPreview();
}
}
public void surfaceCreated(SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated");
try{
mCamera.reconnect();
mCamera = Camera.open();
mCamera.setPreviewCallback(new PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera camera) {
synchronized (SampleViewBase.this) {
mFrame = data;
SampleViewBase.this.notify();
}
/* if((frameNumber%120)==0){
synchronized (SampleViewBase.this) {
mFrame = data;
SampleViewBase.this.notify();
frameNumber=1;
}
}else{
frameNumber++;
}*/
}
});
(new Thread(this)).start();
}catch (Exception e) {
Log.v(TAG, "reconnect error" + e);
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed");
mThreadRun = false;
if (mCamera != null) {
synchronized (this) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
}
protected abstract Bitmap processFrame(byte[] data);
public void run() {
mThreadRun = true;
Log.i(TAG, "Starting processing thread");
while (mThreadRun) {
Bitmap bmp = null;
synchronized (this) {
try {
this.wait();
bmp = processFrame(mFrame);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (bmp != null) {
Canvas canvas = mHolder.lockCanvas();
if (canvas != null) {
canvas.drawBitmap(bmp, (canvas.getWidth() - getFrameWidth()) / 2, (canvas.getHeight() - getFrameHeight()) / 2, null);
mHolder.unlockCanvasAndPost(canvas);
}
bmp.recycle();
}
}
}
public void releaseAll() {
Log.i(TAG, "hardweare released");
mThreadRun = false;
if (mCamera != null) {
synchronized (this) {
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
}
}
Try to release your camera resources from your activity after you override the back key.
#Override
public void onBackPressed()
{
releaseCamera();
super.onBackPressed();
}
private void releaseCamera()
{
synchronized (this)
{
if(mCamera!=null)
{
mCamera.stopPreview();
mCamera.setPreviewCallback(null);
mCamera.release();
mCamera = null;
}
}
}
add the method releaseCamera() to your SurfaceView and make the call from your activity when user clicks back button.
the mCamera.release() function means to disconnect and release the Camera object resources. which performs a job identical to your next mCamera = null; statement. Why would you do that?
I am trying to switch between the device's Front and Back Camera while showing the camera preview. I am following the sample provide by common ware. Below is the code which I am using. Whenever I click on the Flip button, the surface view goes black, and I don't know where I am going wrong. I have tried to restart the current activity, but I don't want like that.
package com.commonsware.android.camera;
import android.app.Activity;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.Toast;
import android.widget.ToggleButton;
public class PreviewDemo extends Activity {
private SurfaceView preview = null;
private SurfaceHolder previewHolder = null;
private Camera camera = null;
private boolean inPreview = false;
private boolean cameraConfigured = false;
private ToggleButton flipCamera;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
flipCamera = (ToggleButton) findViewById(R.id.flip);
preview = (SurfaceView) findViewById(R.id.preview);
previewHolder = preview.getHolder();
previewHolder.addCallback(surfaceCallback);
previewHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
flipCamera.setOnCheckedChangeListener(new OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView,
boolean isChecked) {
// TODO Auto-generated method stub
restartPreview(isChecked);
}
});
}
#Override
public void onResume() {
super.onResume();
// camera=Camera.open();
int camId = Camera.CameraInfo.CAMERA_FACING_BACK;
if (Camera.getNumberOfCameras() > 1
&& camId < Camera.getNumberOfCameras() - 1) {
// startCamera(camId + 1);
camera = Camera.open(camId + 1);
} else {
// startCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
camera = Camera.open(camId);
}
startPreview();
}
void restartPreview(boolean isFront) {
if (inPreview) {
camera.stopPreview();
}
//
camera.release();
// camera=null;
// inPreview=false;
// /*int camId = Camera.CameraInfo.CAMERA_FACING_BACK;
// if (Camera.getNumberOfCameras() > 1 && camId <
// Camera.getNumberOfCameras() - 1) {
// //startCamera(camId + 1);
// camera = Camera.open(camId + 1);
// } else {
// //startCamera(Camera.CameraInfo.CAMERA_FACING_BACK);
// camera = Camera.open(camId);
// }*/
int camId = Camera.CameraInfo.CAMERA_FACING_BACK;
if (isFront) {
camera = Camera.open(camId);
camera.startPreview();
} else {
camera = Camera.open(camId + 1);
camera.startPreview();
}
// startPreview();
}
#Override
public void onPause() {
if (inPreview) {
camera.stopPreview();
}
camera.release();
camera = null;
inPreview = false;
super.onPause();
}
private Camera.Size getBestPreviewSize(int width, int height,
Camera.Parameters parameters) {
Camera.Size result = null;
for (Camera.Size size : parameters.getSupportedPreviewSizes()) {
if (size.width <= width && size.height <= height) {
if (result == null) {
result = size;
} else {
int resultArea = result.width * result.height;
int newArea = size.width * size.height;
if (newArea > resultArea) {
result = size;
}
}
}
}
return (result);
}
private void initPreview(int width, int height) {
if (camera != null && previewHolder.getSurface() != null) {
try {
camera.setPreviewDisplay(previewHolder);
} catch (Throwable t) {
Log.e("PreviewDemo-surfaceCallback",
"Exception in setPreviewDisplay()", t);
Toast.makeText(PreviewDemo.this, t.getMessage(),
Toast.LENGTH_LONG).show();
}
if (!cameraConfigured) {
Camera.Parameters parameters = camera.getParameters();
Camera.Size size = getBestPreviewSize(width, height, parameters);
if (size != null) {
parameters.setPreviewSize(size.width, size.height);
camera.setParameters(parameters);
cameraConfigured = true;
}
}
}
}
private void startPreview() {
if (cameraConfigured && camera != null) {
camera.startPreview();
inPreview = true;
}
}
SurfaceHolder.Callback surfaceCallback = new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
// no-op -- wait until surfaceChanged()
}
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
initPreview(width, height);
startPreview();
}
public void surfaceDestroyed(SurfaceHolder holder) {
// no-op
if (camera != null) {
/*
* Call stopPreview() to stop updating the preview surface.
*/
camera.stopPreview();
/*
* Important: Call release() to release the camera for use by
* other applications. Applications should release the camera
* immediately in onPause() (and re-open() it in onResume()).
*/
camera.release();
camera = null;
}
}
};
}
You seem to have forgotten to call setPreviewDisplay() (or, in your case, initPreview()) before calling startPreview() from your restartPreviev() method. Effectively, you're trying to start preview without specifying a surface to render the preview into.