写在前面

  • 上篇文章讲了调用该系统相机,这里就来讲一下自定义相机吧。上一篇也讲了调用系统相机主要就是界面美观,功能完善,当然对于一个优秀的码畜,这些都是可以通过技术手段实现的。

自定义相机优点: 那就是参数可自定义,可实现各种分辨率效果。

一、录像上传的思路

  • 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, 

最后的最后:

这里附上上一篇调用系统相机博客的路径吧:

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐