2

我正在尝试开发自定义摄像机录像机。当我的设备在 Activity 的 beginRecording() 中执行 start MediaRecorder 方法时,应用程序崩溃。我不知道出了什么问题,因为我遵循Google API Guide。我的设备使用 Android 2.3 或更高版本。在我的 Nexus S 4.1.1 中执行正常,但在我的 Xperia 2.3.3 中没有运行,显示此跟踪。

我的代码是:

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;
}

跟踪错误是:

 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

更新:

我已经修复了这个错误。主要代码是:

 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);
}

但现在,我还有其他问题。当我在 2.2 和 2.3.3 版本的设备中安装应用程序时,因为在此版本中不支持以下行: mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); 如果我更改代码:CamcorderProfile.QUALITY_LOW,则设备以最低质量记录。

我必须更改 2.2 和 2.3 版本中的代码:

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);
}

为什么我必须这样做,当在 Android API 中,setProfile() 方法在 2.2 中可用并且设备应该以更高的质量记录可以支持?

更新2:

在 initCamera 方法中,我改变了:

 Camera.Parameters camParams = mCamera.getParameters();
 camParams.set( "cam_mode", 1 );     
 mCamera.setParameters( camParams );

在 2.3 版本的设备中,我可以使用该行来检测视频配置的分辨率: mRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)); 但在某些设备(如 HTC Desire)中,不支持此配置。

 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);

对于 2.2 版本,可以接受 AAC 音频编码器吗?因为我的 HTC Legent 不支持这个音频编码器?UPDATE3:Android 2.2 版本不支持 ACC 音频编码器。

4

0 回答 0