一、简介
既然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播放录像流的,做法类似)
播放效果如下:
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
《魔兽世界》大逃杀!60人新游玩模式《强袭风暴》3月21日上线
暴雪近日发布了《魔兽世界》10.2.6 更新内容,新游玩模式《强袭风暴》即将于3月21 日在亚服上线,届时玩家将前往阿拉希高地展开一场 60 人大逃杀对战。
艾泽拉斯的冒险者已经征服了艾泽拉斯的大地及遥远的彼岸。他们在对抗世界上最致命的敌人时展现出过人的手腕,并且成功阻止终结宇宙等级的威胁。当他们在为即将于《魔兽世界》资料片《地心之战》中来袭的萨拉塔斯势力做战斗准备时,他们还需要在熟悉的阿拉希高地面对一个全新的敌人──那就是彼此。在《巨龙崛起》10.2.6 更新的《强袭风暴》中,玩家将会进入一个全新的海盗主题大逃杀式限时活动,其中包含极高的风险和史诗级的奖励。
《强袭风暴》不是普通的战场,作为一个独立于主游戏之外的活动,玩家可以用大逃杀的风格来体验《魔兽世界》,不分职业、不分装备(除了你在赛局中捡到的),光是技巧和战略的强弱之分就能决定出谁才是能坚持到最后的赢家。本次活动将会开放单人和双人模式,玩家在加入海盗主题的预赛大厅区域前,可以从强袭风暴角色画面新增好友。游玩游戏将可以累计名望轨迹,《巨龙崛起》和《魔兽世界:巫妖王之怒 经典版》的玩家都可以获得奖励。