video-sdk/windows

Par anthropics · knowledge-work-plugins

Zoom Video SDK pour Windows - Intégration C++ pour les sessions vidéo, la capture audio/vidéo brute, le partage d'écran, l'enregistrement et la communication en temps réel

npx skills add https://github.com/anthropics/knowledge-work-plugins --skill video-sdk/windows

Zoom Video SDK - Développement Windows

Conseils d'experts pour développer avec le Zoom Video SDK sur Windows. Ce SDK permet des applications vidéo personnalisées, la capture/injection de médias bruts, l'enregistrement cloud, la diffusion en direct et la transcription en temps réel sur les plateformes Windows.

Documentation officielle : https://developers.zoom.us/docs/video-sdk/windows/ Référence API : https://marketplacefront.zoom.us/sdk/custom/windows/ Dépôt d'exemples : https://github.com/zoom/videosdk-windows-rawdata-sample

Liens rapides

Nouveau sur Video SDK ? Suivez ce parcours :

  1. Modèle d'architecture SDK - Modèle universel en 3 étapes pour TOUTE fonctionnalité
  2. Modèle de jointure de session - Code fonctionnel complet pour rejoindre une session
  3. Boucle de messages Windows - CRITIQUE : Corrigez les callbacks qui ne se déclenchent pas
  4. Rendu vidéo - Afficher la vidéo avec Canvas API

Référence :

Vous avez des problèmes ?

Créer une interface utilisateur personnalisée ?

Vue d'ensemble du SDK

Le Zoom Video SDK pour Windows est une bibliothèque C++ qui fournit :

  • Gestion de session : Rejoindre/quitter les sessions du SDK vidéo
  • Accès aux données brutes : Capturer les trames audio/vidéo brutes (YUV420, PCM)
  • Injection de données brutes : Envoyer de l'audio/vidéo personnalisé dans les sessions
  • Partage d'écran : Partager les écrans ou injecter des sources de partage personnalisées
  • Enregistrement cloud : Enregistrer les sessions sur le cloud Zoom
  • Diffusion en direct : Diffuser vers des points de terminaison RTMP (YouTube, etc.)
  • Chat et commandes : Messagerie en session et canaux de commande
  • Transcription en direct : Conversion parole-texte en temps réel
  • Sous-sessions : Support des salles de réunion
  • Tableau blanc : Fonctionnalités collaboratives de tableau blanc
  • Annotations : Annotations de partage d'écran
  • Intégration C# : Wrapper C++/CLI pour les applications .NET

Prérequis

Configuration requise du système

  • OS : Windows 10 (1903 ou version ultérieure) ou Windows 11
  • Architecture : x64 (recommandé), x86 ou ARM64
  • Visual Studio : 2019 ou 2022 (Community, Professional ou Enterprise)
  • Windows SDK : 10.0.19041.0 ou version ultérieure
  • .NET Framework : 4.8 ou version ultérieure (pour les applications C#)

Charges de travail Visual Studio

Installez ces charges de travail via Visual Studio Installer :

  1. Développement de bureau avec C++

    • Compilateur MSVC v142 ou v143
    • SDK Windows 10/11
    • Outils CMake C++ (optionnel)
  2. Développement de bureau .NET (pour les applications C#)

    • Pack de ciblage .NET Framework 4.8
    • Support C++/CLI

Démarrage rapide

Application C++

#include <windows.h>
#include "zoom_video_sdk_api.h"
#include "zoom_video_sdk_interface.h"
#include "zoom_video_sdk_delegate_interface.h"

USING_ZOOM_VIDEO_SDK_NAMESPACE

// 1. Créer l'objet SDK
IZoomVideoSDK* video_sdk_obj = CreateZoomVideoSDKObj();

// 2. Initialiser
ZoomVideoSDKInitParams init_params;
init_params.domain = L"https://zoom.us";
init_params.enableLog = true;
init_params.logFilePrefix = L"zoom_win_video";
init_params.videoRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.shareRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.audioRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;

ZoomVideoSDKErrors err = video_sdk_obj->initialize(init_params);

// 3. Ajouter l'écouteur d'événements
video_sdk_obj->addListener(myDelegate);

// 4. Rejoindre la session (IMPORTANT : définir audioOption.connect = false)
ZoomVideoSDKSessionContext session_context;
session_context.sessionName = L"my-session";
session_context.userName = L"Windows User";
session_context.token = L"your-jwt-token";
session_context.videoOption.localVideoOn = false;
session_context.audioOption.connect = false;  // Connecter l'audio après la jointure
session_context.audioOption.mute = true;

IZoomVideoSDKSession* session = video_sdk_obj->joinSession(session_context);

// 5. CRITIQUE : Ajouter la pompe de messages Windows pour que les callbacks fonctionnent
bool running = true;
while (running) {
    // Traiter les messages Windows (obligatoire pour les callbacks du SDK)
    MSG msg;
    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // Logique de votre application ici
    Sleep(10);
}

Application C

using ZoomVideoSDK;

var sdkManager = new ZoomSDKManager();
sdkManager.Initialize();
sdkManager.JoinSession("my-session", "jwt-token", "User Name", "");

Fonctionnalités clés

Fonctionnalité Description
Gestion de session Rejoindre, quitter et gérer les sessions vidéo
Vidéo brute (YUV I420) Capturer et injecter des trames vidéo brutes
Audio brut (PCM) Capturer et injecter des données audio brutes
Partage d'écran Partager les écrans ou le contenu personnalisé
Enregistrement cloud Enregistrer les sessions sur le cloud Zoom
Diffusion en direct Diffuser vers les points de terminaison RTMP
Chat Envoyer/recevoir des messages de chat
Canal de commande Messagerie de commande personnalisée
Transcription en direct Conversion parole-texte en temps réel
Support C# Intégration complète .NET Framework

Exemples d'applications

Dépôt officiel : https://github.com/zoom/videosdk-windows-rawdata-sample

Exemple Description
VSDK_SkeletonDemo Jointure de session minimale - commencez ici
VSDK_getRawVideo Capturer les trames vidéo YUV420
VSDK_getRawAudio Capturer l'audio PCM
VSDK_sendRawVideo Injecter une vidéo personnalisée (caméra virtuelle)
VSDK_sendRawAudio Injecter un audio personnalisé (microphone virtuel)
VSDK_CloudRecording Contrôle de l'enregistrement cloud
VSDK_CommandChannel Messagerie de commande personnalisée
VSDK_TranscriptionAndTranslation Légendes en direct

Voir le guide complet : Référence des exemples d'applications

Points critiques à éviter et bonnes pratiques

⚠️ CRITIQUE : Pompe de messages Windows obligatoire

Le problème n°1 qui provoque la suspension des jointures de session sans callbacks :

Toutes les applications Windows utilisant le SDK Zoom DOIVENT traiter les messages Windows. Le SDK utilise les messages Windows pour livrer les callbacks comme onSessionJoin(), onError(), etc.

Problème : Sans pompe de messages, joinSession() semble réussir mais les callbacks ne se déclenchent jamais.

Solution : Ajoutez ceci à votre boucle principale :

while (running) {
    // OBLIGATOIRE : Traiter les messages Windows
    MSG msg;
    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // Logique de votre application
    Sleep(10);
}

S'applique à :

  • Applications console (pas de pompe de messages automatique)
  • Boucles principales personnalisées
  • Applications qui n'utilisent pas WinMain/WndProc standard

Les applications GUI utilisant WinMain avec boucle de messages standard ont déjà ceci.

Stratégie de connexion audio

Bonne pratique : Définir audioOption.connect = false lors de la jointure, puis connecter l'audio dans le callback onSessionJoin().

// Lors de la jointure
session_context.audioOption.connect = false;  // Ne pas connecter encore
session_context.audioOption.mute = true;

// Dans le callback onSessionJoin()
void onSessionJoin() override {
    IZoomVideoSDKAudioHelper* audioHelper = video_sdk_obj->getAudioHelper();
    if (audioHelper) {
        audioHelper->startAudio();  // Connecter maintenant
    }
}

Pourquoi : Ce modèle est utilisé dans tous les exemples officiels de Zoom. Il sépare la jointure de session de l'initialisation de l'audio pour une meilleure fiabilité et gestion d'erreurs.

Tous les callbacks Delegate doivent être implémentés

L'interface IZoomVideoSDKDelegate a plus de 70 méthodes virtuelles pures. TOUS doivent être implémentés, même s'ils sont vides :

// Obligatoire même si vous ne les utilisez pas
void onProxyDetectComplete() override {}
void onUserWhiteboardShareStatusChanged(IZoomVideoSDKUser*, IZoomVideoSDKWhiteboardHelper*) override {}
// ... etc

Conseil : Vérifiez le zoom_video_sdk_delegate_interface.h de la version du SDK pour la liste complète. L'interface change entre les versions du SDK.

Mode mémoire pour les données brutes

Utilisez toujours le mode heap pour la mémoire des données brutes :

init_params.videoRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.shareRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;
init_params.audioRawDataMemoryMode = ZoomVideoSDKRawDataMemoryModeHeap;

Le mode stack peut causer des problèmes avec les grandes trames vidéo.

Sécurité des threads

Les callbacks du SDK s'exécutent sur les threads du SDK, pas sur votre thread principal :

  • Ne pas effectuer d'opérations lourdes dans les callbacks
  • Ne pas appeler cleanup() depuis les callbacks
  • Utiliser des files d'attente thread-safe pour passer les données au thread UI
  • Utiliser des mutexes lors de l'accès à l'état partagé

Consulter d'abord les exemples officiels

Lorsque le comportement du SDK est inattendu, toujours vérifier les exemples officiels avant le dépannage :

Exemples locaux :

  • C:\tempsdk\Zoom_VideoSDK_Windows_RawDataDemos\VSDK_SkeletonDemo\ (le plus simple)
  • C:\tempsdk\sdksamples\zoom-video-sdk-windows-2.4.12\Sample-Libs\x64\demo\

Les exemples officiels montrent les modèles corrects pour :

  • Implémentation de la pompe de messages ✓
  • Stratégie de connexion audio ✓
  • Gestion d'erreurs ✓
  • Gestion de la mémoire ✓

Rendu vidéo - Deux approches

Le SDK Zoom fournit deux façons différentes de rendre la vidéo. Choisissez en fonction de vos besoins.

🎯 Canvas API (recommandée pour la plupart des cas)

Idéale pour : Applications standard, qualité vidéo optimale, facilité de mise en œuvre

Le SDK rend la vidéo directement à votre HWND. Aucune conversion YUV nécessaire.

// S'abonner à la vidéo d'un utilisateur avec Canvas API
IZoomVideoSDKCanvas* canvas = user->GetVideoCanvas();
if (canvas) {
    ZoomVideoSDKErrors ret = canvas->subscribeWithView(
        hwnd,                                    // Votre handle de fenêtre
        ZoomVideoSDKVideoAspect_PanAndScan,     // Adapter à la fenêtre, peut recadrer
        ZoomVideoSDKResolution_Auto              // Laisser le SDK choisir la meilleure résolution
    );

    if (ret == ZoomVideoSDKErrors_Success) {
        // Le SDK rend maintenant directement à votre fenêtre !
    }
}

// Vous désabonner quand vous avez fini
canvas->unSubscribeWithView(hwnd);

Avantages :

  • Meilleure qualité - Le SDK utilise un rendu optimisé, accéléré matériellement
  • Aucun artefact - Qualité vidéo professionnelle
  • Code simple - 3 lignes pour s'abonner
  • Meilleures performances - Pas de conversion YUV gourmande en CPU
  • Mise à l'échelle automatique - Le SDK gère le redimensionnement de la fenêtre
  • Rapport d'aspect - Gestion du rapport d'aspect intégrée

Exemple de l'exemple officiel .NET :

// Aperçu de votre vidéo
IZoomVideoSDKCanvas* canvas = myself->GetVideoCanvas();
canvas->subscribeWithView(selfVideoHwnd, aspect, resolution);

// Vidéo de l'utilisateur distant
IZoomVideoSDKCanvas* remoteCanvas = remoteUser->GetVideoCanvas();
remoteCanvas->subscribeWithView(remoteVideoHwnd, aspect, resolution);

Options d'aspect vidéo :

  • ZoomVideoSDKVideoAspect_Original - Letterbox/pillarbox, pas de recadrage
  • ZoomVideoSDKVideoAspect_FullFilled - Remplir la fenêtre, peut recadrer les bords
  • ZoomVideoSDKVideoAspect_PanAndScan - Recadrage intelligent pour remplir la fenêtre
  • ZoomVideoSDKVideoAspect_LetterBox - Afficher la vidéo complète avec barres noires

Options de résolution :

  • ZoomVideoSDKResolution_90P
  • ZoomVideoSDKResolution_180P
  • ZoomVideoSDKResolution_360P - Bon équilibre
  • ZoomVideoSDKResolution_720P - Qualité HD
  • ZoomVideoSDKResolution_1080P
  • ZoomVideoSDKResolution_Auto - Laisser le SDK décider (recommandé)

🔧 Raw Data Pipe (Cas d'usage avancés)

Idéale pour : Traitement vidéo personnalisé, effets, enregistrement, vision par ordinateur

Vous recevez les trames YUV420 brutes et gérez le rendu vous-même.

// 1. Créer un delegate pour recevoir les trames
class VideoRenderer : public IZoomVideoSDKRawDataPipeDelegate {
public:
    void onRawDataFrameReceived(YUVRawDataI420* data) override {
        int width = data->GetStreamWidth();
        int height = data->GetStreamHeight();

        char* yBuffer = data->GetYBuffer();
        char* uBuffer = data->GetUBuffer();
        char* vBuffer = data->GetVBuffer();

        // Convertir YUV420 en RGB et rendre
        ConvertYUVToRGB(yBuffer, uBuffer, vBuffer, width, height);
        RenderToWindow(rgbBuffer, width, height);
    }

    void onRawDataStatusChanged(RawDataStatus status) override {
        // Gérer vidéo on/off
    }
};

// 2. S'abonner aux données brutes
IZoomVideoSDKRawDataPipe* pipe = user->GetVideoPipe();
VideoRenderer* renderer = new VideoRenderer();
pipe->subscribe(ZoomVideoSDKResolution_720P, renderer);

Conversion YUV420 vers RGB (ITU-R BT.601) :

void ConvertYUV420ToRGB(char* yBuffer, char* uBuffer, char* vBuffer, 
                        int width, int height) {
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            int yIndex = y * width + x;
            int uvIndex = (y / 2) * (width / 2) + (x / 2);

            int Y = (unsigned char)yBuffer[yIndex];
            int U = (unsigned char)uBuffer[uvIndex];
            int V = (unsigned char)vBuffer[uvIndex];

            // Conversion YUV vers RGB
            int C = Y - 16;
            int D = U - 128;
            int E = V - 128;

            int R = (298 * C + 409 * E + 128) >> 8;
            int G = (298 * C - 100 * D - 208 * E + 128) >> 8;
            int B = (298 * C + 516 * D + 128) >> 8;

            // Limiter à [0, 255]
            R = (R < 0) ? 0 : (R > 255) ? 255 : R;
            G = (G < 0) ? 0 : (G > 255) ? 255 : G;
            B = (B < 0) ? 0 : (B > 255) ? 255 : B;

            // Stocker RGB (format BGR pour Windows)
            rgbBuffer[yIndex * 3 + 0] = (unsigned char)B;
            rgbBuffer[yIndex * 3 + 1] = (unsigned char)G;
            rgbBuffer[yIndex * 3 + 2] = (unsigned char)R;
        }
    }
}

Rendre avec GDI :

void RenderToWindow(unsigned char* rgbBuffer, int width, int height) {
    HDC hdc = GetDC(hwnd);

    BITMAPINFO bmi = {};
    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth = width;
    bmi.bmiHeader.biHeight = -height;  // Négatif pour top-down
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biBitCount = 24;     // RGB 24-bit
    bmi.bmiHeader.biCompression = BI_RGB;

    RECT rect;
    GetClientRect(hwnd, &rect);

    StretchDIBits(hdc,
        0, 0, rect.right, rect.bottom,  // Destination
        0, 0, width, height,              // Source
        rgbBuffer, &bmi,
        DIB_RGB_COLORS, SRCCOPY);

    ReleaseDC(hwnd, hdc);
}

Inconvénients :

  • ⚠️ Gourmand en CPU - La conversion YUV peut causer des pertes de trames
  • ⚠️ Artefacts - Le rendu manuel peut montrer des déchirures/artefacts
  • ⚠️ Complexe - Plus de code à maintenir
  • ⚠️ Performance - Plus lent que Canvas API

Utiliser Raw Data quand :

  • Ajouter des filtres/effets vidéo
  • Enregistrer dans des formats personnalisés
  • Traitement de vision par ordinateur
  • Composition personnalisée
  • Diffuser vers des sorties non-standard

Votre vidéo vs Utilisateurs distants

Votre vidéo (votre propre caméra) :

Option A : Canvas API

IZoomVideoSDKSession* session = sdk->getSessionInfo();
IZoomVideoSDKUser* myself = session->getMyself();
IZoomVideoSDKCanvas* canvas = myself->GetVideoCanvas();
canvas->subscribeWithView(selfVideoHwnd, aspect, resolution);

Option B : Aperçu vidéo (pour vous seul)

IZoomVideoSDKVideoHelper* videoHelper = sdk->getVideoHelper();
videoHelper->startVideo();  // Démarrer la transmission

// Pour le rendu d'aperçu
videoHelper->startVideoCanvasPreview(selfVideoHwnd, aspect, resolution);

Utilisateurs distants (autres participants) :

Canvas API (recommandée) :

// Dans le callback onUserJoin
void onUserJoin(IZoomVideoSDKUserHelper*, IVideoSDKVector<IZoomVideoSDKUser*>* userList) {
    for (int i = 0; i < userList->GetCount(); i++) {
        IZoomVideoSDKUser* user = userList->GetItem(i);
        IZoomVideoSDKCanvas* canvas = user->GetVideoCanvas();
        canvas->subscribeWithView(userVideoHwnd, aspect, resolution);
    }
}

Modèle d'abonnement piloté par les événements

⚠️ CRITIQUE : L'abonnement vidéo doit être piloté par les événements et manuel.

Événements clés :

  1. onSessionJoin - S'abonner à votre vidéo
  2. onUserJoin - S'abonner aux nouveaux utilisateurs distants
  3. onUserVideoStatusChanged - Se réabonner quand la vidéo s'allume/éteint
  4. onUserLeave - Se désabonner et nettoyer

Modèle complet :

class MainFrame : public IZoomVideoSDKDelegate {
private:
    std::map<IZoomVideoSDKUser*, IZoomVideoSDKCanvas*> subscribedUsers_;
    HWND videoWindow_;

public:
    void onSessionJoin() override {
        // Démarrer votre vidéo
        IZoomVideoSDKVideoHelper* videoHelper = sdk->getVideoHelper();
        videoHelper->startVideo();

        // S'abonner à votre vidéo
        IZoomVideoSDKUser* myself = sdk->getSessionInfo()->getMyself();
        SubscribeToUser(myself);
    }

    void onUserJoin(IZoomVideoSDKUserHelper*, 
                    IVideoSDKVector<IZoomVideoSDKUser*>* userList) override {
        // Obtenir l'utilisateur actuel pour l'exclure
        IZoomVideoSDKUser* myself = sdk->getSessionInfo()->getMyself();

        for (int i = 0; i < userList->GetCount(); i++) {
            IZoomVideoSDKUser* user = userList->GetItem(i);

            // IMPORTANT : S'abonner UNIQUEMENT aux utilisateurs DISTANTS !
            if (user != myself) {
                SubscribeToUser(user);
            }
        }
    }

    void onUserVideoStatusChanged(IZoomVideoSDKVideoHelper*, 
                                  IVideoSDKVector<IZoomVideoSDKUser*>* userList) override {
        IZoomVideoSDKUser* myself = sdk->getSessionInfo()->getMyself();

        for (int i = 0; i < userList->GetCount(); i++) {
            IZoomVideoSDKUser* user = userList->GetItem(i);
            if (user != myself) {
                // Se réabonner quand le statut vidéo change
                SubscribeToUser(user);
            }
        }
    }

    void onUserLeave(IZoomVideoSDKUserHelper*, 
                    IVideoSDKVector<IZoomVideoSDKUser*>* userList) override {
        for (int i = 0; i < userList->GetCount(); i++) {
            IZoomVideoSDKUser* user = userList->GetItem(i);
            UnsubscribeFromUser(user);
        }
    }

    void onSessionLeave() override {
        // Nettoyer tous les abonnements
        for (auto& pair : subscribedUsers_) {
            IZoomVideoSDKCanvas* canvas = pair.second;
            if (canvas) {
                canvas->unSubscribeWithView(videoWindow_);
            }
        }
        subscribedUsers_.clear();
    }

private:
    void SubscribeToUser(IZoomVideoSDKUser* user) {
        if (!user || subscribedUsers_.find(user) != subscribedUsers_.end())
            return;

        IZoomVideoSDKCanvas* canvas = user->GetVideoCanvas();
        if (canvas) {
            ZoomVideoSDKErrors ret = canvas->subscribeWithView(
                videoWindow_,
                ZoomVideoSDKVideoAspect_PanAndScan,
                ZoomVideoSDKResolution_Auto
            );

            if (ret == ZoomVideoSDKErrors_Success) {
                subscribedUsers_[user] = canvas;
            }
        }
    }

    void UnsubscribeFromUser(IZoomVideoSDKUser* user) {
        auto it = subscribedUsers_.find(user);
        if (it != subscribedUsers_.end()) {
            IZoomVideoSDKCanvas* canvas = it->second;
            if (canvas) {
                canvas->unSubscribeWithView(videoWindow_);
            }
            subscribedUsers_.erase(it);
        }
    }
};

Points clés :

  • ✅ S'abonner en réponse aux événements (onUserJoin, onUserVideoStatusChanged)
  • ✅ Toujours exclure l'utilisateur actuel des abonnements distants
  • ✅ Se désabonner sur onUserLeave
  • ✅ Nettoyer tous les abonnements sur onSessionLeave
  • ✅ Suivre les abonnements dans une carte pour la gestion du cycle de vie

⚠️ Abonnement au partage d'écran (DIFFÉRENT de la vidéo !)

CRITIQUE : L'abonnement au partage d'écran utilise IZoomVideoSDKShareAction du callback, PAS user->GetShareCanvas() !

// INCORRECT - Cela ne fonctionnera pas pour les partages d'écran distants !
user->GetShareCanvas()->subscribeWithView(hwnd, ...);

// CORRECT - Utiliser IZoomVideoSDKShareAction du callback onUserShareStatusChanged
void onUserShareStatusChanged(IZoomVideoSDKShareHelper* pShareHelper,
                               IZoomVideoSDKUser* pUser,
                               IZoomVideoSDKShareAction* pShareAction) {
    if (!pShareAction) return;

    ZoomVideoSDKShareStatus status = pShareAction->getShareStatus();

    if (status == ZoomVideoSDKShareStatus_Start || 
        status == ZoomVideoSDKShareStatus_Resume) {
        // S'abonner au partage avec Canvas API
        IZoomVideoSDKCanvas* shareCanvas = pShareAction->getShareCanvas();
        if (shareCanvas) {
            shareCanvas->subscribeWithView(shareWindow_, 
                ZoomVideoSDKVideoAspect_Original);
        }
    }
    else if (status == ZoomVideoSDKShareStatus_Stop) {
        // Se désabonner quand le partage s'arrête
        IZoomVideoSDKCanvas* shareCanvas = pShareAction->getShareCanvas();
        if (shareCanvas) {
            shareCanvas->unSubscribeWithView(shareWindow_);
        }
    }
}

Pourquoi le partage est-il différent de la vidéo ?

  • Vidéo : Chaque utilisateur a un flux vidéo → utiliser user->GetVideoCanvas()
  • Partage : Un utilisateur peut avoir plusieurs actions de partage (partage multi) → utiliser IZoomVideoSDKShareAction* du callback
  • L'objet IZoomVideoSDKShareAction représente un flux de partage spécifique et contient le statut de partage, le type et les interfaces de rendu

Voir aussi : Exemple d'abonnement au partage d'écran

Disposition vidéo multi-utilisateur

Pour plusieurs participants, vous avez besoin d'un HWND par utilisateur :

// Créer des fenêtres/panneaux séparés pour chaque utilisateur
HWND selfVideoWindow = CreateWindow(...);   // Votre vidéo
HWND user1Window = CreateWindow(...);       // Vidéo de l'utilisateur 1
HWND user2Window = CreateWindow(...);       // Vidéo de l'utilisateur 2

// S'abonner chaque utilisateur à sa propre fenêtre
myself->GetVideoCanvas()->subscribeWithView(selfVideoWindow, ...);
user1->GetVideoCanvas()->subscribeWithView(user1Window, ...);
user2->GetVideoCanvas()->subscribeWithView(user2Window, ...);

Stratégies de disposition :

  • Grille (2x2, 3x3)
  • Vue galerie (défilement)
  • Orateur actif (grand) + vignettes
  • Image dans l'image

Problèmes vidéo courants

Problème Cause Solution
Vidéo qui ne s'affiche pas N'appelant pas startVideo() Appeler videoHelper->startVideo() dans onSessionJoin
Artefacts/déchirures Utiliser Raw Data Pipe Basculer vers Canvas API
Mauvaises performances Conversion YUV sur le thread UI Utiliser Canvas API ou déplacer la conversion vers un thread de travail
Vidéo figée Ne pas traiter les messages Windows Ajouter pompe de messages à la boucle principale
Ne pas se voir S'abonner au mauvais utilisateur Utiliser session->getMyself() pour votre vidéo
Se voir dans la liste distante Ne pas exclure soi-même Vérifier if (user != myself) avant de s'abonner

Bibliothèque de documentation complète

Cette skill inclut des guides complets organisés par catégorie :

Concepts fondamentaux (Commencez ici !)

Exemples complets

Intégration du framework UI

Modèles de wrapper C++/CLI (Wrapper de TOUTE bibliothèque native)

Dépannage

Références

Problèmes les plus critiques (Basés sur le débogage réel)

  1. Les callbacks ne se déclenchent pas → Boucle de messages Windows manquante (99% des problèmes)

  2. L'abonnement vidéo retourne l'erreur 2 → S'abonner trop tôt

    • Voir : Rendu vidéo - S'abonner dans onUserVideoStatusChanged
  3. Erreurs de classe abstraite → Implémentations de méthode virtuelle manquantes

Point clé

Une fois que vous apprenez le modèle en 3 étapes, vous pouvez implémenter TOUTE fonctionnalité :

  1. Obtenir singleton → 2. Implémenter delegate → 3. S'abonner & utiliser

Voir : Modèle d'architecture SDK

Ressources


Besoin d'aide ? Commencez avec SKILL.md pour une navigation complète.

Fusionné à partir de video-sdk/windows/SKILL.md

Zoom Video SDK Windows - Index de documentation complète

Parcours de démarrage rapide

Si vous êtes nouveau au SDK, suivez cet ordre :

  1. Vue d'ensemblewindows.md

  2. Lire le modèle d'architectureconcepts/sdk-architecture-pattern.md

    • Formule universelle : Singleton → Delegate → S'abonner
    • Une fois que vous comprenez cela, vous pouvez implémenter n'importe quelle fonctionnalité
  3. Corriger les erreurs de compilationtroubleshooting/build-errors.md

    • Dépendances des en-têtes SDK
    • Ordre d'inclusion obligatoire
  4. Implémenter la jointure de sessionexamples/session-join-pattern.md

    • Code complet fonctionnel JWT + jointure de session
  5. Corriger les problèmes de callbacktroubleshooting/windows-message-loop.md

    • CRITIQUE : Pourquoi les callbacks ne se déclenchent pas sans boucle de messages Windows
  6. Implémenter la vidéoexamples/video-rendering.md

    • Canvas API (rendu SDK) vs Raw Data Pipe
  7. Dépanner tout problèmetroubleshooting/common-issues.md

    • Checklist de diagnostic rapide
    • Tableaux des codes d'erreur

Structure de la documentation

video-sdk/windows/
├── SKILL.md                           # Vue d'ensemble principale de la skill
├── SKILL.md                           # Ce fichier - guide de navigation
├── windows.md                          # Document de vue d'ensemble secondaire (style pointeur)
│
├── concepts/                          # Modèles architecturaux fondamentaux
│   ├── sdk-architecture-pattern.md   # Formule universelle pour TOUTE fonctionnalité
│   ├── singleton-hierarchy.md        # Guide de navigation sur 5 niveaux
│   └── canvas-vs-raw-data.md         # Choix entre rendu SDK vs auto-rendu
│
├── examples/                          # Code fonctionnel complet
│   ├── session-join-pattern.md       # Authentification JWT + jointure de session
│   ├── video-rendering.md            # Affichage vidéo Canvas API
│   ├── screen-share-subscription.md  # Afficher les partages d'écran distants
│   ├── raw-video-capture.md          # Capture de trames brutes YUV420
│   ├── raw-audio-capture.md          # Capture d'audio brut PCM
│   ├── send-raw-video.md             # Caméra virtuelle (injecter vidéo)
│   ├── send-raw-audio.md             # Microphone virtuel (injecter audio)
│   ├── cloud-recording.md            # Contrôle d'enregistrement cloud
│   ├── command-channel.md            # Messagerie de commande personnalisée
│   ├── transcription.md              # Transcription/légendes en direct
│   └── dotnet-winforms/              # Intégration du framework UI
│       └── README.md                 # Modèles Win32, WinForms, WPF
│                                     # Modèles de wrapper C++/CLI
│                                     # Directives de qualité production
│
├── troubleshooting/                   # Guides de résolution de problèmes
│   ├── windows-message-loop.md       # CRITIQUE - Pourquoi les callbacks échouent
│   ├── build-errors.md               # Corrections des dépendances d'en-tête
│   └── common-issues.md              # Flux de diagnostic rapide
│
└── references/                        # Documentation de référence
    ├── windows-reference.md           # Hiérarchie API, méthodes, codes d'erreur
    ├── delegate-methods.md            # Tous les 80+ méthodes de callback
    └── samples.md                     # Guide des exemples officiels

Par cas d'usage

Je veux construire une application vidéo

  1. Modèle d'architecture SDK - Comprendre le modèle
  2. Modèle de jointure de session - Rejoindre les sessions
  3. Rendu vidéo - Afficher la vidéo
  4. Boucle de messages Windows - Corriger les problèmes de callback

J'obtiens des erreurs de compilation

  1. Guide des erreurs de compilation - Dépendances des en-têtes SDK
  2. Méthodes Delegate - Erreurs de classe abstraite
  3. Problèmes courants - Erreurs de liaison

J'obtiens des erreurs à l'exécution

  1. Boucle de messages Windows - Les callbacks ne se déclenchent pas
  2. Problèmes courants - Tableaux des codes d'erreur

Je veux afficher les partages d'écran

  1. Abonnement au partage d'écran - DIFFÉRENT de la vidéo !
  2. Modèle d'architecture SDK - Modèle piloté par les événements
  3. Rendu vidéo - Comparer avec l'abonnement vidéo

Je veux capturer audio/vidéo brute

  1. Canvas vs Raw Data - Choisissez votre approche
  2. Capture vidéo brute - Capture de trames YUV420
  3. Capture audio brute - Capture d'audio PCM
  4. Modèle d'architecture SDK - Modèle d'abonnement

Je veux envoyer une vidéo/audio personnalisée (caméra/microphone virtuel)

  1. Envoyer vidéo brute - Injecter des trames vidéo personnalisées
  2. Envoyer audio brut - Injecter de l'audio personnalisé
  3. Modèle d'architecture SDK - Modèle de source externe

Je veux enregistrer des sessions

  1. Enregistrement cloud - Démarrer/arrêter l'enregistrement cloud
  2. Référence API - Méthodes d'aide d'enregistrement

Je veux utiliser la transcription en direct

  1. Transcription - Activer les légendes en direct
  2. Méthodes Delegate - Callbacks de transcription

Je veux la messagerie personnalisée entre participants

  1. Canal de commande - Envoyer des commandes personnalisées
  2. Référence API - Méthodes du canal de commande

Je veux construire une application Win32 native

  1. Intégration Win32 - SDK direct + Canvas API
  2. Rendu vidéo - Modèles Canvas API
  3. Directives production - Bonnes pratiques

Je veux construire une application WinForms (.NET)

  1. Intégration WinForms - Wrapper C++/CLI + Raw Data
  2. Modèles C++/CLI - gcroot, Finalizer, LockBits
  3. Directives production - IDisposable, sécurité des threads

Je veux construire une application WPF (.NET)

  1. Intégration WPF - C++/CLI + BitmapSource
  2. Conversion Bitmap - Freeze(), Dispatcher
  3. Directives production - Optimisation des performances

Je veux utiliser C# / .NET Framework (général)

  1. Vue d'ensemble intégration .NET - Guide complet de wrapper C++/CLI
  2. Capture vidéo brute - Modèles de conversion YUV→RGB
  3. Modèle de jointure de session - Flux d'initialisation du SDK

Je veux wrapper TOUTE bibliothèque C++ native pour .NET

  1. Modèles de wrapper C++/CLI - Guide complet en 8 modèles
  2. Modèle 1 : Structure de base - Configuration du projet + disposition de la classe
  3. Modèle 3 : Callbacks gcroot - Événements natif→géré
  4. Modèle 4 : IDisposable - Modèle de nettoyage
  5. Erreurs courantes - Dépannage

Je veux implémenter une fonctionnalité spécifique

  1. Modèle d'architecture SDK - COMMENCEZ ICI !
  2. Hiérarchie Singleton - Naviguer vers la fonctionnalité
  3. Référence API - Signatures de méthodes

Documents les plus critiques

1. Modèle d'architecture SDK (DOCUMENT MAÎTRE)

concepts/sdk-architecture-pattern.md

Le modèle universel en 3 étapes :

  1. Obtenir singleton (SDK, helpers, session, utilisateurs)
  2. Implémenter delegate (callbacks d'événements)
  3. S'abonner et utiliser

2. Boucle de messages Windows (PROBLÈME PLUS COURANT)

troubleshooting/windows-message-loop.md

99% des problèmes « les callbacks ne se déclenchent pas » sont causés par une boucle de messages Windows manquante.

3. Hiérarchie Singleton (CARTE DE NAVIGATION)

concepts/singleton-hierarchy.md

Navigation profonde sur 5 niveaux montrant comment accéder à chaque fonctionnalité.


Apprentissages clés

Découvertes critiques :

  1. La boucle de messages Windows est OBLIGATOIRE

    • Le SDK utilise la pompe de messages Windows pour les callbacks
    • Sans elle, les callbacks sont mis en file d'attente mais ne se déclenchent jamais
    • Voir : Guide de boucle de messages Windows
  2. S'abonner dans onUserVideoStatusChanged, PAS dans onUserJoin

    • La vidéo peut ne pas être prête quand l'utilisateur rejoint
    • Attendre le callback de changement de statut vidéo
    • Voir : Rendu vidéo
  3. Deux voies de rendu

    • Canvas API : Le SDK rend vers votre HWND (recommandée)
    • Raw Data Pipe : Vous recevez des trames YUV (avancée)
    • Voir : Canvas vs Raw Data
  4. Les helpers contrôlent UNIQUEMENT vos propres flux

    • videoHelper->startVideo() démarre votre caméra
    • Pour voir les autres, s'abonner à leur Canvas/Pipe
    • Voir : Hiérarchie Singleton
  5. L'intégration du framework UI diffère selon la plateforme

    • Win32 : SDK direct, Canvas API (SDK rend vers HWND) - meilleures performances
    • WinForms : Wrapper C++/CLI, Raw Data Pipe, YUV→Bitmap, InvokeRequired
    • WPF : Même wrapper + Bitmap→BitmapSource, Dispatcher, Freeze()
    • Voir : Intégration du framework UI
  6. Modèles de wrapper C++/CLI (pour TOUTE bibliothèque native → .NET)

    • Pointeurs void* - masquer les types natifs des en-têtes gérés
    • gcroot<T^> - empêcher le GC de collecter les références gérées dans le code natif
    • Finalizer + Destructeur - ~Class() et !Class() pour le nettoyage IDisposable
    • pin_ptr + Marshal::Copy - conversion tableau/buffer
    • LockBits - 100x plus rapide que SetPixel pour la manipulation d'image
    • Marshaling de threads - InvokeRequired (WinForms) / Dispatcher (WPF)
    • Voir : Guide de wrapper C++/CLI
  7. Timing de connexion audio

    • Définir audioOption.connect = false lors de la jointure
    • Appeler startAudio() dans le callback onSessionJoin
    • Voir : Directives production

Référence rapide

« Mon code ne compile pas »

Guide des erreurs de compilation

« Les callbacks ne se déclenchent jamais »

Boucle de messages Windows

« L'abonnement vidéo retourne l'erreur 2 »

Rendu vidéo - S'abonner dans onUserVideoStatusChanged

« Erreur de classe abstraite »

Méthodes Delegate

« Comment implémenter [fonctionnalité] ? »

Modèle d'architecture SDK

« Comment naviguer vers [contrôleur] ? »

Hiérarchie Singleton

« Que signifie le code d'erreur ? »

Problèmes courants


Version du document

Basé sur Zoom Video SDK pour Windows v2.x


Bon codage !

Rappelez-vous : Le Modèle d'architecture SDK est votre clé pour déverrouiller le SDK entier. Lisez-le en premier !

Opérations

  • RUNBOOK.md - Checklist de contrôle préalable et débogage en 5 minutes.

Skills similaires