转自:http://blog.csdn.net/coderyue/article/details/52830564
github:https://github.com/jinguangyue/Android-CustomCamera
1. 获取相机实例
/** * 获取Camera实例
* *@return
*/
privateCameragetCamera(intid) {
Camera camera =null;
try{
camera = Camera.open(id);
}catch(Exception e) {
}
returncamera; }
2. 开启预览
要注意, 开启预览要在 Activity 的 onResume 方法里面开启, 然后在 onPause 方法里面释放相机资源, 举一个简单的例子, 如果你在预览的时候按下了home键, 此时再次打开程序, 如果你是在 Oncreate 方法里面开启相机, 那么再次打开预览界面应该会卡住。
/**
* 预览相机
*/
privatevoidstartPreview(Camera camera, SurfaceHolder holder) {
try{
setupCamera(camera);
camera.setPreviewDisplay(holder);
recorderRotation = CameraUtil.getInstance().getRecorderRotation(mCameraId); CameraUtil.getInstance().setCameraDisplayOrientation(this, mCameraId, camera); camera.startPreview();
}catch(IOException e) {
e.printStackTrace();
}
}
/**
* 设置
*/
privatevoidsetupCamera(Camera camera) {
if(camera !=null) {
Camera.Parameters parameters = camera.getParameters();
List focusModes = parameters.getSupportedFocusModes();
if(focusModes !=null&& focusModes.size() >0) {
if(focusModes.contains( Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); }
}
List videoSiezes =null;if(parameters !=null) {
videoSiezes = parameters.getSupportedVideoSizes();
for(Camera.Size size : videoSiezes) {
}
}
if(videoSiezes !=null&& videoSiezes.size() >0) {
Camera.Size videoSize = CameraUtil.getInstance().getPropVideoSize(videoSiezes,720);
video_width = videoSize.width;
video_height = videoSize.height;
LogUtils.i("video_width==="+ video_width);
LogUtils.i("video_height==="+ video_height);
}
Camera.Size previewSize = CameraUtil.getInstance().getPropPreviewSize(parameters.getSupportedPreviewSizes(), video_width);
parameters.setPreviewSize(previewSize.width, previewSize.height);
Camera.Size pictrueSize = CameraUtil.getInstance().getPropPictureSize(parameters.getSupportedPictureSizes(), video_width); parameters.setPictureSize(pictrueSize.width, pictrueSize.height); camera.setParameters(parameters);
/**
* 设置surfaceView的尺寸 因为camera默认是横屏,所以取得支持尺寸也都是横屏的尺寸
* 我们在startPreview方法里面把它矫正了过来,但是这里我们设置设置surfaceView的尺寸的时候要注意 previewSize.height
* previewSize.width才是surfaceView的高度
* 一般相机都是屏幕的宽度 这里设置为屏幕宽度 高度自适应 你也可以设置自己想要的大小
*/
FrameLayout.LayoutParams params =newFrameLayout.LayoutParams(screenWidth, (screenWidth * video_width) / video_height);
surfaceView.setLayoutParams(params);
RelativeLayout.LayoutParams layoutParams =newRelativeLayout.LayoutParams(screenWidth, screenheight - screenWidth);
layoutParams.addRule(RelativeLayout.BELOW, surfaceView.getId()); layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); bottomLayout.setLayoutParams(layoutParams);
}
}
3. 开始录制
这里要注意的是 MediaRecorder 的相关方法的调用顺序时候不能乱的, 详细可以看官网api说明
接下来开启录制:
protected void start() { try { pathName = System.currentTimeMillis() +""//视频存储路径 file = new File(MyApplication.getInstance().getTempPath() + File.separator+ pathName + AppConfig.MP4) //如果没有要创建 BitmapUtils.makeDir(file) //初始化一个MediaRecorder if (mediaRecorder == null) { mediaRecorder = new MediaRecorder() } else { mediaRecorder.reset() } mCamera.unlock() mediaRecorder.setCamera(mCamera) //设置视频输出的方向 很多设备在播放的时候需要设个参数 这算是一个文件属性 mediaRecorder.setOrientationHint(recorderRotation) //视频源类型 mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA) mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC) mediaRecorder.setAudioChannels(2) // 设置视频图像的录入源 // 设置录入媒体的输出格式// mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) // 设置音频的编码格式// mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB) // 设置视频的编码格式// mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264) if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)) { profile = CamcorderProfile.get(CamcorderProfile.QUALITY_720P) } else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P)) { profile = CamcorderProfile.get(CamcorderProfile.QUALITY_1080P) } else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_HIGH)) { profile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH) } else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_LOW)) { profile = CamcorderProfile.get(CamcorderProfile.QUALITY_LOW) } if (profile != null) { profile.audioCodec= MediaRecorder.AudioEncoder.AACprofile.audioChannels=1profile.audioSampleRate=16000profile.videoCodec= MediaRecorder.VideoEncoder.H264 mediaRecorder.setProfile(profile) } //视频尺寸 mediaRecorder.setVideoSize(video_width, video_height) //数值越大 视频质量越高 mediaRecorder.setVideoEncodingBitRate(5*1024*1024) // 设置视频的采样率,每秒帧数// mediaRecorder.setVideoFrameRate(5) // 设置录制视频文件的输出路径 mediaRecorder.setOutputFile(file.getAbsolutePath()) mediaRecorder.setMaxDuration(2000) // 设置捕获视频图像的预览界面 mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface()) mediaRecorder.setOnErrorListener(new MediaRecorder.OnErrorListener() { @Override public void onError(MediaRecorder mr, int what, int extra) { // 发生错误,停止录制 if (mediaRecorder != null) { mediaRecorder.stop() mediaRecorder.release() mediaRecorder = null LogUtils.i("Error") } } }) mediaRecorder.setOnInfoListener(new MediaRecorder.OnInfoListener() { @Override public void onInfo(MediaRecorder mr, int what, int extra) { //录制完成 } }) // 准备、开始 mediaRecorder.prepare() mediaRecorder.start() new Thread(new Runnable() { @Override public void run() { for (int i =0try { Thread.currentThread().sleep(20) Message message = new Message() message.what=1message.obj= i handler.sendMessage(message) } catch (InterruptedException e) { e.printStackTrace() } } } }).start() } catch (Exception e) { e.printStackTrace() } }
4. 录制成功后接下来的重点来了
使用
ffmpeg 对视频进行裁剪正方形, ffmpeg 使用Shell命令的方式进行视频操作, 执行效率也是非常好, 那首先你要集成FFmpeg
到Android 项目里面, 这里我下载好了一个library, 直接引入到项目即可, 感兴趣的伙伴可以自己编译一个库,
这里我把命令贴出来解释一下,
ffmpeg-threads4-y-i/storage/emulated/0/CustomCamera/temp/1476598263062.mp4-metadata:s:v rotate="0"-vftranspose=1, crop=width:height:x:y-presetultrafast-tunezerolatency-r25-vcodeclibx264-acodeccopy /storage/emulated/0/CustomCamera/VIDEO/1476598263062.mp4
1
1
-y: 如果文件存在那么覆盖掉
-i: 输入
metadata:s:v rotate=”0” : 重新编码 除去rotate, 因为默认录制出来的是横屏视频, 这里重新编码
transpose=1 :
0 = 90CounterCLockwise and Vertical Flip (default) 逆时针旋转90度并且垂直翻转, 下面类推
1 = 90Clockwise
2 = 90CounterClockwise
3 = 90Clockwise and Vertical Flip
crop=width:height:x:y,其中 width 和 height 表示裁剪后的尺寸,x:y 表示裁剪区域的左上角坐标
-preset ultrafast -tune zerolatency: 加快效率
r 25:帧率
-vcodec libx264 -acodec: 编码方式libx264
如果想知道更多关于ffmpeg的东西可以访问官网https://ffmpeg.org/
再贴一下我的代码调用:
try{ fc.compress_clipVideo(file.getAbsolutePath(), file2.getAbsolutePath(), mCameraId, video_width, video_height,0,0,newShellUtils.ShellCallback() { @OverridepublicvoidshellOut(String shellLine) { } @OverridepublicvoidprocessComplete(intexitValue) { dialog.dismiss();if(exitValue !=0) { ToastFactory.showLongToast(context, getResources().getString(R.string.state_compress_error)); mHandler.sendEmptyMessage(R.string.state_compress_error); }else{ mHandler.sendEmptyMessage(R.string.state_compress_end); } } }); }catch(Exception e) { e.printStackTrace(); }
FFmpeg编译出来的Android 库还是很大的, 大约15M左右, 无疑增加了apk的大小, 如果你的产品方向是视频图片gif等等的格式转换类似的功能可以考虑使用