0

I'm building a simple recorder app. I want to resize SurfaceView dynamically when it starts recording. For example, when the user sets the video resolution into 4:3 ratio in advance in the settings activity and clicks the 'start recording' button, I want SurfaceView to change it's width and height into 4:3 ratio. So the SurfaceView changes it's size when the recording button is pressed.

I can resize SurfaceView when the app is not recording anything but when I try to change it right before the video recording starts, it resizes the view but recording is not done properly (It throws stopFailed error when I finish recording.)

I want my app to resize SurfaceView and start recording right after. Not before the user presses the recording button!

Here's my code.

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;
}

When I run resizePreview() method when the app is not recording, it changes the view perfectly; but when I run it when the recording button is pressed, it freezes the UI for a while and the video output is not saved properly. Is it possible that the main thread is overloaded?

Thanks in advance.

Wasabi.Mayo
  • 169
  • 1
  • 13
  • This should help! http://stackoverflow.com/questions/20491499/resizing-surface-view-for-aspect-ratio-change-in-video-display-in-android – Aleksandar Cvetić Jul 15 '16 at 14:53
  • @acac97 I've already seen and implemented that question.. it works fine when the app doesn't record anything but I want to resize the SurfaceView when the user presses the StartRecording button. – Wasabi.Mayo Jul 15 '16 at 15:09
  • Also ensure that you've gone trough these steps https://developer.android.com/reference/android/hardware/Camera.html – Aleksandar Cvetić Jul 15 '16 at 15:16

1 Answers1

2

I solved it. It was because of the onSurfaceChanged() method is called when I resize the view. I removed mCamera.stopPreview(), mCamera.setPreviewDisplay(), and mCamera.startPreview() and it works fine now.

Wasabi.Mayo
  • 169
  • 1
  • 13