ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

js读取mjpeg视频流与物体追踪

2022-08-12 13:01:33  阅读:189  来源: 互联网

标签:mjpeg URL ArrayBuffer 视频流 value js 对象 let Blob


js mjpeg buffer stream

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

基础知识

流操作:ReadableStream

  • 流操作API中的ReadableStream接口呈现了一个可读取的二进制流操作。Fetch API 通过Responsebody属性提供了一个具体的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" width="800" height="600"></canvas>
    <img id="image" width="800" height="600" /> 
  </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>

标签:mjpeg,URL,ArrayBuffer,视频流,value,js,对象,let,Blob
来源: https://www.cnblogs.com/rain111/p/16566501.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有