java - android - 如何动态调整 SurfaceView 的大小?

标签 java android android-camera

我正在构建一个简单的录音机应用程序。我想在开始录制时动态调整 SurfaceView 的大小。例如,当用户在设置 Activity 中提前将视频分辨率设置为4:3比例并单击“开始录制”按钮时,我希望SurfaceView将其宽度和高度更改为4:3比例。因此,当按下录制按钮时,SurfaceView 会更改其大小。

当应用程序没有录制任何内容时,我可以调整 SurfaceView 的大小,但是当我尝试在视频录制开始之前更改它时,它会调整 View 大小,但录制未正确完成(当我完成录制时,它会抛出 stopFailed 错误。)

我希望我的应用程序调整 SurfaceView 大小并立即开始录制。在用户按下录制按钮之前!

这是我的代码。

MainActivity.java

private boolean prepRecorder() {
        mRecorder = new MediaRecorder();
        CamcorderProfile profile = getCurrentProfile();

        Camera.Parameters parameters = mCamera.getParameters();
        parameters = setContinuesFocusMode(parameters);

        Camera.Size desiredSize = null, optimalPreviewSize = null;
        if (mVideoSizeIndex != -1) {
            List<Camera.Size> supportedVidSizes = parameters.getSupportedVideoSizes();
            if (mVideoSizeIndex < supportedVidSizes.size()) {
                desiredSize = supportedVidSizes.get(mVideoSizeIndex);
                optimalPreviewSize = mSurface.getOptimalPreviewSize(
                        parameters.getSupportedPreviewSizes(), desiredSize.width, desiredSize.height);

                Point screenSize = getScreenSize();
                mSurface.resizePreview(optimalPreviewSize.width, optimalPreviewSize.height, screenSize.x, screenSize.y);

                parameters.setPreviewSize(optimalPreviewSize.width, optimalPreviewSize.height);
            }
        } else {
            parameters.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
        }

        mCamera.setParameters(parameters);
        mCamera.unlock();

        mRecorder.setCamera(mCamera);
        mRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
        mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
        mRecorder.setProfile(profile);
        mRecorder.setPreviewDisplay(mSurface.getHolder().getSurface());

        mVideoPath = getMediaPath();
        if (mVideoPath != null) {
            mRecorder.setOutputFile(mVideoPath);
        } else {
            return false;
        }

        if (desiredSize != null) {
            mRecorder.setVideoSize(desiredSize.width, desiredSize.height);
        } else {
            mRecorder.setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
        }

        // Orientation adjustment stuff.....


        mTrackerThread = new VideoFileTrackerThread(new Handler(), this, mVideoPath);
        mTrackerThread.start();
        mTrackerThread.prepareHandler();
        mTrackerThread.triggerHandler();

        try {
            mRecorder.prepare();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

VideoSurfaceView.java

 public void resizePreview(int desiredWidth, int desiredHeight, int screenWidth, int screenHeight) {
    float videoProportion = (float) desiredWidth / (float) desiredHeight;
    float screenProportion = (float) screenWidth / screenHeight;

    ViewGroup.LayoutParams lp = this.getLayoutParams();
    if (videoProportion > screenProportion) {
        lp.width = screenWidth;
        lp.height = (int) ((float) screenWidth / videoProportion);
    } else {
        lp.width = (int) (videoProportion * (float) screenHeight);
        lp.height = screenHeight;
    }

    this.setLayoutParams(lp);
}


public Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
    final double ASPECT_TOLERANCE = 0.2;
    double targetRatio = (double) w / h;
    if (sizes == null)
        return null;

    Camera.Size optimalSize = null;
    double minDiff = Double.MAX_VALUE;

    int targetHeight = h;

    for (Camera.Size size : sizes) {
        if (size.width == w && size.height == h) {
            optimalSize = size;
            return optimalSize;
        }
        double ratio = (double) size.width / size.height;
        if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE)
            continue;
        if (Math.abs(size.height - targetHeight) < minDiff) {
            optimalSize = size;
            minDiff = Math.abs(size.height - targetHeight);
        }
    }

    if (optimalSize == null) {
        minDiff = Double.MAX_VALUE;
        for (Camera.Size size : sizes) {
            if (Math.abs(size.height - targetHeight) < minDiff) {
                optimalSize = size;
                minDiff = Math.abs(size.height - targetHeight);
            }
        }
    }
    return optimalSize;
}

当我在应用程序未录制时运行 resizePreview() 方法时,它会完美地更改 View ;但是当我在按下录制按钮时运行它时,它会卡住 UI 一段时间并且视频输出无法正确保存。会不会是主线程重载了?

提前致谢。

最佳答案

我解决了。这是因为当我调整 View 大小时调用了 onSurfaceChanged() 方法。我删除了 mCamera.stopPreview()、mCamera.setPreviewDisplay() 和 mCamera.startPreview() 现在工作正常。

关于java - android - 如何动态调整 SurfaceView 的大小?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38399029/

相关文章:

Android "TAKE PHOTO"- 单击的图像被保存为损坏的图像

Android 默认相机崩溃

javafx gridpane 布局与换行文本

java - Android WebView javascript 支持

java - 如何在android中同时渲染xml View 和java View

Android:扩展一个通过反射获取的隐藏类

android - 在 fragment 中,如何停止ZXing Scanner的摄像头?

java - JMenuItem.setSelected() 不会改变所选项目的外观?

不同屏幕尺寸下的android布局

java - TextView 不使用 Html.fromHtml 应用 HTML 样式