网页录制gb28181录像

网页编解码

网页已经可以编解码h264,h265 等等常规编码,我们可以使用网页来进行gb28181的录像和解码以及形成文件,当然以前也可以,不过现在更为简便。需求来自于客户端不再进行更新,而使用网页版本来制作gb28181的本地录像(非服务器录像),同时创建链接可以下载,格式位webm。
以下将使用两种方式来存储录像,1 是重新编码,可以叠加数据,2 是不重新编码,我们的格式是flv ,将flv demux后直接存储

方式1 使用VideoTrackReader 和MediaStreamTrackProcessor

VideoTrackReader 根据文档已经deprecated,现在比较新的chrome版本应该使用MediaStreamTrackProcessor,并且有些函数已经过时,已经变成全局函数,比如createImageBitmap,不再属于videoFrame的内部函数,取而代之请使用全局createImageBitmap。不过还是给出一段VideoTrackReader的代码

// VideoTrackReader is deprecated; use MediaStreamTrackProcessor instead.

 function startReader(stream) {
   if (videoTrackReader) {
     console.warn('VideoTrackReader ALREADY exist');
     return;
   }

   const track = stream.getVideoTracks()[0];
   videoTrackReader = new VideoTrackReader(track);
   videoTrackReader.start(async (videoFrame) => {
     if (keepAnimation) {
     // 注意videoFrame的createImageBitmap也已经过时
       const imageBitmap = await videoFrame.createImageBitmap();
       drawCanvasBitmap(imageBitmap);
       imageBitmap.close();
     }
     videoFrame.destroy();
   });
 }

使用

function startProcessor(stream) {
    if (processor) {
      console.warn('MediaStreamTrackProcessor ALREADY exist');
      return;
    }

    const track = stream.getVideoTracks()[0];
    processor = new MediaStreamTrackProcessor(track);
    writable = new WritableStream({
      start() {
        console.log('Writable start');
      },
      async write(videoFrame) {
        const imageBitmap =await createImageBitmap(videoFrame);
        drawCanvasBitmap(imageBitmap);
        imageBitmap.close();
        if (videoFrame.close) {
          videoFrame.close();
        }
        else {
          videoFrame.destroy();
        }
      },
      // stop() {
      //   console.log('Writable stop');
      // },
      close() {
        console.log('Writable close');
      },
      abort(reason) {
        console.log('Writable abort:', reason);
      },
    })

    processor.readable
      .pipeTo(writable);
  }

测试

可以使用getUserMedia 来做测试,假定视频已经在网页上播放,制作一个界面
网页录制gb28181录像_第1张图片

  async function startVideo() {
    const constraints = { video: true, audio: false };
    const stream = await navigator.mediaDevices.getUserMedia(constraints)
      .catch(err => {
        console.error('Media ERROR:', err);
        return;
      });

    video.srcObject = stream;
    await video.play().catch(err => console.error('media ERROR:', err));
  }

  async function stopVideo() {
    if (video.srcObject) {
      video.pause();
      stopMediaStream(video.srcObject);
      video.srcObject = null;
    }
  }

网页录制gb28181录像_第2张图片

点击开始录像以后,允许摄像头进行采集,如果没有摄像头,可以使用canvas,随手画上一段动画就行,下面给出一个示例

async function startDrawing() {
  const cnv = document.getElementById("src");
  const ctx = cnv.getContext("2d", { alpha: false });

  ctx.fillStyle = "white";
  const { width } = cnv;
  const { height } = cnv;
  const cx = width / 2;
  const cy = height / 2;
  const r = Math.min(width, height) / 5;
  var drawtime = 0;
  const drawOneFrame = function drawOneFrame(time) {
    //const angle = Math.PI * 2 * (time / 5000);
    //const scale = 1 + 0.3 * Math.sin(Math.PI * 2 * (time / 7000));
    ctx.save();
    ctx.fillRect(0, 0, width, height);

    ctx.translate(cx, cy);
    //ctx.rotate(angle);
    //ctx.scale(scale, scale);

    ctx.font = "30px Verdana";
    ctx.fillStyle = "black";
    const text = "this is " +drawtime++;
    const size = ctx.measureText(text).width;
    ctx.fillText(text, -size / 2, 0);
    ctx.restore();
    window.requestAnimationFrame(drawOneFrame);
  };

网页录制gb28181录像_第3张图片

以上使用不断变化的数字来代替gb28181 的播放,如上图所示。下面为播放中的界面。
网页录制gb28181录像_第4张图片

录像呈现,默认为h264

网页录制gb28181录像_第5张图片

方式2

使用接收的videoFrame去存储,比如我们是flv方式,那就是demux flv以后,装载成videoFrame,然后解码展现,可以将数据直接存储,这样可以省却编码,那么方式1的优势是什么呢?在里面可以直接叠加数据,比如AI 目标框和文字。原理和方式1 无大的差别,读者自己可以实践。demax后,可以使用EncodedVideoChunk来包装接收到的flv数据,变成了videoFrame, 然后进行pipe,如下面代码所示:

function inputChunk(data, pts, iskey) {
  console.log(data, pts, iskey)
  const chunk = new EncodedVideoChunk({
    timestamp: pts,
    type: iskey ? 'key' : 'delta',
    data: data
  });
  decoder.decode(chunk);
}

你可能感兴趣的:(前端技术,IoT,物联网,javascript,前端,开发语言,gb28181,h264)