Я пытаюсь реализовать веб-сокеты в своем интерфейсе реагирования, чтобы передать ему несколько кадров с помощью холста.
Сначала код работал нормально, и я мог очень хорошо получать данные ... но когда я необходимо добавить вызов функции из родительского компонента, я получил сообщение об ошибке:
videoSocket. js: 51 Uncaught TypeError: невозможно прочитать свойство getContext из null
Это код:
import React, { Component } from "react";
import "./canvas.css";
function b64toBlob(dataURI) {
var byteString = atob(dataURI.split(",")[0]);
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: "image/jpeg" });
} /*
ws.onmessage = function(event) {
var img=document.getElementById("video_frames");
var urlObject = URL.createObjectURL(event.data);
img.src = urlObject;
document.body.appendChild(img);
}*/
class VideoSocket extends Component {
state = {
websocket: null,
};
constructor(props) {
super(props);
var ws = new WebSocket("ws://" + props.link);
this.state = {
websocket: ws,
};
}
render() {
const self = this;
this.state.websocket.onmessage = function (event) {
var js = JSON.parse(atob(event.data.split(",")[0]));
var data = b64toBlob(js["data"]);
var personinfo = { infos: js["infos"] };
console.log(self.props);
self.props.setdata(personinfo);
var urlObject = URL.createObjectURL(data);
var canvas = document.getElementById("tools_sketch");
/*
canvas.width = window.innerWidth; // equals window dimension
canvas.height = window.innerHeight;*/
var ctx = canvas.getContext("2d");
var image = new Image();
image.onload = function () {
ctx.drawImage(
image,
0,
0,
image.width,
image.height, // source rectangle
0,
0,
canvas.width,
canvas.height
);
};
image.src = urlObject;
};
return (
<div>
<canvas
id="tools_sketch"
width={this.props.width}
height={this.props.height}
>
Sorry, your browser doesn't support the <canvas> element.
</canvas>
</div>
);
}
}
export default VideoSocket;
Когда я удаляю
self.props.setdata(personinfo);
, он работает нормально, но когда я добавляю его, независимо от того, что я пробовал, он не работает.
Я пытался добавить функцию onmessage к componentdidmount, как показано ниже, но получаю ту же ошибку.
import React, { Component } from "react";
import "./canvas.css";
function b64toBlob(dataURI) {
var byteString = atob(dataURI.split(",")[0]);
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type: "image/jpeg" });
} /*
ws.onmessage = function(event) {
var img=document.getElementById("video_frames");
var urlObject = URL.createObjectURL(event.data);
img.src = urlObject;
document.body.appendChild(img);
}*/
class VideoSocket extends Component {
state = {
websocket: null,
};
constructor(props) {
super(props);
var ws = new WebSocket("ws://" + props.link);
this.state = {
websocket: ws,
};
}
componentDidMount() {
const self = this;
this.state.websocket.onmessage = function (event) {
var js = JSON.parse(atob(event.data.split(",")[0]));
var data = b64toBlob(js["data"]);
var personinfo = { infos: js["infos"] };
console.log(self.props);
self.props.setdata(personinfo);
var urlObject = URL.createObjectURL(data);
var canvas = document.getElementById("tools_sketch");
/*
canvas.width = window.innerWidth; // equals window dimension
canvas.height = window.innerHeight;*/
var ctx = canvas.getContext("2d");
var image = new Image();
image.onload = function () {
ctx.drawImage(
image,
0,
0,
image.width,
image.height, // source rectangle
0,
0,
canvas.width,
canvas.height
);
};
image.src = urlObject;
};
}
render() {
return (
<div>
<canvas
id="tools_sketch"
width={this.props.width}
height={this.props.height}
>
Sorry, your browser doesn't support the <canvas> element.
</canvas>
</div>
);
}
}
export default VideoSocket;
Это код на стороне сервера в python:
#!/usr/bin/env python
import random
import websockets
import asyncio
import os
import numpy as np
import cv2
import json
import base64
#!/usr/bin/env python
# WS server that sends messages at random intervals
class VideoCamera(object):
def __init__(self):
self.video = cv2.VideoCapture('video2.mp4')
def __del__(self):
self.video.release()
def get_frame(self):
while True:
ret, image = self.video.read()
ret, jpeg = cv2.imencode('.jpg', image)
base6 = base64.b64encode(jpeg.tobytes())
yield base6.decode('utf-8')
def gen(camera):
while True:
image = next(camera.get_frame())
yield(image)
async def time(websocket, path):
camera = VideoCamera()
i = 0
while True:
i = i+1
data = next(gen(camera))
js = {'data': data, "infos": [
{'id': 1, 'name': 'name1'}, {'id': 2, 'name': 'name2'}]}
res_bytes = json.dumps(js).encode('utf-8')
base6 = base64.b64encode(res_bytes)
message = base6.decode('utf-8')
await websocket.send(message)
start_server = websockets.serve(time, "127.0.0.1", 5678)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
Edit : код родительского компонента:
import React, { Component, useState } from "react";
import "antd/dist/antd.css";
import VideoSocket from "../components/videoSocket";
import MyTable from "../components/table";
class Home extends Component {
state = { personinfo: {} };
constructor(props) {
super(props);
let links = {
1: "127.0.0.1:5678",
2: "127.0.0.1:5679",
3: "127.0.0.1:5680",
4: "127.0.0.1:5681",
};
const CameraId = props.match.params.cameraId;
console.log(CameraId);
let link = links[CameraId];
if (link == null) {
link = "127.0.0.1:5678";
}
let curent = link;
this.state = {
links: links,
curent: curent,
};
console.log(link);
}
setData = (personinfo) => {
this.setState({
personinfo: personinfo,
});
};
render() {
return (
<div className=".container-fluid overflow-auto" width="100%">
<div></div>
<VideoSocket
className=""
width={(window.innerWidth * 75) / 100}
height="400px"
link={this.state.curent}
setdata={this.setData}
key="1"
></VideoSocket>
<MyTable personinfo={this.state.personinfo}></MyTable>
</div>
);
}
}
export default Home;
Edit : я пытался добавить
shouldComponentUpdate() {
return false;
}
к компоненту videosocket
, но он все еще сделайте ту же задачу