Lien vidéo client-serveur.

Introduction

Comme nous l’avons vu dans cet article, le Raspberry Pi offre plusieurs outils facilitant la transmission d’images vidéo. Le connecteur dédié et la librairie picamera vont nous aider dans cette tâche.

La manipulation d’images vidéo en programmation va nécessiter un lien réseau à haut débit. Le langage python3 nous offre les protocoles UDP et TCP comme mécanismes de transport. Chacun de ces protocoles présente des avantages et des inconvénients. Les logiciels présentés ici utilisent le protocole TCP.

Références

Framboiserobot.ca – Module vidéo

RaspberryPi.org – Python

RaspberryPi.org – Camera Module

Picamera – Site

Picamera – Recipes

Getting started with PiCamera

Construction des programmes

Le langage utilisé est python3. Le serveur exploite la librairie picamera pour capturer les images du module vidéo. Le client se connecte au serveur vidéo à l’aide du protocole TCP qui lui renvoie le flux de données. Le logiciel mplayer est utilisé pour visualiser les images reçues et sera contrôlé par la librairie subprocess de python3. Mplayer est offert dans toutes les distributions Linux et doit être installé manuellement par l’utilisateur.

Serveur Video TCP

Pseudo-code du serveur vidéo.

1 - Initialiser le module vidéo.
2 - Ouvrir un port TCP à l'écoute.
3 - Accepter la connexion d'un client.
4 - Acquérir les images vidéo.
5 - Envoyer les images vidéo au client.
6 - Recommencer à l'étape 4.

code source: TCP_Video_Server.zip

#!/usr/bin/python3
import socket
import time
import picamera
import sys

# global definitions
DEBUG = True
VIDEO_RESOLUTION = (640,480)
VIDEO_FRAMERATE = 20
VIDEO_FORMAT = 'h264'
VIDEO_LENGTH = -1
SERVER_IP = '0.0.0.0'
SERVER_PORT = 10002

# function
def start_video_server(ip,port):
    if DEBUG: print("[MSG]> start video server")
    with picamera.PiCamera() as camera:
        camera.resolution = VIDEO_RESOLUTION
        camera.framerate = VIDEO_FRAMERATE

        server_socket = socket.socket()
        server_socket.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, 1)
        server_socket.bind((ip,port))
        server_socket.listen(0)

        if DEBUG: print("[MSG]> listening on %s:%d" % (ip, port))

        (client_socket, client_address) = server_socket.accept()
        connection = client_socket.makefile('wb')

        if DEBUG: print("[MSG]> connection from %s:%d" % (client_address))

        try:
            if DEBUG: print("[MSG]> start video capture")
            camera.start_preview()
            time.sleep(1)
            camera.start_recording(connection, format=VIDEO_FORMAT)
            while True:
                camera.wait_recording(VIDEO_LENGTH)
                camera.stop_recording()
                if DEBUG: print("[MSG]> stop video capture")
        except:
            if DEBUG: print("[MSG]> error: exception")
            camera.stop_recording()
            connection.close()
        finally:
            if DEBUG: print("[MSG]> close network socket")
            client_socket.close()
            server_socket.close()

# main
if __name__ == "__main__":
    while 1:
        try:
            start_video_server(SERVER_IP, SERVER_PORT)
        except KeyboardInterrupt:
            if DEBUG: print("[MSG]> Ctrl-C detected ... exiting"); 
            sys.exit()
        except Exception as e:
            if DEBUG: print("[MSG]> error: exception %s" % e)
            time.sleep(1)

Client Video TCP

Pseudo-code du client vidéo .

1 - Établir une connexion avec le serveur vidéo.
2 - Ouvrir le programme de visualisation mplayer.
3 - Recevoir les images vidéo.
4 - Envoyer les images au logiciel de visualisation mplayer.
5 - Recommencer à l'étape 3.

code source: TCP_Video_Client.zip

#!/usr/bin/python3
import socket
import subprocess
import time
import sys

# global definitions
DEBUG = True
SERVER_IP = '192.168.99.1'
SERVER_PORT = 10002

# function
def start_video_client(robot_ip,robot_port):
    total_data_recv = 0
    PKT_SIZE = 1024
    cmdline = ['mplayer','-fps','40', '-xy', '800','-msglevel','all=-1','-cache','256','-']

    if DEBUG: print("[MSG]> start_video_client()")

    try:
        client_socket = socket.socket()
        client_socket.connect((robot_ip,robot_port))
        if DEBUG: 
            print("[MSG]> success: connected to {}:{}".format(robot_ip,robot_port))
    except Exception as e:
        if DEBUG: 
            print("[MSG]> error: {}".format(str(e)))
            print("[MSG]> error: not connected to {}:{}".format(robot_ip,robot_port))

    try:
        player = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
        while True:
            data = client_socket.recv(PKT_SIZE)
            if not data:
                 if DEBUG: print('[MSG]> error: connection closed')
                 break
            total_data_recv += len(data)
            if DEBUG:
                print("[MSG]> {} bytes received".format(total_data_recv))
            player.stdin.write(data)
    except Exception as e:
        print("[MSG]> error: {}".format(str(e)))
    finally:
        player.terminate()
        client_socket.close()
        time.sleep(1)
        if DEBUG: print("[MSG]> video channel closed")

# main
if __name__ == "__main__":
    try:
        start_video_client(SERVER_IP, SERVER_PORT)
    except KeyboardInterrupt:
        if DEBUG: print("[MSG]> Ctrl-C detected ... exiting"); sys.exit()