Android 开始录像时,屏幕闪烁并调整大小

Android 开始录像时,屏幕闪烁并调整大小,android,android-camera,surfaceview,android-mediarecorder,Android,Android Camera,Surfaceview,Android Mediarecorder,我正在将照片/视频捕获集成到我的应用程序中,视频捕获有问题。每当视频录制开始时,屏幕就会闪烁,我会暂停片刻,然后开始视频捕获。然而,使用手机的照相/摄像应用程序,根本没有闪烁/暂停 此外,只要调用recorder.start(),我的相机预览显示就会调整大小。我不明白这是为什么。它会使预览失真(所有内容看起来都被压扁且更宽) 我的问题:开始录像时如何防止闪烁/暂停?如何防止recorder.start()调整预览显示的大小 只要启用“视频模式”,就会立即调用initRecording()。一旦用

我正在将照片/视频捕获集成到我的应用程序中,视频捕获有问题。每当视频录制开始时,屏幕就会闪烁,我会暂停片刻,然后开始视频捕获。然而,使用手机的照相/摄像应用程序,根本没有闪烁/暂停

此外,只要调用
recorder.start()
,我的相机预览显示就会调整大小。我不明白这是为什么。它会使预览失真(所有内容看起来都被压扁且更宽)

我的问题:开始录像时如何防止闪烁/暂停?如何防止
recorder.start()
调整预览显示的大小

只要启用“视频模式”,就会立即调用
initRecording()
。一旦用户按下按钮,就会调用
startRecording()
。最后,再次按下按钮时,将调用
stopRecording()
。更重要的是,当切换回“图片模式”时,将调用
destroy recorder()

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

调用MediaRecorder.start()时出现轻微缩放的原因是相机调整了预览大小以匹配正在录制的视频的分辨率。通过在设置中设置预览和视频资源,可以解决此问题。我想我也找到了一种阻止闪烁的方法,尽管我发现当使用照相机和MediaRecorder时,一点点的延迟或闪烁可能来自许多地方,因此可能更难追踪。这是一个很好的起点,可以确保主要部分设置正确,但我发现有必要深入研究一些类api文档,以进行调试,并使体验真正顺畅

Camera.Parameters
课程是保持流畅录像体验的关键。拥有摄影机对象后,可以使用
Camera.getParameters()
获取当前参数以对其进行修改<代码>Camera.setParameters(Camera.Parameters)然后可用于触发所做的任何更改

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

(对于API级别>11,还有一个
getSupportedVideoSizes()
方法,但似乎只有当设备的某些视频大小与预览大小不同时,才会使用此方法,否则返回空值。我还没有成功使用此方法,因此我现在仍坚持使用PreviewSizes,因为它可以保证返回对视频和预览都有利的大小,但这是需要注意的。)

一旦我们有了与我们想要的视频分辨率相对应的
Camera.Size
,我们就可以使用
Camera.Parameters.setPreviewSize(宽度、高度)。
另外,为了帮助消除闪烁,我使用
Camera.Parameters.setFocusMode(Camera.Parameters.FOCUS\u MODE\u continuvideo)。
,使用
Camera.setParameters()
将更改通知摄像机。我在拿到相机后成功地设置了一次这些参数,因为在用户与此活动交互时设置参数会导致一些延迟。如果您使用相同的活动进行视频和图片捕获,也可以在此处设置图片参数,相机对象将使用每个模式的适当参数进行处理

差不多完成了!现在预览已经完成,剩下的就是确保
MediaRecorder
使用与预览相同的分辨率。准备媒体录制器时,在调用
MediaRecorder.setProfile()
(或设置编码器,用于API级别<8)和
MediaRecorder.setOutputFile()
之间,使用与预览相同的值调用
MediaRecorder.setVideoSize(宽度、高度)
。现在,使用
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);

你有没有弄清楚是什么导致了闪烁和调整大小?“我现在正在为一个我正在从事的项目处理同样的问题。@MattDavis抱歉,不幸的是没有。很好的帖子,谢谢你解释整个过程。我遵循这些步骤,但我仍然得到预览和闪烁的大小。我正在将摄像头预览大小和MediaRecorder的视频大小设置为相同的值(640x480)。mediaRecorder.setVideoSize(myVideoSize.width,myVideoSize.height);视频未在android中录制。
//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);