作者:vivo 互联网服务器团队-Li Guolin 
一、前言
二、推拉流模型
三、搭建步骤
搭建直播服务器 使用OBS进行推流 直播流如何观看 直播间消息的实现 
docker run -p 1935:1935 -p 7001:7001 -p 7002:7002 -p 8090:8090 -d gwuhaolin/livego
8090:HTTP 管理访问监听地址 
1935:RTMP 服务监听地址 
7001:HTTP-FLV 服务监听地址 
7002:HLS 服务监听地址 
{"status": 200,"data": "rfBd56ti2SMtYvSgD5xAV0YU99zampta7Z7S575KLkIZ9PYk"}
CBR(Constant Bitrate)恒定码率,一定时间范围内比特率基本保持恒定。使用该模式时,在视频动态画面较多的场景下,图像质量会变差,而在静态画面较多的场景下,图像质量又会变好。 
VBR(Variable Bitrate)可变码率,其码率可以随着图像的复杂程度的不同而变化。使用该模式时,在图像内容比较简单的场景下,分配较少的码率,而在图像内容复杂的场景下,则分配较多的码率。这样既保证了质量,又兼顾到带宽限制,优先考虑到图像质量。 
ABR(Average Bitrate)平均比特率,是VBR的一种插值参数。简单场景分配较低码率,复杂场景分配足够码率,这一点类似VBR。同时,一定时间内平均码率又接近设置的目标码率,这一点又类似CBR。可以认为ABR是CBR和VBR的折中方案。 
CRF(Constant Rate Factor)恒定码率系数。CRF值可以理解为对视频的清晰度和流畅度期望的一个固定输出值,即无论是在复杂场景还是在简单场景下,都希望有一个稳定的主观视频质量。 
I帧(intra coded picture):最完整的画面,自带全部信息,无需参考其他帧即可解码,每个GOP都是以I帧开始; P帧(predictive coded picture):帧间预测编码帧,需要参考前面的I帧或P帧,才能进行解码,压缩率较高; B帧(bipredictive coded picture):双向预测编码帧,以前帧后帧作为参考帧,压缩率最高。 
RTMP 
HLS 
HTTP-FLV 
long time = new Date().getTime();try {// redis中插入消息数据jedisTemplate.zadd(V_UNIQUE_ROOM_ID, time, JSON.toJSONString(roomMessage));// 按照概率性的去删除redis中过期的消息数据if (probability()) {deleteOverTimeCache(V_UNIQUE_ROOM_ID);}} catch (Exception e) {log.error("message save error", e);}
private void deleteOverTimeCache(String roomId) {Long totalCount = jedisTemplate.zcard(roomId);log.info("deleteOldTimeCache size is {}", totalCount);if (totalCount < 600) {return;}// 倒序删除过期数据Settuples = jedisTemplate.zrangeWithScores(roomId, -601, -1); if (CollectionUtils.isNotEmpty(tuples)) {for (Tuple tuple : tuples) {// 这是第一个-600条的那个scoredouble score = tuple.getScore();jedisTemplate.zremrangeByScore(roomId, 0d, score);break;}}}
@Overridepublic RoomMessage queryRoomMessages(MessageMessageReq messageMessageReq) {RoomMessage result = new RoomMessage();long timestamp = messageMessageReq.getTimestamp();Settuples = ; if (timestamp == 0) {// 如果传递是0,说明这个客户端终端是第一次来轮询,我们只要返回一个最近最新的消息返回即可tuples = jedisTemplate.zrevrangeWithScores(UNIQUE_ROOM_ID, 0, 0);} else// 加上一毫秒,返回后续的消息,每次返回5个,防止客户端因为低端手机原因,过多的消息渲染不出来tuples = jedisTemplate.zrangeByScoreWithScores(UNIQUE_ROOM_ID, timestamp + 1, System.currentTimeMillis(), 0, 5);}ListeachRoomMessages = new ArrayList<>(); long lastTimestamp = 0L;if (!CollectionUtils.isEmpty(tuples)) {for (Tuple tuple : tuples) {//最后一次循环后,会把最后一条消息产生的时间戳,返回给客户端,这样下次客户端就可以拿着这个时间戳来进行查询lastTimestamp = new Double(tuple.getScore()).longValue();eachRoomMessages.add(JSON.parseObject(tuple.getElement(), EachRoomMessage.class));}}result.setTimestamp(lastTimestamp);result.setEachRoomMessages(eachRoomMessages);return result;}
四、小结
技术原创及架构实践文章,欢迎通过公众号菜单「联系我们」进行投稿。
