- MediaPlayer API介绍
- 音频播放
- 视频播放及VideoView,SurfaceView
MediaPlayer API介绍
????MediaPlayer OverView官方文档
????Mediaplayer可用来播放video,audio,另外可使用AudioManager(提供铃声和音量的控制)管理音频资源和输出
????MediaPlayer状态转换图:
(上图双箭头表示异步调用)
MediaPlayer 可在任何状态设置相关的事件监听器, 同时提供了一个方便的静态方法create来创建Media Player实例并使其进入Prepared状态。
通过MediaPlayer构造函数所创建的实例处于Idle状态,此时需要调用setDataSource使其进入Initialzed状态,然后可调用prepare方法进入Prepared状态,或其异步版本的prepare方法(prepareAsync),调用prepareSync会进入Preparing状态,使用prepareAsync方法需要设置OnPreparedListener监听器来变为Prepared状态,进入Prepared 状态就可以调用start方法来播放媒体文件。
音频播放
- 播放音频
MediaPlayer player = new MediaPlayer();//Idle状态
????????//在使用app自带资源时
//常使用create简便方法实例化Media Player,并且进入Prepared状态,player = create(this,R.id.resId);
//在使用assets 目录的文件时
//使用AssetsManager来管理,可使用getAssets()得到AssetsManager的实例assetsManager?,
//AssetsFileDescriptor afd = assetsManager.openFd(String fileName);将afd作为参数传递给create或setDataSource
- ? ?
//另外create和setDataSource使用String path作为参数时,path指的是文件系统路径,通常是sdCard目录的媒体文件
player.setDataSource(…)//设置资源,进入Initialized状态
player.prepare() //进入Prepared状态
//or 调用prepareAsync()进入preparing状态,可以设置监听器 setOnPreparedListener(android.media.MediaPlayer.OnPreparedListener).
-
Player.start()//开始播放 进入started状态
? ?
-
音频特效AudioEffect
AudioEffect是Android框架提供的音效控制的基类,应使用其子类来控制特定音效。要使用音效 音效的实例必须调用setEnabled (Boolean enabled)来启用。每种音效都必须或得对应得音频的sessionId,sessionId可通过MediaPlayer.getAudioSessionId()获取。
- AcousticEchoCanceler:????AEC 取消回声控制器
- AutomaticGainControl:????自动增益控制器
- NoiseSuppressor:????噪声压制控制器
上面三个子类只需使用其对应的静态方法create(int audioSession)创建相应实例,然后调用isAvailable()判断是否可用,再调用setEnabled(Boolean enabled)方法启用相应效果。(setEnabled方法由基类Audio Effect提供)
AcousticEchoCanceler aec =AcousticEchoCanceler.create(mediaPlayer.getAudioSessionId());
if(aec.isAvailable){
????aec.setEnable(true);
-
}
其余子类需要调用其构造方法来创建实例
-
BassBoost 重低音
//
BassBoost bassBoost = new BassBoost(0,player.getAudioSessionId());
bassBoost.setEnabled(true);//Basst.setStrength(strength);// 设置强度,范围在0-1000,0最小,1000最大
- Equalizer 均衡器
//通过MediaPlayer.getAudioSessionId()得到音频的AudioSessionId,在Equalizer实例化时将AudioSessionId传入构造参数
Equalizer equalizer = new Equalizer(0,meidiaPlayer.getAudioSessionId);
????????//启用均衡器Equalizer
equalizer.setEnabled(true);
//获取频带增益范围
short[] bandLevelRange = equalizer.getBandLevelRange();
short minLevel = bandLevelRange[0];
short maxLevel = bandLevelRange[1];
- ? ?
????????//getNumberOfBands 得到Equalizer引擎支持的频带数量
for (short band =0 ; i < equalizer.getNumberOfBands();i++){
- ? ?
????//getCenterFreq():获取band对应的频率
int frequency = equalizer.getCenterFreq(band);
}
-
equalizer.setBandLevel(shot band,short level);//为特定频率设置增益,频率为band所对应的frequency
?
?
-
在音频应用中使用 VolumeShaper 来执行渐强、渐弱、渐强渐弱、降低音量以及其他短暂的自动音量转换。VolumeShaper 类在 Android 8.0(API 级别 26)及更高版本中可用。通过对 AudioTrack 或 MediaPlayer 的实例调用 createVolumeShaper() 来创建 VolumeShaper,VolumeShaper 仅对创建它的 AudioTrack 或 MediaPlayer 生成的音频起作用
VolumeShaper 的行为由它的 VolumeShaper.Configuration 定义。该配置指定了音量曲线、插值器类型和持续时间。
//创建配置
VolumeShaper.Configuration configuration = new VolumeShaper.Configuration.Builder()
.setCurve(new float[]{0.0f,0.5f,1.0f},new float[]{0.f, 1.f,0.f})
.setDuration(1000*60*1)
.setInterpolatorType(VolumeShaper.Configuration.INTERPOLATOR_TYPE_LINEAR)
.build();
//创建volumeShaper
VolumeShaper volumeShaper = player.createVolumeShaper(configuration);
//应用volumeShaper到音频
volumeShaper.apply(VolumeShaper.Operation.PLAY);
//替换配置
boolean join = true;
volumeShaper.replace(newConfig, VolumeShaper.Operation.PLAY, join);
//关闭volumeShaper
-
volumeShaper.close();
? ?
-
SoundPool为应用程序管理和播放音频资源,预先将音频加载到内存,低时延、cpu占用少。通常用于游戏播放短音频,支持速率、音量、音频优先级,声道、循环设置。
使用SoundPool.Builder构造实例,构造函数已被废弃。使用SoundPool.Builder时有一下几个方法:setAudioAttribute方法需要一个AudioAttribute对象。
?
AudioAttribute封装了描述音频流信息的属性的集合,使用AudioAttribute.Builder创建AudioAttribute实例。使用setUsage设置使用场景,setContentType设置内容类型,build创建AudioAttribute实例。
SoundPool的方法load方法加载音频并返回一个int值,这个int 值是音频的streamID。播放时调用SoundPool的play方法。第一个参数soundID即是load方法加载音频时返回的代表音频的streamID。第二三个参数时左声道和右声道,0.0f-1.0f。loop代表循环次数(播放次数=循环次数+1),为-1时一直循环。rate:播放速度0.5-2.0,默认为1。
?
AudioAttributes attr = new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_GAME).
setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).build();
SoundPool soundPool = new SoundPool.Builder().setAudioAttributes(attr).setMaxStreams(10).build();
int soundID = soundPool.load(…);//加载音频
soundPool.play(soundID,1.0,1.0,0,0,1);//播放音乐
//可将所加载的音频的streamID放入容器(List,Map),保存streamID。
? ?
?
视频播放及VideoView,SurfaceView
-
VideoView
在使用videoView时(和布局主题有关)会导致有白边现象,可以实现VideoView的子类(自定义View),重写onMeasure()方法。
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取系统服务的WindowManager
WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
assert wm != null;
//将所得到的像素大小保存在point中
Point point = new Point();
wm.getDefaultDisplay().getSize(point);
//设置绘制的大小
setMeasuredDimension(point.x,point.y);
}
?获取当前屏幕的大小与WindowManager,Display,DisplayMetris这三个类有关。getContext.getSystemService(Context.WINDOW_SERVICE)取得windowManager,windowManager.getDefaultDisplay()返回一个Display。Display中有许多获得窗口屏幕大小的方法:getSize,getMetrics。
?
使用自定义的VideoView播放视频
//MediaController提供图形界面对视频的控制
MediaController mediaController = new MediaController(this);
//设置视频
fullScreenVideoView.setVideoURI(Uri.parse("android.resource://"+getPackageName()+"/"+R.raw.fat));
//将meidiaController与videoView联系起来
mediaController.setMediaPlayer(fullScreenVideoView);
fullScreenVideoView.setMediaController(mediaController);
//打开屏幕,获取焦点
fullScreenVideoView.requestFocus();
//播放视频
fullScreenVideoView.start();
? ?
-
SurfaceView
VideoView是SurfaceView的子类
Surface是可以在子线程渲染更新界面,surfaceView.getHolder的返回值就是一个surfaceHolder,也是surfaceView的核心, surfaceHolder.addCallback()为其添加一个回调,在这个回调中包含surface的完整的生命周期:surfaceCreated、surfaceChanged、surfaceDestroy。若使用绘画子线程必须,子线程必须和主线程同步,只有当surface状态在生命周期只能子线程才能访问surface。
mediaPlayer = MediaPlayer.create(this,R.raw.fat);
surfaceView.getHolder().setKeepScreenOn(true);
surfaceView.getHolder().addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
DisplayMetrics metrics = new DisplayMetrics();
MainActivity.this.getWindowManager().getDefaultDisplay().getMetrics(metrics);
surfaceView.setLayoutParams(new ConstraintLayout.LayoutParams(metrics.widthPixels,
mediaPlayer.getVideoHeight()*metrics.widthPixels/mediaPlayer.getVideoWidth()));
mediaPlayer.setDisplay(surfaceView.getHolder());
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}});