视频直播流(摄像头之类的)

一直以来没有做过页面播放直播的连接,都是播放一些用户上传的固定视频之类的,现有的video标签基本就能满足需求。但是遇到直播的连接的时候,需要一些插件进行解码辅助才能进行播放。

主流的几个直播流协议和浏览器

协议

RTSP

Http-flv

HLS

RTMP

Chorme

√ (安装插件)



√(开启Flash)

Firefox

√ (安装插件)



X

IE

√ (安装插件)

X

X

√(开启Flash)

iOS safari

√ (安装插件)

√(仅微信小程序)


√(仅微信小程序)

Andorid browser

√ (安装插件)



√(仅微信小程序)

几个协议的主要差别感兴趣的自行了解,http-flv这个流协议这次没有接触到,不知道具体的封装方式。RTSP一般协议地址的开头就是rstp://,hls就是m3u8的连接地址,RTMP的协议地址开头就是rtmp://。特征非常明显,里面的内容都是分段获取直播流的内容。

集成情况

RTSP集成

这个协议没有没有其它的方法,如果不能转码的话只能通过插件的形式才能集成,目前了解到的集成的插件是libvlc,这个插件还有一个很有意思的功能就是可以模拟各种协议的流包含但不限于rtsp、rmtp协议。因此在做集成测试的时候可以自己模拟流进行测试,不用非要找网上公开的流地址(实锤找到的基本都用不了,非常难找)。

在集成过程中遇到一个非常头疼的问题,就是chrome浏览器在40版本以后就不支持libvlc插件了…又没法对拿到的rtsp协议流转码(受制于服务器和硬件设备太老了不支持),因此只能下载一个40版本chrome安装包进行部署测试。

Http-flv集成

这个因为目前没有涉及到,所以本次其实没有做具体的集成。看了一下,只需要集成flv.js即可,网上很多集成的案例可以参考,vue集成还有专门的依赖。

HLS集成

使用vue集成hls.js即可,网上有教程,十分简单,集成进来后在获取到连接后直接调用以下代码

<video class="video-js fd-vediao-player" autoplay="autoplay" controls preload="auto"
                           muted="muted"
                           id="videoElement" ref="hlsVideo"
                    >
                    </video>
if (Hls.isSupported()) {
                        this.player = new Hls();
                        this.player.loadSource(vedioUrl);
                        this.player.attachMedia(this.$refs.hlsVideo);
                        this.player.on(Hls.Events.MANIFEST_PARSED, () => {
                            console.log('加载成功');
                            this.$refs.hlsVideo.play();
                        });
                        this.player.on(Hls.Events.ERROR, (event, data) => {
                            // console.log(event, data);
                            // 监听出错事件
                            console.log('加载失败');
                            console.log(data);
                        });
                    }
                });

但是要记住,在关闭或者切换资源的时候要销毁hls的player实例

destoryVideo() {
            if (this.player) {
                this.$refs.hlsVideo.pause();
                this.player.destroy();
                this.player = null;
            }
        }

RTMP集成

非常遗憾,这个协议的直播源在不转码的情况下必须依赖于flash,没有flash就没法支持。前后尝试了几个网上推荐的插件,都需要浏览器支持flash。因此如果允许的话,可以直接使用libvlc插件进行集成。

协议转码支持集成

ffmpeg

除了直接js插件支持和需要下载本地插件的方法以外,还有一种通用的解法就是把所有浏览器本身不支持的流进行转码,从而实现无论是什么协议都可以通用的方式。

常用的转码工具基本上都是ffmpeg,java使用maven集成的话最简单粗暴的方式就是集成全包。

<dependency>
			<groupId>org.bytedeco</groupId>
			<artifactId>javacv-platform</artifactId>
			<version>1.5.5</version>
		</dependency>

但是转码是非常消耗CPU的,一个转码在实际测试中要消耗2核心CPU接近百分之70左右。因此要做转码的话需要一台强劲的服务器做支撑…

如果自己做转码,转完以后还要考虑将流纷发给前端浏览器展示,一套搞完非常复杂而且大概率遇到一些流转换出问题的话会造成整个系统瘫痪(ffmpeg在java端调用的一些bug),并且除了重启释放掉转码进程以外目前没有其它办法,就非常不科学…

kurento

经过不断的查找和尝试,最终将转码的任务锁定到kurento这个开源项目,并且这个开源项目的服务端是有docker镜像支持的,直接docker命令启动起来即可,非常方便。

kurento提供了非常丰富的集成案例,有java的kurento-tutorial-java,js的kurento-tutorial-js,只需要clone对应的开源项目,找到需要的的案例,修改默认的客户端初始化方式,注入服务端kurento地址,启动即可(默认访问端口是8443)。

ps:一般在*app.java或者application.java中都有KurentoClient配置,默认的是连接本地的:

@Bean
  public KurentoClient kurentoClient()
  {
    return KurentoClient.create();
  }

如果要改成连接远端服务器的,只需要改成下面这样:

@Bean
    public KurentoClient kurentoClient() {
        return KurentoClient.create("wss://ip:port/kurento");
    }

这里需要注意的是,在和服务端建立连接是支持ws和wss的。所有的实例代码默认都是用的https,如果要改成http的,只需要将application.properties里面的关于ssl的配置全部注掉即可

public AbstractJsonRpcClientWebSocket(String url,
      JsonRpcWSConnectionListener connectionListener) {
.......

    if (!"ws".equalsIgnoreCase(scheme) && !"wss".equalsIgnoreCase(scheme)) {
      throw new IllegalArgumentException("Only WS(S) is supported.");
    }
.......

  }
# EMBEDDED SERVER CONFIGURATION
server.port=${demo.port}
#server.ssl.key-store=classpath:keystore.jks
#server.ssl.key-store-password=kurento
#server.ssl.key-store-type=JKS
#server.ssl.key-alias=kurento-selfsigned

配置完成后,启动访问,按照不同案例的操作进行处理即可。