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 レジェントはこのオーディオ エンコーダーをサポートしていないため?? UPDATE3: Android 2.2 バージョンは ACC オーディオ エンコーダーをサポートできません。

4

0 に答える 0