Как правильно получить видеопоток из RPi в приложение iOS? - PullRequest
0 голосов
/ 14 января 2020

Я пытаюсь создать свой умный глазок. Проект основан на raspberry pi, который работает как сервер, и iphone, который работает как клиент.

На стороне RPi я слушаю сокет для клиентов, и если такой подключается, то я делаю фотографию и отправив его через сокет.

Я написал следующий сервер:

SimpleServer.py

import cv2

from ServerSocket import ServerSocket

server = ServerSocket('', 7070, cv2.VideoCapture(0), 5)
server.start()

print('Server ended')

ServerSocket.py

import socket
import select
import threading
import cv2

from PeepholeClient import PeepholeClient

class ServerSocket():
    def __init__(self, host, port, camera, max_clients=1):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.setblocking(False)
        self.sock.settimeout(10)
        print('Socket created')
        self.camera = camera
        self.host = host
        self.port = port
        self.clients_threads = []
        self.sock.bind((host, port))
        self.sock.listen(max_clients)
        print('ServerSoc initialized')

    def close(self):
        self.sock.close()
        self.sock = None
        print('Server socket closed')

    def start(self):
        print(f'ServerSoc started on port {self.port}')

        client_numb = 1
        shouldStop = False

        while not shouldStop:
            try:
                conn, addr = self.sock.accept() 
            except socket.timeout:
                print('Socket timeout error')
                conn = None
                print(f'Number of connected clients: {len(self.clients_threads)}')

            if conn:
                client = PeepholeClient(conn, addr, client_numb, self.camera)
                client.start()
                self.clients_threads.append(client)
                client_numb += 1

            for client in self.clients_threads:
                if not client.isAlive():
                    self.clients_threads.remove(client)
                if not self.clients_threads:
                    shouldStop = True

            for client in self.clients_threads:
                client.join()

            print('Clients threads joined')

            self.close()

PeepholeClient.py

import socket
import threading
import select
import cv2
import base64

class PeepholeClient(threading.Thread):
    def __init__(self, client_sock, client_addr, number, camera):
        threading.Thread.__init__(self)
        self.client_sock = client_sock
        self.client_addr = client_addr
        self.client_numb = number
        self.running = True
        self.camera = camera
        time.sleep(2)
        print('Created PeepholeClient')

    def run(self):
        print('Started PeepholeClient thread')

        while self.running:
            if self.client_sock:
                try:
                    read_ready, write_ready, except_ready = select.select([], [self.client_sock], [])

                except:
                    print(f'Thread number {self.client_numb} Select() failed on socket with {self.client_addr}')
                    self.stop()
                    Return

                if write_ready:
                    try:
                        ret, frame = self.camera.read()
                        frame = cv2.resize(frame, (640, 480))
                        encoded, buffer = cv2.imencode('.jpg', frame) 
                        jpg_as_text = base64.b64encode(buffer)
                        self.client_sock.send(jpg_as_text)

                    except:
                        print('Cannot send data to client')
                        self.stop()

                else:
                    print(f'No available write ready descriptors for client {self.client_numb}')
                    self.stop()

            else:
                print(f'There is no connection to the {self.client_addr}')
                self.stop()

        self.close()

    def close(self):
        self.client_sock.close()
        print(f'Closed client socket for client {self.client_numb}')
        self.camera.release()

    def stop(self):
        self.running = False

На стороне iPhone В настоящее время я только что подключился к RPi. Но как правильно получить изображение на стороне мобильного телефона? В области отладки я вижу, что данные были переданы. Я думал о чем-то вроде функции cycli c, отвечающей за обновление изображения, пока существует соединение. Что Вы думаете об этом? Или, может быть, вы знаете лучшее решение для потоковой передачи видео прямо с камеры Raspberry Pi в мобильное приложение iOS?

В настоящее время мой контроллер просмотра, отвечающий за получение и отображение изображения, выглядит следующим образом:

import UIKit
import Socket

class CameraViewController: UIViewController {
    @IBOutlet weak var connectedServerAddrLabel: UILabel!
    
    internal var socket: Socket? = nil
    
    @IBOutlet weak var TestImage: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        do {
            connectedServerAddrLabel!.text = String(socket!.remoteHostname)

            let answerFromServer = try socket!.readString()
            print("Answer from server: " + answerFromServer!)
        }
        catch {
            print("Problem in camera view")
        }
    }
    
    @IBAction func backButton_pressed(_ sender: Any) {
        dismiss(animated: true, completion: nil)
    }
    
    func updateUI() {
        // Update image here somehow?
    }
}

Жду любых хороших советов :) Wi sh Вам всего наилучшего!

Спасибо за совет

...