转载请注明出处 传送门 本文出自【付小华的博客】
关于Android 自定义相机和自定义录像功能的封装有很多,我这里也封装了一个,与其它的不同,我这里是非常简便和轻量级的封装,只有一个类(继承自TextureView),大家使用时只需要复制这个类就可以了。
"android.permission.CAMERA" />
"android.permission.RECORD_AUDIO" />
"android.permission.READ_EXTERNAL_STORAGE" />
"android.permission.WRITE_EXTERNAL_STORAGE" />
<xxxxxxx.TextureCameraPreview
android:id="@+id/texture_camera_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
/**
* 拍照
*
* @param listener 拍照监听,不可空
*/
public void takePicture(OnPictureTakenListener listener)
// 声明变量
TextureCameraPreview mTextureCameraPreview;
// 拍照
mTextureCameraPreview.takePicture(new TextureCameraPreview.OnPictureTakenListener() {
@Override
public void onSuccess(byte[] data) {
//TODO 拍照成功时回调
}
@Override
public void onFailed(String msg) {
//TODO 拍照失败时回调
}
});
/**
* 开始录像
*
* @param outputPath 输出录像保存文件路径,如"test.mp4"
* @param listener 录像开始结束的监听,可空
*/
public void startRecord(String outputPath, OnStartVideoListener listener)
// 声明变量
TextureCameraPreview mTextureCameraPreview;
// 录像
// 判断是否正处于录像
if (!mTextureCameraPreview.isRecording()) {
mTextureCameraPreview.startRecord("test.mp4", new TextureCameraPreview.OnStartVideoListener() {
@Override
public void onStart() {
// TODO: 开始录像时的回调
}
@Override
public void onStop() {
// TODO: 录像结束时的回调
}
});
}
// 需要在onPause中结束录像
@Override
public void onPause() {
super.onPause();
if (mTextureCameraPreview.isRecording()) {
// 结束录像
mTextureCameraPreview.stopRecord();
}
}
/**
* 预览界面放大
*
* @param progress 放大倍数 0-100
*/
public void setZoom(int progress)
/**
* 切换前后置摄像头
*
* @param index 0为后置摄像头,1为前置摄像头
*/
public void switchCamera(int index)
import android.content.Context;
import android.graphics.SurfaceTexture;
import android.hardware.Camera;
import android.media.AudioManager;
import android.media.CamcorderProfile;
import android.media.MediaRecorder;
import android.media.ToneGenerator;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.TextureView;
import android.widget.Toast;
/**
* Created by shenhua on 3/29/2017.
* Email [email protected]
*/
public class TextureCameraPreview extends TextureView implements TextureView.SurfaceTextureListener, Camera.PictureCallback, Camera.ShutterCallback {
private Camera mCamera;
private int index = 0;
private OnPictureTakenListener onPictureTakenListener;
private MediaRecorder mMediaRecorder;
private boolean isRecording = false;
private OnStartVideoListener onStartVideoListener;
private SurfaceTexture mSurface;
public TextureCameraPreview(Context context) {
this(context, null);
}
public TextureCameraPreview(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TextureCameraPreview(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setSurfaceTextureListener(this);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mSurface = surface;
openCamera();
}
private void openCamera() {
// 1.打开相机
mCamera = getCameraInstance(getContext(), index);
if (mCamera != null) {
// 2.设置相机参数
Camera.Parameters parameters = mCamera.getParameters();
// 3.调整预览方向
mCamera.setDisplayOrientation(90);
// 4.设置预览尺寸
parameters.setPreviewSize(1920, 1080);
parameters.setPictureSize(1920, 1080);
// 5.调整拍照图片方向
if (index == 0)
parameters.setRotation(90);
if (index == 1)
parameters.setRotation(270);
mCamera.setParameters(parameters);
// 6.开始相机预览
try {
mCamera.setPreviewTexture(mSurface);
mCamera.startPreview();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getContext(), "Error setting camera preview:" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
releaseCamera();
return true;
}
private void releaseCamera() {
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
}
public static Camera getCameraInstance(Context context, int i) {
Camera c = null;
try {
c = Camera.open(i);
} catch (Exception e) {
Toast.makeText(context, "相机打开失败", Toast.LENGTH_SHORT).show();
}
return c;
}
public void takePicture(OnPictureTakenListener listener) {
if (listener != null) {
onPictureTakenListener = listener;
if (mCamera != null) {
mCamera.takePicture(this, null, this);
} else {
onPictureTakenListener.onFailed("拍照失败");
}
}
}
public void setZoom(int progress) {
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setZoom((int) (progress * 1.0f / (40 * 100) * 40));
mCamera.setParameters(parameters);
}
}
public void switchCamera(int index) {
if (isRecording) {
stopRecord();
}
releaseCamera();
this.index = index;
openCamera();
}
@Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
if (index == 1) {
bitmap = reversalBitmap(bitmap, -1, 1);
}
if (onPictureTakenListener != null) {
onPictureTakenListener.onSuccess(bitmap);
}
// 使拍照结束后重新预览
releaseCamera();
openCamera();
}
private Bitmap reversalBitmap(Bitmap srcBitmap, float sx, float sy) {
Bitmap cacheBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), Bitmap.Config.ARGB_8888);
int w = cacheBitmap.getWidth();
int h = cacheBitmap.getHeight();
Canvas canvas = new Canvas(cacheBitmap);
Matrix matrix = new Matrix();
matrix.postScale(sx, sy);
Bitmap bitmap = Bitmap.createBitmap(srcBitmap, 0, 0, w, h, matrix, true);
canvas.drawBitmap(bitmap, new Rect(0, 0, srcBitmap.getWidth(), srcBitmap.getHeight()), new Rect(0, 0, w, h), null);
return bitmap;
}
@Override
public void onShutter() {
}
public interface OnPictureTakenListener {
void onSuccess(Bitmap bitmap);
void onFailed(String msg);
}
// ---------------- 录像
private boolean initMediaRecorder(String outputPath) {
mMediaRecorder = new MediaRecorder();
if (mCamera != null) {
// 1.解锁并将相机设置daoMediaRecorder
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
// 2.设置资源
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// 3.设置CamcorderProfile(需要API级别8或更高版本)
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
// 4.设置输出文件
mMediaRecorder.setOutputFile(outputPath);
// 5.准备配置的MediaRecorder
try {
mMediaRecorder.prepare();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getContext(), "录像配置准备失败", Toast.LENGTH_SHORT).show();
releaseMediaRecorder();
return false;
}
return true;
}
return false;
}
private void releaseMediaRecorder() {
if (mMediaRecorder != null) {
mMediaRecorder.reset();
mMediaRecorder.release();
mMediaRecorder = null;
}
}
public void startRecord(String outputPath, OnStartVideoListener listener) {
this.onStartVideoListener = listener;
if (initMediaRecorder(outputPath)) {
new MediaPrepareTask(listener).execute();
} else {
Toast.makeText(getContext(), "开始录制视频失败", Toast.LENGTH_SHORT).show();
}
}
public void stopRecord() {
if (isRecording) {
mMediaRecorder.stop();
releaseMediaRecorder();
mCamera.lock();
if (onStartVideoListener != null)
onStartVideoListener.onStop();
} else {
releaseMediaRecorder();
}
isRecording = false;
}
public boolean isRecording() {
return isRecording;
}
class MediaPrepareTask extends AsyncTask {
OnStartVideoListener listener;
MediaPrepareTask(OnStartVideoListener listener) {
this.listener = listener;
}
@Override
protected Boolean doInBackground(Void... params) {
mMediaRecorder.start();
isRecording = true;
return true;
}
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
if (listener != null)
listener.onStart();
}
}
public interface OnStartVideoListener {
void onStart();
void onStop();
}
}
至此,正文结束,如大家遇到问题,欢迎评论、私信或邮件。