4

アプリに写真/ビデオ キャプチャを統合していますが、ビデオ キャプチャに問題があります。ビデオの録画が開始されるたびに、画面がちらつき、少し間があいてから、ビデオのキャプチャが開始されます。ただし、電話のカメラアプリを使用すると、ちらつき/一時停止はまったくありません.

また、カメラのプレビュー表示recorder.start()は、呼び出されるとすぐにサイズ変更されます。それがなぜなのかわかりません。プレビューが歪んでしまいます (すべてが押しつぶされて広く見えます)。

私の質問: ビデオ録画を開始するときのちらつき/一時停止を防ぐにはどうすればよいですか? recorder.start()プレビュー表示のサイズを変更できないようにするにはどうすればよいですか?

「ビデオ モード」が有効になるたびに、initRecording()すぐに呼び出されます。ユーザーがボタンを押すと、startRecording()が呼び出されます。最後に、もう一度ボタンを押すと、stopRecording()が呼び出されます。それほど重要ではありませんが、「画像モード」に戻るときにdestroyRecorder()呼び出されます。

@Override
public void onResume() {

    super.onResume();

    Camera camera = null;
    try {
        camera = Camera.open();
    }
    catch (Exception e) {
        // Camera isn't available
        Toast.makeText( getActivity(), "Camera is not available at this time.", Toast.LENGTH_SHORT ).show();
        getActivity().finish();
        return;
    }

    if ( Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD ) {
        setCameraDisplayOrientation( camera );
    }
    else {
        camera.setDisplayOrientation( 90 );
    }

    setCamera( camera );
    setCameraZoomDisplay( camera );

    if ( getSurfaceHolder() != null ) {
        startPreview();

        if ( getMode() == MODE_VIDEO ) {
            initRecording();
        }
    }
}

private void setCameraDisplayOrientation( Camera camera ) {

    CameraInfo info = new CameraInfo();
    Camera.getCameraInfo( 0, info );

    int rotation = getActivity().getWindowManager().getDefaultDisplay().getRotation();
    int degrees = 0;
    switch (rotation) {
        case Surface.ROTATION_0:
            degrees = 0;
            break;
        case Surface.ROTATION_90:
            degrees = 90;
            break;
        case Surface.ROTATION_180:
            degrees = 180;
            break;
        case Surface.ROTATION_270:
            degrees = 270;
            break;
    }

    int result = ( info.orientation - degrees + 360 ) % 360;
    camera.setDisplayOrientation( result );
}

private void initRecording() {

    MediaRecorder recorder = new MediaRecorder();
    setRecorder( recorder );

    Camera camera = getCamera();
    camera.unlock();
    recorder.setCamera( camera );

    recorder.setAudioSource( MediaRecorder.AudioSource.MIC );
    recorder.setVideoSource( MediaRecorder.VideoSource.CAMERA );

    CamcorderProfile cp = CamcorderProfile.get( CamcorderProfile.QUALITY_HIGH );
    recorder.setProfile( cp );

    String extension;
    switch (cp.fileFormat) {
        case MediaRecorder.OutputFormat.MPEG_4:
            extension = "mp4";
            break;
        case MediaRecorder.OutputFormat.THREE_GPP:
            extension = "3gp";
            break;
        default:
            extension = "tmp";
    }

    setVideoMimeType( MimeTypeMap.getSingleton().getMimeTypeFromExtension( extension ) );

    File toFile = new File( getActivity().getCacheDir(), "tempvideo.tmp" );
    if ( toFile.exists() ) {
        toFile.delete();
    }
    setTempFile( toFile );

    recorder.setOutputFile( toFile.getPath() );
    recorder.setPreviewDisplay( getSurfaceHolder().getSurface() );

    try {
        recorder.prepare();
        setRecorderInitialized( true );
    }
    catch (IllegalStateException e) {
        e.printStackTrace();
    }
    catch (IOException e) {
        e.printStackTrace();
    }
}

private boolean startRecording() {

    try {
        getRecorder().start();
        setRecording( true );

        ImageView actionImageView = getActionImageView();
        actionImageView.setImageResource( R.drawable.record_red );
    }
    catch (Exception e) {
        getCamera().lock();
    }

    return true;
}

private void stopRecording() {

    MediaRecorder recorder = getRecorder();
    if ( recorder != null && isRecording() ) {
        recorder.stop();
        setRecording( false );
        setRecorderInitialized( false );

        try {
            insertVideo();
        }
        catch (IOException e) {
            e.printStackTrace();
        }

        initRecording();

        ImageView actionImageView = getActionImageView();
        actionImageView.setImageResource( R.drawable.record_green );
    }
}

private void destroyRecorder() {

    MediaRecorder recorder = getRecorder();
    recorder.release();
    setRecorder( null );
    getCamera().lock();
}
4

1 に答える 1

7

MediaRecorder.start() が呼び出されたときにわずかにズームする理由は、録画中のビデオの解像度に一致するようにカメラがプレビューのサイズを変更するためです。この問題は、セットアップ時にプレビューとビデオの解像度を設定することで解決できます。ちらつきを止める方法も見つけたと思いますが、Camera と MediaRecorder を使用しているときに、少しのラグやちらつきが多くの場所のいずれかから発生する可能性があることがわかりました。追跡するのは少し難しいです。 カメラ/ビデオ レコーダーのセットアップに関する Android ドキュメントは、主要な部分が正しくセットアップされていることを確認するための出発点として適していますが、デバッグしてエクスペリエンスを作成するには、クラス API ドキュメントの一部を詳しく調べる必要があることがわかりました。本当にスムーズ。

Camera.Parametersクラスは、スムーズなビデオ録画体験を維持するための鍵です。Camera オブジェクトを取得したら、使用Camera.getParameters()して現在のパラメーターを取得し、それらを変更できます。 Camera.setParameters(Camera.Parameters)その後、行われた変更をトリガーするために使用できます。

ビデオのサイズ変更を防ぐには、パラメーターのプレビュー サイズが記録されるビデオの解像度と一致していることを確認する必要があります。サポートされているビデオ/プレビュー サイズのリストを取得するには、オブジェクトCamera.Parameters.getSupportedPreviewSizes()のリストを返す現在の Parameters オブジェクトで使用できCamera.Sizeます。これらの各オブジェクトには幅と高さのプロパティがあり、and を介して直接アクセスできますCamera.Size.width(Camera.Size.heightゲッター メソッドはありません)。getSupportedPreviewSizes()メソッドは少なくとも 1 つの結果を返すことが保証されており、結果は解像度の高いものから低いものの順に並べられているように見えます。

(APIレベル> 11の場合もgetSupportedVideoSizes()メソッドがありますが、これはデバイスにプレビューサイズとは異なるビデオサイズがある場合のみのようで、そうでない場合はnullを返します。私はこのメソッドで成功していないので、私はビデオとプレビューの両方に適切なサイズを返すことが保証されるため、今のところ PreviewSizes の使用に固執しますが、今後は注意が必要です。)

Camera.Size必要なビデオ解像度に対応する を取得したら、次を使用してそのサイズを設定できます。Camera.Parameters.setPreviewSize(width, height). さらに、ちらつきを抑えるために、Camera.Parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO). 次の手順を実行Camera.setParameters()し、変更をカメラに通知するために使用します。ユーザーがこのアクティビティとやり取りしている間にパラメーターを設定すると、多少の遅延が発生したため、カメラを取得した直後にこれらのパラメーターを一度設定することに成功しました。ビデオと画像のキャプチャに同じアクティビティを使用している場合は、ここで画像パラメーターを設定することもできます。カメラ オブジェクトは、各モードの適切なパラメーターを使用して処理します。

ほぼ完了しました!プレビューが処理されたので、あとは がMediaRecorderプレビューと同じ解像度を使用するようにするだけです。メディア レコーダーを準備するときは、 への呼び出しMediaRecorder.setProfile()(または API レベル < 8 の場合はエンコーダーの設定) との間で、プレビューと同じ値を使用してMediaRecorder.setOutputFile()への呼び出しを行います。MediaRecorder.setVideoSize(width, height)これで、両方が同じ解像度を使用しているため、プレビューから記録への移行MediaRecorder.start()がシームレスになるはずです。

すべての動作を確認できるように、いくつかの簡単なコード スニペットを次に示します。

パラメータの取得と設定:

Camera.Parameters params = camera.getParameters();

params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);

//myVideoSize is an instance of Camera.Size
List<Camera.Size> previewSizes = params.getSupportedPreviewSizes();
myVideoSize = previewSizes.get(0);
params.setPreviewSize(myVideoSize.width, myVideoSize.height);

camera.setParameters(params);

次に、メディア レコーダーでサイズを設定します。

//After setting the profile....
mediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));

//Use myVideoSize from above
mediaRecorder.setVideoSize(myVideoSize.width, myVideoSize.height);

//Before setting the output file
mediaRecorder.setOutputFile(myFile);
于 2013-04-15T15:58:10.850 に答える