热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

java制作仿微信录制小视频控件

这篇文章主要介绍了java制作仿微信录制小视频控件的代码,录制小视频非常方便,有需要的小伙伴可以参考下。

本文为用 MediaRecorder 录制小视频的控件,可以设置视频录制的时间、空间大小、初始时是否打开摄像头等。 此控件为组合控件,继承自 LinearLayout ,为防止出错,需实现 android.media.MediaRecorder.OnErrorListener 接口。

小视频录制界面

MovieRecorderView.java

import java.io.File;
import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
 
import android.content.Context;
import android.content.res.TypedArray;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.media.MediaRecorder;
import android.media.MediaRecorder.AudioEncoder;
import android.media.MediaRecorder.AudioSource;
import android.media.MediaRecorder.OnErrorListener;
import android.media.MediaRecorder.OutputFormat;
import android.media.MediaRecorder.VideoEncoder;
import android.media.MediaRecorder.VideoSource;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
 
import com.contron.dgyj.R;
import com.contron.dgyj.common.Globals;
import com.contron.dgyj.im.ImGlobal;
import com.lidroid.xutils.util.LogUtils;
 
/**
 * 视频播放控件
 * 
 * @author liuyinjun
 * 
 * @date 2015-2-5
 */
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 mVecordFile = null;// 文件
 
  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_width, 320);// 默认320
    mHeight = a.getInteger(R.styleable.MovieRecorderView_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();
  }
 
  /**
   * 
   * @author liuyinjun
   * 
   * @date 2015-2-5
   */
  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();
    }
 
  }
 
  /**
   * 初始化摄像头
   * 
   * @author liuyinjun
   * @date 2015-2-5
   * @throws IOException
   */
  private void initCamera() throws IOException {
    if (mCamera != null) {
      freeCameraResource();
    }
    try {
      mCamera = Camera.open();
    } catch (Exception e) {
      e.printStackTrace();
      freeCameraResource();
    }
    if (mCamera == null)
      return;
 
    setCameraParams();
    mCamera.setDisplayOrientation(90);
    mCamera.setPreviewDisplay(mSurfaceHolder);
    mCamera.startPreview();
    mCamera.unlock();
  }
 
  /**
   * 设置摄像头为竖屏
   * 
   * @author liuyinjun
   * @date 2015-2-5
   */
  private void setCameraParams() {
    if (mCamera != null) {
      Parameters params = mCamera.getParameters();
      params.set("orientation", "portrait");
      mCamera.setParameters(params);
    }
  }
 
  /**
   * 释放摄像头资源
   * 
   * @author liuyinjun
   * @date 2015-2-5
   */
  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 {
      mVecordFile = File.createTempFile("recording", ".mp4", vecordDir);//mp4格式
      LogUtils.i(mVecordFile.getAbsolutePath());
    } catch (IOException e) {
    }
  }
 
  /**
   * 初始化
   * 
   * @author liuyinjun
   * @date 2015-2-5
   * @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.setVideoSize(mWidth, mHeight);// 设置分辨率:
    // mMediaRecorder.setVideoFrameRate(16);// 这个我把它去掉了,感觉没什么用
    mMediaRecorder.setVideoEncodingBitRate(1 * 1024 * 512);// 设置帧频率,然后就清晰了
    mMediaRecorder.setOrientationHint(90);// 输出旋转90度,保持竖屏录制
    mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);// 视频录制格式
    // mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);
    mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());
    mMediaRecorder.prepare();
    try {
      mMediaRecorder.start();
    } catch (IllegalStateException e) {
      e.printStackTrace();
    } catch (RuntimeException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
 
  /**
   * 开始录制视频
   * 
   * @author liuyinjun
   * @date 2015-2-5
   * @param fileName
   *      视频储存位置
   * @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() {
          // 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();
    }
  }
 
  /**
   * 停止拍摄
   * 
   * @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);
      mMediaRecorder.setPreviewDisplay(null);
      try {
        mMediaRecorder.stop();
      } catch (IllegalStateException e) {
        e.printStackTrace();
      } catch (RuntimeException e) {
        e.printStackTrace();
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
 
  /**
   * 释放资源
   * 
   * @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 getmVecordFile() {
    return mVecordFile;
  }
 
  /**
   * 录制完成回调接口
   *
   * @author liuyinjun
   * 
   * @date 2015-2-5
   */
  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();
    }
  }
}

movie_recorder_view.xml

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 
  
 
  
   

attrs.xml

<&#63;xml version="1.0" encoding="utf-8"&#63;>

 
  
 
  
   

以上所述就是本文的全部内容了,希望大家能够喜欢。


推荐阅读
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 深入理解 Oracle 存储函数:计算员工年收入
    本文介绍如何使用 Oracle 存储函数查询特定员工的年收入。我们将详细解释存储函数的创建过程,并提供完整的代码示例。 ... [详细]
  • 本文总结了2018年的关键成就,包括职业变动、购车、考取驾照等重要事件,并分享了读书、工作、家庭和朋友方面的感悟。同时,展望2019年,制定了健康、软实力提升和技术学习的具体目标。 ... [详细]
  • 在计算机技术的学习道路上,51CTO学院以其专业性和专注度给我留下了深刻印象。从2012年接触计算机到2014年开始系统学习网络技术和安全领域,51CTO学院始终是我信赖的学习平台。 ... [详细]
  • CSS 布局:液态三栏混合宽度布局
    本文介绍了如何使用 CSS 实现液态的三栏布局,其中各栏具有不同的宽度设置。通过调整容器和内容区域的属性,可以实现灵活且响应式的网页设计。 ... [详细]
  • Linux 系统启动故障排除指南:MBR 和 GRUB 问题
    本文详细介绍了 Linux 系统启动过程中常见的 MBR 扇区和 GRUB 引导程序故障及其解决方案,涵盖从备份、模拟故障到恢复的具体步骤。 ... [详细]
  • 本文介绍了如何使用jQuery根据元素的类型(如复选框)和标签名(如段落)来获取DOM对象。这有助于更高效地操作网页中的特定元素。 ... [详细]
  • 在Linux系统中配置并启动ActiveMQ
    本文详细介绍了如何在Linux环境中安装和配置ActiveMQ,包括端口开放及防火墙设置。通过本文,您可以掌握完整的ActiveMQ部署流程,确保其在网络环境中正常运行。 ... [详细]
  • 本文介绍如何通过Windows批处理脚本定期检查并重启Java应用程序,确保其持续稳定运行。脚本每30分钟检查一次,并在需要时重启Java程序。同时,它会将任务结果发送到Redis。 ... [详细]
  • Android LED 数字字体的应用与实现
    本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ... [详细]
  • 本章将深入探讨移动 UI 设计的核心原则,帮助开发者构建简洁、高效且用户友好的界面。通过学习设计规则和用户体验优化技巧,您将能够创建出既美观又实用的移动应用。 ... [详细]
  • 本文介绍如何通过SQL查询从JDE(JD Edwards)系统中提取所有字典数据,涵盖关键表的关联和字段选择。具体包括F0004和F0005系列表的数据提取方法。 ... [详细]
  • RecyclerView初步学习(一)
    RecyclerView初步学习(一)ReCyclerView提供了一种插件式的编程模式,除了提供ViewHolder缓存模式,还可以自定义动画,分割符,布局样式,相比于传统的ListVi ... [详细]
  • 本文详细介绍了如何通过命令行启动MySQL服务,包括打开命令提示符窗口、进入MySQL的bin目录、输入正确的连接命令以及注意事项。文中还提供了更多相关命令的资源链接。 ... [详细]
  • 本文介绍如何使用 NSTimer 实现倒计时功能,详细讲解了初始化方法、参数配置以及具体实现步骤。通过示例代码展示如何创建和管理定时器,确保在指定时间间隔内执行特定任务。 ... [详细]
author-avatar
大魔王
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有