开始视频录制时,屏幕会闪烁并调整大小

时间:2012-05-09 02:44:33

标签: android android-camera surfaceview android-mediarecorder

我正在将照片/视频捕捉整合到我的应用中,并且遇到视频捕捉问题。每当视频录制开始时,屏幕会闪烁,我会暂停一下,然后开始录制视频。但是,使用手机的相机应用程序,根本没有闪烁/暂停。

此外,只要调用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();
}

1 个答案:

答案 0 :(得分:7)

调用MediaRecorder.start()时轻微缩放的原因是相机调整其预览大小以匹配正在录制的视频的分辨率。可以通过在设置上设置预览和视频重新设置来解决此问题。我想我也找到了一种方法来阻止闪烁,虽然我发现在使用Camera和MediaRecorder时,一点点滞后或闪烁可能来自任何一个地方,所以这可能是一个有点难以追查。 The Android documentation for setting up a camera/video recorder是一个开始确保正确设置主要部分的好地方,但我发现有必要深入研究一些类api文档来进行调试并使体验变得非常流畅。

Camera.Parameters课程是保持流畅视频录制体验的关键。拥有Camera对象后,可以使用Camera.getParameters()获取当前参数来修改它们。然后可以使用Camera.setParameters(Camera.Parameters)来触发已经进行的任何更改。

为防止视频大小调整,我们需要确保参数的预览大小与要录制的视频分辨率一致。要获取支持的视频/预览大小列表,我们可以在当前的Parameters对象上使用Camera.Parameters.getSupportedPreviewSizes(),该对象将返回Camera.Size个对象的列表。这些对象中的每一个都具有width和height属性,可通过Camera.Size.widthCamera.Size.height直接访问(无getter方法)。 getSupportedPreviewSizes()方法为guaranteed to return at least one result,,似乎结果从最高分辨率排序到最低分辨率。

(对于API级别> 11,还有一个getSupportedVideoSizes()方法,但似乎只有当设备的某些视频尺寸与预览尺寸不同时才会显示,否则返回null。这个方法取得了成功,所以我现在坚持使用PreviewSizes,因为它可以保证返回适合视频和预览的尺寸,但是要注意这一点。)

一旦我们获得了与我们想要的视频分辨率相对应的Camera.Size,我们就可以使用Camera.Parameters.setPreviewSize(width, height).设置该尺寸。此外,为了帮助消除闪烁,我使用Camera.Parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO).这些步骤之一拍摄后,使用Camera.setParameters()通知相机您的更改。在获取相机后,我已成功设置这些参数,因为在用户与此活动交互时设置参数会导致一些延迟。如果你使用相同的视频和图片捕获活动,你也可以在这里设置图片参数,Camera对象将使用适当的参数为每种模式处理。

差不多完成了!现在预览已经完成,剩下的就是确保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);