Я работаю над проектом, который транслирует видео с пи (который будет установлен на машине r c) на веб-сервер в облаке, и позволяет кому-то управлять автомобилем, используя потоковое видео и нажатия клавиш используя флягу / javascript.
Хотя я натолкнулся на довольно большую стену. Видеопоток, кажется, ставит в очередь любые нажатия клавиш, собранные javascript. Я посмотрел варианты потоков; однако, я не думаю, что это возможно, так как возвращение из функции video_feed является объектом Response, который я не уверен, как бы я мог использовать, если бы он был многопоточным. Другая идея заключалась в том, чтобы каким-то образом иметь другое приложение только для потоковой передачи видео в / video_feed, но я не уверен, возможно ли получить к нему доступ через основное приложение. У меня заканчиваются идеи ...
app.py
@app.route('/video_feed/<car_id>')
@login_required
def video_feed(car_id):
car_video_port = int(car_data['car'+str(car_id)]['video_port'])
stream_viewer = StreamViewer(port=car_video_port)
return Response(stream_viewer.gen_frame(),
mimetype='multipart/x-mixed-replace; boundary=frame')
car_movement = []
@app.route('/command_car/<string:car_id>', methods=['GET', 'POST'])
@login_required
def command_car(car_id):
new_direction = request.get_json(force=True)['direction']
up_or_down = request.get_json(force=True)['up_or_down']
if new_direction == 'stop':
format_movement('stop',car_id)
elif new_direction in car_movement and up_or_down == 'up':
car_movement.remove(new_direction)
format_movement(car_movement,car_id)
elif new_direction in car_movement and up_or_down == 'down':
pass
elif new_direction not in car_movement and up_or_down == 'up':
pass
elif new_direction not in car_movement and up_or_down == 'down':
car_movement.append(new_direction)
format_movement(car_movement,car_id)
stream_viewer.gen_frame
def gen_frame(self):
self.keep_running = True
while self.footage_socket and self.keep_running:
try:
frame = self.footage_socket.recv_string()
img = string_to_image(frame)
encodedImage = cv2.imencode(".jpg", img)[1].tostring()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + encodedImage + b'\r\n\r\n')
except KeyboardInterrupt:
cv2.destroyAllWindows()
break
print("Streaming Stopped!")
html file
{% extends "bootstrap/base.html" %}
{% block title %}
Drive Car
{% endblock %}
{% block styles %}
{{super()}}
<link rel="stylesheet" href="{{url_for('.static', filename='drive_car.css')}}">
{% endblock %}
{% block content %}
<iframe src="/video_feed/{{ car }}" width="400" height="400"></iframe>
Use the arror keys to drive the car!
<script type=text/javascript>
var forward = false;
var reverse = false;
var left = false;
var right = false;
document.onkeydown = checkKeyDown;
function checkKeyDown(e) {
e = e || window.event;
if (e.keyCode == '38') {
direction = 'forward'
if (!forward) {
forward = true;
movement = true;
}
}
else if (e.keyCode == '40') {
direction = 'reverse'
if (!reverse) {
reverse = true;
movement = true;
}
}
else if (e.keyCode == '37') {
direction = 'left'
if (!left) {
left = true;
movement = true;
}
}
else if (e.keyCode == '39') {
direction = 'right'
if (!right) {
right = true;
movement = true;
}
}
else {
movement = false;
}
if (movement) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "/command_car/{{car}}", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({"direction": direction,"up_or_down": "down"}));
}
movement = false;
}
document.onkeyup = checkKeyUp;
function checkKeyUp(e) {
e = e || window.event;
if (e.keyCode == '38') {
direction = 'forward'
forward = false;
change = true;
}
else if (e.keyCode == '40') {
direction = 'reverse'
reverse = false;
change = true;
}
else if (e.keyCode == '37') {
direction = 'left'
left = false;
change = true;
}
else if (e.keyCode == '39') {
direction = 'right'
right = false;
change = true;
}
else {
change = false;
}
if (change) {
var xhr = new XMLHttpRequest();
xhr.open("POST", "/command_car/{{car}}", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({"direction": direction,"up_or_down": "up"}));
}
change = false;
}
window.onbeforeunload = function() {
var xhr = new XMLHttpRequest();
xhr.open("POST", "/command_car/{{car}}", true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify({"direction": "stop","up_or_down": "up"}));
}
</script>
{% endblock %}