我正在尝试构建Android相机&摄像机,并成功地让相机工作。
但是,我遇到摄像机问题,当我开始录制时,应用程序崩溃,手机需要通过取出电池(三星Galaxy S II)重新启动。我已经使用了大量的示例代码,并一直在寻找解决潜在简单问题的方法!
此应用程序的目的是录制视频60秒,然后拍摄5张图像。此过程应该由一个按钮启动,然后循环直到再次按下该按钮,或者电话电量耗尽。我还没有完全实现这个功能!
任何帮助将不胜感激!
---清单---
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.metadev.spacecamx"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="18" />
<!-- Include Camera Properties -->
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<!-- Include Camera Permissions -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.metadev.spacecamx.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
---布局---
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/camera_preview" >
<ImageButton
android:id="@+id/button_capture"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:contentDescription="@null"
android:background="@drawable/ic_action_camera" />
</RelativeLayout>
--- CameraPreview类---
public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "CameraPreview";
private SurfaceHolder mHolder;
private Camera mCamera;
Parameters paras;
public CameraPreview(Context context, Camera camera) {
super(context);
mCamera = camera;
//SurfaceHolder.Callback is implemented to provide notification
//of creation and destruction of underlying surface.
mHolder = getHolder();
mHolder.addCallback(this);
}
//Method to draw camera preview surface.
public void surfaceCreated(SurfaceHolder holder) {
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Camera Preview Creation Failed: " + e.getMessage());
}
}
//Method to release camera preview surface.
public void surfaceDestroyed(SurfaceHolder holder) {
//destroyed
}
//Method to handle changes in orientation of view.
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
if (mHolder.getSurface() == null){
//Preview surface does not exist.
return;
}
try {
mCamera.stopPreview();
} catch (Exception e) {
//Attempt to kill non-existent preview.
}
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d(TAG, "Camera Preview Creation Failed: " + e.getMessage());
}
}
}
--- MainActivity ---
public class MainActivity extends Activity {
private static final String TAG = "CameraRecorderActivity";
public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;
private int pictureCount = 0;
private boolean isRecording = false;
private Camera mCamera;
private CameraPreview mPreview;
private ImageButton mSnapButton;
private MediaRecorder mMediaRecorder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View decorView = getWindow().getDecorView();
//Hide the status bar.
int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
decorView.setSystemUiVisibility(uiOptions);
//Hide the action bar.
ActionBar actionBar = getActionBar();
actionBar.hide();
Boolean hasCamera = checkCameraHardware(getApplicationContext());
if(!hasCamera) {
Toast.makeText(getApplicationContext(), "Camera is unavailable", Toast.LENGTH_LONG).show();
} else {
//Create camera instance
mCamera = getCameraInstance();
mPreview = new CameraPreview(this, mCamera);
RelativeLayout preview = (RelativeLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
mSnapButton = (ImageButton) findViewById(R.id.button_capture);
mSnapButton.bringToFront();
//Image capture button
mSnapButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick (View v) {
if (isRecording) {
// stop recording and release camera
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
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();
// inform user
}
}
//mCamera.takePicture(null, null, mPicture);
}
});
}
}
//Method to check if device has a camera
private boolean checkCameraHardware(Context context) {
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
//Device has a camera
return true;
} else {
//Device does not have a camera.
return false;
}
}
private Camera getCameraInstance() {
Camera c = null;
try {
//Attempt to get camera
c = Camera.open();
} catch (Exception e) {
//Camera unavailable
}
return c;
}
private PictureCallback mPicture = new PictureCallback () {
@Override
public void onPictureTaken(byte[] data, Camera camera) {
File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
if (pictureFile == null) {
Log.d(TAG, "Media Creation Error. Check Storage Permissions.");
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, "Cannot Access File: " + e.getMessage());
} finally {
if (pictureCount < 4) {
mCamera.startPreview();
mCamera.takePicture(null, null, mPicture);
pictureCount++;
} else {
mCamera.startPreview();
}
}
}
};
private boolean prepareVideoRecorder(){
mMediaRecorder = new MediaRecorder();
// 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)
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
// Step 4: Set output file
mMediaRecorder.setOutputFile(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 static File getOutputMediaFile(int type) {
File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES), "SpaceCam");
if(!mediaStorageDir.exists()) {
if(!mediaStorageDir.mkdirs()) {
Log.d("SpaceCam", "Failed to create directory.");
return null;
}
}
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.UK).format(new Date());
File mediaFile;
if (type == MEDIA_TYPE_IMAGE) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator + "IMG_" + timeStamp + ".jpg");
} else if (type == MEDIA_TYPE_VIDEO) {
mediaFile = new File(mediaStorageDir.getPath() + File.separator + "VID_" + timeStamp + ".mp4");
} else {
return null;
}
return mediaFile;
}
@Override
protected void onPause() {
super.onPause();
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mPreview.getHolder().removeCallback(mPreview);
releaseCamera();
RelativeLayout preview = (RelativeLayout) findViewById(R.id.camera_preview);
preview.removeView(mPreview);
mPreview = null;
}
}
@Override
protected void onResume() {
super.onResume();
try {
mCamera = Camera.open(0);
mCamera.setPreviewCallback(null);
mPreview = new CameraPreview(MainActivity.this, mCamera);
RelativeLayout preview = (RelativeLayout) findViewById(R.id.camera_preview);
preview.addView(mPreview);
mSnapButton = (ImageButton) findViewById(R.id.button_capture);
mSnapButton.bringToFront();
} catch (Exception e) {
Log.d(TAG, "Error initiating preview: " + e.getMessage());
}
}
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 (mCamera != null) {
mCamera.release();
mCamera = null;
}
}
}
--- LogCat输出---
02-09 17:59:21.345: D/dalvikvm(6773): Late-enabling CheckJNI
02-09 17:59:21.720: I/Camera(6773): sendBroadcast intent.stop.app-in-app
02-09 17:59:22.020: I/Camera(6773): sendBroadcast intent.stop.app-in-app
02-09 17:59:22.020: D/CameraRecorderActivity(6773): Error initiating preview: Fail to connect to camera service
02-09 17:59:22.110: D/libEGL(6773): loaded /system/lib/egl/libEGL_mali.so
02-09 17:59:22.135: D/libEGL(6773): loaded /system/lib/egl/libGLESv1_CM_mali.so
02-09 17:59:22.150: D/libEGL(6773): loaded /system/lib/egl/libGLESv2_mali.so
02-09 17:59:22.160: D/(6773): Device driver API match
02-09 17:59:22.160: D/(6773): Device driver API version: 10
02-09 17:59:22.160: D/(6773): User space API version: 10
02-09 17:59:22.160: D/(6773): mali: REVISION=Linux-r2p4-02rel0 BUILD_DATE=Thu Oct 25 08:43:05 KST 2012
02-09 17:59:22.195: D/OpenGLRenderer(6773): Enabling debug mode 0
02-09 17:59:22.880: I/Choreographer(6773): Skipped 49 frames! The application may be doing too much work on its main thread.
02-09 17:59:24.030: W/SurfaceView(6773): CHECK surface infomation creating=false formatChanged=false sizeChanged=false visible=false visibleChanged=true surfaceChanged=true realSizeChanged=false redrawNeeded=false left=false top=false
02-09 17:59:24.150: I/Camera(6773): sendBroadcast intent.stop.app-in-app
02-09 17:59:33.925: W/SurfaceView(6773): CHECK surface infomation creating=false formatChanged=false sizeChanged=false visible=false visibleChanged=true surfaceChanged=true realSizeChanged=false redrawNeeded=true left=false top=false
02-09 17:59:33.995: I/Camera(6773): sendBroadcast intent.stop.app-in-app
02-09 17:59:34.205: I/Camera(6773): sendBroadcast intent.stop.app-in-app
02-09 17:59:34.210: D/CameraRecorderActivity(6773): Error initiating preview: Fail to connect to camera service
02-09 17:59:34.985: I/Choreographer(6773): Skipped 45 frames! The application may be doing too much work on its main thread.
02-09 17:59:35.125: E/SpannableStringBuilder(6773): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
02-09 17:59:35.125: E/SpannableStringBuilder(6773): SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
02-09 17:59:40.625: I/MediaRecorderJNI(6773): prepare: surface=0x4f8104f0 (identity=37)
非常感谢你的帮助!!
---更新了LogCat,删除了mCamera.lock()---
02-09 22:46:53.493: D/dalvikvm(6686): Late-enabling CheckJNI
02-09 22:46:53.513: E/jdwp(6686): Failed sending reply to debugger: Broken pipe
02-09 22:46:53.513: D/dalvikvm(6686): Debugger has detached; object registry had 1 entries
02-09 22:46:53.738: I/Camera(6686): sendBroadcast intent.stop.app-in-app
02-09 22:46:54.113: I/Camera(6686): sendBroadcast intent.stop.app-in-app
02-09 22:46:54.118: D/CameraRecorderActivity(6686): Error initiating preview: Fail to connect to camera service
02-09 22:46:54.218: D/libEGL(6686): loaded /system/lib/egl/libEGL_mali.so
02-09 22:46:54.218: D/libEGL(6686): loaded /system/lib/egl/libGLESv1_CM_mali.so
02-09 22:46:54.238: D/libEGL(6686): loaded /system/lib/egl/libGLESv2_mali.so
02-09 22:46:54.243: D/(6686): Device driver API match
02-09 22:46:54.243: D/(6686): Device driver API version: 10
02-09 22:46:54.243: D/(6686): User space API version: 10
02-09 22:46:54.243: D/(6686): mali: REVISION=Linux-r2p4-02rel0 BUILD_DATE=Thu Oct 25 08:43:05 KST 2012
02-09 22:46:54.278: D/OpenGLRenderer(6686): Enabling debug mode 0
02-09 22:46:54.943: I/Choreographer(6686): Skipped 47 frames! The application may be doing too much work on its main thread.
02-09 22:46:56.318: W/SurfaceView(6686): CHECK surface infomation creating=false formatChanged=false sizeChanged=false visible=false visibleChanged=true surfaceChanged=true realSizeChanged=false redrawNeeded=false left=false top=false
02-09 22:46:56.403: I/Camera(6686): sendBroadcast intent.stop.app-in-app
02-09 22:46:59.818: W/SurfaceView(6686): CHECK surface infomation creating=false formatChanged=false sizeChanged=false visible=false visibleChanged=true surfaceChanged=true realSizeChanged=false redrawNeeded=true left=false top=false
02-09 22:47:00.063: I/Camera(6686): sendBroadcast intent.stop.app-in-app
02-09 22:47:04.833: I/MediaRecorderJNI(6686): prepare: surface=0x4d6db008 (identity=16)
答案 0 :(得分:1)
我有一种感觉问题是当你打电话给mCamera.lock();
尝试删除就在这里:
private void releaseMediaRecorder(){
if (mMediaRecorder != null) {
mMediaRecorder.reset(); // clear recorder configuration
mMediaRecorder.release(); // release the recorder object
mMediaRecorder = null;
mCamera.lock(); // ***REMOVE THIS LINE***
}
也在这里:
//Image capture button
mSnapButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick (View v) {
if (isRecording) {
// stop recording and release camera
mMediaRecorder.stop(); // stop the recording
releaseMediaRecorder(); // release the MediaRecorder object
mCamera.lock(); // ***REMOVE THIS LINE***
如果这有帮助,请告诉我。
答案 1 :(得分:0)
啊哈哈简单修复到底!我必须在启动MediaRecorder之前释放相机!现在工作顺利!是时候让它看起来很漂亮了:)
感谢您的帮助!