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();
...
}
}
Related
Video recording App doesn't get destroyed properly. When i press Back button, the Camera App is onPause(). On starting a new instance of APP the video recording fails. If i manually kill previous instance and re-run APP it works perfect. According to my assumption, all life cycle to kill and release camera are implemented. But the integration or Calls are perhaps creating problem. Need help to sort it out, please.
CameraPreview Class
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Camera mCamera;
private MyDrawing md;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
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) {
try {
// create the surface and start camera preview
if (mCamera == null) {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
}
} catch (IOException e) {
Log.d(VIEW_LOG_TAG, "Error setting camera preview: " + e.getMessage());
}
}
public void refreshCamera(Camera camera) {
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
setCamera(camera);
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
//startFaceDetection();
} catch (Exception e) {
Log.d(VIEW_LOG_TAG, "Error starting camera preview: " + e.getMessage());
}
}
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.
refreshCamera(mCamera);
}
public void setCamera(Camera camera) {
//method to set a camera instance
mCamera = camera;
mCamera.setFaceDetectionListener(faceDetectionListener);
startFaceDetection();
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
mCamera.release();
}
private Camera.FaceDetectionListener faceDetectionListener = new Camera.FaceDetectionListener() {
#Override
public void onFaceDetection(Camera.Face[] faces, Camera c) {
if (faces.length > 0) {
Log.d("FaceDetection", "face detected X and Y are as: " + faces.length +
" Face 1 Location X: " + faces[0].rect.centerX() +
"Y: " + faces[0].rect.centerY() +" LIES IN "+(MyDrawing.w-MyDrawing.radius) +"--"+(MyDrawing.w+MyDrawing.radius));
if(faces[0].rect.centerX()>=0 && faces[0].rect.centerX()<115 )
{
Log.d("ALERT = ", "Detection Started" );
AndroidVideoCaptureExample.capture.setText("Recording/ stopNsave ");
AndroidVideoCaptureExample.faceDetect();
}
} else {
Log.d("FaceDetection", "circle cordinates are as: " + (MyDrawing.w-MyDrawing.radius) +"cX"+ MyDrawing.radius+"cY");
}
}
};
public void startFaceDetection(){
// Try starting Face Detection
Camera.Parameters params = mCamera.getParameters();
// start face detection only *after* preview has started
if (params.getMaxNumDetectedFaces() > 0){
// camera supports face detection, so can start it:
mCamera.startFaceDetection();
}
}
}
Main
public class AndroidVideoCaptureExample extends Activity {
private static Camera mCamera;
private static int vWidth,vHeight;
private CameraPreview mPreview;
public static MediaRecorder mediaRecorder;
public static Button capture, switchCamera;
private Context myContext;
private FrameLayout cameraPreview;
private boolean cameraFront = false;
private static int desiredwidth=640, desiredheight=360;
private MyDrawing md;
public static boolean vRecording = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
myContext = this;
initialize();
Log.d("FaceDetection", "face detected BASEER" );
}
private int findFrontFacingCamera() {
int cameraId = -1;
// Search for the front facing camera
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == CameraInfo.CAMERA_FACING_FRONT) {
cameraId = i;
cameraFront = true;
break;
}
}
return cameraId;
}
public void onResume() {
super.onResume();
if (!hasCamera(myContext)) {
Toast toast = Toast.makeText(myContext, "Sorry, your phone does not have a camera!", Toast.LENGTH_LONG);
toast.show();
finish();
}
if (mCamera == null) {
// if the front facing camera does not exist
if (findFrontFacingCamera() < 0) {
Toast.makeText(this, "No front facing camera found.", Toast.LENGTH_LONG).show();
switchCamera.setVisibility(View.GONE);
}
mCamera = Camera.open(findFrontFacingCamera());
mCamera.setDisplayOrientation(90);
mPreview.refreshCamera(mCamera);
}
}
public void initialize() {
cameraPreview = (FrameLayout) findViewById(R.id.camera_preview);
mPreview = new CameraPreview(myContext, mCamera);
cameraPreview.addView(mPreview);
capture = (Button) findViewById(R.id.button_capture);
capture.setOnClickListener(captrureListener);
}
#Override
protected void onPause() {
super.onPause();
// when on Pause, release camera in order to be used from other
// applications
releaseCamera();
}
private boolean hasCamera(Context context) {
// check if the device has camera
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
return true;
} else {
return false;
}
}
static boolean recording = false;
OnClickListener captrureListener = new OnClickListener() {
#Override
public void onClick(View v) {
if (recording) {
// stop recording and release camera
mediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
Toast.makeText(AndroidVideoCaptureExample.this, "Video captured!", Toast.LENGTH_LONG).show();
Toast.makeText(AndroidVideoCaptureExample.this, vWidth+"BY"+vHeight, Toast.LENGTH_LONG).show();
recording = false;
}
}
};
public static void faceDetect()
{
prepareMediaRecorder();
recording = true;
mediaRecorder.start();
}
private static void releaseMediaRecorder() {
if (mediaRecorder != null) {
mediaRecorder.reset(); // clear recorder configuration
mediaRecorder.release(); // release the recorder object
mediaRecorder = null;
mCamera.lock(); // lock camera for later use
}
}
private static boolean prepareMediaRecorder() {
List<Camera.Size> videosizes = mCamera.getParameters().getSupportedVideoSizes();
Camera.Size videosize = videosizes.get(1);
Camera.Size optimalVideoSize = getOptimalPreviewSize(videosize, desiredwidth, desiredheight);
vWidth = optimalVideoSize.width;//mCamera.getParameters().getPreviewSize().width;
vHeight = optimalVideoSize.height;//mCamera.getParameters().getPreviewSize().height;
mediaRecorder = new MediaRecorder();
mCamera.unlock();
mediaRecorder.setCamera(mCamera);
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_LOW));
mediaRecorder.setVideoEncodingBitRate(512* 1000);
mediaRecorder.setVideoFrameRate(15);
mediaRecorder.setVideoSize(optimalVideoSize.width, optimalVideoSize.height);
mediaRecorder.setOutputFile("/sdcard/myvideo.mp4");
mediaRecorder.setMaxDuration(600000); // Set max duration 60 sec.
mediaRecorder.setMaxFileSize(50000000); // Set max file size 50M
try {
mediaRecorder.prepare();
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (IOException e) {
releaseMediaRecorder();
return false;
}
return true;
}
private void releaseCamera() {
// stop and release camera
if (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
private static Camera.Size getOptimalPreviewSize(Camera.Size sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.2;
double targetRatio = (double) w / h;
if (sizes == null)
return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
Camera.Size size = sizes;
Log.d("Camera", "Checking size " + size.width + "w " + size.height
+ "h");
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) <= ASPECT_TOLERANCE)
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;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
return optimalSize;
}
}
ErrorLog
Error/Crash:If App goes to foreground and reopens, As soon as face is detected (video recording starts on this detection)App crashes with following Error.
E/MediaRecorder: start failed: -38
D/AndroidRuntime: Shutting down VM
W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x42230c08)
E/AndroidRuntime: FATAL EXCEPTION: main
E/AndroidRuntime: Process: com.javacodegeeks.androidvideocaptureexample, PID: 8350
E/AndroidRuntime: java.lang.IllegalStateException
E/AndroidRuntime: at android.media.MediaRecorder.start(Native Method)
E/AndroidRuntime: at com.javacodegeeks.androidvideocaptureexample.AndroidVideoCaptureExample.faceDetect(AndroidVideoCaptureExample.java:141)
E/AndroidRuntime: at com.javacodegeeks.androidvideocaptureexample.CameraPreview$1.onFaceDetection(CameraPreview.java:105)
E/AndroidRuntime: at android.hardware.Camera$EventHandler.handleMessage(Camera.java:1015)
E/AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime: at android.os.Looper.loop(Looper.java:146)
E/AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5635)
E/AndroidRuntime: at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime: at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
E/AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
E/AndroidRuntime: at dalvik.system.NativeStart.main(Native Method)
CameraPreview.surfaceDestroyed() release the camera, but does not set mCamera = null;. When the app is recalled from background, AndroidVideoCaptureExample.onCreate() may be skipped, so the mPreview object with an old mCamera reference will be used. Now if surfaceChanged() is executed before AndroidVideoCaptureExample.onResume() calls mPreview.refreshCamera(mCamera);, you are screwed.
The easy fix would be to add mCamera = null; to CameraPreview.surfaceDestroyed(), and check if (camera == null) { return; } in the beginning of CameraPreview.refreshCamera(Camera camera).
BTW, CameraPreview.surfaceCreated() has some broken code:
if (mCamera == null) {
mCamera.setPreviewDisplay(holder);
…
You can simply delete all this block, these operations will be performed in refreshCamera() called from surfaceChanged().
You can also remove the second parameter from CameraPreview constructor.
Get rid of those static variables and see if that solves your problem. When your last activity is finished, the Android framework may keep the process and VM alive to reduce the startup overhead the next time you launch the app. When that happens, all your static variables will retain their old values. (Your Application instance may also be retained, so beware of putting any data there, and never count on Application#onCreate(...) being called when your app is launched.)
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?
I am developing an Android Application. I created a custom camera class to capture images. It is working fine in som many devices but when i Tried it with Samsung Galaxy S4 it returns image with gray lins as shown. My Code is :
![`*public void surfaceCreated(SurfaceHolder holder) {
frontCam = SharedUserPrefs.getSharedPrefData(AutoCapture.this,
Constants.IS_FRONT_CAMERA);
if (frontCam.equals(Constants.VALUE_ON)) {
for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
try {
mCamera = Camera.open(camIdx);
} catch (RuntimeException e) {
Log.e(TAG,
"Camera failed to open: "
+ e.getLocalizedMessage());
}
}
}
} else {
mCamera = Camera.open();
}
mCamera.setDisplayOrientation(90);
Camera.Parameters p = mCamera.getParameters();
if (getPackageManager().hasSystemFeature(
PackageManager.FEATURE_CAMERA_FLASH)) {
if (flashOn.equals(Constants.VALUE_ON)) {
{
p.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
}
}
} else {
p.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
}
p.setPictureFormat(ImageFormat.JPEG);
List<Camera.Size> previewSizes = p.getSupportedPreviewSizes();
Camera.Size previewsize = previewSizes.get(0);
for (Camera.Size size : previewSizes) {
Log.d("Width---" + size.width, "Height---" + size.height);
}
p.setPreviewSize(previewsize.width, previewsize.height);
mCamera.setParameters(p);
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
Log.e(TAG, "surfaceChanged");
if (mPreviewRunning) {
mCamera.stopPreview();
}
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
System.out.println("Caught exception in surface chagned");
e.printStackTrace();
}
mCamera.startPreview();
mPreviewRunning = true;
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e(TAG, "surfaceDestroyed");
if (mPreviewRunning == false) {
if (mCamera != null) {
mPreviewRunning = false;
mCamera.stopPreview();
mCamera.release();
}
if (mCamera != null) {
mPreviewRunning = false;
mCamera.release();
}
}/*
* else if (mCamera != null) { mPreviewRunning = false;
* mCamera.stopPreview(); mCamera.release(); }
*/
}*`][2]
I think you have the same issue me and this other guy did.
Samsung Galaxy S4 , Image gets corrupted while taking from camera
I am creating a camera app but I have problems on startPreview, it sends me:
java.lang.RuntimeException: startPreview failed
here is my camera Activity:
public class CameraActivity extends Activity {
private Camera mCamera;
private CameraPreview mPreview;
private Target_Frame targetFrame;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.camera_layout);
mCamera=getCameraInstance();
mPreview=new CameraPreview(this, mCamera);
FrameLayout preview=(FrameLayout)findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
/** Check if this device has a camera only if not specified in the manifest */
public boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// this device has a camera
return true;
} else {
// no camera on this device
return false;
}
}
/** 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)
}
return c; // returns null if camera is unavailable
}
/**Check if the device has flash*/
public boolean checkFlash(Context context){
if(context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)){
//the device has flash
return true;
}else{
//no flash
return false;
}
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
releaseCamera();
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
releaseCamera();
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
//Test if i have to put all this code like in onCreate
if(mCamera!=null){
return;
}
mCamera=getCameraInstance();
if(mPreview!=null){
return;
}
mPreview=new CameraPreview(this, mCamera);
FrameLayout preview=(FrameLayout)findViewById(R.id.camera_preview);
preview.addView(mPreview);
}
private void releaseCamera(){
if (mCamera != null){
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}}
And here is my SurfaceView code:
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
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.
try {
mCamera.setPreviewDisplay(holder);
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
Parameters parameters= mCamera.getParameters();
parameters.setPreviewSize(w, h);
mCamera.setParameters(parameters);
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e){
Log.d(TAG, "Error starting camera preview: " + e.getMessage());
}
}
}
And here is my error log:
12-01 13:17:01.135: E/AndroidRuntime(1161): FATAL EXCEPTION: main
12-01 13:17:01.135: E/AndroidRuntime(1161): java.lang.RuntimeException: startPreview
12-01 13:17:01.135: E/AndroidRuntime(1161): at com.example.prueba.CameraPreview.surfaceCreated(CameraPreview.java:36)
I have solved deleting some lines in surfaceChanged
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.
Log.d("Function", "surfaceChanged iniciado");
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());
}
}
So the error must be in i one of these lines:
Parameters parameters= mCamera.getParameters();
parameters.setPreviewSize(w, h);
mCamera.setParameters(parameters);
Someone could explain me what was wrong in those lines?
Is (w, h) a valid preview size for your camera?
You can use mCamera.getParameters().getSupportedPreviewSizes() to get all of the valid preview sizes.
Its late, but if someones looking for the answer
The variables w and h are not the optimal preview sizes . You can get optimal preview sizes using the function
public static Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio=(double)h / w;
if (sizes == null) return null;
Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
and you can call the function using
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
..
size=getOptimalPreviewSize(parameters.getSupportedPreviewSizes(), w, h);
parameters.setPreviewSize(size.getWidth(), size.getHeight());
..
}
public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, now tell the camera where to draw the preview.
try {
mCamera.setPreviewDisplay(holder);
mCamera.getParameters().getSupportedPreviewSizes();
mCamera.startPreview();
Log.d(TAG, "Camera preview started.");
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
I had this error, and it's because I didn't call releaseCamera on the onPause the first time I start my app.
After a reboot, everything works fine ^^
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!