Android 小视频录制

一·视频录制界面 SurfaceView 的使用

SurfaceView我们可以把它当作一个容器,它放在所有窗口的下面·提供了一个可见区域,通过SurfaceHolder接口访问这个surface,getHolder()方法可以得到这个接口,它相当于SurfaceView 的控制器 然后通过调用addCallback();方法就可以进入它的生命周期开始使用


二·Camera的使用

1.在 Android Manifest.xml 中声明相机权限
2. 打开相机设备
3. 配置相机参数
4. 设置相机预览方向
5. ~~使用
6. 释放相机设备

三·视频录制控件MediaRecorder的使用
 对MediaRecorder的总结(干货)
http://blog.****.net/qisan__/article/details/79251205
Android 小视频录制


权限
<uses-permissionandroid:name="android.permission.CAMERA"/>
<uses-permissionandroid:name="android.permission.RECORD_AUDIO"/>
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

1:设置SurfaceView:

SurfaceView surfaceView = (SurfaceView) findViewById(R.id.record_surfaceView);
拿到SurfaceView的控制器

mSurfaceHolder = surfaceView.getHolder();

设置类型
mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

四种SurfaceView的类型
SURFACE_TYPE_NORMAL:用RAM缓存原生数据的普通Surface
SURFACE_TYPE_HARDWARE:适用于DMA(Direct memory access )引擎和硬件加速的Surface
SURFACE_TYPE_GPU:适用于GPU加速的Surface
SURFACE_TYPE_PUSH_BUFFERS:表明该Surface不包含原生数据,Surface用到的数据由其他对象提供,在Camera图像预览中就使用该类型的Surface,有Camera负责提供给预览Surface数据,这样图像预览会比较流畅。如果设置这种类型则就不能调用lockCanvas来获取Canvas对象了。

设置分辨率
mSurfaceHolder.setFixedSize(320, 280);

设置该组件不会让屏幕自动关闭
mSurfaceHolder.setKeepScreenOn(true);

实现CallBack初始化SurfaceHolder进入生命周期
mSurfaceHolder.addCallback(mCallBack);

private SurfaceHolder.Callback mCallBack = new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
初始化相机
initCamera();
}

@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) {
if (mSurfaceHolder.getSurface() == null) {
return;
}
}

@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
关闭相机
stopCamera();
}
};

2·初始化相机并且配置
private void initCamera() {
if (mCamera != null) {
stopCamera();
}
//默认启动后置摄像头
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
if (mCamera == null) {
Toast.makeText(this, "未能获取到相机!", Toast.LENGTH_SHORT).show();
return;
}
try {
//显示映视
mCamera.setPreviewDisplay(mSurfaceHolder);
//配置CameraParams

if (mCamera != null) {
Camera.Parameters params = mCamera.getParameters();
//设置相机的横竖屏幕
if (this.getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
//竖屏
params.set("orientation", "portrait");
mCamera.setDisplayOrientation(90);
} else {
//横屏
params.set("orientation", "landscape");
mCamera.setDisplayOrientation(0);
}
//设置聚焦模式
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
//缩短Recording启动时间
params.setRecordingHint(true);
//是否支持影像稳定能力,支持则开启
if (params.isVideoStabilizationSupported())
params.setVideoStabilization(true);
mCamera.setParameters(params);
}

//启动相机预览
mCamera.startPreview();
} catch (IOException e) {
Log.d("TAG", "Error starting camera preview: " + e.getMessage());
}
}


设置停止相机工作方法
private void stopCamera() {
if (mCamera != null) {
mCamera.setPreviewCallback(null);
mCamera.stopPreview();
mCamera.release();
mCamera = null;
}
}

基本都是固定的套路

接下来给开始和停止按钮设置点击事件
开始调用star();
停止调用stop();

private void Start() {
判断路径File对象是否创建成功或者有此路径
boolean creakOk = createRecordDir();
if (!creakOk) {
return;
}
初始化相机
initCamera();
设置录像前需要将相机解锁 (非常重要)
mCamera.unlock();
初始化MediaRecorder
setConfigRecord();
try {
//开始录制
mediaRecorder.prepare();
mediaRecorder.start();
} catch (IOException e) {
e.printStackTrace();
}
把是否正在录制的状态改变
isRecording = true;
}

private void setConfigRecord() {
mediaRecorder = new MediaRecorder(); 创建
mediaRecorder.reset(); 设置为空闲模式 可以赋属性了
mediaRecorder.setCamera(mCamera); 设置一个摄像头用于录制。
mediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() {
@Override
public void onError(MediaRecorder mr, int what, int extra) {
try {
if (mediaRecorder != null) {
mediaRecorder.reset();
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
记录录制时出现的错误的监听器,调用reset();方法设置为空闲模式

//使用SurfaceView预览
mediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

//1.设置采集声音
mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置采集图像
mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
//2.设置视频,音频的输出格式 mp4
mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT);
//3.设置音频的编码格式
mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
//设置图像的编码格式
mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
//音频一秒钟包含多少数据位
CamcorderProfile mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
mediaRecorder.setAudioEncodingBitRate(44100);
if (mProfile.videoBitRate > 2 * 1024 * 1024)
mediaRecorder.setVideoEncodingBitRate(2 * 1024 * 1024);
else
mediaRecorder.setVideoEncodingBitRate(1024 * 1024);
mediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);

//设置选择角度,顺时针方向,因为默认是逆向90度的,这样图像就是正常显示了,这里设置的是观看保存后的视频的角度
mediaRecorder.setOrientationHint(90);
//设置录像的分辨率
mediaRecorder.setVideoSize(352, 288);
储存
mediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());
}

判断路径File对象是否创建成功或者有此路径返回Boolean值
private boolean createRecordDir() {
if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
Toast.makeText(this, "请查看您的SD卡是否存在!", Toast.LENGTH_SHORT).show();
return false;
}

File targetDir = Environment.
getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
if (!targetDir.exists()) {
targetDir.mkdirs();
}
mVecordFile = new File(targetDir,
SystemClock.currentThreadTimeMillis() + ".mp4");

return true;
}


private void stop() {
if (isRecording && mediaRecorder != null) {
将监听还有预览设置为空避免崩溃
mediaRecorder.setOnErrorListener(null);
mediaRecorder.setPreviewDisplay(null);
//停止录制
mediaRecorder.stop();
mediaRecorder.reset();
//释放资源
mediaRecorder.release();
mediaRecorder = null;

isRecording = false;
}
吐司一下视屏存放位置
Toast.makeText(this, ""+mVecordFile.getAbsolutePath(), Toast.LENGTH_LONG).show();
}