视频录制-MediaRecorder

视频录制:

首先视频的录制和音频的录制都是耗时的,需要在单个线程中去操作,在开启录制时,视频这块的录制,配置参数的前后,有严格的要求,颠倒会报错,报关于Camera,和MediaRecorder的错误,直接上代码,代码里写的很清楚了,对了这块用到了SurfaceView这个控件,不清楚的可以去查查资料。

SurfaceView的初始化工作:

    private void initSurfaceView() {
        mSurfaceHolder = mSurfaceView.getHolder();
        //设置屏幕分辨率
        mSurfaceHolder.setFixedSize(videoWidth, videoHeight);
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        mSurfaceHolder.addCallback(this);
        /**
         * 单独处理mSurfaceView的双击事件
         */
        mSurfaceView.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                mDetector.onTouchEvent(event);
                return true;
            }
        });

    }

实现SurfaceHolder.Callback这个回调,3个方法:

@Override
    public void surfaceCreated(SurfaceHolder holder) {
        mSurfaceHolder = holder;
        startPreView(holder);
    }

    /**
     * 开启预览
     *
     * @param holder
     */
    private void startPreView(SurfaceHolder holder) {
        if (mCamera == null) {
            mCamera = Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK);

        }
        if (mMediaRecorder == null) {
            mMediaRecorder = new MediaRecorder();
        }
        if (mCamera != null) {
            mCamera.setDisplayOrientation(90);
            try {
                mCamera.setPreviewDisplay(holder);
                Camera.Parameters parameters = mCamera.getParameters();
                //实现Camera自动对焦
                List<String> focusModes = parameters.getSupportedFocusModes();
                if (focusModes != null) {
                    for (String mode : focusModes) {
                        mode.contains("continuous-video");
                        parameters.setFocusMode("continuous-video");
                    }
                }
                mCamera.setParameters(parameters);
                mCamera.startPreview();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCamera != null) {
            //停止预览并释放摄像头资源
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
        if (mMediaRecorder != null) {
            mMediaRecorder.release();
            mMediaRecorder = null;
        }
    }

onTouch实现按下录制,松开保存功能,上移取消录制:

 @Override
    public boolean onTouch(View v, MotionEvent event) {
        boolean ret = false;
        int action = event.getAction();
        float ey = event.getY();
        float ex = event.getX();
        //只监听中间的按钮处
        int vW = v.getWidth();
        int left = LISTENER_START;
        int right = vW - LISTENER_START;
        float downY = 0;
        switch (v.getId()) {
            case R.id.main_press_control: {
                switch (action) {
                    case MotionEvent.ACTION_DOWN:
                        if (ex > left && ex < right) {
                            mProgressBar.setCancel(false);
                            //显示上滑取消
                            mTvTip.setVisibility(View.VISIBLE);
                            mTvTip.setText("↑ 上滑取消");
                            //记录按下的Y坐标
                            downY = ey;
                            // TODO: 2016/10/20 开始录制视频, 进度条开始走
                            mProgressBar.setVisibility(View.VISIBLE);
                            //开始录制
                            Toast.makeText(this, "开始录制", Toast.LENGTH_SHORT).show();
                            mRecorderService.submit(new Runnable() {
                                @Override
                                public void run() {
                                    startRecord();
                                }
                            });

                            //更新进度条
                            updateProgress();
                            ret = true;
                        }


                        break;
                    case MotionEvent.ACTION_UP:
                        if (ex > left && ex < right) {
                            mTvTip.setVisibility(View.INVISIBLE);
                            mProgressBar.setVisibility(View.INVISIBLE);
                            stopRecord();
                            ret = false;
                        }
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (ex > left && ex < right) {
                            float currentY = event.getY();
                            if (downY - currentY > 10) {
                                isCancel = true;
                                mProgressBar.setCancel(true);
                            }
                        }
                        break;
                }
                break;

            }

        }
        return ret;
    }

开启录制和Recorder的配置:
配置顺序很重要,顺序不对,有的手机可以,有的手机会报错

  /**
     * 开始录制
     */
    private void startRecord() {
        if (mMediaRecorder != null) {
            //没有外置存储, 直接停止录制
            if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                return;
            }
            try {
                if (mMediaRecorder == null) {
                    mMediaRecorder = new MediaRecorder();
                    /// mMediaRecorder.setOnErrorListener(this);
                } else {
                    mMediaRecorder.reset();
                }
                // Step 1: Unlock and set camera to MediaRecorder
                mCamera.unlock();
                mMediaRecorder.setCamera(mCamera);
                mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
                // Step 2: Set sources
                mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);//before setOutputFormat()
                mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//before setOutputFormat()
                //设置视频输出的格式和编码
                mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
                CamcorderProfile mProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_TIME_LAPSE_CIF);
                //after setVideoSource(),after setOutFormat()
                //mMediaRecorder.setVideoSize(mProfile.videoFrameWidth, mProfile.videoFrameHeight);
                mMediaRecorder.setVideoSize(videoWidth, videoHeight);
                mMediaRecorder.setAudioEncodingBitRate(44100);
                if (mProfile.videoBitRate > 2 * 1024 * 1024)
                    mMediaRecorder.setVideoEncodingBitRate(2 * 1024 * 1024);
                else
                    mMediaRecorder.setVideoEncodingBitRate(mProfile.videoBitRate);
                //after setVideoSource(),after setOutFormat();
                mMediaRecorder.setVideoFrameRate(mProfile.videoFrameRate);
                //after setOutputFormat()
                mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
                //after setOutputFormat()
                mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
                // Step 3: Set output file 新建文件保存录制视频
                recordFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath()
                        + "/RecordDemo/" + System.currentTimeMillis() + ".mp4");
                if (!recordFile.getParentFile().exists()) recordFile.getParentFile().mkdirs();
                recordFile.createNewFile();
                //设置输出路径
                mMediaRecorder.setOutputFile(recordFile.getAbsolutePath());
                //解决录制视频, 播放器横向问题
                mMediaRecorder.setOrientationHint(90);
                // Step 4: start and return
                mMediaRecorder.prepare();
                mMediaRecorder.start();
                //     mMediaObject.setStartTime(System.currentTimeMillis());
                isRecording = true;
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }

实现进度条的更新操作:

    /**
     * 跟新进度条,启用一个线程
     */
    private void updateProgress() {
        mUpdateProgressService.submit(new Runnable() {
            @Override
            public void run() {
                try {
                    mProgress = 0;
                    isRunning = true;
                    while (isRunning) {
                        mProgress++;
                        Thread.sleep(20);
                        //主线程更新进度条
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                mProgressBar.setProgress(mProgress);
                            }
                        });
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

松开结束录制:

 private void stopRecord() {
        //判断是否为录制结束, 或者为成功录制(时间过短)
        if (!isCancel) {
            if (mProgress < 50) {
                //时间太短不保存
                stopRecordUnSave();
                Toast.makeText(this, "时间太短", Toast.LENGTH_SHORT).show();
            } else {
                //停止录制
                stopRecordSave();
            }

        } else {
            //现在是取消状态,不保存
            stopRecordUnSave();
            isCancel = false;
            Toast.makeText(this, "取消录制", Toast.LENGTH_SHORT).show();
            mProgressBar.setCancel(false);
        }

    }

保存视频和不保存视频:

/**
     * 停止录制 并且保存
     */
    private void stopRecordSave() {
        if (isRecording) {
            isRunning = false;
            mMediaRecorder.stop();
            isRecording = false;
            Toast.makeText(MainActivity.this, "视频已经放至" + recordFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
        }
    }

    /**
     * 停止录制, 不保存
     */
    private void stopRecordUnSave() {
        if (isRecording) {
            isRunning = false;
            mMediaRecorder.stop();
            isRecording = false;
            if (recordFile.exists()) {
                //不保存直接删掉
                recordFile.delete();
            }
        }
    }

释放资源:

    private void releaseRecorder() {
        if (mMediaRecorder != null) {
            mMediaRecorder.release();
            mMediaRecorder.reset();
            ;
            mMediaRecorder = null;
        }
        if (mCamera != null) {
            mCamera.release();
            mCamera = null;
        }
    }

手势的监听,双击实现焦距变化,放大:

    class ZoomGestureListener extends GestureDetector.SimpleOnGestureListener {
        //双击手势事件
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            super.onDoubleTap(e);
            if (mMediaRecorder != null) {
                if (!isZoomIn) {
                    setZoom(20);
                    isZoomIn = true;
                } else {
                    setZoom(0);
                    isZoomIn = false;
                }
            }
            return true;
        }
    }

题外:还有一点点代码,和布局这里就不放上了,代码会上传,可以下载看看,试了几个手机,都没有出现问题,这里没有对录制的视频进行压缩,后面会试试看,就先写到这里了,有问题下面提出来就可以了 。

问题:下面这个参考代码有点问题,在小米手机上开启视频录制那里会报错,走catch这块报异常,录制的会发现是0kb,可以把我的这块startRecord这里代码复制过去,覆盖掉那一部分就可以解决了,我这块代码更简洁点,逻辑更清楚点,也可以下我的代码,效果会好一点……

参考:http://www.jianshu.com/p/6f84739ab85f

demo下载:https://github.com/amelons/RecordVideoSample

转载标明:http://blog.csdn.net/zxyudia/article/details/69265263

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值