Android七牛拉流基础设置干货

第二次使用七牛直播SDK,在这简明扼要的描述下基础集成的几点要素,建议阅读这篇文章的阅读者先行查看官方开发文档,再回来查看这篇文章也许有可能就一步理解到位了。另附上关键代码可以直接复制使用。

如果对接中有任何问题可以前去提交七牛工单或博客下留言。

七牛拉流


    private PLVideoTextureView mVideoView; //播放器
    private MediaController mMediaController = null;  //控制器
    private int mIsLiveStreaming = 1;
    private boolean mIsActivityPaused = true;
    private boolean llSuccess = false; //拉流成功


    /* 七牛设置 str -------------------------------------------------------*/

    /**
     * 设置基本七牛基本信息-->开始拉流
     */
    public void startLL() {
        mIsLiveStreaming = 1; // 1 = 直播 / 0 = 点播
        int codec = AVOptions.MEDIA_CODEC_AUTO;  //解码方式 sw = 软解 / hw = 硬解 / auto = 自动
        setOptions(codec);
        // You can mirror the display 预览画面反转
        // mVideoView.setMirror(true);

        // You can also use a custom `MediaController` widget
        mMediaController = new MediaController(this, false, mIsLiveStreaming == 1);
        mVideoView.setMediaController(mMediaController);
        //mVideoView.setDisplayOrientation(PLVideoTextureView.ASPECT_RATIO_FIT_PARENT); //default-->ASPECT_RATIO_FIT_PARENT 画面旋转
        mVideoView.setDisplayAspectRatio(PLVideoView.ASPECT_RATIO_PAVED_PARENT);  //画面预览模式


        mVideoView.setOnInfoListener(new PLMediaPlayer.OnInfoListener() {  //播放器状态监听
            @Override
            public boolean onInfo(PLMediaPlayer plMediaPlayer, int i, int i1) {
                switch (i) {
                    case PLMediaPlayer.MEDIA_INFO_UNKNOWN:
                        logger("未知消息");
                        break;
                    case PLMediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START: //加载成功,正在播放
                        logger("第一帧视频已成功渲染");
                        llSuccess = true;
                        break;
                    case PLMediaPlayer.MEDIA_INFO_BUFFERING_START:
                        logger("开始缓冲");
                        break;
                    case PLMediaPlayer.MEDIA_INFO_BUFFERING_END:
                        logger("停止缓冲");
                        break;
                    case PLMediaPlayer.MEDIA_INFO_VIDEO_ROTATION_CHANGED:
                        logger("获取到视频的播放角度");
                        break;
                    case PLMediaPlayer.MEDIA_INFO_AUDIO_RENDERING_START:
                        logger("第一帧音频已成功播放");
                        break;
                }
                return false;
            }
        });
        mVideoView.setOnCompletionListener(new PLMediaPlayer.OnCompletionListener() {  //直播结束监听
            @Override
            public void onCompletion(PLMediaPlayer plMediaPlayer) {

            }
        });
        mVideoView.setOnErrorListener(new PLMediaPlayer.OnErrorListener() {  //直播错误监听
            @Override
            public boolean onError(PLMediaPlayer plMediaPlayer, int i) {
                boolean isNeedReconnect = false; //是否需要重新连接
                boolean customReturn = false;
                switch (i) {
                    case PLMediaPlayer.ERROR_CODE_INVALID_URI:
                        logger("Invalid URL !无效的 URL");
                        break;
                    case PLMediaPlayer.ERROR_CODE_404_NOT_FOUND:
                        logger("404 resource not found !播放资源不存在");
                        break;
                    case PLMediaPlayer.ERROR_CODE_CONNECTION_REFUSED:
                        logger("Connection refused !服务器拒绝连接");
                        break;
                    case PLMediaPlayer.ERROR_CODE_CONNECTION_TIMEOUT:
                        logger("Connection timeout !连接超时");
                        isNeedReconnect = true;
                        break;
                    case PLMediaPlayer.ERROR_CODE_EMPTY_PLAYLIST:
                        logger("Empty playlist !空的播放列表");
                        break;
                    case PLMediaPlayer.ERROR_CODE_STREAM_DISCONNECTED:
                        logger("Stream disconnected !与服务器连接断开");
                        isNeedReconnect = true;
                        break;
                    case PLMediaPlayer.ERROR_CODE_IO_ERROR:
                        logger("Network IO Error !网络异常");
                        isNeedReconnect = true;
                        break;
                    case PLMediaPlayer.ERROR_CODE_UNAUTHORIZED:
                        logger("Unauthorized Error !");
                        break;
                    case PLMediaPlayer.ERROR_CODE_PREPARE_TIMEOUT:
                        logger("Prepare timeout !未授权,播放一个禁播的流");
                        // TODO: 2017/2/16 如果主播正常断开连接,第二次及之后所有的提示将会提示这个提示
                        liveEnd2();
                        customReturn = true;
                        //isNeedReconnect = true;
                        break;
                    case PLMediaPlayer.ERROR_CODE_READ_FRAME_TIMEOUT:
                        // TODO: 2017/2/16 如果主播正常断开连接,第一次提示这个提示
                        logger("Read frame timeout !读取数据超时");
                        isNeedReconnect = true;
                        break;
                    case PLMediaPlayer.ERROR_CODE_HW_DECODE_FAILURE:
                        setOptions(AVOptions.MEDIA_CODEC_SW_DECODE);
                        isNeedReconnect = true;
                        break;
                    case PLMediaPlayer.MEDIA_ERROR_UNKNOWN:
                        logger("未知错误");
                        break;
                    default:
                        logger("unknown error !未知错误");
                        break;
                }
                // Todo pls handle the error status here, reconnect or call finish()
                if (isNeedReconnect) {
                    sendReconnectMessage();
                } else {
                    // TODO: 2017/3/19 直播错误,请手动重连...
                    if (!customReturn)
                        liveEnd();
                }
                // Return true means the error has been handled
                // If return false, then `onCompletion` will be called
                //如果返回true-->错误已被处理 / 返回false-->setOnCompletionListener上交给国家
                return true;
            }
        });

        mVideoView.setVideoPath(mLLAddress);
        mVideoView.start();
    }


    /**
     * 设置播放器参数
     */
    private void setOptions(int codecType) {
        AVOptions options = new AVOptions();

        // the unit of timeout is ms
        options.setInteger(AVOptions.KEY_PREPARE_TIMEOUT, 10 * 1000);
        options.setInteger(AVOptions.KEY_GET_AV_FRAME_TIMEOUT, 10 * 1000);
        options.setInteger(AVOptions.KEY_PROBESIZE, 128 * 1024);
        // Some optimization with buffering mechanism when be set to 1
        options.setInteger(AVOptions.KEY_LIVE_STREAMING, mIsLiveStreaming);
        if (mIsLiveStreaming == 1) {
            options.setInteger(AVOptions.KEY_DELAY_OPTIMIZATION, 1);
        }

        // 1 -> hw codec enable, 0 -> disable [recommended]
        options.setInteger(AVOptions.KEY_MEDIACODEC, codecType);

        // whether start play automatically after prepared, default value is 1
        options.setInteger(AVOptions.KEY_START_ON_PREPARED, 0);

        mVideoView.setAVOptions(options);
    }

    /**
     * 发送重连消息
     */
    private void sendReconnectMessage() {
        showToast(getStr(R.string.reconnection));
        mHandler.removeCallbacksAndMessages(null);
        mHandler.sendMessageDelayed(mHandler.obtainMessage(MESSAGE_ID_RECONNECTING), 500);
    }

    /**
     * 重连 同时对当前流是否可用做出判断
     */
    private static final int MESSAGE_ID_RECONNECTING = 0x01;
    protected Handler mHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(Message msg) {
            if (msg.what != MESSAGE_ID_RECONNECTING) {
                return;
            }
            if (mIsActivityPaused) { // TODO: 2017/2/16 同时可以增加后台确认当前主播是否在直播 (暂不使用)
                return;
            }
            if (!NetworkUtils.isAvailableByPing()) {
                sendReconnectMessage();
                return;
            }
            mVideoView.setVideoPath(mLLAddress);
            mVideoView.start();
        }
    };
    /* 七牛设置 end ---------------------------------*/


    @Override
    protected void onPause() {
        super.onPause();
        mVideoView.pause();
        mIsActivityPaused = true;
    }

    @Override
    protected void onResume() {
        super.onResume();
        mIsActivityPaused = false;
        mVideoView.start();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mVideoView.stopPlayback();
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
直播APP技术架构 直播APP涉及到如下几个方面的角色: 直播业务服务器,该服务器主要是验证客户端的权限并在权限合法之后授权客户端推流参数,客户端使用推流参数进行推流。 七牛直播系统,该系统主要根据直播业务服务器的请求来创建直播流,获取直播流信息,提取直播流回看地址等信息。 推流客户端,推流客户端主要工作是从直播业务服务器获取直播推流参数,然后将录制的视频流推送到七牛直播系统。 直播业务服务器一般由客户自行开发,用来和七牛直播系统进行交互,七牛提供服务端的SDK,客户可以很方便地使用适合自己的编程语言的SDK开发包来开发服务端API。 推流客户端一般由客户自行开发,用来和直播业务服务器交互,将视频流推送到七牛直播系统或者从直播业务服务器获取观看地址,然后从七牛直播系统根据地址获取视频内容。 直播APP业务流程 直播APP登录帐号,该账号的合法性和其相关的业务逻辑由直播业务服务器提供和验证。 直播APP从直播业务服务器获取推流的参数信息,准备使用集成在APP中的七牛推流SDK来将视频流推送到七牛直播系统 直播APP从直播业务服务器获取推流参数后,在开始推流时,发送开始信号给业务服务器,业务服务器记录下该直播过程的起始时间,并生成唯一性id给客户端 直播APP开始进行推流,推送的直播流数据将通过SDK直接发送到七牛直播系统,推流协议为RTMP。 其他的直播APP客户可以从直播业务服务器获取当前直播的RTMP或者HLS的地址进行观看,RTMP的实时性要优于HLS,另外七牛提供的直播播放器支持RTMP协议。 直播APP结束推流,同时发送停止推流信号给直播业务服务器,业务服务器记录下该直播过程的结束时间,可选性地让客户命名直播过程,方便未来回放。 直播APP本身也可以获取已直播完成的视频播放地址进行回看。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值