美文网首页
视频录制

视频录制

作者: 43d60efa37c7 | 来源:发表于2017-03-02 10:39 被阅读29次

    视频录制控件
    布局文件就是一个surfaceView

    /**
     * 视频录制控件
     */
    public class MovieRecorderView extends LinearLayout implements OnErrorListener {
    
        private SurfaceView mSurfaceView;
        private SurfaceHolder mSurfaceHolder;
    
        
         //屏幕方向
         //手机顶部朝上
        public static final int UP = 0;
        //手机底部朝上
        public static final int DOWN = 1;
        //手机左边朝上
        public static final int LEFT = 2;
        //手机右边朝上
        public static final int RIGHT = 3;
        
        private int orientation = UP;
    
        private MediaRecorder mMediaRecorder;
        private Camera mCamera;
        private Timer mTimer;// 计时器
        private OnRecordFinishListener mOnRecordFinishListener;// 录制完成回调接口
    
        private int mWidth;// 视频分辨率宽度
        private int mHeight;// 视频分辨率高度
        private boolean isOpenCamera;// 是否一开始就打开摄像头
        private int mRecordMaxTime;// 一次拍摄最长时间
        private int mTimeCount;// 时间计数
        private File mRecordFile = null;// 文件
        private final int FRONT_CAMERA = 0; //前置摄像头
        private final int BACK_CAMERA = 1;  //后置摄像头
        private int cameraType = BACK_CAMERA;
    
    
        public MovieRecorderView(Context context) {
            this(context, null);
        }
    
        public MovieRecorderView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public MovieRecorderView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            // 初始化各项组件
            TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MovieRecorderView, defStyle, 0);
            mWidth = a.getInteger(R.styleable.MovieRecorderView_video_width, 320);// 默认320
            mHeight = a.getInteger(R.styleable.MovieRecorderView_video_height, 240);// 默认240
    
            isOpenCamera = a.getBoolean(R.styleable.MovieRecorderView_is_open_camera, true);// 默认打开
            mRecordMaxTime = a.getInteger(R.styleable.MovieRecorderView_record_max_time, 10);// 默认为10
    
            LayoutInflater.from(context).inflate(R.layout.movie_recorder_view, this);
            mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
    
    
            
            mSurfaceHolder = mSurfaceView.getHolder();
            mSurfaceHolder.addCallback(new CustomCallBack());
            mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    
            a.recycle();
        }
    
        /**
         *
         */
        private class CustomCallBack implements Callback {
    
            @Override
            public void surfaceCreated(SurfaceHolder holder) {
                if (!isOpenCamera)
                    return;
                try {
                    initCamera();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
    
            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
    
            }
    
            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {
                if (!isOpenCamera)
                    return;
                freeCameraResource();
            }
    
        }
    
        /**
         * 初始化摄像头
         *
         * @date 2015-2-5
         * @throws IOException
         */
        @SuppressWarnings("deprecation")
        public void initCamera() throws IOException {
            if (mCamera != null) {
                freeCameraResource();
            }
            
            int cameraCount = 0;
            CameraInfo cameraInfo = new CameraInfo();
            cameraCount = Camera.getNumberOfCameras();// 得到摄像头的个数
            for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
                Camera.getCameraInfo(camIdx, cameraInfo);
                if (cameraType == FRONT_CAMERA) {
                    //切换成前置
                    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                        //释放资源
                        freeCameraResource();
                        try {
                            mCamera = Camera.open(camIdx);
                             if (mCamera == null)
                                    return;
                            setCameraParams();
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                            freeCameraResource();
                        }
                    }
                }else{
                    //切换成后置
                    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                        //释放资源
                        freeCameraResource();
                        try {
                            mCamera = Camera.open(camIdx);
                             if (mCamera == null)
                                    return;
                            setCameraParams();
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                            freeCameraResource();
                        }
                    }
                }
            }
    //        try {
    //            mCamera = Camera.open();
    //        } catch (Exception e) {
    //            e.printStackTrace();
    //            freeCameraResource();
    //        }
    //        if (mCamera == null)
    //            return;
    //
    //        setCameraParams();
            
        }
        
        /**
         * 设置摄像头属性
         */
        @SuppressWarnings("deprecation")
        public void setCameraParams() {
            try {
                if (mCamera != null) {
                    Parameters params = mCamera.getParameters();
    //              params.set("orientation", "portrait");
                    setPreviewSize(params);
                    mCamera.setParameters(params);
                }
                //设置预览竖屏
                mCamera.setDisplayOrientation(90);
                mCamera.setPreviewDisplay(mSurfaceHolder);
                mCamera.startPreview();
                mCamera.unlock();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 切换前后摄像头
         */
        @SuppressWarnings("deprecation")
        public void toggleCamera(){
            
            int cameraCount = 0;
            CameraInfo cameraInfo = new CameraInfo();
            cameraCount = Camera.getNumberOfCameras();// 得到摄像头的个数
    
            
            for (int camIdx = 0; camIdx < cameraCount; camIdx++) {
                Camera.getCameraInfo(camIdx, cameraInfo);
                if (cameraType == BACK_CAMERA) {
                    //切换成前置
                    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
                        //释放资源
                        freeCameraResource();
                        try {
                            mCamera = Camera.open(camIdx);
                            cameraType = FRONT_CAMERA;
                             if (mCamera == null)
                                    return;
                            setCameraParams();
                            return;
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                            freeCameraResource();
                        }
                    }
                }else{
                    //切换成后置
                    if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
                        //释放资源
                        freeCameraResource();
                        try {
                            mCamera = Camera.open(camIdx);
                            cameraType = BACK_CAMERA;
                             if (mCamera == null)
                                    return;
                            setCameraParams();
                            return;
                        } catch (RuntimeException e) {
                            e.printStackTrace();
                            freeCameraResource();
                        }
                    }
                }
            }
        }
    
    
        /**
         * 释放摄像头资源
         *
         */
        private void freeCameraResource() {
            if (mCamera != null) {
                mCamera.setPreviewCallback(null);
                mCamera.stopPreview();
                mCamera.lock();
                mCamera.release();
                mCamera = null;
            }
        }
    
        private void createRecordDir() {
            File sampleDir = new File(Environment.getExternalStorageDirectory() + File.separator + "im/video/");
            if (!sampleDir.exists()) {
                sampleDir.mkdirs();
            }
            File vecordDir = sampleDir;
            // 创建文件
            try {
                mRecordFile = File.createTempFile("recording", ".mp4", vecordDir); //mp4格式
                Log.i("TAG",mRecordFile.getAbsolutePath());
            } catch (IOException e) {
            }
        }
    
        /**
         * 初始化
         *
         * @throws IOException
         */
        private void initRecord() throws IOException {
            mMediaRecorder = new MediaRecorder();
            mMediaRecorder.reset();
            if (mCamera != null)
                mMediaRecorder.setCamera(mCamera);
            mMediaRecorder.setOnErrorListener(this);
            mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
            mMediaRecorder.setVideoSource(VideoSource.CAMERA);// 视频源
            mMediaRecorder.setAudioSource(AudioSource.MIC);// 音频源
            mMediaRecorder.setOutputFormat(OutputFormat.MPEG_4);// 视频输出格式
            mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);// 音频格式
    //        mMediaRecorder.setVideoFrameRate(16);// 去掉这一行,有些手机会mMediaRecorder.start()失败
            mMediaRecorder.setVideoEncodingBitRate(1 * 1280 * 720);// 设置帧频率,然后就清晰了
            
            //输出角度
            switch (orientation) {
            case UP:
                mMediaRecorder.setOrientationHint(90);// 输出旋转90度,顶部朝上录制
                break;
            case DOWN:
                mMediaRecorder.setOrientationHint(270);
                break;
            case LEFT:
                mMediaRecorder.setOrientationHint(0);
                break;
            case RIGHT:
                mMediaRecorder.setOrientationHint(180);
                break;
            }
            
            mMediaRecorder.setVideoSize(mWidth, mHeight);// 设置分辨率:
            mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);// 视频录制格式
            
            // mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
            
            mMediaRecorder.setOutputFile(mRecordFile.getAbsolutePath());
            mMediaRecorder.prepare();
            try {
                mMediaRecorder.start();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (RuntimeException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 开始录制视频
         *
         * @param onRecordFinishListener
         *            达到指定时间之后回调接口
         */
        public void record(final OnRecordFinishListener onRecordFinishListener) {
            this.mOnRecordFinishListener = onRecordFinishListener;
            createRecordDir();
            try {
                if (!isOpenCamera)// 如果未打开摄像头,则打开
                    initCamera();
                initRecord();
                mTimeCount = 0;// 时间计数器重新赋值
                mTimer = new Timer();
                mTimer.schedule(new TimerTask() {
    
                    @Override
                    public void run() {
                        mTimeCount++;
    //                    mProgressBar.setProgress(mTimeCount);
                        // 设置进度
                        if (mOnRecordFinishListener != null)
                            mOnRecordFinishListener.onRecord(mTimeCount);
                        if (mTimeCount == mRecordMaxTime) {// 达到指定时间,停止拍摄
                            stop();
                            if (mOnRecordFinishListener != null)
                                mOnRecordFinishListener.onRecordFinish();
                        }
                    }
                }, 0, 1000);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 停止拍摄
         *
         * @author liuyinjun
         * @date 2015-2-5
         */
        public void stop() {
            stopRecord();
            releaseRecord();
            freeCameraResource();
        }
    
        /**
         * 停止录制
         *
         * @author liuyinjun
         * @date 2015-2-5
         */
        public void stopRecord() {
    //      mProgressBar.setProgress(0);
            if (mTimer != null)
                mTimer.cancel();
            if (mMediaRecorder != null) {
                // 设置后不会崩
                mMediaRecorder.setOnErrorListener(null);
                try {
                    mMediaRecorder.stop();
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                } catch (RuntimeException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                mMediaRecorder.setPreviewDisplay(null);
            }
        }
    
        /**
         * 释放资源
         *
         * @author liuyinjun
         * @date 2015-2-5
         */
        private void releaseRecord() {
            if (mMediaRecorder != null) {
                mMediaRecorder.setOnErrorListener(null);
                try {
                    mMediaRecorder.release();
                } catch (IllegalStateException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            mMediaRecorder = null;
        }
    
        public int getTimeCount() {
            return mTimeCount;
        }
    
        /**
         * @return the mVecordFile
         */
        public File getmRecordFile() {
            return mRecordFile;
        }
    
        /**
         * 录制完成回调接口
         *
         * @author liuyinjun
         *
         * @date 2015-2-5
         */
        public interface OnRecordFinishListener {
            public void onRecordFinish();
            void onRecord(int progress);
        }
        
        /**
         * 设置最大录制时间
         * @param max
         */
        public void setMaxTime(int max){
            mRecordMaxTime = max; 
        }
        
    
        @Override
        public void onError(MediaRecorder mr, int what, int extra) {
            try {
                if (mr != null)
                    mr.reset();
            } catch (IllegalStateException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        
        /**
         * 根据手机支持的视频分辨率,设置预览尺寸
         *
         * @param params
         */
        @SuppressWarnings("deprecation")
        private void setPreviewSize(Parameters params) {
            if (mCamera == null) {
                return;
            }
            //获取手机支持的分辨率集合,并以宽度为基准降序排序
            List<Camera.Size> previewSizes = params.getSupportedPreviewSizes();
            Collections.sort(previewSizes, new Comparator<Camera.Size>() {
                @Override
                public int compare(Camera.Size lhs, Camera.Size rhs) {
                    if (lhs.width > rhs.width) {
                        return -1;
                    } else if (lhs.width == rhs.width) {
                        return 0;
                    } else {
                        return 1;
                    }
                }
            });
    
            float tmp = 0f;
            float minDiff = 100f;
            float ratio = 3.0f / 4.0f;// 高宽比率3:4,且最接近屏幕宽度的分辨率,可以自己选择合适的想要的分辨率
            Camera.Size best = null;
            for (Camera.Size s : previewSizes) {
                tmp = Math.abs(((float) s.height / (float) s.width) - ratio);
    //            LogUtil.e(LOG_TAG,"tmp:" + tmp);
    //            if (tmp == 0 && getWindowWidth(getContext()) <= s.width) {
    //              break;
    //          }
                if (tmp < minDiff) {
                    minDiff = tmp;
                    best = s;
                    Log.e("屏幕", "setPreviewSize: width:" + s.width + "...height:" + s.height);
                }
            }
    //        List<int[]> range = params.getSupportedPreviewFpsRange();
    //        int[] fps = range.get(0);
    //        LogUtil.e(LOG_TAG,"min="+fps[0]+",max="+fps[1]);
    //        params.setPreviewFpsRange(3,7);
    
            params.setPreviewSize(best.width, best.height);//预览比率
    
    //        params.setPictureSize(480, 720);//拍照保存比率
    
    //        Log.e(LOG_TAG, "setPreviewSize BestSize: width:" + best.width + "...height:" + best.height);
    
            // 大部分手机支持的预览尺寸和录制尺寸是一样的,也有特例,有些手机获取不到,那就把设置录制尺寸放到设置预览的方法里面
            if (params.getSupportedVideoSizes() == null || params.getSupportedVideoSizes().size() == 0) {
                mWidth = best.width;
                mHeight = best.height;
            } else {
                setVideoSize(params);
            }
        }
    
        /**
         * 根据手机支持的视频分辨率,设置录制尺寸
         *
         * @param params
         */
        @SuppressWarnings("deprecation")
        private void setVideoSize(Parameters params) {
            if (mCamera == null) {
                return;
            }
            //获取手机支持的分辨率集合,并以宽度为基准降序排序
            List<Camera.Size> previewSizes = params.getSupportedVideoSizes();
            Collections.sort(previewSizes, new Comparator<Camera.Size>() {
                @Override
                public int compare(Camera.Size lhs, Camera.Size rhs) {
                    if (lhs.width > rhs.width) {
                        return -1;
                    } else if (lhs.width == rhs.width) {
                        return 0;
                    } else {
                        return 1;
                    }
                }
            });
    
            float tmp = 0f;
            float minDiff = 100f;
            float ratio = 720.0f / 1080.0f;//高宽比率3:4,且最接近屏幕宽度的分辨率
            Camera.Size best = null;
            for (Camera.Size s : previewSizes) {
                tmp = Math.abs(((float) s.height / (float) s.width) - ratio);
    //            if (tmp == 0 && getWindowWidth(getContext()) <= s.width) {
    //              break;
    //          }
                if (tmp < minDiff) {
                    minDiff = tmp;
                    best = s;
                    Log.e("摄像头", "setVideoSize: width:" + s.width + "...height:" + s.height);
                }
            }
    //        Log.e(LOG_TAG, "setVideoSize BestSize: width:" + best.width + "...height:" + best.height);
            //设置录制尺寸
            mWidth = best.width;
            mHeight = best.height;
        }
         
        public void setOrientation(int orientation){
            this.orientation = orientation;
        }
    

    attrs文件

    <declare-styleable name="MovieRecorderView">
            <!-- 开始是否打开摄像头 -->
            <attr name="is_open_camera" format="boolean" />
            <!-- 一次拍摄最长时间 -->
            <attr name="record_max_time" format="integer"/>
            <!-- 视频分辨率宽度 -->
            <attr name="video_width" format="integer"/>
            <!-- 视频分辨率高度 -->
            <attr name="video_height" format="integer"/>
        </declare-styleable>
    

    相关文章

      网友评论

          本文标题:视频录制

          本文链接:https://www.haomeiwen.com/subject/kxehgttx.html