我正在尝试在视频录制之前进行预览,然后开始录制视频。
从 BACK相机录制时:预览正常并且录制开始时比率无变化 从前置摄像头录制时:预览正常但录制开始时比率已更改(根据经验我可以说录制高度较小)
前置摄像头保存的视频格式也不正确。
我检索支持的录制尺寸以进行预览和录制。所选的配置文件具有相同的分辨率: 720x480 。
我使用自定义 SurfaceView (SimpleCameraPreview)作为视图添加到FrameLayout:
<FrameLayout
android:id="@+id/camera_preview"
android:layout_width="240dp"
android:layout_height="160dp"
android:layout_weight="1" />
720/3 = 240,480 / 3 = 160 目标版本Android 4.0 +
完整代码:
activity_recording_simple.xml
<FrameLayout android:id="@+id/camera_preview" android:layout_width="240dp" android:layout_height="160dp" android:background="#CC000000" android:layout_weight="1" /> <LinearLayout android:id="@+id/linearLayout" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignBottom="@+id/camera_preview" android:layout_alignParentTop="true" android:layout_toRightOf="@id/camera_preview" android:gravity="center" android:layout_marginLeft="@dimen/activity_horizontal_margin" android:layout_marginRight="@dimen/activity_horizontal_margin" android:orientation="vertical"> <Button android:id="@+id/start_recording_button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:text="Start" /> <Button android:id="@+id/stop_recording_button" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:text="Stop" android:visibility="gone" /> </LinearLayout> </RelativeLayout>
SimpleRecordingActivity.java
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;
import cz.dynabit.voxpopuli.R;
import cz.dynabit.voxpopuli.SimpleCameraPreview;
public class SimpleRecordingActivity extends BaseAddRecipientActivity {
private SimpleCameraPreview mPreview;
private int currentCameraId;
private boolean isRecording;
@Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_recording_simple);
this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
super.onCreate(savedInstanceState);
final Button startButton = (Button) findViewById(R.id.start_recording_button);
final Button stopButton = (Button) findViewById(R.id.stop_recording_button);
startButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isRecording) {
return;
}
startButton.setVisibility(View.GONE);
stopButton.setVisibility(View.VISIBLE);
isRecording = true;
mPreview.prepareVideoRecorder();
}
});
stopButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isRecording) {
mPreview.stopRecording();
isRecording = false;
Intent i = new Intent(SimpleRecordingActivity.this, ReplayActivity.class);
startActivityForResult(i, 1);
}
}
});
}
@Override
protected void onResume() {
super.onResume();
mPreview = new SimpleCameraPreview(this);
mPreview.setCamera(getDefaultCamera());
mPreview.setVisibility(View.VISIBLE);
final FrameLayout preview = (FrameLayout) findViewById(R.id.camera_preview);
preview.removeAllViews();
preview.addView(mPreview);
}
@Override
protected void onPause() {
super.onPause();
if (mPreview != null) {
mPreview.stop();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater mi = getMenuInflater();
mi.inflate(R.menu.recording, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.camera_switch:
mPreview.releaseMediaRecorder();
mPreview.releaseCamera();
Camera nextCamera = openNextCamera(currentCameraId + 1);
if (nextCamera != null) {
mPreview.setCamera(nextCamera);
}
return true;
}
return super.onOptionsItemSelected(item);
}
private int getCameraCount() {
return Camera.getNumberOfCameras();
}
private Camera openNextCamera(int cameraId) {
int cameraCount = getCameraCount();
if (cameraId >= cameraCount) {
cameraId = 0;
}
if (cameraCount > 0) {
try {
Camera cam = Camera.open(cameraId);
currentCameraId = cameraId;
return cam;
} catch (RuntimeException e) {
Log.e("app", "Camera failed to open: " + e.getLocalizedMessage());
}
}
return null;
}
private Camera getDefaultCamera() {
return openFrontFacingCameraGingerbread();
}
private Camera openFrontFacingCameraGingerbread() {
int cameraCount = getCameraCount();
Camera cam = null;
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
Camera.getCameraInfo(camIdx, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
try {
cam = Camera.open(camIdx);
currentCameraId = camIdx;
break;
} catch (RuntimeException e) {
Log.e("app", "Camera failed to open: " + e.getLocalizedMessage());
}
}
}
if (cam == null && cameraCount > 0) {
try {
cam = Camera.open(0);
currentCameraId = 0;
} catch (RuntimeException e) {
Log.e("app", "Camera failed to open: " + e.getLocalizedMessage());
}
}
return cam;
}
}
SimpleCameraPreview.java
import android.app.Activity;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
public class SimpleCameraPreview extends SurfaceView implements SurfaceHolder.Callback {
private static String TAG = "app";
private SurfaceHolder mHolder;
private Camera mCamera;
private MediaRecorder mMediaRecorder;
private String lastFilePath = null;
private CamcorderProfile camProfile;
private Camera.Size optimalPreviewSize;
private Camera.Size optimalVideoSize;
public SimpleCameraPreview(Activity context) {
super(context);
mHolder = getHolder();
mHolder.addCallback(this);
camProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
}
public void setCamera(Camera camera) {
mCamera = camera;
refreshSurface();
}
public boolean prepareVideoRecorder() {
mMediaRecorder = new MediaRecorder();
// Step 1: Unlock and set camera to MediaRecorder
if (mCamera == null) {
return false;
}
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(camProfile);
lastFilePath = String.format("/storage/emulated/0/Podcasts/app/VID_%s.mp4", new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()));
mMediaRecorder.setOutputFile(lastFilePath);
mMediaRecorder.setPreviewDisplay(mHolder.getSurface());
mMediaRecorder.setVideoSize(optimalVideoSize.width, optimalVideoSize.height);
mMediaRecorder.setVideoSize(720, 480);
try {
mMediaRecorder.prepare();
mMediaRecorder.start();
} catch (IllegalStateException e) {
releaseMediaRecorder();
return false;
} catch (Exception e) {
releaseMediaRecorder();
return false;
}
return true;
}
public void refreshSurface() {
surfaceCreated(getHolder());
}
public void surfaceCreated(SurfaceHolder holder) {
try {
if (mCamera == null) {
return;
}
Camera.Parameters parameters = mCamera.getParameters();
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
//Desired ratio is 640/480
int desiredWidth = 640, desiredHeight = 480;
List<Camera.Size> previewSizes = parameters.getSupportedPreviewSizes();
List<Camera.Size> recordingSizes = parameters.getSupportedVideoSizes();
//Selected profiles are both 720x480!
//calculates optimal preview and recording sizes
optimalPreviewSize = getOptimalPreviewSize(previewSizes, desiredWidth, desiredHeight);
optimalVideoSize = getOptimalPreviewSize(recordingSizes, desiredWidth, desiredHeight);
parameters.setPreviewSize(optimalPreviewSize.width, optimalPreviewSize.height);
mCamera.setParameters(parameters);
mCamera.setPreviewDisplay(holder);
mCamera.startPreview();
} catch (IOException e) {
Log.d(TAG, "Error setting camera preview: " + e.getMessage());
}
}
//NOT IMPORTANT STUFF!
private 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) {
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);
}
}
return optimalSize;
}
public void releaseMediaRecorder() {
try {
if (mMediaRecorder != null) {
mMediaRecorder.stop();
mMediaRecorder.reset(); // clear recorder configuration
mMediaRecorder.release(); // release the recorder object
mMediaRecorder = null;
mCamera.lock(); // lock camera for later use
}
} catch (Exception ex) {
Log.e(TAG, "Error during releaseMediaRecorder");
}
}
public void releaseCamera() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release(); // release the camera for other applications
mCamera = null;
}
}
public void surfaceDestroyed(SurfaceHolder holder) {
// empty. Take care of releasing the Camera preview in your activity.
}
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// If your preview can change or rotate, take care of those events here.
// Make sure to stop the preview before resizing or reformatting it.
if (mHolder.getSurface() == null) {
// preview surface does not exist
return;
}
// stop preview before making changes
try {
mCamera.stopPreview();
} catch (Exception e) {
// ignore: tried to stop a non-existent preview
}
// set preview size and make any resize, rotate or
// reformatting changes here
// start preview with new settings
try {
mCamera.setPreviewDisplay(mHolder);
mCamera.startPreview();
} catch (Exception e) {
Log.d("vox", "Error starting camera preview: " + e.getMessage());
}
}
public void stop() {
stopRecording();
releaseCamera(); // release the camera immediately on pause event
}
public void stopRecording() {
releaseMediaRecorder(); // if you are using MediaRecorder, release it first
}
}
更新:
显然这只是某些设备上的问题(例如三星galaxy s4)。有些手机运行正常。