安卓自定义相机录像并上传(详细参数设置)
安卓调用系统相机录像并上传到后端服务器写在前面一、录像上传的思路二、添加相关权限三、按钮设置监听,调用相机录像并回调1、按钮设置监听:2、调用代码3、部分重要参数4、回调上传视频到服务器代码(参考上一篇调用系统相机的文章,同一个项目里写的代码)最后的最后:写在前面上篇文章讲了调用该系统相机,这里就来讲一下自定义相机吧。上一篇也讲了调用系统相机主要就是界面美观,功能完善,当然对于一个优秀的码畜,这些
·
安卓调用系统相机录像并上传到后端服务器
写在前面
- 上篇文章讲了调用该系统相机,这里就来讲一下自定义相机吧。上一篇也讲了调用系统相机主要就是界面美观,功能完善,当然对于一个优秀的码畜,这些都是可以通过技术手段实现的。
自定义相机优点: 那就是参数可自定义,可实现各种分辨率效果。
一、录像上传的思路
- 1、获取摄像头和麦克疯的权限
- 2、缓存到本地内存再进行上传,所以得获取
- 3、通过okhttp以流的方式上传到后台
二、添加相关权限
<!-- 授予该程序使用摄像头的权限 -->
<uses-permission android:name="android.permission.CAMERA"/>
<!-- 授予使用外部存储器的权限 -->
<permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 授予修改系统设置权限 -->
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<!-- 授予该程序使用麦克疯的权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
三、按钮设置监听,调用相机录像并回调
1、按钮设置监听:
2、调用代码
思路: 新建个界面activity 录像机预览画面展示的界面。
public void startCamera(View view) {
//自定义相机拍照 当前activity 跳转到指定activitty
Intent captureImageCamera = new Intent(VideoUploadActivity.this, RecordActivity.class);
startActivityForResult(captureImageCamera, VideoUploadActivity.VIDEO_RECORD);
}
RecordActivity.java:
public class RecordActivity extends Activity implements OnClickListener, Callback {
public static final int MEDIA_TYPE_IMAGE = 1;
public static final int MEDIA_TYPE_VIDEO = 2;
public static final int TIMER_FLAG_START = 1;
public static final int TIMER_FLAG_STOP = 2;
private static final String TAG = "调用相机:";
CameraFocusView cameraFocusView;
MyRunnable mRunnable;
Handler mHandler = new Handler();
int mCurrentSecond = 0;
String seconds = "00";
String minutes = "00";
String hours= "00";
// 程序中的两个button
ImageButton record , stop;
// 系统的视频文件
File videoFile ;
MediaRecorder mRecorder;
private SurfaceHolder mHolder;
private Camera mCamera;
// 显示视频预览的SurfaceView
SurfaceView sView ;
// 记录是否正在进行录制
private boolean isRecording = false;
CamcorderProfile profile;
String videoUrl;
TextView mTvTime5;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 去掉标题栏 ,必须放在setContentView之前
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.record_acitvity);
// 设置屏显示
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
// 设置全屏
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
// 选择支持半透明模式,在有surfaceView的activity中使用。
getWindow().setFormat(PixelFormat.TRANSLUCENT);
// 获取程序界面中的两个button
record = (ImageButton) findViewById(R.id.record);
stop = (ImageButton) findViewById(R.id.stop);
mTvTime5 = findViewById(R.id.mTvTime5);
// 让stopButton不可用。
stop.setEnabled(false);
// 为两个button的单击事件绑定监听器
record.setOnClickListener(this);
stop.setOnClickListener(this);
// 获取程序界面中的SurfaceView
sView = (SurfaceView) this.findViewById(R.id.sView);
mHolder = sView.getHolder();
// 设置分辨率
profile = CamcorderProfile.get(CamcorderProfile.QUALITY_1080P);
mHolder.setFixedSize( profile.videoFrameWidth, profile.videoFrameHeight);
// 设置该组件让屏幕不会自己主动关闭
sView.getHolder().setKeepScreenOn(true);
sView.getHolder().setFormat(PixelFormat.TRANSPARENT);
sView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
float reax = motionEvent.getX();
float reay = motionEvent.getY();
focusTouch(reax,reay);
return false;
}
});
mHolder.addCallback(this);
}
//点击屏幕聚焦
public void focusTouch(float reac_x, float reac_y){
int areaX = (int)(reac_x / sView.getWidth() * 2000) - 1000;
int areaY = (int)(reac_y / sView.getHeight() * 2000) - 1000;
if (mCamera == null){
return;
}
Camera.Parameters parameters = mCamera.getParameters();
if (parameters == null){
return;
}
//创建Rect区域
Rect focusArea = new Rect();
focusArea.left = Math.max(areaX -100,-1000);
focusArea.top = Math.max(areaY - 100,-1000);
focusArea.right = Math.min(areaX + 100,1000);
focusArea.bottom = Math.min(areaY + 100,1000);
//创建Camera.Area
Camera.Area cameraArea = new Camera.Area(focusArea,100);
List<Camera.Area> meteringAreas = new ArrayList<>();
List<Camera.Area> focusAreas = new ArrayList<>();
if (parameters.getMaxNumMeteringAreas() > 0){
meteringAreas.add(cameraArea);
focusAreas.add(cameraArea);
}
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
parameters.setFocusAreas(focusAreas);
parameters.setMeteringAreas(meteringAreas);
try {
mCamera.cancelAutoFocus();
mCamera.setParameters(parameters);
}catch (Exception e){
e.printStackTrace();
}
if (cameraFocusView != null) {
cameraFocusView.currentX = reac_x;
cameraFocusView.currentY = reac_y;
cameraFocusView.startAnimator();
}
}
@Override
public void onClick(View source) {
switch (source.getId()) {
// 单击录制button
case R.id.record:
startTimerOrStop(TIMER_FLAG_START);
try {
// 创建保存录制视频的视频文件
videoFile = CommonCode.getOutputMediaFile(MEDIA_TYPE_VIDEO);
// 创建MediaPlayer对象
mRecorder = new MediaRecorder();
mRecorder.reset();
mRecorder.setCamera(mCamera);
// 设置从麦克风採集声音(或来自录像机的声音AudioSource.CAMCORDER)
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 设置从摄像头採集图像
mRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
// 设置视频文件的输出格式
// 必须在设置声音编码格式、图像编码格式之前设置
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
// 设置声音编码的格式
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
// 设置图像编码的格式
mRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mRecorder.setOrientationHint(90);
mRecorder.setVideoSize(profile.videoFrameWidth, profile.videoFrameHeight);
// 每秒 30帧
mRecorder.setVideoFrameRate(30);
//设置编码比特率
mRecorder.setVideoEncodingBitRate(Constants.VideoEncodingBitRate.MID_2);
//设置文件大小 最大500M
mRecorder.setMaxFileSize(1024L * 1024 * 500);
//设置输出路径 文件存储位置
mRecorder.setOutputFile(videoFile.getAbsolutePath());
videoUrl = videoFile.getAbsolutePath();
// 指定使用SurfaceView来预览视频
mRecorder.setPreviewDisplay(sView.getHolder().getSurface()); //①
mRecorder.prepare();
// 開始录制
mRecorder.start();
System.out.println("---recording---");
// 让recordButton不可用。
record.setEnabled(false);
// 让stopButton可用。
stop.setEnabled(true);
isRecording = true;
Intent mResultData = new Intent();
mResultData.putExtra(Constants.Param.URL, videoUrl);
setResult(VideoUploadActivity.VIDEO_RECORD, mResultData );
} catch (Exception e) {
e.printStackTrace();
}
break;
// 单击停止button
case R.id.stop:
startTimerOrStop(TIMER_FLAG_STOP);
// 假设正在进行录制
if (isRecording) {
// 停止录制
mRecorder.stop();
// 释放资源
mRecorder.release();
mRecorder = null;
// 让recordButton可用。
record.setEnabled(true);
// 让stopButton不可用。
stop.setEnabled(false);
finish();
}
break;
}
}
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
mHolder = holder;
mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);
Camera.Parameters mParameter =mCamera.getParameters();
mParameter.setPreviewSize(profile.videoFrameWidth, profile.videoFrameHeight);
try {
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
mCamera.startPreview();
}
void startTimerOrStop(int flag){
switch (flag) {
case TIMER_FLAG_START: {
if (mRunnable == null) {
mRunnable = new MyRunnable();
mHandler.postDelayed(mRunnable, 0);
}
}
break;
case TIMER_FLAG_STOP: {
mHandler.removeCallbacks(mRunnable);
mRunnable = null;
}
break;
}
}
private class MyRunnable implements Runnable {
@Override
public void run() {
mTvTime5.setText(getTime());
mHandler.postDelayed(this, 1000);
}
}
private String getTime() {
mCurrentSecond++;
int hour = mCurrentSecond / 3600;
int minute = (mCurrentSecond % 3600) / 60;
int second = mCurrentSecond % 60;
if (second < 10) { //处理秒
seconds = "0" + second;
} else {
seconds = String.valueOf(second);
}
if (minute < 10) { //处理分
minutes = "0" + minute;
} else {
minutes = String.valueOf(minute);
}
if (hour < 10) { //处理小时
hours = "0" + hour;
} else {
hours = String.valueOf(hour);
}
//设置数据
return (String.format("%s:%s:%s", hours, minutes, seconds));
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
}
}
record_activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 显示视频预览的SurfaceView -->
<SurfaceView
android:id="@+id/sView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:visibility="visible" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:layout_marginEnd="150px"
android:orientation="vertical"
android:rotation="-90">
<TextView
android:id="@+id/mTvTime5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00:00"
android:textColor="#EC0404"
android:textSize="18sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerInParent="true"
android:orientation="vertical">
<ImageButton
android:id="@+id/stop"
android:layout_width="66dp"
android:layout_height="66dp"
android:scaleType="fitCenter"
android:src="@drawable/stop" />
<ImageButton
android:id="@+id/record"
android:layout_width="66dp"
android:layout_height="66dp"
android:rotation="-90"
android:scaleType="fitCenter"
android:src="@drawable/video" />
</LinearLayout>
</RelativeLayout>
3、部分重要参数
- 包括我们之前最头疼的分辨率也是可以设置了,这是文档里面支持的一部分参数。
// 设置屏幕分辨率
profile = CamcorderProfile.get(CamcorderProfile.QUALITY_1080P);
mHolder.setFixedSize( profile.videoFrameWidth, profile.videoFrameHeight);
- 设置编码比特率,不设置会使视频图像模糊(这个参数也是博主试出来的,md不加这个参数,文件大,画质还糊,可以换着试试那个最合适,博主用的是2,大小画质都比较合适)
//设置编码比特率,
mRecorder.setVideoEncodingBitRate(Constants.VideoEncodingBitRate.MID_2);
- 文件大小、帧数和路径
// 帧数设置 30帧
mRecorder.setVideoFrameRate(30);
//设置文件大小 最大500M
mRecorder.setMaxFileSize(1024L * 1024 * 500);
//设置输出路径 文件存储位置
mRecorder.setOutputFile(videoFile.getAbsolutePath());
4、回调上传视频到服务器代码(参考上一篇调用系统相机的文章,同一个项目里写的代码)
思路: 这三行对应着源activity的回调接口,视频存储到本地返回url到上一个activity
Intent mResultData = new Intent();
mResultData.putExtra(Constants.Param.URL, videoUrl);
setResult(VideoUploadActivity.VIDEO_RECORD,
最后的最后:
这里附上上一篇调用系统相机博客的路径吧:
- 传送门>>>:安卓调用系统相机录像并上传到后端服务器
- 以上便是自定义相机的所有代码,包括各种参数的设置以上已做了说明。
- 如有错误,还望指正!欢迎大家留言交流!
更多推荐
已为社区贡献6条内容
所有评论(0)