Utiliser ffmpeg pour exploiter le flux d'une caméra IP

De Wiki de Mémoire Vive
Aller à la navigation Aller à la recherche

Alors pour ceux qui cherchent un outil performant pour visualiser des flux vidéo provenant d'une caméra, il faut se pencher sur ffmpeg.

https://ffmpeg.org/download.html

ça s'installe sur Linux, Windows, etc. et permet de lire un flux avec RTSP.

Avantage : hyper-réactif, même à travers un VPN. le flux s'affiche en un instant.

Un exemple de code avec 3 caméras:

@echo off
start "" ffplay -rtsp_transport tcp -fflags nobuffer -flags low_delay -probesize 32 -an "rtsp://admin:camera79@192.168.1.201:554"
start "" ffplay -rtsp_transport tcp -fflags nobuffer -flags low_delay -probesize 32 -an "rtsp://admin:camera79@192.168.1.200/11"
start "" ffplay -rtsp_transport tcp -fflags nobuffer -flags low_delay -probesize 32 -an "rtsp://192.168.1.202:554"

A adapter pour chaque caméra.

Sous Win, il faut juste compléter le PATH pour trouver les exécutables, il y en a trois : ffmpeg, ffplay, ffprobe. C'est le second qu'on utilise pour visualiser le flux.

Pour aller plus loin, voici un script .bat qui enregistre des vidéos en fichiers mp4,

@echo off
setlocal enabledelayedexpansion

REM Dossier d'enregistrement
set BASEDIR=C:\RTSP_RECORDS\cam1
mkdir "%BASEDIR%" 2>nul

set SEGMENT_DURATION=60
set FILE_LIFETIME=3600

:LOOP
    REM Création d'un horodatage propre YYYYMMDD_HHMMSS
    for /f %%A in ('powershell -NoProfile -Command "Get-Date -Format yyyyMMdd_HHmmss"') do set TIMESTAMP=%%A

    set FILENAME=%BASEDIR%\cam1_%TIMESTAMP%.mp4

    REM Enregistrement d'un segment vidéo
    ffmpeg -rtsp_transport tcp -fflags nobuffer -i "rtsp://192.168.1.10:554/stream1" -c:v copy -an -t %SEGMENT_DURATION% "%FILENAME%"

    REM Purge des fichiers plus vieux que FILE_LIFETIME secondes
    powershell -Command "Get-ChildItem '%BASEDIR%\cam1_*.mp4' | Where-Object { ($_.CreationTimeUtc -lt (Get-Date).ToUniversalTime().AddSeconds(-%FILE_LIFETIME%)) } | Remove-Item"

goto LOOP

Ensuite on peut utiliser VLC ou SMPlayer par exemple pour relire les fichiers du dossier ainsi constitué.

Alternative avec un script powershell, qu'on peut installer ensuite comme service windows

# ==============================
#   RTSP Recorder - PowerShell
#   Version robuste avec reconnexion et log centralisé
#   Avec traces détaillées
# ==============================

$BaseDir         = "C:\RTSP_RECORDS\cam1"
$SegmentDuration = 600        # 10 minutes
$FileLifetime    = 36000      # 10 heures
$RTSP_URL        = "rtsp://192.168.1.10:554/stream1"
$FFmpegPath      = "C:\ffmpeg\bin\ffmpeg.exe"
$RetryDelay      = 10         # secondes avant de réessayer
$FFmpegTimeout   = 30         # secondes timeout connexion ffmpeg
$LogFile         = Join-Path $BaseDir "ffmpeg.log"

# ------------------------------
# Fonction de log formatée (correcte)
# ------------------------------
function Log($msg) {
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    Add-Content -Path $LogFile -Value "[$timestamp] $msg"
}

# ------------------------------
# Création du dossier si inexistant
# ------------------------------
if (!(Test-Path $BaseDir)) {
    New-Item -ItemType Directory -Path $BaseDir | Out-Null
    Log "Création du dossier $BaseDir"
} else {
    Log "Dossier existant : $BaseDir"
}

# ------------------------------
# Création du fichier log si inexistant
# ------------------------------
if (!(Test-Path $LogFile)) {
    New-Item -Path $LogFile -ItemType File | Out-Null
    Log "Création du fichier de log : $LogFile"
} else {
    Log "Fichier de log existant : $LogFile"
}

# ------------------------------
# Fonction pour tester si le flux RTSP est disponible
# ------------------------------
function Test-RTSP {
    param ([string]$url)
    try {
        $uri = [System.Uri]$url
        Log "Test RTSP sur $($uri.Host):$($uri.Port)"

        $tcp = New-Object System.Net.Sockets.TcpClient
        $async = $tcp.BeginConnect($uri.Host, $uri.Port, $null, $null)
        $wait = $async.AsyncWaitHandle.WaitOne(3000) # timeout 3s

        if (-not $wait) {
            Log "RTSP → échec : timeout"
            return $false
        }

        $tcp.EndConnect($async)
        $tcp.Close()
        Log "RTSP → OK"
        return $true
    }
    catch {
        Log "Erreur Test-RTSP : $_"
        return $false
    }
}

# ------------------------------
# Boucle infinie
# ------------------------------
Log "Service RTSP Recorder démarré"

while ($true) {

    Log "Début boucle principale"

    if (Test-RTSP -url $RTSP_URL) {

        $timestamp = (Get-Date).ToString("yyyyMMdd_HHmmss")
        $file = Join-Path $BaseDir "cam1_$timestamp.mp4"

        Log "Démarrage enregistrement : $file"

        $args = @(
            "-rtsp_transport", "tcp",
            "-fflags", "nobuffer",
            "-timeout", ($FFmpegTimeout * 1000000),  # microsecondes
            "-i", $RTSP_URL,
            "-c:v", "copy",
            "-an",
            "-t", $SegmentDuration,
            $file
        )

        try {
            Log "Lancement ffmpeg..."
            $proc = Start-Process -FilePath $FFmpegPath -ArgumentList $args -NoNewWindow -PassThru
            $proc.WaitForExit()

            Log "ffmpeg terminé (code $($proc.ExitCode))"

            if ($proc.ExitCode -ne 0) {
                Log "Erreur ffmpeg - attente $RetryDelay sec"
                Start-Sleep -Seconds $RetryDelay
            }
            else {
                Log "Segment enregistré : $file"
            }
        }
        catch {
            Log "Exception ffmpeg : $_"
            Log "Pause $RetryDelay sec"
            Start-Sleep -Seconds $RetryDelay
        }

        # ----------------------
        # Purge des fichiers anciens
        # ----------------------
        Log "Purge des anciens fichiers..."

        $limit = (Get-Date).AddSeconds(-$FileLifetime)
        $oldFiles = Get-ChildItem $BaseDir -Filter "cam1_*.mp4" |
                    Where-Object { $_.CreationTime -lt $limit }

        foreach ($f in $oldFiles) {
            Log "Suppression : $($f.FullName)"
            Remove-Item $f.FullName -Force
        }

        Log "Purge terminée"
    }
    else {
        Log "RTSP indisponible, retry dans $RetryDelay sec"
        Start-Sleep -Seconds $RetryDelay
    }

    Log "Fin boucle - pause 0.5 sec"
    Start-Sleep -Milliseconds 500
}

Création d'un service (notes rapides)

telecharger nssm et l’installer

créer un path vers le binaire nssm

créer le service “RTSP-Recorder” en précisant le path du script (C:\RTSP_RECORDS\recorder.ps1), les paramètres, le répertoire de démarrage

nssm install RTSP-Recorder

une fois créé, le lancer (tjs en powershell admin)

nssm start RTSP-Recorder


Vérifier que le service fonctionne

Get-Service RTSP-Recorder

Status Name DisplayName


---- -----------

Running RTSP-Recorder RTSP-Recorder

si modif du script alors, pour prendre en compte les modifs,

nssm stop RTSP-Recorder

nssm start RTSP-Recorder