美文网首页
视频直播,点播,悬浮小窗口播放demo (使用阿里云sdk)

视频直播,点播,悬浮小窗口播放demo (使用阿里云sdk)

作者: 庞哈哈哈12138 | 来源:发表于2018-12-03 15:15 被阅读0次

    使用阿里云直播sdk demo ,支持直播,点播 视频直播与悬浮窗小窗口无缝衔接切换(一般拉流格式 rtmp m3u8等)

    直播点播提示,监听,各种状态返回以及各种提示

    视频播放基础库 支持全屏,快进,手势基础操作

    全局视频小窗口 权限判断,高斯模糊背景(可以加深颜色)

    飘心效果,还有列表单例播放视频 ,列表全屏视频,视频支持手势,进度,亮度,声音

    demo下载地址

    效果图:

    007.gif 002.gif 003.gif 004.gif 005.gif 006.gif 007.gif

    这里对直播与悬浮窗直播无缝切换说一下实现原理:

    1 ,直播组件做成单例,通过addview的形式,在悬浮窗的framelayout上增加直播view,切换正常模式也是在原页面留下的framelayout站位增加这个直播view

    /**
     * Description:初始化直播弹窗工具
     * Created by PangHaHa on 18-7-18.
     * Copyright (c) 2018 PangHaHa All rights reserved.
     */
    public class LiveUtils {
    
        //布局参数.
        private static WindowManager.LayoutParams params;
        //实例化的WindowManager.
        private static WindowManager windowManager;
        private static int statusBarHeight =-1;
        private static FrameLayout toucherLayout;
        private static ImageView imageViewClose;
    
        private static int count = 0;//点击次数
        private static long firstClick = 0;//第一次点击时间
        private static long secondClick = 0;//第二次点击时间
    
        private static float start_X = 0;
        private static float start_Y = 0;
    
    
        // 记录上次移动的位置
        private static float lastX = 0;
        private static float lastY = 0;
        private static int offset;
        // 是否是移动事件
        private static boolean isMoved = false;
        /**
         * 两次点击时间间隔,单位毫秒
         */
        private static final int totalTime = 1000;
    
        private static boolean isInit = true;
    
    
        public static void initLive(final Context context ){
            try {
    
                windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
                //赋值WindowManager&LayoutParam.
                params = new WindowManager.LayoutParams();
                //设置type.系统提示型窗口,一般都在应用程序窗口之上.
                if (Build.VERSION.SDK_INT >= 26) {//8.0新特性
                    params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
                } else {
                    params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
                }
                //设置效果为背景透明.
                params.format = PixelFormat.RGBA_8888;
                //设置flags.不可聚焦及不可使用按钮对悬浮窗进行操控.
                params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                //设置窗口坐标参考系
                params.gravity = Gravity.LEFT | Gravity.TOP;
                //用于检测状态栏高度.
                int resourceId = context.getResources().getIdentifier("status_bar_height",
                        "dimen","android");
                if (resourceId > 0) {
                    statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
                }
                offset = DensityUtil.dp2px(context, 2);//移动偏移量
                //设置原点
                params.x = getScreenWidth(context) - DensityUtil.dp2px(context, 170);
                params.y = getScreenHeight(context) - DensityUtil.dp2px(context, 100+72) ;
                //设置悬浮窗口长宽数据.
                params.width = DensityUtil.dp2px(context, 180);
                params.height = DensityUtil.dp2px(context, 100);
    
                //获取浮动窗口视图所在布局.
                toucherLayout = new FrameLayout(context);
                AliyunVodPlayerView playerView = new AliyunVodPlayerView(context);
                playerView.initVideoView(true);
                playerView.setAutoPlay(true);
                playerView.setKeepScreenOn(true);
                playerView.setTitleBarCanShow(false);
                playerView.setControlBarCanShow(false);
                AliyunLocalSource.AliyunLocalSourceBuilder alsb = new AliyunLocalSource.AliyunLocalSourceBuilder();
                alsb.setSource("http://ivi.bupt.edu.cn/hls/cctv3hd.m3u8");
                AliyunLocalSource localSource = alsb.build();
                playerView.setLiveSource(localSource);
    
                toucherLayout.addView(playerView, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT));
    
                imageViewClose = new ImageView(context);
                imageViewClose.setImageResource(R.drawable.icon_close);
                FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
                        DensityUtil.dp2px(context, 16), DensityUtil.dp2px(context, 16));
                layoutParams.gravity = Gravity.TOP | Gravity.RIGHT;
                layoutParams.rightMargin = DensityUtil.dp2px(context, 3);
                layoutParams.topMargin = DensityUtil.dp2px(context, 3);
                imageViewClose.setLayoutParams(layoutParams);
    
                toucherLayout.addView(imageViewClose,layoutParams);
    
    
                //添加toucherlayout
                if(isInit) {
                    windowManager.addView(toucherLayout,params);
                } else {
                    windowManager.updateViewLayout(toucherLayout,params);
                }
    
                //主动计算出当前View的宽高信息.
                toucherLayout.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
    
                //处理touch
                toucherLayout.setOnTouchListener(new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View view, MotionEvent event) {
    
                        switch (event.getAction()) {
                            case MotionEvent.ACTION_DOWN:
                                isMoved = false;
                                // 记录按下位置
                                lastX = event.getRawX();
                                lastY = event.getRawY();
    
                                start_X = event.getRawX();
                                start_Y = event.getRawY();
                                break;
                            case MotionEvent.ACTION_MOVE:
                                isMoved = true;
                                // 记录移动后的位置
                                float moveX = event.getRawX();
                                float moveY = event.getRawY();
                                // 获取当前窗口的布局属性, 添加偏移量, 并更新界面, 实现移动
                                params.x += (int) (moveX - lastX);
                                params.y += (int) (moveY - lastY);
                                if (toucherLayout!=null){
                                    windowManager.updateViewLayout(toucherLayout,params);
                                }
                                lastX = moveX;
                                lastY = moveY;
                                break;
                            case MotionEvent.ACTION_UP:
    
                                float fmoveX = event.getRawX();
                                float fmoveY = event.getRawY();
    
                                if (Math.abs(fmoveX-start_X)<offset && Math.abs(fmoveY-start_Y)<offset){
                                    isMoved = false;
    
                                    Intent intent = new Intent(context,MainActivity.class);
                                    context.startActivity(intent);
    
    
                                }else {
                                    isMoved = true;
                                }
                                break;
                        }
                            // 如果是移动事件, 则消费掉; 如果不是, 则由其他处理, 比如点击
                        return isMoved;
                    }
    
                });
    
                //删除
                imageViewClose.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        remove(context);
                    }
                });
            }catch (Exception e){
                e.printStackTrace();
            }
    
            isInit = false;
        }
    
        private static void remove(Context context) {
            if(windowManager != null && toucherLayout != null) {
                windowManager.removeView(toucherLayout);
                isInit = true;
            }
        }
    
        /**
         * 获取屏幕宽度(px)
         */
        private static int getScreenWidth(Context context) {
            return context.getResources().getDisplayMetrics().widthPixels;
        }
        /**
         * 获取屏幕高度(px)
         */
        private static int getScreenHeight(Context context){
            return context.getResources().getDisplayMetrics().heightPixels;
        }
    
    }
    

    2,对弹窗初始化时权限的判断 魅族和小米需要特殊处理

     private void showLiveWindow() {
            if (Build.VERSION.SDK_INT >= 23) {
                if (!Settings.canDrawOverlays(getContext())) {
                    //没有悬浮窗权限,跳转申请
                    Toast.makeText(getApplicationContext(), "请开启悬浮窗权限", Toast.LENGTH_LONG).show();
                    //魅族不支持直接打开应用设置
                    if (!MEIZU.isMeizuFlymeOS()) {
                        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName()));
                        startActivityForResult(intent, 0);
                    } else {
                        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
                        startActivityForResult(intent, 0);
                    }
                } else {
                    LiveUtils.initLive(MainActivity.this);
                    finish();
                }
            } else {
                //6.0以下 只有MUI会修改权限
                if (MIUI.rom()) {
                    if (PermissionUtils.hasPermission(getContext())) {
                        LiveUtils.initLive(MainActivity.this);
                        finish();
                    } else {
                        MIUI.req(getContext());
                    }
                } else {
                    LiveUtils.initLive(MainActivity.this);
                    finish();
                }
            }
    
        }
    

    下面是判断各种rom机型工具类

    
    import android.os.Build;
    import android.text.TextUtils;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    
    public class OsUtils {
    
        public static final String ROM_MIUI = "MIUI";
        public static final String ROM_EMUI = "EMUI";
        public static final String ROM_FLYME = "FLYME";
        public static final String ROM_OPPO = "OPPO";
        public static final String ROM_SMARTISAN = "SMARTISAN";
        public static final String ROM_VIVO = "VIVO";
        public static final String ROM_QIKU = "QIKU";
    
        private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name";
        private static final String KEY_VERSION_EMUI = "ro.build.version.emui";
        private static final String KEY_VERSION_OPPO = "ro.build.version.opporom";
        private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version";
        private static final String KEY_VERSION_VIVO = "ro.vivo.os.version";
    
        private static String sName;
        private static String sVersion;
    
        public static boolean isEmui() {
            return check(ROM_EMUI);
        }
    
        public static boolean isMiui() {
            return check(ROM_MIUI);
        }
    
        public static boolean isVivo() {
            return check(ROM_VIVO);
        }
    
        public static boolean isOppo() {
            return check(ROM_OPPO);
        }
    
        public static boolean isFlyme() {
            return check(ROM_FLYME);
        }
    
        public static boolean is360() {
            return check(ROM_QIKU) || check("360");
        }
    
        public static boolean isSmartisan() {
            return check(ROM_SMARTISAN);
        }
    
        public static String getName() {
            if (sName == null) {
                check("");
            }
            return sName;
        }
    
        public static String getVersion() {
            if (sVersion == null) {
                check("");
            }
            return sVersion;
        }
    
        public static boolean check(String rom) {
            if (sName != null) {
                return sName.equals(rom);
            }
    
            if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) {
                sName = ROM_MIUI;
            } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) {
                sName = ROM_EMUI;
            } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) {
                sName = ROM_OPPO;
            } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) {
                sName = ROM_VIVO;
            } else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) {
                sName = ROM_SMARTISAN;
            } else {
                sVersion = Build.DISPLAY;
                if (sVersion.toUpperCase().contains(ROM_FLYME)) {
                    sName = ROM_FLYME;
                } else {
                    sVersion = Build.UNKNOWN;
                    sName = Build.MANUFACTURER.toUpperCase();
                }
            }
            return sName.equals(rom);
        }
    
        public static String getProp(String name) {
            String line = null;
            BufferedReader input = null;
            try {
                Process p = Runtime.getRuntime().exec("getprop " + name);
                input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
                line = input.readLine();
                input.close();
            } catch (IOException ex) {
                return null;
            } finally {
                if (input != null) {
                    try {
                        input.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
            return line;
        }
    }
    
    

    github地址

    相关文章

      网友评论

          本文标题:视频直播,点播,悬浮小窗口播放demo (使用阿里云sdk)

          本文链接:https://www.haomeiwen.com/subject/ripycqtx.html