一、简介
既然 webcoekt 是基于 tcp 连贯的,实践上讲所有的浏览器是能够公有协定解决二进制的,如果咱们须要播放视频,咱们能够将视频数据在后端解码后间接将图片推送到 webcoekt 前端,而后前端通过 websocket 接管图片而后将图片显示到 img 或 canvas 中即可,当然这个是我本人构想的,也是应该能够做的到了,做到如下须要以下技术支持:
- 后端间接 ffmpeg 转码为 jpeg 图片流
- 后端定制播放协定包含根本指令如 play、stop、pause、faster、slower
- 后端须要提供 websocket 反对发送图片流到前端
- 前端须要承受图片流并显示进去
后端 ffmpeg 解码这里就不阐明了,我有很多库,须要的独自分割我购买,前端的显示 jpg 流,这里要借助前端显示图片放的做法,应用图片 base64 数据!前端 HTML 显示二进制 jpeg 图片:图片流 => 二进制转 image 的 base64 编码 => 设置到 img 的 src 中,如前端代码
<body>
<img id="player" style="width:704px;height:576px"/>
</body>
二进制通过 arraybuffer 转 base64
function arrayBufferToBase64(buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
}
最初显示:
var player = document.getElementById('player');
var url= arrayBufferToBase64(data);
player.src='data:image/jpeg;base64,'+url;
当然,还有其余的形式:
var wsCtrl = new WebSocket("ws://127.0.0.1/ctrl/");
//Establish channel code
....
var wsVideo = new WebSocket("ws://127.0.0.1/video/channel1");
wsVideo.onmessage = function(evt)
{
//Method 1
document.getElementById("img1").src = URL.createObjectURL(evt.data);
//Method 2
var read = new FileReader();
read.onload = function(e)
{document.getElementById("img2").src = e.target.result;
}
read.readAsDataURL(evt.data);
}
ws.onmessage = function(evt) {if(typeof(evt.data)=="string"){//textHandler(JSON.parse(evt.data));
}else{var reader = new FileReader();
reader.onload = function(evt){if(evt.target.readyState == FileReader.DONE){
var url = evt.target.result;
alert(url);
var img = document.getElementById("imgDiv");
img.innerHTML = "<img src ="+url+"/>";
}
}
reader.readAsDataURL(evt.data);
}
};
对于 c ++ 的 websocket 开源工程:websocketpp、QWebSocketServer
二、websocket 播放图片流
多说无益,还不如痛痛快快的来一把,为了减低复杂度,我用 java 的 websocket 来实现图片流的发送 (当然 c ++ 的库我也一个实战我的项目中用过的名为 WebSocket 的封装的 dll 工程项目,须要的自行私下购买源码), 前端应用一个 img 标签展现图片,这里阐明一下,后盾模仿发送图片 (这里仅仅是图片, 不是流, 如果是流间接连续不断发送即可须要 ffmpeg 转码)
首先前端的代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>websocket 显示二进制图片流 </title>
<style type="text/css">
</style>
</head>
<script src="jquery.min.js"></script>
<script>
$(document).ready(function(){$("#send").click(function(){//var content = $("#content").val();
$.ajax({
url: "/test/send",
data: {
//content: content
content: ""
},
success: function(result) {console.log("申请胜利!");
}
});
});
});
</script>
<body>
<h1>WebSocket 播放图片 </h1>
<img id="player" style="width:500px;height:400px"/><br/>
<button id="send"> 申请图片 </button>
</body>
<script type="application/javascript">
var websocket = {send: function (str) {}};
window.onload = function () {if (!'WebSocket' in window) return;
webSocketInit();};
function webSocketInit() {
// 连贯到服务端端点
websocket = new WebSocket("ws://127.0.0.1:8080/image/show");
// 胜利建设连贯
websocket.onopen = function () {console.log("胜利连贯到服务器");
websocket.send("胜利连贯到服务器");
};
// 接管到音讯
websocket.onmessage = function (event) {
// 文本数据包
if(typeof(event.data)=="string"){// JSON.parse(evt.data)
console.log("收到服务端发送的音讯:" + event.data);
// 图片数据包 Blob
}else{var reader = new FileReader();
reader.onload = function(evt){if(evt.target.readyState == FileReader.DONE){
// base64 数据
var url = evt.target.result;
document.getElementById("player").src = url;
}
}
reader.readAsDataURL(event.data);
}
};
// 连贯产生谬误
websocket.onerror = function () {console.log("WebSocket 连贯产生谬误");
};
// 连贯敞开
websocket.onclose = function () {console.log("WebSocket 连贯敞开");
};
// 监听窗口敞开事件,当窗口敞开时,被动敞开 websocket 连贯
window.onbeforeunload = function () {websocket.close()
};
}
</script>
</html>
每次点击发送的时候就向后盾申请一张图,后盾将改图发送进来(我简略的应用 websocket 群发, 能够应用 websocket 的可变参数将 websocket 和 http 关联起来, 这个应该很容易我这里不再赘述,不理解的进群探讨 )
package com.easystudy.controller;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Random;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.easystudy.websocket.ImgEndPoint;
/**
* @文件名称: TestController.java
* @性能形容: 图片流申请申请发送接口 (websocket 发送图片到 web 端)
* @版权信息:www.easystudy.com
* @技术交换:961179337(QQ 群)
* @编写作者:lixx2048@163.com
* @联系方式:941415509(QQ)
* @开发日期:2020 年 9 月 21 日
* @历史版本:V1.0
* @备注信息:*/
@RestController
@RequestMapping("/test")
public class TestController {
/**
* @性能形容: 发送申请接口
* @版权信息:www.easystudy.com
* @编写作者:lixx2048@163.com
* @开发日期:2020 年 9 月 21 日
* @备注信息:*/
@SuppressWarnings("unused")
@GetMapping("/send")
public String reponseMsgToClient(@RequestParam(name="content", required = true)String content) throws Exception{System.out.println("开始发送图片数据");
// 随机抉择一张图片发送
int index = new Random().nextInt(4) + 1;
String imgName = index + ".jpg";
// 判断图片是否存在
URL url = getClass().getClassLoader().getResource(imgName);
File file = new File(url.getFile());
if (!file.exists()) {return "未找到图片!";}
// 创立输出图片流
InputStream in = new FileInputStream(file);
if (null == in) {return "关上文件失败!";}
// 读取图片数据
int size = (int)file.length();
byte[] buffer = new byte[ size];
int count = in.read(buffer, 0, size);
System.out.println("文件长度:" + size + ", 读取长度:" + count);
// 发送图片数据 (实践上讲应该只发对端连贯的)
ImgEndPoint.fanoutMessage(buffer);
// 敞开文件流
try {in.close();
} catch (IOException e) {e.printStackTrace();
}
// 接口响应
return "音讯【" +content+ "】发送胜利!";
}
}
我这里多一句嘴,如果是音视频利用的录像播放,这里能够应用 websocket 传输图片流,而后通过计算发送定点的图片流数据到前端来实现自定义的播放器性能(海康萤石云应用的就是 websocket 播放录像流的,做法相似)
播放成果如下:
源码获取、单干、技术交换请获取如下联系方式:
QQ 交换群:961179337
微信账号:lixiang6153
公众号:IT 技术快餐
电子邮箱:lixx2048@163.com