效果图:
java代码:
package com.cayden.videorecord;
import java.io.IOException;
import java.util.List;
import com.cayden.videorecord.util.LogsUtil;
import com.cayden.videorecord.util.SupportedSizesReflect; import android.app.Activity; import android.content.Context; import android.graphics.PixelFormat; import android.hardware.Camera; import android.hardware.Camera.CameraInfo; import android.hardware.Camera.Size; import android.media.AudioManager; import android.media.MediaPlayer; import android.media.MediaPlayer.OnBufferingUpdateListener; import android.media.MediaPlayer.OnCompletionListener; import android.media.MediaRecorder; import android.os.Bundle; import android.util.DisplayMetrics; import android.view.Display; import android.view.SurfaceHolder; import android.view.SurfaceHolder.Callback; import android.view.SurfaceView; import android.view.View; import android.view.WindowManager; import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; /** * TODO * * @author zhujiabin * @version 1.0.0 */ public class RecordActivity extends Activity implements Callback, MediaPlayer.OnPreparedListener, OnBufferingUpdateListener, OnCompletionListener { private static final String TAG = "RecordActivity"; private String videoPath = "/sdcard/love.3gp"; private MediaRecorder mediarecorder;// 录制视频的类 private MediaPlayer mediaPlayer;// 播放视频的类 private SurfaceView surfaceview;// 显示视频的控件 private Camera camera; private SurfaceHolder surfaceHolder;// 实现这个接口的Callback接口 private boolean isRecord = false; // 是否正在录制true录制中 false未录制 public boolean isCameraBack = true; private ImageView recordIv; private ImageView recordPlayIv; private int cameraPosition = 1;// 0代表前置摄像头,1代表后置摄像头 private int mVideoWidth; private int mVideoHeight; int cameraCount = 0; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.video_record); setTitleStr(""); getWindow().setFormat(PixelFormat.TRANSLUCENT);// 选择支持半透明模式,在有surfaceview的activity中使用。 initView(); } private void initView() { surfaceview = (SurfaceView) this.findViewById(R.id.surfaceview); recordIv = (ImageView) findViewById(R.id.recordIv); recordPlayIv = (ImageView) findViewById(R.id.recordPlayIv); SurfaceHolder holder = surfaceview.getHolder();// 取得holder holder.addCallback(this);// holder加入回调接口 holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);// setType必须设置,要不出错. recordIv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { recordVideo(v); } }); } public void playVideo(View v) { // 播放视频 recordPlayIv.setVisibility(View.GONE); try { mediaPlayer = new MediaPlayer(); mediaPlayer.setDataSource(videoPath); mediaPlayer.setDisplay(surfaceHolder); mediaPlayer.prepareAsync(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } mediaPlayer.setOnBufferingUpdateListener(this); mediaPlayer.setOnCompletionListener(this); mediaPlayer.setOnPreparedListener(this); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); } public void recordVideo(View v) { // 开始录制/停止录制 if (isRecord) { isRecord = false; recordIv.setImageResource(R.drawable.video_recorder_start_btn_nor); recordPlayIv.setVisibility(View.VISIBLE); if (mediarecorder != null) { // 停止录制 mediarecorder.stop(); // 释放资源 mediarecorder.release(); mediarecorder = null; } if (camera != null) { camera.release(); } } else { isRecord = true; recordIv.setImageResource(R.drawable.video_recorder_recording_btn); recordPlayIv.setVisibility(View.GONE); if (camera != null) { camera.release(); } if (cameraPosition == 1) { camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);//打开摄像头 camera = deal(camera); //视频旋转90度 mediarecorder.setOrientationHint(90); } else { camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);//打开摄像头 Camera.Parameters parameters = camera.getParameters(); camera.setDisplayOrientation(90); camera.setParameters(parameters); //视频旋转90度 mediarecorder.setOrientationHint(270); } camera.unlock(); mediarecorder.setCamera(camera); // 设置录制视频源为Camera(相机) mediarecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA); // 设置录制完成后视频的封装格式THREE_GPP为3gp.MPEG_4为mp4 mediarecorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP); // 设置录制的视频编码h263 h264 mediarecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264); // 设置视频录制的分辨率。必须放在设置编码和格式的后面,否则报错 mediarecorder.setVideoSize(176, 144); // 设置录制的视频帧率。必须放在设置编码和格式的后面,否则报错 mediarecorder.setVideoFrameRate(20); mediarecorder.setPreviewDisplay(surfaceHolder.getSurface()); // 设置视频文件输出的路径 mediarecorder.setOutputFile(videoPath); try { // 准备录制 mediarecorder.prepare(); mediarecorder.start(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } protected void setTitleStr(String str) { TextView titleText = (TextView) findViewById(R.id.common_title_text); titleText.setText(str.trim()); Button left_button = (Button) findViewById(R.id.left_button); left_button.setVisibility(View.GONE); Button right_button = (Button) findViewById(R.id.right_button); right_button.setVisibility(View.VISIBLE); right_button.setText(""); right_button.setBackgroundResource(R.drawable.btn_video_switch_bg); right_button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub cameraCount = Camera.getNumberOfCameras(); if (isCameraBack) { isCameraBack = false; } else { isCameraBack = true; } int cameraCount = 0; CameraInfo cameraInfo = new CameraInfo(); cameraCount = Camera.getNumberOfCameras(); for (int i = 0; i < cameraCount; i++) { Camera.getCameraInfo(i, cameraInfo);//得到每一个摄像头的信息 if (cameraPosition == 1) { //现在是后置,变更为前置 if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {//代表摄像头的方位,CAMERA_FACING_FRONT前置 CAMERA_FACING_BACK后置 camera.stopPreview();//停掉原来摄像头的预览 camera.release();//释放资源 camera = null;//取消原来摄像头 camera = Camera.open(i);//打开当前选中的摄像头 try { deal(camera); camera.setPreviewDisplay(surfaceHolder);//通过surfaceview显示取景画面 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } camera.startPreview();//开始预览 cameraPosition = 0; break; } } else { //现在是前置, 变更为后置 if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {// 代表摄像头的方位,CAMERA_FACING_FRONT前置 // CAMERA_FACING_BACK后置 camera.stopPreview();// 停掉原来摄像头的预览 camera.release();// 停掉原来摄像头的预览 camera = null;// 释放资源 camera = Camera.open(i);// 取消原来摄像头 try { deal(camera); camera.setPreviewDisplay(surfaceHolder);// 通过surfaceview显示取景画面 } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } camera.startPreview();// 开始预览 cameraPosition = 1; break; } } } } }); } public void back() { // 返回 finish(); } public Camera deal(Camera camera) { // 设置camera预览的角度,因为默认图片是倾斜90度的 camera.setDisplayOrientation(90); Size pictureSize = null; Size previewSize = null; Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewFrameRate(5); // 设置旋转代码 parameters.setRotation(90); List<Size> supportedPictureSizes = SupportedSizesReflect .getSupportedPictureSizes(parameters); List<Size> supportedPreviewSizes = SupportedSizesReflect .getSupportedPreviewSizes(parameters); if (supportedPictureSizes != null && supportedPreviewSizes != null && supportedPictureSizes.size() > 0 && supportedPreviewSizes.size() > 0) { // 2.x pictureSize = supportedPictureSizes.get(0); int maxSize = 1280; if (maxSize > 0) { for (Size size : supportedPictureSizes) { if (maxSize >= Math.max(size.width, size.height)) { pictureSize = size; break; } } } WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); DisplayMetrics displayMetrics = new DisplayMetrics(); display.getMetrics(displayMetrics); previewSize = getOptimalPreviewSize(supportedPreviewSizes, display.getWidth(), display.getHeight()); parameters.setPictureSize(pictureSize.width, pictureSize.height); parameters.setPreviewSize(previewSize.width, previewSize.height); } camera.setParameters(parameters); return camera; } @Override public void surfaceChanged(SurfaceHolder holder, int arg1, int arg2, int arg3) { // 将holder,这个holder为开始在oncreat里面取得的holder,将它赋给surfaceHolder surfaceHolder = holder; } private Size getOptimalPreviewSize(List<Size> sizes, int w, int h) { final double ASPECT_TOLERANCE = 0.1; double targetRatio = (double) w / h; if (sizes == null) return null; Size optimalSize = null; double minDiff = Double.MAX_VALUE; int targetHeight = h; // Try to find an size match aspect ratio and size for (Size size : sizes) { double ratio = (double) size.width / size.height; if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue; if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } // Cannot find the one match the aspect ratio, ignore the requirement if (optimalSize == null) { minDiff = Double.MAX_VALUE; for (Size size : sizes) { if (Math.abs(size.height - targetHeight) < minDiff) { optimalSize = size; minDiff = Math.abs(size.height - targetHeight); } } } return optimalSize; } @Override public void surfaceCreated(SurfaceHolder holder) { // TODO Auto-generated method stub surfaceHolder = holder; try { if (isCameraBack) { camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);// 鎵撳紑鎽勫儚澶� } else { camera = Camera.open(Camera.CameraInfo.CAMERA_FACING_FRONT);// 鎵撳紑鎽勫儚澶� } // 设置camera预览的角度,因为默认图片是倾斜90度的 camera.setDisplayOrientation(90); Size pictureSize = null; Size previewSize = null; Camera.Parameters parameters = camera.getParameters(); parameters.setPreviewFrameRate(5); // 设置旋转代码 parameters.setRotation(90); List<Size> supportedPictureSizes = SupportedSizesReflect .getSupportedPictureSizes(parameters); List<Size> supportedPreviewSizes = SupportedSizesReflect .getSupportedPreviewSizes(parameters); if (supportedPictureSizes != null && supportedPreviewSizes != null && supportedPictureSizes.size() > 0 && supportedPreviewSizes.size() > 0) { // 2.x pictureSize = supportedPictureSizes.get(0); int maxSize = 1280; if (maxSize > 0) { for (Size size : supportedPictureSizes) { if (maxSize >= Math.max(size.width, size.height)) { pictureSize = size; break; } } } WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE); Display display = windowManager.getDefaultDisplay(); DisplayMetrics displayMetrics = new DisplayMetrics(); display.getMetrics(displayMetrics); previewSize = getOptimalPreviewSize(supportedPreviewSizes, display.getWidth(), display.getHeight()); parameters .setPictureSize(pictureSize.width, pictureSize.height); parameters .setPreviewSize(previewSize.width, previewSize.height); } camera.setParameters(parameters); camera.setPreviewDisplay(holder); camera.startPreview(); } catch (Exception e) { e.printStackTrace(); } } @Override public void surfaceDestroyed(SurfaceHolder arg0) { // TODO Auto-generated method stub if (camera != null) { camera.release(); } surfaceview = null; surfaceHolder = null; if (surfaceHolder != null) { surfaceHolder = null; } if (mediarecorder != null) { mediarecorder = null; } if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } } @Override public void onCompletion(MediaPlayer arg0) { // TODO Auto-generated method stub LogsUtil.i(TAG, "onCompletion"); if (mediaPlayer != null) { mediaPlayer.release(); mediaPlayer = null; } recordPlayIv.setVisibility(View.VISIBLE); } @Override public void onPrepared(MediaPlayer arg0) { // TODO Auto-generated method stub mVideoWidth = mediaPlayer.getVideoWidth(); mVideoHeight = mediaPlayer.getVideoHeight(); if (mVideoWidth != 0 && mVideoHeight != 0) { surfaceHolder.setFixedSize(mVideoWidth, mVideoHeight);// 设置视频的宽度和高度 mediaPlayer.start();// 开始播放 } } @Override public void onBufferingUpdate(MediaPlayer player, int arg1) { // TODO Auto-generated method stub } }
布局文件代码:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout android:orientation="vertical" android:layout_width="fill_parent" android:background="@drawable/login_bj" android:layout_height="fill_parent" xmlns:android="http://schemas.android.com/apk/res/android"> <include android:id="@+id/Title" android:layout_alignParentTop="true" android:layout_width="fill_parent" android:layout_height="wrap_content" layout="@layout/layout_common_title"/> <LinearLayout android:layout_below="@+id/Title" android:layout_above="@+id/recordBtn" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="30dp" > <SurfaceView android:id="@+id/surfaceview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout> <RelativeLayout android:id="@+id/videoPlay" android:layout_width="fill_parent" android:layout_height="fill_parent" android:gravity="center" > <ImageView android:src="@drawable/btn_video_play_bg" android:id="@+id/recordPlayIv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="true" android:onClick="playVideo" android:visibility="gone" /> </RelativeLayout> <RelativeLayout android:id="@+id/recordBtn" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:layout_alignParentBottom="true"> <ImageView android:src="@drawable/video_recorder_start_btn_nor" android:id="@+id/recordIv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:clickable="true" android:onClick="recordVideo" /> </RelativeLayout> </RelativeLayout>
这里还有一些地方需要完善,在录制完成后切换会出现问题。由于时间关系这边还没去处理,在后续会进行处理,
此代码采用的sdk是17,由于在android 2.2上录制视频是横着,所以采用了高点的sdk
代码:这里