<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>https://levelkro.xyz/wiki/index.php?action=history&amp;feed=atom&amp;title=MultiWebcams</id>
	<title>MultiWebcams - Historique des versions</title>
	<link rel="self" type="application/atom+xml" href="https://levelkro.xyz/wiki/index.php?action=history&amp;feed=atom&amp;title=MultiWebcams"/>
	<link rel="alternate" type="text/html" href="https://levelkro.xyz/wiki/index.php?title=MultiWebcams&amp;action=history"/>
	<updated>2026-10-26T04:16:27Z</updated>
	<subtitle>Historique des versions pour cette page sur le wiki</subtitle>
	<generator>MediaWiki 1.46.2</generator>
	<entry>
		<id>https://levelkro.xyz/wiki/index.php?title=MultiWebcams&amp;diff=63&amp;oldid=prev</id>
		<title>LevelKro : Page créée avec « Guide pour créer un affichage multiple de caméra depuis un serveur de partage, comme FFServer.  cam.py &lt;pre&gt; import cv2 import pygame import threading import time import json import sys from datetime import datetime  # Chargement de la configuration def load_config():     try:         with open(&quot;config.json&quot;, &quot;r&quot;) as f:             return json.load(f)     except FileNotFoundError:         return {&quot;streams&quot;: [False,False,False,False,False,False,False,False]}  co... »</title>
		<link rel="alternate" type="text/html" href="https://levelkro.xyz/wiki/index.php?title=MultiWebcams&amp;diff=63&amp;oldid=prev"/>
		<updated>2026-10-25T17:45:20Z</updated>

		<summary type="html">&lt;p&gt;Page créée avec « Guide pour créer un affichage multiple de caméra depuis un serveur de partage, comme FFServer.  cam.py &amp;lt;pre&amp;gt; import cv2 import pygame import threading import time import json import sys from datetime import datetime  # Chargement de la configuration def load_config():     try:         with open(&amp;quot;config.json&amp;quot;, &amp;quot;r&amp;quot;) as f:             return json.load(f)     except FileNotFoundError:         return {&amp;quot;streams&amp;quot;: [False,False,False,False,False,False,False,False]}  co... »&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Nouvelle page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;Guide pour créer un affichage multiple de caméra depuis un serveur de partage, comme FFServer.&lt;br /&gt;
&lt;br /&gt;
cam.py&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
import cv2&lt;br /&gt;
import pygame&lt;br /&gt;
import threading&lt;br /&gt;
import time&lt;br /&gt;
import json&lt;br /&gt;
import sys&lt;br /&gt;
from datetime import datetime&lt;br /&gt;
&lt;br /&gt;
# Chargement de la configuration&lt;br /&gt;
def load_config():&lt;br /&gt;
    try:&lt;br /&gt;
        with open(&amp;quot;config.json&amp;quot;, &amp;quot;r&amp;quot;) as f:&lt;br /&gt;
            return json.load(f)&lt;br /&gt;
    except FileNotFoundError:&lt;br /&gt;
        return {&amp;quot;streams&amp;quot;: [False,False,False,False,False,False,False,False]}&lt;br /&gt;
&lt;br /&gt;
config = load_config()&lt;br /&gt;
STREAM_URLS = [f&amp;quot;{config[&amp;#039;url&amp;#039;]}{i}&amp;quot; for i in range(1, 9)]&lt;br /&gt;
active_streams = config.get(&amp;quot;streams&amp;quot;, [True] * 8)&lt;br /&gt;
&lt;br /&gt;
debug_mode = &amp;quot;--debug&amp;quot; in sys.argv&lt;br /&gt;
&lt;br /&gt;
def debug_log(message):&lt;br /&gt;
    if debug_mode:&lt;br /&gt;
        print(message)&lt;br /&gt;
&lt;br /&gt;
class VideoStreamApp:&lt;br /&gt;
    def __init__(self):&lt;br /&gt;
        pygame.init()&lt;br /&gt;
        info = pygame.display.Info()&lt;br /&gt;
        self.screen_width, self.screen_height = info.current_w, info.current_h&lt;br /&gt;
        debug_log(f&amp;quot;Résolution détectée : {self.screen_width}x{self.screen_height}&amp;quot;)&lt;br /&gt;
        self.screen = pygame.display.set_mode((self.screen_width, self.screen_height), pygame.NOFRAME)&lt;br /&gt;
        pygame.display.set_caption(&amp;quot;Surveillance Grid&amp;quot;)&lt;br /&gt;
        self.running = True&lt;br /&gt;
        self.frames = [None] * 8&lt;br /&gt;
        self.status = [&amp;quot;Démarrage&amp;quot; for _ in range(8)]&lt;br /&gt;
        self.threads = []&lt;br /&gt;
        self.start_streams()&lt;br /&gt;
    &lt;br /&gt;
    def start_streams(self):&lt;br /&gt;
        for idx, active in enumerate(active_streams):&lt;br /&gt;
            if active:&lt;br /&gt;
                self.status[idx] = f&amp;quot;Connexion à la caméra {idx+1}...&amp;quot;&lt;br /&gt;
                debug_log(f&amp;quot;Démarrage du thread pour la caméra {idx+1}&amp;quot;)&lt;br /&gt;
                thread = threading.Thread(target=self.stream_video, args=(idx,))&lt;br /&gt;
                thread.daemon = True&lt;br /&gt;
                thread.start()&lt;br /&gt;
                self.threads.append(thread)&lt;br /&gt;
            else:&lt;br /&gt;
                self.status[idx] = f&amp;quot;Caméra {idx+1} désactivé&amp;quot;  # Afficher &amp;quot;Désactivé&amp;quot; pour les caméras désactivées&lt;br /&gt;
    &lt;br /&gt;
    def stream_video(self, index):&lt;br /&gt;
        url = STREAM_URLS[index]&lt;br /&gt;
        cap = None&lt;br /&gt;
        retry_interval = int(config[&amp;#039;retry&amp;#039;])  # Intervalle de reconnexion en secondes&lt;br /&gt;
        previously_connected = False  # Variable pour suivre l&amp;#039;état de la connexion&lt;br /&gt;
&lt;br /&gt;
        while self.running:&lt;br /&gt;
            if not active_streams[index]:  # Si la caméra est désactivée, ne tente pas de se connecter&lt;br /&gt;
                time.sleep(1)&lt;br /&gt;
                continue&lt;br /&gt;
            &lt;br /&gt;
            if cap is None or not cap.isOpened():&lt;br /&gt;
                self.status[index] = f&amp;quot;Connexion à la caméra {index+1}...&amp;quot;&lt;br /&gt;
                debug_log(f&amp;quot;[Camera {index+1}] Tentative de connexion à {url}&amp;quot;)&lt;br /&gt;
                cap = cv2.VideoCapture(url)&lt;br /&gt;
                cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) &lt;br /&gt;
                time.sleep(int(config[&amp;#039;timeout&amp;#039;]))&lt;br /&gt;
&lt;br /&gt;
            if not cap.isOpened():&lt;br /&gt;
                debug_log(f&amp;quot;[Camera {index+1}] Impossible d&amp;#039;ouvrir le flux, reconnexion dans {retry_interval}s&amp;quot;)&lt;br /&gt;
                self.status[index] = f&amp;quot;Attente de reconnexion à la caméra {index+1}...&amp;quot;&lt;br /&gt;
                self.frames[index] = None  # Retirer l&amp;#039;image pour laisser place au message de statut&lt;br /&gt;
                cap.release()  # Libération de l&amp;#039;objet cap&lt;br /&gt;
                cap = None  # Réinitialisation de cap&lt;br /&gt;
                previously_connected = False  # Variable pour suivre l&amp;#039;état de la connexion&lt;br /&gt;
                time.sleep(retry_interval)  # Reconnexion après l&amp;#039;intervalle&lt;br /&gt;
&lt;br /&gt;
            else:&lt;br /&gt;
                #ret, frame = cap.read()&lt;br /&gt;
                for _ in range(1):  # Lire et ignorer les 5 dernières images pour vider le buffer&lt;br /&gt;
                    cap.grab()&lt;br /&gt;
                ret, frame = cap.read()  # Lire seulement la dernière frame après vidage du buffer&lt;br /&gt;
&lt;br /&gt;
                if ret:&lt;br /&gt;
                    # Connexion réussie, on affiche uniquement une fois&lt;br /&gt;
                    if not previously_connected:&lt;br /&gt;
                        self.status[index] = f&amp;quot;Connecté à la caméra {index+1}&amp;quot;&lt;br /&gt;
                        debug_log(f&amp;quot;[Camera {index+1}] Connexion au flux réussie&amp;quot;)&lt;br /&gt;
                        previously_connected = True&lt;br /&gt;
&lt;br /&gt;
                    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)&lt;br /&gt;
                    frame = cv2.resize(frame, (self.screen_width // 3, self.screen_height // 3))&lt;br /&gt;
                    frame = pygame.surfarray.make_surface(frame.swapaxes(0, 1))&lt;br /&gt;
                    self.frames[index] = frame&lt;br /&gt;
                    self.status[index] = &amp;quot;&amp;quot;&lt;br /&gt;
                else:&lt;br /&gt;
                    debug_log(f&amp;quot;[Camera {index+1}] Échec de réception du flux, reconnexion dans {retry_interval}s&amp;quot;)&lt;br /&gt;
                    self.status[index] = f&amp;quot;Attente de reconnexion à la caméra {index+1}...&amp;quot;&lt;br /&gt;
                    self.frames[index] = None  # Retirer l&amp;#039;image pour laisser place au message de statut&lt;br /&gt;
                    cap.release()  # Libération de l&amp;#039;objet cap en cas d&amp;#039;erreur&lt;br /&gt;
                    cap = None  # Réinitialisation de cap&lt;br /&gt;
                    previously_connected = False  # Variable pour suivre l&amp;#039;état de la connexion&lt;br /&gt;
                    time.sleep(retry_interval)  # Reconnexion après l&amp;#039;intervalle&lt;br /&gt;
        &lt;br /&gt;
        if cap:&lt;br /&gt;
            cap.release()&lt;br /&gt;
    &lt;br /&gt;
    def run(self):&lt;br /&gt;
        debug_log(&amp;quot;Boucle principale en cours&amp;quot;)&lt;br /&gt;
        font = pygame.font.SysFont(&amp;#039;Courier&amp;#039;, int(config[&amp;#039;font_camera&amp;#039;]))  # Police monospace (compatible Win/Linux)&lt;br /&gt;
        font_time = pygame.font.SysFont(&amp;#039;Courier&amp;#039;, int(config[&amp;#039;font_time&amp;#039;]))  # Police plus grande pour l&amp;#039;heure et la date&lt;br /&gt;
        font_date = pygame.font.SysFont(&amp;#039;Courier&amp;#039;, int(config[&amp;#039;font_date&amp;#039;]))  # Police plus grande pour l&amp;#039;heure et la date&lt;br /&gt;
        cell_width = self.screen_width // 3&lt;br /&gt;
        cell_height = self.screen_height // 3&lt;br /&gt;
        &lt;br /&gt;
        while self.running:&lt;br /&gt;
            self.screen.fill((0, 0, 0))&lt;br /&gt;
            for event in pygame.event.get():&lt;br /&gt;
                if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_q]):&lt;br /&gt;
                    self.running = False&lt;br /&gt;
            # Affichage des caméras&lt;br /&gt;
            for idx in range(8):&lt;br /&gt;
                x, y = (idx % 3) * cell_width, (idx // 3) * cell_height&lt;br /&gt;
                if self.frames[idx]:&lt;br /&gt;
                    self.screen.blit(self.frames[idx], (x, y))&lt;br /&gt;
                else:&lt;br /&gt;
                    # Centrage du texte&lt;br /&gt;
                    text_surface = font.render(self.status[idx], True, (255, 255, 255))&lt;br /&gt;
                    text_rect = text_surface.get_rect(center=(x + cell_width // 2, y + cell_height // 2))&lt;br /&gt;
                    self.screen.blit(text_surface, text_rect)&lt;br /&gt;
            &lt;br /&gt;
            # Affichage de l&amp;#039;heure et de la date dans la 9e case (dernière case)&lt;br /&gt;
            x, y = (8 % 3) * cell_width, (8 // 3) * cell_height  # Calcul des coordonnées de la 9e case&lt;br /&gt;
            current_time = datetime.now().strftime(&amp;quot;%H:%M:%S&amp;quot;)&lt;br /&gt;
            current_date = datetime.now().strftime(&amp;quot;%d/%m/%Y&amp;quot;)&lt;br /&gt;
            &lt;br /&gt;
            # Affichage de l&amp;#039;heure (plus grand)&lt;br /&gt;
            time_surface = font_time.render(current_time, True, (255, 255, 255))&lt;br /&gt;
            time_rect = time_surface.get_rect(center=(x + cell_width // 2, y + cell_height // 3))&lt;br /&gt;
            self.screen.blit(time_surface, time_rect)&lt;br /&gt;
            &lt;br /&gt;
            # Affichage de la date (plus grand)&lt;br /&gt;
            date_surface = font_date.render(current_date, True, (255, 255, 255))&lt;br /&gt;
            date_rect = date_surface.get_rect(center=(x + cell_width // 2, y + 2 * cell_height // 3))&lt;br /&gt;
            self.screen.blit(date_surface, date_rect)&lt;br /&gt;
            &lt;br /&gt;
            pygame.display.flip()&lt;br /&gt;
            &lt;br /&gt;
            for event in pygame.event.get():&lt;br /&gt;
                if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_q]):&lt;br /&gt;
                    self.running = False&lt;br /&gt;
        &lt;br /&gt;
        pygame.quit()&lt;br /&gt;
        debug_log(&amp;quot;Application fermée.&amp;quot;)&lt;br /&gt;
        &lt;br /&gt;
if __name__ == &amp;quot;__main__&amp;quot;:&lt;br /&gt;
    debug_log(&amp;quot;Démarrage de l&amp;#039;application&amp;quot;)&lt;br /&gt;
    app = VideoStreamApp()&lt;br /&gt;
    app.run()&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
config.json&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;streams&amp;quot;: [true, true, true, true, true, true, false, true],&lt;br /&gt;
	&amp;quot;url&amp;quot;: &amp;quot;http://192.168.0.255:8090/camera&amp;quot;,&lt;br /&gt;
	&amp;quot;timeout&amp;quot;: &amp;quot;1&amp;quot;,&lt;br /&gt;
	&amp;quot;retry&amp;quot;: &amp;quot;5&amp;quot;,&lt;br /&gt;
	&amp;quot;font_camera&amp;quot;: &amp;quot;16&amp;quot;,&lt;br /&gt;
	&amp;quot;font_time&amp;quot;: &amp;quot;90&amp;quot;,&lt;br /&gt;
	&amp;quot;font_date&amp;quot;: &amp;quot;70&amp;quot;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Catégorie:Raspberry Pi]]&lt;br /&gt;
[[Catégorie:Programmation]]&lt;/div&gt;</summary>
		<author><name>LevelKro</name></author>
	</entry>
</feed>