Android视频录制

1.自定义录制视频的控件(MovieRecordView)

public class MovieRecorderView extends LinearLayout implements OnErrorListener {

    private SurfaceView mSurfaceView;
    private SurfaceHolder mSurfaceHolder;
    private ProgressBar mProgressBar;

    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;// 文件

    public MovieRecorderView(Context context) {
        this(context, null);
    }

    public MovieRecorderView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @SuppressLint("NewApi")
	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);
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
        mProgressBar.setMax(mRecordMaxTime);// 设置进度条最大量

        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();
        }

    }

    /**
     * 初始化摄像头
     */
    @SuppressLint("NewApi")
	public void initCamera() throws IOException {
        if (mCamera != null) {
            freeCameraResource();
        }
        try {
            mCamera = Camera.open();
        } catch (Exception e) {
            e.printStackTrace();
            freeCameraResource();
        }
        if (mCamera == null)
            return;
        mCamera.setDisplayOrientation(90);
        mCamera.setPreviewDisplay(mSurfaceHolder);
        mCamera.startPreview();
        mCamera.unlock();
    }

   

    /**
     * 释放摄像头资源
     */
    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) {
        }
    }

    /**
     * 初始化
     */
    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.AAC);// 音频格式
        mMediaRecorder.setVideoSize(mWidth, mHeight);// 设置分辨率:
    
//      mMediaRecorder.setVideoFrameRate(16);// 这个我把它去掉了,感觉没什么用
        mMediaRecorder.setVideoEncodingBitRate(1 * 1280 * 720);// 设置帧频率,然后就清晰了       
        mMediaRecorder.setOrientationHint(90);// 输出旋转90度,保持竖屏录制        
        if(android.os.Build.MODEL.contains("ALE-UL00")||android.os.Build.MODEL.contains("OPPO")|| Build.MODEL.contains("MT7-TL10")){
        	//华为p7型号手机,OPPO手机
        	mMediaRecorder.setVideoEncoder(VideoEncoder.DEFAULT);// 视频录制格式
        }else{
        	
        	mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);// 视频录制格式
        }
        mMediaRecorder.setOutputFile(mRecordFile.getAbsolutePath());
        mMediaRecorder.prepare();
        try {   
            mMediaRecorder.start();
     
        } catch (IllegalStateException e) {
            e.printStackTrace();
        } catch (RuntimeException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 开始录制视频 达到指定时间之后回调接口
     */
    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() {
                    // TODO Auto-generated method stub
                    mTimeCount++;                                        
                    mProgressBar.setProgress(mTimeCount);// 设置进度条
                    if (mTimeCount == mRecordMaxTime) {// 达到指定时间,停止拍摄
                        stop();
                        if (mOnRecordFinishListener != null)
                            mOnRecordFinishListener.onRecordFinish();
                    }
                }
            }, 0, 1000);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 停止拍摄
     */
    public void stop() {
        stopRecord();
        releaseRecord();
        freeCameraResource();
    }

    /**
     * 停止录制
     */
    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);
        }
    }

    /**
     * 释放资源   
     */
    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;
    }

    /**
     * 录制完成回调接口  
     */
    public interface OnRecordFinishListener {
        public void onRecordFinish();
    }

    @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();
        }
    }

}

关于录制时显示的进度条,如果想要实现微信的那种效果(从两边缩进),有两个方法

第一种,用还是用progressBar,设置对应的style即可。详情可以参见文章 仿微信小视屏拍摄的进度条/自定义的progressBar的样式。

第二种,可以自定一个View,根据具体的条件判断,重新绘制。详情参见文章  Android仿微信录制小视频的进度条

2.录制界面

在录制界面的布局中使用这个自定义view,写一个按钮点击开始录制调用方法

   mRecorderView.record(new MovieRecorderView.OnRecordFinishListener() {
                            @Override
                            public void onRecordFinish() { //录制完成(结束)回调
                                handler.sendEmptyMessage(1);
                            }
                        });
写一个停止录制的按钮,这边的话是有删除文件的,如果不需要删除自行做判断即可

   if (mRecorderView.getmRecordFile() != null)
                                mRecorderView.getmRecordFile().delete();  handler.sendEmptyMessage(1);
                            mRecorderView.stop();//停止录制
                        }

3.回调到展示界面

这边的就是根据录制界面setResult()回调本地视频的地址。拿到地址以后就可以,取视频的第一帧图片,以及点击播放视频。

如果想要上传视频,则可以将视频文件转化为二进制上传到服务器,服务器返回网络视频地址。

4.补充

如果想要实现预览界面的话(跟微信小视频拍摄一样),可以在录制完成的时候,handler的回调方法中跳转预览界面(预览界面跟播放界面差不多,关于视频播放界面的代码,百度一下)

遇到的问题:

(1)根据视频的网络地址播放的时候,会出现一种其实界面是跳转了,但是设置videoView的背景颜色不起作用,依然是透明的。这个时候可以调用videoview的

setZOrderOnTop()方法,将videoview移动到上层。还有一点需要注意的是,在加载网络视频的时候,如果视频还未加载出来,就点击返回的话,要在播放活动界面的

onPause(),onResume(),onDestory()生命周期调用videoView对应的pause(),resume(),stopPlayback()方法。

(2)设置视频全屏播放

可以自定义一个view继承VideoView,重写onMeasure()方法

 @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        int width = getDefaultSize(0, widthMeasureSpec);
        int height = getDefaultSize(0, heightMeasureSpec);

        setMeasuredDimension(width, height);
    }
(3)设置隐藏videoView的控制播放按钮,以及视频重复播放

 MediaController controller = new MediaController(this);
        controller.setVisibility(View.GONE);
        mVideoView.setMediaController(controller);

  mVideoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mp) {
                //设置重复播放
                mVideoView.setVideoURI(Uri.parse(videoPath));
                mVideoView.start();
            }
        });


(4)如果有设置预览界面的话,记得在预览界面返回(预览界面我们自己写的两个按钮,一个确认,一个返回)

在录制界面返回的回调里面要重新初始化camera,即调用movieRecordView的initCamera()方法。至于为什么的话,是因为在录制界面到预览界面的时候调用了stop()方法,导致movieRecordView中camera设置的值被清空了。所以如果不调用初始化,会导致从预览界面返回的时候,录制界面是暂停在上次录制的最后一刻画面,再次点击录制的话,屏幕会水平录制,不过输出的视频还是竖直的。如果你们有更好的方法,自己可以根据需要修改movieRecordView的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值