查看: 3814|回复: 1

[Android] 仿微信小视频录制控件

[复制链接]

该用户从未签到

发表于 2015-3-2 12:38:09 | 显示全部楼层 |阅读模式
本文为用 MediaRecorder 录制小视频的控件,可以设置视频录制的时间、空间大小、初始时是否打开摄像头等。 此控件为组合控件,继承自 LinearLayout ,为防止出错,需实现 android.media.MediaRecorder.OnErrorListener 接口。

                                            MovieRecorderView.java
  1. import java.io.File;
  2. import java.io.IOException;
  3. import java.util.Timer;
  4. import java.util.TimerTask;

  5. import android.content.Context;
  6. import android.content.res.TypedArray;
  7. import android.hardware.Camera;
  8. import android.hardware.Camera.Parameters;
  9. import android.media.MediaRecorder;
  10. import android.media.MediaRecorder.AudioEncoder;
  11. import android.media.MediaRecorder.AudioSource;
  12. import android.media.MediaRecorder.OnErrorListener;
  13. import android.media.MediaRecorder.OutputFormat;
  14. import android.media.MediaRecorder.VideoEncoder;
  15. import android.media.MediaRecorder.VideoSource;
  16. import android.util.AttributeSet;
  17. import android.view.LayoutInflater;
  18. import android.view.SurfaceHolder;
  19. import android.view.SurfaceHolder.Callback;
  20. import android.view.SurfaceView;
  21. import android.widget.LinearLayout;
  22. import android.widget.ProgressBar;

  23. import com.contron.dgyj.R;
  24. import com.contron.dgyj.common.Globals;
  25. import com.contron.dgyj.im.ImGlobal;
  26. import com.lidroid.xutils.util.LogUtils;

  27. /**
  28. * 视频播放控件
  29. *
  30. * @author liuyinjun
  31. *
  32. * @date 2015-2-5
  33. */
  34. public class MovieRecorderView extends LinearLayout implements OnErrorListener {

  35.     private SurfaceView mSurfaceView;
  36.     private SurfaceHolder mSurfaceHolder;
  37.     private ProgressBar mProgressBar;

  38.     private MediaRecorder mMediaRecorder;
  39.     private Camera mCamera;
  40.     private Timer mTimer;// 计时器
  41.     private OnRecordFinishListener mOnRecordFinishListener;// 录制完成回调接口

  42.     private int mWidth;// 视频分辨率宽度
  43.     private int mHeight;// 视频分辨率高度
  44.     private boolean isOpenCamera;// 是否一开始就打开摄像头
  45.     private int mRecordMaxTime;// 一次拍摄最长时间
  46.     private int mTimeCount;// 时间计数
  47.     private File mVecordFile = null;// 文件

  48.     public MovieRecorderView(Context context) {
  49.         this(context, null);
  50.     }

  51.     public MovieRecorderView(Context context, AttributeSet attrs) {
  52.         this(context, attrs, 0);
  53.     }

  54.     public MovieRecorderView(Context context, AttributeSet attrs, int defStyle) {
  55.         super(context, attrs, defStyle);

  56.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MovieRecorderView, defStyle, 0);
  57.         mWidth = a.getInteger(R.styleable.MovieRecorderView_width, 320);// 默认320
  58.         mHeight = a.getInteger(R.styleable.MovieRecorderView_height, 240);// 默认240

  59.         isOpenCamera = a.getBoolean(R.styleable.MovieRecorderView_is_open_camera, true);// 默认打开
  60.         mRecordMaxTime = a.getInteger(R.styleable.MovieRecorderView_record_max_time, 10);// 默认为10

  61.         LayoutInflater.from(context).inflate(R.layout.movie_recorder_view, this);
  62.         mSurfaceView = (SurfaceView) findViewById(R.id.surfaceview);
  63.         mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
  64.         mProgressBar.setMax(mRecordMaxTime);// 设置进度条最大量

  65.         mSurfaceHolder = mSurfaceView.getHolder();
  66.         mSurfaceHolder.addCallback(new CustomCallBack());
  67.         mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

  68.         a.recycle();
  69.     }

  70.     /**
  71.      *
  72.      * @author liuyinjun
  73.      *
  74.      * @date 2015-2-5
  75.      */
  76.     private class CustomCallBack implements Callback {

  77.         @Override
  78.         public void surfaceCreated(SurfaceHolder holder) {
  79.             if (!isOpenCamera)
  80.                 return;
  81.             try {
  82.                 initCamera();
  83.             } catch (IOException e) {
  84.                 // TODO Auto-generated catch block
  85.                 e.printStackTrace();
  86.             }
  87.         }

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

  90.         }

  91.         @Override
  92.         public void surfaceDestroyed(SurfaceHolder holder) {
  93.             if (!isOpenCamera)
  94.                 return;
  95.             freeCameraResource();
  96.         }

  97.     }

  98.     /**
  99.      * 初始化摄像头
  100.      *
  101.      * @author liuyinjun
  102.      * @date 2015-2-5
  103.      * @throws IOException
  104.      */
  105.     private void initCamera() throws IOException {
  106.         if (mCamera != null) {
  107.             freeCameraResource();
  108.         }
  109.         try {
  110.             mCamera = Camera.open();
  111.         } catch (Exception e) {
  112.             e.printStackTrace();
  113.             freeCameraResource();
  114.         }
  115.         if (mCamera == null)
  116.             return;

  117.         setCameraParams();
  118.         mCamera.setDisplayOrientation(90);
  119.         mCamera.setPreviewDisplay(mSurfaceHolder);
  120.         mCamera.startPreview();
  121.         mCamera.unlock();
  122.     }

  123.     /**
  124.      * 设置摄像头为竖屏
  125.      *
  126.      * @author liuyinjun
  127.      * @date 2015-2-5
  128.      */
  129.     private void setCameraParams() {
  130.         if (mCamera != null) {
  131.             Parameters params = mCamera.getParameters();
  132.             params.set("orientation", "portrait");
  133.             mCamera.setParameters(params);
  134.         }
  135.     }

  136.     /**
  137.      * 释放摄像头资源
  138.      *
  139.      * @author liuyinjun
  140.      * @date 2015-2-5
  141.      */
  142.     private void freeCameraResource() {
  143.         if (mCamera != null) {
  144.             mCamera.setPreviewCallback(null);
  145.             mCamera.stopPreview();
  146.             mCamera.lock();
  147.             mCamera.release();
  148.             mCamera = null;
  149.         }
  150.     }

  151.     private void createRecordDir() {
  152.         File sampleDir = new File(Environment.getExternalStorageDirectory() + File.separator + "im/video/");
  153.         if (!sampleDir.exists()) {
  154.             sampleDir.mkdirs();
  155.         }
  156.         File vecordDir = sampleDir;
  157.         // 创建文件
  158.         try {
  159.             mVecordFile = File.createTempFile("recording", ".mp4", vecordDir);//mp4格式
  160.             LogUtils.i(mVecordFile.getAbsolutePath());
  161.         } catch (IOException e) {
  162.         }
  163.     }

  164.     /**
  165.      * 初始化
  166.      *
  167.      * @author liuyinjun
  168.      * @date 2015-2-5
  169.      * @throws IOException
  170.      */
  171.     private void initRecord() throws IOException {
  172.         mMediaRecorder = new MediaRecorder();
  173.         mMediaRecorder.reset();
  174.         if (mCamera != null)
  175.             mMediaRecorder.setCamera(mCamera);
  176.         mMediaRecorder.setOnErrorListener(this);
  177.         mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());
  178.         mMediaRecorder.setVideoSource(VideoSource.CAMERA);// 视频源
  179.         mMediaRecorder.setAudioSource(AudioSource.MIC);// 音频源
  180.         mMediaRecorder.setOutputFormat(OutputFormat.MPEG_4);// 视频输出格式
  181.         mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);// 音频格式
  182.         mMediaRecorder.setVideoSize(mWidth, mHeight);// 设置分辨率:
  183.         // mMediaRecorder.setVideoFrameRate(16);// 这个我把它去掉了,感觉没什么用
  184.         mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 512);// 设置帧频率,然后就清晰了
  185.         mMediaRecorder.setOrientationHint(90);// 输出旋转90度,保持竖屏录制
  186.         mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);// 视频录制格式
  187.         // mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
  188.         mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());
  189.         mMediaRecorder.prepare();
  190.         try {
  191.             mMediaRecorder.start();
  192.         } catch (IllegalStateException e) {
  193.             e.printStackTrace();
  194.         } catch (RuntimeException e) {
  195.             e.printStackTrace();
  196.         } catch (Exception e) {
  197.             e.printStackTrace();
  198.         }
  199.     }

  200.     /**
  201.      * 开始录制视频
  202.      *
  203.      * @author liuyinjun
  204.      * @date 2015-2-5
  205.      * @param fileName
  206.      *            视频储存位置
  207.      * @param onRecordFinishListener
  208.      *            达到指定时间之后回调接口
  209.      */
  210.     public void record(final OnRecordFinishListener onRecordFinishListener) {
  211.         this.mOnRecordFinishListener = onRecordFinishListener;
  212.         createRecordDir();
  213.         try {
  214.             if (!isOpenCamera)// 如果未打开摄像头,则打开
  215.                 initCamera();
  216.             initRecord();
  217.             mTimeCount = 0;// 时间计数器重新赋值
  218.             mTimer = new Timer();
  219.             mTimer.schedule(new TimerTask() {

  220.                 @Override
  221.                 public void run() {
  222.                     // TODO Auto-generated method stub
  223.                     mTimeCount++;
  224.                     mProgressBar.setProgress(mTimeCount);// 设置进度条
  225.                     if (mTimeCount == mRecordMaxTime) {// 达到指定时间,停止拍摄
  226.                         stop();
  227.                         if (mOnRecordFinishListener != null)
  228.                             mOnRecordFinishListener.onRecordFinish();
  229.                     }
  230.                 }
  231.             }, 0, 1000);
  232.         } catch (IOException e) {
  233.             e.printStackTrace();
  234.         }
  235.     }

  236.     /**
  237.      * 停止拍摄
  238.      *
  239.      * @author liuyinjun
  240.      * @date 2015-2-5
  241.      */
  242.     public void stop() {
  243.         stopRecord();
  244.         releaseRecord();
  245.         freeCameraResource();
  246.     }

  247.     /**
  248.      * 停止录制
  249.      *
  250.      * @author liuyinjun
  251.      * @date 2015-2-5
  252.      */
  253.     public void stopRecord() {
  254.         mProgressBar.setProgress(0);
  255.         if (mTimer != null)
  256.             mTimer.cancel();
  257.         if (mMediaRecorder != null) {
  258.             // 设置后不会崩
  259.             mMediaRecorder.setOnErrorListener(null);
  260.             mMediaRecorder.setPreviewDisplay(null);
  261.             try {
  262.                 mMediaRecorder.stop();
  263.             } catch (IllegalStateException e) {
  264.                 e.printStackTrace();
  265.             } catch (RuntimeException e) {
  266.                 e.printStackTrace();
  267.             } catch (Exception e) {
  268.                 e.printStackTrace();
  269.             }
  270.         }
  271.     }

  272.     /**
  273.      * 释放资源
  274.      *
  275.      * @author liuyinjun
  276.      * @date 2015-2-5
  277.      */
  278.     private void releaseRecord() {
  279.         if (mMediaRecorder != null) {
  280.             mMediaRecorder.setOnErrorListener(null);
  281.             try {
  282.                 mMediaRecorder.release();
  283.             } catch (IllegalStateException e) {
  284.                 e.printStackTrace();
  285.             } catch (Exception e) {
  286.                 e.printStackTrace();
  287.             }
  288.         }
  289.         mMediaRecorder = null;
  290.     }

  291.     public int getTimeCount() {
  292.         return mTimeCount;
  293.     }

  294.     /**
  295.      * @return the mVecordFile
  296.      */
  297.     public File getmVecordFile() {
  298.         return mVecordFile;
  299.     }

  300.     /**
  301.      * 录制完成回调接口
  302.      *
  303.      * @author liuyinjun
  304.      *
  305.      * @date 2015-2-5
  306.      */
  307.     public interface OnRecordFinishListener {
  308.         public void onRecordFinish();
  309.     }

  310.     @Override
  311.     public void onError(MediaRecorder mr, int what, int extra) {
  312.         try {
  313.             if (mr != null)
  314.                 mr.reset();
  315.         } catch (IllegalStateException e) {
  316.             e.printStackTrace();
  317.         } catch (Exception e) {
  318.             e.printStackTrace();
  319.         }
  320.     }
  321. }
复制代码

movie_recorder_view.xml
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3.     xmlns:tools="http://schemas.android.com/tools"
  4.     android:layout_width="match_parent"
  5.     android:layout_height="match_parent"
  6.     android:background="@android:color/background_dark"
  7.     android:orientation="vertical">

  8.     <SurfaceView
  9.          android:id="@+id/surfaceview"
  10.          android:layout_width="fill_parent"
  11.          android:layout_height="0dp"
  12.          android:layout_weight="1"
  13.           />

  14.     <ProgressBar
  15.         android:id="@+id/progressBar"
  16.         style="?android:attr/progressBarStyleHorizontal"
  17.         android:layout_width="match_parent"
  18.         android:layout_height="2dp"
  19.         />
  20.      
  21. </LinearLayout>
复制代码



您需要登录后才可以回帖 登录 | 注册青鸟豆号

本版积分规则

Copyright 1999-2019 Beijing Aptech Beida Jade Bird Information Technology Co.,Ltd

北大青鸟IT教育 北京阿博泰克北大青鸟信息技术有限公司 版权所有

京ICP备11045574号-3 京公网安备11010802013845号

快速回复 返回顶部 返回列表