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

Jas*_*son 4 android surfaceview android-camera 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();
}
Run Code Online (Sandbox Code Playgroud)

Mat*_*vis 7

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

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

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

(对于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);
Run Code Online (Sandbox Code Playgroud)

然后在媒体记录器上设置大小:

//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);
Run Code Online (Sandbox Code Playgroud)