【问题标题】:android - How can I resize SurfaceView dynamically?android - 如何动态调整 SurfaceView 的大小?
【发布时间】:2016-07-15 14:45:44
【问题描述】:

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

当应用程序没有录制任何内容时,我可以调整 SurfaceView 的大小,但是当我在视频录制开始之前尝试更改它时,它会调整视图的大小但录制未正确完成(当我完成录制时它会引发 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() 方法时,它会完美地改变视图;但是当我按下录制按钮时运行它时,它会冻结 UI 一段时间,并且视频输出没有正确保存。主线程是否可能过载?

提前致谢。

【问题讨论】:

标签: java android android-camera


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2013-11-02
    • 1970-01-01
    • 2011-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多