问题
I am trying to develop a custom camera video recorder. When my devices execute the start MediaRecorder method in beginRecording() in the Activity, the app crashes. I don't know what is wrong, because I follow the Google API Guide. My devices use Android 2.3 or higher version. In my Nexus S 4.1.1 executes ok, but in my Xperia 2.3.3 doesn't go, displaying this trace.
My code is:
private static final String TAG = "RecordVideo";
private MediaRecorder mRecorder = null;
private Camera mCamera = null;
private String OUTPUT_FILE;
private VideoView mVideoView = null;
private Button mStartBtn = null;
private SurfaceHolder mHolder;
private boolean isRecording = false;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
if (checkCameraHardware(this)) {
mStartBtn = (Button) findViewById(R.id.beginBtn);
mVideoView = (VideoView)this.findViewById(R.id.videoView);
// Create our Preview view and set it as the content of our activity.
mHolder = mVideoView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
}
/** Check if this device has a camera */
private 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;
}
}
public void doClick(View view) {
switch(view.getId()) {
case R.id.beginBtn:
beginRecording();
break;
case R.id.stopBtn:
stopRecording();
break;
case R.id.playRecordingBtn:
playRecording();
break;
case R.id.stopPlayingRecordingBtn:
stopPlayingRecording();
break;
}
}
// Once we have a surface, we can start the previewing
// Once we're previewing with Camera, we can setup the
// MediaRecorder
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.v(TAG, "surface created");
mStartBtn.setEnabled(true);
try {
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
prepareForRecording(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.v(TAG, "Surface changed: width x Height = " + width + "x" + height);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.v(TAG, "surface destroyed");
}
private void beginRecording() {
mRecorder.setOnInfoListener(this);
mRecorder.setOnErrorListener(this);
mRecorder.start();
isRecording = true;
}
private void stopRecording() {
Log.v(TAG, "stop recording");
if (mRecorder != null) {
mRecorder.setOnInfoListener(null);
mRecorder.setOnErrorListener(null);
mRecorder.stop();
mRecorder.reset(); // clear recorder configuration
mRecorder.release(); // release the recorder object
mRecorder = null;
mCamera.lock();
}
mCamera.release();
mCamera = null;
isRecording = false;
}
private void playRecording() {
MediaController mc = new MediaController(this);
mVideoView.setMediaController(mc);
mVideoView.setVideoPath(OUTPUT_FILE);
mVideoView.start();
}
private void stopPlayingRecording() {
mVideoView.stopPlayback();
}
@Override
protected void onResume() {
Log.v(TAG, "resuming");
mCamera = Camera.open();
Parameters camParams = mCamera.getParameters();
//camera.setDisplayOrientation(90);
// We could set other parameters in camParams then:
// camera.setParameters(camParams);
super.onResume();
}
@Override
protected void onPause() {
Log.v(TAG, "pausing");
if (mRecorder != null) {
mRecorder.release();
mRecorder = null;
}
if(mCamera != null) {
try {
mCamera.reconnect(); // this also does a lock()
mCamera.release();
mCamera = null;
} catch (IOException e) {
e.printStackTrace();
}
}
super.onPause();
}
@Override
protected void onDestroy() {
Log.v(TAG, "destroying");
super.onDestroy();
}
private void prepareForRecording(SurfaceHolder holder) {
if(mRecorder != null) {
mRecorder.reset();
}
try {
mRecorder = new MediaRecorder();
// Step 1: Unlock and set camera to MediaRecorder
mCamera.unlock();
mRecorder.setCamera(mCamera); // Must be done while MediaRecorder is idle
// mCamera.lock();
// Step 2: Set sources
mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// Step 3: Set a CamcorderProfile (requires API Level 8 or higher)
mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
String fileExtension = ".mp4";
// Step 4: Set output file
OUTPUT_FILE = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/videooutput" + fileExtension;
File outFile = new File(OUTPUT_FILE);
if(outFile.exists()) {
outFile.delete();
}
mRecorder.setOutputFile(OUTPUT_FILE);
// Step 5: Set the preview output
mRecorder.setPreviewDisplay(holder.getSurface());
// mRecorder.setMaxDuration(30000); // limit to 30 seconds
// Must implement onInfoListener
// Step 6: Prepare configured MediaRecorder
mRecorder.prepare();
} catch (IllegalStateException e) {
Log.d(TAG, "IllegalStateException preparing MediaRecorder: " + e.getMessage());
e.printStackTrace();
} catch(Exception e) {
Log.e(TAG, e.toString());
e.printStackTrace();
}
}
@Override
public void onInfo(MediaRecorder mediaRecorder, int what, int extra) {
if(what == MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED) {
Log.i(TAG, "got a recording event");
mCamera.stopPreview();
Toast.makeText(this, "Recording limit has been reached. Stopping the recording", Toast.LENGTH_SHORT).show();
isRecording = false;
}
}
@Override
public void onError(MediaRecorder mr, int what, int extra) {
Log.e(TAG, "got a recording error");
mCamera.stopPreview();
Toast.makeText(this, "Recording error has occurred. Stopping the recording", Toast.LENGTH_SHORT).show();
isRecording = false;
}
Trace error is:
V/RecordVideo(7427): resuming
V/RecordVideo(7427): surface created
I/MediaRecorderJNI(7427): prepare: surface=0x2b8ac8 (identity=2136)
V/RecordVideo(7427): Surface changed: width x Height = 600x375
E/MediaRecorder(7427): start failed: -2147483648
D/AndroidRuntime(7427): Shutting down VM
W/dalvikvm(7427): threadid=1: thread exiting with uncaught exception (group=0x2aac8578)
E/AndroidRuntime(7427): FATAL EXCEPTION: main
E/AndroidRuntime(7427): java.lang.IllegalStateException: Could not execute method of the activity
E/AndroidRuntime(7427): at android.view.View$1.onClick(View.java:2168)
E/AndroidRuntime(7427): at android.view.View.performClick(View.java:2552)
E/AndroidRuntime(7427): at android.view.View$PerformClick.run(View.java:9229)
E/AndroidRuntime(7427): at android.os.Handler.handleCallback(Handler.java:587)
E/AndroidRuntime(7427): at android.os.Handler.dispatchMessage(Handler.java:92)
E/AndroidRuntime(7427): at android.os.Looper.loop(Looper.java:130)
E/AndroidRuntime(7427): at android.app.ActivityThread.main(ActivityThread.java:3701)
E/AndroidRuntime(7427): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(7427): at java.lang.reflect.Method.invoke(Method.java:507)
E/AndroidRuntime(7427): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
E/AndroidRuntime(7427): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:624)
E/AndroidRuntime(7427): at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(7427): Caused by: java.lang.reflect.InvocationTargetException
E/AndroidRuntime(7427): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(7427): at java.lang.reflect.Method.invoke(Method.java:507)
E/AndroidRuntime(7427): at android.view.View$1.onClick(View.java:2163)
E/AndroidRuntime(7427): ... 11 more
E/AndroidRuntime(7427): Caused by: java.lang.RuntimeException: start failed.
E/AndroidRuntime(7427): at android.media.MediaRecorder.start(Native Method)
E/AndroidRuntime(7427): at com.androidbook.record.video.MainActivity.beginRecording(MainActivity.java:124)
E/AndroidRuntime(7427): at com.androidbook.record.video.MainActivity.doClick(MainActivity.java:80)
E/AndroidRuntime(7427): ... 14 more
UPDATE:
I've fixed this error. The main code is:
private boolean initCamera() {
try {
mCamera = Camera.open();
Camera.Parameters camParams = mCamera.getParameters();
List<Size> a = camParams.getSupportedPreviewSizes();
for (int i = 0; i < a.size(); i++) {
if (width_video < a.get(i).width) {
width_video = a.get(i).width;
height_video = a.get(i).height;
}
}
mCamera.lock();
//mCamera.setDisplayOrientation(90);
// Could also set other parameters here and apply using:
//mCamera.setParameters(camParams);
mHolder = mVideoView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
catch(RuntimeException re) {
Log.v(TAG, "Could not initialize the Camera");
re.printStackTrace();
return false;
}
return true;
}
private void initRecorder() {
if(mRecorder != null) return;
mOutputFileName = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) +
"/videooutput" + ".mp4";
File outFile = new File(mOutputFileName);
if(outFile.exists()) {
outFile.delete();
}
try {
mCamera.stopPreview();
mCamera.unlock();
mRecorder = new MediaRecorder();
mRecorder.setCamera(mCamera);
mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
if (Build.VERSION_CODES.GINGERBREAD >= Build.VERSION.SDK_INT) {
mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
} else {
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setVideoSize(width_video, height_video);
mRecorder.setVideoFrameRate(30);
}
mRecorder.setMaxDuration(21000); // limit to 30 seconds
mRecorder.setPreviewDisplay(mHolder.getSurface());
mRecorder.setOutputFile(mOutputFileName);
mRecorder.prepare();
Log.v(TAG, "MediaRecorder initialized");
}
catch(Exception e) {
Log.v(TAG, "MediaRecorder failed to initialize");
e.printStackTrace();
}
}
private void beginRecording() {
mRecorder.setOnInfoListener(this);
mRecorder.setOnErrorListener(this);
mRecorder.start();
mRecordingMsg.setText("RECORDING");
mStartBtn.setEnabled(false);
mStopBtn.setEnabled(true);
}
But now, I've other problem. When I installed the app in devices with 2.2 and 2.3.3 version because in this versions can't support the line: mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); and if I change the code: CamcorderProfile.QUALITY_LOW, the devices record in the lowest level of quality.
And I have to change the code in 2.2 and 2.3 versions doing this:
if (Build.VERSION_CODES.GINGERBREAD >= Build.VERSION.SDK_INT) {
mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
} else {
Recorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setVideoSize(width_video, height_video);
mRecorder.setVideoFrameRate(30);
}
Why I have to do this, when in the Android API the setProfile() method is available in 2.2 and devices should record in their higher quality the can be supported?
UPDATE2:
In initCamera method, I've changed:
Camera.Parameters camParams = mCamera.getParameters();
camParams.set( "cam_mode", 1 );
mCamera.setParameters( camParams );
in the 2.3 version devices I can use the line to detect the resolution video configuration: mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); but in some devices like HTC Desire, don't support this configuration.
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mRecorder.setVideoSize(width_video, height_video);
mRecorder.setVideoFrameRate(30);
For 2.2 version, can accept the AAC Audio Encoder?, because my HTC Legent don't support this Audio Encoder?? UPDATE3: Android 2.2 version can't support ACC Audio Encoder.
来源:https://stackoverflow.com/questions/12154694/how-to-build-a-custom-camera-recorder-app