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.