本篇文章讲述使用阿里云视频视频播放sdk中的高级播放器加上SurfaceView实现,采用id+STS方法进行视频播放。
目录
- 概念介绍
- STS的播放流程
- 如何导入
- 自定义SurfaceView
- 横竖屏切换
- 滑动快进,后退
- 滑动调节音量
- 滑动调节亮度
- 按Home键后重新点开黑屏问题
- Token过期问题
一 首先是概念介绍(只介绍用到的)
- 高级播放器:除了具备基础播放器的所有功能外,还提供播放视频的高级能力,如视频加密、安全下载、边播边下缓存、清晰度切换等功能,建议使用阿里视频云点播和直播业务的用户使用。
- RAM和STS:RAM和STS是阿里云提供的权限管理系统。RAM主要的作用是控制账号系统的权限。通过使用RAM可以将在主账号的权限范围内创建子用户,给不同的子用户分配不同的权限从而达到授权管理的目的。STS是一个安全凭证(Token)的管理系统,用来授予临时的访问权限,这样就可以通过STS来完成对于临时用户的访问授权。
二 STS的播放流程
流程:用户App获取STS凭证 -> 服务端下发STS凭证 -> 用户上传视频并获取vid -> 服务端获取STS凭证 -> 将STS凭证下发给客户端 -> 完成视频播放。
三 如何导入
请看阿里云文档=========》》》》》》阿里云-高级播放器Android使用说明
四 自定义SurfaceView
- 为什么不直接用SurfaceView而是自定义?
如果想实现触摸滑动事件,就必须自定义。
自定义SurfaceView需要继承SurfaceView,我们现在的需求是滑动触控。
罗列出这几种情况:
- 亮度手势,手指在SurfaceView左半部上下滑动时候调用
2.音量手势,手指在SurfaceView右半部上下滑动时候调用
3.快进快退手势,手指在SurfaceView左右滑动的时候调用
4.按下手势,第一根手指按下时候调用
5.快进快退执行后的松开时候调用
我就这几种情况创建了一个接口 :VideoGesureListener
public interface VideoGesureListener{
//亮度手势,手指在SurfaceView左半部上下滑动时候调用
public void onBrightnessGesture(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
//音量手势,手指在SurfaceView右半部上下滑动时候调用
public void onVolumeGesture(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
//快进快退手势,手指在SurfaceView左右滑动的时候调用
public void onFF_REWGesture(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
//按下手势,第一根手指按下时候调用
public void onDown(MotionEvent e);
//快进快退执行后的松开时候调用
public void onEndFF_REW(MotionEvent e);
}
接下来我们来看一下安卓给我们提供的手势控制类
GestureDetector
接口
- OnGestureListener:监听一些手势,如单击、滑动、长按等操作
1.onDown(MotionEvent e):按下屏幕的时候回调
2.onShowPress(MotionEvent e):按下后100ms内未松开的时候回调(目前不知有何用)
3.onLongPress(MotionEvent e):用户长按后回调
4.onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY):手指滑动的时候回调,e1,e2分别是之前DOWN事件和当前的MOVE事件,distanceX和distanceY就是当前MOVE事件和上一个MOVE事件的位移量
5.onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY):滑动后惯性操作回调
6.onSingleTapUp(MotionEvent e):点击抬起时间,没有长按和滑动时回调 - OnDoubleTapListener:监听双击和单击事件。
1.onSingleTapConfirmed(MotionEvent e):单击事件回调
2.onDoubleTap(MotionEvent e):双击事件回调
3.onDoubleTapEvent(MotionEvent e):onDoubleTap双击后的回调 - OnContextClickListener:监听鼠标右键
1.onContextClick(MotionEvent e):当鼠标/触摸板,右键点击时候的回调。
内部类 - SimpleOnGestureListener:实现上面三个接口的内部类,拥有上面三个的所有回调
因为SimpleOnGestureListener不是抽象类,所以我们一般应它进行操纵,这样我们就可以只写我们用到的方法,就不用全部重写所有的方法。
GestureDetector的使用与需要结合触摸事件。只有感受到触摸事件才能去进行手指触控。
setOnTouchListener(this);
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction()==MotionEvent.ACTION_UP){
if (hasFF_REW){
if (mVideoGestureListener!=null){
mVideoGestureListener.onEndFF_REW(event);
}
hasFF_REW=false;
}
}
return mGestureDetector.onTouchEvent(event);
}
其中定义了四种状态 NONE = 0, VOLUME = 1, BRIGHTNESS = 2, FF_REW = 3;
接下来我们来看一下我们自定义的SurfaceViewOnGestureListener继承 GestureDetector.SimpleOnGestureListener主要用到了
onDown(MotionEvent e)
onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)两个方法
public class SurfaceViewOnGestureListener extends GestureDetector.SimpleOnGestureListener{
private MySurfaceView mySurfaceView;
public SurfaceViewOnGestureListener(MySurfaceView mySurfaceView) {
this.mySurfaceView =mySurfaceView;
}
A: @Override
public boolean onDown(MotionEvent e) {
hasFF_REW=false;
mScrollMode=NONE;
if (mVideoGestureListener!=null){
mVideoGestureListener.onDown(e);
}
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
switch (mScrollMode){
B:
case NONE:
if (Math.abs(distanceX)-Math.abs(distanceY)>offsetX){
mScrollMode=FF_REW;
}else {
C:
if (e1.getX()
a.在onDown的时候把状态设置NONE
b.判断横向滑动的距离大于纵向滑动的距离,就把模式赋值为快进和后退
c.在onScroll中进行状态赋值,根据滑动的距离,如果按下的点在屏幕的左半部分就吧状态设置为调节亮度BRIGHTNESS,如果在右半部分就是调节音量
d.各种情况调用各自的接口方法
五 横竖屏切换
- 不设置Activity的android:configChanges,或着设置Activity的android:configChanges="orientation",再或着设置Activity的android:configChanges="orientation|keyboardHidden",切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行一次。
- 配置 android:configChanges="orientation|keyboardHidden|screenSize",不销毁 activity,只调用 onConfigurationChanged方法。
- 首先我们要先判断当前的屏幕是横屏还是竖屏getResources().getConfiguration().orientation (获取状态)进行比较
Configuration.ORIENTATION_LANDSCAPE(横屏)
Configuration.ORIENTATION_PORTRAIT(竖屏)
然后用 setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);(setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);)进行横竖屏设置
接下来我们需要在onConfigurationChanged(Configuration newConfig)方法里面进行设置屏幕切换后大小即可
//获得屏幕宽高
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
width = displayMetrics.widthPixels;
height = displayMetrics.heightPixels;
//设置宽高,首先要找到外部包裹视频界面的布局
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mySurfaceView.getLayoutParams();
params.width = width;
if (newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
params.height = height;
}
if (newConfig.orientation==Configuration.ORIENTATION_PORTRAIT){
params.height = (width /16)*9;(正常比例)
}
mySurfaceView.setLayoutParams(params);
六 滑动快进,后退
快进和后退,我们需要知道的就是我们滑动的距离如何与视频的长度关联起来。
那么咱们就可以把视频的总长度与屏幕的总长度相比,这样就能知道你手指滑动的距离占视频的多少了。
我们可以通过 l = duration / mySurfaceView.getWidth();来获得这个比例,然后用当前的进度加上指滑动的距离占视频的长度就是要播放的视频位置
float offset = e2.getX() - e1.getX();
if (offset>0){
float v = currentPosition + (offset * l) / 4;(除以4是为了让快进的量不是特别大)
aliyunVodPlayer.seekTo((int) v);
}else {
float v = currentPosition +(offset * l) / 4;
aliyunVodPlayer.seekTo((int) v);
}
}
抬起点的x坐标与按下点的X坐标所得的距离,大于0是快进,小于零是后退。
七 滑动调节音量
系统的音量有很多,包括通话音量值,系统铃声值,音乐音量值,闹铃音量值,等等吧。
做一下笔记以备以后用到
AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
max = am.getStreamMaxVolume(AudioManager.STREAM_VOICE_CALL);// 0
current= am.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
- AudioManager.STREAM_VOICE_CALL :通话音量值
- AudioManager.STREAM_SYSTEM:系统音量值
- AudioManager.STREAM_RING:系统铃声值
- AudioManager.STREAM_MUSIC:音乐音量值
- AudioManager.STREAM_ALARM:闹铃音量值
- AudioManager.STREAM_NOTIFICATION:提示声音音量值
视频播放我们用的是音乐音量值,同样的道理,我们需要把音量和高度进行关联,我们可以控件的高度闭上最大音量得出比例后就可以知道你滑动的距离占音量的多少了。
int value = mySurfaceView.getHeight()/maxVolume ;
int newVolume = (int) ((e1.getY()-e2.getY())/value+oldVolume);
mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC,newVolume,AudioManager.FLAG_PLAY_SOUND);
八 滑动调节亮度
1. 屏幕亮度的调节模式有两种
- Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC:值为1,自动调节亮度。
- Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL:值为0,手动模式。
2. 屏幕最大亮度为255, 屏幕最低亮度为0, 屏幕亮度值范围必须位于:0~255。
3. 在设置系统屏幕亮度前,需要保证AndroidManifest.xml中声明如下权限(6.0需要动态设置):
设置屏幕亮度有两种方式
- 一种是通过WindowManager去设置当前界面的亮度
WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
lp.screenBrightness = Float.valueOf(brightness) ;
activity.getWindow().setAttributes(lp);
这里有个注意点就是activity是当前的这个界面,设置的是当前的界面,离开这个界面后就不管用了。
- 第二种方式时通过修改系统数据库来设置亮度
ContentResolver contentResolver = context.getContentResolver();
try {
if(Settings.System.getInt(contentResolver,Settings.System.SCREEN_BRIGHTNESS_MODE)== Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC){
Settings.System.putInt(contentResolver,Settings.System.SCREEN_BRIGHTNESS_MODE, Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
}
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}
Settings.System.putInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS,newBrightness);
相同的道理和滑动调节音量一样也是获得屏幕的高度比上最大的亮度,然后计算滑动的距离转换成亮度是多少。(这里不多讲了)
九 按Home键后重新点开黑屏问题
为什么会出现黑屏,就是按Home键再点App回来后,只有声音没有图片的问题,因为我们用的是SurfaceView,每次点击Home键时会销毁这个SurfaceView,再回来时又会重新创建,这样我们的阿里云播放器与SurfaceView就没有绑定了,画面就没有了。
这样我们需要 给surfaceView添加mySurfaceView.getHolder().addCallback(this);
@Override
public void surfaceCreated(SurfaceHolder holder) {
if (des==true){
aliyunVodPlayer.setSurface(mySurfaceView.getHolder().getSurface());
aliyunVodPlayer.resume();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
aliyunVodPlayer.pause();
des = true;
}
我们在按home键的时候会走surfaceDestroyed。这样,我们就可以在这里做一个标识,让他暂停,然后再回来的时候就会走surfaceCreated,判断标识,然后进行处理就可以了。切记一定要重新让aliyunVodPlayer与SurfaceView进行关联,这样才能有画面也有声音。
十 Token过期问题
由于我们的视频在阿里云的服务器上存着,访问阿里云的服务器需要临时凭证,我们通过STS来获取Token,但是这个Token是有时间限制,正好阿里云的播放器给我们提供了播放视频出错时候的回调接口,我们只需要在这里面进行重新请求Token就可以了
aliyunVodPlayer.setOnErrorListener(new IAliyunVodPlayer.OnErrorListener() {
@Override
public void onError(int arg0, int arg1, String msg) {
});