录制视频(Surfaceview+MediaRecorder)
来源:互联网 发布:大数据行业什么意思 编辑:程序博客网 时间:2024/05/16 19:22
欢迎转载和提问,转载请注明出处
http://blog.csdn.net/ning_gg/article/details/54314315
这个是自己写的录制视频,为了简单,全写在一个Activity中,可以切换照相机,没有带聚焦,需要聚焦自己写个OnTouch即可。在我的测试机上跑起来畅通无阻,我只有3个测试机。如果你使用了我的有问题可以告诉我。
这个demo比网上什么的写死录像尺寸强多了,全部自匹配尺寸。如果你的跑不起可以第一时间检测这个尺寸设置。我的思路是获取手机屏幕尺寸,得到高/宽的比 比如1280/720 或者1920/1080这样的。然后遍历Camera的预览尺寸,得到一个跟手机尺寸最合适的那一个,这样的话预览的时候图像不会变形,然后获取手机录像的尺寸,这里必须说下不是每个手机都提供这个录像尺寸,像华为mate7就不提供,不提供的另说,提供的会遍历这个尺寸,得到相同比例(比如预览是1920/1080=1.77777)最小的一个(800/450),这样的话比大部分提供的写死一个尺寸强多了,而且录制出来的东西不会变形。为什么要找最小的是因为我们的需求录制的视频最小越好。对于那些不提供录像尺寸的,直接把预览尺寸设成录像尺寸就可以了。mate7就是这样跑通的。
附上代码
import android.hardware.Camera;import android.media.MediaRecorder;import android.os.Environment;import android.support.v7.widget.Toolbar;import android.util.DisplayMetrics;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.widget.Button;import android.widget.TextView;import com.imapedia.ykdemo.R;import com.imapedia.ykdemo.base.BaseActivity;import com.imapedia.ykdemo.utils.L;import java.io.File;import java.io.IOException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import butterknife.BindView;import butterknife.OnClick;/** * Created by ning_gg on 2017/1/9. * <p/> * 录制视频,切换摄像头,尺寸匹配 */public class RecordVideoActivity extends BaseActivity implements MediaRecorder.OnErrorListener ,SurfaceHolder.Callback{ private String TAG=RecordVideoActivity.class.getSimpleName(); @BindView(R.id.activity_main_toolbar) Toolbar activity_main_toolbar; @BindView(R.id.recordvideo_sv) SurfaceView recordvideo_sv; private SurfaceHolder mSurfaceHolder; @BindView(R.id.toolbar_change_tv) TextView toolbar_change_tv; @OnClick (R.id.toolbar_change_tv) void toolbar_change_tvOnClick(){ if(recording){ try { stopRecord(); } catch (Exception e) { e.printStackTrace(); } } if (cameraPosition == Camera.CameraInfo.CAMERA_FACING_BACK) { cameraPosition = Camera.CameraInfo.CAMERA_FACING_FRONT; } else { cameraPosition = Camera.CameraInfo.CAMERA_FACING_BACK; } if (isOpenCamera) { mCamera.stopPreview();//停掉原来摄像头的预览 mCamera.release();//释放资源 mCamera = null;//取消原来摄像头 mCamera = Camera.open(cameraPosition); try { setCameraParms(); } catch (IOException e) { e.printStackTrace(); } } } @BindView(R.id.recordvideo_btn) Button recordvideo_btn; @OnClick(R.id.recordvideo_btn) void recordvideo_btnOnClick() { if (!recording) { try { startRecord(); } catch (IOException e) { e.printStackTrace(); } } else { try { stopRecord(); } catch (Exception e) { e.printStackTrace(); } } } private int screenHeight;//屏幕的高度 private int screenWidth;//屏幕的宽度 private Camera mCamera; private int videoWidth = 0;// 视频分辨率宽度 private int videoHeight = 0;// 视频分辨率高度 public Camera.Size pictureSize;//照片分辨率 private Camera.Size previewSize;//预览分辨率 private boolean isOpenCamera;// 是否已经打开摄像头 private int cameraPosition = Camera.CameraInfo.CAMERA_FACING_FRONT;//当前摄像头 private MediaRecorder mMediaRecorder; private String FilePath = Environment .getExternalStorageDirectory().getPath() + File.separator + "ninggegetest" + File.separator; private File mVecordFile; //是否正在录制中 private boolean recording; @Override protected int getLayoutId() { return R.layout.activity_recordvideo; } @Override protected void init() { DisplayMetrics dm = getResources().getDisplayMetrics(); screenWidth = dm.widthPixels; screenHeight = dm.heightPixels; mSurfaceHolder=recordvideo_sv.getHolder(); mSurfaceHolder.addCallback(this); } /** * 开始录制 */ private void startRecord() throws IOException { createRecordDir(); initRecord(); recording=true; recordvideo_btn.setBackgroundResource(R.drawable.stoprecord); } /** * 创建文件 */ private void createRecordDir() throws IOException { File sampleDir = new File(FilePath); if (!sampleDir.exists()) { sampleDir.mkdirs(); } File vecordDir = sampleDir; // 创建文件 SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日_HH_mm_ss"); Date curDate = new Date(System.currentTimeMillis());//获取当前时间 String str = formatter.format(curDate); mVecordFile = File.createTempFile(str, ".mp4", vecordDir);//mp4格式 } /** * 初始化 * * @throws IOException * @author ning_gg * @date 2015-3-16 */ private void initRecord() throws IOException { //必须解锁 不然会报错 mCamera.unlock(); mMediaRecorder = new MediaRecorder(); mMediaRecorder.reset(); if (mCamera != null) mMediaRecorder.setCamera(mCamera); mMediaRecorder.setOnErrorListener(this); mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.DEFAULT); mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); //后置摄像头是旋转90度 if (cameraPosition == 0) { mMediaRecorder.setOrientationHint(90);// 输出旋转90度,保持竖屏录制 } else { //前置摄像头是旋转270度 mMediaRecorder.setOrientationHint(270); } mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);// 视频输出格式 mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 音频格式 //H264用得最广 基本每个手机都支持 反倒其他的没有每个都支持 mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); mMediaRecorder.setVideoSize(videoWidth, videoHeight);// 设置分辨率 mMediaRecorder.setVideoEncodingBitRate(2 * 1024 * 1024);// 设置帧频率,然后就清晰了 // 设置录制的视频帧率。必须放在设置编码和格式的后面,否则报错 // mMediaRecorder.setVideoFrameRate(20); // mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000); mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath()); mMediaRecorder.prepare(); mMediaRecorder.start(); } /** * 停止录制 */ private void stopRecord() throws Exception { if (mMediaRecorder != null) { // 设置后不会崩 mMediaRecorder.setOnErrorListener(null); mMediaRecorder.setPreviewDisplay(null); mMediaRecorder.stop(); mMediaRecorder.release(); mMediaRecorder = null; } recording=false; recordvideo_btn.setBackgroundResource(R.drawable.startrecord); } @Override public void onError(MediaRecorder mediaRecorder, int i, int i1) { } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { if (mCamera != null) { mCamera.stopPreview();//停掉原来摄像头的预览 mCamera.release();//释放资源 mCamera = null;//取消原来摄像头 } int i = Camera.getNumberOfCameras(); //如果只有一个摄像头 if (i == 1) { mCamera = Camera.open(); toolbar_change_tv.setVisibility(View.GONE); } else { mCamera = Camera.open(cameraPosition); } isOpenCamera=true; try { setCameraParms(); } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { try { stopRecord(); } catch (Exception e) { e.printStackTrace(); } if (mCamera != null) { mCamera.setPreviewCallback(null); mCamera.stopPreview(); mCamera.release(); mCamera = null; } } private void setCameraParms() throws IOException{ mCamera.setPreviewDisplay(mSurfaceHolder); Camera.Parameters myParam = mCamera.getParameters(); List<String> flashModes = myParam.getSupportedFlashModes(); String flashMode = myParam.getFlashMode(); // Check if camera flash exists if (flashModes!=null&&!Camera.Parameters.FLASH_MODE_OFF.equals(flashMode)) { // Turn off the flash if (flashModes.contains(Camera.Parameters.FLASH_MODE_OFF)) { myParam.setFlashMode(Camera.Parameters.FLASH_MODE_OFF); } } float percent = calcPreviewPercent(); List<Camera.Size> supportedPreviewSizes = myParam.getSupportedPreviewSizes(); //因为有些手机videoSizes不提供 比如华为mate7 那样的话就只能拿照相机预览数据了 当然预览数据尺寸不知道能不能当视频录制尺寸 List<Camera.Size> videoSizes = mCamera.getParameters().getSupportedVideoSizes(); previewSize = getPreviewMaxSize(supportedPreviewSizes, percent); L.e(TAG, "预览尺寸w===" + previewSize.width + ",h===" + previewSize.height); if (videoSizes != null) { for (Camera.Size _s : videoSizes) { float videoS = (float) _s.width / _s.height; if (videoS == percent && _s.width < previewSize.width && _s.height < previewSize.height) { videoWidth = _s.width; videoHeight = _s.height; continue; } } } if (videoWidth == 0 && videoHeight == 0) { //如果没有拿到值 那就是当前的预览数据了 videoWidth = previewSize.width; videoHeight = previewSize.height; } L.e(TAG, "录像尺寸w===" + videoWidth + ",h===" + videoHeight); // 获取摄像头支持的各种分辨率 List<Camera.Size> supportedPictureSizes = myParam.getSupportedPictureSizes(); pictureSize = findSizeFromList(supportedPictureSizes, previewSize); if (pictureSize == null) { pictureSize = getPictureMaxSize(supportedPictureSizes, previewSize); } L.e(TAG, "照片尺寸w===" + pictureSize.width + ",h===" + pictureSize.height); // 设置照片分辨率,注意要在摄像头支持的范围内选择 myParam.setPictureSize(pictureSize.width, pictureSize.height); // 设置预浏尺寸,注意要在摄像头支持的范围内选择 myParam.setPreviewSize(previewSize.width, previewSize.height); myParam.setJpegQuality(70); mCamera.setParameters(myParam); mCamera.setDisplayOrientation(90); mCamera.startPreview(); mCamera.cancelAutoFocus(); } private float calcPreviewPercent() { float d = screenHeight; return d / screenWidth; } private Camera.Size findSizeFromList(List<Camera.Size> supportedPictureSizes, Camera.Size size) { Camera.Size s = null; if (supportedPictureSizes != null && !supportedPictureSizes.isEmpty()) { for (Camera.Size su : supportedPictureSizes) { if (size.width == su.width && size.height == su.height) { s = su; break; } } } return s; } // 根据摄像头的获取与屏幕分辨率最为接近的一个分辨率 private Camera.Size getPictureMaxSize(List<Camera.Size> l, Camera.Size size) { Camera.Size s = null; for (int i = 0; i < l.size(); i++) { if (l.get(i).width >= size.width && l.get(i).height >= size.width && l.get(i).height != l.get(i).width) { if (s == null) { s = l.get(i); } else { if (s.height * s.width > l.get(i).width * l.get(i).height) { s = l.get(i); } } } } return s; } // 获取预览的最大分辨率 private Camera.Size getPreviewMaxSize(List<Camera.Size> l, float j) { int idx_best = 0; int best_width = 0; float best_diff = 100.0f; for (int i = 0; i < l.size(); i++) { int w = l.get(i).width; int h = l.get(i).height; if (w * h < screenHeight * screenWidth) continue; float previewPercent = (float) w / h; float diff = Math.abs(previewPercent - j); if (diff < best_diff) { idx_best = i; best_diff = diff; best_width = w; } else if (diff == best_diff && w > best_width) { idx_best = i; best_diff = diff; best_width = w; } } return l.get(idx_best); } @Override public void onBackPressed() { super.onBackPressed(); try { stopRecord(); } catch (Exception e) { e.printStackTrace(); } finish(); }}
TextureView+MediaRecorder录像原理跟这个是一样的,只是把SurfaceView替换成TextureView就行了,怎么使用TextureView在这里
http://blog.csdn.net/ning_gg/article/details/54134918
欢迎转载和提问,转载请注明出处
http://blog.csdn.net/ning_gg/article/details/54314315
- 录制视频(Surfaceview+MediaRecorder)
- 安卓使用surfaceview+Camera+MediaRecorder实现视频录制
- 基于camera+SurfaceView+MediaRecorder的录制微视频
- MediaRecorder录制视频
- 视频录制MediaRecorder
- MediaRecorder录制视频
- MediaRecorder录制视频
- 录制视频之MediaRecorder
- Android MediaRecorder视频录制
- MediaRecorder 录制视频
- 视频录制-MediaRecorder
- MediaRecorder录制视频
- MediaRecorder之视频录制
- Android MediaRecorder录制视频
- SurfaceView录制视频
- 使用MediaRecorder录制音视频
- 使用MediaRecorder进行视频录制
- Android MediaRecorder 后台视频录制
- 七,redis集群
- Spring定时任务不执行的解决
- Json键值对
- 用ajax技术实现 无刷新实现用户登录
- Leetcode-96.Unique Binary Search Trees
- 录制视频(Surfaceview+MediaRecorder)
- BigDecimal类的加减乘除
- DRX不连续接收(2)-寻呼Paging
- Android从零开搞系列:网络框架系列(5)Retrofit+RxJava+MVP(中-下)RxJava篇(下)
- 总结解决maven版本兼容方法
- eclipse和myeclipse修改背景色
- 星光级摄像机
- JavaScript闭包
- HTML5学习笔记9-编辑API之Range对象(二)