前言

  MediaRecorder是Android SDK提供用于录制音视频,关于音频的录制在我另一篇博客里已经介绍.传送门: https://www.cnblogs.com/guanxinjing/p/10976026.html,而这篇博客将介绍MediaRecorder视频录制的入门和一些MediaRecorder视频录制的深坑.为什么只介绍简单的录制视频的入门操作,因为MediaRecorder在实际开发的时候肯定还需要配合Camera来使用.而Camera这个大坑又有Camera1和Camera2,所以我们需要分篇幅来介绍Camera1和Camera2与MediaRecorder的使用方式.

  虽然是入门但是还是需要分2个录制操作来说明

  •   MediaRecorder简单的录制视频(不设置Camera)
  •   MediaRecorder设置Camera的录制视频(这里指的是Camera1)

  虽然这2个在简单录制视频的时候操作没啥区别,但是设置Camera录制有一个坑,秉承着写博客就是为了记录深坑避免下次掉坑的精神,所以我要抓出来单独说明.

MediaRecorder简单的录制视频

实现流程

  1. 开启硬件加速(因为个人使用TextureView)
  2. 获取权限
  3. 初始化MediaRecorder
  4. 配置MediaRecorder
  5. 开始录制视频
  6. 停止录制视频
  7. 暂停录制与恢复录制
  8. 销毁释放

开启硬件加速

因为TextureView来预览图像使用效果会比SurfaceView与SurfaceTexture,在预览的时候更不会那么卡顿.但是使用它需要开启硬件加速,但是现在的手机设备上基本上都支持硬件加速,所以主流是使用TextureView.下面就是开启硬件加速的方式,在AndroidManifest.xml里给需要硬件加速的activity添加android:hardwareAccelerated="true" 属性

<activity android:name=".MediaRecorderVideoActivity"
android:hardwareAccelerated="true"></activity>

获取权限

    <!--音频录制权限 -->
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<!--相机权限-->
<uses-permission android:name="android.permission.CAMERA" />
<!--读取和写入存储权限-->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

如果是Android5.0版本这4个权限是需要动态授权的.

初始化MediaRecorder

private void initMediaRecorder(){
mMediaRecorder = new MediaRecorder();
}

很简单就是new一个MediaRecorder

配置MediaRecorder

 private void configMediaRecorder(){
File videoFile = new File(getExternalCacheDir(),"video.mp4");
Log.e(TAG, "文件路径="+videoFile.getAbsolutePath());
if (videoFile.exists()){
videoFile.delete();
}
     mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);//设置音频输入源 也可以使用 MediaRecorder.AudioSource.MIC
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);//设置视频输入源
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);//音频输出格式
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);//设置音频的编码格式
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);//设置图像编码格式 // mMediaRecorder.setVideoFrameRate(30);//要录制的视频帧率 帧率越高视频越流畅 如果设置设备不支持的帧率会报错 按照注释说设备会支持自动帧率所以一般情况下不需要设置
// mMediaRecorder.setVideoSize(1280,1920);//设置录制视频的分辨率 如果设置设备不支持的分辨率会报错
     mMediaRecorder.setVideoEncodingBitRate(8*1920*1080); //设置比特率,比特率是每一帧所含的字节流数量,比特率越大每帧字节越大,画面就越清晰,算法一般是 5 * 选择分辨率宽 * 选择分辨率高,一般可以调整5-10,比特率过大也会报错
mMediaRecorder.setOrientationHint(90);//设置视频的摄像头角度 只会改变录制的视频文件的角度(对预览图像角度没有效果) Surface surface = new Surface(mTextureView.getSurfaceTexture());
mMediaRecorder.setPreviewDisplay(surface);//设置拍摄预览
mMediaRecorder.setOutputFile(videoFile.getAbsolutePath());//MP4文件保存路径 }

配置MediaRecorder是坑比较多的地方,现在我们来一一说下这些坑

  • 坑1:  首先MediaRecorder的配置是有顺序要求的,随便配置参数将会报错,一般顺序是 设置音频输入源与视频输入源  >  设置音频编码格式/视频编码格式/音频输出格式 > 设置分辨率/帧率/摄像头角度 > 添加预览 > 添加保存文件路径
  • 坑2:  在上面的代码上我注释了setVideoFrameRate(int rate) 与 setVideoSize(int width, int height) 这2个方法,设置录制视频帧率与设置视频分辨率.因为这2个设置的参数都是需要手机设备支持所输入的的值的,随便设置将会抛出 start failed -19 的错误
  • 坑3:  setOrientationHint()方法设置角度不会改变预览图像的角度
  • 坑4:  setPreviewDisplay()设置预览,其实只预览录制过程中的图像,停止录制,相机图像预览也停止了.如果想要一直预览就需要操作Camera来实现
  • 坑5:  关于各种参数设置的格式(设置视频输入源,音频输入源,音频输出格式,音频编码格式,图像编码),这里如果你只是实现demo推荐全部使用DEFAULT,上面的demo图像编码和音频编码使用MP4格式只是一个demo告诉你有很多其他格式.很多情况系统虽然提供了很多格式,但是下各个设备支持的格式是不同的.如果你是大量适配机型最好使用默认格式或者AAC音频编码格式与H264视频编码格式(目前这2个格式最通用),如果是只做单一设备开发,可以使用指定格式.
  • 坑6  当你选择默认编码格式录制视频后发现在Ios设备上无法自动播放? 其实是因为默认编码格式选择了IOS设备不支持的格式,Ios只支持AAC音频编码格式H264视频编码格式,在正常开发的时候建议使用这2个编码格式(他们是目前最通用的编码格式)

注意!上面的坑5关于参数配置的问题,当你发现出现MediaRecorder: start failed: -38 或者其他数值的报错,一定会去百度,这时候-38报错 百度可能会告诉是MIC没释放或者Camera没释放(Camera没释放的问题我下面那个demo会说明),这的确有可能,但是还有另外一种可能是设置setAudioEncoder或者setVideoEncoder在或者setAudioSource 上出现了问题,比如一些设备是支持setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);但是换调另外一个设备上就不支持了,所以这个时候请切换成setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT);默认模式,使用还是重新提醒你如果有需要适配大量机型的APP那么尽量选择默认格式.如果你只是为单一Android设备开发你可以指定格式.

小提醒~如果你想一进入Activity就配置MediaRecorder好,那么你就需要设置TextureView的监听setSurfaceTextureListener(SurfaceTextureListener listener),必需它先启动准备好之后在配置MediaRecorder,否则会报错的因为TextureView在启动activity后需要一段时间初始化启动

如果你需要切换摄像头,那么你还需要注意重新配置MediaRecorder时还需要切换角度:

    if (mCurrentCameraFacing){ //相机前后面向
mMediaRecorder.setOrientationHint(270);
}else {
mMediaRecorder.setOrientationHint(90);
}

开始录制视频

private void startRecorder(){
configMediaRecorder();//配置MediaRecorder 因为每一次停止录制后调用重置方法后都会取消配置,所以每一次开始录制都需要重新配置一次
try {
mMediaRecorder.prepare();//准备
mMediaRecorder.start();//开启
} catch (IOException e) {
e.printStackTrace();
}
}

注意!每一次停止录制后调用重置方法后都会取消配置,所以每一次开始录制都需要重新配置一次

停止录制视频

private void stopRecorder(){
mMediaRecorder.stop();//暂停
mMediaRecorder.reset();//重置 重置后将进入空闲状态,再次启动录制需要重新配置MediaRecorder
}

暂停录制与恢复录制

暂停录制,注意这里是pause()方法,不是stop()

private void pauseRecorder(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mMediaRecorder.pause();//暂停
}
}

恢复录制

private void resumeRecorder(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mMediaRecorder.resume();//恢复
}
}

销毁释放

private void destroy(){
if (mMediaRecorder != null){
mMediaRecorder.stop();
mMediaRecorder.release();//释放 释放之前需要先调用stop()
mMediaRecorder = null;
}
}

MediaRecorder设置Camera的录制视频

添加Camera来录制视频本来是另外一个篇幅应该说的事情,但是有个坑不得不在这里先说. 其他初始化和开启/停止/都与上面的介绍一致,下面我们来说说万恶的MediaRecorder配置:

private void configMediaRecorder(){
File videoFile = new File(getExternalCacheDir(),"video.mp4");
Log.e(TAG, "文件路径="+videoFile.getAbsolutePath());
if (videoFile.exists()){
videoFile.delete();
} Camera camera = Camera.open();
camera.unlock();
mMediaRecorder.setCamera(camera);
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);//设置音频输入源
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);//设置视频输入源
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);//音频输出格式
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT);//设置音频的编码格式
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.MPEG_4_SP);//设置图像编码格式
mMediaRecorder.setOrientationHint(90);//设置视频的摄像头角度 只会改变录制的视频角度
Surface surface = new Surface(mTextureView.getSurfaceTexture());
mMediaRecorder.setPreviewDisplay(surface);
mMediaRecorder.setOutputFile(videoFile.getAbsolutePath()); }

  也是一个简单的配置,也就是多了有摄像头的代码,如果你需要选择摄像头可以自己获取摄像头信息来判断前后在获取对应id,打开对应摄像头,作为简单的demo就暂时不演示选择摄像头的代码.

  然后重点来了这里有一个关键,你不会想到Camera.open();执行后摄像头居然是锁定状态的,就算是明白打开后就是锁定,但是你也不会发现在设置mMediaRecorder.setCamera(camera);之前是需要将摄像头解除锁定 camera.unlock();! 是的,就是这行代码困扰我了一下午!!!!!! 所以重点!重点!重点! 就是camera.unlock(); 最蛋疼的是如果你不做解除锁定的操作报错的提示是 start failed -19, 这个报错提示成功的让我反反复复研究是不是分辨率尺寸设置有问题........

  而这个Camera.unlock()在官方注释里也有说明在启动在设置之前先需要解锁摄像头,如下:

     * <p>Use this function to switch quickly between preview and capture mode without a teardown of
* the camera object. {@link android.hardware.Camera#unlock()} should be called before
* this. Must call before {@link #prepare}.</p>

setProfile

这个功能其实是相机预设的一些录制质量,格式和分辨率,官方注释说:

使用CamcorderProfile对象中的设置进行录制。这种方法应该在设置视频和音频源之后和setOutputfile()之前调用。如果使用延时摄像机配置文件,音频相关源或录制参数被忽略。

我们看到关键CamcorderProfile对象,那么看看什么CamcorderProfile的解释:

摄像机应用程序的预定义摄像机配置文件设置,这些设置是只读的。其实就是预设的一些摄像头配置设置

预设的属性有这些:

  • QUALITY_LOW
  • QUALITY_HIGH
  • QUALITY_QCIF
  • QUALITY_CIF
  • QUALITY_480P
  • QUALITY_720P
  • QUALITY_1080P
  • QUALITY_2160P
  • QUALITY_TIME_LAPSE_LOW
  • QUALITY_TIME_LAPSE_HIGH
  • QUALITY_TIME_LAPSE_QCIF
  • QUALITY_TIME_LAPSE_CIF
  • QUALITY_TIME_LAPSE_480P
  • QUALITY_TIME_LAPSE_720P
  • QUALITY_TIME_LAPSE_1080P
  • QUALITY_TIME_LAPSE_2160P
  • QUALITY_HIGH_SPEED_LOW
  • QUALITY_HIGH_SPEED_HIGH
  • QUALITY_HIGH_SPEED_480P
  • QUALITY_HIGH_SPEED_720P
  • QUALITY_HIGH_SPEED_1080P
  • QUALITY_HIGH_SPEED_2160P

使用代码:

if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P)) {
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_480P);
profile.videoBitRate = mPreviewSize.getWidth() * mPreviewSize.getHeight();
mMediaRecorder.setProfile(profile);
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P)) {
CamcorderProfile profile = CamcorderProfile.get(CamcorderProfile.QUALITY_720P);
profile.videoBitRate = mPreviewSize.getWidth() * mPreviewSize.getHeight();
mMediaRecorder.setProfile(profile);
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QVGA)) {
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_QVGA));
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else if (CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_CIF)) {
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_CIF));
mMediaRecorder.setPreviewDisplay(new Surface(mTextureView.getSurfaceTexture()));
} else {
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mMediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
mMediaRecorder.setVideoEncodingBitRate(10000000);
mMediaRecorder.setVideoFrameRate(30);
mMediaRecorder.setVideoSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
}

end

Android 开发 MediaRecorder视频录制入门的更多相关文章

  1. Android 开发 音视频从入门到提高 任务列表 转载

    <Android 音视频从入门到提高 —— 任务列表> 1. 在 Android 平台绘制一张图片,使用至少 3 种不同的 API,ImageView,SurfaceView,自定义 Vi ...

  2. Android开发笔记——视频录制播放常见问题

    本文分享自己在视频录制播放过程中遇到的一些问题,主要包括: 视频录制流程 视频预览及SurfaceHolder 视频清晰度及文件大小 视频文件旋转 一.视频录制流程 以微信为例,其录制触发为按下(住) ...

  3. Android 开发 MediaRecorder音频录制

    前言 MediaRecorder类是Android sdk提供的一个专门用于音视频录制,一般利用手机麦克风采集音频和摄像头采集图像.这个类是属于简单的音频录制类,录制音频简单容易但是对音频流的控制也比 ...

  4. Android菜鸟的成长笔记(1)——Android开发环境搭建从入门到精通

    原文:Android菜鸟的成长笔记(1)--Android开发环境搭建从入门到精通 今天在博客中看到好多Android的初学者对Android的开发环境的搭建不熟悉而导致不能进行学习,所以我决定自己写 ...

  5. Android开发使用控件入门--环境搭建

    Android开发使用控件入门--环境搭建 软件名称(,梦,,想.CAD  ,控件) 1. 环境搭建: 3 1.1. 安装Eclipse 3 1.2. 下载JDK 3 1.3. 下载Android S ...

  6. Android 开发 MediaRecorder使用Camera1配合录制视频

    前言 MediaRecorder可以不依靠Camera API 实现视频的录制,但是如果需要切换摄像头/设置对焦/选择分辨率等等就需要Camera来参与配合录制视频.这篇博客将介绍使用Camera1来 ...

  7. Android开发 MediaRecorder使用Camera2配合录制视频(暂时有异常抛出,无法使用)

    前言 这个博客本来是用来详细介绍MediaRecorder与Camera2,但是出乎预料之外,在获取mMediaRecorder.getSurface();的时候无论如何都是报错的,报错为Surfac ...

  8. Android多媒体录制--MediaRecorder视频录制

    Android使用MediaRecorder类进行视频的录制. 需要注意,使用MediaRecorder 录音录像 的设置代码步骤一定要按照API指定的顺序来设置,否则报错 步骤为: 1.设置视频源, ...

  9. 【Android开发日记】之入门篇(十四)——Button控件+自定义Button控件

        好久不见,又是一个新的学期开始了,为什么我感觉好惆怅啊!这一周也发生了不少事情,节假日放了三天的假(好久没有这么悠闲过了),实习公司那边被组长半强制性的要求去解决一个后台登陆的问题,结果就是把 ...

随机推荐

  1. 利用NHibernate与MySQL数据库交互

    本文章使用Visual Studio作为开发工具,并建立在已经安装MySQL数据库的前提. NHibernate是一个面向.NET环境的对象/关系数据库映射工具.官网:http://nhibernat ...

  2. 大数据-KNN算法

    KNN是通过测量不同特征值之间的距离进行分类.它的思路是:如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别,则该样本也属于这个类别,其中K通常是不大于20的整数 ...

  3. 剑指offer——30包含min函数的栈

    题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1)).   题解: 借助辅助栈,新的数据<=f辅助栈顶时,就压入辅助栈,这样,就能保证辅 ...

  4. Deep Dive into Neo4j 3.5 Full Text Search

    In this blog we will go over the Full Text Search capabilities available in the latest major release ...

  5. 9.ActiveMQ理论

    一.首先说下什么是消息队列? 1.消息队列是在消息的传输过程中保存消息的容器. 二.为什么要用到消息队列? 主要原因是由于在高并发环境下,由于来不及同步处理,请求往往会发生堵塞,比如说,大量的inse ...

  6. JS事件 编程练习-自制计算器 使用JS完成一个简单的计算器功能。实现2个输入框中输入整数后,点击第三个输入框能给出2个整数的加减乘除。

    编程练习 使用JS完成一个简单的计算器功能.实现2个输入框中输入整数后,点击第三个输入框能给出2个整数的加减乘除. 提示:获取元素的值设置和获取方法为:例:赋值:document.getElement ...

  7. 随笔记录 grub引导故障修复 2019.8.7

    系统备份: [root@localhost ~]# mkdir /abc [root@localhost ~]# mount /dev/sdb1 /abc [root@localhost ~]# dd ...

  8. chrome控制台使用jquery

    html页面中加入:<script type="text/javascript" src="http://static.fanxian.com/script/jqu ...

  9. JS调用C++

    1.注册C++函数. //注册回调函数宏 //根据不同需要支持注册两个函数原型,注意CONNECT_JS_CALL_SIMPLE_HANDLER中注册的函数 //需要提前和HTML调用协调好,参数必须 ...

  10. 5020: [THUWC 2017]在美妙的数学王国中畅游

    传送门 当年听llj讲的时候觉得这简直是个不可做的神题. 现在看来并不是很神,可能是我已经被剧透了的缘故... 一开始以为是函数套函数,懵蔽了好久,结果只是求和 被剧透了泰勒展开就比较水了..只要你不 ...