layout:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical"> <SurfaceView android:id="@+id/record_surfaceView" android:layout_width="match_parent" android:layout_height="match_parent" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="#80ffffff" android:padding="10dp"> <!-- 开始/结束 录制按钮 --> <ImageView android:id="@+id/record_control" android:layout_width="60dp" android:layout_height="60dp" android:layout_centerInParent="true" android:onClick="startRecord" android:src="@drawable/recordvideo_start" /> <Chronometer android:id="@+id/record_time" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_alignParentRight="true" android:format="%s" /> </RelativeLayout> </RelativeLayout>
代码:
package com.example.apple.demo.CameraPreview; import com.example.apple.demo.R; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.os.Environment; import android.os.Handler; import android.os.SystemClock; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; import android.widget.Chronometer; import android.widget.Toast; import android.content.Context; import android.content.res.Configuration; import android.hardware.Camera; import android.media.CamcorderProfile; import android.media.MediaRecorder; import java.io.File; import java.io.IOException; public class CustomRecordActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "CustomRecordActivity"; //UI private ImageView mRecordControl; private SurfaceView surfaceView; private SurfaceHolder mSurfaceHolder; private Chronometer mRecordTime; //DATA //录像机状态标识 private int mRecorderState; public static final int STATE_INIT = 0; //开始录制 public static final int STATE_RECORDING = 1;//结束录制 // 存储文件 private File mVecordFile; private Camera mCamera; private MediaRecorder mediaRecorder; private String currentVideoFilePath; private String saveVideoPath = ""; private MediaRecorder.OnErrorListener OnErrorListener = new MediaRecorder.OnErrorListener() { @Override public void onError(MediaRecorder mediaRecorder, int what, int extra) { try { if (mediaRecorder != null) { mediaRecorder.reset(); } } catch (Exception e) { e.printStackTrace(); } } }; private void initView() { surfaceView = (SurfaceView) findViewById(R.id.record_surfaceView); mRecordControl = (ImageView) findViewById(R.id.record_control); mRecordTime = (Chronometer) findViewById(R.id.record_time); mRecordControl.setOnClickListener(this); //配置SurfaceHolder mSurfaceHolder = surfaceView.getHolder(); // 设置Surface不需要维护自己的缓冲区 mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); // 设置分辨率 mSurfaceHolder.setFixedSize(320, 280); // 设置该组件不会让屏幕自动关闭 mSurfaceHolder.setKeepScreenOn(true); //回调接口 mSurfaceHolder.addCallback(mSurfaceCallBack); } private SurfaceHolder.Callback mSurfaceCallBack = 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) { releaseCamera(); } }; /** * 初始化摄像头 * * @throws IOException * @author liuzhongjun */ private void initCamera() { if (mCamera != null) { releaseCamera(); } mCamera = Camera.open(); if (mCamera == null) { Toast.makeText(this, "未能获取到相机!", Toast.LENGTH_SHORT).show(); return; } try { //将相机与SurfaceHolder绑定 mCamera.setPreviewDisplay(mSurfaceHolder); //配置CameraParams configCameraParams(); //启动相机预览 mCamera.startPreview(); } catch (IOException e) { //有的手机会因为兼容问题报错,这就需要开发者针对特定机型去做适配了 Log.d(TAG, "Error starting camera preview: " + e.getMessage()); } } /** * 设置摄像头为竖屏 * * @author lip * @date 2015-3-16 */ private void configCameraParams() { Camera.Parameters params = mCamera.getParameters(); //设置相机的横竖屏(竖屏需要旋转90°) 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); } /** * 释放摄像头资源 * * @date 2016-2-5 */ private void releaseCamera() { if (mCamera != null) { mCamera.setPreviewCallback(null); mCamera.stopPreview(); mCamera.release(); mCamera = null; } } /** * 开始录制视频 */ public boolean startRecord() { initCamera(); //录制视频前必须先解锁Camera mCamera.unlock(); configMediaRecorder(); try { //开始录制 mediaRecorder.prepare(); mediaRecorder.start(); } catch (IOException e) { return false; } return true; } /** * 停止录制视频 */ public void stopRecord() { // 设置后不会崩 mediaRecorder.setOnErrorListener(null); mediaRecorder.setPreviewDisplay(null); //停止录制 mediaRecorder.stop(); mediaRecorder.reset(); //释放资源 mediaRecorder.release(); mediaRecorder = null; } /** * 点击中间按钮,执行的UI更新操作 */ private void refreshControlUI() { if (mRecorderState == STATE_INIT) { //录像时间计时 mRecordTime.setBase(SystemClock.elapsedRealtime()); mRecordTime.start(); mRecordControl.setImageResource(R.drawable.recordvideo_stop); //1s后才能按停止录制按钮 mRecordControl.setEnabled(false); new Handler().postDelayed(new Runnable() { @Override public void run() { mRecordControl.setEnabled(true); } }, 1000); } else if (mRecorderState == STATE_RECORDING) { mRecordTime.stop(); mRecordControl.setImageResource(R.drawable.recordvideo_start); } } @Override public void onClick(View view) { switch (view.getId()) { case R.id.record_control: { if (mRecorderState == STATE_INIT) { if (getSDPath(getApplicationContext()) == null) return; //视频文件保存路径,configMediaRecorder方法中会设置 currentVideoFilePath = getSDPath(getApplicationContext()) + getVideoName(); //开始录制视频 if (!startRecord()) return; refreshControlUI(); mRecorderState = STATE_RECORDING; } else if (mRecorderState == STATE_RECORDING) { //停止视频录制 stopRecord(); //先给Camera加锁后再释放相机 mCamera.lock(); releaseCamera(); refreshControlUI(); //判断是否进行视频合并 if ("".equals(saveVideoPath)) { saveVideoPath = currentVideoFilePath; } mRecorderState = STATE_INIT; //延迟一秒跳转到播放器,(确保视频合并完成后跳转) TODO 具体的逻辑可根据自己的使用场景跳转 new Handler().postDelayed(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "录制成功", Toast.LENGTH_SHORT).show(); onBackPressed(); } }, 1000); } break; } } } /** * 配置MediaRecorder() */ private void configMediaRecorder() { mediaRecorder = new MediaRecorder(); mediaRecorder.reset(); mediaRecorder.setCamera(mCamera); mediaRecorder.setOnErrorListener(OnErrorListener); //使用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); //设置立体声 // mediaRecorder.setAudioChannels(2); //设置最大录像时间 单位:毫秒 // mediaRecorder.setMaxDuration(60 * 1000); //设置最大录制的大小 单位,字节 // mediaRecorder.setMaxFileSize(1024 * 1024); //音频一秒钟包含多少数据位 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(currentVideoFilePath); Log.e("CustomRecordActivity", "CustomRecordActivity:" + getSDPath(CustomRecordActivity.this) + "append.mp4"); } /** * 创建视频文件保存路径 */ public static String getSDPath(Context context) { if (!Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { Toast.makeText(context, "请查看您的SD卡是否存在!", Toast.LENGTH_SHORT).show(); return null; } File sdDir = Environment.getExternalStorageDirectory(); File eis = new File(sdDir.toString() + "/cqytjr/"); if (!eis.exists()) { eis.mkdir(); } return sdDir.toString() + "/cqytjr/"; } private String getVideoName() { return "video" + ".mp4"; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_custom_record); initView(); } }