LSS推流功能简介:

-推流 是指将音视频数据采集的数据编码成H264格式之后推送到指定的云平台上

推流功能:

1 VHLivePusher

1.1 VHLivePushConfig 参数类

VHLivePushConfig是推流功能的配置类,也是推流的核心类之一,这个类决定了你推流时一些必备的参数,如视频流的宽高、帧率、码率、编码类型、推流类型等。传递一个分辨率并创建VHLivePushConfig类 。 分辨率定义如下:

推流分辨率定义 描述
VHLivePushFormat.PUSH_MODE_SD 低清分辨率 352 * 288
VHLivePushFormat.PUSH_MODE_HD 普清分辨率 640 * 480
VHLivePushFormat.PUSH_MODE_XHD 高清分辨率 960 * 540
VHLivePushFormat.PUSH_MODE_XXHD 超清分辨率 1280 * 720
config = new VHLivePushConfig(VHLivePushFormat.PUSH_MODE_HD); //
config.screenOri = VHLivePushFormat.SCREEN_ORI_PORTRAIT //指定推流横竖屏设置 , 很重要

VHLivePushConfig 参数配置 以下是VHLivePushConfig的默认配置,如果需要修改,只需要调用相应的参数重新赋值即可

VHLivePushConfig参数 默认值 描述
screenOri VHLivePushFormat.SCREEN_ORI_LANDSPACE 推流横竖屏
videoFrameRate 15 视频帧率
videoBitrate 400 * 1000 视频码率
pushTimeout 5 * 1000 推流超时
pushReconnectTimes 5 推流重连次数
encodeColorFormat VHLivePushFormat.ENCODE_COLOR_FORMAT_YUV420SP_NV21 采集的颜色空间
streamMode VHLivePushFormat.STREAM_MODE_RTMP 推流协议
encodeType VHLivePushFormat.ENCODE_TYPE_SOFT 编码方式

1.2 初始化音视频采集器

VHVideoCaptureView 是SDK提供的一个视频采集View,VHVideoCaptureView主要操作Camera,完成推流的采集工作和对摄像头的Api调用。需要先在XML中引用View,听过FindView获取采集器的实例。VHAudioCapture 是SDK提供的音频采集类,直接初始化调用

//初始化音视频采集器
videoCapture = (VHVideoCaptureView) this.findViewById(R.id.videoCaptureView);
audioCapture = new VHAudioCapture();

1.3 初始化VHLivePusher

VHLivePusher 是发起推流的核心对象,创建时传递的参数是,视频采集器,音频采集器和VHLivePushConfig,其实就是将1.1到1.3创建对象的实例传入进去。添加监听也在此时配置,监听的描述请看,到这里初始化的操作就完成了

pusher = new VHLivePusher(videoCapture, audioCapture, config);
pusher.addListener(new MyListener());

当初始化工作完成后,就可以调用API的功能了

2: 开始推流

当一切就绪时,调用start()开始推流,此方法需要传入房间号roomId和有效的Token,这些参数在调用Api前获取,调用Start()后,如果想要了解推流的状态可以从监听中获取

	/**
	@param = roomId; //标识当前的房间号
	@param = accessToken; // 发起的Token
	*/
 void start(String roomId,String accessToken);

3: 切换前置或后置摄像头

顺序切换下一个摄像头,返回摄像头ID , 默认使用后置摄像头(注意 一定要将摄像头的权限打开)

    int switchCamera();

4: 指定打开哪个摄像头

返回摄像头ID (注意 一定要将摄像头的权限打开)

    int changeCamera(int cameraId);

5: 切换闪光灯

返回闪光灯打开状态 , 只有在后置的摄像头才能打开闪光灯

    boolean changeFlash(boolean flash);

6: 获取当前直播状态

获取直播时的状态,也可以根据监听获取状态

    Status getStatus();
	enum Status {
        IDEL,STARTED, STOPED, END
    }
状态 描述
IDEL 闲置状态 ,默认状态
STARTED 运行状态
STOPED 停止状态
END 结束状态

7: 暂停直播 / 恢复直播

调用后推流会暂停,采集工作也会停止,根据应用场景调用 ,调用后推流重新连接,采集工作重新开始,根据应用场景调用

	void pause();
	void resume();

8: 聚焦坐标

    void focus(int x, int y);

9: 设置缩放比例

    void setZoom(int level);

10: 设置view内手势是否可用(聚焦和变焦)

videoCaptureView内部实现了手势聚焦和变焦,如果不需要手势,可设置false,自行调用focus和zoom接口

    void setGestureEnable(boolean enable);

11: 设置摄像头预览模式

    void setCameraDrawMode(int mode);
预览模式 参数
VHLivePushFormat.DRAW_MODE_ASPECTFILL 将图像等比例铺满整个屏幕,多余部分裁剪掉,此模式下画面不会留黑边,但可能因为部分区域被裁剪而显示不全
VHLivePushFormat.DRAW_MODE_ASPECTFIT 将图像等比例缩放,适配最长边,缩放后的宽和高都不会超过显示区域,居中显示,画面可能会留有黑边
VHLivePushFormat.DRAW_MODE_NONE 默认

12: 结束直播

当调用stop()方法时,内部的请求地址会置空,当重新发起推流会重新获取推流地址

    void stop();

13:销毁

此方法会销毁当前已经初始化的视频采集器和音频采集器,如果需要再次使用需要重新初始化直播器

    void release();

事件处理 VHPushLiveListener 监听

在构建推流器的时候添加监听,用户根据监听回调的事件可以进行相应的处理,详细信息请查看Demo ,此处只做简单描述

错误码 描述
VHLivePusher.ERROR_PUSH 推送过程出错
VHLivePusher.ERROR_AUDIO_CAPTURE 音频采集过程出错
VHLivePusher.ERROR_VIDEO_CAPTURE 视频采集过程出错
直播事件 描述
VHLivePusher.EVENT_STATUS_STARTING 开始推流
VHLivePusher.EVENT_STATUS_STARTED 推流成功
VHLivePusher.EVENT_STATUS_STOPED 推流停止
VHLivePusher.EVENT_UPLOAD_SPEED 下载速度

Demo示例:

public class PushActivity extends Activity {

    VHVideoCaptureView videoCapture;
    IVHCapture audioCapture;
    VHLivePusher pusher;
    VHLivePushConfig config;
    //status info
    boolean isFlashOpen = false;
    int mCameraId = 0;
    boolean isAudioEnable = true;
    boolean isPushing = false;
    int mDrawMode = VHLivePushFormat.DRAW_MODE_NONE;
    //view
    TextView mSpeedView;
    ProgressBar mLoadingView;
    ImageView mPushBtn;

    private String roomId = "";
    private String accessToken = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        roomId = getIntent().getStringExtra("roomid");
        accessToken =getIntent().getStringExtra("token");
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.push_layout);
        //initview
        mSpeedView = (TextView) this.findViewById(R.id.tv_speed);
        mLoadingView = (ProgressBar) this.findViewById(R.id.pb_loading);
        mPushBtn = (ImageView) this.findViewById(R.id.btn_push);
        //配置发直播系列参数
        config = new VHLivePushConfig(VHLivePushFormat.PUSH_MODE_HD);
        config.screenOri = VHLivePushFormat.SCREEN_ORI_PORTRAIT;//横竖屏设置 重要
        //初始化音视频采集器
        videoCapture = (VHVideoCaptureView) this.findViewById(R.id.videoCaptureView);
        audioCapture = new VHAudioCapture();
        //初始化直播器
        pusher = new VHLivePusher(videoCapture, audioCapture, config);
        pusher.addListener(new MyListener());
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (pusher.getStatus() == IVHLivePusher.Status.STARTED) {
            pusher.pause();
            mPushBtn.setImageResource(R.mipmap.icon_start_bro);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (pusher.resumeAble())
            pusher.resume();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        pusher.release();
    }

    public void push(View view) {
        if (isPushing) {
            pusher.stop();
            mPushBtn.setImageResource(R.mipmap.icon_start_bro);
        } else {
            if (pusher.resumeAble())
                pusher.resume();
            else
                pusher.start(roomId, accessToken);
            mPushBtn.setImageResource(R.mipmap.icon_pause_bro);
        }

    }

    public void changeFlash(View view) {
        isFlashOpen = videoCapture.changeFlash(!isFlashOpen);
    }

    public void changeCamera(View view) {
        mCameraId = videoCapture.switchCamera();
    }

    public void changeFilter(View view) {
        int level = (++mBeautyLevel) % 6;
        if (level == 0)
            videoCapture.setFilter(null);
        else {
            videoCapture.setFilter(new VHBeautyFilter());
            videoCapture.setBeautyLevel(level);
        }
        Toast.makeText(this, "level:" + level, Toast.LENGTH_SHORT).show();
    }

    public void switchAudio(View view) {
        isAudioEnable = audioCapture.setEnable(!isAudioEnable);
    }

    public void changeMode(View view) {
        switch (mDrawMode) {
            case VHLivePushFormat.DRAW_MODE_NONE:
                mDrawMode = VHLivePushFormat.DRAW_MODE_ASPECTFILL;
                break;
            case VHLivePushFormat.DRAW_MODE_ASPECTFILL:
                mDrawMode = VHLivePushFormat.DRAW_MODE_ASPECTFIT;
                break;
            case VHLivePushFormat.DRAW_MODE_ASPECTFIT:
                mDrawMode = VHLivePushFormat.DRAW_MODE_NONE;
                break;
        }
        videoCapture.setCameraDrawMode(mDrawMode);
    }

    class MyListener implements VHPushLiveListener {

        @Override
        public void onError(int errorCode, int innerErrorCode) {
            mLoadingView.setVisibility(View.GONE);
            switch (errorCode) {
                case VHLivePusher.ERROR_PUSH://推送过程出错
                    break;
                case VHLivePusher.ERROR_AUDIO_CAPTURE://音频采集过程出错
                    break;
                case VHLivePusher.ERROR_VIDEO_CAPTURE://视频采集过程出错
                    break;
            }
            Toast.makeText(PushActivity.this, "push error,errorCode:" + errorCode + ",innerCode:" + innerErrorCode, Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onEvent(int eventCode, String eventMsg) {
            switch (eventCode) {
                case VHLivePusher.EVENT_STATUS_STARTING:
                    mLoadingView.setVisibility(View.VISIBLE);
                    break;
                case VHLivePusher.EVENT_STATUS_STARTED:
                    mLoadingView.setVisibility(View.GONE);
                    isPushing = true;
                    break;
                case VHLivePusher.EVENT_STATUS_STOPED:
                    mLoadingView.setVisibility(View.GONE);
                    isPushing = false;
                    break;
                case VHLivePusher.EVENT_UPLOAD_SPEED:
                    mSpeedView.setText(eventMsg + "kbps");
                    break;
            }
        }
    }
}