I'm experiencing an odd problem. I'm doing my testing on an HTC EVO. I have written a demo camera application targeting 2.2 and almost everything works correctly. The problem is that after taking three or four pictures, the application crashes and gives me the following messages:
D/QualcommCameraHardware( 64): takePicture(479)
D/QualcommCameraHardware( 64): val_ril_status = 0,val_wimax_status = 0,val_hotspot_status = 0,val_low_temp_limit = 10.000000,val_batt_temp = 29.799999,val_low_temp_limit = 15,val_batt_cap = 96
D/QualcommCameraHardware( 64): FLASHLIGHT is ENABLED
D/QualcommCameraHardware( 64): stopPreviewInternal E: 1
D/QualcommCameraHardware( 64): cancelAutoFocusInternal E
D/QualcommCameraHardware( 64): cancelAutoFocusInternal X: 0
I/QualcommCameraHardware( 64): deinitPreview E
D/QualcommCameraHardware( 64): launch_watchdog_thread:
D/QualcommCameraHardware( 64): watchdog_thread_id = 369048
I/QualcommCameraHardware( 64): register_buf: camfd = 35, reg = 1 buffer = 0x4153f000
I/QualcommCameraHardware( 64): register_buf: camfd = 35, reg = 1 buffer = 0x415bf000
I/QualcommCameraHardware( 64): register_buf: camfd = 35, reg = 1 buffer = 0x4163f000
I/QualcommCameraHardware( 64): register_buf: camfd = 35, reg = 1 buffer = 0x416bf000
I/QualcommCameraHardware( 64): register_buf: camfd = 38, reg = 1 buffer = 0x4331d000
I/QualcommCameraHardware( 64): register_buf: camfd = 38, reg = 1 buffer = 0x4351d000
I/QualcommCameraHardware( 64): register_buf: camfd = 38, reg = 1 buffer = 0x4371d000
I/QualcommCameraHardware( 64): register_buf: camfd = 38, reg = 1 buffer = 0x4391d000
I/QualcommCameraHardware( 64): register_buf: camfd = 38, reg = 1 buffer = 0x43b1d000
I/QualcommCameraHardware( 64): register_buf: camfd = 38, reg = 1 buffer = 0x43d1d000
I/QualcommCameraHardware( 64): register_buf: camfd = 38, reg = 1 buffer = 0x43f1d000
I/QualcommCameraHardware( 64): register_buf: camfd = 38, reg = 1 buffer = 0x4411d000
I/QualcommCameraHardware( 64): deinitPreview X
D/QualcommCameraHardware( 64): stopPreviewInternal X: 0
D/QualcommCameraHardware( 64): initRaw E: raw size=3264x2448
D/QualcommCameraHardware( 64): initRaw: raw ration = 0.750000, display size=768x432
D/QualcommCameraHardware( 64): initRaw: thumbnail_width=768, thumbnail_height=576, thumbnail_buffer_size=663552
D/QualcommCameraHardware( 64): native_access_parm: fd 24, type 1, length 32
D/mm-camera-ov8810_u( 64): andy cam_mode_sel 0
D/QualcommCameraHardware( 64): initRaw: initializing mRawHeap.
E/MemoryHeapBase( 64): error opening /dev/pmem_camera: No such file or directory
E/QualcommCameraHardware( 64): failed to construct master heap for pmem pool /dev/pmem_camera
E/QualcommCameraHardware( 64): initRaw X failed with pmem_camera, trying with pmem_adsp
D/QualcommCameraHardware( 64): frame_thread X
D/QualcommCameraHardware( 64): watchdog_thread_id = 369048
D/QualcommCameraHardware( 64): release_watchdog_thread: frame_thread_released = 1
E/MemoryHeapBase( 64): mmap(fd=38, size=11988992) failed (Invalid argument)
E/QualcommCameraHardware( 64): failed to construct master heap for pmem pool /dev/pmem_adsp
E/QualcommCameraHardware( 64): initRaw X: error initializing mRawHeap
E/QualcommCameraHardware( 64): initRaw failed. Not taking picture.
D/AndroidRuntime( 2650): Shutting down VM
W/dalvikvm( 2650): threadid=1: thread exiting with uncaught exception (group=0x400259f8)
E/AndroidRuntime( 2650): FATAL EXCEPTION: main
E/AndroidRuntime( 2650): java.lang.RuntimeException: takePicture failed
E/AndroidRuntime( 2650): at android.hardware.Camera.native_takePicture(Native Method)
E/AndroidRuntime( 2650): at android.hardware.Camera.takePicture(Camera.java:535)
E/AndroidRuntime( 2650): at android.hardware.Camera.takePicture(Camera.java:503)
E/AndroidRuntime( 2650): at spikes.cameraSpike03.MainActivity.takePicture(MainActivity.java:90)
E/AndroidRuntime( 2650): at spikes.cameraSpike03.MainActivity.access$3(MainActivity.java:87)
E/AndroidRuntime( 2650): at spikes.cameraSpike03.MainActivity$3.onClick(MainActivity.java:80)
E/AndroidRuntime( 2650): at android.view.View.performClick(View.java:2408)
E/AndroidRuntime( 2650): at android.view.View$PerformClick.run(View.java:8817)
E/AndroidRuntime( 2650): at android.os.Handler.handleCallback(Handler.java:587)
E/AndroidRuntime( 2650): at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime( 2650): at android.os.Looper.loop(Looper.java:144)
E/AndroidRuntime( 2650): at android.app.ActivityThread.main(ActivityThread.java:4937)
E/AndroidRuntime( 2650): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime( 2650): at java.lang.reflect.Method.invoke(Method.java:521)
E/AndroidRuntime( 2650): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
E/AndroidRuntime( 2650): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
E/AndroidRuntime( 2650): at dalvik.system.NativeStart.main(Native Method)
W/ActivityManager( 107): Force finishing activity spikes.cameraSpike03/.MainActivity
D/QualcommCameraHardware( 64): void* watchdog(void*), frame_thread_released = 1, cnt = 0
D/QualcommCameraHardware( 64): void* watchdog(void*), exit, frame_thread_released=1
D/QualcommCameraHardware( 64): void release_watchdog_thread(): pthread_join succeeded on watchdog.
Could this be a memory management problem?
Below is all the code I'm using.
[AndroidManifest.xml]
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="spikes.cameraSpike03"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="true">
<activity android:name=".MainActivity" android:label="@string/app_name" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="8" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera.flash" />
</manifest>
[main.xml]
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
<SurfaceView android:id="@+id/svCameraView" android:layout_width="fill_parent" android:layout_height="fill_parent" />
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:background="#3000" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:gravity="center_horizontal">
<Button android:id="@+id/btnCapture" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="capture" />
<CheckBox android:id="@+id/chkAutofocus" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Autofocus" />
</LinearLayout>
</RelativeLayout>
[MainActivity.java]
package spikes.cameraSpike03;
import java.util.List;
import android.app.Activity;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.PixelFormat;
import android.hardware.Camera;
import android.hardware.Camera.AutoFocusCallback;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.ShutterCallback;
import android.hardware.Camera.Size;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
public class MainActivity extends Activity implements SurfaceHolder.Callback {
private static final String LOG_TAG = MainActivity.class.getName();
private static final String LOG_LINE = "---------------------------------";
private Camera _camera;
private boolean _previewIsRunning = false;
private SurfaceView _svCameraView;
private SurfaceHolder _surfaceHolder;
private Button _btnCapture;
private CheckBox _chkAutofocus;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
_svCameraView = (SurfaceView)findViewById(R.id.svCameraView);
_surfaceHolder = _svCameraView.getHolder();
_surfaceHolder.addCallback(this);
_surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
_chkAutofocus = (CheckBox)findViewById(R.id.chkAutofocus);
_btnCapture = (Button)findViewById(R.id.btnCapture);
_btnCapture.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(_camera != null){
//Decide whether or not to use autofocus
if(_chkAutofocus.isChecked()){
Log.d(LOG_TAG, LOG_LINE + "Preparing to take the picture using autofocus...");
_camera.autoFocus(new AutoFocusCallback() {
@Override
public void onAutoFocus(boolean success, Camera camera) {
Log.d(LOG_TAG, LOG_LINE + "_camera.autoFocus.onAutoFocus(...) entered.");
takePicture();
Log.d(LOG_TAG, LOG_LINE + "_camera.autoFocus.onAutoFocus(...) finished.");
}
});
}
else{
Log.d(LOG_TAG, LOG_LINE + "Preparing to take the picture without autofocus...");
takePicture();
}
}
}
});
}
private void takePicture(){
Log.d(LOG_TAG, LOG_LINE + "takePicture() entered.");
_camera.takePicture(_shutterCallback, null, _jpegCallback);
_previewIsRunning = false;
Log.d(LOG_TAG, LOG_LINE + "takePicture() finished.");
}
private ShutterCallback _shutterCallback = new ShutterCallback() {
@Override
public void onShutter() {
Log.d(LOG_TAG, LOG_LINE + "_shutterCallback.onShutter() called.");
}
};
private PictureCallback _jpegCallback = new PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.d(LOG_TAG, LOG_LINE + "_jpegCallback.onPictureTaken() called.");
_camera.startPreview();
_previewIsRunning = true;
}
};
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
if(_previewIsRunning){
Log.d(LOG_TAG, LOG_LINE + "About to stop preview...");
_camera.stopPreview();
Log.d(LOG_TAG, LOG_LINE + "Stopped preview.");
}
try{
Log.d(LOG_TAG, LOG_LINE + "About to set up camera parameters...");
Camera.Parameters parameters = _camera.getParameters();
//Get the optimal preview size so we don't get an exception when setting the parameters
List<Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
Size optimalPreviewSize = CameraUtil.getOptimalPreviewSize(supportedPreviewSizes, width, height);
parameters.setPreviewSize(optimalPreviewSize.width, optimalPreviewSize.height);
parameters.setFocusMode(Parameters.FOCUS_MODE_AUTO);
parameters.setFlashMode(Parameters.FLASH_MODE_AUTO);
_camera.setDisplayOrientation(90);
_camera.setParameters(parameters);
_camera.setPreviewDisplay(holder);
Log.d(LOG_TAG, LOG_LINE + "Finished setting up camera parameters.");
}
catch(Exception ex){
ex.printStackTrace();
Log.e(LOG_TAG, ex.toString());
}
Log.d(LOG_TAG, LOG_LINE + "About to start preview...");
_camera.startPreview();
_previewIsRunning = true;
Log.d(LOG_TAG, LOG_LINE + "Started preview.");
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
_camera = Camera.open();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(LOG_TAG, LOG_LINE + "Tearing down camera because surface was destroyed...");
_camera.stopPreview();
_previewIsRunning = false;
_camera.release();
Log.d(LOG_TAG, LOG_LINE + "Finished tearing down camera because surface was destroyed.");
}
@Override
public void onConfigurationChanged(Configuration newConfig){
Log.d(LOG_TAG, LOG_LINE + "About to set request orientation to SCREEN_ORIENTATION_PORTRAIT...");
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
Log.d(LOG_TAG, LOG_LINE + "Successfully set request orientation to SCREEN_ORIENTATION_PORTRAIT.");
}
}
[CameraUtil.java]
package spikes.cameraSpike03;
import java.util.List;
import android.hardware.Camera.Size;
public class CameraUtil {
private CameraUtil(){}
/**
* Returns a Size object containing the dimensions for an optimal preview size for the current hardware.
* This code is based on that found at: http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.html
*
* @param supportedSizes
* A list of Size objects representing all the known preview sizes supported by this hardware.
*
* @param w
* The surface width.
*
* @param h
* The surface height.
*
* @return
* Returns a Size object containing the dimensions for an optimal preview size for the current hardware.
*/
public static Size getOptimalPreviewSize(List<Size> supportedSizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.05;
double targetRatio = (double) w / h;
if (supportedSizes == null) return null;
Size optimalSize = null;
double minDiff = Double.MAX_VALUE;
int targetHeight = h;
// Try to find an size match aspect ratio and size
for (Size size : supportedSizes) {
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);
}
}
// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Size size : supportedSizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}
}
Any suggestions would be greatly appreciated.
Thank you.