效果
代码
package com.javen.devicemange.CrazyOne.media; import android.Manifest; import android.hardware.Camera; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.view.View; import android.widget.ImageButton; import android.widget.TextView; import com.javen.devicemange.R; import java.io.File; import java.text.SimpleDateFormat; import java.util.Date; /** * Created by Administrator on 2017/3/2 0002. * 使用MediaRecorder实现简单的录像功能 */ public class MediaRecordVideo extends AppCompatActivity implements View.OnClickListener { private SurfaceView mCameraPreview; private SurfaceHolder mSurfaceHolder; private ImageButton mShutter; private TextView mMinutePrefix; private TextView mMinuteText; private TextView mSecondPrefix; private TextView mSecondText; private Camera mCamera; private MediaRecorder mRecorder; private final static int CAMERA_ID = 0; private boolean mIsRecording = false; private boolean mIsSufaceCreated = false; private static final String TAG = "GsonUtils"; private Handler mHandler = new Handler(); private int width; private int height; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mediarecordvideo); //申请权限 requestPermission(); mCameraPreview = (SurfaceView) findViewById(R.id.camera_preview); mMinutePrefix = (TextView) findViewById(R.id.timestamp_minute_prefix); mMinuteText = (TextView) findViewById(R.id.timestamp_minute_text); mSecondPrefix = (TextView) findViewById(R.id.timestamp_second_prefix); mSecondText = (TextView) findViewById(R.id.timestamp_second_text); mShutter = (ImageButton) findViewById(R.id.record_shutter); Log.d(TAG, "mShutter=" + mShutter); /***1.定义一个SurfaceView用来显示预览***/ mSurfaceHolder = mCameraPreview.getHolder(); mSurfaceHolder.addCallback(mSurfaceCallback); // mSurfaceView 不需要自己的缓冲区 mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); //获取SurfaceView的宽高 width = mCameraPreview.getWidth(); height = mCameraPreview.getHeight(); Log.d("GsonUtils", "width=" + width); Log.d("GsonUtils", "height=" + height); mShutter.setOnClickListener(this); } /** * 申请权限 */ private void requestPermission() { String[] needPermission = { Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, }; ActivityCompat.requestPermissions(this, needPermission, 1); } @Override protected void onPause() { super.onPause(); if (mIsRecording) { //先停止记录 stopRecording(); } //停止预览 stopPreview(); } /*** * 2.在SurfaceHolder的回调中用Camera对象启动预览 ***/ private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceDestroyed(SurfaceHolder holder) { mIsSufaceCreated = false; } @Override public void surfaceCreated(SurfaceHolder holder) { mIsSufaceCreated = true; } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { startPreview(); } }; /** * 启动预览 */ private void startPreview() { //保证只有一个Camera对象 //当mCamera存在的,或者mIsSufaceCreated还存在 if (mCamera != null || !mIsSufaceCreated) { Log.d(TAG, "startPreview will return"); return; } //打开相机 mCamera = Camera.open(CAMERA_ID); Camera.Parameters parameters = mCamera.getParameters(); //获取最佳的预览尺寸 Camera.Size size = getBestPreviewSize(width, height, parameters); if (size != null) { //设置预览的尺寸 parameters.setPreviewSize(size.width, size.height); } parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO); //设置视频每秒20帧 parameters.setPreviewFrameRate(20); //设置相机预览方向 mCamera.setDisplayOrientation(90); mCamera.setParameters(parameters); try { //让surfaceView来预览Camera mCamera.setPreviewDisplay(mSurfaceHolder); //mCamera.setPreviewCallback(mPreviewCallback); } catch (Exception e) { Log.d(TAG, e.getMessage()); } //开始预览 mCamera.startPreview(); } private void stopPreview() { //释放Camera对象 if (mCamera != null) { try { mCamera.setPreviewDisplay(null); } catch (Exception e) { Log.e(TAG, e.getMessage()); } mCamera.stopPreview(); mCamera.release(); mCamera = null; } } /** * 获取最佳的预览尺寸 * * @param width * @param height * @param parameters * @return */ private Camera.Size getBestPreviewSize(int width, int height, Camera.Parameters parameters) { Camera.Size result = null; for (Camera.Size size : parameters.getSupportedPreviewSizes()) { //如果系统相机所支持的尺寸小于传入的尺寸, if (size.width <= width && size.height <= height) { //第一次初始化,就选用系统相机的尺寸 if (result == null) { result = size; } else { //获取上一次的面积区域 int resultArea = result.width * result.height; //遍历下一次的面积区域 int newArea = size.width * size.height; //选用面积区域大的尺寸 if (newArea > resultArea) { result = size; } } } } return result; } @Override public void onClick(View v) { if (mIsRecording) { stopRecording(); } else { /***3.然后调用MediaRecorder来录像***/ initMediaRecorder(); startRecording(); //开始录像后,每隔1s去更新录像的时间戳,开启任务 mHandler.postDelayed(mTimestampRunnable, 1000); } } /** * 初始化MediaRecorder */ private void initMediaRecorder() { mRecorder = new MediaRecorder();//实例化 mCamera.unlock(); //给Recorder设置Camera对象,保证录像跟预览的方向保持一致 mRecorder.setCamera(mCamera); mRecorder.setOrientationHint(90); //改变保存后的视频文件播放时是否横屏(不加这句,视频文件播放的时候角度是反的) mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); // 设置从麦克风采集声音 mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 设置从摄像头采集图像 mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4); // 设置视频的输出格式 为MP4 mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); // 设置音频的编码格式 mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置视频的编码格式 mRecorder.setVideoSize(176, 144); // 设置视频大小 mRecorder.setVideoFrameRate(20); // 设置帧率 // mRecorder.setMaxDuration(10000); //设置最大录像时间为10s mRecorder.setPreviewDisplay(mSurfaceHolder.getSurface()); String videoPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + File.separator + "VideoRecorder".toString(); Log.d("GsonUtils", "videoPath=" + videoPath); //设置视频存储路径sd卡:movies/VideoRecorder File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES) + File.separator + "VideoRecorder"); if (!file.exists()) { //多级文件夹的创建 file.mkdirs(); } //获取到当前时间状态 Date date = new Date(); date.setTime(System.currentTimeMillis()); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd_HH:mm"); String currentTime = simpleDateFormat.format(date); Log.d("GsonUtils", "currentTime=" + currentTime); mRecorder.setOutputFile(file.getPath() + File.separator + "VID_" + currentTime + ".mp4"); } /** * 开始记录 */ private void startRecording() { if (mRecorder != null) { try { mRecorder.prepare(); mRecorder.start(); } catch (Exception e) { mIsRecording = false; Log.e(TAG, e.getMessage()); } } mShutter.setImageDrawable(getResources().getDrawable(R.drawable.btn_radio_on)); //标记为已经在记录中 mIsRecording = true; } /** * 停止记录 */ private void stopRecording() { if (mCamera != null) { mCamera.lock(); } if (mRecorder != null) { mRecorder.stop(); mRecorder.release(); mRecorder = null; } mShutter.setImageDrawable(getResources().getDrawable(R.drawable.btn_radio_off_)); mIsRecording = false; //移除runnable的任务 mHandler.removeCallbacks(mTimestampRunnable); //将录像时间还原 mMinutePrefix.setVisibility(View.VISIBLE); mMinuteText.setText("0"); mSecondPrefix.setVisibility(View.VISIBLE); mSecondText.setText("0"); //重启预览 startPreview(); } private Runnable mTimestampRunnable = new Runnable() { @Override public void run() { updateTimestamp(); //每隔1s开启runnable任务 mHandler.postDelayed(this, 1000); } }; /** * 动态的刷新时间分秒 */ private void updateTimestamp() { int second = Integer.parseInt(mSecondText.getText().toString()); int minute = Integer.parseInt(mMinuteText.getText().toString()); second++; Log.d(TAG, "second: " + second); if (second < 10) { mSecondText.setText(String.valueOf(second)); } else if (second >= 10 && second < 60) { //超过10s,隐藏十位上的秒。 mSecondPrefix.setVisibility(View.GONE); mSecondText.setText(String.valueOf(second)); } else if (second >= 60) { //超过60s,显示十位上的秒。 mSecondPrefix.setVisibility(View.VISIBLE); mSecondText.setText("0"); minute++; mMinuteText.setText(String.valueOf(minute)); } else if (minute >= 10) { mMinutePrefix.setVisibility(View.GONE); } } }
布局
AndroidManifest.xml
<!--授予程序相机,读写sd卡的权限--> <uses-permission android:name="android.permission.RECORD_AUDIO"/> <uses-permission android:name="android.permission.CAMERA"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> <!--硬件支持--> <uses-feature android:name="android.hardware.camera"/> <uses-feature android:name="android.hardware.camera.autofocus"/>
。。。