




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
【移动应用开发技术】怎么在Android中使用MediaRecorder类实现视频和音频录制功能
怎么在Android中使用MediaRecorder类实现视频和音频录制功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、前期基础知识储备Android提供了MediaRecorder这一个类来实现视频和音频的录制。
由官方配图可知,MediaRecorder用于录制视频时需要调用一系列的API来设置和录制相关的配置,而且调用方法的顺序是固定的,必须按照这个顺序进行API调用才能正确利用手机摄像头实现录像功能。调用MediaRecorder的录像API顺序如下:1)OpenCamera-UsetheCamera.open()togetaninstanceofthecameraobject.
2)ConnectPreview-PreparealivecameraimagepreviewbyconnectingaSurfaceViewtothecamerausingCamera.setPreviewDisplay().
3)StartPreview-CallCamera.startPreview()tobegindisplayingthelivecameraimages.
4)StartRecordingVideo-Thefollowingstepsmustbecompletedinordertosuccessfullyrecordvideo:
a.UnlocktheCamera-UnlockthecameraforusebyMediaRecorderbycallingCamera.unlock().
b.ConfigureMediaRecorder-CallinthefollowingMediaRecordermethodsinthisorder:setCamera()-Setthecameratobeusedforvideocapture,绑定Camera进行视频录制。setAudioSource()-Settheaudiosource,设置音频源。setVideoSource()-Setthevideosource,设置视频源。setProfile()-Setthevideooutputformatandencoding,录制效果的配置。setOutputFile()-Settheoutputfile,设置录制好的文件存储位置。setPreviewDisplay()-ConnectPreview,设置预览效果。c.PrepareMediaRecorder-PreparetheMediaRecorderwithprovidedconfigurationsettingsbycallingMediaRecorder.prepare().
d.StartMediaRecorder-StartrecordingvideobycallingMediaRecorder.start().停止录像时调用的API顺序如下:1)StopMediaRecorder-StoprecordingvideobycallingMediaRecorder.stop().
2)ResetMediaRecorder-Optionally,removetheconfigurationsettingsfromtherecorderbycallingMediaRecorder.reset().
3)ReleaseMediaRecorder-ReleasetheMediaRecorderbycallingMediaRecorder.release().
4)LocktheCamera-LockthecamerasothatfutureMediaRecordersessionscanuseitbycallingCamera.lock().
5)StopthePreview-Whenyouractivityhasfinishedusingthecamera,stopthepreviewusingCamera.stopPreview().
6)ReleaseCamera-ReleasethecamerasothatotherapplicationscanuseitbycallingCamera.release().二、上代码,具体实现录制视频和视频播放功能这里调用MediaRecorder的API实现视频录制功能并借用MediaPlayer多媒体播放类实现录制好的视频播放。(1)布局文件如下,非常简单两个按钮下放置一个SurfaceView;<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/record_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_weight="1"
android:text="record"
/>
<Button
android:id="@+id/play_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="15dp"
android:layout_weight="1"
android:text="play"
/>
</LinearLayout>
<SurfaceView
android:id="@+id/surface_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="20dp"
/>
</LinearLayout>(2)相机录像前的准备代码;
/*
*
相机预览前的准备工作代码
单独抽出来
*
*/
private
boolean
prepareVideoRecorder()
throws
IOException
{
if
(mMediaRecorder
==
null)
{
mMediaRecorder
=
new
MediaRecorder();
mMediaRecorder.reset();
}
/*camera相关设置部分*/
mCamera
=
Camera.open(0);//Camera.CameraInfo.CAMERA_FACING_BACK
if
(mCamera
!=
null)
{
//设置旋转角度,顺时针方向,因为默认是逆向90度的,这样图像就是正常显示了
mCamera.setDisplayOrientation(90);
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
}
/*recorder设置部分*/
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
mMediaRecorder.setOutputFile(getOutputMediaFile());
mMediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());
mMediaRecorder.prepare();
return
true;
}(3)创建录像文件存储位置代码;
/*
*
获取手机外部存储路径
*
*/
private
String
getOutputFile()
{
File
mediaFile
=
null;
boolean
OutputExist
=
Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
if
(OutputExist)
{
mediaFile
=
Environment.getExternalStorageDirectory();
return
mediaFile.toString();
}
return
null;
}
/*
*
获取录制视频的日期
作为存储文件路径一部分
*
*/
private
String
getDate()
{
Log.d(TAG,
"获取录制视频的日期
");
Calendar
ca
=
Calendar.getInstance();
int
year
=
ca.get(Calendar.YEAR);
//
获取年份
int
month
=
ca.get(Calendar.MONTH);
//
获取月份
int
day
=
ca.get(Calendar.DATE);
//
获取日
String
date
=
""
+
year
+
"_"
+
(month
+
1)
+
"_"
+
day;
return
date;
}
/*
*创建视频存储文件夹
录制好的视频存储在手机外部存储中
以录像时间+mp4格式命名
*
*/
private
String
getOutputMediaFile()
{
Log.d(TAG,
"获取视频存储的位置
");
String
mediaPath
=
getOutputFile();
if
(mediaPath
!=
null)
{
File
mediaFile
=
new
File(mediaPath
+
"/recordVideo");
if
(!mediaFile.exists())
{
mediaFile.mkdir();
}
return
mMediaPath
=
mediaFile.getAbsolutePath()
+
File.separator
+
getDate()
+
".mp4";
}
return
null;
}(4)录制视频结束时释放相机资源;
/*
*
录制视频结束时释放相机资源
*
*/
private
void
releaseMediaRecorder()
{
Log.d(TAG,
"录制结束后释放资源
");
if
(mMediaRecorder
!=
null)
{
mMediaRecorder.reset();
//
clear
recorder
configuration
mMediaRecorder.release();
//
release
the
recorder
object
mMediaRecorder
=
null;
mCamera.lock();
//
lock
camera
for
later
use
}
}(5)点击录制视频按钮mRecordBtn开始录制和再次点击停止录制;
private
void
initBtnClick()
{
StartRecording();
mPlayBtn.setOnClickListener(new
View.OnClickListener()
{
@Override
public
void
onClick(View
view)
{
if
(mMediaPlayer
==
null)
{
mMediaPlayer
=
new
MediaPlayer();
mMediaPlayer.reset();
Uri
uri
=
Uri.parse(mMediaPath);
mMediaPlayer
=
MediaPlayer.create(MainActivity.this,uri);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setDisplay(mSurfaceHolder);
try{
mMediaPlayer.prepare();
}catch
(Exception
e){
e.printStackTrace();
}
mMediaPlayer.start();
}
}
});
}
private
void
StartRecording(){
mRecordBtn.setOnClickListener(new
View.OnClickListener()
{
@Override
public
void
onClick(View
view)
{
if
(!mIsRecord)
{
try
{
Log.d(TAG,
"首次点击开始录像
");
if
(prepareVideoRecorder())
{
mMediaRecorder.start();
mIsRecord
=
true;
mRecordBtn.setText("stop");
}
}
catch
(IOException
e)
{
e.printStackTrace();
}
}
else
{
Log.d(TAG,
"再次点击停止录像");
mMediaRecorder.stop();
releaseMediaRecorder();
mCamera.lock();
mRecordBtn.setText("record");
mIsRecord
=
false;
if
(mCamera
!=
null)
{
mCamera.release();
mCamera
=
null;
}
}
}
});
}(6)点击播放视频按钮mPlayBtn开始播放录制刚刚录制好的视频;
mPlayBtn.setOnClickListener(new
View.OnClickListener()
{
@Override
public
void
onClick(View
view)
{
if
(mMediaPlayer
==
null)
{
mMediaPlayer
=
new
MediaPlayer();
mMediaPlayer.reset();
Uri
uri
=
Uri.parse(mMediaPath);
mMediaPlayer
=
MediaPlayer.create(MainActivity.this,uri);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setDisplay(mSurfaceHolder);
try{
mMediaPlayer.prepare();
}catch
(Exception
e){
e.printStackTrace();
}
mMediaPlayer.start();
}
}
});(7)针对6.0以上系统进行运行时权限申请
private
void
requestCameraAndStoragePermission()
{
//检查用户是否授权
for
(int
i
=
0;
i
<
permissions.length;
i++)
{
if
(ContextCompat.checkSelfPermission(MainActivity.this,
permissions[i])
!=
PackageManager.PERMISSION_GRANTED)
{
//没有授权则请求相应权限
ActivityCompat.requestPermissions(MainActivity.this,
new
String[]{permissions[i]},
1);
}
}
//利用权限申请工具类来实现
mPermissionsUtils
=
PermissionsUtils.getInstance();
mPermissionsUtils.chekPermissions(MainActivity.this,permissions,
permissionsResult);
}
//创建监听权限的接口对象
PermissionsUtils.IPermissionsResult
permissionsResult
=
new
PermissionsUtils.IPermissionsResult()
{
@Override
public
void
passPermissons()
{
//StartRecording();
注意这里的逻辑
并不是权限通过了就立即开始录像了
而是权限通过了
就可以打开Camera进行预览
mCamera
=
Camera.open(0);//Camera.CameraInfo.CAMERA_FACING_BACK
}
@Override
public
void
forbitPermissons()
{
Toast.makeText(MainActivity.this,
"You
denyied
the
permission",
Toast.LENGTH_SHORT).show();
}
};录制视频及播放录制视频完整代码如下public
class
MainActivity
extends
AppCompatActivity
implements
SurfaceHolder.Callback{
private
static
final
String
TAG
=
"MainActivity";
private
SurfaceView
mSurfaceView;
private
Button
mRecordBtn,
mPlayBtn;
private
boolean
mIsRecord
=
false;
//是否正在录像
private
Camera
mCamera;
private
MediaRecorder
mMediaRecorder;
private
String
mMediaPath;
private
MediaPlayer
mMediaPlayer;
private
SurfaceHolder
mSurfaceHolder;
private
PermissionsUtils
mPermissionsUtils;
private
String[]
permissions
=
{Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA,
Manifest.permission.RECORD_AUDIO};
@Override
protected
void
onCreate(Bundle
savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//6.0及以上系统请求运行时权限
利用权限申请工具类(见下文)
requestCameraAndStoragePermission();
mSurfaceView
=
(SurfaceView)
findViewById(R.id.surface_view);
mSurfaceView.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
//
必须-设置Surface不需要维护自己的缓冲区
mRecordBtn
=
(Button)
findViewById(R.id.record_btn);
mPlayBtn
=
(Button)
findViewById(R.id.play_btn);
initBtnClick();
SurfaceHolder
holder
=
mSurfaceView.getHolder();
holder.addCallback(this);
}
private
void
requestCameraAndStoragePermission()
{
//检查用户是否授权
for
(int
i
=
0;
i
<
permissions.length;
i++)
{
if
(ContextCompat.checkSelfPermission(MainActivity.this,
permissions[i])
!=
PackageManager.PERMISSION_GRANTED)
{
//没有授权则请求相应权限
ActivityCompat.requestPermissions(MainActivity.this,
new
String[]{permissions[i]},
1);
}
}
//利用权限申请工具类来实现
mPermissionsUtils
=
PermissionsUtils.getInstance();
mPermissionsUtils.chekPermissions(MainActivity.this,permissions,
permissionsResult);
}
//创建监听权限的接口对象
PermissionsUtils.IPermissionsResult
permissionsResult
=
new
PermissionsUtils.IPermissionsResult()
{
@Override
public
void
passPermissons()
{
//
StartRecording();
注意这里的逻辑
并不是权限通过了就立即开始录像了
而是权限通过了
就可以打开Camera进行预览
mCamera
=
Camera.open(0);//Camera.CameraInfo.CAMERA_FACING_BACK
}
@Override
public
void
forbitPermissons()
{
Toast.makeText(MainActivity.this,
"You
denyied
the
permission",
Toast.LENGTH_SHORT).show();
}
};
private
void
StartRecording(){
mRecordBtn.setOnClickListener(new
View.OnClickListener()
{
@Override
public
void
onClick(View
view)
{
if
(!mIsRecord)
{
try
{
Log.d(TAG,
"首次点击开始录像
");
if
(prepareVideoRecorder())
{
mMediaRecorder.start();
mIsRecord
=
true;
mRecordBtn.setText("stop");
}
}
catch
(IOException
e)
{
e.printStackTrace();
}
}
else
{
Log.d(TAG,
"再次点击停止录像");
mMediaRecorder.stop();
releaseMediaRecorder();
mCamera.lock();
mRecordBtn.setText("record");
mIsRecord
=
false;
if
(mCamera
!=
null)
{
mCamera.release();
mCamera
=
null;
}
}
}
});
}
private
void
initBtnClick()
{
StartRecording();
mPlayBtn.setOnClickListener(new
View.OnClickListener()
{
@Override
public
void
onClick(View
view)
{
if
(mMediaPlayer
==
null)
{
mMediaPlayer
=
new
MediaPlayer();
mMediaPlayer.reset();
Uri
uri
=
Uri.parse(mMediaPath);
mMediaPlayer
=
MediaPlayer.create(MainActivity.this,uri);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mMediaPlayer.setDisplay(mSurfaceHolder);
try{
mMediaPlayer.prepare();
}catch
(Exception
e){
e.printStackTrace();
}
mMediaPlayer.start();
}
}
});
}
/*
*
相机预览前的准备工作代码
单独抽出来
*
*/
private
boolean
prepareVideoRecorder()
throws
IOException
{
if
(mMediaRecorder
==
null)
{
mMediaRecorder
=
new
MediaRecorder();
mMediaRecorder.reset();
}
/*camera相关设置部分*/
mCamera
=
Camera.open(0);//Camera.CameraInfo.CAMERA_FACING_BACK
if
(mCamera
!=
null)
{
//设置旋转角度,顺时针方向,因为默认是逆向90度的,这样图像就是正常显示了
mCamera.setDisplayOrientation(90);
mCamera.unlock();
mMediaRecorder.setCamera(mCamera);
}
/*recorder设置部分*/
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
mMediaRecorder.setProfile(CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH));
mMediaRecorder.setOutputFile(getOutputMediaFile());
mMediaRecorder.setPreviewDisplay(mSurfaceView.getHolder().getSurface());
mMediaRecorder.prepare();
return
true;
}
/*
*
获取手机外部存储路径
*
*/
private
String
getOutputFile()
{
File
mediaFile
=
null;
boolean
OutputExist
=
Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
if
(OutputExist)
{
mediaFile
=
Environment.getExternalStorageDirectory();
return
mediaFile.toString();
}
return
null;
}
/*
*
获取录制视频的日期
作为存储文件路径一部分
*
*/
private
String
getDate()
{
Log.d(TAG,
"获取录制视频的日期
");
Calendar
ca
=
Calendar.getInstance();
int
year
=
ca.get(Calendar.YEAR);
//
获取年份
int
month
=
ca.get(Calendar.MONTH);
//
获取月份
int
day
=
ca.get(Calendar.DATE);
//
获取日
String
date
=
""
+
year
+
"_"
+
(month
+
1)
+
"_"
+
day;
return
date;
}
/*
*创建视频存储文件夹
录制好的视频存储在手机外部存储中
以录像时间+mp4格式命名
*
*/
private
String
getOutputMediaFile()
{
Log.d(TAG,
"获取视频存储的位置
");
String
mediaPath
=
getOutputFile();
if
(mediaPath
!=
null)
{
File
mediaFile
=
new
File(mediaPath
+
"/recordVideo");
if
(!mediaFile.exists())
{
mediaFile.mkdir();
}
return
mMediaPath
=
mediaFile.getAbsolutePath()
+
File.separator
+
getDate()
+
".mp4";
}
return
null;
}
/*
*
录制视频结束时释放相机资源
*
*/
private
void
releaseMediaRecorder()
{
Log.d(TAG,
"录制结束后释放资源
");
if
(mMediaRecorder
!=
null)
{
mMediaRecorder.reset();
//
clear
recorder
configuration
mMediaRecorder.release();
//
release
the
recorder
object
mMediaRecorder
=
null;
mCamera.lock();
//
lock
camera
for
later
use
}
}
@Override
public
void
surfaceCreated(SurfaceHolder
surfaceHolder)
{
mSurfaceHolder
=
surfaceHolder;
}
@Override
public
void
surfaceChanged(SurfaceHolder
surfaceHolder,
int
i,
int
i1,
int
i2)
{
mSurfaceHolder
=
surfaceHolder;
}
@Override
public
void
surfaceDestroyed(SurfaceHolder
surfaceHolder)
{
mSurfaceView
=
null;
mSurfaceHolder
=
null;
releaseMediaRecorder();
if
(mCamera
!=
null)
{
mCamera.release();
mCamera
=
null;
}
if
(mMediaPlayer
!=
null){
mMediaPlayer.release();
mMediaPlayer
=
null;
}
}
}三、延伸知识,运行时权限申请工具类完整代码如下/**
*
运行时权限申请工具类:
*
检查用户是否授权——ContextCompat.checkSelfPermission
*
如果没有授权,那么申请授权——ActivityCompat.requestPermissions
*
申请授权之后的回调——onRequestPermissionsResult
*
精髓:检查权限
申请权限的代码写在工具类内
同时写入一个接口
两个抽象方法-获取权限成功
+
获取权限失败
然后在外部使用权限工具类时实现这两个抽象方法
*
Created
by
Administrator
on
2018/7/3.
*/
public
class
PermissionsUtils
{
private
final
int
mRequestCode
=
100;//权限请求码
public
static
boolean
showSystemSetting
=
true;
private
PermissionsUtils()
{
}
private
static
PermissionsUtils
permissionsUtils;
private
IPermissionsResult
mPermissionsResult;
/*
*
单例模式创建PermissionUtils实例
工具类中的静态方法可以直接使用类名+方法名调用
非静态方法还是需要获取到工具类的实例
实例对方法进行调用
*
*/
public
static
PermissionsUtils
getInstance()
{
if
(permissionsUtils
==
null)
{
synchronized
(PermissionsUtils.class)
{
if
(permissionsUtils
==
null)
permissionsUtils
=
new
PermissionsUtils();
}
}
return
permissionsUtils;
}
/*
*
检查用户是否授权
+
如果没有授权
则申请授权
-
系统标准方法
*
*/
public
void
chekPermissions(Activity
context,
String[]
permissions,
@NonNull
IPermissionsResult
permissionsResult)
{
mPermissionsResult
=
permissionsResult;
if
(Build.VERSION.SDK_INT
<
23)
{//6.0系统及以上才会动态申请权限
以下不用
所以直接return出去
permissionsResult.passPermissons();
return;
}
//创建一个mPermissionList,逐个判断哪些权限未授予,未授予的权限存储到mPerrrmissionList中
List<String>
mPermissionList
=
new
ArrayList<>();
//逐个判断你要的权限是否已经通过
for
(int
i
=
0;
i
<
permissions.length;
i++)
{
if
(ContextCompat.checkSelfPermission(context,
permissions[i])
!=
PackageManager.PERMISSION_GRANTED)
{
mPermissionList.add(permissions[i]);//添加还未授予的权限
}
}
//申请权限
if
(mPermissionList.size()
>
0)
{//有权限没有通过,需要申请
ActivityCompat.requestPermissions(context,
permissions,
mRequestCode);
}
else
{
//说明权限都已经通过,利用接口变量调用实现的接口方法
即有权限之后需要调用的方法
permissionsResult.passPermissons();
return;
}
}
//请求权限后回调的方法
//参数:
requestCode
是我们自己定义的权限请求码
//参数:
permissions
是我们请求的权限名称数组
//参数:
grantResults
是我们在弹出页面后是否允许权限的标识数组,数组的长度对应的是权限名称数组的长度,数组的数据0表示允许权限,-1表示我们点击了禁止权限
public
void
onRequestPermissionsResult(Activity
context,
int
requestCode,
@NonNull
String[]
permissions,
@NonNul
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 智慧断路器合同协议书
- 联合拍地协议书
- 花呗升级协议书
- 缴费平台协议书
- 退房定金协议书
- 英文赠予协议书
- 混凝土开票个人协议书
- 签署保密协议书
- 自愿分房协议书
- 联营单位协议书
- 《新闻传播伦理与法规》大一笔记
- 湖北大学知行学院《面向对象程序设计》2021-2022学年第一学期期末试卷
- 【MOOC】中国特色文化英语教学-苏州大学 中国大学慕课MOOC答案
- 【MOOC】财务会计-淄博职业学院 中国大学慕课MOOC答案
- 机场安检液态物品培训
- 2024年剑桥KET口语题库(附参考答案)
- 手术分级目录(2023年修订)
- 2024年东西损毁赔偿协议书模板
- 林权继承协议书范本
- 2024年四川省巴中市中考文科综合试卷(含答案解析)
- 学校食堂人员工资发放方案范文
评论
0/150
提交评论