<?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-05-22T17:08:19Z</updated>
	<subtitle>Historique des versions pour cette page sur le wiki</subtitle>
	<generator>MediaWiki 1.32.0</generator>
	<entry>
		<id>https://levelkro.xyz/wiki//index.php?title=MultiWebcams&amp;diff=510&amp;oldid=prev</id>
		<title>LevelKro le 26 juillet 2025 à 23:35</title>
		<link rel="alternate" type="text/html" href="https://levelkro.xyz/wiki//index.php?title=MultiWebcams&amp;diff=510&amp;oldid=prev"/>
		<updated>2025-07-26T23:35:54Z</updated>

		<summary type="html">&lt;p&gt;&lt;/p&gt;
&lt;table class=&quot;diff diff-contentalign-left&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;fr&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #222; text-align: center;&quot;&gt;← Version précédente&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #222; text-align: center;&quot;&gt;Version du 26 juillet 2025 à 23:35&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot; id=&quot;mw-diff-left-l183&quot; &gt;Ligne 183 :&lt;/td&gt;
&lt;td colspan=&quot;2&quot; class=&quot;diff-lineno&quot;&gt;Ligne 183 :&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Catégorie:Raspberry Pi]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt; &lt;/td&gt;&lt;td style=&quot;background-color: #f8f9fa; color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #eaecf0; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Catégorie:Raspberry Pi]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class='diff-marker'&gt;−&lt;/td&gt;&lt;td style=&quot;color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #ffe49c; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[&lt;del class=&quot;diffchange diffchange-inline&quot;&gt;:&lt;/del&gt;Catégorie:Programmation]]&lt;/div&gt;&lt;/td&gt;&lt;td class='diff-marker'&gt;+&lt;/td&gt;&lt;td style=&quot;color: #222; font-size: 88%; border-style: solid; border-width: 1px 1px 1px 4px; border-radius: 0.33em; border-color: #a3d3ff; vertical-align: top; white-space: pre-wrap;&quot;&gt;&lt;div&gt;[[Catégorie:Programmation]]&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;

&lt;!-- diff cache key wiki-wiki:diff::1.12:old-509:rev-510 --&gt;
&lt;/table&gt;</summary>
		<author><name>LevelKro</name></author>
		
	</entry>
	<entry>
		<id>https://levelkro.xyz/wiki//index.php?title=MultiWebcams&amp;diff=509&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... »</title>
		<link rel="alternate" type="text/html" href="https://levelkro.xyz/wiki//index.php?title=MultiWebcams&amp;diff=509&amp;oldid=prev"/>
		<updated>2025-07-26T23:35:32Z</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... »&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['url']}{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['retry'])  # Intervalle de reconnexion en secondes&lt;br /&gt;
        previously_connected = False  # Variable pour suivre l'é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['timeout']))&lt;br /&gt;
&lt;br /&gt;
            if not cap.isOpened():&lt;br /&gt;
                debug_log(f&amp;quot;[Camera {index+1}] Impossible d'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'image pour laisser place au message de statut&lt;br /&gt;
                cap.release()  # Libération de l'objet cap&lt;br /&gt;
                cap = None  # Réinitialisation de cap&lt;br /&gt;
                previously_connected = False  # Variable pour suivre l'état de la connexion&lt;br /&gt;
                time.sleep(retry_interval)  # Reconnexion après l'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'image pour laisser place au message de statut&lt;br /&gt;
                    cap.release()  # Libération de l'objet cap en cas d'erreur&lt;br /&gt;
                    cap = None  # Réinitialisation de cap&lt;br /&gt;
                    previously_connected = False  # Variable pour suivre l'état de la connexion&lt;br /&gt;
                    time.sleep(retry_interval)  # Reconnexion après l'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('Courier', int(config['font_camera']))  # Police monospace (compatible Win/Linux)&lt;br /&gt;
        font_time = pygame.font.SysFont('Courier', int(config['font_time']))  # Police plus grande pour l'heure et la date&lt;br /&gt;
        font_date = pygame.font.SysFont('Courier', int(config['font_date']))  # Police plus grande pour l'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'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'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'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>