Aller au contenu

Intégration de caméras IP ONVIF — Guide complet

Video Capture SDK .Net Media Blocks SDK .Net

Prise en charge multiplateforme

La découverte ONVIF et le contrôle PTZ fonctionnent à la fois sur VideoCaptureCore (Windows uniquement, DirectShow classique) et VideoCaptureCoreX / Media Blocks SDK (multiplateforme : Windows, macOS, Linux, Android et iOS via GStreamer). Consultez la matrice de prise en charge des plateformes et le guide de déploiement Linux.

Agents de codage IA : utilisez le serveur MCP VisioForge

Vous développez ceci avec Claude Code, Cursor ou un autre agent de codage IA ? Connectez-vous au serveur MCP public VisioForge à l'adresse https://mcp.visioforge.com/mcp pour des recherches API structurées, des exemples de code exécutables et des guides de déploiement — plus précis qu'un grep sur llms.txt. Aucune authentification requise.

Claude Code : claude mcp add --transport http visioforge-sdk https://mcp.visioforge.com/mcp

Table des matières

Qu'est-ce qu'ONVIF ?

ONVIF (Open Network Video Interface Forum) est un protocole standard de l'industrie qui permet une interopérabilité fluide entre les produits vidéo réseau de différents fabricants. Ce protocole définit une interface commune pour les périphériques de sécurité basés sur IP, notamment les caméras, les NVR (Network Video Recorders) et les systèmes de contrôle d'accès.

Avantages clés : - Indépendance vis-à-vis du fabricant : travaillez avec des caméras de différents fabricants via une API unifiée - Communication standardisée : méthodes cohérentes pour la découverte de périphériques, le streaming et le contrôle - Pérenne : les nouveaux périphériques compatibles ONVIF fonctionnent avec les applications existantes - Riche jeu de fonctionnalités : accès aux profils, aux flux multimédias, aux événements, au PTZ et plus

Avantages de l'intégration ONVIF

  • Neutralité fabricant : créez des applications qui fonctionnent avec des caméras de plusieurs fabricants
  • Développement pérenne : à mesure que de nouvelles caméras compatibles ONVIF entrent sur le marché, votre application les prendra en charge
  • Communication standardisée : méthodes cohérentes pour la découverte de périphériques, le streaming vidéo et les contrôles PTZ
  • Temps de développement réduit : pas besoin d'implémenter des API propriétaires pour chaque marque de caméra
  • Fonctionnalités avancées : accès aux profils, aux flux multimédias, aux événements et à la gestion des périphériques

Découverte et énumération des caméras

Découverte des caméras ONVIF sur votre réseau

La première étape du travail avec des caméras ONVIF consiste à les découvrir sur votre réseau local à l'aide du protocole WS-Discovery.

using VisioForge.Core.ONVIFDiscovery;
using VisioForge.Core.ONVIFDiscovery.Models;

private Discovery _onvifDiscovery = new Discovery();
private CancellationTokenSource _cts;

// Découvrir les caméras pendant 5 secondes
_cts = new CancellationTokenSource();

try
{
    await _onvifDiscovery.Discover(5, (device) =>
    {
        if (device.XAdresses?.Any() == true)
        {
            var address = device.XAdresses.FirstOrDefault();
            if (!string.IsNullOrEmpty(address))
            {
                Console.WriteLine($"Found camera at: {address}");
                // Ajouter à la liste de l'UI, etc.
            }
        }
    }, _cts.Token);
}
catch (OperationCanceledException)
{
    // Découverte annulée
}

Fonctionnalités clés : - Protocole WS-Discovery : découvre automatiquement les caméras compatibles ONVIF sur le réseau local - Contrôle du délai : spécifiez la durée de découverte en secondes - Rappel asynchrone : recevez les périphériques découverts en temps réel à mesure qu'ils répondent - Prise en charge de l'annulation : annulez la découverte à l'aide d'un CancellationToken

Interrogation des capacités de la caméra

Une fois découverte, vous pouvez vous connecter à une caméra et interroger ses capacités :

using VisioForge.Core.ONVIFX;

var onvifClient = new ONVIFClientX();
var result = await onvifClient.ConnectAsync(cameraUrl, username, password);

if (result)
{
    // Obtenir les informations sur le périphérique
    var deviceInfo = onvifClient.DeviceInformation;
    Console.WriteLine($"Camera: {deviceInfo?.Model}, S/N: {deviceInfo?.SerialNumber}");

    // Obtenir les profils disponibles
    var profiles = await onvifClient.GetProfilesAsync();
    if (profiles != null)
    {
        foreach (var profile in profiles)
        {
            var mediaUri = await onvifClient.GetStreamUriAsync(profile);
            if (mediaUri != null)
            {
                Console.WriteLine($"Profile: {profile.Name}, URI: {mediaUri.Uri}");
            }
        }
    }
}

Connexion aux caméras ONVIF

Connexion de base

using VisioForge.Core.ONVIFX;

// Se connecter à la caméra ONVIF
var onvifClient = new ONVIFClientX();
var connected = await onvifClient.ConnectAsync(
    "http://192.168.1.100:80/onvif/device_service", 
    "admin", 
    "password");

if (connected)
{
    Console.WriteLine("Successfully connected to camera");
}
else
{
    Console.WriteLine("Connection failed");
}

Travailler avec les profils multimédias

Les caméras ONVIF fournissent généralement plusieurs profils multimédias avec différentes résolutions, codecs et fréquences d'images.

// Obtenir tous les profils disponibles
var profiles = await onvifClient.GetProfilesAsync();

if (profiles != null && profiles.Length > 0)
{
    foreach (var profile in profiles)
    {
        Console.WriteLine($"Profile: {profile.Name}");
        Console.WriteLine($"Token: {profile.token}");

        // Obtenir l'URI du flux pour ce profil
        var mediaUri = await onvifClient.GetStreamUriAsync(profile);
        if (mediaUri != null)
        {
            Console.WriteLine($"  Stream URI: {mediaUri.Uri}");
        }
    }

    // Utiliser le premier profil
    var selectedProfile = profiles[0];
    var streamUri = await onvifClient.GetStreamUriAsync(selectedProfile);
}

Aperçu vidéo

Configuration de l'aperçu de base

using VisioForge.Core.MediaBlocks;
using VisioForge.Core.MediaBlocks.Sources;
using VisioForge.Core.MediaBlocks.VideoRendering;
using VisioForge.Core.MediaBlocks.AudioRendering;
using VisioForge.Core.Types.X.Sources;

// Créer le pipeline
var pipeline = new MediaBlocksPipeline();

// Obtenir l'URL RTSP depuis le profil ONVIF
var streamUri = await onvifClient.GetStreamUriAsync(profile);

// Créer la source RTSP
var rtspSettings = await RTSPSourceSettings.CreateAsync(
    new Uri(streamUri.Uri), 
    username, 
    password, 
    true); // activer l'audio

var rtspSource = new RTSPSourceBlock(rtspSettings);

// Créer le moteur de rendu vidéo
var videoRenderer = new VideoRendererBlock(pipeline, videoView);

// Connecter les blocs
pipeline.Connect(rtspSource.VideoOutput, videoRenderer.Input);

// Optionnel : ajouter le rendu audio
var audioRenderer = new AudioRendererBlock();
pipeline.Connect(rtspSource.AudioOutput, audioRenderer.Input);

// Démarrer l'aperçu
await pipeline.StartAsync();
using VisioForge.Core.Types.X.Sources;
using VisioForge.Core.VideoCaptureX;

// Créer le moteur de capture vidéo
var videoCapture = new VideoCaptureCoreX(videoView);

// Obtenir l'URI du flux depuis ONVIF
var streamUri = await onvifClient.GetStreamUriAsync(profile);

// Créer les paramètres de source RTSP
var rtspSettings = await RTSPSourceSettings.CreateAsync(
    new Uri(streamUri.Uri), 
    username, 
    password, 
    true); // activer l'audio

// Définir la source vidéo
videoCapture.Video_Source = rtspSettings;

// Configurer l'audio
videoCapture.Audio_Record = true;
videoCapture.Audio_Play = true;

// Démarrer l'aperçu
await videoCapture.StartAsync();

Aperçu à faible latence

Pour les applications de vidéosurveillance et de monitoring en temps réel, activez le mode à faible latence :

// Créer la source RTSP avec faible latence
var rtspSettings = await RTSPSourceSettings.CreateAsync(
    new Uri(streamUri.Uri), 
    username, 
    password, 
    true);

// Activer le mode faible latence (60-120 ms de latence totale)
rtspSettings.LowLatencyMode = true;

var rtspSource = new RTSPSourceBlock(rtspSettings);
var videoRenderer = new VideoRendererBlock(pipeline, videoView);

// Désactiver la synchronisation pour une latence encore plus faible
videoRenderer.IsSync = false;

pipeline.Connect(rtspSource.VideoOutput, videoRenderer.Input);
await pipeline.StartAsync();
// Créer la source RTSP
var rtspSettings = await RTSPSourceSettings.CreateAsync(
    new Uri(streamUri.Uri), 
    username, 
    password, 
    true);

// Activer le mode faible latence
rtspSettings.LowLatencyMode = true;

videoCapture.Video_Source = rtspSettings;
videoCapture.Audio_Record = true;
videoCapture.Audio_Play = true;

await videoCapture.StartAsync();

Contrôle PTZ (Pan-Tilt-Zoom)

Opérations PTZ de base

using VisioForge.Core.ONVIFX;
using VisioForge.Core.ONVIFX.PTZ;

// Se connecter à la caméra
var onvifClient = new ONVIFClientX();
await onvifClient.ConnectAsync(cameraUrl, username, password);

// Obtenir le token de profil
var profiles = await onvifClient.GetProfilesAsync();
var profileToken = profiles[0].token;

// La surcharge scalaire légère de ContinuousMoveAsync prend les vitesses
// pan/tilt/zoom directement (plage -1.0..1.0 ; 0 = aucun mouvement sur cet axe).

// Pan à droite
await onvifClient.ContinuousMoveAsync(profileToken, pan: 0.5f, tilt: 0f, zoom: 0f);

// Pan à gauche
await onvifClient.ContinuousMoveAsync(profileToken, pan: -0.5f, tilt: 0f, zoom: 0f);

// Tilt vers le haut
await onvifClient.ContinuousMoveAsync(profileToken, pan: 0f, tilt: 0.5f, zoom: 0f);

// Tilt vers le bas
await onvifClient.ContinuousMoveAsync(profileToken, pan: 0f, tilt: -0.5f, zoom: 0f);

// Zoom avant
await onvifClient.ContinuousMoveAsync(profileToken, pan: 0f, tilt: 0f, zoom: 0.5f);

// Zoom arrière
await onvifClient.ContinuousMoveAsync(profileToken, pan: 0f, tilt: 0f, zoom: -0.5f);

// Arrêter le mouvement sur les deux axes
await onvifClient.StopMoveAsync(profileToken, panTilt: true, zoom: true);

Préréglages PTZ

// Obtenir les préréglages disponibles
var presets = await onvifClient.GetPresetsAsync(profileToken);

foreach (var preset in presets)
{
    Console.WriteLine($"Preset: {preset.Name}, Token: {preset.token}");
}

// Aller au préréglage (position initiale)
if (presets != null && presets.Length > 0)
{
    await onvifClient.GoToPresetAsync(
        profileToken,
        presets[0].token,
        panSpeed:  1.0f,
        tiltSpeed: 1.0f,
        zoomSpeed: 1.0f);
}

// Définir la position actuelle comme préréglage
await onvifClient.SetPresetAsync(profileToken, "MyPreset");

Positionnement absolu

// Se déplacer vers une position pan + tilt + zoom absolue avec des vitesses par axe
await onvifClient.AbsoluteMoveAsync(
    profileToken,
    pan:       0.5f,
    tilt:      0.3f,
    zoom:      0.7f,
    panSpeed:  1.0f,
    tiltSpeed: 1.0f,
    zoomSpeed: 1.0f);

Actions et capacités de la caméra

Interroger les capacités de la caméra

using VisioForge.Core.ONVIFX;

var onvifClient = new ONVIFClientX();
await onvifClient.ConnectAsync(cameraUrl, username, password);

// Obtenir les informations sur le périphérique
var deviceInfo = onvifClient.DeviceInformation;
Console.WriteLine($"Manufacturer: {deviceInfo?.Manufacturer}");
Console.WriteLine($"Model: {deviceInfo?.Model}");
Console.WriteLine($"Firmware: {deviceInfo?.FirmwareVersion}");
Console.WriteLine($"Serial Number: {deviceInfo?.SerialNumber}");
Console.WriteLine($"Hardware ID: {deviceInfo?.HardwareId}");

// Obtenir les capacités des services
var capabilities = await onvifClient.GetCapabilitiesAsync();

// Vérifier la prise en charge PTZ
if (capabilities?.PTZ != null)
{
    Console.WriteLine("PTZ supported");
}

// Vérifier l'analytique
if (capabilities?.Analytics != null)
{
    Console.WriteLine("Analytics supported");
}

// Vérifier les événements
if (capabilities?.Events != null)
{
    Console.WriteLine("Events supported");
}

Redémarrer la caméra

await onvifClient.SystemRebootAsync();

Obtenir la date et l'heure système

var dateTime = await onvifClient.GetSystemDateAndTimeAsync();
Console.WriteLine($"Camera time: {dateTime}");

Transformer une caméra locale en source ONVIF

Convertissez votre webcam USB locale en flux IP que des clients ONVIF peuvent consommer. La démo console RTSP Webcam Server incluse avec Media Blocks SDK expose une caméra DirectShow en tant que point de terminaison RTSP que les enregistreurs ONVIF et logiciels VMS peuvent ingérer.

using System;
using System.Threading;
using VisioForge.Core;
using VisioForge.Core.MediaBlocks;
using VisioForge.Core.MediaBlocks.Sinks;
using VisioForge.Core.MediaBlocks.Sources;
using VisioForge.Core.MediaBlocks.VideoEncoders;
using VisioForge.Core.Types.X.Output;
using VisioForge.Core.Types.X.Sources;
using VisioForge.Core.Types.X.VideoCapture;

Console.WriteLine("Initializing VisioForge SDK.");
VisioForgeX.InitSDK();

var cameras = DeviceEnumerator.Shared.VideoSources();
Console.WriteLine("Select the web camera");
for (int i = 0; i < cameras.Length; i++)
{
    Console.WriteLine($"{i + 1}: {cameras[i].DisplayName}");
}

Console.Write("Enter the number of the camera: ");
VideoCaptureDeviceInfo cameraInfo = null;
if (int.TryParse(Console.ReadLine(), out int cameraIndex) && cameraIndex > 0 && cameraIndex <= cameras.Length)
{
    cameraInfo = cameras[cameraIndex - 1];
    Console.WriteLine($"Selected camera: {cameraInfo.DisplayName}");
}
else
{
    Console.WriteLine("Invalid selection. Exiting.");

    VisioForgeX.DestroySDK();
    return;
}

var pipeline = new MediaBlocksPipeline();

var videoSourceSettings = new VideoCaptureDeviceSourceSettings(cameraInfo);
videoSourceSettings.Format = cameraInfo.GetHDVideoFormatAndFrameRate(out var frameRate).ToFormat();
videoSourceSettings.Format.FrameRate = frameRate;

var cameraSource = new SystemVideoSourceBlock(videoSourceSettings);

var rtspServerSettings = new RTSPServerSettings(H264EncoderBlock.GetDefaultSettings(), null)
{
    Port = 8554,
};

var rtspBlock = new RTSPServerBlock(rtspServerSettings);

Console.WriteLine("RTSP Server URL: " + rtspBlock.Settings.URL);

pipeline.Connect(cameraSource.Output, rtspBlock.Input);

Console.WriteLine("Starting the pipeline...");

new Thread(() =>
{
    pipeline.Start();
}).Start();

Console.WriteLine("Pipeline started. Press any key to stop the server and exit.");
Console.ReadKey();

Console.WriteLine("Stopping the pipeline...");

pipeline.Stop();

Console.WriteLine("Pipeline stopped.");

pipeline.Dispose();

VisioForgeX.DestroySDK();
// La fonctionnalité serveur ONVIF/RTSP est fournie par Media Blocks SDK.

Bonnes pratiques

Gestion des connexions

  1. Libérez toujours correctement les clients ONVIF :

    using (var onvifClient = new ONVIFClientX())
    {
        await onvifClient.ConnectAsync(url, username, password);
        // ... utiliser le client ...
    } // Automatiquement libéré
    

  2. Gérez gracieusement les échecs de connexion :

    var maxRetries = 3;
    var retryCount = 0;
    
    while (retryCount < maxRetries)
    {
        try
        {
            var connected = await onvifClient.ConnectAsync(url, user, pass);
            if (connected)
                break;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Connection attempt {retryCount + 1} failed: {ex.Message}");
        }
    
        retryCount++;
        await Task.Delay(2000); // Attendre avant de réessayer
    }
    

  3. Utilisez des jetons d'annulation pour la découverte :

    var cts = new CancellationTokenSource();
    cts.CancelAfter(TimeSpan.FromSeconds(10));
    
    await _onvifDiscovery.Discover(10, callback, cts.Token);
    

Optimisation des performances

  1. Utilisez RTSPRAWSourceBlock pour l'enregistrement sans réencodage — réduit considérablement l'utilisation CPU
  2. N'activez le mode faible latence que lorsque c'est nécessaire — échange stabilité contre vitesse
  3. Limitez les flux simultanés en fonction des capacités matérielles
  4. Utilisez les décodeurs matériels lorsqu'ils sont disponibles :
    rtspSettings.UseGPUDecoder = true;
    

Considérations réseau

  1. Utilisez TCP pour des connexions fiables (AllowedProtocols est un enum-drapeau RTSPSourceProtocol — définissez-le pour forcer un transport spécifique) :

    rtspSettings.AllowedProtocols = RTSPSourceProtocol.TCP;
    

  2. Ajustez la latence du tampon anti-gigue (il n'y a pas de propriété Timeout autonome ; Latency contrôle le tampon anti-gigue RTSP — des valeurs plus élevées échangent la latence contre la stabilité sur les réseaux avec pertes) :

    rtspSettings.Latency = TimeSpan.FromMilliseconds(1000);
    

  3. Surveillez les déconnexions :

    pipeline.OnError += (sender, e) =>
    {
        if (e.Message.Contains("disconnect"))
        {
            // Tenter la reconnexion
        }
    };
    

Sécurité

  1. Ne codez jamais les identifiants en dur — utilisez des fichiers de configuration ou un stockage sécurisé
  2. Utilisez HTTPS pour le streaming web lorsque c'est possible
  3. Implémentez l'authentification pour les points de terminaison de streaming
  4. Validez les entrées utilisateur lors de la construction des URL
  5. Gardez les identifiants en mémoire le moins longtemps possible

Gestion des erreurs

  1. Journalisez toutes les erreurs à des fins de diagnostic :

    pipeline.OnError += (sender, e) =>
    {
        Logger.Error($"Pipeline error: {e.Message}");
    };
    

  2. Activez le mode débogage pendant le développement :

    pipeline.Debug_Mode = true;
    pipeline.Debug_Dir = @"C:\Logs\VisioForge";
    

  3. Gérez les interruptions de flux :

    // Implémenter la logique de reconnexion automatique
    var reconnectAttempts = 0;
    const int maxReconnects = 5;
    
    pipeline.OnError += async (sender, e) =>
    {
        if (reconnectAttempts < maxReconnects)
        {
            reconnectAttempts++;
            await Task.Delay(5000);
            await pipeline.StopAsync();
            await pipeline.StartAsync();
        }
    };
    

Dépannage

Problèmes courants

"Impossible de se connecter à la caméra ONVIF"

Causes possibles : - Format d'URL incorrect (devrait être : http://IP:PORT/onvif/device_service) - Identifiants incorrects - Pare-feu réseau bloquant la connexion - Service ONVIF de la caméra désactivé

Solutions :

// Essayer différents formats d'URL
var urls = new[]
{
    "http://192.168.1.100:80/onvif/device_service",
    "http://192.168.1.100:8080/onvif/device_service",
    "http://192.168.1.100/onvif/device_service"
};

foreach (var url in urls)
{
    if (await onvifClient.ConnectAsync(url, user, pass))
    {
        Console.WriteLine($"Connected using: {url}");
        break;
    }
}

"Aucune caméra découverte"

Causes possibles : - Caméras sur un sous-réseau différent - Multicast bloqué par le réseau - Pare-feu bloquant WS-Discovery

Solutions : 1. Vérifiez la configuration réseau 2. Essayez une connexion directe avec une IP connue 3. Vérifiez que la prise en charge ONVIF de la caméra est activée 4. Augmentez le délai de découverte

"Le flux ne se lit pas"

Causes possibles : - Codec non pris en charge - Bande passante réseau insuffisante - URL de flux incorrecte

Solutions :

// Lire et mettre en cache les informations du flux avant de démarrer le pipeline.
// ReadInfoAsync sonde la caméra ; GetInfo() retourne ensuite le MediaFileInfo mis en cache.
var info = await rtspSettings.ReadInfoAsync();
if (info == null)
{
    Console.WriteLine("Cannot get stream info - check URL");
    return;
}

Console.WriteLine($"Video codec: {info.VideoStreams[0].Codec}");
Console.WriteLine($"Resolution: {info.VideoStreams[0].Width}x{info.VideoStreams[0].Height}");
Console.WriteLine($"Bitrate: {info.VideoStreams[0].Bitrate}");

"Utilisation CPU élevée pendant l'enregistrement"

Causes possibles : - Réencodage inutile - Trop de flux simultanés - Décodage logiciel au lieu de matériel

Solutions : 1. Utilisez RTSPRAWSourceBlock pour l'enregistrement sans réencodage 2. Activez le décodeur matériel :

rtspSettings.UseGPUDecoder = true;
3. Limitez les flux simultanés 4. Réduisez la résolution/le débit à la caméra

"Les commandes PTZ ne fonctionnent pas"

Causes possibles : - La caméra ne prend pas en charge le PTZ - Mauvais profil sélectionné - Service PTZ désactivé

Solutions :

// Vérifier les capacités PTZ
var capabilities = await onvifClient.GetCapabilitiesAsync();
if (capabilities?.PTZ != null)
{
    Console.WriteLine("PTZ is supported");

    // Obtenir la configuration PTZ
    var profiles = await onvifClient.GetProfilesAsync();
    foreach (var profile in profiles)
    {
        Console.WriteLine($"Profile: {profile.Name}, Token: {profile.token}");
    }
}
else
{
    Console.WriteLine("PTZ not supported by this camera");
}

Outils de diagnostic

Activer la journalisation de débogage

pipeline.Debug_Mode = true;
pipeline.Debug_Dir = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), 
    "VisioForge", 
    "Logs");
videoCapture.Debug_Mode = true;
videoCapture.Debug_Dir = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), 
    "VisioForge", 
    "Logs");

Tester la connexion RTSP

// Tester si l'URL RTSP est valide
var rtspSettings = await RTSPSourceSettings.CreateAsync(
    new Uri(rtspUrl), 
    username, 
    password, 
    true);

var info = await rtspSettings.ReadInfoAsync();
if (info != null)
{
    Console.WriteLine("✓ RTSP connection successful");
    Console.WriteLine($"  Video streams: {info.VideoStreams.Count}");
    Console.WriteLine($"  Audio streams: {info.AudioStreams.Count}");

    foreach (var stream in info.VideoStreams)
    {
        Console.WriteLine($"  Video: {stream.Codec} {stream.Width}x{stream.Height}");
    }
}
else
{
    Console.WriteLine("✗ RTSP connection failed");
}

Obtenir de l'aide

Démos associées

Documentation associée