首页IT科技js获取video的src(js读取mjpeg视频流与物体追踪)

js获取video的src(js读取mjpeg视频流与物体追踪)

时间2025-08-04 11:03:39分类IT科技浏览5988
导读:js mjpeg buffer stream 项目要求使用http和mjpeg在页面实现实时展示视频流...

js mjpeg buffer stream

项目要求使用http和mjpeg在页面实现实时展示视频流

基础知识

流操作:ReadableStream

流操作API中的ReadableStream接口呈现了一个可读取的二进制流操作                。Fetch API 通过Response的body属性提供了一个具体的ReadableStream对象; ReadableStream.getReader()方法创建一个读取器并将流锁定于其上               ,一旦流被锁定                        ,其他读取器不能读取它        ,直到它被释放

Uint8Array && ArrayBuffer

Uint8Array 数组类型表示一个8位无符号整型数组           ,创建时内容被初始化为0                       。创建完后                        ,可以以对象的方式或使用数组下标索引的方式引用数组中的元素; ArrayBuffer 对象用来表示 「通用的               、固定长度的」原始二进制数据缓冲区        。ArrayBuffer 不能直接操作            ,而是要通过类型数组对象 或 DataView 对象来操作        ,它们会将缓冲区中的数据表示为特定的格式                        ,并通过这些格式来读写缓冲区的内容            。 new Uint8Array(new ArrayBuffer(imageLength)):创建初始化为0                ,包含imageLength字节个元素的无符号整型数组

Blob

Blob(Binary Large Object)表示二进制类型的大对象                       。在数据库管理系统中   ,将二进制数据存储为一个单一个体的集合            。Blob 通常是影像                        、声音或多媒体文件        。Blob构造函数的语法为:var aBlob = newBlob(blobParts, options); blobParts:它是一个由 ArrayBuffer                       ,ArrayBufferView                    ,Blob,DOMString 等对象构成的数组                       。DOMStrings 会被编码为 UTF-8                。 options:一个可选的对象 在浏览器中                   ,我们使用 URL.createObjectURL 方法来创建 Blob URL                        ,该方法接收一个 Blob 对象    ,并为其创建一个唯一的 URL    。浏览器内部为每个通过 URL.createObjectURL 生成的 URL 存储了一个 「URL → Blob」映射                       。因此               ,此类 URL 较短                        ,但可以访问 Blob                    。 这里我们先把响应对象转换为 ArrayBuffer 对象        ,然后通过调用 Blob 构造函数           ,把 ArrayBuffer 对象转换为 Blob 对象                        ,再利用 createObjectURL 方法创建 Object URL            ,最终实现图片预览

Canvas

在画布上定位图像—> context.drawImage(img,x,y); 在画布上定位图像       ,并规定图像的宽度和高度—> context.drawImage(img,x,y,width,height); 剪切图像                        ,并在画布上定位被剪切的部分—> context.drawImage(img,sx,sy,swidth,sheight,x,y,width,height); 绘制一个描边矩形                ,直接绘制,不需要手动调用stroke():ctx.strokeRect( 起点x轴坐标   ,起点y轴坐标                       ,宽                    ,高 )

本示例中,我们要不断地从后端读取视频流                   ,(我们读到的本质上是一帧一帧的图片)                        ,然后在页面中通过img标签展示出来    ,动态变化的图片即形成视频。

在拿到url后               ,我们使用ReadableStream.getReader()方法创建一个读取器                        ,因为需要对视频流进行操作;读出每一帧图片所携带的信息:图片本身的信息和json数据        ,这个json数据就是我们要画出的点的位置           ,但是在这里我只做一个演示                        ,json中存放了一个键值对            ,我们把键值对读出来动态展示到画布上即可                    。

js 解析 mjpeg 视频流代码: 点击查看代码 <style> .container{ width: 800px; height: 600px; position: relative; } #canvas{ position: absolute; top: 0; left: 0; } </style> <body> <div class="container"> <canvas id="canvas" ></canvas> <img id="image" /> </div> <script> const url = mjpegurl; fetch(url).then((res) => { const reader = res.body.getReader(); let lineLength = 0; let lineBuffer = new Uint8Array(new ArrayBuffer(1000)) let headers = ""; let contentLength = -1; let contentType = ""; let imageLength = -1; let imageBuffer = null; let jsonLength = -1; let jsonData = ""; let bytesRead = 0; const read = () => { reader.read().then(({done, value}) => { if(done) return for(let index = 0,len = value.length; index < len; index++) { //先读取分段的头部块                       。按行读取       ,当数据块长度未有效时                        ,表示正在读取头部块    。 if(contentLength <= 0) { lineBuffer[lineLength++] = value[index]; //每行字符长度最小为2字节                。 if(lineLength < 2) continue; //如果行首尾不是\r\n则本行未结束                ,继续读                       。 if(lineBuffer[lineLength - 2] != 0x0d || lineBuffer[lineLength - 1] != 0x0a) continue; //成功读取一行   ,转换为String类型                       ,同时把本行数据拼接到头部的字符串变量中        。 for(let i = 0; i < lineLength; i++){ headers += String.fromCharCode(lineBuffer[i]) } //检查本行是否为结束行            。当行首为\r\n时头部结束                       。 if(lineBuffer[0] === 0x0d && lineBuffer[1] === 0x0a) { //以下是解析头部数据            。 contentType = getValue(headers, "Content-Type"); contentLength = getValue(headers, "Content-length"); imageLength = getValue(headers, "Content-image-length"); jsonLength = getValue(headers, "Content-json-length"); imageBuffer = new Uint8Array(new ArrayBuffer(imageLength)); } //清空行长度                    ,用于读取下一行        。 lineLength = 0; } //读取分段的数据块                       。按数据块的长度读取                。 else if(bytesRead < contentLength) { let tempLength = imageLength + jsonLength; //先读取图片数据    。 if(bytesRead < imageLength){ imageBuffer[bytesRead] = value[index] } //图片数据后紧接着是json数据                       。 else if(bytesRead < tempLength) { jsonData += String.fromCharCode(value[index]) } bytesRead++; }else{ //把图像更新到img控件上                   。 let img = document.getElementById("image") img.src = URL.createObjectURL(new Blob([imageBuffer], {type: contentType})) //把图像更新到canvas控件上。 let ctx = document.getElementById("canvas").getContext("2d") ctx.drawImage(img, 0, 0, 800, 600); var obj = {} try { obj = JSON.parse(jsonData) } catch (error) { console.log("obj parse error", error); } for(var key in obj){ ctx.font = "24px Arial" ctx.fillStyle = "#ca0c16" ctx.fillText(`${key}:${obj[key]}`, 115, 140) } contentLength = 0; imageLength = 0; jsonLength = 0; bytesRead = 0 ; headers = ; jsonData = ; } } read(); }).catch((error) => { console.log("read error", error); }) } read() }).catch((error) => { console.error(error); }) const getValue = (headers, key) => { let value = headers.split("\n").forEach((item) => { const itemArr = item.split(":") if(itemArr[0] === key) value = itemArr[1] }) if(key.includes(length)) { return Number(value) }else{ return value; } } </script> </body>

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
win10 网络属性无法打开(win10网络属性能复制吗? win10复制网络属性能的技巧) 服务器租用租赁(租用普通服务器如何预防DdoS攻击)