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

时间:2016-07-15 14:45:45

标签: java android android-camera

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

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

我希望我的应用程序调整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一段时间,并且视频输出无法正确保存。主线程是否可能过载?

提前致谢。

1 个答案:

答案 0 :(得分:1)

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